tbb-commits
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 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
- 1 participants
- 20073 discussions
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 16439: Remove screencasting code
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit a7f0b00932ff417397cab114902af76eb871c644
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Wed Jun 24 11:01:11 2015 -0400
Bug 16439: Remove screencasting code
We avoid including the screencasting code on mobile (it got ripped out
for desktop in bug 1393582) by simply excluding the related JS modules
from Tor Browser.
---
toolkit/modules/moz.build | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build
index f000f35c126f..e1f1eb5759c5 100644
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -260,10 +260,11 @@ if 'Android' != CONFIG['OS_TARGET']:
]
else:
DEFINES['ANDROID'] = True
- EXTRA_JS_MODULES += [
- 'secondscreen/RokuApp.jsm',
- 'secondscreen/SimpleServiceDiscovery.jsm',
- ]
+ if not CONFIG['TOR_BROWSER_VERSION']:
+ EXTRA_JS_MODULES += [
+ 'secondscreen/RokuApp.jsm',
+ 'secondscreen/SimpleServiceDiscovery.jsm',
+ ]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 12974: Disable NTLM and Negotiate HTTP Auth
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit b8cf4a0f60673aafb9c7bbf6d7d798f0fe3ec096
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Wed Aug 27 15:19:10 2014 -0700
Bug 12974: Disable NTLM and Negotiate HTTP Auth
This is technically an embargoed Mozilla bug, so I probably shouldn't provide
too many details.
Suffice to say that NTLM and Negotiate auth are bad for Tor users, and I doubt
very many (or any of them) actually need it.
The Mozilla bug is https://bugzilla.mozilla.org/show_bug.cgi?id=1046421
---
extensions/auth/nsHttpNegotiateAuth.cpp | 4 ++++
netwerk/protocol/http/nsHttpNTLMAuth.cpp | 3 +++
2 files changed, 7 insertions(+)
diff --git a/extensions/auth/nsHttpNegotiateAuth.cpp b/extensions/auth/nsHttpNegotiateAuth.cpp
index 99720475b9dd..1c08fcf3da7e 100644
--- a/extensions/auth/nsHttpNegotiateAuth.cpp
+++ b/extensions/auth/nsHttpNegotiateAuth.cpp
@@ -152,6 +152,10 @@ nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
nsIAuthModule* rawModule = (nsIAuthModule*)*continuationState;
*identityInvalid = false;
+
+ /* Always fail Negotiate auth for Tor Browser. We don't need it. */
+ return NS_ERROR_ABORT;
+
if (rawModule) {
return NS_OK;
}
diff --git a/netwerk/protocol/http/nsHttpNTLMAuth.cpp b/netwerk/protocol/http/nsHttpNTLMAuth.cpp
index 0a30de051014..891aaadfd758 100644
--- a/netwerk/protocol/http/nsHttpNTLMAuth.cpp
+++ b/netwerk/protocol/http/nsHttpNTLMAuth.cpp
@@ -168,6 +168,9 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel* channel,
*identityInvalid = false;
+ /* Always fail Negotiate auth for Tor Browser. We don't need it. */
+ return NS_ERROR_ABORT;
+
// Start a new auth sequence if the challenge is exactly "NTLM".
// If native NTLM auth apis are available and enabled through prefs,
// try to use them.
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 9173: Change the default Firefox profile directory to be TBB-relative.
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 1e7f9abacc4814e8e60ced907ee69f3da3b5035a
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Fri Oct 18 15:20:06 2013 -0400
Bug 9173: Change the default Firefox profile directory to be TBB-relative.
This should eliminate our need to rely on a wrapper script that
sets /Users/arthur and launches Firefox with -profile.
---
toolkit/profile/nsToolkitProfileService.cpp | 5 +-
toolkit/xre/nsAppRunner.cpp | 2 +-
toolkit/xre/nsConsoleWriter.cpp | 2 +-
toolkit/xre/nsXREDirProvider.cpp | 150 ++++++----------------------
toolkit/xre/nsXREDirProvider.h | 16 +--
xpcom/io/nsAppFileLocationProvider.cpp | 97 +++++++-----------
6 files changed, 84 insertions(+), 188 deletions(-)
diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp
index dc4811313b5e..a3e50f8c00d3 100644
--- a/toolkit/profile/nsToolkitProfileService.cpp
+++ b/toolkit/profile/nsToolkitProfileService.cpp
@@ -723,10 +723,11 @@ nsresult nsToolkitProfileService::Init() {
NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!");
nsresult rv;
- rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(mAppData));
+ rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData));
NS_ENSURE_SUCCESS(rv, rv);
- rv = nsXREDirProvider::GetUserLocalDataDirectory(getter_AddRefs(mTempData));
+ rv =
+ gDirServiceProvider->GetUserLocalDataDirectory(getter_AddRefs(mTempData));
NS_ENSURE_SUCCESS(rv, rv);
rv = mAppData->Clone(getter_AddRefs(mProfileDBFile));
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 8b5bce27cdc4..e3e7f785ada9 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -3182,7 +3182,7 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory))) {
nsCOMPtr<nsIFile> file;
- rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file));
+ rv = mDirProvider.GetUserAppDataDirectory(getter_AddRefs(file));
if (NS_SUCCEEDED(rv)) {
CrashReporter::SetUserAppDataDirectory(file);
}
diff --git a/toolkit/xre/nsConsoleWriter.cpp b/toolkit/xre/nsConsoleWriter.cpp
index 0a2c0c342893..46735a293a00 100644
--- a/toolkit/xre/nsConsoleWriter.cpp
+++ b/toolkit/xre/nsConsoleWriter.cpp
@@ -29,7 +29,7 @@ void WriteConsoleLog() {
} else {
if (!gLogConsoleErrors) return;
- rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(lfile));
+ rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(lfile));
if (NS_FAILED(rv)) return;
lfile->AppendNative(NS_LITERAL_CSTRING("console.log"));
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
index 7641ef683c39..f80cb2827349 100644
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -32,6 +32,7 @@
#include "nsArrayEnumerator.h"
#include "nsEnumeratorUtils.h"
#include "nsReadableUtils.h"
+#include "nsXPCOMPrivate.h" // for XPCOM_FILE_PATH_SEPARATOR
#include "SpecialSystemDirectory.h"
@@ -249,9 +250,6 @@ nsresult nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult) {
nsresult rv = GetUserDataDirectory(getter_AddRefs(file), false);
if (NS_SUCCEEDED(rv)) {
-#if !defined(XP_UNIX) || defined(XP_MACOSX)
- rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
-#endif
// We must create the profile directory here if it does not exist.
nsresult tmp = EnsureDirectoryExists(file);
if (NS_FAILED(tmp)) {
@@ -267,9 +265,6 @@ nsresult nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult) {
nsresult rv = GetUserDataDirectory(getter_AddRefs(file), true);
if (NS_SUCCEEDED(rv)) {
-#if !defined(XP_UNIX) || defined(XP_MACOSX)
- rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
-#endif
// We must create the profile directory here if it does not exist.
nsresult tmp = EnsureDirectoryExists(file);
if (NS_FAILED(tmp)) {
@@ -1403,7 +1398,7 @@ nsresult nsXREDirProvider::SetUserDataProfileDirectory(nsCOMPtr<nsIFile>& aFile,
nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
bool aLocal) {
// Copied from nsAppFileLocationProvider (more or less)
- nsresult rv;
+ NS_ENSURE_ARG_POINTER(aFile);
nsCOMPtr<nsIFile> localDir;
if (aLocal && gDataDirHomeLocal) {
@@ -1413,81 +1408,39 @@ nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
return gDataDirHome->Clone(aFile);
}
-#if defined(XP_MACOSX)
- FSRef fsRef;
- OSType folderType;
- if (aLocal) {
- folderType = kCachedDataFolderType;
- } else {
-# ifdef MOZ_THUNDERBIRD
- folderType = kDomainLibraryFolderType;
-# else
- folderType = kApplicationSupportFolderType;
-# endif
- }
- OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
- NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
-
- rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
+ nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
- NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
-
- rv = dirFileMac->InitWithFSRef(&fsRef);
- NS_ENSURE_SUCCESS(rv, rv);
+ int levelsToRemove = 1; // In FF21+, appDir points to browser subdirectory.
+#if defined(XP_MACOSX)
+ levelsToRemove += 2;
+#endif
+ while (localDir && (levelsToRemove > 0)) {
+ // When crawling up the hierarchy, components named "." do not count.
+ nsAutoCString removedName;
+ rv = localDir->GetNativeLeafName(removedName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool didRemove = !removedName.Equals(".");
- localDir = dirFileMac;
-#elif defined(XP_IOS)
- nsAutoCString userDir;
- if (GetUIKitDirectory(aLocal, userDir)) {
- rv = NS_NewNativeLocalFile(userDir, true, getter_AddRefs(localDir));
- } else {
- rv = NS_ERROR_FAILURE;
- }
- NS_ENSURE_SUCCESS(rv, rv);
-#elif defined(XP_WIN)
- nsString path;
- if (aLocal) {
- rv = GetShellFolderPath(FOLDERID_LocalAppData, path);
- if (NS_FAILED(rv)) rv = GetRegWindowsAppDataFolder(aLocal, path);
- }
- if (!aLocal || NS_FAILED(rv)) {
- rv = GetShellFolderPath(FOLDERID_RoamingAppData, path);
- if (NS_FAILED(rv)) {
- if (!aLocal) rv = GetRegWindowsAppDataFolder(aLocal, path);
- }
+ // Remove a directory component.
+ nsCOMPtr<nsIFile> parentDir;
+ rv = localDir->GetParent(getter_AddRefs(parentDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ localDir = parentDir;
+ if (didRemove) --levelsToRemove;
}
- NS_ENSURE_SUCCESS(rv, rv);
- rv = NS_NewLocalFile(path, true, getter_AddRefs(localDir));
-#elif defined(XP_UNIX)
- const char* homeDir = getenv("HOME");
- if (!homeDir || !*homeDir) return NS_ERROR_FAILURE;
+ if (!localDir) return NS_ERROR_FAILURE;
-# ifdef ANDROID /* We want (ProfD == ProfLD) on Android. */
- aLocal = false;
-# endif
+ rv = localDir->AppendRelativeNativePath(
+ NS_LITERAL_CSTRING("TorBrowser" XPCOM_FILE_PATH_SEPARATOR
+ "Data" XPCOM_FILE_PATH_SEPARATOR "Browser"));
+ NS_ENSURE_SUCCESS(rv, rv);
if (aLocal) {
- // If $XDG_CACHE_HOME is defined use it, otherwise use $HOME/.cache.
- const char* cacheHome = getenv("XDG_CACHE_HOME");
- if (cacheHome && *cacheHome) {
- rv = NS_NewNativeLocalFile(nsDependentCString(cacheHome), true,
- getter_AddRefs(localDir));
- } else {
- rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
- getter_AddRefs(localDir));
- if (NS_SUCCEEDED(rv))
- rv = localDir->AppendNative(NS_LITERAL_CSTRING(".cache"));
- }
- } else {
- rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
- getter_AddRefs(localDir));
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
+ NS_ENSURE_SUCCESS(rv, rv);
}
-#else
-# error "Don't know how to get product dir on your platform"
-#endif
NS_IF_ADDREF(*aFile = localDir);
return rv;
@@ -1670,39 +1623,23 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
}
nsAutoCString profile;
- nsAutoCString appName;
- nsAutoCString vendor;
if (gAppData->profile) {
profile = gAppData->profile;
- } else {
- appName = gAppData->name;
- vendor = gAppData->vendor;
}
- nsresult rv = NS_OK;
+ nsresult rv = NS_ERROR_FAILURE;
#if defined(XP_MACOSX)
if (!profile.IsEmpty()) {
rv = AppendProfileString(aFile, profile.get());
- } else {
- // Note that MacOS ignores the vendor when creating the profile hierarchy -
- // all application preferences directories live alongside one another in
- // ~/Library/Application Support/
- rv = aFile->AppendNative(appName);
+ NS_ENSURE_SUCCESS(rv, rv);
}
- NS_ENSURE_SUCCESS(rv, rv);
#elif defined(XP_WIN)
if (!profile.IsEmpty()) {
rv = AppendProfileString(aFile, profile.get());
- } else {
- if (!vendor.IsEmpty()) {
- rv = aFile->AppendNative(vendor);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- rv = aFile->AppendNative(appName);
+ NS_ENSURE_SUCCESS(rv, rv);
}
- NS_ENSURE_SUCCESS(rv, rv);
#elif defined(ANDROID)
// The directory used for storing profiles
@@ -1712,11 +1649,6 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
rv = aFile->AppendNative(nsDependentCString("mozilla"));
NS_ENSURE_SUCCESS(rv, rv);
#elif defined(XP_UNIX)
- nsAutoCString folder;
- // Make it hidden (by starting with "."), except when local (the
- // profile is already under ~/.cache or XDG_CACHE_HOME).
- if (!aLocal) folder.Assign('.');
-
if (!profile.IsEmpty()) {
// Skip any leading path characters
const char* profileStart = profile.get();
@@ -1724,32 +1656,16 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
// On the off chance that someone wanted their folder to be hidden don't
// let it become ".."
- if (*profileStart == '.' && !aLocal) profileStart++;
+ if (*profileStart == '.') profileStart++;
+ // Make it hidden (by starting with ".").
+ nsAutoCString folder(".");
folder.Append(profileStart);
ToLowerCase(folder);
rv = AppendProfileString(aFile, folder.BeginReading());
- } else {
- if (!vendor.IsEmpty()) {
- folder.Append(vendor);
- ToLowerCase(folder);
-
- rv = aFile->AppendNative(folder);
- NS_ENSURE_SUCCESS(rv, rv);
-
- folder.Truncate();
- }
-
- // This can be the case in tests.
- if (!appName.IsEmpty()) {
- folder.Append(appName);
- ToLowerCase(folder);
-
- rv = aFile->AppendNative(folder);
- }
+ NS_ENSURE_SUCCESS(rv, rv);
}
- NS_ENSURE_SUCCESS(rv, rv);
#else
# error "Don't know how to get profile path on your platform"
diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
index e55b4e153c56..b9678d4ec577 100644
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -63,15 +63,19 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
void DoShutdown();
- static nsresult GetUserAppDataDirectory(nsIFile** aFile) {
+ nsresult GetUserAppDataDirectory(nsIFile** aFile) {
return GetUserDataDirectory(aFile, false);
}
- static nsresult GetUserLocalDataDirectory(nsIFile** aFile) {
+ nsresult GetUserLocalDataDirectory(nsIFile** aFile) {
return GetUserDataDirectory(aFile, true);
}
// GetUserDataDirectory gets the profile path from gAppData.
- static nsresult GetUserDataDirectory(nsIFile** aFile, bool aLocal);
+
+ // This function now calls GetAppDir(), so it cannot be static anymore.
+ // The same happens with all the functions (in)directly calling this one (the
+ // rest of Get*Directory functions in this file)
+ nsresult GetUserDataDirectory(nsIFile** aFile, bool aLocal);
/* make sure you clone it, if you need to do stuff to it */
nsIFile* GetGREDir() { return mGREDir; }
@@ -112,9 +116,9 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
protected:
nsresult GetFilesInternal(const char* aProperty,
nsISimpleEnumerator** aResult);
- static nsresult GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal);
- static nsresult GetSysUserExtensionsDirectory(nsIFile** aFile);
- static nsresult GetSysUserExtensionsDevDirectory(nsIFile** aFile);
+ nsresult GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal);
+ nsresult GetSysUserExtensionsDirectory(nsIFile** aFile);
+ nsresult GetSysUserExtensionsDevDirectory(nsIFile** aFile);
#if defined(XP_UNIX) || defined(XP_MACOSX)
static nsresult GetSystemExtensionsDirectory(nsIFile** aFile);
#endif
diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp
index 915e8bc7361e..81551a8e3893 100644
--- a/xpcom/io/nsAppFileLocationProvider.cpp
+++ b/xpcom/io/nsAppFileLocationProvider.cpp
@@ -15,6 +15,7 @@
#include "nsSimpleEnumerator.h"
#include "prenv.h"
#include "nsCRT.h"
+#include "nsXPCOMPrivate.h" // for XPCOM_FILE_PATH_SEPARATOR
#if defined(MOZ_WIDGET_COCOA)
# include <Carbon/Carbon.h>
# include "nsILocalFileMac.h"
@@ -233,9 +234,8 @@ nsresult nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile) {
// GetProductDirectory - Gets the directory which contains the application data
// folder
//
-// UNIX : ~/.mozilla/
-// WIN : <Application Data folder on user's machine>\Mozilla
-// Mac : :Documents:Mozilla:
+// UNIX and WIN : <App Folder>/TorBrowser/Data/Browser
+// Mac : <App Folder>/../../TorBrowser/Data/Browser
//----------------------------------------------------------------------------------------
nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
bool aLocal) {
@@ -247,49 +247,45 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
bool exists;
nsCOMPtr<nsIFile> localDir;
-#if defined(MOZ_WIDGET_COCOA)
- FSRef fsRef;
- OSType folderType =
- aLocal ? (OSType)kCachedDataFolderType : (OSType)kDomainLibraryFolderType;
- OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
- if (err) {
- return NS_ERROR_FAILURE;
+ rv = CloneMozBinDirectory(getter_AddRefs(localDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ int levelsToRemove = 1; // In FF21+, bin dir points to browser subdirectory.
+#if defined(XP_MACOSX)
+ levelsToRemove += 2;
+#endif
+ while (localDir && (levelsToRemove > 0)) {
+ // When crawling up the hierarchy, components named "." do not count.
+ nsAutoCString removedName;
+ rv = localDir->GetNativeLeafName(removedName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool didRemove = !removedName.Equals(".");
+
+ // Remove a directory component.
+ nsCOMPtr<nsIFile> parentDir;
+ rv = localDir->GetParent(getter_AddRefs(parentDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ localDir = parentDir;
+
+ if (didRemove) {
+ --levelsToRemove;
+ }
}
- NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localDir));
+
if (!localDir) {
return NS_ERROR_FAILURE;
}
- nsCOMPtr<nsILocalFileMac> localDirMac(do_QueryInterface(localDir));
- rv = localDirMac->InitWithFSRef(&fsRef);
- if (NS_FAILED(rv)) {
- return rv;
- }
-#elif defined(XP_WIN)
- nsCOMPtr<nsIProperties> directoryService =
- do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
- if (NS_FAILED(rv)) {
- return rv;
- }
- const char* prop = aLocal ? NS_WIN_LOCAL_APPDATA_DIR : NS_WIN_APPDATA_DIR;
- rv = directoryService->Get(prop, NS_GET_IID(nsIFile),
- getter_AddRefs(localDir));
- if (NS_FAILED(rv)) {
- return rv;
- }
-#elif defined(XP_UNIX)
- rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
- getter_AddRefs(localDir));
- if (NS_FAILED(rv)) {
- return rv;
- }
-#else
-# error dont_know_how_to_get_product_dir_on_your_platform
-#endif
- rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR);
- if (NS_FAILED(rv)) {
- return rv;
+ rv = localDir->AppendRelativeNativePath(
+ NS_LITERAL_CSTRING("TorBrowser" XPCOM_FILE_PATH_SEPARATOR
+ "Data" XPCOM_FILE_PATH_SEPARATOR "Browser"));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aLocal) {
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
+ NS_ENSURE_SUCCESS(rv, rv);
}
+
rv = localDir->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists) {
@@ -308,10 +304,6 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
//----------------------------------------------------------------------------------------
// GetDefaultUserProfileRoot - Gets the directory which contains each user
// profile dir
-//
-// UNIX : ~/.mozilla/
-// WIN : <Application Data folder on user's machine>\Mozilla\Profiles
-// Mac : :Documents:Mozilla:Profiles:
//----------------------------------------------------------------------------------------
nsresult nsAppFileLocationProvider::GetDefaultUserProfileRoot(
nsIFile** aLocalFile, bool aLocal) {
@@ -327,23 +319,6 @@ nsresult nsAppFileLocationProvider::GetDefaultUserProfileRoot(
return rv;
}
-#if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
- // These 3 platforms share this part of the path - do them as one
- rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Profiles"));
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- bool exists;
- rv = localDir->Exists(&exists);
- if (NS_SUCCEEDED(rv) && !exists) {
- rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
-#endif
-
localDir.forget(aLocalFile);
return rv;
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 14631: Improve profile access error messages.
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 271d6fec55c7251600386cc0ab798fc003a47479
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Tue Feb 24 13:50:23 2015 -0500
Bug 14631: Improve profile access error messages.
Instead of always reporting that the profile is locked, display specific
messages for "access denied" and "read-only file system".
To allow for localization, get profile-related error strings from Torbutton.
Use app display name ("Tor Browser") in profile-related error alerts.
---
.../mozapps/profile/profileSelection.properties | 5 +
toolkit/profile/nsToolkitProfileService.cpp | 57 +++++++-
toolkit/profile/nsToolkitProfileService.h | 13 +-
toolkit/xre/nsAppRunner.cpp | 155 ++++++++++++++++++---
4 files changed, 207 insertions(+), 23 deletions(-)
diff --git a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
index 2be092bf4c4b..922b52cb1385 100644
--- a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
@@ -12,6 +12,11 @@ restartMessageUnlocker=%S is already running, but is not responding. The old %S
restartMessageNoUnlockerMac=A copy of %S is already open. Only one copy of %S can be open at a time.
restartMessageUnlockerMac=A copy of %S is already open. The running copy of %S will quit in order to open this one.
+# LOCALIZATION NOTE (profileProblemTitle, profileReadOnly, profileReadOnlyMac, profileAccessDenied): Messages displayed when the browser profile cannot be accessed or written to. %S is the application name.
+profileProblemTitle=%S Profile Problem
+profileReadOnly=You cannot run %S from a read-only file system. Please copy %S to another location before trying to use it.
+profileReadOnlyMac=You cannot run %S from a read-only file system. Please copy %S to your Desktop or Applications folder before trying to use it.
+profileAccessDenied=%S does not have permission to access the profile. Please adjust your file system permissions and try again.
# Profile manager
# LOCALIZATION NOTE (profileTooltip): First %S is the profile name, second %S is the path to the profile folder.
profileTooltip=Profile: ‘%S’ - Path: ‘%S’
diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp
index a3e50f8c00d3..3f32bd95f9c9 100644
--- a/toolkit/profile/nsToolkitProfileService.cpp
+++ b/toolkit/profile/nsToolkitProfileService.cpp
@@ -1161,9 +1161,10 @@ nsToolkitProfileService::SelectStartupProfile(
}
bool wasDefault;
+ ProfileStatus profileStatus;
nsresult rv =
SelectStartupProfile(&argc, argv.get(), aIsResetting, aRootDir, aLocalDir,
- aProfile, aDidCreate, &wasDefault);
+ aProfile, aDidCreate, &wasDefault, profileStatus);
// Since we were called outside of the normal startup path complete any
// startup tasks.
@@ -1196,7 +1197,8 @@ nsToolkitProfileService::SelectStartupProfile(
nsresult nsToolkitProfileService::SelectStartupProfile(
int* aArgc, char* aArgv[], bool aIsResetting, nsIFile** aRootDir,
nsIFile** aLocalDir, nsIToolkitProfile** aProfile, bool* aDidCreate,
- bool* aWasDefaultSelection) {
+ bool* aWasDefaultSelection, ProfileStatus& aProfileStatus) {
+ aProfileStatus = PROFILE_STATUS_OK;
if (mStartupProfileSelected) {
return NS_ERROR_ALREADY_INITIALIZED;
}
@@ -1290,6 +1292,13 @@ nsresult nsToolkitProfileService::SelectStartupProfile(
rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
NS_ENSURE_SUCCESS(rv, rv);
+ aProfileStatus = CheckProfileWriteAccess(lf);
+ if (PROFILE_STATUS_OK != aProfileStatus) {
+ NS_ADDREF(*aRootDir = lf);
+ NS_ADDREF(*aLocalDir = lf);
+ return NS_ERROR_FAILURE;
+ }
+
// Make sure that the profile path exists and it's a directory.
bool exists;
rv = lf->Exists(&exists);
@@ -2079,3 +2088,47 @@ nsresult XRE_GetFileFromPath(const char* aPath, nsIFile** aResult) {
# error Platform-specific logic needed here.
#endif
}
+
+// Check for write permission to the profile directory by trying to create a
+// new file (after ensuring that no file with the same name exists).
+ProfileStatus nsToolkitProfileService::CheckProfileWriteAccess(
+ nsIFile* aProfileDir) {
+#if defined(XP_UNIX)
+ NS_NAMED_LITERAL_STRING(writeTestFileName, ".parentwritetest");
+#else
+ NS_NAMED_LITERAL_STRING(writeTestFileName, "parent.writetest");
+#endif
+
+ nsCOMPtr<nsIFile> writeTestFile;
+ nsresult rv = aProfileDir->Clone(getter_AddRefs(writeTestFile));
+ if (NS_SUCCEEDED(rv)) rv = writeTestFile->Append(writeTestFileName);
+
+ if (NS_SUCCEEDED(rv)) {
+ bool doesExist = false;
+ rv = writeTestFile->Exists(&doesExist);
+ if (NS_SUCCEEDED(rv) && doesExist) rv = writeTestFile->Remove(true);
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = writeTestFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
+ (void)writeTestFile->Remove(true);
+ }
+
+ ProfileStatus status =
+ NS_SUCCEEDED(rv) ? PROFILE_STATUS_OK : PROFILE_STATUS_OTHER_ERROR;
+ if (NS_ERROR_FILE_ACCESS_DENIED == rv)
+ status = PROFILE_STATUS_ACCESS_DENIED;
+ else if (NS_ERROR_FILE_READ_ONLY == rv)
+ status = PROFILE_STATUS_READ_ONLY;
+
+ return status;
+}
+
+ProfileStatus nsToolkitProfileService::CheckProfileWriteAccess(
+ nsIToolkitProfile* aProfile) {
+ nsCOMPtr<nsIFile> profileDir;
+ nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
+ if (NS_FAILED(rv)) return PROFILE_STATUS_OTHER_ERROR;
+
+ return CheckProfileWriteAccess(profileDir);
+}
diff --git a/toolkit/profile/nsToolkitProfileService.h b/toolkit/profile/nsToolkitProfileService.h
index f2a238312b95..cfb1964ee1d7 100644
--- a/toolkit/profile/nsToolkitProfileService.h
+++ b/toolkit/profile/nsToolkitProfileService.h
@@ -15,6 +15,14 @@
#include "nsProfileLock.h"
#include "nsINIParser.h"
+enum ProfileStatus {
+ PROFILE_STATUS_OK,
+ PROFILE_STATUS_ACCESS_DENIED,
+ PROFILE_STATUS_READ_ONLY,
+ PROFILE_STATUS_IS_LOCKED,
+ PROFILE_STATUS_OTHER_ERROR
+};
+
class nsToolkitProfile final
: public nsIToolkitProfile,
public mozilla::LinkedListElement<RefPtr<nsToolkitProfile>> {
@@ -79,10 +87,13 @@ class nsToolkitProfileService final : public nsIToolkitProfileService {
nsresult SelectStartupProfile(int* aArgc, char* aArgv[], bool aIsResetting,
nsIFile** aRootDir, nsIFile** aLocalDir,
nsIToolkitProfile** aProfile, bool* aDidCreate,
- bool* aWasDefaultSelection);
+ bool* aWasDefaultSelection,
+ ProfileStatus& aProfileStatus);
nsresult CreateResetProfile(nsIToolkitProfile** aNewProfile);
nsresult ApplyResetProfile(nsIToolkitProfile* aOldProfile);
void CompleteStartup();
+ static ProfileStatus CheckProfileWriteAccess(nsIToolkitProfile* aProfile);
+ static ProfileStatus CheckProfileWriteAccess(nsIFile* aProfileDir);
private:
friend class nsToolkitProfile;
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index e3e7f785ada9..8de43a8c4cfc 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1731,6 +1731,91 @@ nsresult LaunchChild(bool aBlankCommandLine) {
return NS_ERROR_LAUNCHED_CHILD_PROCESS;
}
+static nsresult GetOverrideStringBundleForLocale(nsIStringBundleService* aSBS,
+ const char* aTorbuttonURI,
+ const char* aLocale,
+ nsIStringBundle** aResult) {
+ NS_ENSURE_ARG(aSBS);
+ NS_ENSURE_ARG(aTorbuttonURI);
+ NS_ENSURE_ARG(aLocale);
+ NS_ENSURE_ARG(aResult);
+
+ const char* kFormatStr =
+ "jar:%s!/chrome/torbutton/locale/%s/torbutton.properties";
+ nsPrintfCString strBundleURL(kFormatStr, aTorbuttonURI, aLocale);
+ nsresult rv = aSBS->CreateBundle(strBundleURL.get(), aResult);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // To ensure that we have a valid string bundle, try to retrieve a string
+ // that we know exists.
+ nsAutoString val;
+ rv = (*aResult)->GetStringFromName("profileProblemTitle", val);
+ if (!NS_SUCCEEDED(rv)) *aResult = nullptr; // No good. Discard it.
+
+ return rv;
+}
+
+static void GetOverrideStringBundle(nsIStringBundleService* aSBS,
+ nsIStringBundle** aResult) {
+ if (!aSBS || !aResult) return;
+
+ *aResult = nullptr;
+
+ // Build Torbutton file URI string by starting from GREDir.
+ RefPtr<nsXREDirProvider> dirProvider = nsXREDirProvider::GetSingleton();
+ if (!dirProvider) return;
+
+ nsCOMPtr<nsIFile> greDir = dirProvider->GetGREDir();
+ if (!greDir) return;
+
+ // Create file URI, extract as string, and append omni.ja relative path.
+ nsCOMPtr<nsIURI> uri;
+ nsAutoCString uriString;
+ if (NS_FAILED(NS_NewFileURI(getter_AddRefs(uri), greDir)) ||
+ NS_FAILED(uri->GetSpec(uriString))) {
+ return;
+ }
+
+ uriString.Append("omni.ja");
+
+ nsAutoCString userAgentLocale;
+ if (!NS_SUCCEEDED(
+ Preferences::GetCString("intl.locale.requested", userAgentLocale))) {
+ return;
+ }
+
+ nsresult rv = GetOverrideStringBundleForLocale(
+ aSBS, uriString.get(), userAgentLocale.get(), aResult);
+ if (NS_FAILED(rv)) {
+ // Try again using base locale, e.g., "en" vs. "en-US".
+ int16_t offset = userAgentLocale.FindChar('-', 1);
+ if (offset > 0) {
+ nsAutoCString shortLocale(Substring(userAgentLocale, 0, offset));
+ rv = GetOverrideStringBundleForLocale(aSBS, uriString.get(),
+ shortLocale.get(), aResult);
+ }
+ }
+}
+
+static nsresult GetFormattedString(nsIStringBundle* aOverrideBundle,
+ nsIStringBundle* aMainBundle,
+ const char* aName,
+ const nsTArray<nsString>& aParams,
+ nsAString& aResult) {
+ NS_ENSURE_ARG(aName);
+
+ nsresult rv = NS_ERROR_FAILURE;
+ if (aOverrideBundle) {
+ rv = aOverrideBundle->FormatStringFromName(aName, aParams, aResult);
+ }
+
+ // If string was not found in override bundle, use main (browser) bundle.
+ if (NS_FAILED(rv) && aMainBundle)
+ rv = aMainBundle->FormatStringFromName(aName, aParams, aResult);
+
+ return rv;
+}
+
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
@@ -1779,7 +1864,7 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
- NS_ConvertUTF8toUTF16 appName(gAppData->name);
+ NS_ConvertUTF8toUTF16 appName(MOZ_APP_DISPLAYNAME);
AutoTArray<nsString, 2> params = {appName, appName};
// profileMissing
@@ -1801,11 +1886,12 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
}
}
-static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
- nsIFile* aProfileLocalDir,
- nsIProfileUnlocker* aUnlocker,
- nsINativeAppSupport* aNative,
- nsIProfileLock** aResult) {
+static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
+ nsIFile* aProfileLocalDir,
+ ProfileStatus aStatus,
+ nsIProfileUnlocker* aUnlocker,
+ nsINativeAppSupport* aNative,
+ nsIProfileLock** aResult) {
nsresult rv;
bool exists;
@@ -1833,24 +1919,39 @@ static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
- NS_ConvertUTF8toUTF16 appName(gAppData->name);
+ nsCOMPtr<nsIStringBundle> overrideSB;
+ GetOverrideStringBundle(sbs, getter_AddRefs(overrideSB));
+
+ NS_ConvertUTF8toUTF16 appName(MOZ_APP_DISPLAYNAME);
AutoTArray<nsString, 3> params = {appName, appName, appName};
nsAutoString killMessage;
#ifndef XP_MACOSX
- rv = sb->FormatStringFromName(
- aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2",
- params, killMessage);
+ static const char kRestartUnlocker[] = "restartMessageUnlocker";
+ static const char kRestartNoUnlocker[] = "restartMessageNoUnlocker2";
+ static const char kReadOnly[] = "profileReadOnly";
#else
- rv = sb->FormatStringFromName(
- aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac",
- params, killMessage);
+ static const char kRestartUnlocker[] = "restartMessageUnlockerMac";
+ static const char kRestartNoUnlocker[] = "restartMessageNoUnlockerMac";
+ static const char kReadOnly[] = "profileReadOnlyMac";
#endif
+ static const char kAccessDenied[] = "profileAccessDenied";
+
+ const char* errorKey = aUnlocker ? kRestartUnlocker : kRestartNoUnlocker;
+ if (PROFILE_STATUS_READ_ONLY == aStatus)
+ errorKey = kReadOnly;
+ else if (PROFILE_STATUS_ACCESS_DENIED == aStatus)
+ errorKey = kAccessDenied;
+ rv = GetFormattedString(overrideSB, sb, errorKey, params, killMessage);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+ const char* titleKey = ((PROFILE_STATUS_READ_ONLY == aStatus) ||
+ (PROFILE_STATUS_ACCESS_DENIED == aStatus))
+ ? "profileProblemTitle"
+ : "restartTitle";
params.SetLength(1);
nsAutoString killTitle;
- rv = sb->FormatStringFromName("restartTitle", params, killTitle);
+ rv = sb->FormatStringFromName(titleKey, params, killTitle);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
if (gfxPlatform::IsHeadless()) {
@@ -2008,6 +2109,13 @@ static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
nsIFile* aLocalDir, nsIToolkitProfile* aProfile,
nsIProfileLock** aResult) {
+ ProfileStatus status =
+ (aProfile ? nsToolkitProfileService::CheckProfileWriteAccess(aProfile)
+ : nsToolkitProfileService::CheckProfileWriteAccess(aRootDir));
+ if (PROFILE_STATUS_OK != status)
+ return ProfileErrorDialog(aRootDir, aLocalDir, status, nullptr, aNative,
+ aResult);
+
// If you close Firefox and very quickly reopen it, the old Firefox may
// still be closing down. Rather than immediately showing the
// "Firefox is running but is not responding" message, we spend a few
@@ -2034,7 +2142,8 @@ static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
} while (TimeStamp::Now() - start <
TimeDuration::FromSeconds(kLockRetrySeconds));
- return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult);
+ return ProfileErrorDialog(aRootDir, aLocalDir, PROFILE_STATUS_IS_LOCKED,
+ unlocker, aNative, aResult);
}
// Pick a profile. We need to end up with a profile root dir, local dir and
@@ -2049,7 +2158,8 @@ static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir,
static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
nsINativeAppSupport* aNative, nsIFile** aRootDir,
nsIFile** aLocalDir, nsIToolkitProfile** aProfile,
- bool* aWasDefaultSelection) {
+ bool* aWasDefaultSelection,
+ nsIProfileLock** aResult) {
StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
nsresult rv;
@@ -2095,9 +2205,14 @@ static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
// Ask the profile manager to select the profile directories to use.
bool didCreate = false;
- rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
- aRootDir, aLocalDir, aProfile,
- &didCreate, aWasDefaultSelection);
+ ProfileStatus profileStatus = PROFILE_STATUS_OK;
+ rv = aProfileSvc->SelectStartupProfile(
+ &gArgc, gArgv, gDoProfileReset, aRootDir, aLocalDir, aProfile, &didCreate,
+ aWasDefaultSelection, profileStatus);
+ if (PROFILE_STATUS_OK != profileStatus) {
+ return ProfileErrorDialog(*aRootDir, *aLocalDir, profileStatus, nullptr,
+ aNative, aResult);
+ }
if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
return ShowProfileManager(aProfileSvc, aNative);
@@ -3927,7 +4042,7 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
nsCOMPtr<nsIToolkitProfile> profile;
rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
getter_AddRefs(mProfLD), getter_AddRefs(profile),
- &wasDefaultSelection);
+ &wasDefaultSelection, getter_AddRefs(mProfileLock));
if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
*aExitFlag = true;
return 0;
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 13028: Prevent potential proxy bypass cases.
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit c6abd623813d299900ea0b0901985a338b700680
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Mon Sep 29 14:30:19 2014 -0700
Bug 13028: Prevent potential proxy bypass cases.
It looks like these cases should only be invoked in the NSS command line
tools, and not the browser, but I decided to patch them anyway because there
literally is a maze of network function pointers being passed around, and it's
very hard to tell if some random code might not pass in the proper proxied
versions of the networking code here by accident.
---
security/nss/lib/certhigh/ocsp.c | 8 ++++++++
.../lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c | 21 +++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/security/nss/lib/certhigh/ocsp.c b/security/nss/lib/certhigh/ocsp.c
index cea8456606bf..86fa971cfbef 100644
--- a/security/nss/lib/certhigh/ocsp.c
+++ b/security/nss/lib/certhigh/ocsp.c
@@ -2932,6 +2932,14 @@ ocsp_ConnectToHost(const char *host, PRUint16 port)
PRNetAddr addr;
char *netdbbuf = NULL;
+ // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but
+ // we want to ensure nothing can ever hit this code in production.
+#if 1
+ printf("Tor Browser BUG: Attempted OSCP direct connect to %s, port %u\n", host,
+ port);
+ goto loser;
+#endif
+
sock = PR_NewTCPSocket();
if (sock == NULL)
goto loser;
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
index e8698376b5be..85791d84a932 100644
--- a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
@@ -1334,6 +1334,13 @@ pkix_pl_Socket_Create(
plContext),
PKIX_COULDNOTCREATESOCKETOBJECT);
+ // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but
+ // we want to ensure nothing can ever hit this code in production.
+#if 1
+ printf("Tor Browser BUG: Attempted pkix direct socket connect\n");
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+#endif
+
socket->isServer = isServer;
socket->timeout = timeout;
socket->clientSock = NULL;
@@ -1433,6 +1440,13 @@ pkix_pl_Socket_CreateByName(
localCopyName = PL_strdup(serverName);
+ // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but
+ // we want to ensure nothing can ever hit this code in production.
+#if 1
+ printf("Tor Browser BUG: Attempted pkix direct connect to %s\n", serverName);
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+#endif
+
sepPtr = strchr(localCopyName, ':');
/* First strip off the portnum, if present, from the end of the name */
if (sepPtr) {
@@ -1582,6 +1596,13 @@ pkix_pl_Socket_CreateByHostAndPort(
PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort");
PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
+ // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but
+ // we want to ensure nothing can ever hit this code in production.
+#if 1
+ printf("Tor Browser BUG: Attempted pkix direct connect to %s, port %u\n", hostname,
+ portnum);
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+#endif
prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 13252: Do not store data in the app bundle
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit ae86161b6049d43134f271c8f4af43ca8a187398
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Fri Mar 18 14:20:02 2016 -0400
Bug 13252: Do not store data in the app bundle
When --enable-tor-browser-data-outside-app-dir is enabled,
all user data is stored in a directory named
TorBrowser-Data which is located next to the application directory.
Display an informative error message if the TorBrowser-Data
directory cannot be created due to an "access denied" or a
"read only volume" error.
On Mac OS, add support for the --invisible command line option which
is used by the meek-http-helper to avoid showing an icon for the
helper browser on the dock.
---
toolkit/xre/nsAppRunner.cpp | 76 +++++++++++++++---
toolkit/xre/nsXREDirProvider.cpp | 43 +++++-----
toolkit/xre/nsXREDirProvider.h | 6 ++
xpcom/io/TorFileUtils.cpp | 142 +++++++++++++++++++++++++++++++++
xpcom/io/TorFileUtils.h | 33 ++++++++
xpcom/io/moz.build | 5 ++
xpcom/io/nsAppFileLocationProvider.cpp | 53 +++++-------
7 files changed, 290 insertions(+), 68 deletions(-)
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 8de43a8c4cfc..9854332f6917 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1886,6 +1886,8 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
}
}
+// If aUnlocker is NULL, it is also OK for the following arguments to be NULL:
+// aProfileDir, aProfileLocalDir, aResult.
static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
nsIFile* aProfileLocalDir,
ProfileStatus aStatus,
@@ -1894,17 +1896,19 @@ static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
nsIProfileLock** aResult) {
nsresult rv;
- bool exists;
- aProfileDir->Exists(&exists);
- if (!exists) {
- return ProfileMissingDialog(aNative);
+ if (aProfileDir) {
+ bool exists;
+ aProfileDir->Exists(&exists);
+ if (!exists) {
+ return ProfileMissingDialog(aNative);
+ }
}
ScopedXPCOMStartup xpcom;
rv = xpcom.Initialize();
NS_ENSURE_SUCCESS(rv, rv);
- mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
+ if (aProfileDir) mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
rv = xpcom.SetWindowCreator(aNative);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
@@ -1994,7 +1998,8 @@ static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
}
} else {
#ifdef MOZ_WIDGET_ANDROID
- if (java::GeckoAppShell::UnlockProfile()) {
+ if (aProfileDir && aProfileLocalDir && aResult &&
+ java::GeckoAppShell::UnlockProfile()) {
return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nullptr,
aResult);
}
@@ -2102,6 +2107,23 @@ static ReturnAbortOnError ShowProfileManager(
return LaunchChild(false);
}
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+static ProfileStatus CheckTorBrowserDataWriteAccess(nsIFile* aAppDir) {
+ // Check whether we can write to the directory that will contain
+ // TorBrowser-Data.
+ nsCOMPtr<nsIFile> tbDataDir;
+ RefPtr<nsXREDirProvider> dirProvider = nsXREDirProvider::GetSingleton();
+ if (!dirProvider) return PROFILE_STATUS_OTHER_ERROR;
+ nsresult rv =
+ dirProvider->GetTorBrowserUserDataDir(getter_AddRefs(tbDataDir));
+ NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
+ nsCOMPtr<nsIFile> tbDataDirParent;
+ rv = tbDataDir->GetParent(getter_AddRefs(tbDataDirParent));
+ NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
+ return nsToolkitProfileService::CheckProfileWriteAccess(tbDataDirParent);
+}
+#endif
+
static bool gDoMigration = false;
static bool gDoProfileReset = false;
static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
@@ -3178,6 +3200,14 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
#endif
+#if defined(XP_MACOSX) && defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
+ bool hideDockIcon = (CheckArg("invisible") == ARG_FOUND);
+ if (hideDockIcon) {
+ ProcessSerialNumber psn = {0, kCurrentProcess};
+ TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
+ }
+#endif
+
IncreaseDescriptorLimits();
#ifdef USE_GLX_TEST
@@ -4026,7 +4056,34 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
return 0;
}
+#if (defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)) || \
+ defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
+ nsCOMPtr<nsIFile> exeFile, exeDir;
+ bool persistent;
+ rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
+ getter_AddRefs(exeFile));
+ NS_ENSURE_SUCCESS(rv, 1);
+ rv = exeFile->GetParent(getter_AddRefs(exeDir));
+ NS_ENSURE_SUCCESS(rv, 1);
+#endif
+
rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+ if (NS_FAILED(rv)) {
+ // NS_NewToolkitProfileService() returns a generic NS_ERROR_FAILURE error
+ // if creation of the TorBrowser-Data directory fails due to access denied
+ // or because of a read-only disk volume. Do an extra check here to detect
+ // these errors so we can display an informative error message.
+ ProfileStatus status = CheckTorBrowserDataWriteAccess(exeDir);
+ if ((PROFILE_STATUS_ACCESS_DENIED == status) ||
+ (PROFILE_STATUS_READ_ONLY == status)) {
+ ProfileErrorDialog(nullptr, nullptr, status, nullptr, mNativeApp,
+ nullptr);
+ return 1;
+ }
+ }
+ #endif
+
if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
PR_fprintf(PR_STDERR,
"Error: Access was denied while trying to open files in "
@@ -4095,7 +4152,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
// Check for and process any available updates
nsCOMPtr<nsIFile> updRoot;
- bool persistent;
rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
getter_AddRefs(updRoot));
// XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
@@ -4131,12 +4187,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
if (CheckArg("test-process-updates")) {
SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
}
- nsCOMPtr<nsIFile> exeFile, exeDir;
- rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
- getter_AddRefs(exeFile));
- NS_ENSURE_SUCCESS(rv, 1);
- rv = exeFile->GetParent(getter_AddRefs(exeDir));
- NS_ENSURE_SUCCESS(rv, 1);
ProcessUpdates(mDirProvider.GetGREDir(), exeDir, updRoot, gRestartArgc,
gRestartArgv, mAppData->version);
if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
index f80cb2827349..335a340ea3e9 100644
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -51,6 +51,8 @@
# include "nsIPK11Token.h"
#endif
+#include "TorFileUtils.h"
+
#include <stdlib.h>
#ifdef XP_WIN
@@ -1408,34 +1410,18 @@ nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
return gDataDirHome->Clone(aFile);
}
- nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
+ nsresult rv = GetTorBrowserUserDataDir(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
- int levelsToRemove = 1; // In FF21+, appDir points to browser subdirectory.
-#if defined(XP_MACOSX)
- levelsToRemove += 2;
-#endif
- while (localDir && (levelsToRemove > 0)) {
- // When crawling up the hierarchy, components named "." do not count.
- nsAutoCString removedName;
- rv = localDir->GetNativeLeafName(removedName);
- NS_ENSURE_SUCCESS(rv, rv);
- bool didRemove = !removedName.Equals(".");
-
- // Remove a directory component.
- nsCOMPtr<nsIFile> parentDir;
- rv = localDir->GetParent(getter_AddRefs(parentDir));
- NS_ENSURE_SUCCESS(rv, rv);
- localDir = parentDir;
- if (didRemove) --levelsToRemove;
- }
-
- if (!localDir) return NS_ERROR_FAILURE;
-
+#if !defined(ANDROID)
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Browser"));
+#else
rv = localDir->AppendRelativeNativePath(
- NS_LITERAL_CSTRING("TorBrowser" XPCOM_FILE_PATH_SEPARATOR
- "Data" XPCOM_FILE_PATH_SEPARATOR "Browser"));
+ NS_LITERAL_CSTRING("Data" XPCOM_FILE_PATH_SEPARATOR "Browser"));
+#endif
NS_ENSURE_SUCCESS(rv, rv);
+#endif
if (aLocal) {
rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
@@ -1541,6 +1527,15 @@ nsresult nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal) {
return NS_OK;
}
+nsresult nsXREDirProvider::GetTorBrowserUserDataDir(nsIFile** aFile) {
+ NS_ENSURE_ARG_POINTER(aFile);
+ nsCOMPtr<nsIFile> exeFile;
+ bool per = false;
+ nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(exeFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+ return TorBrowser_GetUserDataDir(exeFile, aFile);
+}
+
nsresult nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory) {
nsresult rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
index b9678d4ec577..2aa2face5974 100644
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -113,6 +113,12 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
*/
nsresult GetProfileDir(nsIFile** aResult);
+ /**
+ * Get the TorBrowser user data directory by calling the
+ * TorBrowser_GetUserDataDir() utility function.
+ */
+ nsresult GetTorBrowserUserDataDir(nsIFile** aFile);
+
protected:
nsresult GetFilesInternal(const char* aProperty,
nsISimpleEnumerator** aResult);
diff --git a/xpcom/io/TorFileUtils.cpp b/xpcom/io/TorFileUtils.cpp
new file mode 100644
index 000000000000..bddf8d7bbd95
--- /dev/null
+++ b/xpcom/io/TorFileUtils.cpp
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TorFileUtils.h"
+#include "nsString.h"
+#ifdef MOZ_WIDGET_COCOA
+#include <Carbon/Carbon.h>
+#include "nsILocalFileMac.h"
+#endif
+
+static nsresult GetAppRootDir(nsIFile *aExeFile, nsIFile** aFile);
+
+//-----------------------------------------------------------------------------
+nsresult
+TorBrowser_GetUserDataDir(nsIFile *aExeFile, nsIFile** aFile)
+{
+ NS_ENSURE_ARG_POINTER(aFile);
+ nsCOMPtr<nsIFile> tbDataDir;
+
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+ nsAutoCString tbDataLeafName(NS_LITERAL_CSTRING("TorBrowser-Data"));
+ nsCOMPtr<nsIFile> appRootDir;
+ nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(appRootDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+#ifndef XP_MACOSX
+ // On all platforms except Mac OS, we always operate in a "portable" mode
+ // where the TorBrowser-Data directory is located next to the application.
+ rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = tbDataDir->AppendNative(tbDataLeafName);
+ NS_ENSURE_SUCCESS(rv, rv);
+#else
+ // For Mac OS, determine whether we should store user data in the OS's
+ // standard location (i.e., under ~/Library/Application Support). We use
+ // the OS location if (1) the application is installed in a directory whose
+ // path contains "/Applications" or (2) the TorBrowser-Data directory does
+ // not exist and cannot be created (which probably means we lack write
+ // permission to the directory that contains the application).
+ nsAutoString appRootPath;
+ rv = appRootDir->GetPath(appRootPath);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool useOSLocation = (appRootPath.Find("/Applications",
+ true /* ignore case */) >= 0);
+ if (!useOSLocation) {
+ // We hope to use the portable (aka side-by-side) approach, but before we
+ // commit to that, let's ensure that we can create the TorBrowser-Data
+ // directory. If it already exists, we will try to use it; if not and we
+ // fail to create it, we will switch to ~/Library/Application Support.
+ rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = tbDataDir->AppendNative(tbDataLeafName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool exists = false;
+ rv = tbDataDir->Exists(&exists);
+ if (NS_SUCCEEDED(rv) && !exists)
+ rv = tbDataDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
+ useOSLocation = NS_FAILED(rv);
+ }
+
+ if (useOSLocation) {
+ // We are using ~/Library/Application Support/TorBrowser-Data. We do not
+ // need to create that directory here because the code in nsXREDirProvider
+ // will do so (and the user should always have write permission for
+ // ~/Library/Application Support; if they do not we have no more options).
+ FSRef fsRef;
+ OSErr err = ::FSFindFolder(kUserDomain, kApplicationSupportFolderType,
+ kCreateFolder, &fsRef);
+ NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
+ // To convert the FSRef returned by FSFindFolder() into an nsIFile that
+ // points to ~/Library/Application Support, we first create an empty
+ // nsIFile object (no path) and then use InitWithFSRef() to set the
+ // path.
+ rv = NS_NewNativeLocalFile(EmptyCString(), true,
+ getter_AddRefs(tbDataDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(tbDataDir);
+ if (!dirFileMac)
+ return NS_ERROR_UNEXPECTED;
+ rv = dirFileMac->InitWithFSRef(&fsRef);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = tbDataDir->AppendNative(tbDataLeafName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+#endif
+
+#elif defined(ANDROID)
+ // Tor Browser Android stores data in the app home directory.
+ const char* homeDir = getenv("HOME");
+ if (!homeDir || !*homeDir)
+ return NS_ERROR_FAILURE;
+ nsresult rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
+ getter_AddRefs(tbDataDir));
+#else
+ // User data is embedded within the application directory (i.e.,
+ // TOR_BROWSER_DATA_OUTSIDE_APP_DIR is not defined).
+ nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(tbDataDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = tbDataDir->AppendNative(NS_LITERAL_CSTRING("TorBrowser"));
+ NS_ENSURE_SUCCESS(rv, rv);
+#endif
+
+ tbDataDir.forget(aFile);
+ return NS_OK;
+}
+
+static nsresult
+GetAppRootDir(nsIFile *aExeFile, nsIFile** aFile)
+{
+ NS_ENSURE_ARG_POINTER(aExeFile);
+ NS_ENSURE_ARG_POINTER(aFile);
+ nsCOMPtr<nsIFile> appRootDir = aExeFile;
+
+ int levelsToRemove = 1; // Remove firefox (the executable file).
+#if defined(XP_MACOSX)
+ levelsToRemove += 2; // On Mac OS, we must also remove Contents/MacOS.
+#endif
+ while (appRootDir && (levelsToRemove > 0)) {
+ // When crawling up the hierarchy, components named "." do not count.
+ nsAutoCString removedName;
+ nsresult rv = appRootDir->GetNativeLeafName(removedName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool didRemove = !removedName.Equals(".");
+
+ // Remove a directory component.
+ nsCOMPtr<nsIFile> parentDir;
+ rv = appRootDir->GetParent(getter_AddRefs(parentDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+ appRootDir = parentDir;
+
+ if (didRemove)
+ --levelsToRemove;
+ }
+
+ if (!appRootDir)
+ return NS_ERROR_FAILURE;
+
+ appRootDir.forget(aFile);
+ return NS_OK;
+}
diff --git a/xpcom/io/TorFileUtils.h b/xpcom/io/TorFileUtils.h
new file mode 100644
index 000000000000..d5e86abf9685
--- /dev/null
+++ b/xpcom/io/TorFileUtils.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TorFileUtils_h__
+#define TorFileUtils_h__
+
+#include "nsIFile.h"
+
+/**
+ * TorBrowser_GetUserDataDir
+ *
+ * Retrieve the Tor Browser user data directory.
+ * When built with --enable-tor-browser-data-outside-app-dir, the directory
+ * is next to the application directory, except on Mac OS where it may be
+ * there or it may be at ~/Library/Application Support/TorBrowser-Data (the
+ * latter location is used if the .app bundle is in a directory whose path
+ * contains /Applications or if we lack write access to the directory that
+ * contains the .app).
+ * When built without --enable-tor-browser-data-outside-app-dir, this
+ * directory is TorBrowser.app/TorBrowser.
+ *
+ * @param aExeFile The firefox executable.
+ * @param aFile Out parameter that is set to the Tor Browser user data
+ * directory.
+ * @return NS_OK on success. Error otherwise.
+ */
+extern nsresult
+TorBrowser_GetUserDataDir(nsIFile *aExeFile, nsIFile** aFile);
+
+#endif // !TorFileUtils_h__
diff --git a/xpcom/io/moz.build b/xpcom/io/moz.build
index a165b491bc56..b0eb74f4c56d 100644
--- a/xpcom/io/moz.build
+++ b/xpcom/io/moz.build
@@ -86,6 +86,7 @@ EXPORTS += [
'nsUnicharInputStream.h',
'nsWildCard.h',
'SpecialSystemDirectory.h',
+ 'TorFileUtils.h',
]
EXPORTS.mozilla += [
@@ -135,6 +136,10 @@ UNIFIED_SOURCES += [
'SpecialSystemDirectory.cpp',
]
+SOURCES += [
+ 'TorFileUtils.cpp',
+]
+
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
SOURCES += [
'CocoaFileUtils.mm',
diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp
index 81551a8e3893..9f95e5cbec2d 100644
--- a/xpcom/io/nsAppFileLocationProvider.cpp
+++ b/xpcom/io/nsAppFileLocationProvider.cpp
@@ -28,6 +28,8 @@
# include <sys/param.h>
#endif
+#include "TorFileUtils.h"
+
// WARNING: These hard coded names need to go away. They need to
// come from localizable resources
@@ -234,8 +236,14 @@ nsresult nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile) {
// GetProductDirectory - Gets the directory which contains the application data
// folder
//
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+// UNIX and WIN : <App Folder>/../TorBrowser-Data/Browser
+// Mac : <App Folder>/../../../TorBrowser-Data/Browser OR
+// ~/Library/Application Support/TorBrowser-Data/Browser
+#else
// UNIX and WIN : <App Folder>/TorBrowser/Data/Browser
// Mac : <App Folder>/../../TorBrowser/Data/Browser
+#endif
//----------------------------------------------------------------------------------------
nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
bool aLocal) {
@@ -243,42 +251,25 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
return NS_ERROR_INVALID_ARG;
}
- nsresult rv;
+ nsresult rv = NS_ERROR_UNEXPECTED;
bool exists;
- nsCOMPtr<nsIFile> localDir;
+ nsCOMPtr<nsIFile> localDir, exeFile;
- rv = CloneMozBinDirectory(getter_AddRefs(localDir));
+ nsCOMPtr<nsIProperties> directoryService(
+ do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = directoryService->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
+ getter_AddRefs(exeFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = TorBrowser_GetUserDataDir(exeFile, getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
- int levelsToRemove = 1; // In FF21+, bin dir points to browser subdirectory.
-#if defined(XP_MACOSX)
- levelsToRemove += 2;
-#endif
- while (localDir && (levelsToRemove > 0)) {
- // When crawling up the hierarchy, components named "." do not count.
- nsAutoCString removedName;
- rv = localDir->GetNativeLeafName(removedName);
- NS_ENSURE_SUCCESS(rv, rv);
- bool didRemove = !removedName.Equals(".");
-
- // Remove a directory component.
- nsCOMPtr<nsIFile> parentDir;
- rv = localDir->GetParent(getter_AddRefs(parentDir));
- NS_ENSURE_SUCCESS(rv, rv);
- localDir = parentDir;
-
- if (didRemove) {
- --levelsToRemove;
- }
- }
-
- if (!localDir) {
- return NS_ERROR_FAILURE;
- }
-
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Browser"));
+#else
rv = localDir->AppendRelativeNativePath(
- NS_LITERAL_CSTRING("TorBrowser" XPCOM_FILE_PATH_SEPARATOR
- "Data" XPCOM_FILE_PATH_SEPARATOR "Browser"));
+ NS_LITERAL_CSTRING("Data" XPCOM_FILE_PATH_SEPARATOR "Browser"));
+#endif
NS_ENSURE_SUCCESS(rv, rv);
if (aLocal) {
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 16620: Clear window.name when no referrer sent
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 6e6decf232840962c66292c198cea963ad37a7e2
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Fri Oct 30 14:28:13 2015 -0400
Bug 16620: Clear window.name when no referrer sent
Convert JS implementation (within Torbutton) to a C++ browser patch.
---
docshell/base/nsDocShell.cpp | 60 +++++++
docshell/test/mochitest/mochitest.ini | 3 +
docshell/test/mochitest/test_tor_bug16620.html | 211 +++++++++++++++++++++++++
docshell/test/mochitest/tor_bug16620.html | 51 ++++++
docshell/test/mochitest/tor_bug16620_form.html | 51 ++++++
5 files changed, 376 insertions(+)
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index d0aa79344605..22eb5c4556f6 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7476,11 +7476,71 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType,
aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
}
FirePageHideNotification(!mSavingOldViewer);
+
if (mIsBeingDestroyed) {
// Force to stop the newly created orphaned viewer.
viewer->Stop();
return NS_ERROR_DOCSHELL_DYING;
}
+
+ // Tor bug 16620: Clear window.name of top-level documents if
+ // there is no referrer. We make an exception for new windows,
+ // e.g., window.open(url, "MyName").
+ bool isNewWindowTarget = false;
+ nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aRequest, &rv));
+ if (props) {
+ props->GetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
+ &isNewWindowTarget);
+ }
+
+ if (!isNewWindowTarget) {
+ nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aOpenedChannel));
+ nsCOMPtr<nsIURI> httpReferrer;
+ if (httpChannel) {
+ nsCOMPtr<nsIReferrerInfo> referrerInfo;
+ rv = httpChannel->GetReferrerInfo(getter_AddRefs(referrerInfo));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (referrerInfo) {
+ // We want GetComputedReferrer() instead of GetOriginalReferrer(), since
+ // the former takes into consideration referrer policy, protocol
+ // whitelisting...
+ httpReferrer = referrerInfo->GetComputedReferrer();
+ }
+ }
+
+ bool isTopFrame = mBrowsingContext->IsTop();
+
+#ifdef DEBUG_WINDOW_NAME
+ printf("DOCSHELL %p CreateContentViewer - possibly clearing window.name:\n",
+ this);
+ printf(" current window.name: \"%s\"\n",
+ NS_ConvertUTF16toUTF8(mName).get());
+
+ nsAutoCString curSpec, loadingSpec;
+ if (this->mCurrentURI) mCurrentURI->GetSpec(curSpec);
+ if (mLoadingURI) mLoadingURI->GetSpec(loadingSpec);
+ printf(" current URI: %s\n", curSpec.get());
+ printf(" loading URI: %s\n", loadingSpec.get());
+ printf(" is top document: %s\n", isTopFrame ? "Yes" : "No");
+
+ if (!httpReferrer) {
+ printf(" referrer: None\n");
+ } else {
+ nsAutoCString refSpec;
+ httpReferrer->GetSpec(refSpec);
+ printf(" referrer: %s\n", refSpec.get());
+ }
+#endif
+
+ bool clearName = isTopFrame && !httpReferrer;
+ if (clearName) SetName(NS_LITERAL_STRING(""));
+
+#ifdef DEBUG_WINDOW_NAME
+ printf(" action taken: %s window.name\n",
+ clearName ? "Cleared" : "Preserved");
+#endif
+ }
+
mLoadingURI = nullptr;
// Set mFiredUnloadEvent = false so that the unload handler for the
diff --git a/docshell/test/mochitest/mochitest.ini b/docshell/test/mochitest/mochitest.ini
index 25d3187711fe..663750b7fc8e 100644
--- a/docshell/test/mochitest/mochitest.ini
+++ b/docshell/test/mochitest/mochitest.ini
@@ -52,6 +52,8 @@ support-files =
start_historyframe.html
url1_historyframe.html
url2_historyframe.html
+ tor_bug16620.html
+ tor_bug16620_form.html
[test_anchor_scroll_after_document_open.html]
[test_bfcache_plus_hash.html]
@@ -115,6 +117,7 @@ support-files = file_bug675587.html
[test_framedhistoryframes.html]
support-files = file_framedhistoryframes.html
[test_pushState_after_document_open.html]
+[test_tor_bug16620.html]
[test_windowedhistoryframes.html]
[test_triggeringprincipal_location_seturi.html]
[test_bug1507702.html]
diff --git a/docshell/test/mochitest/test_tor_bug16620.html b/docshell/test/mochitest/test_tor_bug16620.html
new file mode 100644
index 000000000000..46fff5a04711
--- /dev/null
+++ b/docshell/test/mochitest/test_tor_bug16620.html
@@ -0,0 +1,211 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+ Tor Bug 16620: Clear window.name when no referrer sent.
+ https://trac.torproject.org/projects/tor/ticket/16620
+-->
+<meta charset="utf-8">
+<head>
+ <title>Test for Tor Bug 16620 - Clear window.name when no referrer sent</title>
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/16620">Tor Bug 16620</a>
+<script>
+// ## Test constants
+const kTestPath = "/tests/docshell/test/mochitest/";
+const kLinkFile = "tor_bug16620.html";
+const kFormFile = "tor_bug16620_form.html";
+const kBaseURL1 = "http://example.com";
+const kBaseURL1_https = "https://example.com";
+const kBaseURL2 = "http://example.net";
+const kSendReferrerPref = "network.http.sendRefererHeader";
+const kSendReferrerNever = 0;
+const kSendReferrerForUserAction = 1;
+const kSendReferrerAlways = 2;
+
+let gTests = [
+ // Test #1: Same domain; never send referrer.
+ { startURL: kBaseURL1, destURL: kBaseURL1,
+ referrerPref: kSendReferrerNever,
+ expectIsolation: true },
+
+ // Test #2: Same domain; send referrer upon user action.
+ { startURL: kBaseURL1, destURL: kBaseURL1,
+ referrerPref: kSendReferrerForUserAction,
+ expectIsolation: false },
+
+ // Test #3: Same domain; always send referrer.
+ { startURL: kBaseURL1, destURL: kBaseURL1,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: false },
+
+ // Test #4: Different top-level domains; never send referrer.
+ { startURL: kBaseURL1, destURL: kBaseURL2,
+ referrerPref: kSendReferrerNever,
+ expectIsolation: true },
+
+ // Test #5: Different top-level domains; send referrer upon user action.
+ { startURL: kBaseURL1, destURL: kBaseURL2,
+ referrerPref: kSendReferrerForUserAction,
+ expectIsolation: false },
+
+ // Test #6: Different top-level domains; always send referrer.
+ { startURL: kBaseURL1, destURL: kBaseURL2,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: false },
+
+ // Test #7: https -> http transition.
+ { startURL: kBaseURL1_https, destURL: kBaseURL1,
+ referrerPref: kSendReferrerForUserAction,
+ expectIsolation: true },
+
+ // Test #8: Same domain, rel="noreferrer" on link.
+ { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerOnLink: true,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: true },
+
+ // Test #9: Same domain, "no-referrer" meta tag in document.
+ { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: true },
+
+ // Test #10: Like test #9, but reset window.name during unload.
+ // (similar to http://www.thomasfrank.se/sessvarsTestPage1.html)
+ { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true,
+ resetInUnload: true,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: true },
+
+ // Test #11: Data URL as destination (no referrer).
+ { startURL: kBaseURL1,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: true },
+
+ // Test #12: Ensure that window.name is preserved when a dynamically loaded
+ // iframe is used to perform a form post (regression test for Tor bug 18168).
+ { startURL: kBaseURL1,
+ isFormTest: true,
+ referrerPref: kSendReferrerAlways,
+ expectIsolation: false },
+];
+
+let gCurTest = 0;
+let gCurWinName, gChildWin, gDataURL;
+
+// ## Utility functions
+function generateRandomName()
+{
+ // Generate a random 6 character string using 0-9 and a-z.
+ return ((1 + Math.random()).toString(36) + '000000').substr(2, 6);
+}
+
+function startNextTest() {
+ ++gCurTest;
+ if (gCurTest > gTests.length) {
+ SimpleTest.finish();
+ } else {
+ let curTest = gTests[gCurTest - 1];
+ if ("referrerPref" in curTest)
+ SpecialPowers.setIntPref(kSendReferrerPref, curTest.referrerPref);
+ else
+ SpecialPowers.setIntPref(kSendReferrerPref, kSendReferrerForUserAction);
+ gCurWinName = generateRandomName();
+ let url = curTest.startURL + kTestPath;
+ if (curTest.isFormTest === true) {
+ url += kFormFile + "?" + gCurWinName;
+ gChildWin = window.open(url, undefined);
+ } else {
+ url += kLinkFile + "?firstDocLoaded";
+ gChildWin = window.open(url, gCurWinName);
+ }
+ }
+}
+
+// ## Add a message event listener.
+window.addEventListener("message", function(aEvent) {
+ if (aEvent.source !== gChildWin)
+ return;
+
+// console.log("parent received message:" + JSON.stringify(aEvent.data));
+
+ let proceedToNextTest = false;
+ let curTest = gTests[gCurTest - 1];
+ let state = aEvent.data.state;
+ let winName = aEvent.data.winName;
+ if ("firstDocLoaded" == state) {
+ // Process response from step one of the link-based tests.
+ let step1Passed = (winName === gCurWinName);
+ if (!step1Passed) {
+ ok(step1Passed, "Test #" + gCurTest +
+ " - first document's name matches window.open parameter");
+ proceedToNextTest = true;
+ }
+
+ // Send an "openURL" message to the loaded document.
+ let url2 = (curTest.destURL)
+ ? curTest.destURL + kTestPath + kLinkFile + "?secondDocLoaded"
+ : gDataURL;
+ let noReferrerOnLink = (curTest.noReferrerOnLink === true);
+ let noReferrerInMetaTag = (curTest.noReferrerInMetaTag === true);
+ let resetInUnload = (curTest.resetInUnload === true);
+ aEvent.source.postMessage({ action: "openURL", url: url2,
+ noReferrerOnLink: noReferrerOnLink,
+ noReferrerInMetaTag: noReferrerInMetaTag,
+ resetInUnload: resetInUnload },
+ "*");
+ } else if ("secondDocLoaded" == state) {
+ // Process response from step two of the link-based tests.
+ if (curTest.expectIsolation) {
+ ok(winName === "",
+ "Test #" + gCurTest + " - second document: name was cleared");
+ } else {
+ ok(winName === gCurWinName,
+ "Test #" + gCurTest + " - second document: name was preserved");
+ }
+ proceedToNextTest = true;
+ } else if ("formPostDone" == state) {
+ // Process response from the form post tests.
+ if (curTest.expectIsolation) {
+ ok(winName === "",
+ "Test #" + gCurTest + " - iframe form post: name was cleared");
+ } else {
+ ok(winName === gCurWinName,
+ "Test #" + gCurTest + " - iframe form post: name was preserved");
+ }
+ proceedToNextTest = true;
+
+ }
+
+ if (proceedToNextTest) {
+ gChildWin.close();
+ startNextTest();
+ }
+ }, false);
+
+ SimpleTest.waitForExplicitFinish();
+
+ if (SpecialPowers.getBoolPref("security.nocertdb")) {
+ // Mochitests don't simulate https correctly with "security.nocertdb"
+ // enabled. See https://bugs.torproject.org/18087
+ ok(false, "Please disable the pref `security.nocertdb` before running this test.");
+ SimpleTest.finish();
+ } else {
+
+ // Read file contents, construct a data URL (used by some tests), and
+ // then start the first test.
+ let url = kTestPath + kLinkFile;
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", url);
+ xhr.onload = function() {
+ gDataURL = "data:text/html;charset=utf-8,"
+ + encodeURIComponent(this.responseText);
+ startNextTest();
+ }
+ xhr.send();
+ }
+</script>
+</body>
+</html>
diff --git a/docshell/test/mochitest/tor_bug16620.html b/docshell/test/mochitest/tor_bug16620.html
new file mode 100644
index 000000000000..26b8e406bbff
--- /dev/null
+++ b/docshell/test/mochitest/tor_bug16620.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+ Tor Bug 16620: Clear window.name when no referrer sent.
+ https://trac.torproject.org/projects/tor/ticket/16620
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Supporting Doc for Tor Bug 16620 Tests</title>
+</head>
+<body>
+<a id="link" href="">secondDoc</a>
+
+<script>
+// Extract test state from our query string, defaulting to
+// "secondDocLoaded" to support use of this HTML content within
+// a data URI (where query strings are not supported).
+let state = (location.search.length > 0) ? location.search.substr(1)
+ : "secondDocLoaded";
+
+// Notify the test driver.
+opener.postMessage({ state: state, winName: window.name }, "*");
+
+// Add a message event listener to process "openURL" actions.
+window.addEventListener("message", function(aEvent) {
+ if (aEvent.data.action == "openURL") {
+ if (aEvent.data.noReferrerInMetaTag) {
+ let metaElem = document.createElement("meta");
+ metaElem.name = "referrer";
+ metaElem.content = "no-referrer";
+ document.head.appendChild(metaElem);
+ }
+
+ let linkElem = document.getElementById("link");
+ linkElem.href = aEvent.data.url;
+ if (aEvent.data.noReferrerOnLink)
+ linkElem.rel = "noreferrer";
+
+ if (aEvent.data.resetInUnload) {
+ let tmpName = window.name;
+ window.addEventListener("unload", function() {
+ window.name = tmpName;
+ }, false);
+ }
+
+ linkElem.click();
+ }
+}, false);
+</script>
+</body>
+</html>
diff --git a/docshell/test/mochitest/tor_bug16620_form.html b/docshell/test/mochitest/tor_bug16620_form.html
new file mode 100644
index 000000000000..279f62e63fab
--- /dev/null
+++ b/docshell/test/mochitest/tor_bug16620_form.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+ Tor Bug 16620: Clear window.name when no referrer sent.
+ https://trac.torproject.org/projects/tor/ticket/16620
+
+ Regression test for bug 18168: iframe-based AJAX call opening in new tab
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Supporting Form-based Doc for Tor Bug 16620 Tests</title>
+</head>
+<body>
+
+<script>
+document.addEventListener("DOMContentLoaded", function () {
+ addPostTarget();
+}, false);
+
+
+function addPostTarget()
+{
+ let frameName = location.search.substr(1);
+ let form = document.getElementById("postform");
+ let iframe = document.createElement("iframe");
+ iframe.style.border = "1px solid red";
+ iframe.src = "about:blank";
+ form.target = iframe.name = iframe.id = frameName;
+ document.body.appendChild(iframe);
+
+ let didSubmit = false;
+ iframe.onload = function() {
+ if (!didSubmit) {
+ didSubmit = true;
+ let submitButton = document.getElementById("submitButton");
+ submitButton.click();
+ } else {
+ // Form submission complete. Report iframe's name to test driver.
+ opener.postMessage({ state: "formPostDone", winName: iframe.name }, "*");
+ }
+ };
+}
+
+</script>
+<form name="postform" id="postform"
+ action="data:text/plain;charset=utf-8,Hello%20world"
+ method="POST" enctype="multipart/form-data">
+ <input type="hidden" name="field1" value="value1"><br>
+ <input id="submitButton" type="submit" value="Post It">
+</body>
+</html>
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 18821: Disable libmdns for Android and Desktop
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 39cc4793ba8100032caf1105bc090019f750032e
Author: Georg Koppen <gk(a)torproject.org>
Date: Wed Apr 20 14:34:50 2016 +0000
Bug 18821: Disable libmdns for Android and Desktop
There should be no need to remove the OS X support introduced in
https://bugzilla.mozilla.org/show_bug.cgi?id=1225726 as enabling this
is governed by a preference (which is actually set to `false`). However,
we remove it at build time as well (defense in depth).
This is basically a backout of the relevant passages of
https://hg.mozilla.org/mozilla-central/rev/6bfb430de85d,
https://hg.mozilla.org/mozilla-central/rev/609b337bf7ab and
https://hg.mozilla.org/mozilla-central/rev/8e092ec5fbbd.
Fixed bug 21861 (Disable additional mDNS code to avoid proxy bypasses)
as well.
---
dom/presentation/provider/components.conf | 10 ----------
dom/presentation/provider/moz.build | 1 -
netwerk/dns/mdns/libmdns/components.conf | 15 ---------------
netwerk/dns/mdns/libmdns/moz.build | 28 ----------------------------
4 files changed, 54 deletions(-)
diff --git a/dom/presentation/provider/components.conf b/dom/presentation/provider/components.conf
index 04cb28ec757e..56994ed7cd94 100644
--- a/dom/presentation/provider/components.conf
+++ b/dom/presentation/provider/components.conf
@@ -6,9 +6,6 @@
categories = {}
-if buildconfig.substs['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'android'):
- categories["presentation-device-provider"] = "MulticastDNSDeviceProvider"
-
Classes = [
{
'cid': '{f4079b8b-ede5-4b90-a112-5b415a931deb}',
@@ -16,11 +13,4 @@ Classes = [
'jsm': 'resource://gre/modules/PresentationControlService.jsm',
'constructor': 'PresentationControlService',
},
- {
- 'cid': '{814f947a-52f7-41c9-94a1-3684797284ac}',
- 'contract_ids': ['@mozilla.org/presentation-device/multicastdns-provider;1'],
- 'type': 'mozilla::dom::presentation::MulticastDNSDeviceProvider',
- 'headers': ['/dom/presentation/provider/MulticastDNSDeviceProvider.h'],
- 'categories': categories,
- },
]
diff --git a/dom/presentation/provider/moz.build b/dom/presentation/provider/moz.build
index eaea61af415a..d97b75ddbcf9 100644
--- a/dom/presentation/provider/moz.build
+++ b/dom/presentation/provider/moz.build
@@ -10,7 +10,6 @@ EXTRA_JS_MODULES += [
UNIFIED_SOURCES += [
'DeviceProviderHelpers.cpp',
- 'MulticastDNSDeviceProvider.cpp',
]
XPCOM_MANIFESTS += [
diff --git a/netwerk/dns/mdns/libmdns/components.conf b/netwerk/dns/mdns/libmdns/components.conf
index 6e64140c820e..1b50dbf673a4 100644
--- a/netwerk/dns/mdns/libmdns/components.conf
+++ b/netwerk/dns/mdns/libmdns/components.conf
@@ -5,20 +5,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
Classes = [
- {
- 'cid': '{14a50f2b-7ff6-48a5-88e3-615fd111f5d3}',
- 'contract_ids': ['@mozilla.org/toolkit/components/mdnsresponder/dns-info;1'],
- 'type': 'mozilla::net::nsDNSServiceInfo',
- 'headers': ['/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.h'],
- },
]
-if buildconfig.substs['MOZ_WIDGET_TOOLKIT'] != 'cocoa':
- Classes += [
- {
- 'cid': '{f9346d98-f27a-4e89-b744-493843416480}',
- 'contract_ids': ['@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1'],
- 'jsm': 'resource://gre/modules/DNSServiceDiscovery.jsm',
- 'constructor': 'nsDNSServiceDiscovery',
- },
- ]
diff --git a/netwerk/dns/mdns/libmdns/moz.build b/netwerk/dns/mdns/libmdns/moz.build
index 05dc75eb9eda..a6fc1a8a559a 100644
--- a/netwerk/dns/mdns/libmdns/moz.build
+++ b/netwerk/dns/mdns/libmdns/moz.build
@@ -4,34 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
- UNIFIED_SOURCES += [
- 'MDNSResponderOperator.cpp',
- 'MDNSResponderReply.cpp',
- 'nsDNSServiceDiscovery.cpp',
- ]
-
- LOCAL_INCLUDES += [
- '/netwerk/base',
- ]
-
-else:
- EXTRA_JS_MODULES += [
- 'DNSServiceDiscovery.jsm',
- 'fallback/DataReader.jsm',
- 'fallback/DataWriter.jsm',
- 'fallback/DNSPacket.jsm',
- 'fallback/DNSRecord.jsm',
- 'fallback/DNSResourceRecord.jsm',
- 'fallback/DNSTypes.jsm',
- 'fallback/MulticastDNS.jsm',
- ]
-
- if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
- EXTRA_JS_MODULES += [
- 'MulticastDNSAndroid.jsm',
- ]
-
UNIFIED_SOURCES += [
'nsDNSServiceInfo.cpp',
]
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 18800: Remove localhost DNS lookup in nsProfileLock.cpp
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 280f21cd4bbe8be38eeafdc7453e672a932f262c
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Thu Apr 21 10:40:26 2016 -0400
Bug 18800: Remove localhost DNS lookup in nsProfileLock.cpp
Instead of using the local computer's IP address within
symlink-based profile lock signatures, always use 127.0.0.1.
---
toolkit/profile/nsProfileLock.cpp | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/toolkit/profile/nsProfileLock.cpp b/toolkit/profile/nsProfileLock.cpp
index 25c4f5a79e56..1942815e3446 100644
--- a/toolkit/profile/nsProfileLock.cpp
+++ b/toolkit/profile/nsProfileLock.cpp
@@ -289,18 +289,17 @@ nsresult nsProfileLock::LockWithSymlink(nsIFile* aLockFile,
if (!mReplacedLockTime)
aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime);
+ // For Tor Browser, avoid a DNS lookup here so the Tor network is not
+ // bypassed. Instead, always use 127.0.0.1 for the IP address portion
+ // of the lock signature, which may cause the browser to refuse to
+ // start in the rare event that all of the following conditions are met:
+ // 1. The browser profile is on a network file system.
+ // 2. The file system does not support fcntl() locking.
+ // 3. Tor Browser is run from two different computers at the same time.
+
struct in_addr inaddr;
inaddr.s_addr = htonl(INADDR_LOOPBACK);
- char hostname[256];
- PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname);
- if (status == PR_SUCCESS) {
- char netdbbuf[PR_NETDB_BUF_SIZE];
- PRHostEnt hostent;
- status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent);
- if (status == PR_SUCCESS) memcpy(&inaddr, hostent.h_addr, sizeof inaddr);
- }
-
mozilla::SmprintfPointer signature =
mozilla::Smprintf("%s:%s%lu", inet_ntoa(inaddr),
aHaveFcntlLock ? "+" : "", (unsigned long)getpid());
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 11641: change TBB directory structure to be more like Firefox's
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 679c7e3622f6050706046028ef3beb22cac9cd6f
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Tue Apr 29 13:08:24 2014 -0400
Bug 11641: change TBB directory structure to be more like Firefox's
Unless the -osint command line flag is used, the browser now defaults
to the equivalent of -no-remote. There is a new -allow-remote flag that
may be used to restore the original (Firefox-like) default behavior.
---
toolkit/xre/nsAppRunner.cpp | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 9854332f6917..69006b49250e 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1429,8 +1429,10 @@ static void DumpHelp() {
" --migration Start with migration wizard.\n"
" --ProfileManager Start with ProfileManager.\n"
#ifdef MOZ_HAS_REMOTE
- " --no-remote Do not accept or send remote commands; implies\n"
+ " --no-remote (default) Do not accept or send remote commands; "
+ "implies\n"
" --new-instance.\n"
+ " --allow-remote Accept and send remote commands.\n"
" --new-instance Open new instance, not a new window in running "
"instance.\n"
#endif
@@ -3543,16 +3545,25 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
gSafeMode);
#if defined(MOZ_HAS_REMOTE)
+ // In Tor Browser, remoting is disabled by default unless -osint is used.
+ bool allowRemote = (CheckArg("allow-remote") == ARG_FOUND);
+ bool isOsint = (CheckArg("osint", nullptr, CheckArgFlag::None) == ARG_FOUND);
+ if (!allowRemote && !isOsint) {
+ SaveToEnv("MOZ_NO_REMOTE=1");
+ }
// Handle --no-remote and --new-instance command line arguments. Setup
// the environment to better accommodate other components and various
// restart scenarios.
ar = CheckArg("no-remote");
- if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) {
+ if ((ar == ARG_FOUND) && allowRemote) {
+ PR_fprintf(PR_STDERR,
+ "Error: argument --no-remote is invalid when argument "
+ "--allow-remote is specified\n");
+ return 1;
+ }
+ if (EnvHasValue("MOZ_NO_REMOTE")) {
mDisableRemoteClient = true;
mDisableRemoteServer = true;
- if (!EnvHasValue("MOZ_NO_REMOTE")) {
- SaveToEnv("MOZ_NO_REMOTE=1");
- }
}
ar = CheckArg("new-instance");
1
0
[tor-browser/tor-browser-78.13.0esr-11.0-1] Bug 19273: Avoid JavaScript patching of the external app helper dialog.
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit baeefaced69a711994ca28afe45c391130438b38
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Tue Jun 28 15:13:05 2016 -0400
Bug 19273: Avoid JavaScript patching of the external app helper dialog.
When handling an external URI or downloading a file, invoke Torbutton's
external app blocker component (which will present a download warning
dialog unless the user has checked the "Automatically download files
from now on" box).
For e10s compatibility, avoid using a modal dialog and instead use
a callback interface (nsIHelperAppWarningLauncher) to allow Torbutton
to indicate the user's desire to cancel or continue each request.
Other bugs fixed:
Bug 21766: Crash with e10s enabled while trying to download a file
Bug 21886: Download is stalled in non-e10s mode
Bug 22471: Downloading files via the PDF viewer download button is broken
Bug 22472: Fix FTP downloads when external helper app dialog is shown
Bug 22610: Avoid crashes when canceling external helper app downloads
Bug 22618: Downloading pdf file via file:/// is stalling
---
.../exthandler/nsExternalHelperAppService.cpp | 202 +++++++++++++++++----
uriloader/exthandler/nsExternalHelperAppService.h | 3 +
.../exthandler/nsIExternalHelperAppService.idl | 47 +++++
3 files changed, 217 insertions(+), 35 deletions(-)
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 4ff7ed2e27cc..0dcc1d3ed6ab 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -132,6 +132,9 @@ static const char NEVER_ASK_FOR_SAVE_TO_DISK_PREF[] =
static const char NEVER_ASK_FOR_OPEN_FILE_PREF[] =
"browser.helperApps.neverAsk.openFile";
+static const char WARNING_DIALOG_CONTRACT_ID[] =
+ "@torproject.org/torbutton-extAppBlocker;1";
+
// Helper functions for Content-Disposition headers
/**
@@ -388,6 +391,22 @@ static nsresult GetDownloadDirectory(nsIFile** _directory,
return NS_OK;
}
+static already_AddRefed<nsIInterfaceRequestor> GetDialogParentAux(
+ BrowsingContext* aBrowsingContext, nsIInterfaceRequestor* aWindowContext) {
+ nsCOMPtr<nsIInterfaceRequestor> dialogParent = aWindowContext;
+
+ if (!dialogParent && aBrowsingContext) {
+ dialogParent = do_QueryInterface(aBrowsingContext->GetDOMWindow());
+ }
+ if (!dialogParent && aBrowsingContext && XRE_IsParentProcess()) {
+ RefPtr<Element> element = aBrowsingContext->Top()->GetEmbedderElement();
+ if (element) {
+ dialogParent = do_QueryInterface(element->OwnerDoc()->GetWindow());
+ }
+ }
+ return dialogParent.forget();
+}
+
/**
* Structure for storing extension->type mappings.
* @see defaultMimeEntries
@@ -544,6 +563,111 @@ static const nsDefaultMimeTypeEntry nonDecodableExtensions[] = {
{APPLICATION_COMPRESS, "z"},
{APPLICATION_GZIP, "svgz"}};
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+// begin nsExternalLoadURIHandler class definition and implementation
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+class nsExternalLoadURIHandler final : public nsIHelperAppWarningLauncher {
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIHELPERAPPWARNINGLAUNCHER
+
+ nsExternalLoadURIHandler(nsIHandlerInfo* aHandlerInfo, nsIURI* aURI,
+ nsIPrincipal* aTriggeringPrincipal,
+ BrowsingContext* aBrowsingContext);
+
+ protected:
+ ~nsExternalLoadURIHandler();
+
+ nsCOMPtr<nsIHandlerInfo> mHandlerInfo;
+ nsCOMPtr<nsIURI> mURI;
+ nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+ RefPtr<BrowsingContext> mBrowsingContext;
+ nsCOMPtr<nsIHelperAppWarningDialog> mWarningDialog;
+};
+
+NS_IMPL_ADDREF(nsExternalLoadURIHandler)
+NS_IMPL_RELEASE(nsExternalLoadURIHandler)
+
+NS_INTERFACE_MAP_BEGIN(nsExternalLoadURIHandler)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHelperAppWarningLauncher)
+ NS_INTERFACE_MAP_ENTRY(nsIHelperAppWarningLauncher)
+NS_INTERFACE_MAP_END
+
+nsExternalLoadURIHandler::nsExternalLoadURIHandler(
+ nsIHandlerInfo* aHandlerInfo, nsIURI* aURI,
+ nsIPrincipal* aTriggeringPrincipal, BrowsingContext* aBrowsingContext)
+ : mHandlerInfo(aHandlerInfo),
+ mURI(aURI),
+ mTriggeringPrincipal(aTriggeringPrincipal),
+ mBrowsingContext(aBrowsingContext)
+
+{
+ nsresult rv = NS_OK;
+ mWarningDialog = do_CreateInstance(WARNING_DIALOG_CONTRACT_ID, &rv);
+ if (NS_SUCCEEDED(rv) && mWarningDialog) {
+ // This will create a reference cycle (the dialog holds a reference to us
+ // as nsIHelperAppWarningLauncher), which will be broken in ContinueRequest
+ // or CancelRequest.
+ nsCOMPtr<nsIInterfaceRequestor> dialogParent =
+ GetDialogParentAux(aBrowsingContext, nullptr);
+ rv = mWarningDialog->MaybeShow(this, dialogParent);
+ }
+
+ if (NS_FAILED(rv)) {
+ // If for some reason we could not open the download warning prompt,
+ // continue with the request.
+ ContinueRequest();
+ }
+}
+
+nsExternalLoadURIHandler::~nsExternalLoadURIHandler() {}
+
+NS_IMETHODIMP nsExternalLoadURIHandler::ContinueRequest() {
+ MOZ_ASSERT(mURI);
+ MOZ_ASSERT(mHandlerInfo);
+
+ // Break our reference cycle with the download warning dialog (set up in
+ // LoadURI).
+ mWarningDialog = nullptr;
+
+ nsHandlerInfoAction preferredAction;
+ mHandlerInfo->GetPreferredAction(&preferredAction);
+ bool alwaysAsk = true;
+ mHandlerInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
+
+ nsresult rv = NS_OK;
+ // If we are not supposed to ask, and the preferred action is to use
+ // a helper app or the system default, we just launch the URI.
+ if (!alwaysAsk && (preferredAction == nsIHandlerInfo::useHelperApp ||
+ preferredAction == nsIHandlerInfo::useSystemDefault)) {
+ rv = mHandlerInfo->LaunchWithURI(mURI, mBrowsingContext);
+ // We are not supposed to ask, but when file not found the user most likely
+ // uninstalled the application which handles the uri so we will continue
+ // by application chooser dialog.
+ if (rv != NS_ERROR_FILE_NOT_FOUND) {
+ return rv;
+ }
+ }
+
+ nsCOMPtr<nsIContentDispatchChooser> chooser =
+ do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return chooser->Ask(mHandlerInfo, mURI, mTriggeringPrincipal,
+ mBrowsingContext,
+ nsIContentDispatchChooser::REASON_CANNOT_HANDLE);
+}
+
+NS_IMETHODIMP nsExternalLoadURIHandler::CancelRequest(nsresult aReason) {
+ NS_ENSURE_ARG(NS_FAILED(aReason));
+
+ // Break our reference cycle with the download warning dialog (set up in
+ // LoadURI).
+ mWarningDialog = nullptr;
+
+ return NS_OK;
+}
+
static StaticRefPtr<nsExternalHelperAppService> sExtHelperAppSvcSingleton;
/**
@@ -570,6 +694,9 @@ nsExternalHelperAppService::GetSingleton() {
return do_AddRef(sExtHelperAppSvcSingleton);
}
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+// nsExternalHelperAppService definition and implementation
+//////////////////////////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS(nsExternalHelperAppService, nsIExternalHelperAppService,
nsPIExternalAppLauncher, nsIExternalProtocolService,
nsIMIMEService, nsIObserver, nsISupportsWeakReference)
@@ -1003,30 +1130,13 @@ nsExternalHelperAppService::LoadURI(nsIURI* aURI,
rv = GetProtocolHandlerInfo(scheme, getter_AddRefs(handler));
NS_ENSURE_SUCCESS(rv, rv);
- nsHandlerInfoAction preferredAction;
- handler->GetPreferredAction(&preferredAction);
- bool alwaysAsk = true;
- handler->GetAlwaysAskBeforeHandling(&alwaysAsk);
-
- // if we are not supposed to ask, and the preferred action is to use
- // a helper app or the system default, we just launch the URI.
- if (!alwaysAsk && (preferredAction == nsIHandlerInfo::useHelperApp ||
- preferredAction == nsIHandlerInfo::useSystemDefault)) {
- rv = handler->LaunchWithURI(uri, aBrowsingContext);
- // We are not supposed to ask, but when file not found the user most likely
- // uninstalled the application which handles the uri so we will continue
- // by application chooser dialog.
- if (rv != NS_ERROR_FILE_NOT_FOUND) {
- return rv;
- }
+ RefPtr<nsExternalLoadURIHandler> h = new nsExternalLoadURIHandler(
+ handler, uri, aTriggeringPrincipal, aBrowsingContext);
+ if (!h) {
+ return NS_ERROR_OUT_OF_MEMORY;
}
- nsCOMPtr<nsIContentDispatchChooser> chooser =
- do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return chooser->Ask(handler, uri, aTriggeringPrincipal, aBrowsingContext,
- nsIContentDispatchChooser::REASON_CANNOT_HANDLE);
+ return NS_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1171,6 +1281,7 @@ NS_INTERFACE_MAP_BEGIN(nsExternalAppHandler)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIHelperAppLauncher)
+ NS_INTERFACE_MAP_ENTRY(nsIHelperAppWarningLauncher)
NS_INTERFACE_MAP_ENTRY(nsICancelable)
NS_INTERFACE_MAP_ENTRY(nsIBackgroundFileSaverObserver)
NS_INTERFACE_MAP_ENTRY(nsINamed)
@@ -1532,18 +1643,7 @@ void nsExternalAppHandler::MaybeApplyDecodingForExtension(
already_AddRefed<nsIInterfaceRequestor>
nsExternalAppHandler::GetDialogParent() {
- nsCOMPtr<nsIInterfaceRequestor> dialogParent = mWindowContext;
-
- if (!dialogParent && mBrowsingContext) {
- dialogParent = do_QueryInterface(mBrowsingContext->GetDOMWindow());
- }
- if (!dialogParent && mBrowsingContext && XRE_IsParentProcess()) {
- RefPtr<Element> element = mBrowsingContext->Top()->GetEmbedderElement();
- if (element) {
- dialogParent = do_QueryInterface(element->OwnerDoc()->GetWindow());
- }
- }
- return dialogParent.forget();
+ return GetDialogParentAux(mBrowsingContext, mWindowContext);
}
NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
@@ -1651,6 +1751,29 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
+ mWarningDialog = do_CreateInstance(WARNING_DIALOG_CONTRACT_ID, &rv);
+ if (NS_SUCCEEDED(rv) && mWarningDialog) {
+ // This will create a reference cycle (the dialog holds a reference to us
+ // as nsIHelperAppWarningLauncher), which will be broken in ContinueRequest
+ // or CancelRequest.
+ nsCOMPtr<nsIInterfaceRequestor> dialogParent = GetDialogParent();
+ rv = mWarningDialog->MaybeShow(this, dialogParent);
+ }
+
+ if (NS_FAILED(rv)) {
+ // If for some reason we could not open the download warning prompt,
+ // continue with the request.
+ ContinueRequest();
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsExternalAppHandler::ContinueRequest() {
+ // Break our reference cycle with the download warning dialog (set up in
+ // OnStartRequest).
+ mWarningDialog = nullptr;
+
// now that the temp file is set up, find out if we need to invoke a dialog
// asking the user what they want us to do with this content...
@@ -1736,6 +1859,7 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
action = nsIMIMEInfo::saveToDisk;
}
+ nsresult rv = NS_OK;
if (alwaysAsk) {
// Display the dialog
mDialog = do_CreateInstance(NS_HELPERAPPLAUNCHERDLG_CONTRACTID, &rv);
@@ -1793,6 +1917,14 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
return NS_OK;
}
+NS_IMETHODIMP nsExternalAppHandler::CancelRequest(nsresult aReason) {
+ // Break our reference cycle with the download warning dialog (set up in
+ // OnStartRequest).
+ mWarningDialog = nullptr;
+
+ return Cancel(aReason);
+}
+
// Convert error info into proper message text and send OnStatusChange
// notification to the dialog progress listener or nsITransfer implementation.
void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv,
@@ -2456,7 +2588,7 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) {
}
// Break our reference cycle with the helper app dialog (set up in
- // OnStartRequest)
+ // ContinueRequest)
mDialog = nullptr;
mRequest = nullptr;
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h
index f2bd67f64ccd..8c2d8817ac7b 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -203,6 +203,7 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
*/
class nsExternalAppHandler final : public nsIStreamListener,
public nsIHelperAppLauncher,
+ public nsIHelperAppWarningLauncher,
public nsIBackgroundFileSaverObserver,
public nsINamed {
public:
@@ -210,6 +211,7 @@ class nsExternalAppHandler final : public nsIStreamListener,
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIHELPERAPPLAUNCHER
+ NS_DECL_NSIHELPERAPPWARNINGLAUNCHER
NS_DECL_NSICANCELABLE
NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER
NS_DECL_NSINAMED
@@ -460,6 +462,7 @@ class nsExternalAppHandler final : public nsIStreamListener,
nsCOMPtr<nsITransfer> mTransfer;
nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;
+ nsCOMPtr<nsIHelperAppWarningDialog> mWarningDialog;
/**
diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl
index ea8b9b08f3e6..8b58671f7597 100644
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl
+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl
@@ -182,3 +182,50 @@ interface nsIHelperAppLauncher : nsICancelable
*/
readonly attribute uint64_t browsingContextId;
};
+
+/**
+ * nsIHelperAppWarningLauncher is implemented by two classes:
+ * nsExternalLoadURIHandler
+ * nsExternalAppHandler
+ */
+[scriptable, uuid(cffd508b-4aaf-43ad-99c6-671d35cbc558)]
+interface nsIHelperAppWarningLauncher : nsISupports
+{
+ /**
+ * Callback invoked by the external app warning dialog to continue the
+ * request.
+ * NOTE: This will release the reference to the nsIHelperAppWarningDialog.
+ */
+ void continueRequest();
+
+ /**
+ * Callback invoked by the external app warning dialog to cancel the request.
+ * NOTE: This will release the reference to the nsIHelperAppWarningDialog.
+ *
+ * @param aReason
+ * Pass a failure code to indicate the reason why this operation is
+ * being canceled. It is an error to pass a success code.
+ */
+ void cancelRequest(in nsresult aReason);
+};
+
+/**
+ * nsIHelperAppWarningDialog is implemented by Torbutton's external app
+ * blocker (src/components/external-app-blocker.js).
+ */
+[scriptable, uuid(f4899a3f-0df3-42cc-9db8-bdf599e5a208)]
+interface nsIHelperAppWarningDialog : nsISupports
+{
+ /**
+ * Possibly show a launch warning dialog (it will not be shown if the user
+ * has chosen to not see the warning again).
+ *
+ * @param aLauncher
+ * A nsIHelperAppWarningLauncher to be invoked after the user confirms
+ * or cancels the download.
+ * @param aWindowContext
+ * The window associated with the download.
+ */
+ void maybeShow(in nsIHelperAppWarningLauncher aLauncher,
+ in nsISupports aWindowContext);
+};
1
0
[Git][tpo/applications/fenix][tor-browser-91.1.0-11.0-1] squash! Modify UI/UX
by boklm (@boklm) 10 Aug '21
by boklm (@boklm) 10 Aug '21
10 Aug '21
boklm pushed to branch tor-browser-91.1.0-11.0-1 at The Tor Project / Applications / fenix
Commits:
4350df29 by Matthew Finkel at 2021-08-10T16:55:11+02:00
squash! Modify UI/UX
Bug 40186: Hide Credit Cards in Settings
- - - - -
1 changed file:
- app/src/main/res/xml/account_settings_preferences.xml
Changes:
=====================================
app/src/main/res/xml/account_settings_preferences.xml
=====================================
@@ -31,6 +31,7 @@
<CheckBoxPreference
android:defaultValue="true"
+ android:visible="false"
android:key="@string/pref_key_sync_credit_cards"
android:layout="@layout/checkbox_left_preference"
android:title="@string/preferences_sync_credit_cards" />
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/commit/4350df293955c…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/commit/4350df293955c…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/fenix][tor-browser-91.1.0-11.0-1] 10 commits: Bug 40002: Add GitLab CI
by boklm (@boklm) 10 Aug '21
by boklm (@boklm) 10 Aug '21
10 Aug '21
boklm pushed to branch tor-browser-91.1.0-11.0-1 at The Tor Project / Applications / fenix
Commits:
38363fba by Matthew Finkel at 2021-08-09T19:11:02+00:00
Bug 40002: Add GitLab CI
Pin CI builds to runners with 32GB of RAM to avoid OOM conditions.
- - - - -
e3ddcd20 by Matthew Finkel at 2021-08-09T19:11:04+00:00
Rename as Tor Browser
Bug 40020: Change applicationId
Bug 40020: Change app name
Bug 40020: Change deeplink scheme
Bug 40020: Change App icons
Bug 40073: Use correct branding on About page
Bug 40088: Use Tor Browser logo in migration screen
- - - - -
2eac143b by Matthew Finkel at 2021-08-09T19:11:05+00:00
Disable features and functionality
Bug 33594: Disable data collection by default (Glean)
Bug 40019: Adjust is disabled on Release when data collection is disabled
Bug 34338: Disable the crash reporter
Bug 40014: Neuter Google Advertising ID
Bug 40018: Disable Push service
Bug 40034: Disable PWA onboading
Bug 40072: Disable Tracking Protection
Bug 40061: Do not show "Send to device" in sharing menu
Bug 40109: Reduce requested permissions
Exclude LOCATION and NETWORK_STATE
- - - - -
11438ee5 by Georg Koppen at 2021-08-09T19:11:06+00:00
Modify build system
Bug 40083: Make locale ordering in BuildConfig deterministic
Bug 40042: Add option do overwrite timestamp in extension version
Bug 40059: Use MOZ_BUILD_DATE for versionCode
At the same time we adapt MOZ_BUILD_DATE to our needs where it is
actually used and not in tor-browser-build. This gives us more
flexibility. See: tor-browser-build#40084.
Bug 40067: Fix reproducibility issue in classes2.dex
We make sure our MOZ_BUILD_DATE gets used as a source for showing date
related information on the Fenix about page.
Bug 40071: Show only supported locales
Bug 40064: Use Gecko Beta for Nightly and Debug variants
Bug 40123: Allow building the instrumented tests apks for variants other than debug
This allows to specify the variant of the instrumented tests via
a `testBuildType` gradle argument. It also applies a workaround for
a R8 issue from https://issuetracker.google.com/issues/140851070.
Bug 40143: Use deterministic date in Test apk
The build config was using Date() when generating the Test apk's
versionName.
- - - - -
99359e91 by Matthew Finkel at 2021-08-09T19:11:09+00:00
Add Tor integration and UI
Bug 40001: Start Tor as part of the Fenix initialization
Bug 40028: Implement Tor Service controller
Bug 40028: Integrate Tor Controller into HomeFragment
Bug 40028: Implement Tor connect and logger screens
Bug 40028: Implement Tor Onboarding
Bug 40028: Implement new home screen
Bug 40028: Define bootstrapping events and Quick Start
Bug 40041: Implement Tor Network Settings
Bug 40041: Integrate Tor Network Settings
Bug 40179: Show Snowflake bridge option on Release
Bug 40176: Re-render Home fragment on resume
- - - - -
ec7d8997 by Alex Catarineu at 2021-08-09T19:11:35+00:00
Modify UI/UX
Bug 40015: Modify Home menu
Bug 40016: Hide unwanted Settings
Bug 40016: Modify Default toolbar menu
Bug 40016: Add Donate settings button
Bug 40016: Move Allow Screenshots under Advanced
Bug 40016: Don't install WebCompat webext
Bug 40016: Don't onboard Search Suggestions
Bug 40094: Do not use MasterPasswordTipProvider in HomeFragment
Bug 40095: Hide "Sign in to sync" in bookmarks
Bug 40031: Hide Mozilla-specific items on About page
Bug 40032: Set usesCleartextTraffic as false
Bug 40063: Do not sort search engines alphabetically
Bug 34378: Port external helper app prompting
With the corresponding android-components patch, this allows all `startActivity`
that may open external apps to be replaced by `TorUtils.startActivityPrompt`.
Bug 34403: Disable Normal mode by default
Bug 40087: Implement a switch for english locale spoofing
Bug 40144: Hide Download Manager
Bug 40141: Hide EME site permission
Bug 40166: Hide "Normal" tab (again) and Sync tab in TabTray
Bug 40167: Hide "Save to Collection" in menu
Bug 40172: Find the Quit button
- - - - -
353a7011 by Alex Catarineu at 2021-08-09T19:11:36+00:00
Modify Add-on support
Bug 40030: Install HTTPS Everywhere and NoScript addons on startup
HTTPS Everywhere is installed as a builtin extension and NoScript as
a regular AMO addon. To avoid unnecessary I/O we only install NoScript
the first time, and rely on the browser addon updating mechanism for
keeping up with new versions. This is the same behaviour that was
implemented in the Fennec-based Tor Browser, where it was installed
as a "distribution addon", which also only occurred once.
Bug 40062: HTTPS Everywhere is not shown as installed
Also 40070: Consider storing the list of recommended addons
This implements our own AddonsProvider, which loads the list of
available addons from assets instead of fetching it from an
endpoint. In this list, we replace https-everywhere by
our https-everywhere-eff, so that the EFF one is shown as installed
in the addons list and the AMO one is not displayed.
Also, we hide the uninstall button for builtin addons.
Bug 40058: Hide option for disallowing addon in private mode
- - - - -
5a27bf5d by Matthew Finkel at 2021-08-09T19:11:37+00:00
Add Security Level UI
Bug 40026: Implement Security Level settings
Bug 40026: Integrate Security Level settings
- - - - -
11239f73 by HackerNCoder at 2021-08-09T20:37:37+00:00
Bug 40177: Hide Tor icons in settings
- - - - -
187677e9 by Matthew Finkel at 2021-08-09T20:37:38+00:00
Bug 40185: Use NimbusDisabled
- - - - -
30 changed files:
- + .gitlab-ci.yml
- app/build.gradle
- app/proguard-rules.pro
- app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt
- − app/src/beta/res/drawable/ic_launcher_foreground.xml
- app/src/beta/res/mipmap-hdpi/ic_launcher.png
- app/src/beta/res/mipmap-mdpi/ic_launcher.png
- app/src/beta/res/mipmap-xhdpi/ic_launcher.png
- app/src/beta/res/mipmap-xxhdpi/ic_launcher.png
- app/src/beta/res/mipmap-xxxhdpi/ic_launcher.png
- app/src/beta/res/values/static_strings.xml
- app/src/beta/res/xml/shortcuts.xml
- − app/src/debug/res/drawable/ic_launcher_foreground.xml
- app/src/debug/res/xml/shortcuts.xml
- app/src/main/AndroidManifest.xml
- + app/src/main/assets/allowed_addons.json
- app/src/main/java/org/mozilla/fenix/FenixApplication.kt
- app/src/main/java/org/mozilla/fenix/HomeActivity.kt
- app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt
- app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
- app/src/main/java/org/mozilla/fenix/components/Analytics.kt
- app/src/main/java/org/mozilla/fenix/components/Components.kt
- app/src/main/java/org/mozilla/fenix/components/Core.kt
- + app/src/main/java/org/mozilla/fenix/components/TorAddonCollectionProvider.kt
- + app/src/main/java/org/mozilla/fenix/components/TorBrowserFeatures.kt
- app/src/main/java/org/mozilla/fenix/components/metrics/AdjustMetricsService.kt
- app/src/main/java/org/mozilla/fenix/components/metrics/MetricsUtils.kt
- app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt
- app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
- app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt
The diff was not included because it is too large.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/compare/bdf9c3ec4b7c…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/compare/bdf9c3ec4b7c…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/fenix][tor-browser-91.0.0b5-11.0-1] squash! Modify UI/UX
by boklm (@boklm) 10 Aug '21
by boklm (@boklm) 10 Aug '21
10 Aug '21
boklm pushed to branch tor-browser-91.0.0b5-11.0-1 at The Tor Project / Applications / fenix
Commits:
2ed13c5b by Matthew Finkel at 2021-08-10T02:15:47+00:00
squash! Modify UI/UX
Bug 40186: Hide Credit Cards in Settings
- - - - -
1 changed file:
- app/src/main/res/xml/account_settings_preferences.xml
Changes:
=====================================
app/src/main/res/xml/account_settings_preferences.xml
=====================================
@@ -31,6 +31,7 @@
<CheckBoxPreference
android:defaultValue="true"
+ android:visible="false"
android:key="@string/pref_key_sync_credit_cards"
android:layout="@layout/checkbox_left_preference"
android:title="@string/preferences_sync_credit_cards" />
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/commit/2ed13c5b461c6…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/commit/2ed13c5b461c6…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/android-components][android-components-91.0.12-11.0-1] 12 commits: Bug 40005: Modify Default toolbar menu
by boklm (@boklm) 10 Aug '21
by boklm (@boklm) 10 Aug '21
10 Aug '21
boklm pushed to branch android-components-91.0.12-11.0-1 at The Tor Project / Applications / android-components
Commits:
c5c7ee71 by Matthew Finkel at 2021-08-09T20:41:36+00:00
Bug 40005: Modify Default toolbar menu
- - - - -
4225880d by Alex Catarineu at 2021-08-09T20:41:38+00:00
Bug 40007: Port external helper app prompting
Together with the corresponding fenix patch, this allows all `startActivity`
that may open external apps to be replaced by `TorUtils.startActivityPrompt`.
- - - - -
51bf7362 by Alex Catarineu at 2021-08-09T20:41:39+00:00
Bug 40002: Ensure system download manager is not used
- - - - -
0598c534 by Alex Catarineu at 2021-08-09T20:41:42+00:00
Bug 40009: Change the default search engines
This matches the search engines from desktop, that is:
DDG as the default, then YouTube, Google, DDGOnion,
Startpage, Twitter, Wikipedia and Yahoo.
Bug 40062: Update DuckDuckGo onion search plugin
- - - - -
b6d332a1 by Alex Catarineu at 2021-08-09T20:41:43+00:00
Modify Addon support
Bug 40011: Hide option for disallowing addons in private mode
Bug 40016: Allow inheriting from AddonCollectionProvider
This will allow implementing our own AddonsProvider in fenix.
- - - - -
1d80ff34 by Georg Koppen at 2021-08-09T20:41:44+00:00
Bug 40013: Add option do overwrite timestamp in extension version
- - - - -
4a6d898f by Alex Catarineu at 2021-08-09T20:41:46+00:00
Bug 40015: Port padlock states for .onion services
- - - - -
0bdf2d6f by Alex Catarineu at 2021-08-09T20:41:47+00:00
Bug 40021: Force telemetry=false in Fennec settings migration
- - - - -
4cbc881f by Alex Catarineu at 2021-08-09T20:41:48+00:00
Bug 40022: Migrate Tor security level from Fennec
- - - - -
801cc97a by Matthew Finkel at 2021-08-09T20:41:50+00:00
Modify Tracking Protection configuration
Bug 40020: Disable third-party cookies
Bug 40024: Disable tracking protection by default
- - - - -
0ad6c6a3 by Matthew Finkel at 2021-08-09T20:41:51+00:00
Bug 40023: Stop PrivateNotificationService
- - - - -
2ec2e7e7 by Matthew Finkel at 2021-08-09T20:41:53+00:00
Add support for new GeckoView interfaces
Bug 40006: Expose Security Level interface
Bug 40019: Expose spoofEnglish pref
Bug 34439: Isolate Icon loader on Android
- - - - -
30 changed files:
- build.gradle
- components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt
- components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/fetch/GeckoViewFetchClient.kt
- components/browser/icons/src/main/java/mozilla/components/browser/icons/loader/HttpIconLoader.kt
- components/browser/menu/src/main/java/mozilla/components/browser/menu/WebExtensionBrowserMenuBuilder.kt
- components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt
- components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIconView.kt
- components/browser/toolbar/src/main/res/drawable/mozac_ic_site_security.xml
- components/browser/toolbar/src/main/res/values/attrs_browser_toolbar.xml
- components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt
- components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt
- components/concept/fetch/src/main/java/mozilla/components/concept/fetch/Request.kt
- components/concept/toolbar/src/main/java/mozilla/components/concept/toolbar/Toolbar.kt
- components/feature/addons/src/main/java/mozilla/components/feature/addons/amo/AddonCollectionProvider.kt
- components/feature/addons/src/main/res/layout/mozac_feature_addons_fragment_dialog_addon_installed.xml
- components/feature/app-links/build.gradle
- components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksFeature.kt
- components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt
- components/feature/contextmenu/src/main/java/mozilla/components/feature/contextmenu/ContextMenuCandidate.kt
- components/feature/downloads/build.gradle
- components/feature/downloads/src/main/java/mozilla/components/feature/downloads/AbstractFetchDownloadService.kt
- components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadsFeature.kt
- components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeature.kt
- components/feature/search/src/main/assets/search/list.json
- + components/feature/search/src/main/assets/searchplugins/ddg-onion.xml
- components/feature/search/src/main/assets/searchplugins/ddg.xml
- + components/feature/search/src/main/assets/searchplugins/startpage.xml
- + components/feature/search/src/main/assets/searchplugins/yahoo.xml
- components/feature/toolbar/src/main/java/mozilla/components/feature/toolbar/ToolbarPresenter.kt
- components/support/ktx/src/main/java/mozilla/components/support/ktx/android/content/Context.kt
The diff was not included because it is too large.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/android-components/-/compare…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/android-components/-/compare…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
commit 644285778dcfa79b582b7339edfe429aa01d2f91
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Tue Aug 10 02:56:47 2021 +0000
Update FF78/90 audits
---
audits/FF78_NETWORK_AUDIT | 2 +-
audits/FF90_NETWORK_AUDIT | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/audits/FF78_NETWORK_AUDIT b/audits/FF78_NETWORK_AUDIT
index 6626dda..498176c 100644
--- a/audits/FF78_NETWORK_AUDIT
+++ b/audits/FF78_NETWORK_AUDIT
@@ -1,6 +1,6 @@
Summary of findings: https://gitlab.torproject.org/tpo/applications/fenix/-/issues/34177
-`git diff 8da33f6c34c0ca5b1d7bca58ca86cb5e436333e8 4735a392536150f49518c48aa9510cf313603b92`
+`git diff 8da33f6c34c0ca5b1d7bca58ca86cb5e436333e8 b2301d04e91a4eacf230e6ed9b69ad932993b340`
and then go over all the changes containing the
above mentioned potentially dangerous calls and features. Grep the diff for
the following strings and examine surrounding usage.
diff --git a/audits/FF90_NETWORK_AUDIT b/audits/FF90_NETWORK_AUDIT
index 7a667c1..672ded1 100644
--- a/audits/FF90_NETWORK_AUDIT
+++ b/audits/FF90_NETWORK_AUDIT
@@ -14,7 +14,7 @@ functions are documented and analyzed in this audit.
============ Firefox General Portion =============
Start: 3862f77749dd50e54c3d9eea32fb59e84d978c96 # FIREFOX_89_0_RELEASE
-End: 5e8ffbe1bf6d448cb235cb0a64a56646a6537b22 # FIREFOX_90_0b12_BUILD1
+End: bf8b9c6630fca1b774dbf1573bf14c9315349514 # FIREFOX_90_0_BUILD1
# Nothing of interest (using `code_audit.sh`)
@@ -34,7 +34,7 @@ End: dd09c25f14dbf45f1637ed8dca2d1e5ff668479f # v77.0.2
============ Android Components Portion =============
Start: 5204f4025ce8b60c64f92eb3f60ee644cafd4fc8 # v75.0.22
-End: 536cb9fe133e555109c3f25024148260aace6dab # v90.0.11
+End: 0ab0465c5ca99b9b01a32e4562905fe51a709204 # v90.0.12
# Issue #10162
# - Don't show the contextual menu for blocked urls
@@ -55,7 +55,7 @@ End: 536cb9fe133e555109c3f25024148260aace6dab # v90.0.11
============ Fenix Portion =============
Start: edea181c543ffee077bb3ca52830ba8d320358b2 # v89.1.1
-End: 6d43c622b4515becbf29ba7956ec2fbe1e5bdc31 # v90.0.0-beta.6
+End: aeedb6b53781c6d29fda9034267a4ce8aeed6468 # v90.1.1
# Issue #19693
# - Display a biometric prompt when a credit card is selected to autofill (#19697)
1
0
[Git][tpo/applications/android-components] Pushed new branch android-components-91.0.12-11.0-1
by Matthew Finkel (@sysrqb) 09 Aug '21
by Matthew Finkel (@sysrqb) 09 Aug '21
09 Aug '21
Matthew Finkel pushed new branch android-components-91.0.12-11.0-1 at The Tor Project / Applications / android-components
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/android-components/-/tree/an…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/fenix] Pushed new branch tor-browser-91.1.0-11.0-1
by Matthew Finkel (@sysrqb) 09 Aug '21
by Matthew Finkel (@sysrqb) 09 Aug '21
09 Aug '21
Matthew Finkel pushed new branch tor-browser-91.1.0-11.0-1 at The Tor Project / Applications / fenix
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/fenix/-/tree/tor-browser-91.…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[tor-browser-build/maint-10.5] Tor Browser 10.5.4 release preparations
by boklm@torproject.org 05 Aug '21
by boklm@torproject.org 05 Aug '21
05 Aug '21
commit 9b3892532ac96593997afbf16ca8642cd84a51a6
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 4 18:15:11 2021 +0000
Tor Browser 10.5.4 release preparations
Version bumps and Changelog update
---
projects/firefox/config | 2 +-
projects/go/config | 4 ++--
projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt | 11 +++++++++++
projects/tor-browser/config | 4 ++--
rbm.conf | 4 ++--
5 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/projects/firefox/config b/projects/firefox/config
index d62d9ab..1837c5c 100644
--- a/projects/firefox/config
+++ b/projects/firefox/config
@@ -8,7 +8,7 @@ git_submodule: 1
gpg_keyring: torbutton.gpg
var:
- firefox_platform_version: 78.12.0
+ firefox_platform_version: 78.13.0
firefox_version: '[% c("var/firefox_platform_version") %]esr'
torbrowser_branch: 10.5
branding_directory: 'browser/branding/alpha'
diff --git a/projects/go/config b/projects/go/config
index 8a67ae8..9572cd2 100644
--- a/projects/go/config
+++ b/projects/go/config
@@ -1,5 +1,5 @@
# vim: filetype=yaml sw=2
-version: 1.15.13
+version: 1.15.14
filename: '[% project %]-[% c("version") %]-[% c("var/build_id") %].tar.gz'
var:
@@ -118,7 +118,7 @@ input_files:
enable: '[% ! c("var/linux") %]'
- URL: 'https://golang.org/dl/go[% c("version") %].src.tar.gz'
name: go
- sha256sum: 99069e7223479cce4553f84f874b9345f6f4045f27cf5089489b546da619a244
+ sha256sum: 60a4a5c48d63d0a13eca8849009b624629ff429c8bc5d1a6a8c3c4da9f34e70a
- URL: 'https://golang.org/dl/go[% c("var/go14_version") %].src.tar.gz'
name: go14
sha256sum: 9947fc705b0b841b5938c48b22dc33e9647ec0752bae66e50278df4f23f64959
diff --git a/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt b/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt
index 5eca79f..bc768d0 100644
--- a/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt
+++ b/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt
@@ -1,3 +1,14 @@
+Tor Browser 10.5.4 -- August 10 2021
+ * Windows + OS X + Linux
+ * Update Firefox to 78.13.0esr
+ * Update NoScript to 11.2.11
+ * Bug 40041: Remove V2 Deprecation banner on about:tor for desktop [torbutton]
+ * Bug 40506: Saved Logins not available in 10.5 [tor-browser]
+ * Bug 40524: Update DuckDuckGo onion site URL in search preferences and onboarding [tor-browser]
+ * Build System
+ * Windows + OS X + Linux
+ * Update Go to 1.15.14
+
Tor Browser 10.5.3 -- July 17 2021
* Android
* Update HTTPS Everywhere to 2021.7.13
diff --git a/projects/tor-browser/config b/projects/tor-browser/config
index 1045d90..4091361 100644
--- a/projects/tor-browser/config
+++ b/projects/tor-browser/config
@@ -78,9 +78,9 @@ input_files:
enable: '[% ! c("var/android") %]'
- filename: Bundle-Data
enable: '[% ! c("var/android") %]'
- - URL: https://addons.cdn.mozilla.net/user-media/addons/722/noscript_security_suit…
+ - URL: https://addons.cdn.mozilla.net/user-media/addons/722/noscript_security_suit…
name: noscript
- sha256sum: 830a25dad07327ae220b4740ea834b0abe715e9ef3dabc326bf7fef2c5af1efb
+ sha256sum: b833e81823986646dbc473ebbee987bd47757fbe79c9d1720150f08ba6ca9ba9
- filename: 'RelativeLink/start-tor-browser.desktop'
enable: '[% c("var/linux") %]'
- filename: 'RelativeLink/execdesktop'
diff --git a/rbm.conf b/rbm.conf
index 5972405..95ec20a 100644
--- a/rbm.conf
+++ b/rbm.conf
@@ -57,11 +57,11 @@ buildconf:
git_signtag_opt: '-s'
var:
- torbrowser_version: '10.5.3'
+ torbrowser_version: '10.5.4'
torbrowser_build: 'build1'
torbrowser_incremental_from:
- - 10.0.18
- 10.5
+ - 10.5.2
project_name: tor-browser
multi_lingual: 0
build_mar: 1
1
0
[tor-browser/tor-browser-78.12.0esr-11.0-1] fixup! Bug 10760: Integrate TorButton to TorBrowser core
by sysrqb@torproject.org 05 Aug '21
by sysrqb@torproject.org 05 Aug '21
05 Aug '21
commit 769d48202099078c96835de9758d1fdbe04372e7
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Thu Aug 5 15:05:56 2021 +0000
fixup! Bug 10760: Integrate TorButton to TorBrowser core
---
toolkit/torproject/torbutton | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/toolkit/torproject/torbutton b/toolkit/torproject/torbutton
index f5a747e06001..32c71313e4e1 160000
--- a/toolkit/torproject/torbutton
+++ b/toolkit/torproject/torbutton
@@ -1 +1 @@
-Subproject commit f5a747e06001898e80ef2b0676ed264eb20be349
+Subproject commit 32c71313e4e1da24510402b9051543e144a3129b
1
0
[tor-browser/tor-browser-78.13.0esr-10.5-1] fixup! Bug 10760: Integrate TorButton to TorBrowser core
by sysrqb@torproject.org 05 Aug '21
by sysrqb@torproject.org 05 Aug '21
05 Aug '21
commit b2cae7891c8f2b9db3fde6fb99c3e6ea7bee447e
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Thu Aug 5 15:05:56 2021 +0000
fixup! Bug 10760: Integrate TorButton to TorBrowser core
---
toolkit/torproject/torbutton | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/toolkit/torproject/torbutton b/toolkit/torproject/torbutton
index f5a747e06001..32c71313e4e1 160000
--- a/toolkit/torproject/torbutton
+++ b/toolkit/torproject/torbutton
@@ -1 +1 @@
-Subproject commit f5a747e06001898e80ef2b0676ed264eb20be349
+Subproject commit 32c71313e4e1da24510402b9051543e144a3129b
1
0
[torbutton/master] Revert "Bug 40037: Announce v2 onion service deprecation on about:tor"
by sysrqb@torproject.org 05 Aug '21
by sysrqb@torproject.org 05 Aug '21
05 Aug '21
commit 32c71313e4e1da24510402b9051543e144a3129b
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 4 17:55:31 2021 +0000
Revert "Bug 40037: Announce v2 onion service deprecation on about:tor"
This reverts commit cc73f75d99e5bd1b610e4a96e89b895ced72407b.
Bug 40041: Remove V2 Deprecation banner on about:tor for desktop
---
chrome/content/aboutTor/aboutTor.xhtml | 15 ----------
chrome/skin/aboutTor.css | 49 ---------------------------------
chrome/skin/tor-banner-warning-icon.svg | 1 -
3 files changed, 65 deletions(-)
diff --git a/chrome/content/aboutTor/aboutTor.xhtml b/chrome/content/aboutTor/aboutTor.xhtml
index 7a50ebdf..f3a9032f 100644
--- a/chrome/content/aboutTor/aboutTor.xhtml
+++ b/chrome/content/aboutTor/aboutTor.xhtml
@@ -65,21 +65,6 @@
</form>
</div>
- <div id="infoBanner">
- <img id="infoBannerImg" src="resource://torbutton-assets/tor-banner-warning-icon.svg" />
- <div id="infoBannerTextCol">
- <div id="infoBannerDescription">
- Tor is ending its support for version 2 (v2) Onion Services, and
- v2 onion sites have since been deprecated. If
- you're a <b>site administrator</b>, upgrade to a
- v3 onion service immediately.
- <a id="infoBannerLink" target="_blank" href="https://support.torproject.org/onionservices/#v2-deprecation">
- Learn more
- </a>
- </div>
- </div>
- </div>
-
<div id="bottom">
<p id="donate" class="moreInfoLink">&aboutTor.donationBanner.freeToUse;
<a href="https://donate.torproject.org/">&aboutTor.donationBanner.buttonA; »</a>
diff --git a/chrome/skin/aboutTor.css b/chrome/skin/aboutTor.css
index 65cc1d3b..38486241 100644
--- a/chrome/skin/aboutTor.css
+++ b/chrome/skin/aboutTor.css
@@ -220,55 +220,6 @@ body:not([showmanual]) .showForManual {
background-color: rgba(12, 12, 13, 0.1); /* same as Firefox's about:home */
}
-#infoBanner {
- width: 690px;
- padding: 20px 25px 25px;
- background: rgba(0, 0, 0, 0.3);
- border-radius: 6px;
- margin: 35px auto 0px;
- display: flex;
- flex-direction: row;
- align-items: flex-start;
- position: static;
-}
-
-@media only screen and (min-width: 900px) {
- #infoBanner {
- margin: 35px 0px 0px 135px;
- }
-}
-
-#infoBannerTextCol {
- padding: 8px 0px 0px 15px;
- font-size: 15px;
- line-height: normal;
- color: #FFFFFF;
- width: 633px;
-}
-
-#infoBannerHeader {
- font-weight: bold;
-}
-
-#infoBannerImg {
- width: 32px;
- height: 32px;
- position: static;
- border-radius: 32px;
-}
-
-div.infoBannerDescription, div.infoBannerLink {
- padding-top: 10px;
-}
-
-a#infoBannerLink {
- text-decoration: underline;
-}
-
-a#infoBannerLink:hover {
- text-decoration: none;
-}
-
/* #search-text is the search input field */
#search-text {
flex: 1;
diff --git a/chrome/skin/tor-banner-warning-icon.svg b/chrome/skin/tor-banner-warning-icon.svg
deleted file mode 100644
index 3686aba6..00000000
--- a/chrome/skin/tor-banner-warning-icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg fill="none" height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><rect fill="#fdd204" height="32" rx="16" width="32"/><path clip-rule="evenodd" d="m16 25c-4.9708 0-9-4.0295-9-9.0002 0-4.9706 4.0292-8.9998 9-8.9998 4.9705 0 9 4.0292 9 8.9998 0 4.9707-4.0295 9.0002-9 9.0002zm.0185-2.7279v1.091c4.0584-.01 7.3449-3.3024 7.3449-7.3633 0-4.0607-3.2865-7.35293-7.3449-7.36316v1.09101c3.4559.00997 6.2541 2.81395 6.2541 6.27215 0 3.4583-2.7982 6.2623-6.2541 6.2723zm3.527-6.2723c0 1.9519-1.5778 3.5344-3.527 3.5447v1.0907c2.552-.0099 4.618-2.0809 4.618-4.6354 0-2.5543-2.066-4.6253-4.618-4.6353v1.0908c1.9492.0102 3.527 1.5927 3.527 3.5445zm-3.527-1.9081c1.0456.01 1.8906.86 1.8906 1.908 0 1.0484-.845 1.8984-1.8906 1.9084z" fill="#240a3b" fill-rule="evenodd"/></svg>
\ No newline at end of file
1
0
[tor-browser/tor-browser-78.13.0esr-10.5-1] fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
by sysrqb@torproject.org 04 Aug '21
by sysrqb@torproject.org 04 Aug '21
04 Aug '21
commit 554f13a35ba478cf2b325f1dd50e1cc2e83027f1
Author: Richard Pospesel <richard(a)torproject.org>
Date: Sun Jul 11 17:44:40 2021 +0200
fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
---
browser/components/torconnect/TorConnectParent.jsm | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm
index 54548891fbab..c34fab76ddbb 100644
--- a/browser/components/torconnect/TorConnectParent.jsm
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -11,6 +11,10 @@ const { TorLauncherUtil } = ChromeUtils.import(
"resource://torlauncher/modules/tl-util.jsm"
);
+const { TorConnect } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+
const kTorProcessReadyTopic = "TorProcessIsReady";
const kTorProcessExitedTopic = "TorProcessExited";
const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
1
0
[tor-browser/tor-browser-78.13.0esr-10.5-1] Bug 27476: Implement about:torconnect captive portal within Tor Browser
by sysrqb@torproject.org 04 Aug '21
by sysrqb@torproject.org 04 Aug '21
04 Aug '21
commit 9f3e530412046c26b51b11d539e910682caf9fd7
Author: Richard Pospesel <richard(a)torproject.org>
Date: Wed Apr 28 23:09:34 2021 -0500
Bug 27476: Implement about:torconnect captive portal within Tor Browser
- implements new about:torconnect page as tor-launcher replacement
- adds tor connection status to url bar and tweaks UX when not online
- adds new torconnect component to browser
- tor process management functionality remains implemented in tor-launcher through the TorProtocolService module
- the onion pattern from about:tor migrated to an .inc.xhtml file now used by both about:tor and about:torconnect
- various design tweaks and resusability fixes to onion pattern
- adds warning/error box to about:preferences#tor when not connected to tor
- explicitly allows about:torconnect URIs to ignore Resist Fingerprinting (RFP)
- various tweaks to info-pages.inc.css for about:torconnect (also affects other firefox info pages)
---
browser/actors/NetErrorParent.jsm | 8 +
browser/base/content/aboutNetError.js | 10 +-
browser/base/content/browser-siteIdentity.js | 2 +-
browser/base/content/browser.js | 10 +
browser/base/content/browser.xhtml | 2 +
browser/components/BrowserGlue.jsm | 59 +++-
browser/components/about/AboutRedirector.cpp | 4 +
browser/components/about/components.conf | 1 +
browser/components/moz.build | 1 +
.../onionservices/HttpsEverywhereControl.jsm | 17 +-
browser/components/sessionstore/SessionStore.jsm | 16 +
browser/components/torconnect/TorConnectChild.jsm | 9 +
browser/components/torconnect/TorConnectParent.jsm | 122 ++++++++
.../torconnect/content/aboutTorConnect.css | 151 +++++++++
.../torconnect/content/aboutTorConnect.js | 339 +++++++++++++++++++++
.../torconnect/content/aboutTorConnect.xhtml | 54 ++++
.../components/torconnect/content/onion-slash.svg | 7 +
browser/components/torconnect/content/onion.svg | 3 +
.../torconnect/content/torBootstrapUrlbar.js | 136 +++++++++
.../torconnect/content/torconnect-urlbar.css | 65 ++++
.../torconnect/content/torconnect-urlbar.inc.xhtml | 11 +
browser/components/torconnect/jar.mn | 7 +
browser/components/torconnect/moz.build | 6 +
.../components/torpreferences/content/torPane.js | 86 ++++++
.../torpreferences/content/torPane.xhtml | 34 +++
.../torpreferences/content/torPreferences.css | 121 ++++++++
browser/components/urlbar/UrlbarInput.jsm | 31 ++
browser/modules/TorConnect.jsm | 62 ++++
browser/modules/TorProcessService.jsm | 12 +
browser/modules/TorProtocolService.jsm | 124 +++++++-
browser/modules/TorStrings.jsm | 75 +++++
browser/modules/moz.build | 2 +
browser/themes/shared/jar.inc.mn | 1 +
browser/themes/shared/onionPattern.css | 124 ++++++++
browser/themes/shared/onionPattern.inc.xhtml | 210 +++++++++++++
browser/themes/shared/urlbar-searchbar.inc.css | 2 +
dom/base/Document.cpp | 51 +++-
dom/base/nsGlobalWindowOuter.cpp | 2 +
toolkit/modules/AsyncPrefs.jsm | 2 +
toolkit/modules/RemotePageAccessManager.jsm | 26 ++
toolkit/mozapps/update/UpdateService.jsm | 68 ++++-
.../themes/shared/in-content/info-pages.inc.css | 15 +-
.../lib/environments/browser-window.js | 4 +
43 files changed, 2076 insertions(+), 16 deletions(-)
diff --git a/browser/actors/NetErrorParent.jsm b/browser/actors/NetErrorParent.jsm
index 035195391554..fa3cbf23fcb7 100644
--- a/browser/actors/NetErrorParent.jsm
+++ b/browser/actors/NetErrorParent.jsm
@@ -17,6 +17,10 @@ const { SessionStore } = ChromeUtils.import(
);
const { HomePage } = ChromeUtils.import("resource:///modules/HomePage.jsm");
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
const PREF_SSL_IMPACT_ROOTS = [
"security.tls.version.",
"security.ssl3.",
@@ -318,6 +322,10 @@ class NetErrorParent extends JSWindowActorParent {
break;
}
}
+ break;
+ case "ShouldShowTorConnect":
+ return TorProtocolService.shouldShowTorConnect();
}
+ return undefined;
}
}
diff --git a/browser/base/content/aboutNetError.js b/browser/base/content/aboutNetError.js
index 60db17f46eb9..6844154e16e3 100644
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -194,8 +194,16 @@ async function setErrorPageStrings(err) {
document.l10n.setAttributes(titleElement, title);
}
-function initPage() {
+async function initPage() {
var err = getErrorCode();
+
+ // proxyConnectFailure because no-tor running daemon would return this error
+ if (
+ (err === "proxyConnectFailure") &&
+ (await RPMSendQuery("ShouldShowTorConnect"))
+ ) {
+ document.location.replace("about:torconnect");
+ }
// List of error pages with an illustration.
let illustratedErrors = [
"malformedURI",
diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js
index 539d6d4056a3..2a3431172886 100644
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -57,7 +57,7 @@ var gIdentityHandler = {
* RegExp used to decide if an about url should be shown as being part of
* the browser UI.
*/
- _secureInternalUIWhitelist: (AppConstants.TOR_BROWSER_UPDATE ? /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|tbupdate)(?:[?#]|$)/i : /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor)(?:[?#]|$)/i),
+ _secureInternalUIWhitelist: (AppConstants.TOR_BROWSER_UPDATE ? /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|torconnect|tbupdate)(?:[?#]|$)/i : /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|torconnect)(?:[?#]|$)/i),
/**
* Whether the established HTTPS connection is considered "broken".
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 04f8752b93f4..916cd69320cb 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -77,6 +77,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
TabModalPrompt: "chrome://global/content/tabprompts.jsm",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm",
+ TorProtocolService: "resource:///modules/TorProtocolService.jsm",
Translation: "resource:///modules/translation/TranslationParent.jsm",
OnionAliasStore: "resource:///modules/OnionAliasStore.jsm",
UITour: "resource:///modules/UITour.jsm",
@@ -633,6 +634,7 @@ var gPageIcons = {
var gInitialPages = [
"about:tor",
+ "about:torconnect",
"about:blank",
"about:newtab",
"about:home",
@@ -1959,6 +1961,8 @@ var gBrowserInit = {
}
this._loadHandled = true;
+
+ TorBootstrapUrlbar.init();
},
_cancelDelayedStartup() {
@@ -2490,6 +2494,10 @@ var gBrowserInit = {
let uri = window.arguments[0];
let defaultArgs = BrowserHandler.defaultArgs;
+ if (TorProtocolService.shouldShowTorConnect()) {
+ return "about:torconnect";
+ }
+
// If the given URI is different from the homepage, we want to load it.
if (uri != defaultArgs) {
AboutNewTab.noteNonDefaultStartup();
@@ -2582,6 +2590,8 @@ var gBrowserInit = {
OnionAuthPrompt.uninit();
+ TorBootstrapUrlbar.uninit();
+
gAccessibilityServiceIndicator.uninit();
AccessibilityRefreshBlocker.uninit();
diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml
index c2caecc1a416..032db1967c69 100644
--- a/browser/base/content/browser.xhtml
+++ b/browser/base/content/browser.xhtml
@@ -112,6 +112,7 @@
Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this);
Services.scriptloader.loadSubScript("chrome://torbutton/content/tor-circuit-display.js", this);
Services.scriptloader.loadSubScript("chrome://torbutton/content/torbutton.js", this);
+ Services.scriptloader.loadSubScript("chrome://browser/content/torconnect/torBootstrapUrlbar.js", this);
window.onload = gBrowserInit.onLoad.bind(gBrowserInit);
window.onunload = gBrowserInit.onUnload.bind(gBrowserInit);
@@ -1055,6 +1056,7 @@
data-l10n-id="urlbar-go-button"/>
<hbox id="page-action-buttons" context="pageActionContextMenu">
<toolbartabstop/>
+#include ../../components/torconnect/content/torconnect-urlbar.inc.xhtml
<hbox id="contextual-feature-recommendation" role="button" hidden="true">
<hbox id="cfr-label-container">
<label id="cfr-label"/>
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 5f708fca3d5c..8735783cee2b 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -17,6 +17,31 @@ const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
+// TorProtocolService and TorConnect modules need to be lazily-loaded
+// here because they will trigger generation of the random password used
+// to talk to the tor daemon in tor-launcher. Generating the random
+// password will initialize the cryptographic service ( nsNSSComponent )
+//
+// If this service is init'd before the profile has been setup, it will
+// use the fallback init path which behaves as if security.nocertdb=true
+//
+// We make these module getters so init happens when they are needed
+// (when init'ing the OnionAliasStore). With theze getters, the password
+// generation is triggered in torbutton after the 'profile-after-change'
+// topic (so after the profile is initialized)
+
+ChromeUtils.defineModuleGetter(
+ this,
+ "TorProtocolService",
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+ChromeUtils.defineModuleGetter(
+ this,
+ "TorConnect",
+ "resource:///modules/TorConnect.jsm"
+);
+
ChromeUtils.defineModuleGetter(
this,
"ActorManagerParent",
@@ -503,6 +528,20 @@ let JSWINDOWACTORS = {
allFrames: true,
},
+ TorConnect: {
+ parent: {
+ moduleURI: "resource:///modules/TorConnectParent.jsm",
+ },
+ child: {
+ moduleURI: "resource:///modules/TorConnectChild.jsm",
+ events: {
+ DOMWindowCreated: {},
+ },
+ },
+
+ matches: ["about:torconnect"],
+ },
+
Translation: {
parent: {
moduleURI: "resource:///modules/translation/TranslationParent.jsm",
@@ -2492,7 +2531,25 @@ BrowserGlue.prototype = {
{
task: () => {
- OnionAliasStore.init();
+ if (TorProtocolService.isBootstrapDone() || !TorProtocolService.ownsTorDaemon) {
+ // we will take this path when the user is using the legacy tor launcher or
+ // when Tor Browser didn't launch its own tor.
+ OnionAliasStore.init();
+ } else {
+ // this path is taken when using about:torconnect, we wait to init
+ // after we are bootstrapped and connected to tor
+ const topic = "torconnect:bootstrap-complete";
+ let bootstrapObserver = {
+ observe(aSubject, aTopic, aData) {
+ if (aTopic === topic) {
+ OnionAliasStore.init();
+ // we only need to init once, so remove ourselves as an obvserver
+ Services.obs.removeObserver(this, topic);
+ }
+ }
+ };
+ Services.obs.addObserver(bootstrapObserver, topic);
+ }
},
},
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
index e7c377d655e7..db5f3ead4bb8 100644
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -120,6 +120,10 @@ static const RedirEntry kRedirMap[] = {
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
#endif
+ {"torconnect", "chrome://browser/content/torconnect/aboutTorConnect.xhtml",
+ nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
+ nsIAboutModule::HIDE_FROM_ABOUTABOUT},
};
static nsAutoCString GetAboutModuleName(nsIURI* aURI) {
diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf
index 8e04467c05da..01c99ad4ed0c 100644
--- a/browser/components/about/components.conf
+++ b/browser/components/about/components.conf
@@ -26,6 +26,7 @@ pages = [
'robots',
'sessionrestore',
'tabcrashed',
+ 'torconnect',
'welcome',
'welcomeback',
]
diff --git a/browser/components/moz.build b/browser/components/moz.build
index b660be047b14..fb90c499c616 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -59,6 +59,7 @@ DIRS += [
'syncedtabs',
'uitour',
'urlbar',
+ 'torconnect',
'torpreferences',
'translation',
]
diff --git a/browser/components/onionservices/HttpsEverywhereControl.jsm b/browser/components/onionservices/HttpsEverywhereControl.jsm
index 525ed5233be7..d673de4cd6e5 100644
--- a/browser/components/onionservices/HttpsEverywhereControl.jsm
+++ b/browser/components/onionservices/HttpsEverywhereControl.jsm
@@ -41,6 +41,7 @@ const SECUREDROP_TOR_ONION_CHANNEL = {
class HttpsEverywhereControl {
constructor() {
this._extensionMessaging = null;
+ this._init();
}
async _sendMessage(type, object) {
@@ -61,7 +62,6 @@ class HttpsEverywhereControl {
* Installs the .tor.onion update channel in https-everywhere
*/
async installTorOnionUpdateChannel(retries = 5) {
- this._init();
// TODO: https-everywhere store is initialized asynchronously, so sending a message
// immediately results in a `store.get is undefined` error.
@@ -143,5 +143,20 @@ class HttpsEverywhereControl {
if (!this._extensionMessaging) {
this._extensionMessaging = new ExtensionMessaging();
}
+
+ // update all of the existing https-everywhere channels
+ setTimeout(async () => {
+ let pinnedChannels = await this._sendMessage("get_pinned_update_channels");
+ for(let channel of pinnedChannels.update_channels) {
+ this._sendMessage("update_update_channel", channel);
+ }
+
+ let storedChannels = await this._sendMessage("get_stored_update_channels");
+ for(let channel of storedChannels.update_channels) {
+ this._sendMessage("update_update_channel", channel);
+ }
+ }, 0);
+
+
}
}
diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm
index 6ab86fd5913e..2d66422abf58 100644
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -213,6 +213,10 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/sessionstore/SessionHistory.jsm"
);
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
XPCOMUtils.defineLazyServiceGetters(this, {
gScreenManager: ["@mozilla.org/gfx/screenmanager;1", "nsIScreenManager"],
Telemetry: ["@mozilla.org/base/telemetry;1", "nsITelemetry"],
@@ -1888,11 +1892,23 @@ var SessionStoreInternal = {
}, "browser-delayed-startup-finished");
});
+ let bootstrapPromise = new Promise(resolve => {
+ if (TorProtocolService.isBootstrapDone() || !TorProtocolService.ownsTorDaemon) {
+ resolve();
+ } else {
+ Services.obs.addObserver(function obs(subject, topic) {
+ Services.obs.removeObserver(obs, topic);
+ resolve();
+ }, "torconnect:bootstrap-complete");
+ }
+ });
+
// We are ready for initialization as soon as the session file has been
// read from disk and the initial window's delayed startup has finished.
this._promiseReadyForInitialization = Promise.all([
promise,
SessionStartup.onceInitialized,
+ bootstrapPromise,
]);
}
diff --git a/browser/components/torconnect/TorConnectChild.jsm b/browser/components/torconnect/TorConnectChild.jsm
new file mode 100644
index 000000000000..bd6dd549f156
--- /dev/null
+++ b/browser/components/torconnect/TorConnectChild.jsm
@@ -0,0 +1,9 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+var EXPORTED_SYMBOLS = ["TorConnectChild"];
+
+const { RemotePageChild } = ChromeUtils.import(
+ "resource://gre/actors/RemotePageChild.jsm"
+);
+
+class TorConnectChild extends RemotePageChild {}
diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm
new file mode 100644
index 000000000000..54548891fbab
--- /dev/null
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -0,0 +1,122 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+var EXPORTED_SYMBOLS = ["TorConnectParent"];
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
+const { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+);
+
+const kTorProcessReadyTopic = "TorProcessIsReady";
+const kTorProcessExitedTopic = "TorProcessExited";
+const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
+const kTorShowProgressPanelTopic = "TorShowProgressPanel";
+const kTorBootstrapStatusTopic = "TorBootstrapStatus";
+const kTorBootstrapErrorTopic = "TorBootstrapError";
+const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
+
+const gActiveTopics = [
+ kTorProcessReadyTopic,
+ kTorProcessExitedTopic,
+ kTorProcessDidNotStartTopic,
+ kTorShowProgressPanelTopic,
+ kTorBootstrapStatusTopic,
+ kTorBootstrapErrorTopic,
+ kTorLogHasWarnOrErrTopic,
+ "torconnect:bootstrap-complete",
+];
+
+const gTorLauncherPrefs = {
+ quickstart: "extensions.torlauncher.quickstart",
+}
+
+class TorConnectParent extends JSWindowActorParent {
+ constructor(...args) {
+ super(...args);
+
+ const self = this;
+ this.gObserver = {
+ observe(aSubject, aTopic, aData) {
+ const obj = aSubject?.wrappedJSObject;
+ if (obj) {
+ obj.handled = true;
+ }
+ self.sendAsyncMessage(aTopic, obj);
+ },
+ };
+
+ for (const topic of gActiveTopics) {
+ Services.obs.addObserver(this.gObserver, topic);
+ }
+
+ this.quickstartObserver = {
+ observe(aSubject, aTopic, aData) {
+ if (aTopic === "nsPref:changed" &&
+ aData == gTorLauncherPrefs.quickstart) {
+ self.sendAsyncMessage("TorQuickstartPrefChanged", Services.prefs.getBoolPref(gTorLauncherPrefs.quickstart));
+ }
+ },
+ }
+ Services.prefs.addObserver(gTorLauncherPrefs.quickstart, this.quickstartObserver);
+ }
+
+ willDestroy() {
+ for (const topic of gActiveTopics) {
+ Services.obs.removeObserver(this.gObserver, topic);
+ }
+ }
+
+
+ _OpenTorAdvancedPreferences() {
+ const win = this.browsingContext.top.embedderElement.ownerGlobal;
+ win.openTrustedLinkIn("about:preferences#tor", "tab");
+ }
+
+ _TorCopyLog() {
+ // Copy tor log messages to the system clipboard.
+ const chSvc = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
+ Ci.nsIClipboardHelper
+ );
+ const countObj = { value: 0 };
+ chSvc.copyString(TorProtocolService.getLog(countObj));
+ const count = countObj.value;
+ return TorLauncherUtil.getFormattedLocalizedString(
+ "copiedNLogMessagesShort",
+ [count],
+ 1
+ );
+ }
+
+ receiveMessage(message) {
+ switch (message.name) {
+ case "TorBootstrapErrorOccurred":
+ return TorProtocolService.torBootstrapErrorOccurred();
+ case "TorRetrieveBootstrapStatus":
+ return TorProtocolService.retrieveBootstrapStatus();
+ case "OpenTorAdvancedPreferences":
+ return this._OpenTorAdvancedPreferences();
+ case "GetLocalizedBootstrapStatus":
+ const { status, keyword } = message.data;
+ return TorLauncherUtil.getLocalizedBootstrapStatus(status, keyword);
+ case "TorCopyLog":
+ return this._TorCopyLog();
+ case "TorIsNetworkDisabled":
+ return TorProtocolService.isNetworkDisabled();
+ case "TorStopBootstrap":
+ return TorProtocolService.torStopBootstrap();
+ case "TorConnect":
+ return TorProtocolService.connect();
+ case "GetDirection":
+ return Services.locale.isAppLocaleRTL ? "rtl" : "ltr";
+ case "GetTorStrings":
+ return TorStrings;
+ case "TorLogHasWarnOrErr":
+ return TorProtocolService.torLogHasWarnOrErr();
+ }
+ return undefined;
+ }
+}
diff --git a/browser/components/torconnect/content/aboutTorConnect.css b/browser/components/torconnect/content/aboutTorConnect.css
new file mode 100644
index 000000000000..a70904ca0b28
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.css
@@ -0,0 +1,151 @@
+
+/* Copyright (c) 2021, The Tor Project, Inc. */
+
+
+@import url("chrome://browser/skin/error-pages.css");
+
+:root {
+ --onion-opacity: 1;
+ --onion-color: var(--card-outline-color);
+ --onion-radius: 50px;
+}
+
+/* override firefox's default blue focus coloring */
+:focus {
+ outline: none!important;
+ box-shadow: 0 0 0 3px #CD8CED !important;
+ border: 1px #59316B solid !important;
+}
+
+@media (prefers-color-scheme: dark)
+{
+ :focus {
+ box-shadow: 0 0 0 3px #8C689E !important;
+ }
+}
+
+/* override firefox's default blue border on hover */
+input[type="checkbox"]:not(:disabled):hover {
+ border-color: #59316B;
+}
+
+/* fix checkbox visibility when dark mode enabled */
+input[type="checkbox"]:checked {
+ fill: var(--in-content-page-color);
+}
+
+#connectButton {
+ background-color: #7D4698;
+}
+
+#connectButton:hover {
+ background-color: #59316B;
+}
+
+#progressBackground {
+ position:fixed;
+ padding:0;
+ margin:0;
+ top:0;
+ left:0;
+ width: 0%;
+ height: 7px;
+ background-image: linear-gradient(90deg, rgb(20, 218, 221) 0%, rgb(128, 109, 236) 100%);
+ border-radius: 0;
+}
+
+#connectPageContainer {
+ margin-top: 10vh;
+ width: 50%;
+}
+
+#quickstartCheckbox, #quickstartCheckboxLabel {
+ vertical-align: middle;
+}
+
+#copyLogButton {
+ position: relative;
+}
+
+/* mirrors p element spacing */
+#copyLogContainer {
+ margin: 1em 0;
+ height: 1.2em;
+ min-height: 1.2em;
+}
+
+#copyLogLink {
+ position: relative;
+ display: inline-block;
+ color: var(--in-content-link-color);
+}
+
+/* hidden apparently only works if no display is set; who knew? */
+#copyLogLink[hidden="true"] {
+ display: none;
+}
+
+#copyLogLink:hover {
+ cursor:pointer;
+}
+
+/* This div:
+ - is centered over its parent
+ - centers its child
+ - has z-index above parent
+ - ignores mouse events from parent
+*/
+#copyLogTooltip {
+ pointer-events: none;
+ visibility: hidden;
+ display: flex;
+ justify-content: center;
+ white-space: nowrap;
+ width: 0;
+ position: absolute;
+
+ z-index: 1;
+ left: 50%;
+ bottom: calc(100% + 0.25em);
+}
+
+/* tooltip content (any content could go here) */
+#copyLogTooltipText {
+ background-color: #30E60B;
+ color: #003706;
+ border-radius: 2px;
+ padding: 4px;
+ line-height: 13px;
+ font: 11px sans-serif;
+ font-weight: 400;
+}
+
+/* our speech bubble tail */
+#copyLogTooltipText::after {
+ content: "";
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -4px;
+ border-width: 4px;
+ border-style: solid;
+ border-color: #30E60B transparent transparent transparent;
+}
+
+body {
+ padding: 0px !important;
+ justify-content: space-between;
+ background-color: var(--in-content-page-background);
+}
+
+.title {
+ background-image: url("chrome://browser/content/torconnect/onion.svg");
+ -moz-context-properties: fill, fill-opacity;
+ fill-opacity: 1;
+ fill: var(--onion-color);
+}
+
+.title.error {
+ background-image: url("chrome://browser/content/torconnect/onion-slash.svg");
+}
+
diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js
new file mode 100644
index 000000000000..19fd335ccd13
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.js
@@ -0,0 +1,339 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+/* eslint-env mozilla/frame-script */
+
+const kTorProcessReadyTopic = "TorProcessIsReady";
+const kTorProcessExitedTopic = "TorProcessExited";
+const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
+const kTorBootstrapStatusTopic = "TorBootstrapStatus";
+const kTorBootstrapErrorTopic = "TorBootstrapError";
+const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
+const kTorQuickstartPrefChanged = "TorQuickstartPrefChanged";
+
+const TorLauncherPrefs = {
+ quickstart: "extensions.torlauncher.quickstart",
+ prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
+}
+
+class AboutTorConnect {
+ log(...args) {
+ console.log(...args);
+ }
+
+ logError(...args) {
+ console.error(...args);
+ }
+
+ logDebug(...args) {
+ console.debug(...args);
+ }
+
+ getElem(id) {
+ return document.getElementById(id);
+ }
+ get elemProgressContent() {
+ return this.getElem("progressContent");
+ }
+ get elemProgressDesc() {
+ return this.getElem("connectShortDescText");
+ }
+ get elemProgressMeter() {
+ return this.getElem("progressBackground");
+ }
+ get elemCopyLogLink() {
+ return this.getElem("copyLogLink");
+ }
+ get elemCopyLogTooltip() {
+ return this.getElem("copyLogTooltip");
+ }
+ get elemCopyLogTooltipText() {
+ return this.getElem("copyLogTooltipText");
+ }
+ get elemQuickstartCheckbox() {
+ return this.getElem("quickstartCheckbox");
+ }
+ get elemQuickstartLabel() {
+ return this.getElem("quickstartCheckboxLabel");
+ }
+ get elemConnectButton() {
+ return this.getElem("connectButton");
+ }
+ get elemAdvancedButton() {
+ return this.getElem("advancedButton");
+ }
+ get elemCancelButton() {
+ return this.getElem("cancelButton");
+ }
+ get elemTextContainer() {
+ return this.getElem("text-container");
+ }
+ get elemTitle() {
+ return this.elemTextContainer.getElementsByClassName("title")[0];
+ }
+
+ static get STATE_INITIAL() {
+ return "STATE_INITIAL";
+ }
+
+ static get STATE_BOOTSTRAPPING() {
+ return "STATE_BOOTSTRAPPING";
+ }
+
+ static get STATE_BOOTSTRAPPED() {
+ return "STATE_BOOTSTRAPPED";
+ }
+
+ static get STATE_BOOTSTRAP_ERROR() {
+ return "STATE_BOOTSTRAP_ERROR";
+ }
+
+ get state() {
+ return this._state;
+ }
+
+ setInitialUI() {
+ this.setTitle(this.torStrings.torConnect.torConnect);
+ this.elemProgressDesc.textContent =
+ this.torStrings.settings.torPreferencesDescription;
+ this.showElem(this.elemConnectButton);
+ this.elemConnectButton.focus();
+ this.showElem(this.elemAdvancedButton);
+ this.hideElem(this.elemCopyLogLink);
+ this.hideElem(this.elemCancelButton);
+ this.hideElem(this.elemProgressContent);
+ this.hideElem(this.elemProgressMeter);
+ this.elemTitle.classList.remove("error");
+ }
+
+ setBootstrappingUI() {
+ this.setTitle(this.torStrings.torConnect.torConnecting);
+ this.hideElem(this.elemConnectButton);
+ this.hideElem(this.elemAdvancedButton);
+ this.hideElem(this.elemCopyLogLink);
+ this.showElem(this.elemCancelButton);
+ this.elemCancelButton.focus();
+ this.showElem(this.elemProgressContent);
+ this.showElem(this.elemProgressMeter);
+ this.elemTitle.classList.remove("error");
+ }
+
+ setBootstrapErrorUI() {
+ this.setTitle(this.torStrings.torConnect.torBootstrapFailed);
+ this.elemConnectButton.textContent = this.torStrings.torConnect.tryAgain;
+ this.showElem(this.elemConnectButton);
+ this.hideElem(this.elemCancelButton);
+ this.showElem(this.elemAdvancedButton);
+ this.elemAdvancedButton.focus();
+ this.showElem(this.elemProgressContent);
+ this.hideElem(this.elemProgressMeter);
+ this.elemTitle.classList.add("error");
+ }
+
+ set state(state) {
+ const oldState = this.state;
+ if (oldState === state) {
+ return;
+ }
+ this._state = state;
+ switch (this.state) {
+ case AboutTorConnect.STATE_INITIAL:
+ this.setInitialUI();
+ break;
+ case AboutTorConnect.STATE_BOOTSTRAPPING:
+ this.setBootstrappingUI();
+ break;
+ case AboutTorConnect.STATE_BOOTSTRAP_ERROR:
+ this.setBootstrapErrorUI();
+ break;
+ case AboutTorConnect.STATE_BOOTSTRAPPED:
+ window.close();
+ break;
+ }
+ }
+
+ async showErrorMessage(aErrorObj) {
+ if (aErrorObj && aErrorObj.message) {
+ this.setTitle(aErrorObj.message);
+ if (aErrorObj.details) {
+ this.elemProgressDesc.textContent = aErrorObj.details;
+ }
+ }
+
+ this.showCopyLog();
+ this.showElem(this.elemConnectButton);
+ }
+
+ showElem(elem) {
+ elem.removeAttribute("hidden");
+ }
+
+ hideElem(elem) {
+ elem.setAttribute("hidden", "true");
+ }
+
+ async connect() {
+ // reset the text to original description
+ // in case we are trying again after an error (clears out error text)
+ this.elemProgressDesc.textContent =
+ this.torStrings.settings.torPreferencesDescription;
+
+ this.state = AboutTorConnect.STATE_BOOTSTRAPPING;
+ const error = await RPMSendQuery("TorConnect");
+ if (error) {
+ if (error.details) {
+ this.showErrorMessage({ message: error.details }, true);
+ this.showSaveSettingsError(error.details);
+ }
+ }
+ }
+
+ showCopyLog() {
+ this.elemCopyLogLink.removeAttribute("hidden");
+ }
+
+ async updateBootstrapProgress(status) {
+ let labelText = await RPMSendQuery("GetLocalizedBootstrapStatus", {
+ status,
+ keyword: "TAG",
+ });
+ let percentComplete = status.PROGRESS ? status.PROGRESS : 0;
+ this.elemProgressMeter.style.width = `${percentComplete}%`;
+
+ if (await RPMSendQuery("TorBootstrapErrorOccurred")) {
+ this.state = AboutTorConnect.STATE_BOOTSTRAP_ERROR;
+ return;
+ } else if (await RPMSendQuery("TorIsNetworkDisabled")) {
+ // If tor network is not connected, let's go to the initial state, even
+ // if bootstrap state is greater than 0.
+ this.state = AboutTorConnect.STATE_INITIAL;
+ return;
+ } else if (percentComplete > 0) {
+ this.state = AboutTorConnect.STATE_BOOTSTRAPPING;
+ }
+
+ // Due to async, status might have changed. Do not override desc if so.
+ if (this.state === AboutTorConnect.STATE_BOOTSTRAPPING) {
+ this.hideElem(this.elemConnectButton);
+ }
+ }
+
+ stopTorBootstrap() {
+ RPMSendAsyncMessage("TorStopBootstrap");
+ }
+
+ setTitle(title) {
+ const titleElement = document.querySelector(".title-text");
+ titleElement.textContent = title;
+ document.title = title;
+ }
+
+ async initElements() {
+ this.elemAdvancedButton.textContent = this.torStrings.torConnect.torConfigure;
+ this.elemAdvancedButton.addEventListener("click", () => {
+ RPMSendAsyncMessage("OpenTorAdvancedPreferences");
+ });
+
+ // sets the text content while keping the child elements intact
+ this.elemCopyLogLink.childNodes[0].nodeValue =
+ this.torStrings.torConnect.copyLog;
+ this.elemCopyLogLink.addEventListener("click", async (event) => {
+ const copiedMessage = await RPMSendQuery("TorCopyLog");
+ aboutTorConnect.elemCopyLogTooltipText.textContent = copiedMessage;
+ aboutTorConnect.elemCopyLogTooltip.style.visibility = "visible";
+
+ // clear previous timeout if one already exists
+ if (aboutTorConnect.copyLogTimeoutId) {
+ clearTimeout(aboutTorConnect.copyLogTimeoutId);
+ }
+
+ // hide tooltip after X ms
+ const TOOLTIP_TIMEOUT = 2000;
+ aboutTorConnect.copyLogTimeoutId = setTimeout(function() {
+ aboutTorConnect.elemCopyLogTooltip.style.visibility = "hidden";
+ aboutTorConnect.copyLogTimeoutId = 0;
+ }, TOOLTIP_TIMEOUT);
+ });
+
+
+ this.elemQuickstartLabel.textContent = this.torStrings.settings.quickstartCheckbox;
+ this.elemQuickstartCheckbox.addEventListener("change", () => {
+ const quickstart = this.elemQuickstartCheckbox.checked;
+ RPMSetBoolPref(TorLauncherPrefs.quickstart, quickstart);
+ });
+ this.elemQuickstartCheckbox.checked = await RPMGetBoolPref(TorLauncherPrefs.quickstart);
+
+ this.elemConnectButton.textContent =
+ this.torStrings.torConnect.torConnectButton;
+ this.elemConnectButton.addEventListener("click", () => {
+ this.connect();
+ });
+
+ this.elemCancelButton.textContent = this.torStrings.torConnect.cancel;
+ this.elemCancelButton.addEventListener("click", () => {
+ this.stopTorBootstrap();
+ });
+ }
+
+ initObservers() {
+ RPMAddMessageListener(kTorBootstrapErrorTopic, ({ data }) => {
+ this.showCopyLog();
+ this.stopTorBootstrap();
+ this.showErrorMessage(data);
+ });
+ RPMAddMessageListener(kTorLogHasWarnOrErrTopic, () => {
+ this.showCopyLog();
+ });
+ RPMAddMessageListener(kTorProcessDidNotStartTopic, ({ data }) => {
+ this.showErrorMessage(data);
+ });
+ RPMAddMessageListener(kTorBootstrapStatusTopic, ({ data }) => {
+ this.updateBootstrapProgress(data);
+ });
+ RPMAddMessageListener(kTorQuickstartPrefChanged, ({ data }) => {
+ // update checkbox with latest quickstart pref value
+ this.elemQuickstartCheckbox.checked = data;
+ });
+ RPMAddMessageListener("torconnect:bootstrap-complete", () => {
+ this.state = AboutTorConnect.STATE_BOOTSTRAPPED;
+ });
+ }
+
+ initKeyboardShortcuts() {
+ document.onkeydown = (evt) => {
+ // unfortunately it looks like we still haven't standardized keycodes to
+ // integers, so we must resort to a string compare here :(
+ // see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code for relevant documentation
+ if (evt.code === "Escape") {
+ this.stopTorBootstrap();
+ }
+ };
+ }
+
+ async init() {
+ this.torStrings = await RPMSendQuery("GetTorStrings");
+ document.documentElement.setAttribute(
+ "dir",
+ await RPMSendQuery("GetDirection")
+ );
+ this.initElements();
+ this.initObservers();
+ this.initKeyboardShortcuts();
+ this.state = AboutTorConnect.STATE_INITIAL;
+
+ // Request the most recent bootstrap status info so that a
+ // TorBootstrapStatus notification is generated as soon as possible.
+ RPMSendAsyncMessage("TorRetrieveBootstrapStatus");
+
+ // quickstart is the user set pref for starting tor automatically
+ // prompt_at_startup will be set to false after successful bootstrap, and true on error
+ // by tor-launcher, so we want to keep the connect screen up when prompt_at_startup is true
+ /// even if quickstart is enabled so user can potentially resolve errors on next launch
+ if (await RPMGetBoolPref(TorLauncherPrefs.quickstart) &&
+ !await RPMGetBoolPref(TorLauncherPrefs.prompt_at_startup)) {
+ this.connect();
+ }
+ }
+}
+
+const aboutTorConnect = new AboutTorConnect();
+aboutTorConnect.init();
diff --git a/browser/components/torconnect/content/aboutTorConnect.xhtml b/browser/components/torconnect/content/aboutTorConnect.xhtml
new file mode 100644
index 000000000000..0a0721afb7db
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.xhtml
@@ -0,0 +1,54 @@
+<!-- Copyright (c) 2021, The Tor Project, Inc. -->
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'" />
+ <link rel="stylesheet" href="chrome://browser/skin/onionPattern.css" type="text/css" media="all" />
+ <link rel="stylesheet" href="chrome://browser/content/torconnect/aboutTorConnect.css" type="text/css" media="all" />
+ </head>
+ <body>
+ <div id="progressBackground"></div>
+ <div id="connectPageContainer" class="container">
+ <div id="text-container">
+ <div class="title">
+ <h1 class="title-text"/>
+ </div>
+ <div id="connectLongContent">
+ <div id="connectShortDesc">
+ <p id="connectShortDescText" />
+ </div>
+ </div>
+
+ <div id="progressContent" hidden="true">
+ <div class="tbb-header" pack="center">
+ <image class="tbb-logo"/>
+ </div>
+ <div flex="1">
+ <div id="progressDesc"/>
+ </div>
+ </div>
+
+ <div id="copyLogContainer">
+ <span id="copyLogLink" hidden="true">
+ <div id="copyLogTooltip">
+ <span id="copyLogTooltipText"/>
+ </div>
+ </span>
+ </div>
+
+ <div id="quickstartContainer">
+ <input id="quickstartCheckbox" type="checkbox" />
+ <label id="quickstartCheckboxLabel" for="quickstartCheckbox"/>
+ </div>
+
+ <div id="connectButtonContainer" class="button-container">
+ <button id="advancedButton" hidden="true"></button>
+ <button id="cancelButton" hidden="true"></button>
+ <button id="connectButton" class="primary try-again" hidden="true"></button>
+ </div>
+ </div>
+ </div>
+#include ../../../themes/shared/onionPattern.inc.xhtml
+ </body>
+ <script src="chrome://browser/content/torconnect/aboutTorConnect.js"/>
+</html>
diff --git a/browser/components/torconnect/content/onion-slash.svg b/browser/components/torconnect/content/onion-slash.svg
new file mode 100644
index 000000000000..efb09700ec0b
--- /dev/null
+++ b/browser/components/torconnect/content/onion-slash.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <g fill-opacity="context-fill-opacity" fill="context-fill">
+ <path d="M3.409559 13.112147C3.409559 13.112147 8.200807 8.103115 8.200807 8.103115C8.200807 8.103115 8.200807 6.516403 8.200807 6.516403C8.620819 6.516403 9.009719 6.703075 9.274171 6.998639C9.274171 6.998639 10.160863 6.080835 10.160863 6.080835C9.663071 5.567487 8.978607 5.256367 8.200807 5.256367C8.200807 5.256367 8.200807 4.400787 8.200807 4.400787C9.196391 4.400787 10.098639 4.805243 10.736435 5.458595C10.736435 5.458595 11.623127 4.540791 11.623127 4.540791C10.751991 3.669655 9.538623 3.125195 8.200807 3.125195C8.200807 3.125195 8.200807 2.269615 8.200807 2.269615C9.756407 2.269615 11.172003 2.907411 12.214255 3.918551C12.214255 3.918551 13.100947 3.000747 13.100947 3.000747C11.825355 1.756267 10.098639 0.994023 8.185251 0.994023C4.311807 0.994023 1.185051 4.120779 1.185051 7.994223C1.185051 10.016503 2.040631 11.836555 3.409559 13.112147C3.409559 13.112147 3.409559 13.112147 3.409559 13.112147"/>
+ <path d="M14.205423 4.416343C14.205423 4.416343 13.287619 5.380815 13.287619 5.380815C13.692075 6.158615 13.909859 7.045307 13.909859 7.994223C13.909859 11.152091 11.358675 13.718831 8.200807 13.718831C8.200807 13.718831 8.200807 12.863251 8.200807 12.863251C10.891995 12.863251 13.069835 10.669855 13.069835 7.978667C13.069835 7.278647 12.929831 6.625295 12.665379 6.018611C12.665379 6.018611 11.685351 7.045307 11.685351 7.045307C11.763131 7.340871 11.809799 7.651991 11.809799 7.963111C11.809799 9.954279 10.207531 11.556547 8.216363 11.572103C8.216363 11.572103 8.216363 10.716523 8.216363 10.716523C9.725295 10.700967 10.954219 9.472043 10.954219 7.963111C10.954219 7.916443 10.954219 7.854219 10.954219 7.807551C10.954219 7.807551 4.887379 14.169955 4.887379 14.169955C5.867407 14.698859 6.987439 14.994423 8.185251 14.994423C12.058695 14.994423 15.185451 11.867667 15.185451 7.994223C15.185451 6.687519 14.827663 5.474151 14.205423 4.416343C14.205423 4.416343 14.205423 4.416343 14.20542
3 4.416343"/>
+ <path d="M1.791735 15.461103C1.402835 15.461103 1.045047 15.212207 0.889487 14.838863C0.733927 14.465519 0.827267 14.014395 1.107271 13.734387C1.107271 13.734387 13.458735 0.822907 13.458735 0.822907C13.847635 0.434007 14.454319 0.449563 14.827663 0.838467C15.201007 1.227367 15.216563 1.865163 14.843223 2.269619C14.843223 2.269619 2.491759 15.181099 2.491759 15.181099C2.289531 15.352215 2.040635 15.461107 1.791739 15.461107C1.791739 15.461107 1.791735 15.461103 1.791735 15.461103"/>
+ </g>
+</svg>
diff --git a/browser/components/torconnect/content/onion.svg b/browser/components/torconnect/content/onion.svg
new file mode 100644
index 000000000000..30cd52ba5c51
--- /dev/null
+++ b/browser/components/torconnect/content/onion.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <path fill="context-fill" fill-opacity="context-fill-opacity" d="M12.0246161,21.8174863 L12.0246161,20.3628098 C16.6324777,20.3495038 20.3634751,16.6108555 20.3634751,11.9996673 C20.3634751,7.38881189 16.6324777,3.65016355 12.0246161,3.63685757 L12.0246161,2.18218107 C17.4358264,2.1958197 21.8178189,6.58546322 21.8178189,11.9996673 C21.8178189,17.4142042 17.4358264,21.8041803 12.0246161,21.8174863 L12.0246161,21.8174863 Z M12.0246161,16.7259522 C14.623607,16.7123136 16.7272828,14.6023175 16.7272828,11.9996673 C16.7272828,9.39734991 14.623607,7.28735377 12.0246161,7.27371516 L12.0246161,5.81937131 C15.4272884,5.8326773 18.1819593,8.59400123 18.1819593,11.9996673 C18.1819593,15.4056661 15.4272884,18.1669901 12.0246161,18.1802961 L12.0246161,16.7259522 Z M12.0246161,9.45556355 C13.4187503,9.46886953 14.5454344,10.6022066 14.5454344,11.9996673 C14.5454344,13.3974608 13.4187503,14.5307978 12.0246161,14.5441038 L12.0246161,9.45556355 Z M0,11.9996673 C0,18.6273771 5.37229031,24 12,24 C18
.6273771,24 24,18.6273771 24,11.9996673 C24,5.37229031 18.6273771,0 12,0 C5.37229031,0 0,5.37229031 0,11.9996673 Z"/>
+</svg>
\ No newline at end of file
diff --git a/browser/components/torconnect/content/torBootstrapUrlbar.js b/browser/components/torconnect/content/torBootstrapUrlbar.js
new file mode 100644
index 000000000000..55a595b2dbab
--- /dev/null
+++ b/browser/components/torconnect/content/torBootstrapUrlbar.js
@@ -0,0 +1,136 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+"use strict";
+
+ const TorConnectionStatus = {
+ invalid: -1,
+ offline: 0,
+ connecting: 1,
+ connected: 2,
+ failure: 3,
+ };
+var TorBootstrapUrlbar;
+
+{
+ const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+ );
+ const { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+ );
+ const { TorStrings } = ChromeUtils.import(
+ "resource:///modules/TorStrings.jsm"
+ );
+
+ const kTorProcessReadyTopic = "TorProcessIsReady";
+ const kTorProcessExitedTopic = "TorProcessExited";
+ const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
+ const kTorBootstrapStatusTopic = "TorBootstrapStatus";
+ const kTorBootstrapErrorTopic = "TorBootstrapError";
+
+ const gActiveTopics = [
+ kTorProcessReadyTopic,
+ kTorProcessExitedTopic,
+ kTorProcessDidNotStartTopic,
+ kTorBootstrapStatusTopic,
+ kTorBootstrapErrorTopic,
+ ];
+
+ TorBootstrapUrlbar = {
+ _connectionStatus: TorConnectionStatus.invalid,
+ get ConnectionStatus() {
+ return this._connectionStatus;
+ },
+
+ _torConnectBox : null,
+ get TorConnectBox() {
+ if (!this._torConnectBox) {
+ this._torConnectBox =
+ browser.ownerGlobal.document.getElementById("torconnect-box");
+ }
+ return this._torConnectBox;
+ },
+
+ _torConnectLabel : null,
+ get TorConnectLabel() {
+ if (!this._torConnectLabel) {
+ this._torConnectLabel =
+ browser.ownerGlobal.document.getElementById("torconnect-label");
+ }
+ return this._torConnectLabel;
+ },
+
+ _updateConnectionStatus(percentComplete = 0) {
+ if (TorProtocolService.ownsTorDaemon &&
+ !TorLauncherUtil.useLegacyLauncher) {
+ if (TorProtocolService.isNetworkDisabled()) {
+ if (TorProtocolService.torBootstrapErrorOccurred()) {
+ this._connectionStatus = TorConnectionStatus.failure;
+ } else {
+ this._connectionStatus = TorConnectionStatus.offline;
+ }
+ } else if (percentComplete < 100) {
+ this._connectionStatus = TorConnectionStatus.connecting;
+ } else if (percentComplete === 100) {
+ this._connectionStatus = TorConnectionStatus.connected;
+ }
+ }
+ else
+ {
+ this._connectionStatus = TorConnectionStatus.invalid;
+ }
+
+ switch(this._connectionStatus)
+ {
+ case TorConnectionStatus.failure:
+ case TorConnectionStatus.offline:
+ this.TorConnectBox.removeAttribute("hidden");
+ this.TorConnectLabel.textContent = TorStrings.torConnect.offline;
+ gURLBar._inputContainer.setAttribute("torconnect", "offline");
+ break;
+ case TorConnectionStatus.connecting:
+ this.TorConnectLabel.textContent =
+ TorStrings.torConnect.torConnectingConcise;
+ gURLBar._inputContainer.setAttribute("torconnect", "connecting");
+ break;
+ case TorConnectionStatus.connected:
+ this.TorConnectLabel.textContent =
+ TorStrings.torConnect.torConnectedConcise;
+ gURLBar._inputContainer.setAttribute("torconnect", "connected");
+ // hide torconnect box after 5 seconds
+ let self = this;
+ setTimeout(function() {
+ self.TorConnectBox.setAttribute("hidden", "true");
+ }, 5000);
+ break;
+ }
+ },
+
+ observe(aSubject, aTopic, aData) {
+ const obj = aSubject?.wrappedJSObject;
+
+ switch (aTopic) {
+ case kTorProcessReadyTopic:
+ case kTorProcessExitedTopic:
+ case kTorProcessDidNotStartTopic:
+ case kTorBootstrapErrorTopic:
+ this._updateConnectionStatus();
+ break;
+ case kTorBootstrapStatusTopic:
+ let percentComplete = obj.PROGRESS ? obj.PROGRESS : 0;
+ this._updateConnectionStatus(percentComplete);
+ break;
+ }
+ },
+ init() {
+ for (const topic of gActiveTopics) {
+ Services.obs.addObserver(this, topic);
+ }
+ },
+ uninit() {
+ for (const topic of gActiveTopics) {
+ Services.obs.removeObserver(this, topic);
+ }
+ },
+ };
+}
diff --git a/browser/components/torconnect/content/torconnect-urlbar.css b/browser/components/torconnect/content/torconnect-urlbar.css
new file mode 100644
index 000000000000..db2f1069b22b
--- /dev/null
+++ b/browser/components/torconnect/content/torconnect-urlbar.css
@@ -0,0 +1,65 @@
+/*
+ ensure our torconnect button is always visible (same rule as for the bookmark button)
+*/
+hbox.urlbar-page-action#torconnect-box {
+ display: -moz-inline-box!important;
+ margin: 0 6px;
+ height: 28px;
+}
+/* disable the button-like default css */
+hbox.urlbar-page-action#torconnect-box:hover,
+hbox.urlbar-page-action#torconnect-box:active {
+ background-color: inherit!important;
+}
+
+label#torconnect-label {
+ line-height: 28px;
+ margin: 0;
+ opacity: 0.6;
+}
+
+/* set appropriate sizes for the non-standard ui densities */
+:root[uidensity=compact] {
+ hbox.urlbar-page-action#torconnect-box {
+ margin: 0 4px;
+ height: 24px;
+ }
+ label#torconnect-label {
+ line-height: 24px;
+ }
+}
+:root[uidensity=touch] {
+ hbox.urlbar-page-action#torconnect-box {
+ margin: 0 7px;
+ height: 30px;
+ }
+ label#torconnect-label {
+ line-height: 30px;
+ }
+}
+
+/* hide when hidden attribute is set */
+hbox.urlbar-page-action#torconnect-box[hidden="true"],
+/* hide when user is typing in URL bar */
+#urlbar[usertyping] > #urlbar-input-container > #page-action-buttons > #torconnect-box {
+ display: none!important;
+}
+
+/* hide urlbar's placeholder text when not connectd to tor */
+hbox#urlbar-input-container[torconnect="offline"] input#urlbar-input::placeholder,
+hbox#urlbar-input-container[torconnect="connecting"] input#urlbar-input::placeholder {
+ opacity: 0;
+}
+
+/* hide search suggestions when not connected to tor */
+hbox#urlbar-input-container[torconnect="offline"] + vbox.urlbarView,
+hbox#urlbar-input-container[torconnect="connecting"] + vbox.urlbarView {
+ display: none!important;
+}
+
+/* hide search icon when we are not connected to tor */
+hbox#urlbar-input-container[torconnect="offline"] > #identity-box[pageproxystate="invalid"] > #identity-icon,
+hbox#urlbar-input-container[torconnect="connecting"] > #identity-box[pageproxystate="invalid"] > #identity-icon
+{
+ display: none!important;
+}
diff --git a/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml
new file mode 100644
index 000000000000..bdf9d8f0df00
--- /dev/null
+++ b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml
@@ -0,0 +1,11 @@
+# Copyright (c) 2021, The Tor Project, Inc.
+
+<hbox id="torconnect-box"
+ class="urlbar-icon-wrapper urlbar-page-action"
+ role="status"
+ hidden="true">
+ <image id="torconnect-button" role="presentation"/>
+ <hbox id="torconnect-container">
+ <label id="torconnect-label"/>
+ </hbox>
+</hbox>
\ No newline at end of file
diff --git a/browser/components/torconnect/jar.mn b/browser/components/torconnect/jar.mn
new file mode 100644
index 000000000000..ed8a4de299b2
--- /dev/null
+++ b/browser/components/torconnect/jar.mn
@@ -0,0 +1,7 @@
+browser.jar:
+ content/browser/torconnect/torBootstrapUrlbar.js (content/torBootstrapUrlbar.js)
+ content/browser/torconnect/aboutTorConnect.css (content/aboutTorConnect.css)
+* content/browser/torconnect/aboutTorConnect.xhtml (content/aboutTorConnect.xhtml)
+ content/browser/torconnect/aboutTorConnect.js (content/aboutTorConnect.js)
+ content/browser/torconnect/onion.svg (content/onion.svg)
+ content/browser/torconnect/onion-slash.svg (content/onion-slash.svg)
diff --git a/browser/components/torconnect/moz.build b/browser/components/torconnect/moz.build
new file mode 100644
index 000000000000..eb29c31a4243
--- /dev/null
+++ b/browser/components/torconnect/moz.build
@@ -0,0 +1,6 @@
+JAR_MANIFESTS += ['jar.mn']
+
+EXTRA_JS_MODULES += [
+ 'TorConnectChild.jsm',
+ 'TorConnectParent.jsm',
+]
diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js
index 49054b5dac6a..01609ddda090 100644
--- a/browser/components/torpreferences/content/torPane.js
+++ b/browser/components/torpreferences/content/torPane.js
@@ -1,5 +1,7 @@
"use strict";
+/* global Services */
+
const { TorProtocolService } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
@@ -51,6 +53,10 @@ const { parsePort, parseBridgeStrings, parsePortList } = ChromeUtils.import(
"chrome://browser/content/torpreferences/parseFunctions.jsm"
);
+const TorLauncherPrefs = {
+ quickstart: "extensions.torlauncher.quickstart",
+}
+
/*
Tor Pane
@@ -62,11 +68,21 @@ const gTorPane = (function() {
category: {
title: "label#torPreferences-labelCategory",
},
+ messageBox: {
+ box: "div#torPreferences-connectMessageBox",
+ message: "td#torPreferences-connectMessageBox-message",
+ button: "button#torPreferences-connectMessageBox-button",
+ },
torPreferences: {
header: "h1#torPreferences-header",
description: "span#torPreferences-description",
learnMore: "label#torPreferences-learnMore",
},
+ quickstart: {
+ header: "h2#torPreferences-quickstart-header",
+ description: "span#torPreferences-quickstart-description",
+ enableQuickstartCheckbox: "checkbox#torPreferences-quickstart-toggle",
+ },
bridges: {
header: "h2#torPreferences-bridges-header",
description: "span#torPreferences-bridges-description",
@@ -112,6 +128,10 @@ const gTorPane = (function() {
let retval = {
// cached frequently accessed DOM elements
+ _messageBox: null,
+ _messageBoxMessage: null,
+ _messageBoxButton: null,
+ _enableQuickstartCheckbox: null,
_useBridgeCheckbox: null,
_bridgeSelectionRadiogroup: null,
_builtinBridgeOption: null,
@@ -161,6 +181,43 @@ const gTorPane = (function() {
let prefpane = document.getElementById("mainPrefPane");
+ // 'Connect to Tor' Message Bar
+
+ this._messageBox = prefpane.querySelector(selectors.messageBox.box);
+ this._messageBoxMessage = prefpane.querySelector(selectors.messageBox.message);
+ this._messageBoxButton = prefpane.querySelector(selectors.messageBox.button);
+ // wire up connect button
+ this._messageBoxButton.addEventListener("click", () => {
+ TorProtocolService.connect();
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ // switch to existing about:torconnect tab or create a new one
+ win.switchToTabHavingURI("about:torconnect", true);
+ });
+
+ let populateMessagebox = () => {
+ if (TorProtocolService.shouldShowTorConnect()) {
+ // set messagebox style and text
+ if (TorProtocolService.torBootstrapErrorOccurred()) {
+ this._messageBox.className = "error";
+ this._messageBoxMessage.innerText = TorStrings.torConnect.tryAgainMessage;
+ this._messageBoxButton.innerText = TorStrings.torConnect.tryAgain;
+ } else {
+ this._messageBox.className = "warning";
+ this._messageBoxMessage.innerText = TorStrings.torConnect.connectMessage;
+ this._messageBoxButton.innerText = TorStrings.torConnect.torConnectButton;
+ }
+ } else {
+ this._messageBox.className = "hidden";
+ this._messageBoxMessage.innerText = "";
+ this._messageBoxButton.innerText = "";
+ }
+ }
+ populateMessagebox();
+ // update the messagebox whenever we come back to the page
+ window.addEventListener("focus", val => {
+ populateMessagebox();
+ });
+
// Heading
prefpane.querySelector(selectors.torPreferences.header).innerText =
TorStrings.settings.torPreferencesHeading;
@@ -177,6 +234,26 @@ const gTorPane = (function() {
);
}
+ // Quickstart
+ prefpane.querySelector(selectors.quickstart.header).innerText =
+ TorStrings.settings.quickstartHeading;
+ prefpane.querySelector(selectors.quickstart.description).textContent =
+ TorStrings.settings.quickstartDescription;
+
+ this._enableQuickstartCheckbox = prefpane.querySelector(
+ selectors.quickstart.enableQuickstartCheckbox
+ );
+ this._enableQuickstartCheckbox.setAttribute(
+ "label",
+ TorStrings.settings.quickstartCheckbox
+ );
+ this._enableQuickstartCheckbox.addEventListener("command", e => {
+ const checked = this._enableQuickstartCheckbox.checked;
+ Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, checked);
+ });
+ this._enableQuickstartCheckbox.checked = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ Services.prefs.addObserver(TorLauncherPrefs.quickstart, this);
+
// Bridge setup
prefpane.querySelector(selectors.bridges.header).innerText =
TorStrings.settings.bridgesHeading;
@@ -537,6 +614,15 @@ const gTorPane = (function() {
// Callbacks
//
+ // callback for when the quickstart pref changes
+ observe(subject, topic, data) {
+ if (topic != "nsPref:changed") return;
+ if (data === TorLauncherPrefs.quickstart) {
+ this._enableQuickstartCheckbox.checked =
+ Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ }
+ },
+
// callback when using bridges toggled
onToggleBridge(enabled) {
this._useBridgeCheckbox.checked = enabled;
diff --git a/browser/components/torpreferences/content/torPane.xhtml b/browser/components/torpreferences/content/torPane.xhtml
index 3c966b2b3726..7c8071f2cf10 100644
--- a/browser/components/torpreferences/content/torPane.xhtml
+++ b/browser/components/torpreferences/content/torPane.xhtml
@@ -3,6 +3,29 @@
<script type="application/javascript"
src="chrome://browser/content/torpreferences/torPane.js"/>
<html:template id="template-paneTor">
+
+<!-- Tor Connect Message Box -->
+<groupbox data-category="paneTor" hidden="true">
+ <html:div id="torPreferences-connectMessageBox"
+ class="subcategory"
+ data-category="paneTor"
+ hidden="true">
+ <html:table >
+ <html:tr>
+ <html:td>
+ <html:div id="torPreferences-connectMessageBox-icon"/>
+ </html:td>
+ <html:td id="torPreferences-connectMessageBox-message">
+ </html:td>
+ <html:td>
+ <html:button id="torPreferences-connectMessageBox-button">
+ </html:button>
+ </html:td>
+ </html:tr>
+ </html:table>
+ </html:div>
+</groupbox>
+
<hbox id="torPreferencesCategory"
class="subcategory"
data-category="paneTor"
@@ -18,6 +41,17 @@
</description>
</groupbox>
+<!-- Quickstart -->
+<groupbox id="torPreferences-quickstart-group"
+ data-category="paneTor"
+ hidden="true">
+ <html:h2 id="torPreferences-quickstart-header"/>
+ <description flex="1">
+ <html:span id="torPreferences-quickstart-description"/>
+ </description>
+ <checkbox id="torPreferences-quickstart-toggle"/>
+</groupbox>
+
<!-- Bridges -->
<groupbox id="torPreferences-bridges-group"
data-category="paneTor"
diff --git a/browser/components/torpreferences/content/torPreferences.css b/browser/components/torpreferences/content/torPreferences.css
index 4dac2c457823..f125936dac74 100644
--- a/browser/components/torpreferences/content/torPreferences.css
+++ b/browser/components/torpreferences/content/torPreferences.css
@@ -2,6 +2,127 @@
list-style-image: url("chrome://browser/content/torpreferences/torPreferencesIcon.svg");
}
+/* Connect Message Box */
+
+#torPreferences-connectMessageBox {
+ display: block;
+ position: relative;
+
+ width: auto;
+ min-height: 32px;
+ border-radius: 4px;
+ padding: 4px;
+}
+
+#torPreferences-connectMessageBox.hidden {
+ display: none;
+}
+
+#torPreferences-connectMessageBox.error {
+ background-color: var(--red-60);
+ color: white;
+}
+
+#torPreferences-connectMessageBox.warning {
+ background-color: var(--yellow-50);
+ color: var(--yellow-90);
+}
+
+#torPreferences-connectMessageBox table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+#torPreferences-connectMessageBox td {
+ vertical-align: top;
+ padding: 0px;
+}
+
+#torPreferences-connectMessageBox td:first-child {
+ width: 24px;
+}
+
+#torPreferences-connectMessageBox-icon {
+ display: block;
+ width: 16px;
+ height: 16px;
+ padding: 4px;
+
+ mask-repeat: no-repeat !important;
+ mask-size: 16px !important;
+ mask-position: 4px 4px !important;
+}
+
+#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-icon
+{
+ mask: url("chrome://browser/skin/onion-slash.svg");
+ background-color: white;
+}
+
+#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-icon
+{
+ mask: url("chrome://global/skin/icons/warning.svg");
+ background-color: black;
+}
+
+#torPreferences-connectMessageBox-message {
+ display: block;
+ line-height: 16px;
+ font-size: 13px;
+ margin-right: 8px;
+ padding-left: 4px!important;
+ padding-top: 4px!important;
+}
+
+#torPreferences-connectMessageBox-button {
+ display: block;
+ width: auto;
+ height: 24px;
+ line-height: 24px;
+ min-height: 24px;
+ max-height: 24px;
+ margin: 0px;
+
+ border-radius: 2px;
+ border: 0;
+ padding-left: 8px;
+ padding-right: 8px;
+ margin-left: auto;
+ margin-right: 0px;
+
+ font-size: 11px;
+ font-weight: 400;
+ white-space: nowrap;
+}
+
+#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button {
+ background-color: var(--red-70);
+}
+
+#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button:hover {
+ background-color: var(--red-80);
+}
+
+#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button:active {
+ background-color: var(--red-90);
+}
+
+#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button {
+ background-color: var(--yellow-60);
+}
+
+#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:hover {
+ background-color: var(--yellow-70);
+ color: white!important;
+}
+
+#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:active {
+ background-color: var(--yellow-80);
+ color: white!important;
+}
+
+/* Advanced Settings */
+
#torPreferences-advanced-grid {
display: grid;
grid-template-columns: auto 1fr;
diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm
index 13b1279105f2..f727c386701c 100644
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -10,6 +10,33 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+// in certain scenarios we want user input uris to open in a new tab if they do so from the
+// about:torconnect tab
+function maybeUpdateOpenLocationForTorConnect(openUILinkWhere, currentURI, destinationURI) {
+ try {
+ // only open in new tab if:
+ if (// user is navigating away from about:torconnect
+ currentURI === "about:torconnect" &&
+ // we are trying to open in same tab
+ openUILinkWhere === "current" &&
+ // only if user still has not bootstrapped
+ TorProtocolService.shouldShowTorConnect() &&
+ // and user is not just navigating to about:torconnect
+ destinationURI !== "about:torconnect") {
+ return "tab";
+ }
+ } catch (e) {
+ // swallow exception and fall through returning original so we don't accidentally break
+ // anything if an exception is thrown
+ }
+
+ return openUILinkWhere;
+};
+
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
@@ -1832,6 +1859,10 @@ class UrlbarInput {
// area when the current tab is re-selected.
browser.focus();
+ openUILinkWhere = maybeUpdateOpenLocationForTorConnect(
+ openUILinkWhere,
+ this.window.gBrowser.currentURI.asciiSpec,
+ url);
if (openUILinkWhere != "current") {
this.handleRevert();
}
diff --git a/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm
new file mode 100644
index 000000000000..3125c84558db
--- /dev/null
+++ b/browser/modules/TorConnect.jsm
@@ -0,0 +1,62 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["TorConnect"];
+
+const { Services } = ChromeUtils.import(
+ "resource://gre/modules/Services.jsm"
+);
+
+const { BrowserWindowTracker } = ChromeUtils.import(
+ "resource:///modules/BrowserWindowTracker.jsm"
+);
+
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+// TODO: move the bootstrap state management out of each of the individual
+// about:torconnect pages and stick it here
+var TorConnect = (() => {
+ let retval = {
+ init : function() {
+ let topics = [
+ "TorBootstrapStatus",
+ ];
+
+ for(const topic of topics) {
+ Services.obs.addObserver(this, topic);
+ }
+ },
+
+ observe: function(subject, topic, data) {
+ switch(topic) {
+ case "TorBootstrapStatus":
+ const obj = subject?.wrappedJSObject;
+ if (obj?.PROGRESS === 100) {
+ // open home page(s) in new tabs
+ const win = BrowserWindowTracker.getTopWindow()
+ const urls = Services.prefs.getStringPref("browser.startup.homepage").split('|');
+
+ let location="tab";
+ for(const url of urls) {
+ win.openTrustedLinkIn(url, location);
+ // open subsequent tabs behind first tab
+ location = "tabshifted";
+ }
+
+ Services.obs.notifyObservers(null, "torconnect:bootstrap-complete");
+ }
+ break;
+ default:
+ // ignore
+ break;
+ }
+ },
+
+ shouldShowTorConnect : function() {
+ return TorProtocolService.shouldShowTorConnect();
+ },
+ };
+ retval.init();
+ return retval;
+})(); /* TorConnect */
\ No newline at end of file
diff --git a/browser/modules/TorProcessService.jsm b/browser/modules/TorProcessService.jsm
new file mode 100644
index 000000000000..201e331b2806
--- /dev/null
+++ b/browser/modules/TorProcessService.jsm
@@ -0,0 +1,12 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["TorProcessService"];
+
+var TorProcessService = {
+ get isBootstrapDone() {
+ const svc = Cc["@torproject.org/torlauncher-process-service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject;
+ return svc.mIsBootstrapDone;
+ },
+};
diff --git a/browser/modules/TorProtocolService.jsm b/browser/modules/TorProtocolService.jsm
index b4e6ed9a3253..fc7f2c884aa2 100644
--- a/browser/modules/TorProtocolService.jsm
+++ b/browser/modules/TorProtocolService.jsm
@@ -1,3 +1,5 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
"use strict";
var EXPORTED_SYMBOLS = ["TorProtocolService"];
@@ -11,6 +13,10 @@ var TorProtocolService = {
Ci.nsISupports
).wrappedJSObject,
+ _tlproc: Cc["@torproject.org/torlauncher-process-service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject,
+
// maintain a map of tor settings set by Tor Browser so that we don't
// repeatedly set the same key/values over and over
// this map contains string keys to primitive or array values
@@ -196,11 +202,11 @@ var TorProtocolService = {
// writes current tor settings to disk
flushSettings() {
- this._tlps.TorSendCommand("SAVECONF");
+ this.sendCommand("SAVECONF");
},
- getLog() {
- let countObj = { value: 0 };
+ getLog(countObj) {
+ countObj = countObj || { value: 0 };
let torLog = this._tlps.TorGetLog(countObj);
return torLog;
},
@@ -209,4 +215,116 @@ var TorProtocolService = {
get ownsTorDaemon() {
return TorLauncherUtil.shouldStartAndOwnTor;
},
+
+ // Assumes `ownsTorDaemon` is true
+ isNetworkDisabled() {
+ const reply = TorProtocolService._tlps.TorGetConfBool(
+ "DisableNetwork",
+ true
+ );
+ if (TorProtocolService._tlps.TorCommandSucceeded(reply)) {
+ return reply.retVal;
+ }
+ return true;
+ },
+
+ enableNetwork() {
+ let settings = {};
+ settings.DisableNetwork = false;
+ let errorObject = {};
+ if (!this._tlps.TorSetConfWithReply(settings, errorObject)) {
+ throw new Error(errorObject.details);
+ }
+ },
+
+ sendCommand(cmd) {
+ return this._tlps.TorSendCommand(cmd);
+ },
+
+ retrieveBootstrapStatus() {
+ return this._tlps.TorRetrieveBootstrapStatus();
+ },
+
+ _GetSaveSettingsErrorMessage(aDetails) {
+ try {
+ return TorLauncherUtil.getSaveSettingsErrorMessage(aDetails);
+ } catch (e) {
+ console.log("GetSaveSettingsErrorMessage error", e);
+ return "Unexpected Error";
+ }
+ },
+
+ setConfWithReply(settings) {
+ let result = false;
+ const error = {};
+ try {
+ result = this._tlps.TorSetConfWithReply(settings, error);
+ } catch (e) {
+ console.log("TorSetConfWithReply error", e);
+ error.details = this._GetSaveSettingsErrorMessage(e.message);
+ }
+ return { result, error };
+ },
+
+ isBootstrapDone() {
+ return this._tlproc.mIsBootstrapDone;
+ },
+
+ clearBootstrapError() {
+ return this._tlproc.TorClearBootstrapError();
+ },
+
+ shouldShowTorConnect() {
+ return (
+ this.ownsTorDaemon &&
+ !TorLauncherUtil.useLegacyLauncher &&
+ (this.isNetworkDisabled() || !this.isBootstrapDone())
+ );
+ },
+
+ torBootstrapErrorOccurred() {
+ return this._tlproc.TorBootstrapErrorOccurred;
+ },
+
+ // Resolves to null if ok, or an error otherwise
+ connect() {
+ const kTorConfKeyDisableNetwork = "DisableNetwork";
+ const settings = {};
+ settings[kTorConfKeyDisableNetwork] = false;
+ const { result, error } = this.setConfWithReply(settings);
+ if (!result) {
+ return error;
+ }
+ try {
+ this.sendCommand("SAVECONF");
+ this.clearBootstrapError();
+ this.retrieveBootstrapStatus();
+ } catch (e) {
+ return error;
+ }
+ return null;
+ },
+
+ torLogHasWarnOrErr() {
+ return this._tlps.TorLogHasWarnOrErr;
+ },
+
+ torStopBootstrap() {
+ // Tell tor to disable use of the network; this should stop the bootstrap
+ // process.
+ const kErrorPrefix = "Setting DisableNetwork=1 failed: ";
+ try {
+ let settings = {};
+ settings.DisableNetwork = true;
+ const { result, error } = this.setConfWithReply(settings);
+ if (!result) {
+ console.log(
+ `Error stopping bootstrap ${kErrorPrefix} ${error.details}`
+ );
+ }
+ } catch (e) {
+ console.log(`Error stopping bootstrap ${kErrorPrefix} ${e}`);
+ }
+ this.retrieveBootstrapStatus();
+ },
};
diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm
index 1e08b168e4af..c086d0fe3117 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -257,6 +257,9 @@ var TorStrings = {
"Tor Browser routes your traffic over the Tor Network, run by thousands of volunteers around the world."
),
learnMore: getString("torPreferences.learnMore", "Learn More"),
+ quickstartHeading: getString("torPreferences.quickstart", "Quickstart"),
+ quickstartDescription: getString("torPreferences.quickstartDescription", "Quickstart allows Tor Browser to connect automatically."),
+ quickstartCheckbox : getString("torPreferences.quickstartCheckbox", "Always connect automatically"),
bridgesHeading: getString("torPreferences.bridges", "Bridges"),
bridgesDescription: getString(
"torPreferences.bridgesDescription",
@@ -364,6 +367,78 @@ var TorStrings = {
return retval;
})() /* Tor Network Settings Strings */,
+ torConnect: (() => {
+ const tsbNetwork = new TorDTDStringBundle(
+ ["chrome://torlauncher/locale/network-settings.dtd"],
+ ""
+ );
+ const tsbLauncher = new TorPropertyStringBundle(
+ "chrome://torlauncher/locale/torlauncher.properties",
+ "torlauncher."
+ );
+ const tsbCommon = new TorPropertyStringBundle(
+ "chrome://global/locale/commonDialogs.properties",
+ ""
+ );
+
+ const getStringNet = tsbNetwork.getString.bind(tsbNetwork);
+ const getStringLauncher = tsbLauncher.getString.bind(tsbLauncher);
+ const getStringCommon = tsbCommon.getString.bind(tsbCommon);
+
+ return {
+ torConnect: getStringNet(
+ "torsettings.wizard.title.default",
+ "Connect to Tor"
+ ),
+
+ torConnecting: getStringNet(
+ "torsettings.wizard.title.connecting",
+ "Establishing a Connection"
+ ),
+
+ torConnectingConcise: getStringNet(
+ "torConnect.connectingConcise",
+ "Connecting…"
+ ),
+
+ torBootstrapFailed: getStringLauncher(
+ "tor_bootstrap_failed",
+ "Tor failed to establish a Tor network connection."
+ ),
+
+ torConfigure: getStringNet(
+ "torsettings.wizard.title.configure",
+ "Tor Network Settings"
+ ),
+
+ copyLog: getStringNet(
+ "torConnect.copyLog",
+ "Copy Tor Logs"
+ ),
+
+ torConnectButton: getStringNet("torSettings.connect", "Connect"),
+
+ cancel: getStringCommon("Cancel", "Cancel"),
+
+ torConnected: getStringLauncher(
+ "torlauncher.bootstrapStatus.done",
+ "Connected to the Tor network"
+ ),
+
+ torConnectedConcise: getStringLauncher(
+ "torConnect.connectedConcise",
+ "Connected"
+ ),
+
+ tryAgain: getStringNet("torConnect.tryAgain", "Try connecting again"),
+ offline: getStringNet("torConnect.offline", "Offline"),
+
+ // tor connect strings for message box in about:preferences#tor
+ connectMessage: getStringNet("torConnect.connectMessage", "Changes to Tor Settings will not take effect until you connect to the Tor Network"),
+ tryAgainMessage: getStringNet("torConnect.tryAgainMessage", "Tor Browser has failed to establish a connection to the Tor Network"),
+ };
+ })(),
+
/*
Tor Onion Services Strings, e.g., for the authentication prompt.
*/
diff --git a/browser/modules/moz.build b/browser/modules/moz.build
index 5fb78d1c07a8..7f091e0e7711 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -155,6 +155,8 @@ EXTRA_JS_MODULES += [
'TabUnloader.jsm',
'ThemeVariableMap.jsm',
'TopSiteAttribution.jsm',
+ 'TorConnect.jsm',
+ 'TorProcessService.jsm',
'TorProtocolService.jsm',
'TorStrings.jsm',
'TransientPrefs.jsm',
diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
index e4a3c8d2d41c..d38e1001282b 100644
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -8,6 +8,7 @@
# to the location of the actual manifest.
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
+ skin/classic/browser/onionPattern.css (../shared/onionPattern.css)
skin/classic/browser/blockedSite.css (../shared/blockedSite.css)
skin/classic/browser/error-pages.css (../shared/error-pages.css)
skin/classic/browser/aboutRestartRequired.css (../shared/aboutRestartRequired.css)
diff --git a/browser/themes/shared/onionPattern.css b/browser/themes/shared/onionPattern.css
new file mode 100644
index 000000000000..c605a4b4f59e
--- /dev/null
+++ b/browser/themes/shared/onionPattern.css
@@ -0,0 +1,124 @@
+/* Onion pattern */
+
+:root {
+ --sqrt3: 1.73205080757;
+}
+
+.onion-pattern-container {
+ opacity: var(--onion-opacity, 1);
+ flex: auto; /* grow to consume remaining space on the page */
+ display: flex;
+ margin: 0 auto;
+ width: 100%;
+ height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); /* room for 2 rows of circles */
+ max-height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px));
+ direction: ltr;
+}
+
+.onion-pattern-crop {
+ display: flex;
+ justify-content: center;
+ overflow-x: hidden;
+ pointer-events: none; /* for some reason, elements with overflow-x: hidden set become focusable */
+
+ margin: 0 auto;
+}
+
+/* Centers horizontally within the root container*/
+.onion-pattern-column {
+ width: calc(40 * var(--onion-radius, 50px)); /* room for 20 circles in a row */
+ height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); /* room for 2 rows of circles */
+ flex-shrink: 0;
+ overflow-x: hidden; /* clip extra circles on the sides */
+ pointer-events: none; /* for some reason, elements with overflow-x: hidden set become focusable */
+}
+
+.onion-pattern-row {
+ width: calc(40 * var(--onion-radius, 50px)); /* room for 20 circles in a row */
+ display: flex;
+ flex-direction: row;
+ position: relative;
+}
+
+.onion-pattern-offset-row {
+ left: calc(-1 * var(--onion-radius, 50px));
+ margin-top: calc((var(--sqrt3) - 2.0) * var(--onion-radius, 50px));
+}
+
+/* With borders, circles are 100x100 pixels*/
+.circle {
+ position: relative;
+ min-width: calc(2 * var(--onion-radius, 50px));
+ min-height: calc(2 * var(--onion-radius, 50px));
+ border-radius: 50%;
+ box-sizing: border-box;
+}
+
+.inner {
+ position: absolute;
+ box-sizing: border-box;
+ border-radius: 50%;
+}
+
+.inner:nth-child(1){
+ width: 100%;
+ height: 100%;
+}
+
+.inner:nth-child(2){
+ transform: translate(20%, 20%);
+ width: calc(100% * 5/7);
+ height: calc(100% * 5/7);
+}
+
+.inner:nth-child(3){
+ transform: translate(calc(100% * 2/3), calc(100% * 2/3));
+ width: calc(100% * 3/7);
+ height: calc(100% * 3/7);
+}
+
+.inner:nth-child(4){
+ transform: translate(300%, 300%);
+ width: calc(100% * 1/7);
+ height: calc(100% * 1/7);
+}
+
+.solid {
+ background-color: var(--onion-color, #000);
+}
+
+.border {
+ border: 4px solid var(--onion-color, #000);
+}
+
+.dashed {
+ border: 4px dashed var(--onion-color, #000);
+}
+
+.dotted {
+ border: 4px dotted var(--onion-color, #000);
+}
+
+.bold {
+ border: 8px solid var(--onion-color, #000);
+}
+
+.top-half {
+ width: calc(2 * var(--onion-radius, 50px));
+ height: var(--onion-radius, 50px);
+ border-radius: var(--onion-radius, 50px) var(--onion-radius, 50px) 0 0;
+ box-sizing: border-box;
+}
+
+.bottom-half {
+ width: calc(2 * var(--onion-radius, 50px));
+ height: var(--onion-radius, 50px);
+ border-radius: 0 0 var(--onion-radius, 50px) var(--onion-radius, 50px);
+ box-sizing: border-box;
+}
+
+.scaler {
+ position: absolute;
+ left:0;
+ bottom:0;
+}
\ No newline at end of file
diff --git a/browser/themes/shared/onionPattern.inc.xhtml b/browser/themes/shared/onionPattern.inc.xhtml
new file mode 100644
index 000000000000..6bbde93684a2
--- /dev/null
+++ b/browser/themes/shared/onionPattern.inc.xhtml
@@ -0,0 +1,210 @@
+<!--
+ - The abstract onion pattern begins here. There are two
+ - "onion-pattern-row" elements, each containing 14 circles. The width
+ - of "onion-pattern-row" is fixed at a value that is wide enough so the
+ - circles are not distorted by the flex-based layout. The parent
+ - "onion-pattern-container" element has overflow-x: hidden and is designed
+ - to expand to the width of the page, until it reaches a maximum width
+ - that can accommodate all 14 circles. Since the rows are wider than
+ - most browser windows, typically the two rows of onions will fill the
+ - bottom of the page. On really wide pages, the onions are centered at
+ - the bottom of the page.
+-->
+
+<div class="onion-pattern-container">
+ <!-- for some reason, these two elements are focusable, seems related to
+ - flex css somehow; disable their tabindex to fix
+ -->
+ <div class="onion-pattern-crop" tabindex="-1">
+ <div class="onion-pattern-column" tabindex="-1">
+ <div class="onion-pattern-row">
+ <div class="circle solid"></div>
+
+ <div class="circle dashed"></div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle">
+ <div class="bottom-half solid"></div>
+ <div class="bottom-half dotted"></div>
+ </div>
+
+ <div class="circle border"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle">
+ <div class="bottom-half solid"></div>
+ <div class="bottom-half solid"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle dashed"></div>
+ </div>
+
+ <div class="onion-pattern-row onion-pattern-offset-row">
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="top-half solid"></div>
+ <div class="top-half solid"></div>
+ </div>
+
+ <div class="circle border"></div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle">
+ <div class="top-half border"></div>
+ <div class="top-half dashed"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle">
+ <div class="top-half dotted"></div>
+ <div class="top-half solid"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="top-half solid"></div>
+ <div class="top-half dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle">
+ <div class="top-half solid"></div>
+ <div class="top-half solid"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/browser/themes/shared/urlbar-searchbar.inc.css b/browser/themes/shared/urlbar-searchbar.inc.css
index d3cc6bf7f024..297dbcdf444d 100644
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -826,3 +826,5 @@
}
%include ../../components/onionservices/content/onionlocation-urlbar.css
+%include ../../components/torconnect/content/torconnect-urlbar.css
+
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index afc872569519..e74851a6672c 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -16387,9 +16387,56 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) {
StylePrefersColorScheme Document::PrefersColorScheme(
IgnoreRFP aIgnoreRFP) const {
+
+ // tor-browser#27476
+ // should this document ignore resist finger-printing settings with regards to
+ // setting the color scheme
+ // currently only enabled for about:torconnect but we could expand to other non-
+ // SystemPrincipal pages if we wish
+ const auto documentUsesPreferredColorScheme = [](auto const* constDocument) -> bool {
+ if (auto* document = const_cast<Document*>(constDocument); document != nullptr) {
+ auto uri = document->GetDocBaseURI();
+
+ // try and extract out our prepath and filepath portions of the uri to C-strings
+ nsAutoCString prePathStr, filePathStr;
+ if(NS_FAILED(uri->GetPrePath(prePathStr)) ||
+ NS_FAILED(uri->GetFilePath(filePathStr))) {
+ return false;
+ }
+
+ // stick them in string view for easy comparisons
+ std::string_view prePath(prePathStr.get(), prePathStr.Length()),
+ filePath(filePathStr.get(), filePathStr.Length());
+
+ // these about URIs will have the user's preferred color scheme exposed to them
+ // we can place other URIs here in the future if we wish
+ // see nsIURI.idl for URI part definitions
+ constexpr struct {
+ std::string_view prePath;
+ std::string_view filePath;
+ } allowedURIs[] = {
+ { "about:", "torconnect" },
+ };
+
+ // check each uri in the allow list against this document's uri
+ // verify the prepath and the file path match
+ for(auto const& uri : allowedURIs) {
+ if (prePath == uri.prePath &&
+ filePath == uri.filePath) {
+ // positive match means we can apply dark-mode to the page
+ return true;
+ }
+ }
+ }
+
+ // do not allow if no match or other error
+ return false;
+ };
+
if (aIgnoreRFP == IgnoreRFP::No &&
- nsContentUtils::ShouldResistFingerprinting(this)) {
- return StylePrefersColorScheme::Light;
+ nsContentUtils::ShouldResistFingerprinting(this) &&
+ !documentUsesPreferredColorScheme(this)) {
+ return StylePrefersColorScheme::Light;
}
if (nsPresContext* pc = GetPresContext()) {
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
index abe1e56d9714..759060f131ff 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -6082,6 +6082,8 @@ void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
NS_ENSURE_SUCCESS_VOID(rv);
if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
+ // we want about:torconnect pages to be able to close themselves after bootstrap
+ !StringBeginsWith(url, NS_LITERAL_STRING("about:torconnect")) &&
!HadOriginalOpener() && !aTrustedCaller) {
bool allowClose =
mAllowScriptsToClose ||
diff --git a/toolkit/modules/AsyncPrefs.jsm b/toolkit/modules/AsyncPrefs.jsm
index aca86556cd5e..b81ff5e22b9b 100644
--- a/toolkit/modules/AsyncPrefs.jsm
+++ b/toolkit/modules/AsyncPrefs.jsm
@@ -18,6 +18,8 @@ const kAllowedPrefs = new Set([
"testing.allowed-prefs.some-char-pref",
"testing.allowed-prefs.some-int-pref",
+ "extensions.torlauncher.quickstart",
+
"narrate.rate",
"narrate.voice",
diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm
index eceaa7c857de..0927391c2ba7 100644
--- a/toolkit/modules/RemotePageAccessManager.jsm
+++ b/toolkit/modules/RemotePageAccessManager.jsm
@@ -96,6 +96,7 @@ let RemotePageAccessManager = {
RPMPrefIsLocked: ["security.tls.version.min"],
RPMAddToHistogram: ["*"],
RPMGetTorStrings: ["*"],
+ RPMSendQuery: ["ShouldShowTorConnect"],
},
"about:newinstall": {
RPMGetUpdateChannel: ["*"],
@@ -179,6 +180,31 @@ let RemotePageAccessManager = {
RPMAddMessageListener: ["*"],
RPMRemoveMessageListener: ["*"],
},
+ "about:torconnect": {
+ RPMAddMessageListener: ["*"],
+ RPMSendAsyncMessage: [
+ "OpenTorAdvancedPreferences",
+ "TorRetrieveBootstrapStatus",
+ "TorStopBootstrap",
+ ],
+ RPMSendQuery: [
+ "GetDirection",
+ "GetLocalizedBootstrapStatus",
+ "GetTorStrings",
+ "TorBootstrapErrorOccurred",
+ "TorConnect",
+ "TorCopyLog",
+ "TorIsNetworkDisabled",
+ "TorLogHasWarnOrErr",
+ ],
+ RPMGetBoolPref: [
+ "extensions.torlauncher.quickstart",
+ "extensions.torlauncher.prompt_at_startup",
+ ],
+ RPMSetBoolPref: [
+ "extensions.torlauncher.quickstart",
+ ],
+ },
},
/**
diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm
index 1fb397373151..79881cba42d6 100644
--- a/toolkit/mozapps/update/UpdateService.jsm
+++ b/toolkit/mozapps/update/UpdateService.jsm
@@ -12,6 +12,17 @@ const { AppConstants } = ChromeUtils.import(
const { AUSTLMY } = ChromeUtils.import(
"resource://gre/modules/UpdateTelemetry.jsm"
);
+
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+function _shouldRegisterBootstrapObserver(errorCode) {
+ return errorCode == PROXY_SERVER_CONNECTION_REFUSED &&
+ !TorProtocolService.isBootstrapDone() &&
+ TorProtocolService.ownsTorDaemon;
+};
+
const {
Bits,
BitsRequest,
@@ -201,6 +212,7 @@ const INVALID_UPDATER_STATUS_CODE = 99;
// Custom update error codes
const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
const NETWORK_ERROR_OFFLINE = 111;
+const PROXY_SERVER_CONNECTION_REFUSED = 2152398920;
// Error codes should be < 1000. Errors above 1000 represent http status codes
const HTTP_ERROR_OFFSET = 1000;
@@ -2220,6 +2232,9 @@ UpdateService.prototype = {
case "network:offline-status-changed":
this._offlineStatusChanged(data);
break;
+ case "torconnect:bootstrap-complete":
+ this._bootstrapComplete();
+ break;
case "nsPref:changed":
if (data == PREF_APP_UPDATE_LOG || data == PREF_APP_UPDATE_LOG_FILE) {
gLogEnabled; // Assigning this before it is lazy-loaded is an error.
@@ -2640,6 +2655,35 @@ UpdateService.prototype = {
this._attemptResume();
},
+ _registerBootstrapObserver: function AUS__registerBootstrapObserver() {
+ if (this._registeredBootstrapObserver) {
+ LOG(
+ "UpdateService:_registerBootstrapObserver - observer already registered"
+ );
+ return;
+ }
+
+ LOG(
+ "UpdateService:_registerBootstrapObserver - waiting for tor bootstrap to " +
+ "be complete, then forcing another check"
+ );
+
+ Services.obs.addObserver(this, "torconnect:bootstrap-complete");
+ this._registeredBootstrapObserver = true;
+ },
+
+ _bootstrapComplete: function AUS__bootstrapComplete() {
+ Services.obs.removeObserver(this, "torconnect:bootstrap-complete");
+ this._registeredBootstrapObserver = false;
+
+ LOG(
+ "UpdateService:_bootstrapComplete - bootstrapping complete, forcing " +
+ "another background check"
+ );
+
+ this._attemptResume();
+ },
+
onCheckComplete: function AUS_onCheckComplete(request, updates) {
this._selectAndInstallUpdate(updates);
},
@@ -2659,6 +2703,11 @@ UpdateService.prototype = {
AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_OFFLINE);
}
return;
+ } else if (_shouldRegisterBootstrapObserver(update.errorCode)) {
+ // Register boostrap observer to try again, but only when we own the
+ // tor process.
+ this._registerBootstrapObserver();
+ return;
}
// Send the error code to telemetry
@@ -5189,6 +5238,7 @@ Downloader.prototype = {
var state = this._patch.state;
var shouldShowPrompt = false;
var shouldRegisterOnlineObserver = false;
+ var shouldRegisterBootstrapObserver = false;
var shouldRetrySoon = false;
var deleteActiveUpdate = false;
var retryTimeout = Services.prefs.getIntPref(
@@ -5266,7 +5316,18 @@ Downloader.prototype = {
);
shouldRegisterOnlineObserver = true;
deleteActiveUpdate = false;
-
+ } else if(_shouldRegisterBootstrapObserver(status)) {
+ // Register a bootstrap observer to try again.
+ // The bootstrap observer will continue the incremental download by
+ // calling downloadUpdate on the active update which continues
+ // downloading the file from where it was.
+ LOG("Downloader:onStopRequest - not bootstrapped, register bootstrap observer: true");
+ AUSTLMY.pingDownloadCode(
+ this.isCompleteUpdate,
+ AUSTLMY.DWNLD_RETRY_OFFLINE
+ );
+ shouldRegisterBootstrapObserver = true;
+ deleteActiveUpdate = false;
// Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED,
// NS_ERROR_NET_RESET and NS_ERROR_DOCUMENT_NOT_CACHED can be returned
// when disconnecting the internet while a download of a MAR is in
@@ -5384,7 +5445,7 @@ Downloader.prototype = {
// Only notify listeners about the stopped state if we
// aren't handling an internal retry.
- if (!shouldRetrySoon && !shouldRegisterOnlineObserver) {
+ if (!shouldRetrySoon && !shouldRegisterOnlineObserver && !shouldRegisterBootstrapObserver) {
// Make shallow copy in case listeners remove themselves when called.
var listeners = this._listeners.concat();
var listenerCount = listeners.length;
@@ -5532,6 +5593,9 @@ Downloader.prototype = {
if (shouldRegisterOnlineObserver) {
LOG("Downloader:onStopRequest - Registering online observer");
this.updateService._registerOnlineObserver();
+ } else if (shouldRegisterBootstrapObserver) {
+ LOG("Downloader:onStopRequest - Registering bootstrap observer");
+ this.updateService._registerBootstrapObserver();
} else if (shouldRetrySoon) {
LOG("Downloader:onStopRequest - Retrying soon");
this.updateService._consecutiveSocketErrors++;
diff --git a/toolkit/themes/shared/in-content/info-pages.inc.css b/toolkit/themes/shared/in-content/info-pages.inc.css
index 6943a3340e35..5b3c911a5aab 100644
--- a/toolkit/themes/shared/in-content/info-pages.inc.css
+++ b/toolkit/themes/shared/in-content/info-pages.inc.css
@@ -41,10 +41,11 @@ body.wide-container {
background-image: url("chrome://global/skin/icons/info.svg");
background-position: left 0;
background-repeat: no-repeat;
- background-size: 1.6em;
- margin-inline-start: -2.3em;
- padding-inline-start: 2.3em;
- font-size: 2.2em;
+ background-size: 3.0em;
+ margin-inline-start: -4.5em;
+ padding-inline-start: 4.5em;
+ margin-bottom: -2.0em;
+ font-size: 1.5em;
-moz-context-properties: fill;
fill: currentColor;
}
@@ -56,7 +57,10 @@ body.wide-container {
.title-text {
font-size: inherit;
- padding-bottom: 0.4em;
+ padding-bottom: 2.0em !important;
+ line-height: 1.0em;
+ font-weight: bold;
+ vertical-align: top;
}
@media (max-width: 970px) {
@@ -68,6 +72,7 @@ body.wide-container {
.title-text {
padding-top: 0;
+ vertical-align: middle !important;
}
}
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
index 2ff107b553b2..f8fa83574df7 100644
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
@@ -70,6 +70,10 @@ function getGlobalScriptIncludes(scriptPath) {
let match = line.match(globalScriptsRegExp);
if (match) {
let sourceFile = match[1]
+ .replace(
+ "chrome://browser/content/torconnect/",
+ "browser/components/torconnect/content/"
+ )
.replace(
"chrome://browser/content/search/",
"browser/components/search/content/"
1
0
[tor-browser/tor-browser-78.13.0esr-10.5-1] Bring back old Firefox onboarding
by sysrqb@torproject.org 04 Aug '21
by sysrqb@torproject.org 04 Aug '21
04 Aug '21
commit 606a8fc5963abb98a2eb3bd269d1923005968bf1
Author: Alex Catarineu <acat(a)torproject.org>
Date: Wed May 29 20:04:37 2019 +0200
Bring back old Firefox onboarding
Revert "Bug 1462415 - Delete onboarding system add-on r=Standard8,k88hudson"
This reverts commit f7ffd78b62541d44d0102f8051d2f4080bdbc432.
Revert "Bug 1498378 - Actually remove the old onboarding add-on's prefs r=Gijs"
This reverts commit 057fe36fc6f3e93e265505c7dcc703a0941778e2.
Bug 28822: Convert onboarding to webextension
Partially revert 1564367 (controlCenter in UITour.jsm)
---
browser/app/profile/firefox.js | 16 +
browser/components/BrowserGlue.jsm | 11 -
browser/components/uitour/UITour.jsm | 42 +
browser/extensions/moz.build | 1 +
.../extensions/onboarding/OnboardingTelemetry.jsm | 578 +++++++
.../extensions/onboarding/OnboardingTourType.jsm | 40 +
browser/extensions/onboarding/README.md | 87 ++
browser/extensions/onboarding/api.js | 238 +++
browser/extensions/onboarding/background.js | 8 +
.../extensions/onboarding/content/Onboarding.jsm | 1581 ++++++++++++++++++++
.../onboarding/content/img/figure_addons.svg | 1 +
.../onboarding/content/img/figure_customize.svg | 561 +++++++
.../onboarding/content/img/figure_default.svg | 1 +
.../onboarding/content/img/figure_library.svg | 689 +++++++++
.../onboarding/content/img/figure_performance.svg | 1 +
.../onboarding/content/img/figure_private.svg | 1 +
.../onboarding/content/img/figure_screenshots.svg | 191 +++
.../onboarding/content/img/figure_singlesearch.svg | 1 +
.../onboarding/content/img/figure_sync.svg | 1 +
.../onboarding/content/img/icons_addons.svg | 1 +
.../onboarding/content/img/icons_customize.svg | 1 +
.../onboarding/content/img/icons_default.svg | 1 +
.../onboarding/content/img/icons_library.svg | 1 +
.../onboarding/content/img/icons_performance.svg | 1 +
.../onboarding/content/img/icons_private.svg | 1 +
.../onboarding/content/img/icons_screenshots.svg | 1 +
.../onboarding/content/img/icons_singlesearch.svg | 1 +
.../onboarding/content/img/icons_sync.svg | 1 +
.../onboarding/content/img/icons_tour-complete.svg | 17 +
.../onboarding/content/img/watermark.svg | 1 +
.../onboarding/content/onboarding-tour-agent.js | 94 ++
.../extensions/onboarding/content/onboarding.css | 589 ++++++++
.../extensions/onboarding/content/onboarding.js | 37 +
browser/extensions/onboarding/data_events.md | 154 ++
browser/extensions/onboarding/jar.mn | 14 +
.../onboarding/locales/en-US/onboarding.properties | 126 ++
browser/extensions/onboarding/locales/jar.mn | 8 +
browser/extensions/onboarding/locales/moz.build | 7 +
browser/extensions/onboarding/manifest.json | 26 +
browser/extensions/onboarding/moz.build | 29 +
browser/extensions/onboarding/schema.json | 1 +
.../onboarding/test/browser/.eslintrc.js | 7 +
.../extensions/onboarding/test/browser/browser.ini | 18 +
.../browser/browser_onboarding_accessibility.js | 89 ++
.../test/browser/browser_onboarding_keyboard.js | 137 ++
.../browser/browser_onboarding_notification.js | 62 +
.../browser/browser_onboarding_notification_2.js | 80 +
.../browser/browser_onboarding_notification_3.js | 82 +
.../browser/browser_onboarding_notification_4.js | 84 ++
.../browser/browser_onboarding_notification_5.js | 25 +
...arding_notification_click_auto_complete_tour.js | 33 +
.../browser_onboarding_select_default_tour.js | 80 +
.../test/browser/browser_onboarding_skip_tour.js | 47 +
.../test/browser/browser_onboarding_tours.js | 115 ++
.../test/browser/browser_onboarding_tourset.js | 82 +
.../test/browser/browser_onboarding_uitour.js | 167 +++
browser/extensions/onboarding/test/browser/head.js | 288 ++++
.../extensions/onboarding/test/unit/.eslintrc.js | 7 +
browser/extensions/onboarding/test/unit/head.js | 54 +
.../test/unit/test-onboarding-tour-type.js | 89 ++
.../extensions/onboarding/test/unit/xpcshell.ini | 5 +
browser/installer/package-manifest.in | 1 +
browser/locales/Makefile.in | 2 +
browser/locales/filter.py | 1 +
browser/locales/l10n.ini | 1 +
browser/locales/l10n.toml | 4 +
extensions/permissions/PermissionManager.cpp | 3 +
tools/lint/codespell.yml | 1 +
68 files changed, 6714 insertions(+), 11 deletions(-)
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index fb2d10c0a305..cf0ebf0aab58 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1856,6 +1856,22 @@ pref("browser.sessionstore.restore_tabs_lazily", true);
pref("browser.suppress_first_window_animation", true);
+// Preferences for Photon onboarding system extension
+pref("browser.onboarding.enabled", true);
+// Mark this as an upgraded profile so we don't offer the initial new user onboarding tour.
+pref("browser.onboarding.tourset-version", 2);
+pref("browser.onboarding.state", "default");
+// On the Activity-Stream page, the snippet's position overlaps with our notification.
+// So use `browser.onboarding.notification.finished` to let the AS page know
+// if our notification is finished and safe to show their snippet.
+pref("browser.onboarding.notification.finished", false);
+pref("browser.onboarding.notification.mute-duration-on-first-session-ms", 300000); // 5 mins
+pref("browser.onboarding.notification.max-life-time-per-tour-ms", 432000000); // 5 days
+pref("browser.onboarding.notification.max-life-time-all-tours-ms", 1209600000); // 14 days
+pref("browser.onboarding.notification.max-prompt-count-per-tour", 8);
+pref("browser.onboarding.newtour", "performance,private,screenshots,addons,customize,default");
+pref("browser.onboarding.updatetour", "performance,library,screenshots,singlesearch,customize,sync");
+
// Preference that allows individual users to disable Screenshots.
pref("extensions.screenshots.disabled", false);
// Preference that allows individual users to leave Screenshots enabled, but
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 44b1426b92e0..7d147d01d561 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -3414,17 +3414,6 @@ BrowserGlue.prototype = {
);
}
- if (currentUIVersion < 76) {
- // Clear old onboarding prefs from profile (bug 1462415)
- let onboardingPrefs = Services.prefs.getBranch("browser.onboarding.");
- if (onboardingPrefs) {
- let onboardingPrefsArray = onboardingPrefs.getChildList("");
- for (let item of onboardingPrefsArray) {
- Services.prefs.clearUserPref("browser.onboarding." + item);
- }
- }
- }
-
if (currentUIVersion < 77) {
// Remove currentset from all the toolbars
let toolbars = [
diff --git a/browser/components/uitour/UITour.jsm b/browser/components/uitour/UITour.jsm
index ac6c38320df2..2e0a178bf425 100644
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -875,6 +875,14 @@ var UITour = {
["ViewShowing", this.onPageActionPanelSubviewShowing],
],
},
+ {
+ name: "controlCenter",
+ node: aWindow.gIdentityHandler._identityPopup,
+ events: [
+ ["popuphidden", this.onPanelHidden],
+ ["popuphiding", this.onControlCenterHiding],
+ ],
+ },
];
for (let panel of panels) {
// Ensure the menu panel is hidden and clean up panel listeners after calling hideMenu.
@@ -1515,6 +1523,31 @@ var UITour = {
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
openMenuButton(menuBtn);
+ } else if (aMenuName == "controlCenter") {
+ let popup = aWindow.gIdentityHandler._identityPopup;
+
+ // Add the listener even if the panel is already open since it will still
+ // only get registered once even if it was UITour that opened it.
+ popup.addEventListener("popuphiding", this.onControlCenterHiding);
+ popup.addEventListener("popuphidden", this.onPanelHidden);
+
+ popup.setAttribute("noautohide", "true");
+ this.clearAvailableTargetsCache();
+
+ if (popup.state == "open") {
+ if (aOpenCallback) {
+ aOpenCallback();
+ }
+ return;
+ }
+
+ this.recreatePopup(popup);
+
+ // Open the control center
+ if (aOpenCallback) {
+ popup.addEventListener("popupshown", aOpenCallback, { once: true });
+ }
+ aWindow.document.getElementById("identity-box").click();
} else if (aMenuName == "pocket") {
let pageAction = PageActions.actionForID("pocket");
if (!pageAction) {
@@ -1558,6 +1591,9 @@ var UITour = {
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
closeMenuButton(menuBtn);
+ } else if (aMenuName == "controlCenter") {
+ let panel = aWindow.gIdentityHandler._identityPopup;
+ panel.hidePopup();
} else if (aMenuName == "urlbar") {
aWindow.gURLBar.view.close();
} else if (aMenuName == "pageActionPanel") {
@@ -1654,6 +1690,12 @@ var UITour = {
);
},
+ onControlCenterHiding(aEvent) {
+ UITour._hideAnnotationsForPanel(aEvent, true, aTarget => {
+ return aTarget.targetName.startsWith("controlCenter-");
+ });
+ },
+
onPanelHidden(aEvent) {
aEvent.target.removeAttribute("noautohide");
UITour.recreatePopup(aEvent.target);
diff --git a/browser/extensions/moz.build b/browser/extensions/moz.build
index 499c59b8d6a5..b0f98f9d4a2a 100644
--- a/browser/extensions/moz.build
+++ b/browser/extensions/moz.build
@@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
+ 'onboarding',
'pdfjs',
]
diff --git a/browser/extensions/onboarding/OnboardingTelemetry.jsm b/browser/extensions/onboarding/OnboardingTelemetry.jsm
new file mode 100644
index 000000000000..494c8d246d87
--- /dev/null
+++ b/browser/extensions/onboarding/OnboardingTelemetry.jsm
@@ -0,0 +1,578 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["OnboardingTelemetry"];
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+ PingCentre: "resource:///modules/PingCentre.jsm",
+});
+XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
+ "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
+
+// Validate the content has non-empty string
+function hasString(str) {
+ return typeof str == "string" && str.length > 0;
+}
+
+// Validate the content is an empty string
+function isEmptyString(str) {
+ return typeof str == "string" && str === "";
+}
+
+// Validate the content is an interger
+function isInteger(i) {
+ return Number.isInteger(i);
+}
+
+// Validate the content is a positive interger
+function isPositiveInteger(i) {
+ return Number.isInteger(i) && i > 0;
+}
+
+// Validate the number is -1
+function isMinusOne(num) {
+ return num === -1;
+}
+
+// Validate the category value is within the list
+function isValidCategory(category) {
+ return ["logo-interactions", "onboarding-interactions",
+ "overlay-interactions", "notification-interactions"]
+ .includes(category);
+}
+
+// Validate the page value is within the list
+function isValidPage(page) {
+ return ["about:newtab", "about:home", "about:welcome"].includes(page);
+}
+
+// Validate the tour_type value is within the list
+function isValidTourType(type) {
+ return ["new", "update"].includes(type);
+}
+
+// Validate the bubble state value is within the list
+function isValidBubbleState(str) {
+ return ["bubble", "dot", "hide"].includes(str);
+}
+
+// Validate the logo state value is within the list
+function isValidLogoState(str) {
+ return ["logo", "watermark"].includes(str);
+}
+
+// Validate the notification state value is within the list
+function isValidNotificationState(str) {
+ return ["show", "hide", "finished"].includes(str);
+}
+
+// Validate the column must be defined per ping
+function definePerPing(column) {
+ return function() {
+ throw new Error(`Must define the '${column}' validator per ping because it is not the same for all pings`);
+ };
+}
+
+// Basic validators for session pings
+// client_id, locale are added by PingCentre, IP is added by server
+// so no need check these column here
+const BASIC_SESSION_SCHEMA = {
+ addon_version: hasString,
+ category: isValidCategory,
+ page: isValidPage,
+ parent_session_id: hasString,
+ root_session_id: hasString,
+ session_begin: isInteger,
+ session_end: isInteger,
+ session_id: hasString,
+ tour_type: isValidTourType,
+ type: hasString,
+};
+
+// Basic validators for event pings
+// client_id, locale are added by PingCentre, IP is added by server
+// so no need check these column here
+const BASIC_EVENT_SCHEMA = {
+ addon_version: hasString,
+ bubble_state: definePerPing("bubble_state"),
+ category: isValidCategory,
+ current_tour_id: definePerPing("current_tour_id"),
+ logo_state: definePerPing("logo_state"),
+ notification_impression: definePerPing("notification_impression"),
+ notification_state: definePerPing("notification_state"),
+ page: isValidPage,
+ parent_session_id: hasString,
+ root_session_id: hasString,
+ target_tour_id: definePerPing("target_tour_id"),
+ timestamp: isInteger,
+ tour_type: isValidTourType,
+ type: hasString,
+ width: isPositiveInteger,
+};
+
+/**
+ * We send 2 kinds (firefox-onboarding-event2, firefox-onboarding-session2) of pings to ping centre
+ * server (they call it `topic`). The `internal` state in `topic` field means this event is used internaly to
+ * track states and will not send out any message.
+ *
+ * To save server space and make query easier, we track session begin and end but only send pings
+ * when session end. Therefore the server will get single "onboarding/overlay/notification-session"
+ * event which includes both `session_begin` and `session_end` timestamp.
+ *
+ * We send `session_begin` and `session_end` timestamps instead of `session_duration` diff because
+ * of analytics engineer's request.
+ */
+const EVENT_WHITELIST = {
+ // track when a notification appears.
+ "notification-appear": {
+ topic: "firefox-onboarding-event2",
+ category: "notification-interactions",
+ parent: "notification-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isValidBubbleState,
+ current_tour_id: hasString,
+ logo_state: isValidLogoState,
+ notification_impression: isPositiveInteger,
+ notification_state: isValidNotificationState,
+ target_tour_id: isEmptyString,
+ }),
+ },
+ // track when a user clicks close notification button
+ "notification-close-button-click": {
+ topic: "firefox-onboarding-event2",
+ category: "notification-interactions",
+ parent: "notification-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isValidBubbleState,
+ current_tour_id: hasString,
+ logo_state: isValidLogoState,
+ notification_impression: isPositiveInteger,
+ notification_state: isValidNotificationState,
+ target_tour_id: hasString,
+ }),
+ },
+ // track when a user clicks notification's Call-To-Action button
+ "notification-cta-click": {
+ topic: "firefox-onboarding-event2",
+ category: "notification-interactions",
+ parent: "notification-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isValidBubbleState,
+ current_tour_id: hasString,
+ logo_state: isValidLogoState,
+ notification_impression: isPositiveInteger,
+ notification_state: isValidNotificationState,
+ target_tour_id: hasString,
+ }),
+ },
+ // track the start and end time of the notification session
+ "notification-session": {
+ topic: "firefox-onboarding-session2",
+ category: "notification-interactions",
+ parent: "onboarding-session",
+ validators: BASIC_SESSION_SCHEMA,
+ },
+ // track the start of a notification
+ "notification-session-begin": {topic: "internal"},
+ // track the end of a notification
+ "notification-session-end": {topic: "internal"},
+ // track when a user clicks the Firefox logo
+ "onboarding-logo-click": {
+ topic: "firefox-onboarding-event2",
+ category: "logo-interactions",
+ parent: "onboarding-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isValidBubbleState,
+ current_tour_id: isEmptyString,
+ logo_state: isValidLogoState,
+ notification_impression: isMinusOne,
+ notification_state: isValidNotificationState,
+ target_tour_id: isEmptyString,
+ }),
+ },
+ // track when the onboarding is not visisble due to small screen in the 1st load
+ "onboarding-noshow-smallscreen": {
+ topic: "firefox-onboarding-event2",
+ category: "onboarding-interactions",
+ parent: "onboarding-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: isEmptyString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: isEmptyString,
+ }),
+ },
+ // init onboarding session with session_key, page url, and tour_type
+ "onboarding-register-session": {topic: "internal"},
+ // track the start and end time of the onboarding session
+ "onboarding-session": {
+ topic: "firefox-onboarding-session2",
+ category: "onboarding-interactions",
+ parent: "onboarding-session",
+ validators: BASIC_SESSION_SCHEMA,
+ },
+ // track onboarding start time (when user loads about:home or about:newtab)
+ "onboarding-session-begin": {topic: "internal"},
+ // track onboarding end time (when user unloads about:home or about:newtab)
+ "onboarding-session-end": {topic: "internal"},
+ // track when a user clicks the close overlay button
+ "overlay-close-button-click": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: hasString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: hasString,
+ }),
+ },
+ // track when a user clicks outside the overlay area to end the tour
+ "overlay-close-outside-click": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: hasString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: hasString,
+ }),
+ },
+ // track when a user clicks overlay's Call-To-Action button
+ "overlay-cta-click": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: hasString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: hasString,
+ }),
+ },
+ // track when a tour is shown in the overlay
+ "overlay-current-tour": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: hasString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: isEmptyString,
+ }),
+ },
+ // track when an overlay is opened and disappeared because the window is resized too small
+ "overlay-disapear-resize": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: isEmptyString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: isEmptyString,
+ }),
+ },
+ // track when a user clicks a navigation button in the overlay
+ "overlay-nav-click": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: hasString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: hasString,
+ }),
+ },
+ // track the start and end time of the overlay session
+ "overlay-session": {
+ topic: "firefox-onboarding-session2",
+ category: "overlay-interactions",
+ parent: "onboarding-session",
+ validators: BASIC_SESSION_SCHEMA,
+ },
+ // track the start of an overlay session
+ "overlay-session-begin": {topic: "internal"},
+ // track the end of an overlay session
+ "overlay-session-end": {topic: "internal"},
+ // track when a user clicks 'Skip Tour' button in the overlay
+ "overlay-skip-tour": {
+ topic: "firefox-onboarding-event2",
+ category: "overlay-interactions",
+ parent: "overlay-session",
+ validators: Object.assign({}, BASIC_EVENT_SCHEMA, {
+ bubble_state: isEmptyString,
+ current_tour_id: hasString,
+ logo_state: isEmptyString,
+ notification_impression: isMinusOne,
+ notification_state: isEmptyString,
+ target_tour_id: isEmptyString,
+ }),
+ },
+};
+
+const ONBOARDING_ID = "onboarding";
+
+let OnboardingTelemetry = {
+ sessionProbe: null,
+ eventProbe: null,
+ state: {
+ sessions: {},
+ },
+
+ init(startupData) {
+ this.sessionProbe = new PingCentre({topic: "firefox-onboarding-session2"});
+ this.eventProbe = new PingCentre({topic: "firefox-onboarding-event2"});
+ this.state.addon_version = startupData.version;
+ },
+
+ // register per tab session data
+ registerNewOnboardingSession(data) {
+ let { page, session_key, tour_type } = data;
+ if (this.state.sessions[session_key]) {
+ return;
+ }
+ // session_key and page url are must have
+ if (!session_key || !page || !tour_type) {
+ throw new Error("session_key, page url, and tour_type are required for onboarding-register-session");
+ }
+ let onboarding_session_id = gUUIDGenerator.generateUUID().toString();
+ this.state.sessions[session_key] = {
+ onboarding_session_id,
+ overlay_session_id: "",
+ notification_session_id: "",
+ page,
+ tour_type,
+ };
+ },
+
+ process(data) {
+ let { type, session_key } = data;
+ if (type === "onboarding-register-session") {
+ this.registerNewOnboardingSession(data);
+ return;
+ }
+
+ if (!this.state.sessions[session_key]) {
+ throw new Error(`${type} should pass valid session_key`);
+ }
+
+ switch (type) {
+ case "onboarding-session-begin":
+ if (!this.state.sessions[session_key].onboarding_session_id) {
+ throw new Error(`should fire onboarding-register-session event before ${type}`);
+ }
+ this.state.sessions[session_key].onboarding_session_begin = Date.now();
+ return;
+ case "onboarding-session-end":
+ data = Object.assign({}, data, {
+ type: "onboarding-session",
+ });
+ this.state.sessions[session_key].onboarding_session_end = Date.now();
+ break;
+ case "overlay-session-begin":
+ this.state.sessions[session_key].overlay_session_id = gUUIDGenerator.generateUUID().toString();
+ this.state.sessions[session_key].overlay_session_begin = Date.now();
+ return;
+ case "overlay-session-end":
+ data = Object.assign({}, data, {
+ type: "overlay-session",
+ });
+ this.state.sessions[session_key].overlay_session_end = Date.now();
+ break;
+ case "notification-session-begin":
+ this.state.sessions[session_key].notification_session_id = gUUIDGenerator.generateUUID().toString();
+ this.state.sessions[session_key].notification_session_begin = Date.now();
+ return;
+ case "notification-session-end":
+ data = Object.assign({}, data, {
+ type: "notification-session",
+ });
+ this.state.sessions[session_key].notification_session_end = Date.now();
+ break;
+ }
+ let topic = EVENT_WHITELIST[data.type] && EVENT_WHITELIST[data.type].topic;
+ if (!topic) {
+ throw new Error(`ping-centre doesn't know ${type} after processPings, only knows ${Object.keys(EVENT_WHITELIST)}`);
+ }
+ this._sendPing(topic, data);
+ },
+
+ // send out pings by topic
+ _sendPing(topic, data) {
+ if (topic === "internal") {
+ throw new Error(`internal ping ${data.type} should be processed within processPings`);
+ }
+
+ let {
+ addon_version,
+ } = this.state;
+ let {
+ bubble_state = "",
+ current_tour_id = "",
+ logo_state = "",
+ notification_impression = -1,
+ notification_state = "",
+ session_key,
+ target_tour_id = "",
+ type,
+ width,
+ } = data;
+ let {
+ notification_session_begin,
+ notification_session_end,
+ notification_session_id,
+ onboarding_session_begin,
+ onboarding_session_end,
+ onboarding_session_id,
+ overlay_session_begin,
+ overlay_session_end,
+ overlay_session_id,
+ page,
+ tour_type,
+ } = this.state.sessions[session_key];
+ let {
+ category,
+ parent,
+ } = EVENT_WHITELIST[type];
+ let parent_session_id;
+ let payload;
+ let session_begin;
+ let session_end;
+ let session_id;
+ let root_session_id = onboarding_session_id;
+
+ // assign parent_session_id
+ switch (parent) {
+ case "onboarding-session":
+ parent_session_id = onboarding_session_id;
+ break;
+ case "overlay-session":
+ parent_session_id = overlay_session_id;
+ break;
+ case "notification-session":
+ parent_session_id = notification_session_id;
+ break;
+ }
+ if (!parent_session_id) {
+ throw new Error(`Unable to find the ${parent} parent session for the event ${type}`);
+ }
+
+ switch (topic) {
+ case "firefox-onboarding-session2":
+ switch (type) {
+ case "onboarding-session":
+ session_id = onboarding_session_id;
+ session_begin = onboarding_session_begin;
+ session_end = onboarding_session_end;
+ delete this.state.sessions[session_key];
+ break;
+ case "overlay-session":
+ session_id = overlay_session_id;
+ session_begin = overlay_session_begin;
+ session_end = overlay_session_end;
+ break;
+ case "notification-session":
+ session_id = notification_session_id;
+ session_begin = notification_session_begin;
+ session_end = notification_session_end;
+ break;
+ }
+ if (!session_id || !session_begin || !session_end) {
+ throw new Error(`should fire ${type}-begin and ${type}-end event before ${type}`);
+ }
+
+ payload = {
+ addon_version,
+ category,
+ page,
+ parent_session_id,
+ root_session_id,
+ session_begin,
+ session_end,
+ session_id,
+ tour_type,
+ type,
+ };
+ this._validatePayload(payload);
+ this.sessionProbe && this.sessionProbe.sendPing(payload,
+ {filter: ONBOARDING_ID});
+ break;
+ case "firefox-onboarding-event2":
+ let timestamp = Date.now();
+ payload = {
+ addon_version,
+ bubble_state,
+ category,
+ current_tour_id,
+ logo_state,
+ notification_impression,
+ notification_state,
+ page,
+ parent_session_id,
+ root_session_id,
+ target_tour_id,
+ timestamp,
+ tour_type,
+ type,
+ width,
+ };
+ this._validatePayload(payload);
+ this.eventProbe && this.eventProbe.sendPing(payload,
+ {filter: ONBOARDING_ID});
+ break;
+ }
+ },
+
+ // validate data sanitation and make sure correct ping params are sent
+ _validatePayload(payload) {
+ let type = payload.type;
+ let { validators } = EVENT_WHITELIST[type];
+ if (!validators) {
+ throw new Error(`Event ${type} without validators should not be sent.`);
+ }
+ let validatorKeys = Object.keys(validators);
+ // Not send with undefined column
+ if (Object.keys(payload).length > validatorKeys.length) {
+ throw new Error(`Event ${type} want to send more columns than expect, should not be sent.`);
+ }
+ let results = {};
+ let failed = false;
+ // Per column validation
+ for (let key of validatorKeys) {
+ if (payload[key] !== undefined) {
+ results[key] = validators[key](payload[key]);
+ if (!results[key]) {
+ failed = true;
+ }
+ } else {
+ results[key] = false;
+ failed = true;
+ }
+ }
+ if (failed) {
+ throw new Error(`Event ${type} contains incorrect data: ${JSON.stringify(results)}, should not be sent.`);
+ }
+ },
+};
diff --git a/browser/extensions/onboarding/OnboardingTourType.jsm b/browser/extensions/onboarding/OnboardingTourType.jsm
new file mode 100644
index 000000000000..d984fc42f390
--- /dev/null
+++ b/browser/extensions/onboarding/OnboardingTourType.jsm
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["OnboardingTourType"];
+
+ChromeUtils.defineModuleGetter(this, "Services",
+ "resource://gre/modules/Services.jsm");
+
+var OnboardingTourType = {
+ /**
+ * Determine the current tour type (new user tour or update user tour).
+ * The function checks 2 criterias
+ * - TOURSET_VERSION: current onboarding tourset version
+ * - PREF_SEEN_TOURSET_VERSION: the user seen tourset version
+ * As the result the function will set the right current tour type in the tour type pref (PREF_TOUR_TYPE) for later use.
+ */
+ check() {
+ const PREF_TOUR_TYPE = "browser.onboarding.tour-type";
+ const PREF_SEEN_TOURSET_VERSION = "browser.onboarding.seen-tourset-version";
+ const TOURSET_VERSION = Services.prefs.getIntPref("browser.onboarding.tourset-version");
+
+ if (!Services.prefs.prefHasUserValue(PREF_SEEN_TOURSET_VERSION)) {
+ // User has never seen an onboarding tour, present the user with the new user tour.
+ Services.prefs.setStringPref(PREF_TOUR_TYPE, "new");
+ } else if (Services.prefs.getIntPref(PREF_SEEN_TOURSET_VERSION) < TOURSET_VERSION) {
+ // show the update user tour when tour set version is larger than the seen tourset version
+ Services.prefs.setStringPref(PREF_TOUR_TYPE, "update");
+ // Reset all the notification-related prefs because tours update.
+ Services.prefs.setBoolPref("browser.onboarding.notification.finished", false);
+ Services.prefs.clearUserPref("browser.onboarding.notification.prompt-count");
+ Services.prefs.clearUserPref("browser.onboarding.notification.last-time-of-changing-tour-sec");
+ Services.prefs.clearUserPref("browser.onboarding.notification.tour-ids-queue");
+ Services.prefs.clearUserPref("browser.onboarding.state");
+ }
+ Services.prefs.setIntPref(PREF_SEEN_TOURSET_VERSION, TOURSET_VERSION);
+ },
+};
diff --git a/browser/extensions/onboarding/README.md b/browser/extensions/onboarding/README.md
new file mode 100644
index 000000000000..c63be42b7181
--- /dev/null
+++ b/browser/extensions/onboarding/README.md
@@ -0,0 +1,87 @@
+# Onboarding
+
+System addon to provide the onboarding overlay for user-friendly tours.
+
+## How to show the onboarding tour
+
+Open `about:config` page and filter with `onboarding` keyword. Then set following preferences:
+
+```
+browser.onboarding.disabled = false
+browser.onboarding.tour-set = "new" // for new user tour, or "update" for update user tour
+```
+And make sure the value of `browser.onboarding.tourset-verion` and `browser.onboarding.seen-tourset-verion` are the same.
+
+## How to show the onboarding notification
+
+Besides above settings, notification will wait 5 minutes before showing the first notification on a new profile or the updated user profile (to not put too much information to the user at once).
+
+To manually remove the mute duration, set pref `browser.onboarding.notification.mute-duration-on-first-session-ms` to `0` and notification will be shown at the next time you open `about:home`, `about:newtab`, or `about:welcome`.
+
+## How to show the snippets
+
+Snippets (the remote notification that handled by activity stream) will only be shown after onboarding notifications are all done. You can set preference `browser.onboarding.notification.finished` to `true` to disable onboarding notification and accept snippets right away.
+
+## Architecture
+
+
+
+During booting from `bootstrap.js`, `OnboardingTourType.jsm` will check the onboarding tour type (`new` and `update` are supported types) and set required initial states into preferences.
+
+Everytime `about:home`, `about:newtab`, or `about:welcome` page is opened, `onboarding.js` is injected into that page via [frame scripts](https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/M….
+
+Then in `onboarding.js`, all tours are defined inside of `onboardingTourset` dictionary. `getTourIDList` function will load tours from proper preferences. (Check `How to change the order of tours` section for more detail).
+
+When user clicks the action button in each tour, We use [UITour](http://bedrock.readthedocs.io/en/latest/uitour.html) to highlight the correspondent browser UI element. The UITour client is bundled in onboarding addon via `jar.mn`.
+
+## Landing rules
+
+We would apply some rules:
+
+* To avoid conflict with the origin page, all styles and ids should be formatted as `onboarding-*`.
+* For consistency and easier filtering, all strings in `locales` should be formatted as `onboarding.*`.
+* For consistency, all related preferences should be formatted as `browser.onboarding.*`.
+* For accessibility, images that are for presentation only should have `role="presentation"` attribute.
+
+## How to change the order of tours
+
+Edit `browser/app/profile/firefox.js` and modify `browser.onboarding.newtour` for the new user tour or `browser.onboarding.updatetour` for the update user tour. You can change the tour list and the order by concate `tourIds` with `,` sign. You can find available `tourId` from `onboardingTourset` in `onboarding.js`.
+
+## How to pump tour set version after update tours
+
+We only update the tourset version when we have different **update** tourset. Update the new tourset **does not** require update the tourset version.
+
+The tourset version is used to track the last major tourset change version. The `tourset-version` pref store the major tourset version (ex: `1`) but not the current browser version. When browser update to the next version (ex: 58, 59) the tourset pref is still `1` if we didn't do any major tourset update.
+
+Once the tour set version is updated (ex: `2`), onboarding overlay should show the update tour to the updated user (ex: update from v56 -> v57), even when user has watched the previous tours or preferred to hide the previous tours.
+
+Edit `browser/app/profile/firefox.js` and set `browser.onboarding.tourset-version` as `[tourset version]` (in integer format).
+
+For example, if we update the tourset in v60 and decide to show all update users the tour, we set `browser.onboarding.tourset-version` as `3`.
+
+## Icon states
+
+Onboarding module has two states for its overlay icon: `default` and `watermark`.
+By default, it shows `default` state.
+When either tours or notifications are all completed, the icon changes to the `watermark` state.
+The icon state is stored in `browser.onboarding.state`.
+When `tourset-version` is updated, or when we detect the `tour-type` is changed to `update`, icon state will be changed back to the `default` state.
+
+## Customizable preferences
+
+Here are current support preferences that allow to customize the Onboarding's behavior.
+
+| PREF | DESCRIPTION | DEFAULT |
+|-----|-------------|:-----:|
+| `browser.onboarding.enabled` | disable onboarding experience entirely | true
+| `browser.onboarding.notification.finished` | Decide if we want to hide the notification permanently. | false
+| `browser.onboarding.notification.mute-duration-on-first-session-ms` |Notification mute duration. It also effect when the speech bubble is hidden and turned into the blue dot | 300000 (5 Min)
+| `browser.onboarding.notification.max-life-time-all-tours-ms` | Notification tours will all hide after this period | 1209600000 (10 Days)
+| `browser.onboarding.notification.max-life-time-per-tours-ms` | Per Notification tours will hide and show the next tour after this period | 432000000 (5 Days)
+| `browser.onboarding.notification.max-prompt-count-per-tour` | Each tour can only show the specific times in notification bar if user didn't interact with the tour notification. | 8
+| `browser.onboarding.newtour` | The tourset of new user tour. | performance,private,screenshots,addons,customize,default
+| `browser.onboarding.newtour.tooltip` | The string id which is shown in the new user tour's speech bubble. The preffered length is 2 lines. Should use `%S` to denote Firefox (brand short name) in string, or use `%1$S` if the name shows more than 1 time. | `onboarding.overlay-icon-tooltip2`
+| `browser.onboarding.updatetour` | The tourset of new user tour. | performance,library,screenshots,singlesearch,customize,sync
+| `browser.onboarding.updatetour.tooltip` | The string id which is shown in the update user tour's speech bubble. The preffered length is 2 lines. Should use `%S` to denote Firefox (brand short name) in string, or use `%1$S` if the name shows shows more than 1 time. | `onboarding.overlay-icon-tooltip-updated2`
+| `browser.onboarding.default-icon-src` | The default icon url. Should be svg or at least 64x64 | `chrome://branding/content/icon64.png`
+| `browser.onboarding.watermark-icon-src` | The watermark icon url. Should be svg or at least 64x64 | `resource://onboarding/img/watermark.svg`
diff --git a/browser/extensions/onboarding/api.js b/browser/extensions/onboarding/api.js
new file mode 100644
index 000000000000..c40800577976
--- /dev/null
+++ b/browser/extensions/onboarding/api.js
@@ -0,0 +1,238 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* globals APP_STARTUP, ADDON_INSTALL */
+"use strict";
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+ OnboardingTourType: "resource://onboarding/modules/OnboardingTourType.jsm",
+ OnboardingTelemetry: "resource://onboarding/modules/OnboardingTelemetry.jsm",
+ Services: "resource://gre/modules/Services.jsm",
+ UIState: "resource://services-sync/UIState.jsm",
+});
+
+XPCOMUtils.defineLazyServiceGetter(this, "resProto",
+ "@mozilla.org/network/protocol;1?name=resource",
+ "nsISubstitutingProtocolHandler");
+
+const RESOURCE_HOST = "onboarding";
+
+const {PREF_STRING, PREF_BOOL, PREF_INT} = Ci.nsIPrefBranch;
+
+const BROWSER_READY_NOTIFICATION = "browser-delayed-startup-finished";
+const BROWSER_SESSION_STORE_NOTIFICATION = "sessionstore-windows-restored";
+const PREF_WHITELIST = [
+ ["browser.onboarding.enabled", PREF_BOOL],
+ ["browser.onboarding.state", PREF_STRING],
+ ["browser.onboarding.notification.finished", PREF_BOOL],
+ ["browser.onboarding.notification.prompt-count", PREF_INT],
+ ["browser.onboarding.notification.last-time-of-changing-tour-sec", PREF_INT],
+ ["browser.onboarding.notification.tour-ids-queue", PREF_STRING],
+];
+
+[
+ "onboarding-tour-addons",
+ "onboarding-tour-customize",
+ "onboarding-tour-default-browser",
+ "onboarding-tour-library",
+ "onboarding-tour-performance",
+ "onboarding-tour-private-browsing",
+ "onboarding-tour-screenshots",
+ "onboarding-tour-singlesearch",
+ "onboarding-tour-sync",
+].forEach(tourId => PREF_WHITELIST.push([`browser.onboarding.tour.${tourId}.completed`, PREF_BOOL]));
+
+let waitingForBrowserReady = true;
+let startupData;
+
+/**
+ * Set pref. Why no `getPrefs` function is due to the privilege level.
+ * We cannot set prefs inside a framescript but can read.
+ * For simplicity and efficiency, we still read prefs inside the framescript.
+ *
+ * @param {Array} prefs the array of prefs to set.
+ * The array element carries info to set pref, should contain
+ * - {String} name the pref name, such as `browser.onboarding.state`
+ * - {*} value the value to set
+ **/
+function setPrefs(prefs) {
+ prefs.forEach(pref => {
+ let prefObj = PREF_WHITELIST.find(([name ]) => name == pref.name);
+ if (!prefObj) {
+ return;
+ }
+
+ let [name, type] = prefObj;
+
+ switch (type) {
+ case PREF_BOOL:
+ Services.prefs.setBoolPref(name, pref.value);
+ break;
+ case PREF_INT:
+ Services.prefs.setIntPref(name, pref.value);
+ break;
+ case PREF_STRING:
+ Services.prefs.setStringPref(name, pref.value);
+ break;
+ default:
+ throw new TypeError(`Unexpected type (${type}) for preference ${name}.`);
+ }
+ });
+}
+
+/**
+ * syncTourChecker listens to and maintains the login status inside, and can be
+ * queried at any time once initialized.
+ */
+let syncTourChecker = {
+ _registered: false,
+ _loggedIn: false,
+
+ isLoggedIn() {
+ return this._loggedIn;
+ },
+
+ observe(subject, topic) {
+ const state = UIState.get();
+ if (state.status == UIState.STATUS_NOT_CONFIGURED) {
+ this._loggedIn = false;
+ } else {
+ this.setComplete();
+ }
+ },
+
+ init() {
+ if (!Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
+ return;
+ }
+ // Check if we've already logged in at startup.
+ const state = UIState.get();
+ if (state.status != UIState.STATUS_NOT_CONFIGURED) {
+ this.setComplete();
+ }
+ this.register();
+ },
+
+ register() {
+ if (this._registered) {
+ return;
+ }
+ Services.obs.addObserver(this, "sync-ui-state:update");
+ this._registered = true;
+ },
+
+ setComplete() {
+ this._loggedIn = true;
+ Services.prefs.setBoolPref("browser.onboarding.tour.onboarding-tour-sync.completed", true);
+ },
+
+ unregister() {
+ if (!this._registered) {
+ return;
+ }
+ Services.obs.removeObserver(this, "sync-ui-state:update");
+ this._registered = false;
+ },
+
+ uninit() {
+ this.unregister();
+ },
+};
+
+/**
+ * Listen and process events from content.
+ */
+function initContentMessageListener() {
+ Services.mm.addMessageListener("Onboarding:OnContentMessage", msg => {
+ switch (msg.data.action) {
+ case "set-prefs":
+ setPrefs(msg.data.params);
+ break;
+ case "get-login-status":
+ msg.target.messageManager.sendAsyncMessage("Onboarding:ResponseLoginStatus", {
+ isLoggedIn: syncTourChecker.isLoggedIn(),
+ });
+ break;
+ case "ping-centre":
+ try {
+ OnboardingTelemetry.process(msg.data.params.data);
+ } catch (e) {
+ Cu.reportError(e);
+ }
+ break;
+ }
+ });
+}
+
+/**
+ * onBrowserReady - Continues startup of the add-on after browser is ready.
+ */
+function onBrowserReady() {
+ waitingForBrowserReady = false;
+
+ OnboardingTourType.check();
+ OnboardingTelemetry.init(startupData);
+ Services.mm.loadFrameScript("resource://onboarding/onboarding.js", true, true);
+ initContentMessageListener();
+}
+
+/**
+ * observe - nsIObserver callback to handle various browser notifications.
+ */
+function observe(subject, topic, data) {
+ switch (topic) {
+ case BROWSER_READY_NOTIFICATION:
+ Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
+ onBrowserReady();
+ break;
+ case BROWSER_SESSION_STORE_NOTIFICATION:
+ Services.obs.removeObserver(observe, BROWSER_SESSION_STORE_NOTIFICATION);
+ // Postpone Firefox account checking until "before handling user events"
+ // phase to meet performance criteria. The reason we don't postpone the
+ // whole onBrowserReady here is because in that way we will miss onload
+ // events for onboarding.js.
+ Services.tm.idleDispatchToMainThread(() => syncTourChecker.init());
+ break;
+ }
+}
+
+this.onboarding = class extends ExtensionAPI {
+ onStartup() {
+ resProto.setSubstitutionWithFlags(RESOURCE_HOST,
+ Services.io.newURI("chrome/content/", null, this.extension.rootURI),
+ resProto.ALLOW_CONTENT_ACCESS);
+
+ if (this.extension.rootURI instanceof Ci.nsIJARURI) {
+ this.manifest = this.extension.rootURI.JARFile.QueryInterface(Ci.nsIFileURL).file;
+ } else if (this.extension.rootURI instanceof Ci.nsIFileURL) {
+ this.manifest = this.extension.rootURI.file;
+ }
+
+ if (this.manifest) {
+ Components.manager.addBootstrappedManifestLocation(this.manifest);
+ } else {
+ Cu.reportError("Cannot find onboarding chrome.manifest for registring translated strings");
+ }
+
+ // Only start Onboarding when the browser UI is ready
+ if (Services.startup.startingUp) {
+ Services.obs.addObserver(observe, BROWSER_READY_NOTIFICATION);
+ Services.obs.addObserver(observe, BROWSER_SESSION_STORE_NOTIFICATION);
+ } else {
+ onBrowserReady();
+ syncTourChecker.init();
+ }
+ }
+
+ onShutdown() {
+ resProto.setSubstitution(RESOURCE_HOST, null);
+
+ // Stop waiting for browser to be ready
+ if (waitingForBrowserReady) {
+ Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
+ }
+ syncTourChecker.uninit();
+ }
+};
diff --git a/browser/extensions/onboarding/background.js b/browser/extensions/onboarding/background.js
new file mode 100644
index 000000000000..efe296ff2278
--- /dev/null
+++ b/browser/extensions/onboarding/background.js
@@ -0,0 +1,8 @@
+/* eslint-env webextensions */
+
+"use strict";
+
+browser.runtime.onUpdateAvailable.addListener(details => {
+ // By listening to but ignoring this event, any updates will
+ // be delayed until the next browser restart.
+});
diff --git a/browser/extensions/onboarding/content/Onboarding.jsm b/browser/extensions/onboarding/content/Onboarding.jsm
new file mode 100644
index 000000000000..de95a66632ab
--- /dev/null
+++ b/browser/extensions/onboarding/content/Onboarding.jsm
@@ -0,0 +1,1581 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env mozilla/frame-script */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["Onboarding"];
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const ONBOARDING_CSS_URL = "resource://onboarding/onboarding.css";
+const BUNDLE_URI = "chrome://onboarding/locale/onboarding.properties";
+const UITOUR_JS_URI = "resource://onboarding/lib/UITour-lib.js";
+const TOUR_AGENT_JS_URI = "resource://onboarding/onboarding-tour-agent.js";
+const BRAND_SHORT_NAME = Services.strings
+ .createBundle("chrome://branding/locale/brand.properties")
+ .GetStringFromName("brandShortName");
+const PROMPT_COUNT_PREF = "browser.onboarding.notification.prompt-count";
+const NOTIFICATION_FINISHED_PREF = "browser.onboarding.notification.finished";
+const ONBOARDING_DIALOG_ID = "onboarding-overlay-dialog";
+const ONBOARDING_MIN_WIDTH_PX = 960;
+const SPEECH_BUBBLE_MIN_WIDTH_PX = 1365;
+const SPEECH_BUBBLE_NEWTOUR_STRING_ID = "onboarding.overlay-icon-tooltip2";
+const SPEECH_BUBBLE_UPDATETOUR_STRING_ID = "onboarding.overlay-icon-tooltip-updated2";
+const ICON_STATE_WATERMARK = "watermark";
+const ICON_STATE_DEFAULT = "default";
+
+/**
+ * Helper function to create the tour description UI element.
+ */
+function createOnboardingTourDescription(div, title, description) {
+ let doc = div.ownerDocument;
+ let section = doc.createElement("section");
+ section.className = "onboarding-tour-description";
+
+ let h1 = doc.createElement("h1");
+ h1.setAttribute("data-l10n-id", title);
+ section.appendChild(h1);
+
+ let p = doc.createElement("p");
+ p.setAttribute("data-l10n-id", description);
+ section.appendChild(p);
+
+ div.appendChild(section);
+ return section;
+}
+
+/**
+ * Helper function to create the tour content UI element.
+ */
+function createOnboardingTourContent(div, imageSrc) {
+ let doc = div.ownerDocument;
+ let section = doc.createElement("section");
+ section.className = "onboarding-tour-content";
+
+ let img = doc.createElement("img");
+ img.setAttribute("src", imageSrc);
+ img.setAttribute("role", "presentation");
+ section.appendChild(img);
+
+ div.appendChild(section);
+ return section;
+}
+
+/**
+ * Helper function to create the tour button UI element.
+ */
+function createOnboardingTourButton(div, buttonId, l10nId, buttonElementTagName = "button") {
+ let doc = div.ownerDocument;
+ let aside = doc.createElement("aside");
+ aside.className = "onboarding-tour-button-container";
+
+ let button = doc.createElement(buttonElementTagName);
+ button.id = buttonId;
+ button.className = "onboarding-tour-action-button";
+ button.setAttribute("data-l10n-id", l10nId);
+ aside.appendChild(button);
+
+ div.appendChild(aside);
+ return aside;
+}
+
+/**
+ * Add any number of tours, key is the tourId, value should follow the format below
+ * "tourId": { // The short tour id which could be saved in pref
+ * // The unique tour id
+ * id: "onboarding-tour-addons",
+ * // (optional) mark tour as complete instantly when the user enters the tour
+ * instantComplete: false,
+ * // The string id of tour name which would be displayed on the navigation bar
+ * tourNameId: "onboarding.tour-addon",
+ * // The method returing strings used on tour notification
+ * getNotificationStrings(bundle):
+ * - title: // The string of tour notification title
+ * - message: // The string of tour notification message
+ * - button: // The string of tour notification action button title
+ * // Return a div appended with elements for this tours.
+ * // Each tour should contain the following 3 sections in the div:
+ * // .onboarding-tour-description, .onboarding-tour-content, .onboarding-tour-button-container.
+ * // If there was a .onboarding-tour-action-button present and was clicked, tour would be marked as completed.
+ * getPage() {},
+ * },
+ **/
+var onboardingTourset = {
+ "private": {
+ id: "onboarding-tour-private-browsing",
+ tourNameId: "onboarding.tour-private-browsing",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-private-browsing.title"),
+ message: bundle.GetStringFromName("onboarding.notification.onboarding-tour-private-browsing.message2"),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win) {
+ let div = win.document.createElement("div");
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-private-browsing.title2", "onboarding.tour-private-browsing.description3");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_private.svg");
+ createOnboardingTourButton(div,
+ "onboarding-tour-private-browsing-button", "onboarding.tour-private-browsing.button");
+
+ return div;
+ },
+ },
+ "addons": {
+ id: "onboarding-tour-addons",
+ tourNameId: "onboarding.tour-addons",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-addons.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-addons.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win) {
+ let div = win.document.createElement("div");
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-addons.title2", "onboarding.tour-addons.description2");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_addons.svg");
+ createOnboardingTourButton(div,
+ "onboarding-tour-addons-button", "onboarding.tour-addons.button");
+
+ return div;
+ },
+ },
+ "customize": {
+ id: "onboarding-tour-customize",
+ tourNameId: "onboarding.tour-customize",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-customize.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-customize.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win) {
+ let div = win.document.createElement("div");
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-customize.title2", "onboarding.tour-customize.description2");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_customize.svg");
+ createOnboardingTourButton(div,
+ "onboarding-tour-customize-button", "onboarding.tour-customize.button");
+
+ return div;
+ },
+ },
+ "default": {
+ id: "onboarding-tour-default-browser",
+ instantComplete: true,
+ tourNameId: "onboarding.tour-default-browser",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.formatStringFromName("onboarding.notification.onboarding-tour-default-browser.title", [BRAND_SHORT_NAME], 1),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-default-browser.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win, bundle) {
+ let div = win.document.createElement("div");
+ let setFromBackGround = bundle.formatStringFromName("onboarding.tour-default-browser.win7.button", [BRAND_SHORT_NAME], 1);
+ let setFromPanel = bundle.GetStringFromName("onboarding.tour-default-browser.button");
+ let isDefaultMessage = bundle.GetStringFromName("onboarding.tour-default-browser.is-default.message");
+ let isDefault2ndMessage = bundle.formatStringFromName("onboarding.tour-default-browser.is-default.2nd-message", [BRAND_SHORT_NAME], 1);
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-default-browser.title2", "onboarding.tour-default-browser.description2");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_default.svg");
+
+ let aside = win.document.createElement("aside");
+ aside.className = "onboarding-tour-button-container";
+ div.appendChild(aside);
+
+ let button = win.document.createElement("button");
+ button.id = "onboarding-tour-default-browser-button";
+ button.className = "onboarding-tour-action-button";
+ button.setAttribute("data-bg", setFromBackGround);
+ button.setAttribute("data-panel", setFromPanel);
+ aside.appendChild(button);
+
+ let isDefaultBrowserMsg = win.document.createElement("div");
+ isDefaultBrowserMsg.id = "onboarding-tour-is-default-browser-msg";
+ isDefaultBrowserMsg.className = "onboarding-hidden";
+ aside.appendChild(isDefaultBrowserMsg);
+ isDefaultBrowserMsg.append(isDefaultMessage);
+
+ let br = win.document.createElement("br");
+ isDefaultBrowserMsg.appendChild(br);
+ isDefaultBrowserMsg.append(isDefault2ndMessage);
+
+ div.addEventListener("beforeshow", () => {
+ win.document.dispatchEvent(new Event("Agent:CanSetDefaultBrowserInBackground"));
+ });
+ return div;
+ },
+ },
+ "sync": {
+ id: "onboarding-tour-sync",
+ instantComplete: true,
+ tourNameId: "onboarding.tour-sync2",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-sync.title"),
+ message: bundle.GetStringFromName("onboarding.notification.onboarding-tour-sync.message"),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win, bundle) {
+ const STATE_LOGOUT = "logged-out";
+ const STATE_LOGIN = "logged-in";
+ let div = win.document.createElement("div");
+ div.dataset.loginState = STATE_LOGOUT;
+ // The email validation pattern used in the form comes from IETF rfc5321,
+ // which is identical to server-side checker of Firefox Account. See
+ // discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1378770#c6
+ // for detail.
+ let emailRegex = "^[\\w.!#$%&’*+\\/=?^`{|}~-]{1,64}@[a-z\\d](?:[a-z\\d-]{0,253}[a-z\\d])?(?:\\.[a-z\\d](?:[a-z\\d-]{0,253}[a-z\\d])?)+$";
+
+ let description = createOnboardingTourDescription(div,
+ "onboarding.tour-sync.title2", "onboarding.tour-sync.description2");
+
+ description.querySelector("h1").className = "show-on-logged-out";
+ description.querySelector("p").className = "show-on-logged-out";
+
+ let h1LoggedIn = win.document.createElement("h1");
+ h1LoggedIn.setAttribute("data-l10n-id", "onboarding.tour-sync.logged-in.title");
+ h1LoggedIn.className = "show-on-logged-in";
+ description.appendChild(h1LoggedIn);
+
+ let pLoggedIn = win.document.createElement("p");
+ pLoggedIn.setAttribute("data-l10n-id", "onboarding.tour-sync.logged-in.description");
+ pLoggedIn.className = "show-on-logged-in";
+ description.appendChild(pLoggedIn);
+
+ let content = win.document.createElement("section");
+ content.className = "onboarding-tour-content";
+ div.appendChild(content);
+
+ let form = win.document.createElement("form");
+ form.className = "show-on-logged-out";
+ content.appendChild(form);
+
+ let h3 = win.document.createElement("h3");
+ h3.setAttribute("data-l10n-id", "onboarding.tour-sync.form.title");
+ form.appendChild(h3);
+
+ let p = win.document.createElement("p");
+ p.setAttribute("data-l10n-id", "onboarding.tour-sync.form.description");
+ form.appendChild(p);
+
+ let input = win.document.createElement("input");
+ input.id = "onboarding-tour-sync-email-input";
+ input.setAttribute("required", "true");
+ input.setAttribute("type", "email");
+ input.placeholder =
+ bundle.GetStringFromName("onboarding.tour-sync.email-input.placeholder");
+ input.pattern = emailRegex;
+ form.appendChild(input);
+
+ let br = win.document.createElement("br");
+ form.appendChild(br);
+
+ let button = win.document.createElement("button");
+ button.id = "onboarding-tour-sync-button";
+ button.className = "onboarding-tour-action-button";
+ button.setAttribute("data-l10n-id", "onboarding.tour-sync.button");
+ form.appendChild(button);
+
+ let img = win.document.createElement("img");
+ img.setAttribute("src", "resource://onboarding/img/figure_sync.svg");
+ img.setAttribute("role", "presentation");
+ content.appendChild(img);
+
+ let aside = win.document.createElement("aside");
+ aside.className = "onboarding-tour-button-container show-on-logged-in";
+ div.appendChild(aside);
+
+ let connectDeviceButton = win.document.createElement("button");
+ connectDeviceButton.id = "onboarding-tour-sync-connect-device-button";
+ connectDeviceButton.className = "onboarding-tour-action-button";
+ connectDeviceButton.setAttribute("data-l10n-id", "onboarding.tour-sync.connect-device.button");
+ aside.appendChild(connectDeviceButton);
+
+ div.addEventListener("beforeshow", () => {
+ function loginStatusListener(msg) {
+ removeMessageListener("Onboarding:ResponseLoginStatus", loginStatusListener);
+ div.dataset.loginState = msg.data.isLoggedIn ? STATE_LOGIN : STATE_LOGOUT;
+ }
+ this.sendMessageToChrome("get-login-status");
+ this.mm.addMessageListener("Onboarding:ResponseLoginStatus", loginStatusListener);
+ });
+
+ return div;
+ },
+ },
+ "library": {
+ id: "onboarding-tour-library",
+ tourNameId: "onboarding.tour-library",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-library.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-library.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win) {
+ let div = win.document.createElement("div");
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-library.title", "onboarding.tour-library.description2");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_library.svg");
+ createOnboardingTourButton(div,
+ "onboarding-tour-library-button", "onboarding.tour-library.button2");
+
+ return div;
+ },
+ },
+ "singlesearch": {
+ id: "onboarding-tour-singlesearch",
+ tourNameId: "onboarding.tour-singlesearch",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-singlesearch.title"),
+ message: bundle.GetStringFromName("onboarding.notification.onboarding-tour-singlesearch.message"),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win, bundle) {
+ let div = win.document.createElement("div");
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-singlesearch.title", "onboarding.tour-singlesearch.description");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_singlesearch.svg");
+ createOnboardingTourButton(div,
+ "onboarding-tour-singlesearch-button", "onboarding.tour-singlesearch.button");
+
+ return div;
+ },
+ },
+ "performance": {
+ id: "onboarding-tour-performance",
+ instantComplete: true,
+ tourNameId: "onboarding.tour-performance",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-performance.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-performance.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win, bundle) {
+ let div = win.document.createElement("div");
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-performance.title", "onboarding.tour-performance.description");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_performance.svg");
+
+ return div;
+ },
+ },
+ "screenshots": {
+ id: "onboarding-tour-screenshots",
+ tourNameId: "onboarding.tour-screenshots",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-screenshots.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-screenshots.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
+ getPage(win, bundle) {
+ let div = win.document.createElement("div");
+ // Screenshot tour opens the screenshot page directly, see below a#onboarding-tour-screenshots-button.
+ // The screenshots page should be responsible for highlighting the Screenshots button
+
+ createOnboardingTourDescription(div,
+ "onboarding.tour-screenshots.title", "onboarding.tour-screenshots.description");
+ createOnboardingTourContent(div, "resource://onboarding/img/figure_screenshots.svg");
+
+ let aside = createOnboardingTourButton(div,
+ "onboarding-tour-screenshots-button",
+ "onboarding.tour-screenshots.button",
+ "a");
+
+ let button = aside.querySelector("a");
+ button.setAttribute("href", "https://screenshots.firefox.com/#tour");
+ button.setAttribute("target", "_blank");
+
+ return div;
+ },
+ },
+};
+
+/**
+ * The script won't be initialized if we turned off onboarding by
+ * setting "browser.onboarding.enabled" to false.
+ */
+class Onboarding {
+ constructor(mm, contentWindow) {
+ this.mm = mm;
+ this.init(contentWindow);
+ }
+
+
+ /**
+ * @param {String} action the action to ask the chrome to do
+ * @param {Array | Object} params the parameters for the action
+ */
+ sendMessageToChrome(action, params) {
+ this.mm.sendAsyncMessage("Onboarding:OnContentMessage", {
+ action, params,
+ });
+ }
+
+ /**
+ * Template code for talking to `PingCentre`
+ * @param {Object} data the payload for the telemetry
+ */
+ telemetry(data) {
+ this.sendMessageToChrome("ping-centre", {data});
+ }
+
+ registerNewTelemetrySession(data) {
+ this.telemetry(Object.assign(data, {
+ type: "onboarding-register-session",
+ }));
+ }
+
+ async init(contentWindow) {
+ this._window = contentWindow;
+ // session_key is used for telemetry to track the current tab.
+ // The number will renew after reloading the page.
+ this._session_key = Date.now();
+ this._tours = [];
+ this._tourType = Services.prefs.getStringPref("browser.onboarding.tour-type", "update");
+
+ let tourIds = this._getTourIDList();
+ tourIds.forEach(tourId => {
+ if (onboardingTourset[tourId]) {
+ this._tours.push(onboardingTourset[tourId]);
+ }
+ });
+
+ if (this._tours.length === 0) {
+ return;
+ }
+
+ // We want to create and append elements after CSS is loaded so
+ // no flash of style changes and no additional reflow.
+ await this._loadCSS();
+ this._bundle = Services.strings.createBundle(BUNDLE_URI);
+
+ this._loadJS(UITOUR_JS_URI);
+
+ this.uiInitialized = false;
+ let doc = this._window.document;
+ if (doc.hidden) {
+ // When the preloaded-browser feature is on,
+ // it would preload a hidden about:newtab in the background.
+ // We don't want to show onboarding experience in that hidden state.
+ let onVisible = () => {
+ if (!doc.hidden) {
+ doc.removeEventListener("visibilitychange", onVisible);
+ this._startUI();
+ }
+ };
+ doc.addEventListener("visibilitychange", onVisible);
+ } else {
+ this._startUI();
+ }
+ }
+
+ _startUI() {
+ this.registerNewTelemetrySession({
+ page: this._window.location.href,
+ session_key: this._session_key,
+ tour_type: this._tourType,
+ });
+
+ this._window.addEventListener("beforeunload", this);
+ this._window.addEventListener("unload", this);
+ this._window.addEventListener("resize", this);
+ this._resizeTimerId =
+ this._window.requestIdleCallback(() => this._resizeUI());
+ // start log the onboarding-session when the tab is visible
+ this.telemetry({
+ type: "onboarding-session-begin",
+ session_key: this._session_key,
+ });
+ }
+
+ _resizeUI() {
+ this._windowWidth = this._window.document.body.getBoundingClientRect().width;
+ if (this._windowWidth < ONBOARDING_MIN_WIDTH_PX) {
+ // Don't show the overlay UI before we get to a better, responsive design.
+ this.destroy();
+ return;
+ }
+
+ this._initUI();
+ if (this._isFirstSession && this._windowWidth >= SPEECH_BUBBLE_MIN_WIDTH_PX) {
+ this._overlayIcon.classList.add("onboarding-speech-bubble");
+ } else {
+ this._overlayIcon.classList.remove("onboarding-speech-bubble");
+ }
+ }
+
+ _initUI() {
+ if (this.uiInitialized) {
+ return;
+ }
+ this.uiInitialized = true;
+ this._tourItems = [];
+ this._tourPages = [];
+
+ let { body } = this._window.document;
+ this._overlayIcon = this._renderOverlayButton();
+ this._overlayIcon.addEventListener("click", this);
+ this._overlayIcon.addEventListener("keypress", this);
+ body.insertBefore(this._overlayIcon, body.firstChild);
+
+ this._overlay = this._renderOverlay();
+ this._overlay.addEventListener("click", this);
+ this._overlay.addEventListener("keydown", this);
+ this._overlay.addEventListener("keypress", this);
+ body.appendChild(this._overlay);
+
+ this._loadJS(TOUR_AGENT_JS_URI);
+
+ this._initPrefObserver();
+ this._onIconStateChange(Services.prefs.getStringPref("browser.onboarding.state", ICON_STATE_DEFAULT));
+
+ // Doing tour notification takes some effort. Let's do it on idle.
+ this._window.requestIdleCallback(() => this.showNotification());
+ }
+
+ _getTourIDList() {
+ let tours = Services.prefs.getStringPref(`browser.onboarding.${this._tourType}tour`, "");
+ return tours.split(",").filter(tourId => {
+ if (tourId === "sync" && !Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
+ return false;
+ }
+ return tourId !== "";
+ }).map(tourId => tourId.trim());
+ }
+
+ _initPrefObserver() {
+ if (this._prefsObserved) {
+ return;
+ }
+
+ this._prefsObserved = new Map();
+ this._prefsObserved.set("browser.onboarding.state", () => {
+ this._onIconStateChange(Services.prefs.getStringPref("browser.onboarding.state", ICON_STATE_DEFAULT));
+ });
+ this._tours.forEach(tour => {
+ let tourId = tour.id;
+ this._prefsObserved.set(`browser.onboarding.tour.${tourId}.completed`, () => {
+ this.markTourCompletionState(tourId);
+ this._checkWatermarkByTours();
+ });
+ });
+ for (let [name, callback] of this._prefsObserved) {
+ Services.prefs.addObserver(name, callback);
+ }
+ }
+
+ _checkWatermarkByTours() {
+ let tourDone = this._tours.every(tour => this.isTourCompleted(tour.id));
+ if (tourDone) {
+ this.sendMessageToChrome("set-prefs", [{
+ name: "browser.onboarding.state",
+ value: ICON_STATE_WATERMARK,
+ }]);
+ }
+ }
+
+ _clearPrefObserver() {
+ if (this._prefsObserved) {
+ for (let [name, callback] of this._prefsObserved) {
+ Services.prefs.removeObserver(name, callback);
+ }
+ this._prefsObserved = null;
+ }
+ }
+
+ /**
+ * Find a tour that should be selected. It is either a first tour that was not
+ * yet complete or the first one in the tab list.
+ */
+ get _firstUncompleteTour() {
+ return this._tours.find(tour => !this.isTourCompleted(tour.id)) ||
+ this._tours[0];
+ }
+
+ /*
+ * Return currently showing tour navigation item
+ */
+ get _activeTourId() {
+ // We are doing lazy load so there might be no items.
+ if (!this._tourItems) {
+ return "";
+ }
+
+ let tourItem = this._tourItems.find(item => item.classList.contains("onboarding-active"));
+ return tourItem ? tourItem.id : "";
+ }
+
+ /**
+ * Return current logo state as "logo" or "watermark".
+ */
+ get _logoState() {
+ return this._overlayIcon.classList.contains("onboarding-watermark") ?
+ "watermark" : "logo";
+ }
+
+ /**
+ * Return current speech bubble state as "bubble", "dot" or "hide".
+ */
+ get _bubbleState() {
+ let state;
+ if (this._overlayIcon.classList.contains("onboarding-watermark")) {
+ state = "hide";
+ } else if (this._overlayIcon.classList.contains("onboarding-speech-bubble")) {
+ state = "bubble";
+ } else {
+ state = "dot";
+ }
+ return state;
+ }
+
+ /**
+ * Return current notification state as "show", "hide" or "finished".
+ */
+ get _notificationState() {
+ if (this._notificationCachedState === "finished") {
+ return this._notificationCachedState;
+ }
+
+ if (Services.prefs.getBoolPref(NOTIFICATION_FINISHED_PREF, false)) {
+ this._notificationCachedState = "finished";
+ } else if (this._notification) {
+ this._notificationCachedState = "show";
+ } else {
+ // we know it is in the hidden state if there's no notification bar
+ this._notificationCachedState = "hide";
+ }
+
+ return this._notificationCachedState;
+ }
+
+ /**
+ * Return current notification prompt count.
+ */
+ get _notificationPromptCount() {
+ return Services.prefs.getIntPref(PROMPT_COUNT_PREF, 0);
+ }
+
+ /**
+ * Return current screen width and round it up to the nearest 50 pixels.
+ * Collecting rounded values reduces the risk that this could be used to
+ * derive a unique user identifier
+ */
+ get _windowWidthRounded() {
+ return Math.round(this._windowWidth / 50) * 50;
+ }
+
+ handleClick(target) {
+ let { id, classList } = target;
+ // Only containers receive pointer events in onboarding tour tab list,
+ // actual semantic tab is their first child.
+ if (classList.contains("onboarding-tour-item-container")) {
+ ({ id, classList } = target.firstChild);
+ }
+
+ switch (id) {
+ case "onboarding-overlay-button-icon":
+ case "onboarding-overlay-button":
+ this.telemetry({
+ type: "onboarding-logo-click",
+ bubble_state: this._bubbleState,
+ logo_state: this._logoState,
+ notification_state: this._notificationState,
+ session_key: this._session_key,
+ width: this._windowWidthRounded,
+ });
+ this.showOverlay();
+ this.gotoPage(this._firstUncompleteTour.id);
+ break;
+ case "onboarding-skip-tour-button":
+ this.hideNotification();
+ this.hideOverlay();
+ this.skipTour();
+ break;
+ case "onboarding-overlay-close-btn":
+ // If the clicking target is directly on the outer-most overlay,
+ // that means clicking outside the tour content area.
+ // Let's toggle the overlay.
+ case "onboarding-overlay":
+ let eventName = id === "onboarding-overlay-close-btn" ?
+ "overlay-close-button-click" : "overlay-close-outside-click";
+ this.telemetry({
+ type: eventName,
+ current_tour_id: this._activeTourId,
+ session_key: this._session_key,
+ target_tour_id: this._activeTourId,
+ width: this._windowWidthRounded,
+ });
+ this.hideOverlay();
+ break;
+ case "onboarding-notification-close-btn":
+ let currentTourId = this._notificationBar.dataset.targetTourId;
+ // should trigger before notification-session event is sent
+ this.telemetry({
+ type: "notification-close-button-click",
+ bubble_state: this._bubbleState,
+ current_tour_id: currentTourId,
+ logo_state: this._logoState,
+ notification_impression: this._notificationPromptCount,
+ notification_state: this._notificationState,
+ session_key: this._session_key,
+ target_tour_id: currentTourId,
+ width: this._windowWidthRounded,
+ });
+ this.hideNotification();
+ this._removeTourFromNotificationQueue(currentTourId);
+ break;
+ case "onboarding-notification-action-btn":
+ let tourId = this._notificationBar.dataset.targetTourId;
+ this.telemetry({
+ type: "notification-cta-click",
+ bubble_state: this._bubbleState,
+ current_tour_id: tourId,
+ logo_state: this._logoState,
+ notification_impression: this._notificationPromptCount,
+ notification_state: this._notificationState,
+ session_key: this._session_key,
+ target_tour_id: tourId,
+ width: this._windowWidthRounded,
+ });
+ this.showOverlay();
+ this.gotoPage(tourId);
+ this._removeTourFromNotificationQueue(tourId);
+ break;
+ }
+ if (classList.contains("onboarding-tour-item")) {
+ this.telemetry({
+ type: "overlay-nav-click",
+ current_tour_id: this._activeTourId,
+ session_key: this._session_key,
+ target_tour_id: id,
+ width: this._windowWidthRounded,
+ });
+ this.gotoPage(id);
+ // Keep focus (not visible) on current item for potential keyboard
+ // navigation.
+ target.focus();
+ } else if (classList.contains("onboarding-tour-action-button")) {
+ let activeTourId = this._activeTourId;
+ this.setToursCompleted([ activeTourId ]);
+ this.telemetry({
+ type: "overlay-cta-click",
+ current_tour_id: activeTourId,
+ session_key: this._session_key,
+ target_tour_id: activeTourId,
+ width: this._windowWidthRounded,
+ });
+ }
+ }
+
+ /**
+ * Wrap keyboard focus within the dialog.
+ * When moving forward, focus on the first element when the current focused
+ * element is the last one.
+ * When moving backward, focus on the last element when the current focused
+ * element is the first one.
+ * Do nothing if focus is moving in the middle of the list of dialog's focusable
+ * elements.
+ *
+ * @param {DOMNode} current currently focused element
+ * @param {Boolean} back direction
+ * @return {DOMNode} newly focused element if any
+ */
+ wrapMoveFocus(current, back) {
+ let elms = [...this._dialog.querySelectorAll(
+ `button, input[type="checkbox"], input[type="email"], [tabindex="0"]`)];
+ let next;
+ if (back) {
+ if (elms.indexOf(current) === 0) {
+ next = elms[elms.length - 1];
+ next.focus();
+ }
+ } else if (elms.indexOf(current) === elms.length - 1) {
+ next = elms[0];
+ next.focus();
+ }
+ return next;
+ }
+
+ handleKeydown(event) {
+ let { target, key, shiftKey } = event;
+
+ // Currently focused item could be tab container if previous navigation was done
+ // via mouse.
+ if (target.classList.contains("onboarding-tour-item-container")) {
+ target = target.firstChild;
+ }
+ let targetIndex;
+ switch (key) {
+ case "ArrowUp":
+ // Go to and focus on the previous tab if it's available.
+ targetIndex = this._tourItems.indexOf(target);
+ if (targetIndex > 0) {
+ let previous = this._tourItems[targetIndex - 1];
+ this.handleClick(previous);
+ previous.focus();
+ }
+ event.preventDefault();
+ break;
+ case "ArrowDown":
+ // Go to and focus on the next tab if it's available.
+ targetIndex = this._tourItems.indexOf(target);
+ if (targetIndex > -1 && targetIndex < this._tourItems.length - 1) {
+ let next = this._tourItems[targetIndex + 1];
+ this.handleClick(next);
+ next.focus();
+ }
+ event.preventDefault();
+ break;
+ case "Escape":
+ this.hideOverlay();
+ break;
+ case "Tab":
+ let next = this.wrapMoveFocus(target, shiftKey);
+ // If focus was wrapped, prevent Tab key default action.
+ if (next) {
+ event.preventDefault();
+ }
+ break;
+ default:
+ break;
+ }
+ event.stopPropagation();
+ }
+
+ handleKeypress(event) {
+ let { target, key } = event;
+
+ if (target === this._overlayIcon) {
+ if ([" ", "Enter"].includes(key)) {
+ // Remember that the dialog was opened with a keyboard.
+ this._overlayIcon.dataset.keyboardFocus = true;
+ this.handleClick(target);
+ event.preventDefault();
+ }
+ return;
+ }
+
+ // Currently focused item could be tab container if previous navigation was done
+ // via mouse.
+ if (target.classList.contains("onboarding-tour-item-container")) {
+ target = target.firstChild;
+ }
+ switch (key) {
+ case " ":
+ case "Enter":
+ // Assume that the handle function should be identical for keyboard
+ // activation if there is a click handler for the target.
+ if (target.classList.contains("onboarding-tour-item")) {
+ this.handleClick(target);
+ target.focus();
+ }
+ break;
+ default:
+ break;
+ }
+ event.stopPropagation();
+ }
+
+ handleEvent(evt) {
+ switch (evt.type) {
+ case "beforeunload":
+ // To make sure the telemetry pings are sent,
+ // we send "onboarding-session-end" ping as well as
+ // "overlay-session-end" and "notification-session-end" ping
+ // (by hiding the overlay and notificaiton) on beforeunload.
+ this.hideOverlay();
+ this.hideNotification();
+ this.telemetry({
+ type: "onboarding-session-end",
+ session_key: this._session_key,
+ });
+ break;
+ case "unload":
+ // Notice: Cannot do `destroy` on beforeunload, must do on unload.
+ // Otherwise, we would hit the docShell leak in the test.
+ // See Bug 1413830#c190 and Bug 1429652 for details.
+ this.destroy();
+ break;
+ case "resize":
+ this._window.cancelIdleCallback(this._resizeTimerId);
+ this._resizeTimerId =
+ this._window.requestIdleCallback(() => this._resizeUI());
+ break;
+ case "keydown":
+ this.handleKeydown(evt);
+ break;
+ case "keypress":
+ this.handleKeypress(evt);
+ break;
+ case "click":
+ this.handleClick(evt.target);
+ break;
+ default:
+ break;
+ }
+ }
+
+ destroy() {
+ if (!this.uiInitialized) {
+ return;
+ }
+ this.uiInitialized = false;
+
+ this._overlayIcon.dispatchEvent(new this._window.CustomEvent("Agent:Destroy"));
+
+ this._clearPrefObserver();
+ this._overlayIcon.remove();
+ if (this._overlay) {
+ // send overlay-session telemetry
+ this.hideOverlay();
+ this._overlay.remove();
+ }
+ if (this._notificationBar) {
+ // send notification-session telemetry
+ this.hideNotification();
+ this._notificationBar.remove();
+ }
+ this._tourItems = this._tourPages =
+ this._overlayIcon = this._overlay = this._notificationBar = null;
+ }
+
+ _onIconStateChange(state) {
+ switch (state) {
+ case ICON_STATE_DEFAULT:
+ this._overlayIcon.classList.remove("onboarding-watermark");
+ break;
+ case ICON_STATE_WATERMARK:
+ this._overlayIcon.classList.add("onboarding-watermark");
+ break;
+ }
+ return true;
+ }
+
+ showOverlay() {
+ if (this._tourItems.length == 0) {
+ // Lazy loading until first toggle.
+ this._loadTours(this._tours);
+ }
+
+ if (this._overlay && !this._overlay.classList.contains("onboarding-opened")) {
+ this.hideNotification();
+ this._overlay.classList.add("onboarding-opened");
+ this.toggleModal(true);
+ this.telemetry({
+ type: "overlay-session-begin",
+ session_key: this._session_key,
+ });
+ }
+ }
+
+ hideOverlay() {
+ if (this._overlay && this._overlay.classList.contains("onboarding-opened")) {
+ this._overlay.classList.remove("onboarding-opened");
+ this.toggleModal(false);
+ this.telemetry({
+ type: "overlay-session-end",
+ session_key: this._session_key,
+ });
+ }
+ }
+
+ /**
+ * Set modal dialog state and properties for accessibility purposes.
+ * @param {Boolean} opened whether the dialog is opened or closed.
+ */
+ toggleModal(opened) {
+ let { document: doc } = this._window;
+ if (opened) {
+ // Set aria-hidden to true for the rest of the document.
+ [...doc.body.children].forEach(
+ child => child.id !== "onboarding-overlay" &&
+ child.setAttribute("aria-hidden", true));
+ // When dialog is opened with the keyboard, focus on the first
+ // uncomplete tour because it will be the selected tour.
+ if (this._overlayIcon.dataset.keyboardFocus) {
+ doc.getElementById(this._firstUncompleteTour.id).focus();
+ } else {
+ // When the dialog is opened with the mouse, focus on the dialog
+ // itself to avoid visible keyboard focus styling.
+ this._dialog.focus();
+ }
+ } else {
+ // Remove all set aria-hidden attributes.
+ [...doc.body.children].forEach(
+ child => child.removeAttribute("aria-hidden"));
+ // If dialog was opened with a keyboard, set the focus back to the overlay
+ // button.
+ if (this._overlayIcon.dataset.keyboardFocus) {
+ delete this._overlayIcon.dataset.keyboardFocus;
+ this._overlayIcon.focus();
+ } else {
+ this._window.document.activeElement.blur();
+ }
+ }
+ }
+
+ /**
+ * Switch to proper tour.
+ * @param {String} tourId specify which tour should be switched.
+ */
+ gotoPage(tourId) {
+ let targetPageId = `${tourId}-page`;
+ for (let page of this._tourPages) {
+ if (page.id === targetPageId) {
+ page.style.display = "";
+ page.dispatchEvent(new this._window.CustomEvent("beforeshow"));
+ } else {
+ page.style.display = "none";
+ }
+ }
+ for (let tab of this._tourItems) {
+ if (tab.id == tourId) {
+ tab.classList.add("onboarding-active");
+ tab.setAttribute("aria-selected", true);
+ this.telemetry({
+ type: "overlay-current-tour",
+ current_tour_id: tourId,
+ session_key: this._session_key,
+ width: this._windowWidthRounded,
+ });
+
+ // Some tours should complete instantly upon showing.
+ if (tab.getAttribute("data-instant-complete")) {
+ this.setToursCompleted([tourId]);
+ }
+ } else {
+ tab.classList.remove("onboarding-active");
+ tab.setAttribute("aria-selected", false);
+ }
+ }
+ }
+
+ isTourCompleted(tourId) {
+ return Services.prefs.getBoolPref(`browser.onboarding.tour.${tourId}.completed`, false);
+ }
+
+ setToursCompleted(tourIds) {
+ let params = [];
+ tourIds.forEach(id => {
+ if (!this.isTourCompleted(id)) {
+ params.push({
+ name: `browser.onboarding.tour.${id}.completed`,
+ value: true,
+ });
+ }
+ });
+ if (params.length > 0) {
+ this.sendMessageToChrome("set-prefs", params);
+ }
+ }
+
+ markTourCompletionState(tourId) {
+ // We are doing lazy load so there might be no items.
+ if (!this._tourItems || this._tourItems.length === 0) {
+ return;
+ }
+
+ let completed = this.isTourCompleted(tourId);
+ let targetItem = this._tourItems.find(item => item.id == tourId);
+ let completedTextId = `onboarding-complete-${tourId}-text`;
+ // Accessibility: Text version of the auxiliary information about the tour
+ // item completion is provided via an invisible node with an aria-label that
+ // the tab is pointing to via aria-described by.
+ let completedText = targetItem.querySelector(`#${completedTextId}`);
+ if (completed) {
+ targetItem.classList.add("onboarding-complete");
+ if (!completedText) {
+ completedText = this._window.document.createElement("span");
+ completedText.id = completedTextId;
+ completedText.setAttribute("aria-label",
+ this._bundle.GetStringFromName("onboarding.complete"));
+ targetItem.appendChild(completedText);
+ targetItem.setAttribute("aria-describedby", completedTextId);
+ }
+ } else {
+ targetItem.classList.remove("onboarding-complete");
+ targetItem.removeAttribute("aria-describedby");
+ if (completedText) {
+ completedText.remove();
+ }
+ }
+ }
+
+ get _isFirstSession() {
+ // Should only directly return on the "false" case. Consider:
+ // 1. On the 1st session, `_firstSession` is true
+ // 2. During the 1st session, user resizes window so that the UI is destroyed
+ // 3. After the 1st mute session, user resizes window so that the UI is re-init
+ if (this._firstSession === false) {
+ return false;
+ }
+ this._firstSession = true;
+
+ // There is a queue, which means we had prompted tour notifications before. Therefore this is not the 1st session.
+ if (Services.prefs.prefHasUserValue("browser.onboarding.notification.tour-ids-queue")) {
+ this._firstSession = false;
+ }
+
+ // When this is set to 0 on purpose, always judge as not the 1st session
+ if (Services.prefs.getIntPref("browser.onboarding.notification.mute-duration-on-first-session-ms") === 0) {
+ this._firstSession = false;
+ }
+
+ return this._firstSession;
+ }
+
+ _getLastTourChangeTime() {
+ return 1000 * Services.prefs.getIntPref("browser.onboarding.notification.last-time-of-changing-tour-sec", 0);
+ }
+
+ _muteNotificationOnFirstSession(lastTourChangeTime) {
+ if (!this._isFirstSession) {
+ return false;
+ }
+
+ if (lastTourChangeTime <= 0) {
+ this.sendMessageToChrome("set-prefs", [{
+ name: "browser.onboarding.notification.last-time-of-changing-tour-sec",
+ value: Math.floor(Date.now() / 1000),
+ }]);
+ return true;
+ }
+ let muteDuration = Services.prefs.getIntPref("browser.onboarding.notification.mute-duration-on-first-session-ms");
+ return Date.now() - lastTourChangeTime <= muteDuration;
+ }
+
+ _isTimeForNextTourNotification(lastTourChangeTime) {
+ let maxCount = Services.prefs.getIntPref("browser.onboarding.notification.max-prompt-count-per-tour");
+ if (this._notificationPromptCount >= maxCount) {
+ return true;
+ }
+
+ let maxTime = Services.prefs.getIntPref("browser.onboarding.notification.max-life-time-per-tour-ms");
+ if (lastTourChangeTime && Date.now() - lastTourChangeTime >= maxTime) {
+ return true;
+ }
+
+ return false;
+ }
+
+ _removeTourFromNotificationQueue(tourId) {
+ let params = [];
+ let queue = this._getNotificationQueue();
+ params.push({
+ name: "browser.onboarding.notification.tour-ids-queue",
+ value: queue.filter(id => id != tourId).join(","),
+ });
+ params.push({
+ name: "browser.onboarding.notification.last-time-of-changing-tour-sec",
+ value: 0,
+ });
+ params.push({
+ name: "browser.onboarding.notification.prompt-count",
+ value: 0,
+ });
+ this.sendMessageToChrome("set-prefs", params);
+ }
+
+ _getNotificationQueue() {
+ let queue = "";
+ if (Services.prefs.prefHasUserValue("browser.onboarding.notification.tour-ids-queue")) {
+ queue = Services.prefs.getStringPref("browser.onboarding.notification.tour-ids-queue");
+ } else {
+ // For each tour, it only gets 2 chances to prompt with notification
+ // (each chance includes 8 impressions or 5-days max life time)
+ // if user never interact with it.
+ // Assume there are tour #0 ~ #5. Here would form the queue as
+ // "#0,#1,#2,#3,#4,#5,#0,#1,#2,#3,#4,#5".
+ // Then we would loop through this queue and remove prompted tour from the queue
+ // until the queue is empty.
+ let ids = this._tours.map(tour => tour.id).join(",");
+ queue = `${ids},${ids}`;
+ this.sendMessageToChrome("set-prefs", [{
+ name: "browser.onboarding.notification.tour-ids-queue",
+ value: queue,
+ }]);
+ }
+ return queue ? queue.split(",") : [];
+ }
+
+ showNotification() {
+ if (this._notificationState === "finished") {
+ return;
+ }
+
+ let lastTime = this._getLastTourChangeTime();
+ if (this._muteNotificationOnFirstSession(lastTime)) {
+ return;
+ }
+
+ // After the notification mute on the 1st session,
+ // we don't want to show the speech bubble by default
+ this._overlayIcon.classList.remove("onboarding-speech-bubble");
+
+ let queue = this._getNotificationQueue();
+ let totalMaxTime = Services.prefs.getIntPref("browser.onboarding.notification.max-life-time-all-tours-ms");
+ if (lastTime && Date.now() - lastTime >= totalMaxTime) {
+ // Reach total max life time for all tour notifications.
+ // Clear the queue so that we would finish tour notifications below
+ queue = [];
+ }
+
+ let startQueueLength = queue.length;
+ // See if need to move on to the next tour
+ if (queue.length > 0 && this._isTimeForNextTourNotification(lastTime)) {
+ queue.shift();
+ }
+ // We don't want to prompt the completed tour.
+ while (queue.length > 0 && this.isTourCompleted(queue[0])) {
+ queue.shift();
+ }
+
+ if (queue.length == 0) {
+ this.sendMessageToChrome("set-prefs", [
+ {
+ name: NOTIFICATION_FINISHED_PREF,
+ value: true,
+ },
+ {
+ name: "browser.onboarding.notification.tour-ids-queue",
+ value: "",
+ },
+ {
+ name: "browser.onboarding.state",
+ value: ICON_STATE_WATERMARK,
+ },
+ ]);
+ return;
+ }
+ let targetTourId = queue[0];
+ let targetTour = this._tours.find(tour => tour.id == targetTourId);
+
+ // Show the target tour notification
+ this._notificationBar = this._renderNotificationBar();
+ this._notificationBar.addEventListener("click", this);
+ this._notificationBar.dataset.targetTourId = targetTour.id;
+ let notificationStrings = targetTour.getNotificationStrings(this._bundle);
+ let actionBtn = this._notificationBar.querySelector("#onboarding-notification-action-btn");
+ actionBtn.textContent = notificationStrings.button;
+ let tourTitle = this._notificationBar.querySelector("#onboarding-notification-tour-title");
+ tourTitle.textContent = notificationStrings.title;
+ let tourMessage = this._notificationBar.querySelector("#onboarding-notification-tour-message");
+ tourMessage.textContent = notificationStrings.message;
+ this._notificationBar.classList.add("onboarding-opened");
+ this._window.document.body.appendChild(this._notificationBar);
+
+ let params = [];
+ let promptCount = 1;
+ if (startQueueLength != queue.length) {
+ // We just change tour so update the time, the count and the queue
+ params.push({
+ name: "browser.onboarding.notification.last-time-of-changing-tour-sec",
+ value: Math.floor(Date.now() / 1000),
+ });
+ params.push({
+ name: PROMPT_COUNT_PREF,
+ value: promptCount,
+ });
+ params.push({
+ name: "browser.onboarding.notification.tour-ids-queue",
+ value: queue.join(","),
+ });
+ } else {
+ promptCount = this._notificationPromptCount + 1;
+ params.push({
+ name: PROMPT_COUNT_PREF,
+ value: promptCount,
+ });
+ }
+ this.sendMessageToChrome("set-prefs", params);
+ this.telemetry({
+ type: "notification-session-begin",
+ session_key: this._session_key,
+ });
+ // since set-perfs is async, pass promptCount directly to avoid gathering the wrong
+ // notification_impression.
+ this.telemetry({
+ type: "notification-appear",
+ bubble_state: this._bubbleState,
+ current_tour_id: targetTourId,
+ logo_state: this._logoState,
+ notification_impression: promptCount,
+ notification_state: this._notificationState,
+ session_key: this._session_key,
+ width: this._windowWidthRounded,
+ });
+ }
+
+ hideNotification() {
+ if (this._notificationBar) {
+ if (this._notificationBar.classList.contains("onboarding-opened")) {
+ this._notificationBar.classList.remove("onboarding-opened");
+ this.telemetry({
+ type: "notification-session-end",
+ session_key: this._session_key,
+ });
+ }
+ }
+ }
+
+ _renderNotificationBar() {
+ let footer = this._window.document.createElement("footer");
+ footer.id = "onboarding-notification-bar";
+ footer.setAttribute("aria-live", "polite");
+ footer.setAttribute("aria-labelledby", "onboarding-notification-tour-title");
+
+ let section = this._window.document.createElement("section");
+ section.id = "onboarding-notification-message-section";
+ section.setAttribute("role", "presentation");
+ footer.appendChild(section);
+
+ let icon = this._window.document.createElement("div");
+ icon.id = "onboarding-notification-tour-icon";
+ icon.setAttribute("role", "presentation");
+ section.appendChild(icon);
+
+ let onboardingNotificationBody = this._window.document.createElement("div");
+ onboardingNotificationBody.id = "onboarding-notification-body";
+ onboardingNotificationBody.setAttribute("role", "presentation");
+ section.appendChild(onboardingNotificationBody);
+
+ let title = this._window.document.createElement("h1");
+ title.id = "onboarding-notification-tour-title";
+ onboardingNotificationBody.appendChild(title);
+
+ let message = this._window.document.createElement("p");
+ message.id = "onboarding-notification-tour-message";
+ onboardingNotificationBody.appendChild(message);
+
+ let actionButton = this._window.document.createElement("button");
+ actionButton.id = "onboarding-notification-action-btn";
+ actionButton.className = "onboarding-action-button";
+ section.appendChild(actionButton);
+
+ let closeButton = this._window.document.createElement("button");
+ closeButton.id = "onboarding-notification-close-btn";
+ closeButton.className = "onboarding-close-btn";
+ footer.appendChild(closeButton);
+
+ closeButton.setAttribute("title",
+ this._bundle.GetStringFromName("onboarding.notification-close-button-tooltip"));
+
+ return footer;
+ }
+
+ skipTour() {
+ this.setToursCompleted(this._tours.map(tour => tour.id));
+ this.sendMessageToChrome("set-prefs", [
+ {
+ name: NOTIFICATION_FINISHED_PREF,
+ value: true,
+ },
+ {
+ name: "browser.onboarding.state",
+ value: ICON_STATE_WATERMARK,
+ },
+ ]);
+ this.telemetry({
+ type: "overlay-skip-tour",
+ current_tour_id: this._activeTourId,
+ session_key: this._session_key,
+ width: this._windowWidthRounded,
+ });
+ }
+
+ _renderOverlay() {
+ let div = this._window.document.createElement("div");
+ div.id = "onboarding-overlay";
+
+ this._dialog = this._window.document.createElement("div");
+ this._dialog.setAttribute("role", "dialog");
+ this._dialog.setAttribute("tabindex", "-1");
+ this._dialog.setAttribute("aria-labelledby", "onboarding-header");
+ this._dialog.id = ONBOARDING_DIALOG_ID;
+ div.appendChild(this._dialog);
+
+ let header = this._window.document.createElement("header");
+ header.id = "onboarding-header";
+ header.textContent = this._bundle.GetStringFromName("onboarding.overlay-title2");
+ this._dialog.appendChild(header);
+
+ let nav = this._window.document.createElement("nav");
+ this._dialog.appendChild(nav);
+
+ let tourList = this._window.document.createElement("ul");
+ tourList.id = "onboarding-tour-list";
+ tourList.setAttribute("role", "tablist");
+ nav.appendChild(tourList);
+
+ let footer = this._window.document.createElement("footer");
+ footer.id = "onboarding-footer";
+ this._dialog.appendChild(footer);
+
+ let button = this._window.document.createElement("button");
+ button.id = "onboarding-overlay-close-btn";
+ button.className = "onboarding-close-btn";
+ button.setAttribute("title",
+ this._bundle.GetStringFromName("onboarding.overlay-close-button-tooltip"));
+ this._dialog.appendChild(button);
+
+ // support show/hide skip tour button via pref
+ if (!Services.prefs.getBoolPref("browser.onboarding.skip-tour-button.hide", false)) {
+ let skipButton = this._window.document.createElement("button");
+ skipButton.id = "onboarding-skip-tour-button";
+ skipButton.classList.add("onboarding-action-button");
+ skipButton.textContent = this._bundle.GetStringFromName("onboarding.skip-tour-button-label");
+ footer.appendChild(skipButton);
+ }
+
+ return div;
+ }
+
+ _renderOverlayButton() {
+ let button = this._window.document.createElement("button");
+ // support customize speech bubble string via pref
+ let tooltipStringPrefId = "";
+ let defaultTourStringId = "";
+ if (this._tourType === "new") {
+ tooltipStringPrefId = "browser.onboarding.newtour.tooltip";
+ defaultTourStringId = SPEECH_BUBBLE_NEWTOUR_STRING_ID;
+ } else {
+ tooltipStringPrefId = "browser.onboarding.updatetour.tooltip";
+ defaultTourStringId = SPEECH_BUBBLE_UPDATETOUR_STRING_ID;
+ }
+ let tooltip = "";
+ try {
+ let tooltipStringId = Services.prefs.getStringPref(tooltipStringPrefId, defaultTourStringId);
+ tooltip = this._bundle.formatStringFromName(tooltipStringId, [BRAND_SHORT_NAME], 1);
+ } catch (e) {
+ Cu.reportError(e);
+ // fallback to defaultTourStringId to proceed
+ tooltip = this._bundle.formatStringFromName(defaultTourStringId, [BRAND_SHORT_NAME], 1);
+ }
+ button.setAttribute("aria-label", tooltip);
+ button.id = "onboarding-overlay-button";
+ button.setAttribute("aria-haspopup", true);
+ button.setAttribute("aria-controls", `${ONBOARDING_DIALOG_ID}`);
+ let defaultImg = this._window.document.createElement("img");
+ defaultImg.id = "onboarding-overlay-button-icon";
+ defaultImg.setAttribute("role", "presentation");
+ defaultImg.src = Services.prefs.getStringPref("browser.onboarding.default-icon-src",
+ "chrome://branding/content/icon64.png");
+ button.appendChild(defaultImg);
+ let watermarkImg = this._window.document.createElement("img");
+ watermarkImg.id = "onboarding-overlay-button-watermark-icon";
+ watermarkImg.setAttribute("role", "presentation");
+ watermarkImg.src = Services.prefs.getStringPref("browser.onboarding.watermark-icon-src",
+ "resource://onboarding/img/watermark.svg");
+ button.appendChild(watermarkImg);
+ return button;
+ }
+
+ _loadTours(tours) {
+ let itemsFrag = this._window.document.createDocumentFragment();
+ let pagesFrag = this._window.document.createDocumentFragment();
+ for (let tour of tours) {
+ // Create tour navigation items dynamically
+ let li = this._window.document.createElement("li");
+ // List item should have no semantics. It is just a container for an
+ // actual tab.
+ li.setAttribute("role", "presentation");
+ li.className = "onboarding-tour-item-container";
+ // Focusable but not tabbable.
+ li.tabIndex = -1;
+
+ let tab = this._window.document.createElement("span");
+ tab.id = tour.id;
+ tab.textContent = this._bundle.GetStringFromName(tour.tourNameId);
+ tab.className = "onboarding-tour-item";
+ if (tour.instantComplete) {
+ tab.dataset.instantComplete = true;
+ }
+ tab.tabIndex = 0;
+ tab.setAttribute("role", "tab");
+
+ let tourPanelId = `${tour.id}-page`;
+ tab.setAttribute("aria-controls", tourPanelId);
+
+ li.appendChild(tab);
+ itemsFrag.appendChild(li);
+ // Dynamically create tour pages
+ let div = tour.getPage.call(this, this._window, this._bundle);
+
+ // Do a traverse for elements in the page that need to be localized.
+ let l10nElements = div.querySelectorAll("[data-l10n-id]");
+ for (let i = 0; i < l10nElements.length; i++) {
+ let element = l10nElements[i];
+ // We always put brand short name as the first argument for it's the
+ // only and frequently used arguments in our l10n case. Rewrite it if
+ // other arguments appear.
+ element.textContent = this._bundle.formatStringFromName(
+ element.dataset.l10nId, [BRAND_SHORT_NAME], 1);
+ }
+
+ div.id = tourPanelId;
+ div.classList.add("onboarding-tour-page");
+ div.setAttribute("role", "tabpanel");
+ div.setAttribute("aria-labelledby", tour.id);
+ div.style.display = "none";
+ pagesFrag.appendChild(div);
+ // Cache elements in arrays for later use to avoid cost of querying elements
+ this._tourItems.push(tab);
+ this._tourPages.push(div);
+
+ this.markTourCompletionState(tour.id);
+ }
+
+ let ul = this._window.document.getElementById("onboarding-tour-list");
+ ul.appendChild(itemsFrag);
+ let footer = this._window.document.getElementById("onboarding-footer");
+ this._dialog.insertBefore(pagesFrag, footer);
+ }
+
+ _loadCSS() {
+ // Returning a Promise so we can inform caller of loading complete
+ // by resolving it.
+ return new Promise(resolve => {
+ let doc = this._window.document;
+ let link = doc.createElement("link");
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = ONBOARDING_CSS_URL;
+ link.addEventListener("load", resolve);
+ doc.head.appendChild(link);
+ });
+ }
+
+ _loadJS(uri) {
+ let doc = this._window.document;
+ let script = doc.createElement("script");
+ script.type = "text/javascript";
+ script.src = uri;
+ doc.head.appendChild(script);
+ }
+}
diff --git a/browser/extensions/onboarding/content/img/figure_addons.svg b/browser/extensions/onboarding/content/img/figure_addons.svg
new file mode 100644
index 000000000000..b5f056737f11
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_addons.svg
@@ -0,0 +1 @@
+<svg width="295" height="199" viewBox="0 0 295 199" xmlns="http://www.w3.org/2000/svg"><title>addons</title><defs><linearGradient x1="-3335.765%" y1="-2236.632%" x2="5558.543%" y2="3780.103%" id="a"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-251.09%" y1="-799.657%" x2="413.095%" y2="1054.368%" id="b"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-573.525%" y1="-521.071%" x2="763.527%" y2="703.894%" id="c"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-2190.515%" y1="-1349.885%" x2="1528.924%" y2="974.764%" id="d"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1533.42%" y1="-541.311%" x2="2119.6%" y2="822.483%" id="e"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="1
00%"/></linearGradient><linearGradient x1="-16561.05%" y1="-16565.77%" x2="3895.86%" y2="3891.14%" id="f"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-204.8%" y1="-96.752%" x2="205.158%" y2="122.743%" id="g"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-112.715%" y1="-148.497%" x2="122.964%" y2="186.313%" id="h"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-817.408%" y1="-862.654%" x2="1335.951%" y2="1471.194%" id="i"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-923.374%" y1="-755.994%" x2="781.368%" y2="664.624%" id="j"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-57.385%" y1="-74.839%" x2="205.558%" y2="247.317%" i
d="k"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-136.437%" y1="-251.542%" x2="257.723%" y2="370.248%" id="l"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-3134.668%" y1="-1436.328%" x2="4644.893%" y2="2194.132%" id="m"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-3763.993%" y1="-1729.31%" x2="4015.564%" y2="1901.152%" id="n"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-967.977%" y1="-2316.493%" x2="1244.002%" y2="2869.881%" id="o"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-828.528%" y1="-1974.736%" x2="1398.399%" y2="3211.636%" id="p"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100
%"/></linearGradient><linearGradient x1="-341.455%" y1="-545.157%" x2="204.062%" y2="280.185%" id="q"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-6989.704%" y1="-10987.987%" x2="1723.404%" y2="2626.238%" id="r"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-346.468%" y1="-491.716%" x2="205.755%" y2="249.195%" id="s"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-163.142%" y1="-212.577%" x2="367.782%" y2="441.559%" id="t"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-431.069%" y1="-1508.892%" x2="196.676%" y2="489.527%" id="u"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-46.826%" y1="-91.711%" x2="115.212%" y2="164.256%
" id="v"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-469.407%" y1="-1536.217%" x2="369.344%" y2="1016.816%" id="w"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1395.389%" y1="-1859.067%" x2="1629.996%" y2="2107.556%" id="x"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2132.529%" y1="-2452.139%" x2="1054.189%" y2="1199.521%" id="y"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1425.341%" y1="-2206.746%" x2="1446.3%" y2="2189.629%" id="z"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1606.851%" y1="-1906.042%" x2="1515.309%" y2="1780.906%" id="A"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offse
t="100%"/></linearGradient><linearGradient x1="-2952.119%" y1="-1785.48%" x2="1577.955%" y2="986.112%" id="B"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1774.73%" y1="-1132.379%" x2="2586.424%" y2="1691.85%" id="C"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2922.831%" y1="-2221.905%" x2="1969.085%" y2="1525.629%" id="D"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2790%" y1="-1744.265%" x2="1698.406%" y2="1091.887%" id="E"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2160.459%" y1="-2153.729%" x2="1208.199%" y2="1206.393%" id="F"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2197.557%" y1="-2601.613%" x2="936.46
2%" y2="1097.31%" id="G"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2154.892%" y1="-3309.827%" x2="719.541%" y2="1068.777%" id="H"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-548.887%" y1="-964.209%" x2="654.188%" y2="1081.481%" id="I"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-318.202%" y1="-291.169%" x2="636.625%" y2="583.64%" id="J"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-455.827%" y1="-310.105%" x2="637.3%" y2="482.798%" id="K"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-5771.947%" y1="-7842.936%" x2="4994.847%" y2="6769.143%" id="L"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF"
offset="100%"/></linearGradient><linearGradient x1="-4086.052%" y1="-5400.884%" x2="4096.712%" y2="5365.911%" id="M"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1126.574%" y1="-1260.202%" x2="1146.414%" y2="1265.342%" id="N"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1150.53%" y1="-1333.596%" x2="1122.46%" y2="1289.085%" id="O"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-3947.183%" y1="-5480.943%" x2="3106.924%" y2="4260.443%" id="P"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-3712.853%" y1="-2757.137%" x2="2679.931%" y2="2000.284%" id="Q"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1265.89%" y1="-1395.587%"
x2="1007.1%" y2="1099.159%" id="R"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-2822.135%" y1="-2883.724%" x2="1935.286%" y2="1986.969%" id="S"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1548.018%" y1="-2218.877%" x2="1374.022%" y2="1940.124%" id="T"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1369.976%" y1="-1928.433%" x2="1334.398%" y2="1827.217%" id="U"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-2000.906%" y1="-2495.611%" x2="1322.352%" y2="1633.822%" id="V"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1470.604%" y1="-2072.202%" x2="1136.662%" y2="1558.26%" id="W"><stop stop-color="#00C8D7" offset="0%"/><st
op stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1194.36%" y1="-1336.72%" x2="901.341%" y2="996.106%" id="X"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-3044.038%" y1="-2935.975%" x2="2075.73%" y2="2014.652%" id="Y"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1070.957%" y1="-1207.499%" x2="1021.673%" y2="1139.289%" id="Z"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-668.331%" y1="-735.951%" x2="792.876%" y2="862.245%" id="aa"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-757.712%" y1="-833.503%" x2="703.496%" y2="764.693%" id="ab"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-27.011%" y1
="-65.863%" x2="141.75%" y2="151.803%" id="ac"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1321.337%" y1="-997.486%" x2="1168.46%" y2="905.137%" id="ad"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-1178.308%" y1="-888.422%" x2="1311.49%" y2="1014.201%" id="ae"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-546.976%" y1="-767.016%" x2="189.173%" y2="248.435%" id="af"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-93.493%" y1="-91.832%" x2="384.41%" y2="447.193%" id="ag"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-258.202%" y1="-134.734%" x2="952.458%" y2="591.721%" id="ah"><stop stop-color="#00C8D7" offset="0%"/><stop
stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-764.248%" y1="-327.902%" x2="2650.413%" y2="1243.88%" id="ai"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-341.63%" y1="-267.69%" x2="726.152%" y2="596.706%" id="aj"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-517.979%" y1="-536.225%" x2="166.434%" y2="167.425%" id="ak"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-792.149%" y1="-462.294%" x2="98.549%" y2="87.052%" id="al"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-964.554%" y1="-879.35%" x2="1659.876%" y2="1524.226%" id="am"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-797.538%" y1="-665.
814%" x2="581.403%" y2="509.871%" id="an"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1165.123%" y1="-1561.869%" x2="356.021%" y2="461.04%" id="ao"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-505.775%" y1="-623.411%" x2="1092.421%" y2="1325.92%" id="ap"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-365.189%" y1="-194.484%" x2="727.939%" y2="447.534%" id="aq"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-2359.875%" y1="-1563.43%" x2="1606.616%" y2="1099.129%" id="ar"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M-31-68h352v303H-31z"/><g fill-rule="nonzero"><g fill="#D7D7DB"><path d="M23
8.3 15.6c-5.5 0-8.3-1.5-11-3-2.6-1.4-5-2.7-9.9-2.7s-7.4 1.3-9.9 2.7c-2.7 1.5-5.5 3-11 3s-8.3-1.5-11-3c-2.6-1.4-5-2.7-9.9-2.7s-7.4 1.3-9.9 2.7c-2.7 1.5-5.5 3-11 3-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1 4.9 0 7.4-1.3 9.9-2.7 2.7-1.5 5.5-3 11-3s8.3 1.5 11 3c2.6 1.4 5 2.7 9.9 2.7s7.4-1.3 9.9-2.7c2.7-1.5 5.5-3 11-3s8.3 1.5 11 3c2.6 1.4 5 2.7 9.9 2.7s7.4-1.3 9.9-2.7c2.7-1.5 5.5-3 11-3 .6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1-4.9 0-7.4 1.3-9.9 2.7-2.7 1.5-5.5 3-11 3zM196.2 7.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6 1.2 0 2.2-.1 3.2-.3.3-.1.6.2.6.5.1.3-.2.6-.5.6-1 .3-2.1.4-3.3.4zm7.6-1.6c-.2 0-.4-.1-.5-.3-.1-.3 0-.6.3-.7.3-.2.7-.3 1-.5.3-.1.6 0 .7.2.1.3 0 .6-.2.7-.3.2-.7.3-1 .5-.2.1-.2.1-.3.1zm-16.3-.1c-.1 0-.2 0-.2-.1-.8-.4-1.5-.7-2.2-1.1-2.6-1.4-5.1-2.8-10.2-2.8-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6 5.4 0 8.1 1.5 10.7 2.9.7.4 1.4.7 2.1 1.1.3.1.4.5.3.7-.1.4-.3.5-.5.5zm26.6-3.8c-.3 0-.5-.2-.6-.5 0-.3.2-.6.5-.6.8-.1 1.7-.1 2.7-.1.3 0 .6.2.6.6 0 .3-.2.6-.6.6-.9-.2-1.7-.1-2.6 0 .1 0 0 0 0 0zM238.5 23.1c-.3
0-.6-.2-.6-.6 0-.3.2-.6.6-.6 1.2 0 2.2-.1 3.2-.3.3-.1.6.2.6.5.1.3-.2.6-.5.6-1 .3-2.1.4-3.3.4zm7.6-1.5c-.2 0-.4-.1-.5-.3-.1-.3 0-.6.3-.7.3-.2.7-.3 1-.5.3-.1.6 0 .7.2.1.3 0 .6-.2.7-.3.2-.7.3-1 .5-.2 0-.3.1-.3.1zm-16.3-.2c-.1 0-.2 0-.2-.1-.8-.4-1.5-.7-2.2-1.1-2.6-1.4-5.1-2.8-10.2-2.8-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6 5.4 0 8.1 1.5 10.7 2.9.7.4 1.4.7 2.1 1.1.3.1.4.5.3.7-.1.4-.3.5-.5.5zm26.6-3.8c-.3 0-.5-.2-.6-.5 0-.3.2-.6.5-.6.8-.1 1.7-.1 2.6-.1.3 0 .6.2.6.6 0 .3-.2.6-.6.6-.8-.1-1.6-.1-2.5 0z"/></g><path d="M6.2 133.5c-2.8 0-5.1-2.2-5.1-4.8V10.2c0-3 2.4-5.4 5.4-5.4h127.2c3 0 5.4 2.4 5.4 5.4v118.5c0 2.6-2.3 4.8-5 4.8H6.2z" fill="#FFF"/><path d="M133.7 6c2.3 0 4.2 1.9 4.2 4.2v118.5c0 2-1.8 3.7-3.9 3.7H6.2c-2.2 0-3.9-1.7-3.9-3.7V10.2C2.3 7.9 4.2 6 6.5 6h127.2zm0-2.2H6.6C3 3.8.1 6.7.1 10.3v118.4c0 3.3 2.8 5.9 6.2 5.9H134c3.4 0 6.2-2.7 6.2-5.9V10.2c0-3.5-2.9-6.4-6.5-6.4z" fill="#D7D7DB"/><path d="M132.6 27.1v98.2c0 1-.1 1.2-.1 1.2s-.2.1-1.2.1H9.1c-1 0-1.2-.1-1.2-.1s-.1-.2-.1-1.2V27.1h124.8zm1.
1-1.1H6.6v99.3c0 2 .4 2.5 2.5 2.5h122.2c2 0 2.5-.4 2.5-2.5V26h-.1z" fill="#D7D7DB"/><g fill="#D7D7DB"><circle cx="3.4" cy="2.9" r="2.9" transform="translate(10 13)"/><circle cx="3.7" cy="2.9" r="2.9" transform="translate(19 13)"/><path d="M102.1 19.2H38.2c-1.7 0-3.1-1.4-3.1-3.1v-.3c0-1.7 1.4-3.1 3.1-3.1h63.9c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.7-1.4 3.1-3.1 3.1z"/><g><circle cx="3.6" cy="2.9" r="2.9" transform="translate(114 13)"/><circle cx="2.9" cy="2.9" r="2.9" transform="translate(124 13)"/></g></g><ellipse fill="#EDEDF0" cx="177.8" cy="191.1" rx="78.4" ry="7.4"/><g fill="#D7D7DB"><path d="M241.5 164.9c-5.5 0-8.3-1.5-11-3-2.6-1.4-5-2.7-9.9-2.7s-7.4 1.3-9.9 2.7c-2.7 1.5-5.5 3-11 3s-8.3-1.5-11-3c-2.6-1.4-5-2.7-9.9-2.7s-7.4 1.3-9.9 2.7c-2.7 1.5-5.5 3-11 3s-8.3-1.5-11-3c-2.6-1.4-5-2.7-9.9-2.7s-7.4 1.3-9.9 2.7c-2.7 1.5-5.5 3-11 3s-8.3-1.5-11-3c-2.6-1.4-5-2.7-9.9-2.7-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1 5.5 0 8.3 1.5 11 3 2.6 1.4 5 2.7 9.9 2.7s7.4-1.3 9.9-2.7c2.7-1.5 5.5-3 11-3s8.3 1.5 11
3c2.6 1.4 5 2.7 9.9 2.7s7.4-1.3 9.9-2.7c2.7-1.5 5.5-3 11-3s8.3 1.5 11 3c2.6 1.4 5 2.7 9.9 2.7s7.4-1.3 9.9-2.7c2.7-1.5 5.5-3 11-3s8.3 1.5 11 3c2.6 1.4 5 2.7 9.9 2.7.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1zM200.5 155.8c-.8 0-1.5 0-2.3-.1-.3 0-.5-.3-.5-.6s.3-.5.6-.5c.7.1 1.4.1 2.2.1h1.1c.3 0 .6.2.6.5s-.2.6-.5.6h-1.2zm-41.4 0c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6 1.2 0 2.2-.1 3.2-.3.3-.1.6.2.6.5.1.3-.2.6-.5.6-1 .3-2.1.4-3.3.4zm46.9-.7c-.2 0-.5-.2-.5-.4-.1-.3.1-.6.4-.7.4-.1.7-.2 1-.3.3-.1.6.1.7.3.1.3-.1.6-.3.7-.4.1-.7.2-1.1.3-.1.1-.2.1-.2.1zm-39.3-.9c-.2 0-.4-.1-.5-.3-.1-.3 0-.6.3-.7.3-.2.7-.3 1-.5.3-.1.6 0 .7.2.1.3 0 .6-.2.7-.3.2-.7.3-1 .5-.2.1-.3.1-.3.1zm-16.3-.1c-.1 0-.2 0-.2-.1-.8-.4-1.5-.7-2.2-1.1-2.6-1.4-5.1-2.8-10.2-2.8-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6 5.4 0 8.1 1.5 10.7 2.9.7.4 1.4.7 2.1 1.1.3.1.4.5.3.7-.1.3-.3.5-.5.5zm39.5-1.2c-.1 0-.2 0-.3-.1-2.4-1.3-4.9-2.7-10-2.7-.9 0-1.7 0-2.5.1-.3 0-.6-.2-.6-.5s.2-.6.5-.6c.8-.1 1.7-.1 2.7-.1 5.4 0 8.1 1.5 10.5 2.8.3.1.4.5.2.8-.1.1-.3.3-.5.3zm26.3-2
.2c-.2 0-.5-.2-.5-.4-.1-.3.1-.6.4-.7 1.6-.4 3.3-.6 5.3-.6.3 0 .6.2.6.6 0 .3-.2.6-.6.6-1.9 0-3.5.2-5 .6-.1-.1-.2-.1-.2-.1z"/></g><g fill="#D7D7DB"><path d="M76.9 101c-.8 0-2.2-.1-3.6-.7-1.8-.8-2.7-2.2-2.7-4.1 0-1.6.9-2.6 1.8-3.5 1-1 1.9-2 1.9-3.8 0-1.5-2.1-3.7-5.8-3.7-3.8 0-5.5 2.2-5.5 3.7 0 1.8.9 2.8 1.9 3.8.9.9 1.9 1.9 1.9 3.5 0 3.5-3.2 4.8-6.2 4.8H47.8c-2.4 0-4.3-2-4.3-4.4V84.9c0-.1-.2-3 1.5-4.8.8-.9 1.9-1.3 3.3-1.3 1.6 0 2.5 1 3.4 1.9.9 1 1.8 2 3.6 2 1.6 0 3.3-1.9 3.3-5.4 0-3.6-1.7-5.2-3.3-5.2-1.8 0-2.7 1-3.6 2-.9 1-1.7 2-3.4 2-1.4 0-2.5-.4-3.3-1.3-1.7-1.8-1.5-4.9-1.5-5v-7.4c0-.9.3-1.8.8-2.6.8-1.1 2.1-1.8 3.5-1.8h9.3s2.7-.5 2.7-2.3c0-.7-.4-1.2-1.1-1.9-1-1-2.2-2.2-2.2-4.9 0-2.3 1.1-6.2 8.2-6.2 7.6 0 8.5 4.3 8.5 6.2 0 2.7-1.3 4-2.4 5-.8.7-1.2 1.2-1.2 1.9 0 1.8 2.8 2.3 2.8 2.3h9.9c2.4 0 4.3 2 4.3 4.4v5.6s.4 3 2.1 3c.7 0 1.1-.4 1.7-1.1.8-1 2-2.4 4.7-2.4 2.4 0 6.5 1 6.5 8.1 0 7.8-4.9 8.4-6.5 8.4-2.8 0-3.9-1.4-4.7-2.5-.6-.8-1-1.2-1.7-1.2-1.8 0-2.1 3-2.2 3v13.5c0 2.4-1.9 4.4-4.3 4.4h-5c
0-.3-.1-.3-.3-.3z"/></g></g><path d="M258.9 143.4c-.2.6-.7 1.1-1.2 1.5 0 1-.2 1.9-.6 2.8.9-.3 1.8-.8 2.6-1.6.7-.8 1.1-1.6 1.5-2.3.8-2 .4-4.2-1.1-5.5-.4-.4-1-.6-1.5-.8-.7-.2-1.5-.2-2.3 0 2.2 1.4 3.6 3.4 2.6 5.9zM129.7 89.8l-.2-.1c-.2 0-.3-.1-.5-.1h-.1-.1-.1H128.1c-.1 0-.1 0-.1.1 0 0-.1 0-.2.1-.1 0-.2.1-.3.2-.3.2-.7.6-1.1 1.1l-.7.7c.1.1.2.3.1.5-.2 1.1-.5 1.9-.8 2.7.2.6.4 1.1.6 1.6.4.8.9 1.6 1.5 2.4.6.8 1.3 1.5 2.2 2.2.5.4.9.7 1.3.9h.1c.4.3.9.5 1.5.7 1 .4 2.1.7 3.2.8.3 0 .7.1 1.1.1h2.1c.6-.1 1.1-.3 1.5-.4.6-.2 1-.4 1.3-.6.3-.2.5-.3.8-.5.5-3.3.9-7 1.1-11.2-1.3-.6-2.6-1.3-3.7-2.1-1 1-2 1.6-2.9 1.6-.3 0-.5 0-.8-.1l-3-1.2c-1.2.6-2.3.9-3.2.6z"/><path d="M141.1 57.4c0 .7 0 1.4.1 2.1-.3.3-.7.6-1 .9.3-.3.6-.6 1-.9-.1-.7-.1-1.4-.1-2.1zM180.3 24.8c-2-.4-4-.6-6-.6-.7 0-1.4 0-2.1.1.7 0 1.4-.1 2.1-.1 2 .1 4 .2 6 .6zM122.9 136.4c.6-.6 1.2-1.3 1.8-2-.6.6-1.2 1.3-1.8 2-1 1-2 2-3 2.9 1-.9 2-1.9 3-2.9zM134.2 123.6c.3-.4.7-.7 1.1-1.1l-1.1 1.1c-1.3 1.4-2.6 2.8-3.9 4.3-.6.7-1.2 1.5-1.9 2.2.6-.7 1.2-1.5 1.9
-2.2 1.2-1.4 2.5-2.9 3.9-4.3zM129.1 119.1l1.8.9c.6.3 1.3.5 1.9.7-.7-.2-1.3-.5-1.9-.7l-1.8-.9zM241.7 82.7v-.3M244.7 142.3h-.4.4zM145.9 40.2c.6-.9 1.2-1.8 1.8-2.6-.7.8-1.3 1.7-1.8 2.6zM211 186.6h.2-.5.3zM137.4 186.6h.3-.5.2zM177.3 142.7c-.3-.8-.6-1.5-.9-2.2.3.7.6 1.4.9 2.2zM109.4 153.9c1 .2 2.1.3 3.2.3h1.4-1.4c-1.1 0-2.2-.1-3.2-.3zM144.3 43c.5-1 1-1.9 1.5-2.8-.5.9-1 1.9-1.5 2.8z" fill="#FFF" fill-rule="nonzero"/><path d="M142 102c-.3.2-.5.3-.8.5-.3.2-.8.4-1.3.6-.4.1-.9.3-1.5.4h-1-1.1c-.4 0-.8 0-1.1-.1-1.1-.1-2.2-.4-3.2-.8-.6-.2-1-.5-1.5-.7h-.1c-.4-.2-.8-.5-1.3-.9-.8-.7-1.6-1.5-2.2-2.2-.6-.8-1.1-1.6-1.5-2.4-.2-.5-.5-1-.6-1.6-.5.9-1 1.6-1.8 2.1h-.1c.1.2.1.3.2.5.5 1 1 1.9 1.7 2.8.7.9 1.6 1.8 2.6 2.6.6.5 1.1.8 1.6 1.1.5.3 1.1.6 1.8.9 1.2.5 2.5.9 3.8 1 .4 0 .8.1 1.3.1h2.5c.7-.2 1.3-.3 1.8-.5.7-.3 1.2-.5 1.6-.7.6-.3 1.2-.8 1.8-1.2.7-4 1.2-8.6 1.4-13.9-1.6-.6-3.1-1.3-4.4-2.3-.4.6-.8 1.2-1.3 1.6 1.1.8 2.4 1.6 3.7 2.1-.1 4-.4 7.7-1 11z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M140.8 174.9
c.5-.5 1-1 1.4-1.5-.4.5-.9 1-1.4 1.5zM198.7 183.3c1.1.6 2.1 1.1 3.1 1.5.5.2 1 .4 1.5.5-.5-.2-1-.3-1.5-.5-1-.4-2-.9-3.1-1.5zM203.8 136.1c.6.1 1.2.2 1.9.4.3.1.6.2.9.2-.3-.1-.6-.2-.9-.2-.7-.2-1.3-.3-1.9-.4zM182.4 161.8c.2.7.5 1.4.7 2.1.5 1.4 1.1 2.8 1.8 4.1-.7-1.3-1.2-2.7-1.8-4.1-.2-.7-.4-1.4-.7-2.1zM180.3 153v.1-.1zM255 146.2c-.1.6-.4 1.1-.7 1.6.1 0 .1.1.2.1.8.2 1.7.2 2.6-.1.4-.9.6-1.8.6-2.8-.7.5-1.6.9-2.7 1.2z" fill="#FFF" fill-rule="nonzero"/><path d="M249.9 67.3c-.6.7-1.1 1.3-1.6 1.9-.5.7-1.1 1.4-1.5 2.2-.5.8-.9 1.6-1.3 2.3-.3.7-.7 1.5-1 2.4-.5 1.6-.7 3.4-.7 5.4V83.2l.1 1.2v.4c0 .4.1.7.1 1 .1 2 .1 4.1 0 6.1-.3 4.7-1.3 9.1-2.9 13.1-1 2.4-2.1 4.6-3.5 6.6-1.2 1.8-2.7 3.4-4.4 4.9-.3.4-.8.8-1.2 1.2-.3.2-.5.4-.8.5-1.8 1.3-3.7 2.5-5.8 3.4-1 .4-1.9.7-2.8 1 2.1 1.6 4.8 4.3 7.8 8.7 4.8 7.1 10.4 8.7 14.7 9 .4-.9.8-1.7 1.2-2.2-4.1-.1-9.3-1.3-13.8-8-1.9-2.8-3.7-5-5.4-6.6 2.5-1.1 4.8-2.6 6.9-4.3 2.2-1.8 4.2-3.9 5.8-6.2 1.5-2.1 2.8-4.5 3.8-7 1.7-4.2 2.7-8.8 3.1-13.8.1-2.1.1-4.2 0-6.3 0-.4 0-.7-.1
-1.1v-.4l-.1-1.1V82.4v-.5-.2c0-1.7.2-3.3.6-4.7.2-.6.5-1.3.9-2.2.3-.7.7-1.4 1.1-2 .4-.7.9-1.3 1.4-2 .4-.5.8-1 1.3-1.6-.8-.6-1.5-1.2-1.9-1.9zM138.8 58.5v-1.1c0-19.5 15.9-35.4 35.4-35.4s35.4 15.9 35.4 35.4v1.1c3.8 3.5 5.9 8.3 5.9 13.5 0 7.9-4.9 14.7-12.2 17.3 0 .8.1 1.5.1 2.3 0 0 .1.1.1.2.2.3.3.6.5.9l.3.6v.1c.1.3.3.5.4.8v.1c.1.2.2.3.2.5 0 .1.1.1.1.2l.1.2v.1l.1.2.1.2.3.6c.1.1.1.2.2.4.1.1.2.3.2.4.4.6.7 1.1 1 1.5.4.5.9 1 1.3 1.4.9.8 2 1.4 3.2 1.7h.1c.5.2 1.1.2 1.8.2h.2c.4 0 .8-.1 1.3-.1h.1c1.2-.2 2.2-.7 3.1-1.3.7-.5 1.2-1 1.6-1.5.5-.6 1-1.3 1.4-2.1 1-1.9 1.7-4.1 2-6.4.2-1.5.4-2.7.4-3.8v-.1-.5-1-2.3c0-.4.1-.9.1-1.3.4-4 1.7-8 3.5-11.5 1.6-3 3.6-5.7 6.1-8.2 1.8-1.8 3.8-3.3 6.3-4.9 1.9-1.3 3.6-2.1 5.1-2.9l.2-.1-.3-1-3.2 1.1c-.3.1-.7.2-1.1.2h-.2l-1.5.9c-2.6 1.6-4.7 3.3-6.6 5.2-2.7 2.6-4.9 5.6-6.5 8.7-2 3.7-3.3 8-3.7 12.3 0 .4-.1.9-.1 1.3v.4l-.1.7v2.9c-.1 1-.2 2.2-.4 3.6-.3 2.1-1 4.1-1.8 5.7-.3.6-.7 1.2-1.1 1.7-.3.4-.7.7-1.2 1.1-.7.5-1.4.8-2.2 1-.4.1-.8.1-1 .1h-.1c-.3 0-.9-.1-1.2-.1h-.1c-.8-.2-
1.6-.6-2.3-1.2-.4-.3-.7-.7-1-1.1-.2-.3-.5-.7-.8-1.2-.1-.1-.1-.3-.2-.4 0-.1-.1-.1-.1-.2-.1-.2-.2-.5-.3-.7l-.1-.1-.1-.2s0-.1-.1-.1l-.1-.2v-.1c-.1-.2-.2-.3-.3-.5v-.1c-.1-.2-.3-.5-.4-.7 0-.1-.1-.1-.1-.2-.1-.2-.2-.4-.3-.5-.1-.2-.2-.4-.4-.7v-.1c7.3-3.3 12.1-10.5 12.1-18.8 0-5.4-2.1-10.6-5.9-14.4V58c0-20.8-16.9-37.6-37.6-37.6-20.7 0-37.6 16.9-37.6 37.6v.2c-3.2 3.2-5.1 7.3-5.7 11.8l1.9.8c.5-5.1 2.5-9.2 5.8-12.3z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M238.7 153.9h-1.6.4c.5.1.9.1 1.2 0zM223.8 148.2c-.4-.3-.9-.7-1.3-1-.7-.5-1.3-1.1-2-1.6.6.5 1.3 1.1 2 1.6.4.3.9.6 1.3 1z" fill="#FFF" fill-rule="nonzero"/><path d="M251.4 150.6c-.1.1-.2.2-.4.3-.9.7-1.9 1.4-3.2 2.2-1.3.8-3 1.7-5.2 2.3-1.1.3-2.3.6-3.7.7-.4 0-.9.1-1.4.1-.9 0-1.9-.1-2.8-.2-3.2-.5-6-1.9-7.8-3-2.2-1.3-4.1-2.8-5.8-4.1-.8-.6-1.5-1.3-2.3-1.9-.7-.6-1.4-1.1-2.1-1.7-.2-.1-.5-.3-.7-.5-.4-.3-.7-.6-1-.9-1-.8-2-1.5-2.9-2.1-.6-.4-1.2-.7-1.9-1.2-.7-.4-1.3-.7-1.9-.9-1.1-.5-2.1-.9-3.3-1.2-.9-.2-1.9-.4-2.8-.5v7c.1 1.4.1 2.8.1 4.2v1.5c.4 16.7
4.3 19.4 9.8 23.1 6.3 4.2 8.2 5.5 7.7 9-.1 3.1-2.7 5.7-5.8 5.7h-.1c-.5.1-1.5.2-3 .2-.5 0-1.1 0-1.6-.1-1.8-.1-3.6-.4-5.3-.9-1.1-.3-2.2-.6-3.2-1.1-1.3-.5-2.4-1-3.4-1.6-1.2-.7-2.3-1.4-3.4-2.2-1.1-.9-2.2-1.8-3.3-2.8-1-1-2-2.1-3-3.4-1-1.2-1.9-2.5-2.7-3.8-1.6-2.6-3-5.5-4.1-8.4-.5-1.4-1-2.9-1.4-4.4-.2-.6-.3-1.2-.5-1.8v-.2l-.1-.4c-.1-.6-.3-1.2-.4-1.9l-.4-2v-.2V153.2l-.1-.4-.2-.8c-.3-1-.5-2.1-.8-3.2-.5-2-1.1-3.8-1.7-5.2-.4-.9-.6-1.5-.9-2.1-.1-.1-.1-.2-.2-.3 0 .1-.1.2-.1.3-.3.6-.5 1.2-.9 2.1-.6 1.5-1.2 3.2-1.7 5.3-.3 1-.6 2.1-.8 3.2l-.2.8-.1.4v.5l-.4 2c-.1.7-.3 1.3-.4 1.9l-.1.4-.1.5c-.1.6-.3 1.2-.5 1.7-.4 1.5-.9 3-1.4 4.4-1.1 3-2.5 5.8-4.1 8.4-.8 1.3-1.7 2.6-2.7 3.8-1.1 1.3-2 2.4-3 3.4s-2.2 2-3.3 2.8c-1.1.8-2.2 1.5-3.4 2.2-1 .6-2.1 1.1-3.4 1.6-1 .4-2.1.8-3.2 1.1-1.7.5-3.5.8-5.3.9h-1.6c-1.5 0-2.5-.1-3-.2h-.1c-3.2 0-5.8-2.7-5.8-5.9 0-3 2.3-5.6 5.3-5.9l.2-.1c.4-.2 1-.4 1.7-.8.8-.4 1.6-1 2.4-1.6.4-.4.9-.7 1.3-1.1.4-.3.8-.8 1.3-1.3.4-.5.8-1 1.2-1.6.4-.6.7-1.2 1.1-1.8.3-.6.6-1.3.9-2.1.3-.7.5-1.5.8-
2.3.2-.7.4-1.6.6-2.6.2-.8.3-1.7.4-2.7.1-.9.2-1.9.3-3 0-.4 0-.8.1-1.2v-.3V151.3v-.1-1.9c0-1.5 0-2.9.1-4.3l.3-3.9c-.9.5-1.8 1.2-3 2-.8.5-1.6 1.1-2.4 1.7-2.4 1.6-5 3.5-7.9 5.2-2.2 1.4-4.3 2.4-6.2 3.3-2.4 1.1-4.7 1.9-7 2.5-1.1.3-2.3.5-3.7.6-1 .1-1.9.1-2.8.1h-.9c-1.8-.1-3.5-.3-5.3-.8.4.8.7 1.6.9 2.4 1.5.3 3 .5 4.6.6h1c.9 0 1.9 0 3-.2h.1c1.5-.2 2.8-.4 4-.7 2.4-.6 4.9-1.4 7.4-2.6 2-.9 4.1-2 6.4-3.4 2.9-1.8 5.6-3.6 8-5.3.5-.4 1-.7 1.5-1.1-.1 1.3-.1 2.5-.1 3.9v5.2c0 .4 0 .8-.1 1.2v.1c-.1 1-.2 2-.3 2.8-.1 1-.3 1.8-.4 2.5-.2.9-.4 1.7-.6 2.4-.2.8-.5 1.5-.7 2.2-.3.7-.6 1.3-.9 1.9l-.9 1.5c-.4.5-.7 1-1 1.4-.4.5-.8.9-1.1 1.2-.4.3-.8.7-1.2 1-.8.6-1.6 1.1-2.1 1.4-.6.3-1.1.6-1.5.7-3.9.6-6.9 4-6.9 8 0 4.4 3.5 8 7.9 8.1.5.1 1.7.2 3.3.2.6 0 1.1 0 1.7-.1 2-.1 3.9-.4 5.7-.9 1.2-.3 2.3-.7 3.4-1.1 1.3-.5 2.5-1.1 3.6-1.7 1.3-.7 2.5-1.5 3.6-2.3 1.2-.9 2.4-1.9 3.5-3 1.1-1 2.1-2.2 3.2-3.6 1-1.3 2-2.6 2.8-4 1.7-2.8 3.2-5.7 4.3-8.8.5-1.5 1-3 1.5-4.6.2-.6.3-1.2.5-1.8l.1-.4v-.1l.1-.4c.1-.6.3-1.3.4-2l.4-2v-.2-.2l.1-.
5.2-.8c.2-1 .5-2.1.8-3.1l.6-2.1c.2.7.4 1.3.6 2.1.3 1 .5 2.1.8 3.1l.2.8.1.4v.4l.4 2c.1.7.3 1.3.4 2l.1.4v.1l.1.4c.1.6.3 1.2.5 1.9.4 1.6.9 3.1 1.5 4.6 1.1 3.1 2.6 6 4.3 8.8.9 1.4 1.8 2.8 2.8 4 1.1 1.4 2.2 2.6 3.2 3.6 1.1 1.1 2.3 2.1 3.5 3 1.2.9 2.4 1.6 3.7 2.4 1.1.6 2.3 1.2 3.6 1.7 1.1.4 2.3.8 3.4 1.1 1.8.5 3.8.8 5.7.9.6 0 1.2.1 1.7.1 1.6 0 2.7-.1 3.3-.2 4.2-.1 7.7-3.5 7.9-7.7.6-4.8-2.3-6.8-8.7-11.1-5.1-3.4-8.5-5.7-8.9-21.2v-1.5c0-1.4 0-2.9-.1-4.3v-3.9-.4c1.1.3 2 .6 2.9 1h.1c.5.2 1 .5 1.6.8.7.4 1.3.7 1.8 1.1 1.2.8 2.5 1.7 4 3 .8.6 1.6 1.3 2.4 2 .7.6 1.5 1.3 2.3 1.9 1.8 1.4 3.7 2.9 6.1 4.3 2 1.2 5 2.7 8.6 3.3 1.1.2 2.1.3 3.2.3.5 0 1.1 0 1.6-.1 1.5-.1 2.8-.4 4.1-.8 2.4-.7 4.3-1.7 5.7-2.5 1.4-.9 2.5-1.7 3.4-2.4l.1-.1c.5-.4.9-.7 1.2-1-.1 0-.3 0-.4-.1-.2-.2-1-.5-1.6-1z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M258.3 51.2c-.2-.3-.5-.5-.8-.7l.3.9c.1-.1.3-.1.5-.2z" fill="#FFF" fill-rule="nonzero"/><path d="M100.3 137.6c.1-.1.1-.1.2-.1.3-.1.6.1.7.4 0 .1.1.3.1.4.7.2 1.4.4 2.3.7 2.3.8 5.5 1.
8 8.4 1.8 1 0 1.9-.1 2.6-.4 1-.6 2.1-1.4 3.2-2.3 1.1-.9 2.2-2 3.5-3.4 1.8-1.9 3.5-3.9 5.4-6.1.6-.8 1.3-1.5 1.9-2.3 1.3-1.5 2.4-2.7 3.4-3.8-.7-.2-1.3-.5-1.9-.7-2.7-1.1-5.1-2.6-7.3-4.4-1.1-.9-2.1-1.8-2.9-2.7-.8-.8-1.6-1.8-2.4-2.9-1.4-1.9-2.4-3.9-3.2-5.9-.3-.7-.5-1.4-.7-2-.5-.4-.9-1-1-1.7v-.3-.1-.2-.8-1.2c0-.2 0-.4.1-.6-.1-.9-.2-1.8-.2-2.7v-.8V94.7v-.2c-1-1.1-1.4-2.3-1.6-3.3-.1.4-.2.8-.2 1.2l-.1.8c0 .4-.1.9-.1 1.3v1.7c0 1.6.2 3.1.4 4.6.3 2 .9 3.9 1.6 5.8.9 2.2 2 4.3 3.5 6.4.9 1.2 1.7 2.2 2.6 3.2.9 1 2 2 3.1 2.9 2.1 1.7 4.3 3.1 6.8 4.2-.4.4-.8.9-1.2 1.4-.7.8-1.3 1.5-2 2.3-1.8 2.1-3.5 4.2-5.3 6-1.2 1.3-2.3 2.3-3.3 3.2-.9.8-1.8 1.4-2.6 1.9-.5.1-1.1.2-1.8.2-2.5 0-5.4-.9-7.6-1.7-1.5-.5-2.6-.9-3.7-1-.4-.1-.7-.1-1.1-.1-.3 0-.6 0-.8.1l.1.6c.3.5.8.9 1.1 1.4z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M146.2 166.2c-.1.4-.2.7-.4 1.1.2-.3.3-.7.4-1.1z" fill="#FFF" fill-rule="nonzero"/><path d="M37.1 92.1c.1 0 .2-.1.3-.1-.6-.9-1.2-1.8-1.7-2.7-.2.1-.4.2-.6.2.1.2.2.5.2.7.3.8.7 1.6 1.1 2.5.2-.3.4-.5
.7-.6z" fill="url(#a)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M65.2 105.7s2.7-.5 6.3-2.1c.1-.3.1-.5.2-.8-3.1 1.1-6.7 1.7-10.9 1.7h-1.1c-8.8-.2-15.1-4.7-18.7-8.2.2 1 .1 1.8-.1 2.5.7.7 1.5 1.5 2.3 2.1 1.5 1.2 3.1 2.3 4.9 3.2l1.8.9c.6.3 1.3.5 1.9.7.7.2 1.3.4 2 .6l1 .2c.1 0 .2 0 .3.1l-.1.1c3.6.6 6.8.7 9.2.6 0-.1-.1-.2-.1-.2.1-.7.5-1.3 1.1-1.4z" fill="url(#b)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M38.9 124.2c2.9-2.4 6.1-6.1 10-10.6 1.6-1.8 3.4-3.9 5.3-6.1l-1.1 1.1c-1.3 1.4-2.6 2.8-3.9 4.3-.6.7-1.2 1.5-1.9 2.2-.6.7-1.2 1.4-1.8 2.2l-1.8 2.1c-.6.7-1.2 1.4-1.8 2-1 1-2 2-3 2.8z" fill="url(#c)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M65.2 151.2c-.1.4-.2.7-.4 1.1-.3.8-.7 1.5-1 2.3-.4.7-.8 1.4-1.2 2-.4.6-.9 1.2-1.3 1.8-.5.5-.9 1.1-1.4 1.5-.1.1-.1.1-.2.1 2.5-1.8 4.4-4.6 5.5-8.8z" fill="url(#d)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M70.5 73.8c-.1 0-.1 0 0 0-.2 0-.8.1-1.8.1-.7 0-1.5 0-2.3-.1-.2 5.8-.7 10.7-1.5 15 .6
-.7 1-1.3 1.4-1.9 1.9-3.4 3.4-9.4 4.2-13.1z" fill="url(#e)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M171.4 131.5s.1 0 0 0c.1 0 .1 0 0 0 .1 0 .1 0 0 0z" fill="url(#f)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M162.9 131.2c-7.1 3-14.2-.7-19.1-5.2-4.9-4.5-16.4-17.9-16.4-17.9l9.3-.7s.5.1 1.5.6c-.3-.3-.7-.5-1-.8h-1.3c-2.6 0-4.7-.4-4.8-.4-.3-.1-.5-.3-.5-.6.1-.3.3-.5.6-.5 0 0 4 .7 7.7.2.4-.1.7-.1 1.1-.2 1.2-.3 2.4-.7 3.5-1.2 1-.4 1.9-.9 2.9-1.4-.4-1 .4-2.7 2.1-3.9 1.5-1.1 3.1-1.5 4-1 .9-.9 1.6-1.9 2.3-2.9 1-1.5 1.9-3 2.6-4.6.2-.5.5-1 .7-1.6.6-1.4 1-2.8 1.4-4.3-.3.1-.5.1-.8.1-1.2-.3-1.6-2.3-1.1-4.4.6-2.1 2-3.6 3.1-3.3v-.4c.1-2 .1-3.9 0-5.8 0-.5-.1-.9-.1-1.4 0-.4-.1-.8-.1-1.2v-.8-.2-.7c0-1.6.1-3.2.4-4.6.1-.5.2-1 .4-1.4.3-.9.7-1.8 1.1-2.7.4-.9.9-1.7 1.4-2.6l1.5-2.1c-.4 0-.7-.2-.9-.4-.8-.9-.2-2.8 1.4-4.3.4-.4.9-.7 1.3-1l-.6-1.7c-1.8 1.2-3.6 2.7-4.8 4.8-3.6 6.1-4.4 8.7-4.4 13.9v1.3c0 6.1.1 17.4-4.2 23.9-5.6 8.4-14 12.5-25.6 12.5H126c2.9.5 6 .7 9.4.2.6-.1 1.2
.3 1.3.9.1.6-.3 1.2-.9 1.3-1.5.2-3 .4-4.5.4-5.3 0-9.9-1.4-13.2-2.9.7 4 1.1 8.1 1.2 12.3.3 0 .5.2.5.5 0 0 .2 2.3.2 6.2.4 0 .8 0 1.2.1.4 0 .9.1 1.4.2.6.1 1.2.2 1.9.4.3.1.6.2.9.2.6.2 1.2.4 1.9.6.3.1.6.3 1 .4.7.3 1.3.6 2 1s1.4.8 2.1 1.3c.3.2.5.4.8.6.8-.8 2.7-.5 4.4.7 1.8 1.3 2.7 3.2 2 4.1.6.5 1.3 1.1 2 1.6.4.3.8.7 1.3 1 .4.3.9.7 1.3 1l1.8 1.2c0-.1 0-.3.1-.4.4-1.1 2.5-1.3 4.5-.5 2.1.8 3.4 2.4 2.9 3.5-.1.2-.2.4-.4.5.3.1.7.2 1 .2.6.1 1.1.1 1.7.2h2c1.2-.1 2.2-.3 3.2-.6.2-.1.4-.1.6-.2l-.3-.3c-.6-1 .5-2.8 2.4-3.9 1.4-.8 3.1-1.1 4.3-.8l-.6-1.2c-1-.4-1.8-1-2.4-1.6-.7.1-1.4.4-2.1.7z" fill="url(#g)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M134.8 169.1c-3.6 0-10.7-2.3-15.5-4.8-7.7-4.1-13.4-16.9-14.8-26.9-1.7-12.1-5.1-22.4-8.1-25.1-1.3-1.1-2.5-1.7-3.5-1.9-2.6.9-4.7 2.6-6.1 5.1-2 3.5-2.8 10.4-3.7 17.7-1 8.3-2.1 16.9-4.9 21.5-5.7 9.4-11.9 13.8-20.6 14.8-1.1.1-2.1.2-2.9.2-2.8 0-4.2-.6-4.9-1.1.4 1.6 1.8 2.8 3.5 2.8h4.5c1.4-.1 3-.3 4.8-.8.5-.1.9-.3 1.4-.4.5-.2 1-.3 1.5-.5s1-.4 1.5-.7c
.5-.2 1-.5 1.6-.8 1.1-.6 2.1-1.3 3.2-2 .2-.2.5-.4.7-.6-.1 0-.1-.1-.2-.1-.9-.8-.3-2.8 1.3-4.4 1.6-1.6 3.5-2.2 4.4-1.3 0 0 .1.1.1.2.8-1 1.5-2 2.2-3.1.4-.6.8-1.3 1.1-1.9.7-1.3 1.4-2.7 2-4 .3-.7.6-1.4.8-2.1.4-1.1.8-2.2 1.1-3.3h-.7c-1.1-.4-1.4-2.4-.7-4.5.7-1.9 2-3.2 3.1-3.1l.1-.2.1-.4.2-.9c.3-1.1.5-2.2.8-3.2.3-1 .6-2 .9-2.9.3-.9.6-1.8.9-2.6.3-.8.6-1.5.9-2.2.2-.3.3-.6.5-.9.1-.3.3-.6.4-.9.5-.8.9-1.5 1.3-2.2.4.6.8 1.4 1.3 2.2.1.3.3.6.4.9.1.3.3.6.5.9.3.7.6 1.4.9 2.2.6 1.6 1.2 3.4 1.8 5.5.3 1 .6 2.1.8 3.2l.2.9.1.4.1.2V138.3l.4 2c.1.8.3 1.5.5 2.2l.6 2.1.6 2.1c.2.7.5 1.4.7 2.1.5 1.4 1.1 2.8 1.8 4.1.7 1.3 1.4 2.7 2.2 3.9.8 1.3 1.6 2.5 2.5 3.6.9 1.1 1.8 2.2 2.9 3.2.5.5 1 .9 1.5 1.4.5.4 1 .9 1.6 1.2.5.4 1.1.8 1.6 1.1.5.3 1.1.7 1.6 1 1.1.6 2.1 1.1 3.1 1.5.5.2 1 .4 1.5.5.5.2 1 .3 1.4.4 1.9.5 3.5.7 4.8.8h4.6c1.7 0 3.1-1.1 3.5-2.7h-.1c-.4.2-1 .3-1.7.3z" fill="url(#h)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M62.2 64.1c0 1.5-.3 3.3-1.1 5.3-.1.2-.2.5-.3.7 1.6 1.2 3.5 2.1 5.6 2.6 1.9.3
3.7.1 3.9.1-.7-1-1.4-2-2.1-3.1-2.4-1.4-4.5-3.3-6-5.6z" fill="url(#i)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M129.4 88.3c-1.2-.4-2.3-1.1-3.3-1.9-.6-.5-1.1-1.1-1.6-1.7-.2-.3-.5-.6-.7-.9l-.6-.9c-.2-.3-.4-.6-.5-.9-.1-.2-.2-.3-.2-.5-.1-.2-.1-.3-.2-.5-.1-.1-.2-.3-.2-.4-.1-.1-.1-.3-.2-.4-.1-.3-.3-.6-.4-.8-.1-.3-.3-.5-.4-.8-.1-.2-.2-.5-.4-.7-.1-.2-.2-.4-.3-.5-.1-1.1-.2-2.3-.2-3.5-1.2.2-2.3.3-2.8.3.1 2.1.3 4.3.9 5.8.7 1.7 3.6 7.6 11.1 8.3z" fill="url(#j)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M64.6 42.9c-.1-1.1-.2-2.1-.2-3.2C64.4 23.8 77.3 11 93.1 11c15.9 0 28.7 12.9 28.7 28.7v1.5c4.1 3.1 6.7 7.9 6.7 13.4 0 6.4-3.6 12-8.8 14.8-.7 1.2-1.5 2.4-2.3 3.5.6 0 1.7-.1 3-.3.7-.2 1.4-.4 2.1-.7.8-.4 1.6-.8 2.3-1.3 4.4-2.9 7.4-7.9 7.4-13.5 0-2.5-.6-4.9-1.6-7-1-2.1-2.5-4-4.3-5.5 0-.7.1-1.4.1-2.1 0-2.8-.3-5.4-1-8-.1-.2-.1-.4-.2-.6-1.5-5.7-4.5-10.8-8.6-14.8-1-1-2.1-2-3.2-2.8-1.1-.9-2.3-1.7-3.6-2.4-2.5-1.4-5.2-2.6-8-3.3-.2-.1-.4-.1-.6-.2-.6-.2-1.3-.3-1.9-.4-2-.4-4-
.6-6-.6-.7 0-1.4 0-2.1.1-2.1.1-4.2.5-6.2 1-6.9 1.8-12.9 5.7-17.3 11-.3.4-.7.8-1 1.3-.6.9-1.2 1.7-1.8 2.6-.6.9-1.1 1.9-1.5 2.8-.7 1.5-1.3 3-1.8 4.5-.3 1-.6 2.1-.8 3.2-.4 2.2-.7 4.4-.7 6.7 0 .7 0 1.4.1 2.1-.3.3-.7.6-1 .9-.6.6-1.2 1.3-1.7 2-.3.4-.5.7-.7 1.1-.6 1-1.1 2.1-1.5 3.2-.5 1.4-.8 2.9-.9 4.4l1.8.7c.9.4 1.4 1.4 1.6 2.8l3 1.2c-.7-1.8-1.1-3.8-1.1-5.9-.2-4.9 1.8-9.1 4.9-12.2z" fill="url(#k)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M70.7 106.4c-.2.1-.5.2-.7.3.2.1.3.2.4.4.1.3-.1.6-.4.7-.2 0-2.9.7-7.2.7-1 0-2.1 0-3.3-.1l1.9.7c.1 0 .2.1.3.2.2.4 1.1 2.5-4.2 7.8l-1.3 1.3c-5.2 5.2-13 13.1-21.1 13.8-.7.1-1.4.1-2 .1-5.2 0-10.7-1.5-14.3-2.7l.6 5.5c.3.1.5.2.8.3v-.1c.6-1 2.7-1 4.6.2 1.6.9 2.5 2.3 2.5 3.3.4.1.7.2 1.1.2 1 .2 2.1.3 3.2.3H33.4c.5 0 1-.1 1.5-.1h.2c-.1-.1-.2-.2-.2-.3-.4-1.1.9-2.7 2.9-3.5 2.1-.8 4.1-.6 4.5.5.2.5 0 1.1-.4 1.7l3-1.2c1.5-.7 2.9-1.4 4.2-2.2-.2-.1-.3-.2-.4-.4-.7-1 .2-2.8 2-4.1 1.8-1.3 3.8-1.6 4.5-.6.2.3.3.7.2 1.2 1.2-.8 2.3-1.6 3.4-2.3.8-.6 1.6-1.1 2.3-1
.6 1.5-1 2.9-2 4.2-2.7.6-.4 1.2-.7 1.8-1 .8-4.4 1-7.1 1-7.2 0-.3.3-.5.5-.5.1-.3.1-.6.2-.9.4-2.2 1.1-4.8 1.9-7.7z" fill="url(#l)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M153.8 118c.1 0 .2-.1.3-.1.9-.4 1.9-1.2 2.7-1.9-.9.5-1.8 1-2.8 1.4-.1.2-.1.4-.2.6z" fill="#FAFAFA" fill-rule="nonzero"/><path d="M131.2 182.5c.3.3 1.9 1.5 7.2.9 8.3-1 14.3-5.3 19.8-14.3 2.7-4.4 3.7-12.9 4.8-21.1.9-7.4 1.8-14.4 3.8-18.2 1.1-2 2.6-3.5 4.2-4.5-.5.2-.8.3-.8.3l-1.1.7 4-22.6c-.5-.6-1-1.2-1.4-1.8-2.8-4.2.3-9.3 4.1-13.4v-.3h.2c3.5-3.7 7.5-6.4 7.8-6.6l.2-.1 14.6 1.2-.1.6s-.2 2-.2 4.4h.2c.9-1.1 1.6-2.3 2.3-3.5 5.3-2.8 8.8-8.4 8.8-14.8 0-5.5-2.7-10.4-6.7-13.4v-1.5c0-15.9-12.9-28.7-28.7-28.7-15.9 0-28.7 12.9-28.7 28.7 0 1.1.1 2.2.2 3.2-3.1 3.1-5.1 7.3-5.1 12 0 2.1.4 4 1.1 5.9 1 .4 1.6 1.6 1.6 3.2 1.5 2.3 3.5 4.2 6 5.6.6 1.1 1.3 2.1 2.1 3.1.1 0 .3 0 .4.1.3-1.4.4-2.3.5-2.3l.1-.3.3-.1c.5-.2 13.4-5.6 18.2-1.2 2 1.8 2.3 5 .9 9.4-2.5 8-5.5 14.5-10 19 .1 0 .2.1.3.2.5.4.5 1.1.1 1.6-.1.2-3.7 4.2-6.9 5.
8-.7.4-1.4.7-2.1 1-.9 3.3-1.6 6.1-2 8.3-1.8 10-1.9 13.6-2.1 21 0 1.7-.1 3.7-.2 6-.4 12-3.6 18.7-9.9 21.2-.5.2-1.1.4-1.6.6-.6.2-1.1.4-1.6.6-.3.1-.5.2-.7.3-.4.2-.6.3-.5.3h-.2c-1.9.9-3.1 1.9-3.2 3.5zm63.3-112.3c0 .8-.6 1.4-1.4 1.4-.8 0-1.4-.6-1.4-1.4V67c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4v3.2zm-6.2-15c.1-.1 1.6-2.5 4.8-2.5 3.1 0 4.7 2.4 4.8 2.5.3.5.2 1.2-.3 1.5-.2.1-.4.2-.6.2-.4 0-.7-.2-.9-.5 0-.1-1-1.5-2.9-1.5s-2.9 1.4-2.9 1.5c-.3.5-1 .7-1.5.3-.7-.3-.8-1-.5-1.5zm-29 15c0 .8-.6 1.4-1.4 1.4-.8 0-1.4-.6-1.4-1.4V67c0-.8.6-1.4 1.4-1.4.8 0 1.4.6 1.4 1.4v3.2zm3-7c-.2.1-.4.2-.6.2-.4 0-.7-.2-.9-.5 0-.1-1-1.5-2.9-1.5s-2.9 1.4-2.9 1.5c-.3.5-1 .7-1.5.3-.5-.3-.7-1-.3-1.5.1-.1 1.6-2.5 4.8-2.5 3.2 0 4.7 2.4 4.8 2.5.2.5 0 1.2-.5 1.5z" fill="#FAFAFA" fill-rule="nonzero"/><path d="M138.7 177.3c6.3-2.5 9.5-9.2 9.9-21.2.1-2.3.1-4.2.2-6 .2-7.3.3-11 2.1-21 .4-2.2 1.1-5 2-8.3-.5.2-.9.4-1.3.5-.8 2.9-1.4 5.6-1.8 7.6-.1.3-.1.6-.2.9h.1c.3 0 .5.3.5.6 0 0-.2 3.5-1.3 8.9-.1.6-.2 1.1-.3 1.7-.2 1.4-.3 2.7-.4 4.1 0
.7-.1 1.4-.1 2.1v7.2c0 .5 0 1.1-.1 1.6-.1 1-.2 2.1-.3 3.1-.1.5-.1 1-.2 1.5s-.2 1-.3 1.4c-.2.9-.4 1.9-.7 2.7-.2.5-.3 1-.5 1.4-1.1 4.1-3 7-5.5 8.8-.4.4-.9.8-1.3 1.1-1 .7-1.9 1.3-2.7 1.8l-1.2.6c.5-.2 1.1-.4 1.6-.6.8-.1 1.3-.3 1.8-.5z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M76.9 50.6c-.8 0-1.4.6-1.4 1.4v3.2c0 .8.6 1.4 1.4 1.4.8 0 1.4-.6 1.4-1.4V52c0-.8-.6-1.4-1.4-1.4z" fill="url(#m)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M112.1 50.6c-.8 0-1.4.6-1.4 1.4v3.2c0 .8.6 1.4 1.4 1.4.8 0 1.4-.6 1.4-1.4V52c0-.8-.7-1.4-1.4-1.4z" fill="url(#n)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M107.6 41.7c.5.3 1.2.2 1.5-.3 0 0 1-1.5 2.9-1.5s2.8 1.4 2.9 1.5c.2.3.6.5.9.5.2 0 .4-.1.6-.2.5-.3.7-1 .3-1.5-.1-.1-1.6-2.5-4.8-2.5-3.1 0-4.7 2.4-4.8 2.5-.1.5 0 1.2.5 1.5z" fill="url(#o)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M76.9 44.2c-3.1 0-4.7 2.4-4.8 2.5-.3.5-.2 1.2.3 1.5.5.3 1.2.2 1.5-.3 0 0 1-1.5 2.9-1.5s2.8 1.4 2.9 1.5c.2.3.6.5.9.5.2 0 .4-.1.6-.2
.5-.3.7-1 .3-1.5.1-.1-1.5-2.5-4.6-2.5z" fill="url(#p)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M140.7 118.4c15.7.3 23.7-6.5 29.7-25.4 1.3-4 1.1-6.7-.6-8.2-3.9-3.6-14.8.6-16.7 1.3-.3 1.9-2.2 11.5-4.9 16.3-2.3 4.1-7.5 7.6-13.9 6.2-6.5-1.5-12.3-5.7-14.1-10.1 0 0 0 .1-.1.1-.2.6-.4 1.1-.6 1.7-.2.6-.5 1.1-.7 1.5-.3.5-.5.9-.8 1.2-.2.3-.4.5-.5.6 1 1.7 2.2 3.5 3.7 5.3 3.1 3.4 9.6 9.3 19.5 9.5z" fill="#FAFAFA" fill-rule="nonzero"/><path d="M120.3 98.4c1.9 4.4 7.6 8.7 14.1 10.1 6.4 1.4 11.6-2.1 13.9-6.2 2.7-4.8 4.5-14.4 4.9-16.3 1.9-.8 12.8-4.9 16.7-1.3 1.6 1.5 1.8 4.3.6 8.2-6 18.9-14 25.8-29.7 25.4-9.9-.2-16.4-6.1-19.4-9.5-1.5-1.7-2.7-3.5-3.7-5.3l-.1.1-.2.2-.1.1c-.2.1-.4.3-.6.4.5.9 1.1 1.8 1.7 2.7 1.1-.1 2.5 1.1 3.2 3 .2.4.3.9.4 1.3 3.6 3.5 9.8 8 18.7 8.2h1.1c4.2 0 7.8-.6 10.9-1.7-.1.3-.2.5-.2.8.4-.2.9-.4 1.3-.6.1-.2.1-.4.2-.6 1-.4 1.9-.9 2.8-1.4 1.9-1.6 3.4-3.4 3.5-3.4.3-.4.8-.5 1.3-.3 4.5-4.5 7.4-11 10-19 1.4-4.4 1.1-7.6-.9-9.4-4.8-4.4-17.7 1-18.2 1.2l-.3.1-.1.3s-.2.9-.5
2.3c.1.1.2.2.2.4 0 .3-.2.5-.4.6-.8 3.7-2.3 9.7-4.1 13-.3.6-.8 1.3-1.4 1.9 0 .2-.1.4-.1.6-.8.8-1.7 1.4-2.8 2-.3.2-.6.3-.9.5-.3.1-.6.3-1 .4-.3.1-.7.2-1 .3-.4.1-.7.2-1.1.3h.2H136.1c-.5 0-1.1 0-1.6-.1-1.1-.1-2.3-.4-3.4-.8-.4-.1-.7-.3-1.1-.4-.4-.2-.7-.3-1-.5-.3-.2-.7-.4-1-.6-.3-.2-.6-.4-1-.6-.3-.2-.6-.4-.9-.7-1.2-.9-2.2-2-3-3-.6-.8-1.1-1.6-1.5-2.4-.1-.3-.3-.5-.4-.8-.1-.3-.2-.5-.3-.8h-.2c0 .1-.1.1-.1.2-.1.7-.2.9-.3 1.1z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M174 104.9l-3.4 19.5c.5-.2 1.2-.3 2-.3 1.5 0 3.4.5 5.5 2.3 3.8 3.4 7 15.4 8.5 25.8 1.6 11.5 7.8 22.7 14.2 26.1 6.5 3.4 14.5 5.4 16.3 4.5.1 0 .1-.1.2-.1.3-1.7-.2-2.2-6.5-6.4-5.7-3.9-10.7-7.2-11.1-25.4-.1-3.3-.1-6.6-.1-9.8 0-8.9 0-17.1-1.5-24.9-.4-.2-.8-.4-1.1-.6-9.5-1.9-18.1-5.9-23-10.7z" fill="#FAFAFA" fill-rule="nonzero"/><path d="M198 116.2c1.5 7.8 1.5 15.9 1.5 24.9 0 3.2 0 6.4.1 9.8.4 18.2 5.3 21.5 11.1 25.4 6.3 4.2 6.8 4.7 6.5 6.4 0 0-.1.1-.2.1-1.7.9-9.7-1.1-16.3-4.5-6.5-3.4-12.6-14.6-14.2-26.1-1.5-10.4-4.7-22.4-8.5-25.8-2-
1.8-4-2.3-5.5-2.3-.8 0-1.5.1-2 .3l3.4-19.5c4.9 4.9 13.5 8.9 22.9 10.8-1.8-.9-2.9-1.7-3-1.8 0 0 0-.1-.1-.1-9.5-2.5-17.7-7.1-21.2-12.4-4.6-6.9 10-17.4 11.7-18.6l13.1 1.1c-.1 1.9-.5 8 .8 11.3.9 2.4 4.9 10.1 15.3 9.2 9.7-.8 12.1-9.5 13.2-17.9.1-1.2.3-2.2.4-3.2.8-6.3 1-8.4 3.6-14.2l.3-.6c-.4.7-.9 1.4-1.3 2.2-1.6 3.1-2.8 6.8-3.2 10.7-.1.5-.1 1-.1 1.6v3.5c-.1 1.4-.3 2.7-.5 4.1-.4 2.6-1.2 5.1-2.3 7.1-.5 1-1.1 1.9-1.7 2.6-.6.7-1.3 1.3-1.9 1.8-.7.5-1.3.8-2 1.1-.7.3-1.4.5-2.1.6-.6.1-1.2.2-1.8.2h-.4c-.7 0-1.5-.1-2.2-.3-.3-.1-.5-.2-.8-.3-7.4-.7-10.4-6.5-11.2-8.5-.6-1.5-.8-3.7-.9-5.8h-.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h.3c0-2.4.2-4.4.2-4.4l.1-.6-14.6-1.2-.2.1c-.3.2-4.3 2.9-7.8 6.6h-.2v.3c-3.8 4-6.9 9.1-4.1 13.4.4.6.9 1.2 1.4 1.8l-4 22.6 1.1-.7s.3-.2.8-.3c-1.6 1-3.1 2.4-4.2 4.5-2.1 3.7-2.9 10.7-3.8 18.2-1 8.2-2 16.6-4.8 21.1-5.5 9.1-11.4 13.3-19.8 14.3-5.2.6-6.8-.5-7.2-.9.1-1.7 1.3-2.7 2.9-3.5-1.9.1-3.5 1.7-3.5 3.7 0 .3 0 .6.1.9.7.5 2.1 1.1 4.9 1.1.8 0 1.8-.1 2.9-.2 8.7-1 14.9-5.5 20.6-14.8 2.8-4
.7 3.9-13.2 4.9-21.5.9-7.3 1.7-14.2 3.7-17.7 1.4-2.5 3.4-4.2 6.1-5.1 1 .2 2.2.8 3.5 1.9 3 2.7 6.4 13 8.1 25.1 1.4 10 7.1 22.9 14.8 26.9 4.8 2.5 11.9 4.8 15.5 4.8.7 0 1.3-.1 1.8-.3h.1c.1-.3.2-.7.2-1 .1-.5.1-1 0-1.4-.3-1.1-1.6-2.1-4.6-4.2-.6-.4-1.3-.9-2.1-1.4-2.5-1.7-4.7-3.3-6.5-5.7-1.1-1.5-2-3.3-2.7-5.7-.4-1.2-.7-2.5-.9-4-.4-2.6-.7-5.7-.8-9.5v-1.5c0-1.3 0-2.7-.1-4.1v-9.4c-.1-3.8-.2-6.1-.2-6.1 0-.3.2-.6.5-.6h.1c-.2-4.2-.5-8.3-1.2-12.3-.7-.5-1.1-.7-1.5-.9z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M227 83.3c-.1 1-.2 2-.4 3.2-1.1 8.4-3.4 17.1-13.2 17.9-10.4.9-14.3-6.8-15.3-9.2-1.3-3.3-1-9.4-.8-11.3l-13.1-1.1c-1.7 1.2-16.3 11.6-11.7 18.6 3.5 5.3 11.7 9.9 21.2 12.4-.4-.4-.5-1-.2-1.5.4-.5 1.1-.6 1.6-.3 0 0 2.6 1.8 6.6 3.3 1.5.2 3 .3 4.5.4 12.5.6 21.4-3.3 27.1-11.9 4.1-6.2 4.1-17.7 4.1-23.3v-1.3c0-5.5.9-8.2 4.6-14.5 1.4-2.3 3.4-4 5.4-5.3l-1.3-3.9c-.3.2-.6.3-1 .5-1.1.6-2.4 1.3-3.8 2.2l-.1.1c-2.3 1.6-4.6 3.5-6.5 5.4-.8.8-1.5 1.6-2.2 2.6-.5.7-1 1.3-1.5 2.1l-.3.6c-2.7 5.8-3 8-3.7 14.3z" fil
l="#FAFAFA" fill-rule="nonzero"/><path d="M241.9 64.8c-3.7 6.3-4.6 9-4.6 14.5v1.3c0 5.5.1 17-4.1 23.3-5.8 8.6-14.6 12.5-27.1 11.9-1.5-.1-3-.2-4.5-.4 1.6.6 3.5 1.2 5.5 1.5h1.5c11.6 0 20-4.1 25.6-12.5 4.3-6.5 4.3-17.8 4.2-23.9v-1.3c0-5.2.8-7.8 4.4-13.9 1.2-2 3-3.6 4.8-4.8l-.4-1.1c-1.9 1.4-3.9 3.1-5.3 5.4zM235.3 63c-.3.2-.5.5-.8.8 1.9-1.9 4.2-3.7 6.5-5.4-1.7 1.2-3.7 2.7-5.7 4.6z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M127.4 108s11.6 13.5 16.4 17.9c4.9 4.5 12 8.2 19.1 5.2.7-.3 1.4-.6 2-.8-.5-.5-.9-1.1-1.1-1.8-.1-.4-.2-.9-.2-1.3h-.4c-.2 0-.4 0-.6-.1-.2 0-.3 0-.5-.1-.2 0-.4-.1-.6-.1-.2 0-.3-.1-.5-.1s-.4-.1-.6-.1c-.2 0-.4-.1-.5-.1-.2-.1-.4-.1-.7-.2-.2-.1-.4-.1-.6-.2-.2-.1-.4-.2-.7-.2-.2-.1-.4-.1-.6-.2-.2-.1-.4-.2-.7-.3l-.6-.3c-.2-.1-.5-.2-.7-.4l-.6-.3c-.2-.1-.5-.3-.7-.4-.2-.1-.4-.2-.6-.4-.2-.2-.5-.3-.7-.5-.2-.1-.4-.3-.6-.4-.2-.2-.5-.4-.7-.6-.2-.2-.4-.3-.5-.5l-.7-.7-.5-.5c-.3-.3-.5-.6-.8-.9-.1-.2-.3-.3-.4-.5-.4-.5-.8-1-1.2-1.6-.4-.5-.7-1-1-1.5-.1-.1-.2-.2-.2-.3-.3-.5-.7-.9-1-1.3v-.1c
-.3-.4-.6-.8-.9-1.1-.1-.1-.1-.2-.2-.2-.3-.3-.6-.7-.9-1l-.1-.1-.8-.8-.2-.2c-.3-.3-.5-.5-.8-.7-.1 0-.1-.1-.2-.1-.2-.2-.4-.3-.6-.5-.1-.1-.2-.1-.2-.2-.2-.2-.4-.3-.6-.4-.1-.1-.2-.1-.3-.2-.1-.1-.2-.1-.3-.2-.1-.1-.2-.1-.3-.2-.3-.2-.5-.3-.7-.4-.9-.5-1.5-.6-1.5-.6l-9.1.6z" fill="url(#q)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M116 146c7.7-.7 15.4-8.4 20.4-13.5l1.3-1.3c3.9-3.9 4.1-5.8 4-6.3l-5.4-2c-2.1 2.3-3.9 4.5-5.6 6.4-6.1 7-10.5 12.1-15.1 13.6-4.4 1.4-9.5-.3-13-1.4-.5-.2-1-.3-1.5-.5-.1.3-.2.7-.4 1-.3.5-.6.9-1 1.3 4 1.4 10.7 3.2 16.3 2.7z" fill="#FAFAFA" fill-rule="nonzero"/><path d="M116.1 147.1c8.1-.7 16-8.6 21.1-13.8l1.3-1.3c5.3-5.3 4.4-7.4 4.2-7.8-.1-.1-.2-.2-.3-.2l-1.9-.7c-1.6-.1-3.4-.3-5.2-.7-1.9 2.2-3.7 4.2-5.3 6.1-3.9 4.5-7.1 8.2-10 10.6-.2.2-.5.4-.7.6-1.2 1-2.5 1.9-3.7 2.6-1.1.4-2.3.5-3.5.5-4 0-8.1-1.7-10.6-2.4 0 .2-.1.4-.1.5.5.1.9.3 1.5.5 3.4 1.1 8.6 2.9 13 1.4 4.6-1.5 9-6.6 15.1-13.6 1.7-1.9 3.6-4.1 5.6-6.4l5.4 2c0 .5-.2 2.4-4 6.3l-1.3 1.3c-5.1 5.1-12.7 12.8-
20.4 13.5-5.6.5-12.3-1.4-16.2-2.6l-.2.2.1 1c3.5 1.2 9.1 2.7 14.3 2.7.4-.2 1.1-.2 1.8-.3z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M171.5 131.5c.1.2.3.4.5.6.4.3.8.5 1.3.7.3-.5.6-1 .7-1.6-.8.2-1.6.3-2.5.3z" fill="url(#r)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M149.4 116.1c-3-4.4-5.7-7.1-7.8-8.7.9-.2 1.8-.6 2.8-1 2.1-.9 4.1-2 5.8-3.4-1.5.9-3.1.9-3.7.1-.1-.1-.1-.2-.1-.3-.9.5-1.9 1-2.9 1.4-1.1.5-2.3.9-3.5 1.2-.3.1-.7.1-1.1.2-3.7.5-7.7-.1-7.7-.2-.3-.1-.6.2-.6.5-.1.3.2.6.5.6.1 0 2.2.4 4.8.4h1.3c.3.3.7.5 1 .8.2.1.5.2.7.4.1.1.2.1.3.2.1.1.2.1.3.2.1.1.2.1.3.2.2.1.4.3.6.4.1.1.2.1.2.2.2.1.4.3.6.5.1 0 .1.1.2.1.2.2.5.5.8.7l.2.2c.3.2.5.5.8.8l.1.1c.3.3.6.6.9 1 .1.1.1.2.2.2.3.4.6.7.9 1.1v.1c.3.4.7.8 1 1.3.1.1.2.2.2.3.3.5.7 1 1 1.5.4.6.8 1.1 1.2 1.6.1.2.3.3.4.5.3.3.5.7.8.9l.5.5c.2.3.5.5.7.7.2.2.4.3.5.5.2.2.5.4.7.6.2.2.4.3.6.4.2.2.5.4.7.5.2.1.4.3.6.4.2.2.5.3.7.4l.6.3c.2.1.5.2.7.4l.6.3c.2.1.4.2.7.3.2.1.4.2.6.2.2.1.4.2.7.2.2.1.4.1.6.2.2.1.4.1.7.2.2 0 .4.1.5.1.2.1.4.1.6.1.2 0 .4.
1.5.1.2 0 .4.1.6.1.2 0 .3.1.5.1s.4 0 .6.1h.4c0 .4 0 .9.2 1.3.2.7.6 1.3 1.1 1.8.6.6 1.4 1.1 2.4 1.6.6.2 1.2.5 1.9.6h.1c.2 0 .5-.2.5-.4.1-.3-.1-.6-.4-.7-.1 0-.2-.1-.3-.1-2.4-.7-3.8-1.8-4.2-3.2-.7-2.5 1.8-5.4 1.9-5.4.1-.1.2-.3.1-.5 0-.1-.1-.2-.2-.3-.2-.2-.6-.2-.8 0 0 0-.3.3-.6.7-.4.5-.9 1.3-1.2 2.2-4.5.3-10.1-1.3-14.9-8.4z" fill="url(#s)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M31.3 79.8v1.6c0 .9.1 1.8.2 2.7 0-.3.1-.6.2-1 .1-.3.1-.6.2-.9.1-.3.2-.7.3-1 .1-.2.1-.4.2-.6.7.5 1.6.9 2.8 1.3 1.3.4 2.7.7 4.1.7H39.9c.1.3.2.5.3.8.1.3.3.5.4.8.4.8.9 1.6 1.5 2.4.8 1.1 1.8 2.1 3 3 .3.2.6.5.9.7.3.2.6.4 1 .6.3.2.7.4 1 .6.3.2.7.3 1 .5.4.2.7.3 1.1.4 1.1.4 2.2.6 3.4.8.5.1 1.1.1 1.6.1h3.1-.2c.4-.1.7-.2 1.1-.3.4-.1.7-.2 1-.3.3-.1.7-.3 1-.4.3-.1.6-.3.9-.5 1-.6 2-1.3 2.8-2 0-.2.1-.4.1-.6.8-4.3 1.3-9.2 1.5-15 .8.1 1.6.1 2.3.1.9 0 1.6-.1 1.7-.1h.1c.3-.1.4-.3.4-.6 0-.2-.1-.3-.2-.4-.1-.1-.3-.1-.4-.1-.1 0-2 .2-3.9-.1-2-.5-3.9-1.4-5.6-2.6.1-.2.2-.5.3-.7.8-1.9 1.1-3.8 1.1-5.3-.1-1.6-.6-2.8-1.6-3
.2l-3-1.2c.1.4.1.8.1 1.2l2.5 1c1.1.5 1.4 3.5-.1 7.1-1.5 3.6-3.7 5.6-4.9 5.1l-2.5-1c-.3.3-.6.6-.9.8l3 1.2c.2.1.5.1.8.1.9 0 1.9-.6 2.9-1.6.4-.5.9-1 1.3-1.6 1.4.9 2.8 1.7 4.4 2.3-.2 5.3-.7 9.9-1.4 13.9-.5.5-1.1.9-1.8 1.2-.4.2-.9.5-1.6.7-.5.2-1.1.3-1.8.5h-.8H55.1c-.5 0-.9 0-1.3-.1-1.3-.1-2.6-.5-3.8-1l-1.8-.9c-.5-.3-1-.7-1.6-1.1-1-.8-1.9-1.7-2.6-2.6-.7-.9-1.2-1.8-1.7-2.8-.1-.2-.1-.3-.2-.5h.1c.8-.5 1.3-1.2 1.8-2.1.4-.7.7-1.6.8-2.7 0-.2 0-.3-.1-.5-.1-.1-.2-.2-.3-.2-.3-.1-.6.2-.6.5 0 .1-.1.3-.1.4-.4 1.8-1 3-2 3.6-1.3.8-3.1.8-6.1-.1-5.7-1.7-4.6-6-4.5-6.2.1-.2 0-.5-.2-.6-.1 0-.1-.1-.2-.1-.3-.1-.6.1-.7.4 0 0-.2.9-.1 2.1.1 1 .5 2.2 1.6 3.3-.2 0-.2.1-.2.1z" fill="url(#t)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M157.7 138.9c-.4 0-.8.1-1.2.1h-.8c-.5 0-1.1-.1-1.7-.2-.3-.1-.7-.1-1-.2-.8.6-2.4.7-4.1 0-1.8-.7-3.1-2.1-3-3.1l-1.8-1.2c-.5-.3-.9-.7-1.3-1-.4-.3-.9-.7-1.3-1-.7-.5-1.3-1.1-2-1.6-.6.8-2.2.7-3.8-.2.7.5 1.4 1.1 2.1 1.7.7.6 1.5 1.2 2.3 1.9 1.7 1.4 3.6 2.8 5.8 4.1 1.8 1.1 4.6 2
.5 7.8 3 1 .1 1.9.2 2.8.2.5 0 .9 0 1.4-.1 1.3-.1 2.5-.3 3.7-.7 2.2-.6 3.8-1.5 5.2-2.3 1.3-.8 2.3-1.6 3.2-2.2.1-.1.3-.2.4-.3-.3-.2-.6-.4-.8-.6-.2-.2-.4-.4-.6-.5-.2 1-1.6 2.3-3.1 3.2-1.7 1-3.5 1.2-4.3.4-.2.1-.4.1-.6.2-1 .1-2.1.3-3.3.4z" fill="url(#u)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M31.5 141.4h.9c.9 0 1.8 0 2.8-.1 1.4-.2 2.6-.4 3.7-.6 2.3-.5 4.6-1.4 7-2.5 1.9-.9 4-2 6.2-3.3 2.9-1.7 5.5-3.6 7.9-5.2.8-.6 1.6-1.1 2.4-1.7 1.1-.8 2.1-1.4 3-2-.2 1.3-.3 2.6-.3 3.9-.1 1.4-.1 2.8-.1 4.3V139.6c0 .4 0 .8-.1 1.2-.1 1.1-.2 2.1-.3 3-.1 1-.3 1.9-.4 2.7-.2 1-.4 1.8-.6 2.6-.2.8-.5 1.6-.8 2.3-.3.8-.7 1.5-.9 2.1-.3.6-.7 1.2-1.1 1.8-.4.6-.8 1.1-1.2 1.6-.5.6-.9 1-1.3 1.3-.4.4-.9.8-1.3 1.1-.8.6-1.6 1.1-2.4 1.6-.7.4-1.3.7-1.7.8l-.2.1c-3 .3-5.3 2.8-5.3 5.9 0 3.2 2.6 5.9 5.8 5.9h.1c.5.1 1.5.2 3 .2h1.6c1.8-.1 3.6-.4 5.3-.9 1.1-.3 2.1-.6 3.2-1.1 1.2-.5 2.4-1 3.4-1.6 1.2-.7 2.3-1.4 3.4-2.2 1.1-.9 2.3-1.8 3.3-2.8 1-1 2-2.1 3-3.4 1-1.2 1.9-2.5 2.7-3.8 1.6-2.6 3-5.5 4.1-8.4.5-1.4 1-2.9 1
.4-4.4.2-.6.3-1.2.5-1.7l.1-.5.1-.4c.1-.6.3-1.2.4-1.9l.4-2v-.2V138.2l.1-.4.2-.8c.2-1 .5-2.1.8-3.2.5-2 1.1-3.8 1.7-5.3.3-.8.6-1.5.9-2.1 0-.1.1-.2.1-.3.1.1.1.2.2.3.2.5.5 1.2.9 2.1.6 1.5 1.2 3.2 1.7 5.2.3 1 .6 2.1.8 3.2l.2.8.1.4v.5l.4 2c.1.7.3 1.3.4 1.9l.1.4.1.5c.1.6.3 1.2.5 1.8.4 1.5.9 3 1.4 4.4 1.1 2.9 2.5 5.8 4.1 8.4.8 1.3 1.7 2.6 2.7 3.8 1 1.3 2 2.4 3 3.4s2.2 2 3.3 2.8c1.1.8 2.2 1.5 3.4 2.2 1 .6 2.1 1.1 3.4 1.6 1 .4 2.1.8 3.2 1.1 1.7.5 3.5.8 5.3.9.5 0 1.1.1 1.6.1 1.5 0 2.5-.1 3-.2h.1c3.1 0 5.7-2.6 5.8-5.7.5-3.5-1.5-4.8-7.7-9-5.5-3.7-9.5-6.4-9.8-23.1v-1.5c0-1.4 0-2.8-.1-4.2v-4-3c.9.1 1.9.3 2.8.5 1.2.3 2.3.7 3.3 1.2.6.3 1.2.6 1.9.9.7.4 1.3.8 1.9 1.2.9.6 1.8 1.3 2.9 2.1-1.1-1.2-1.5-2.5-1-3.2l.1-.1c-.3-.2-.5-.4-.8-.6-.7-.5-1.4-.9-2.1-1.3-.7-.4-1.3-.7-2-1-.3-.2-.6-.3-1-.4-.6-.3-1.3-.5-1.9-.6-.3-.1-.6-.2-.9-.2-.7-.2-1.3-.3-1.9-.4-.5-.1-.9-.1-1.4-.2-.4 0-.8-.1-1.2-.1-.1-3.9-.2-6.2-.2-6.2 0-.3-.2-.5-.5-.5h-.1c-.3 0-.5.3-.5.6 0 0 .2 2.3.2 6.1v9.4c.1 1.4.1 2.8.1 4.1v1.5c.1 3.8.4 6.9.8 9.5.2 1
.5.6 2.8.9 4 .7 2.4 1.6 4.2 2.7 5.7 1.7 2.4 3.9 4 6.5 5.7.8.5 1.5 1 2.1 1.4 3.1 2.1 4.3 3.1 4.6 4.2.1.4.1.9 0 1.4 0 .4-.1.7-.2 1-.4 1.5-1.8 2.7-3.5 2.7h-.1H132h-.5H128.1c-1.4-.1-3-.3-4.8-.8-.5-.1-.9-.3-1.4-.4-.5-.2-1-.3-1.5-.5-1-.4-2.1-.9-3.1-1.5-.5-.3-1.1-.6-1.6-1-.5-.3-1.1-.7-1.6-1.1-.5-.4-1-.8-1.6-1.2-.5-.4-1-.9-1.5-1.4-1-1-1.9-2-2.9-3.2-.9-1.1-1.8-2.3-2.5-3.6-.8-1.3-1.5-2.6-2.2-3.9-.7-1.3-1.2-2.7-1.8-4.1-.3-.7-.5-1.4-.7-2.1l-.6-2.1-.6-2.1c-.2-.7-.3-1.4-.5-2.2l-.4-2v-.2-.1l-.1-.2-.1-.4-.2-.9c-.3-1.1-.5-2.2-.8-3.2-.6-2.1-1.2-3.9-1.8-5.5-.3-.8-.6-1.5-.9-2.2-.2-.3-.3-.6-.5-.9-.1-.3-.3-.6-.4-.9-.5-.8-.9-1.5-1.3-2.2-.4.6-.8 1.4-1.3 2.2-.1.3-.3.6-.4.9-.1.3-.3.6-.5.9-.3.7-.6 1.4-.9 2.2-.3.8-.6 1.6-.9 2.6-.3.9-.6 1.9-.9 2.9-.3 1-.6 2.1-.8 3.2l-.2.9-.1.4-.1.2h.3c1.1.4 1.4 2.4.7 4.5-.6 1.7-1.7 2.9-2.7 3.1-.3 1.1-.7 2.2-1.1 3.3-.3.7-.5 1.4-.8 2.1-.6 1.4-1.2 2.7-2 4-.4.7-.7 1.3-1.1 1.9-.7 1.1-1.4 2.1-2.2 3.1.7.9.1 2.7-1.4 4.2s-3.3 2.1-4.2 1.5c-.2.2-.5.4-.7.6-1.1.8-2.1 1.5-3.2 2-.5.3-1.1.6-1.
6.8-.5.2-1 .5-1.5.7-.5.2-1 .4-1.5.5-.5.2-1 .3-1.4.4-1.9.5-3.5.7-4.8.8H54.1h-1-.2c-1.7 0-3.1-1.2-3.5-2.8-.1-.3-.1-.6-.1-.9 0-2 1.5-3.6 3.5-3.7h.2c-.1 0 .1-.1.5-.3.2-.1.4-.2.7-.3.3-.2.7-.4 1.2-.6.8-.4 1.7-1 2.7-1.8.4-.3.9-.7 1.3-1.1.1-.1.1-.1.2-.1.5-.5 1-1 1.4-1.5.5-.5.9-1.1 1.3-1.8.4-.6.8-1.3 1.2-2 .4-.7.7-1.5 1-2.3.1-.3.2-.7.4-1.1.2-.5.3-.9.5-1.4.3-.9.5-1.8.7-2.7.1-.5.2-.9.3-1.4.1-.5.1-1 .2-1.5.1-1 .2-2 .3-3.1 0-.5.1-1 .1-1.6V136.2v.1-1.8-2.1c0-.7 0-1.4.1-2.1.1-1.3.2-2.7.4-4.1.1-.6.2-1.1.3-1.7 1.1-5.4 1.3-8.9 1.3-8.9 0-.3-.2-.6-.5-.6h-.1c-.3 0-.5.2-.5.5 0 0-.2 2.8-1 7.2-.6.3-1.1.6-1.8 1-1.3.8-2.7 1.7-4.2 2.7-.8.5-1.5 1-2.3 1.6-1.1.7-2.2 1.5-3.4 2.3-.2.9-1 2.1-2.2 2.9-1.5 1.1-3.2 1.5-4.1 1-1.4.8-2.8 1.5-4.2 2.2-1 .4-2 .9-3 1.2-.5.7-1.4 1.4-2.5 1.8-1.8.7-3.6.6-4.3-.2h-.2c-.5 0-1 .1-1.5.1h-1.8c-1.1 0-2.2-.2-3.2-.3-.4-.1-.7-.2-1.1-.2 0 .2 0 .4-.2.6-.2.4-.7.6-1.4.7-1.3-2.1-3.3-3.8-5.6-4.7-.3-.1-.5-.2-.8-.3l-.6-5.5-.1-1 .2-.2c.4-.4.7-.8 1-1.3.2-.3.3-.6.4-1 .1-.2.1-.4.1-.5 2.5.8 6.6 2.4 10
.6 2.4 1.2 0 2.4-.2 3.5-.5 1.2-.7 2.5-1.6 3.7-2.6.2-.2.5-.4.7-.6 1-.9 2-1.8 3-2.9.6-.6 1.2-1.3 1.8-2l1.8-2.1c.6-.7 1.2-1.4 1.8-2.2.6-.7 1.2-1.5 1.9-2.2 1.3-1.5 2.5-2.9 3.9-4.3.3-.4.7-.7 1.1-1.1 1.9.4 3.6.6 5.2.7 1.2.1 2.3.1 3.3.1 4.3 0 7-.7 7.2-.7.3-.1.5-.4.4-.7-.1-.2-.2-.3-.4-.4h-.3s-2 .5-5.3.6c-2.4.1-5.6 0-9.2-.6l.1-.1c-.1 0-.2 0-.3-.1l-1-.2c-.7-.2-1.3-.4-2-.6-.7-.2-1.3-.5-1.9-.7l-1.8-.9c-1.8-.9-3.4-2-4.9-3.2-.8-.7-1.6-1.4-2.3-2.1-.2.4-.4.6-.7.8-1.1.5-2.7-.8-3.5-2.9-.6-1.6-.7-3.1-.1-4-.4-.8-.8-1.7-1.1-2.5-.1-.2-.2-.5-.2-.7-.1 0-.2.1-.3.1-.8.1-1.7-.1-2.3-.6.2.7.4 1.4.7 2 .8 2 1.9 4 3.2 5.9.8 1.1 1.6 2.1 2.4 2.9.8.9 1.8 1.8 2.9 2.7 2.2 1.8 4.6 3.3 7.3 4.4.6.3 1.2.5 1.9.7-1 1.1-2.1 2.3-3.4 3.8-.7.8-1.3 1.5-1.9 2.3-1.8 2.2-3.6 4.2-5.4 6.1-1.3 1.4-2.4 2.5-3.5 3.4-1.1.9-2.1 1.7-3.2 2.3-.8.2-1.7.4-2.6.4-2.9 0-6-1.1-8.4-1.8-.9-.3-1.7-.6-2.3-.7 0-.1 0-.3-.1-.4-.1-.3-.4-.4-.7-.4-.1 0-.1.1-.2.1-.2.1-.2.4-.2.6.4 1.2.3 2.3-.3 3.4-1 1.7-3.2 2.9-4.9 3.3-2.5.6-4.4.3-5.6-.7-1.5-1.2-1.4-3.3-1.4-3.3
0-.3-.2-.5-.4-.5h-.2c-.3 0-.6.2-.6.5 0 .1-.1 2.6 1.8 4.2.6.5 1.4.9 2.3 1.1l.5 4.8c-1.3.7-2.5 1.7-3.4 2.8-1.9 2.4-2.8 5.4-2.5 8.4.5 4.6 3.6 8.4 8 9.8.2.1.3.1.5.1h.2c.4 0 .8-.3 1.1-.6.3-.3.4-.8.4-1.2v-.2l-.8-7.7c0-.2.1-.3.1-.3 0-.1.1-.1.3-.2l2-.2.8-.1.8-.1c.3 0 .5.2.5.4l.8 7.9c.1.8.8 1.5 1.6 1.5h.2c.2 0 .4-.1.6-.2.4-.2.9-.5 1.3-.9.8-.6 1.4-1.2 2-1.9 1.9-2.4 2.8-5.4 2.5-8.4L27 143c-.2-.9-.5-1.7-.9-2.4 1.8.5 3.6.8 5.4.8zm-5.2 3.6c.3 2.9-.6 5.6-2.3 7.6-.5.6-1.1 1.2-1.8 1.7l-.8-7.7c0-.4-.2-.8-.5-1-.3-.2-.6-.4-1-.4h-.2l-3.6.4-2 .2c-.4 0-.8.3-1 .6-.3.3-.4.7-.3 1.1l.8 7.7c-3.2-1.5-5.5-4.6-5.9-8.3-.3-2.9.6-5.6 2.3-7.6 1-1.2 2.3-2.2 3.7-2.9l-.6-5.3c.4-.1.7-.1 1.1-.2 1.1-.2 2.4-.8 3.5-1.5l.7 6.5c4.2 1 7.5 4.5 7.9 9.1z" fill="url(#v)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M114.1 97.1c-.5-.4-1.2-.2-1.6.3-.3.5-.2 1.1.2 1.5 0 0 0 .1.1.1.1.1 1.2.9 3 1.8.3.2.7.4 1.1.6l1.2.6c3.3 1.4 7.9 2.9 13.2 2.9 1.5 0 2.9-.1 4.5-.4.6-.1 1-.7.9-1.3-.1-.6-.7-1-1.3-.9-3.3.5-6.5.3-9.4-.2-2-.4-3.9
-.9-5.5-1.5-3.8-1.7-6.3-3.5-6.4-3.5z" fill="url(#w)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M24.8 135.4c-1.9-1.1-4-1.2-4.6-.2v.1c2.4.9 4.3 2.6 5.6 4.7.6-.1 1.1-.3 1.4-.7.1-.2.1-.4.2-.6-.1-1.1-1.1-2.4-2.6-3.3z" fill="url(#x)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M148.5 99.1c-1.6 1.2-2.5 2.9-2.1 3.9 0 .1.1.2.1.3.6.8 2.2.7 3.7-.1.3-.2.5-.3.8-.5.5-.4.9-.8 1.2-1.2.9-1.1 1.2-2.3.7-3-.1-.2-.3-.3-.5-.4-.8-.5-2.4-.1-3.9 1z" fill="url(#y)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M42.4 135.7c-.4-1.1-2.5-1.3-4.5-.5-2.1.8-3.4 2.4-2.9 3.5.1.1.1.2.2.3.7.8 2.5.9 4.3.2 1.1-.5 2-1.1 2.5-1.8.4-.6.6-1.2.4-1.7z" fill="url(#z)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M55.3 128.9c-.7-1-2.7-.7-4.5.6-1.8 1.3-2.7 3.2-2 4.1.1.2.3.3.4.4.9.5 2.6.1 4.1-1 1.2-.9 2-2 2.2-2.9.1-.5 0-.9-.2-1.2z" fill="url(#A)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M157.7 80.4c-.6 2.1-.1 4.1 1.1 4.4.3.1.5 0 .8-.1 1-.3 1.9-1.6 2.4-3.3.
6-2.1.1-4.1-1.1-4.4-1.2-.2-2.6 1.3-3.2 3.4z" fill="url(#B)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M41 96.3c-.1-.4-.2-.9-.4-1.3-.8-1.9-2.1-3.1-3.2-3-.1 0-.2 0-.3.1-.3.1-.5.3-.6.6-.5.9-.5 2.4.1 4 .8 2.1 2.4 3.4 3.5 2.9.3-.1.6-.4.7-.8.4-.7.4-1.6.2-2.5z" fill="url(#C)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M164.5 52.7c.2.2.6.4.9.4.9.1 2.1-.4 3.2-1.4v-.1l-1.4-4.3c-.4.3-.9.6-1.3 1-1.6 1.5-2.2 3.5-1.4 4.4z" fill="url(#D)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M84 141c-.7 2.1-.4 4.1.7 4.5.2.1.4.1.7 0 1-.2 2.1-1.4 2.7-3.1.7-2.1.4-4.1-.7-4.5h-.3c-1.1-.1-2.4 1.2-3.1 3.1z" fill="url(#E)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M73.7 161.2c-1.6 1.6-2.1 3.5-1.3 4.4 0 0 .1.1.2.1.9.6 2.7 0 4.2-1.5s2.1-3.3 1.4-4.2c0-.1-.1-.1-.1-.2-.9-.8-2.9-.2-4.4 1.4z" fill="url(#F)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M139.6 130.5c.8-1-.1-2.9-1.9-4.2-1.7-1.2-3.6-1.5-4.4-.7l-.1.1c-.6.8-.1 2.1 1 3.2.3.3.6.6 1 .9.
2.2.5.3.7.5 1.4.9 3 1 3.7.2z" fill="url(#G)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M149 138.6c1.7.7 3.3.6 4.1 0 .2-.1.4-.3.4-.5.4-1.1-.9-2.7-2.9-3.5-2.1-.8-4.1-.6-4.5.5 0 .1-.1.3-.1.4-.1 1 1.1 2.3 3 3.1z" fill="url(#H)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M72 105.8c.7-.3 1.4-.6 2.1-1 3.2-1.6 6.7-5.7 6.9-5.8.4-.5.4-1.2-.1-1.6-.1-.1-.2-.1-.3-.2-.4-.2-.9-.1-1.3.3 0 0-1.6 1.8-3.5 3.4-.9.8-1.9 1.5-2.7 1.9-.1 0-.2.1-.3.1-.5.2-.9.4-1.3.6-3.6 1.6-6.2 2.1-6.3 2.1-.6.1-1 .7-.9 1.3 0 .1.1.2.1.2 3.3-.1 5.3-.6 5.3-.6h.3c.2-.1.5-.2.7-.3.4 0 .8-.2 1.3-.4z" fill="url(#I)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M11.6 117.5c-4.2-1-7.4-4.5-7.8-9.1-.3-2.9.6-5.6 2.3-7.6.5-.6 1.1-1.2 1.8-1.7l.8 7.7c.1.8.8 1.4 1.5 1.4h.2l2-.2 3.6-.4c.4 0 .8-.3 1-.6.3-.3.4-.7.3-1.1l-.8-7.7c3.2 1.5 5.5 4.6 5.9 8.3.3 2.9-.6 5.6-2.3 7.6-1 1.2-2.3 2.2-3.7 2.9l.4 3.7c.4.2.8.3 1.2.6l-.1-.6-.3-3.1c1.3-.7 2.5-1.7 3.4-2.8 1.9-2.4 2.8-5.4 2.5-8.4-.4-4-2.8-7.5-6.5-9.2l-1
.5-.6c-.2-.1-.3-.1-.5-.1h-.2c-.4 0-.8.3-1.1.6-.3.3-.4.8-.4 1.2l.8 7.9c0 .2-.1.3-.1.3 0 .1-.1.1-.3.2l-1.6.2-2 .2c-.3 0-.5-.2-.5-.4L9 99v-.2c-.1-.8-.8-1.5-1.6-1.5h-.2c-.2 0-.4.1-.6.2-1.3.7-2.4 1.7-3.3 2.8-1.9 2.4-2.8 5.4-2.5 8.4.5 4.7 3.7 8.5 8.1 9.9l.3 2.8c.8-.5 1.8-.8 2.9-1l-.5-2.9z" fill="url(#J)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M18.3 135.9l-.7-6.5c-1.1.8-2.4 1.3-3.5 1.5-.4.1-.7.1-1.1.2l.6 5.3c-1.5.7-2.7 1.7-3.7 2.9-1.7 2.1-2.6 4.8-2.3 7.6.4 3.8 2.7 6.8 5.9 8.3l-.8-7.7c0-.4.1-.8.3-1.1.3-.3.6-.5 1-.6l2-.2 3.6-.4h.2c.4 0 .8.1 1 .4.3.2.5.6.5 1l.8 7.7c.7-.5 1.3-1.1 1.8-1.7 1.7-2.1 2.6-4.8 2.3-7.6-.3-4.6-3.6-8.1-7.9-9.1z" fill="url(#K)" fill-rule="nonzero" transform="translate(81 15)"/><path fill="url(#L)" fill-rule="nonzero" d="M171.1 22.7l-.3-.8-1.6 1.4" transform="translate(81 15)"/><path fill="url(#M)" fill-rule="nonzero" d="M158.9 18.3l.3 1.1 2.2-1.9" transform="translate(81 15)"/><path d="M168.9 16.1l-.3-.9-2 .7-6.4 5.4c-.1.1-.2.1-.3.2l.6 1.8 8.1-6.9c.1-
.2.2-.3.3-.3z" fill="url(#N)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M161.1 25.2l.2.7 2.7-.9 5.8-4.9c.1-.1.2-.1.3-.2l-.6-1.8-8.1 6.9c-.1.1-.2.1-.3.2z" fill="url(#O)" fill-rule="nonzero" transform="translate(81 15)"/><path fill="url(#P)" fill-rule="nonzero" d="M165 37.1l.4 1.2 2.5-2.1" transform="translate(81 15)"/><path d="M170.3 41.7l-2.7 2.3c-.1.1-.2.1-.3.2l.6 1.8 2.6-2.2c-.2-.8-.2-1.5-.2-2.1z" fill="url(#Q)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M175.1 35l-.4-1.1-1.6.5-6.7 5.7c-.1.1-.2.1-.3.2l.6 1.8 8.1-6.9c.1-.1.2-.1.3-.2z" fill="url(#R)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M171.5 45.5l-2.6 2.2c-.1.1-.2.1-.3.2l.6 1.8 3.7-3.1c-.6-.3-1-.7-1.4-1.1z" fill="url(#S)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M164 25l5.2-1.7 1.6-1.4.3-.3c.4-.4.5-1 .1-1.5-.3-.3-.7-.4-1.1-.3-.1 0-.2.1-.3.2l-5.8 5z" fill="url(#T)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M166.6 15.8l-5.2 1.7-2.2 1.9-.3.3c-.4
.4-.5 1-.1 1.5l.3.3c.2.1.5.1.8.1.1 0 .2-.1.3-.2l6.4-5.6z" fill="url(#U)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M175 47.4c-.8-.2-1.6-.5-2.2-.9l-3.7 3.1-.3.3c-.4.4-.5 1-.1 1.5l.3.3c.3.1.6.1.8 0 .1 0 .2-.1.3-.2l4.9-4.1z" fill="url(#V)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M173.2 34.5l-5.2 1.7-2.5 2.1-.3.3c-.4.4-.5 1-.1 1.5l.3.3c.2.1.5.1.8.1.1 0 .2-.1.3-.2l6.7-5.8z" fill="url(#W)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M170.3 41.7c.1-1.1.6-2 .6-2 .1-.3.5-.4.7-.2.1 0 .1.1.2.1 1.1-1.3 2.8-2.3 4.5-3 .2-.4.2-.9-.1-1.2-.3-.3-.7-.4-1.1-.3-.1 0-.2.1-.3.2l-8.1 6.9-.3.3c-.4.4-.5 1-.1 1.5l.3.3c.2.1.5.1.8.1.1 0 .2-.1.3-.2l2.6-2.5z" fill="url(#X)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M171.5 45.5c-.3-.4-.6-.7-.8-1.2-.1-.2-.2-.4-.2-.7l-2.6 2.2-.3.3c-.4.4-.5 1-.1 1.5l.3.3c.2.1.5.1.8.1.1 0 .2-.1.3-.2l2.6-2.3z" fill="url(#Y)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M161.1 25.2c.1 0 .2-.1.3-.2l8.1-6.9.
3-.3c.4-.4.5-1 .1-1.5-.3-.3-.7-.4-1.1-.3-.1 0-.2.1-.3.2l-8.1 6.9-.3.3c-.4.4-.5 1-.1 1.5l.3.3c.3 0 .5.1.8 0z" fill="url(#Z)" fill-rule="nonzero" transform="translate(81 15)"/><path fill="url(#aa)" fill-rule="nonzero" d="M165.6 4.8l-11 3.6 3 9.2 11-3.7" transform="translate(81 15)"/><path fill="url(#ab)" fill-rule="nonzero" d="M174.8 32.7l-3-9.1-11 3.6 3 9.2" transform="translate(81 15)"/><path d="M160.8 38.5l3.2-1.1.3 1-.2.1c-1.5.7-3.2 1.6-5.1 2.9-2.4 1.6-4.4 3.1-6.3 4.9-2.5 2.5-4.6 5.2-6.1 8.2-1.8 3.5-3 7.4-3.5 11.5 0 .4-.1.8-.1 1.3v3.9c-.1 1.1-.2 2.3-.4 3.8-.4 2.3-1.1 4.5-2 6.4-.4.8-.9 1.5-1.4 2.1-.4.5-.9 1-1.6 1.5-.9.7-1.9 1.1-3.1 1.3h-.1c-.5.1-.9.1-1.3.1h-.2c-.6 0-1.3-.1-1.8-.2h-.1c-1.2-.3-2.3-.9-3.2-1.7-.5-.4-.9-.9-1.3-1.4-.3-.4-.6-.9-1-1.5-.1-.1-.1-.3-.2-.4-.1-.1-.1-.2-.2-.4l-.3-.6-.1-.2-.1-.2v-.1l-.1-.2c0-.1-.1-.1-.1-.2-.1-.2-.2-.3-.2-.5v-.1c-.1-.3-.3-.5-.4-.8v-.1l-.3-.6c-.2-.3-.3-.6-.5-.9 0-.1-.1-.1-.1-.2-.1-.7-.1-1.5-.1-2.3 7.3-2.6 12.2-9.4 12.2-17.3 0-5.2-2.1-10-5.9-13.5v-1
.1c0-19.5-15.9-35.4-35.4-35.4S58.3 22.4 58.3 41.9V43c-3.3 3.1-5.4 7.2-5.8 11.6l2.2.9c.1-1.5.4-3 .9-4.4.4-1.1.9-2.2 1.5-3.2.2-.4.5-.7.7-1.1.5-.7 1.1-1.4 1.7-2 .3-.3.6-.6 1-.9 0-.7-.1-1.4-.1-2.1 0-2.3.2-4.5.7-6.7.2-1.1.5-2.1.8-3.2.5-1.6 1.1-3.1 1.8-4.5.5-1 1-1.9 1.5-2.8.6-.9 1.2-1.8 1.8-2.6.3-.4.6-.8 1-1.3 4.4-5.3 10.4-9.3 17.3-11 2-.5 4-.8 6.2-1 .7 0 1.4-.1 2.1-.1 2.1 0 4.1.2 6 .6.7.1 1.3.3 1.9.4.2.1.4.1.6.2 2.8.8 5.5 1.9 8 3.3 1.2.7 2.4 1.5 3.6 2.4 1.1.9 2.2 1.8 3.2 2.8 4 4 7 9.1 8.6 14.8.1.2.1.4.2.6.6 2.6 1 5.2 1 8 0 .7 0 1.4-.1 2.1 1.8 1.5 3.3 3.3 4.3 5.5 1 2.1 1.6 4.5 1.6 7 0 5.7-2.9 10.7-7.4 13.5-.7.5-1.5.9-2.3 1.3-.7.3-1.4.5-2.1.7-1.3.2-2.4.3-3 .3h-.5c-.3 0-.6.3-.6.6s.2.6.6.6h.3c.5 0 1.5-.1 2.8-.3.1 1.2.1 2.4.2 3.5.1.2.2.3.3.5.1.2.2.5.4.7.1.2.3.5.4.8.1.3.3.5.4.8.1.1.1.3.2.4.1.1.2.3.2.4.1.1.1.3.2.5s.2.3.2.5c.1.3.3.6.5.9l.6.9c.2.3.4.6.7.9.5.6 1 1.2 1.6 1.7 1 .8 2.1 1.5 3.3 1.9.3.1.5.2.8.3.7.2 1.5.3 2.2.3h.4c.6 0 1.2-.1 1.8-.2.7-.1 1.4-.3 2.1-.6.7-.3 1.3-.7 2-1.1.6-.5 1.3-1.1 1.9-
1.8.6-.7 1.2-1.6 1.7-2.6 1-2 1.8-4.4 2.3-7.1.2-1.3.4-2.7.5-4.1V68.8 67c0-.5.1-1.1.1-1.6.4-3.9 1.6-7.6 3.2-10.7.4-.8.8-1.5 1.3-2.2l1.5-2.1c.7-.9 1.5-1.8 2.2-2.6l.8-.8c2-1.9 4-3.4 5.8-4.6l.1-.1c1.4-.9 2.7-1.6 3.8-2.2.3-.2.7-.3 1-.5l1.3 3.9.4 1.1.6 1.7 1.4 4.3v.1c-1.1.9-2.3 1.4-3.2 1.4l-1.5 2.1c-.5.8-1 1.7-1.4 2.6-.4.9-.8 1.8-1.1 2.7-.1.5-.3.9-.4 1.4-.3 1.5-.5 3-.4 4.6v1.7c0 .4.1.8.1 1.2 0 .5.1.9.1 1.4.1 1.9.1 3.8 0 5.8v.4c1.1.3 1.6 2.3 1.1 4.4-.4 1.7-1.4 3-2.4 3.3-.4 1.4-.8 2.8-1.4 4.3-.2.5-.4 1-.7 1.6-.7 1.6-1.6 3.1-2.6 4.6-.7 1-1.5 2-2.3 2.9.2.1.4.2.5.4.5.7.2 1.9-.7 3 1.7-1.5 3.1-3.2 4.4-4.9 1.4-2 2.6-4.2 3.5-6.6 1.6-4 2.6-8.4 2.9-13.1.1-2 .1-4.1 0-6.1 0-.3 0-.7-.1-1v-.4l-.1-1.2V66.3v0-.1-.4-.3c0-2 .2-3.8.7-5.4.3-.9.7-1.8 1-2.4.4-.8.8-1.5 1.3-2.3.5-.7 1-1.5 1.5-2.2.5-.6 1-1.2 1.6-1.9.4.7 1 1.3 1.8 1.7.5.2 1.1.4 1.7.4.4 0 .8-.1 1.2-.2l4.4-1.4c1-.3 1.8-1 2.3-2 .5-.9.6-2 .2-3l-.2-.7c-.4.1-.7.2-1.1.2l.3.8c.5 1.5-.3 3.1-1.8 3.6l-4.4 1.4c-.3.1-.6.1-.9.1-1 0-2-.6-2.5-1.5-.3.1-.6.1-.8 0-.1-
.1-.2-.1-.3-.3-.4-.4-.3-1.1.1-1.5l.3-.3-.6-1.8c-.3.1-.5.1-.8-.1-.1-.1-.2-.1-.3-.3-.4-.4-.3-1.1.1-1.5l.3-.3-.6-1.8c-.3.1-.5.1-.8-.1-.1-.1-.2-.1-.3-.3-.4-.4-.3-1.1.1-1.5l.3-.3-.6-1.8c-.3.1-.5.1-.8-.1-.1-.1-.2-.1-.3-.3-.4-.4-.3-1.1.1-1.5l.3-.3-.4-1.2 2.9-1 5.2-1.7 1.6-.5.4 1.1c.4-.1.8 0 1.1.3.3.4.3.9.1 1.2.2-.1.3-.1.5-.2l-.3-.9-.6-2 3.2-1.1c.9-.3 1.6-.9 2-1.7.4-.8.5-1.7.2-2.6l-1.6-4.8c-.6-1.8-2.5-2.7-4.3-2.2l-3.2 1.1-2.5-7.5 3.2-1.1c.9-.3 1.6-.9 2-1.7.1-.2.2-.4.2-.6.1-.2.1-.4.1-.6 0-.4 0-.9-.2-1.3l-1.6-4.8c-.3-.9-.9-1.6-1.7-2-.8-.4-1.7-.5-2.6-.2l-18.3 6c-1.8.6-2.7 2.5-2.2 4.3l1.6 4.8c.3.9.9 1.6 1.7 2 .5.2 1 .4 1.5.4.4 0 .7-.1 1.1-.2l3.2-1.1 2.5 7.5-3.2 1.1c-.9.3-1.6.9-2 1.7-.4.8-.5 1.7-.2 2.6l1.6 4.8c.3.9.9 1.6 1.7 2 .4.2.9.3 1.4.3h.2c.3 1.9.6 1.8 1 1.7zm14.9-16.2c1.2-.4 2.5.3 2.9 1.5l1.6 4.8c.2.6.1 1.2-.1 1.7-.3.5-.7.9-1.3 1.1l-2.8.9-3-9.2 2.7-.8zm-6.2-18.8c.6-.2 1.2-.1 1.7.1.5.3.9.7 1.1 1.3l1.6 4.8c.2.6.1 1.2-.1 1.7-.3.5-.7.9-1.3 1.1l-2.8.9-3-9.2 2.8-.7zm-11.7 14.6l-3.4 1.1c-1.5.5-3.
1-.3-3.6-1.8l-1.6-4.8c-.5-1.5.3-3.1 1.8-3.6l3.4-1.1.2.5 11-3.6 3 9.2-11 3.6.2.5zm2.2 6.8c-.4-.4-.3-1.1.1-1.5l.3-.3-.6-1.8c-.3.1-.5.1-.8-.1-.1-.1-.2-.1-.3-.3-.4-.4-.3-1.1.1-1.5l.3-.3-.3-1 2.5-.8 5.2-1.7 2-.7.3.9c.4-.1.8 0 1.1.3.4.4.3 1.1-.1 1.5l-.3.3.6 1.8c.4-.1.8 0 1.1.3.4.4.3 1.1-.1 1.5l-.3.3.2.8-1.9.6L164 25l-2.7.9-.2-.7c-.3.1-.5.1-.8-.1-.1 0-.2-.1-.3-.2zm-3 11.3l-1.6-4.8c-.5-1.5.3-3.1 1.8-3.6l3.4-1.1.2.5 11-3.6 3 9.2-11 3.6.2.5-3.4 1.1c-1.5.5-3.1-.3-3.6-1.8z" fill="url(#ac)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M164 36.9l-.2-.5-3-9.2-.2-.5-3.4 1.1c-1.5.5-2.3 2.1-1.8 3.6l1.6 4.8c.5 1.5 2.1 2.3 3.6 1.8l3.4-1.1z" fill="url(#ad)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M154.4 7.9L151 9c-1.5.5-2.3 2.1-1.8 3.6l1.6 4.8c.5 1.5 2.1 2.3 3.6 1.8l3.4-1.1-.2-.5-3-9.2-.2-.5z" fill="url(#ae)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M253.5 27.7c.6-.2 1-.6 1.3-1.1.3-.5.3-1.2.1-1.7l-1.6-4.8c-.2-.6-.6-1-1.1-1.3-.5-.3-1.2-.3-1.7-.1l-2.8.9 3
9.2 2.8-1.1zM259.7 46.5c.6-.2 1-.6 1.3-1.1.3-.5.3-1.2.1-1.7l-1.6-4.8c-.4-1.2-1.7-1.8-2.9-1.5l-2.8.9 3 9.2 2.9-1z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M190.7 121.8c0-.2-.1-.4-.2-.6-.1-.3-.3-.5-.5-.7l-3.2-2.6c-.1-.1-.2-.1-.3-.2-.1-.1-.3-.1-.4-.2-.2-.1-.4-.1-.7-.1h-.2c-.4.1-.8.3-1.1.7l-2.2 2.7-.4-.4c-.9-.7-1.9-1.2-3-1.5-3-.8-6.3.2-8.7 2.5 1.8-.1 3.8.3 5.5 1.3.8-.2 1.5-.2 2.3 0 .6.1 1.1.4 1.5.8 1.5 1.2 1.9 3.4 1.1 5.5-.3.7-.8 1.4-1.5 2.3-.8.7-1.7 1.3-2.6 1.6-.9.3-1.8.3-2.6.1-.1 0-.1-.1-.2-.1-.5-.2-.9-.4-1.3-.7-.2-.2-.4-.3-.5-.5-.8 0-1.6 0-2.3-.1.1 0 .2.1.3.1.3.1.5.4.4.7-.1.2-.3.4-.5.4h-.1c-.7-.2-1.3-.4-1.9-.6l.6 1.2c-1.1-.3-2.9 0-4.3.8-1.9 1.1-3 2.9-2.4 3.9l.3.3c.8.7 2.6.6 4.3-.4 1.5-.9 2.9-2.2 3.1-3.2.2.2.4.4.6.5.3.2.5.4.8.6.7.4 1.4.7 2.2.9.1 0 .3 0 .4.1 3.3.7 6.9-.6 9.2-3.5.2-.2.3-.4.5-.7l3-3.7 4.6-5.6c.3-.6.5-1.1.4-1.6z" fill="url(#af)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M126.4 68.5l-.1-.1c-.2-.3-.5-.6-.8-.7-.2-.1-.3-.1-.5-.1h-.2l-.1-.1c-7.8-4.7-17.8
-11.7-21.3-17.9-.2-.5-.4-.9-.6-1.2-.5-.8-1.1-1.3-1.8-1.6-1.9-.8-4.5.3-7.3 3-2.9 2.8-5.5 7-7.5 11.8-3.9 9.7-3.8 19.3.3 20.9 1.2.5 2.7.3 4.3-.7l.1-.1c6.9-1.7 18.4.3 26.8 2.2h.2l.1.2c.2.2.4.4.6.5.4.2.8.1 1.3-.1l.2-.1h.2c.2.1.4.1.6.2 1.8-1.1 3.8-3.7 5.1-7 1.4-3.5 1.8-6.8 1.1-8.8-.2-.1-.4-.3-.7-.4v.1zm-23.7-6.6s0 .1 0 0c-.1.6-.3 1.2-.4 1.7 0 .1 0 .2-.1.3-.1.5-.3 1-.5 1.5 0 .1-.1.2-.1.3-.2.6-.4 1.2-.7 1.8-.2.6-.5 1.1-.7 1.7 0 .1-.1.2-.1.3-.3.5-.5 1-.8 1.5-2.9 5.3-6.6 8.7-9.6 8.7-.5 0-.9-.1-1.4-.3-1.9-.8-3-3.1-3-6.4-.1-3.2.7-7.1 2.3-11 1.6-3.9 3.7-7.2 6-9.5 2.4-2.4 4.8-3.3 6.7-2.5 2.8 1.2 3.7 6 2.4 11.9z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M39.9 69.8c-.2-.1-.4-.1-.6-.2h-.2l-.2.1c-.5.2-1 .2-1.3.1-.2-.1-.4-.3-.6-.5l-.1-.2h-.2c-8.4-1.9-19.9-3.8-26.8-2.2l-.1.1c-1.6.9-3.1 1.1-4.3.7-4.1-1.7-4.2-11.2-.3-20.9 2-4.8 4.6-9 7.5-11.8 2.7-2.6 5.4-3.7 7.3-3 .7.3 1.3.8 1.8 1.6.2.3.4.7.6 1.2 3.5 6.2 13.5 13.1 21.3 17.9l.1.1h.2c.2 0 .4 0 .5.1.3.1.5.3.8.7l.1.1.1.1c.2.1.5.3.7.4-.3-.9-.7-1.5-1.4-1.8
l1.9.8c-.2-.1-.3-.2-.5-.3-.3-.5-.7-.8-1.2-1-.2-.1-.5-.2-.8-.2-6.3-3.8-17.2-11.2-20.8-17.3-.2-.5-.4-.9-.7-1.3-.6-1-1.4-1.6-2.3-2-2.4-1-5.4.2-8.5 3.2-3 2.9-5.7 7.2-7.8 12.2C-.2 57.1.2 66.9 5 68.9c1.5.6 3.3.4 5.2-.7 6.6-1.6 17.8.3 26 2.1.3.3.6.5.9.7.5.2 1.1.2 1.7.1l-1.5-.6c.9 0 1.7-.2 2.6-.7z" fill="url(#ag)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M133.7 88l2.5 1c1.1.5 3.4-1.5 4.9-5.1 1.5-3.6 1.2-6.6.1-7.1l-2.5-1c0 1.9-.5 4.2-1.4 6.5-1 2.4-2.3 4.4-3.6 5.7z" fill="#F9F9FA" fill-rule="nonzero"/><path d="M19.3 35c-1.9-.8-4.2.1-6.7 2.5-2.3 2.3-4.5 5.6-6 9.5-1.6 3.9-2.4 7.8-2.3 11 .1 3.4 1.2 5.7 3 6.4.4.2.9.3 1.4.3 3 0 6.8-3.4 9.6-8.7.3-.5.5-1 .8-1.5.1-.1.1-.2.1-.3.3-.5.5-1.1.7-1.7.2-.6.5-1.2.7-1.8 0-.1.1-.2.1-.3.2-.5.3-1 .5-1.5 0-.1 0-.2.1-.3.2-.6.3-1.1.4-1.7v-.1c1.3-5.8.4-10.6-2.4-11.8zm1.6 10.3c-.4 2.2-1 4.5-1.9 6.8-.9 2.3-2.1 4.4-3.3 6.2h-.1c-.9-.4-1.1-3.3.5-7.4.7-1.8 1.7-3.4 2.7-4.5.7-.8 1.4-1.2 1.9-1.2l.2.1c-.1-.1 0-.1 0 0z" fill="url(#ah)" fill-rule="nonzero" tran
sform="translate(81 15)"/><path d="M18.7 46.4c-1 1.1-2 2.7-2.7 4.5-1.6 4-1.4 7-.5 7.4h.1c1.3-1.8 2.4-4 3.3-6.2.9-2.3 1.6-4.6 1.9-6.8H20.5c-.4-.1-1.1.3-1.8 1.1z" fill="url(#ai)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M43.6 77.3c0-.1.1-.3.1-.4.1-.3.3-.5.6-.5.1 0 .2.1.3.2.2-.3.5-.5.7-.7.4-.5.8-.8 1.1-1.1.1-.1.3-.2.3-.2.1-.1.1-.1.2-.1s0 0 .1-.1H47.9c.2.1.3.1.5.1l.2.1c.9.4 2 0 3.2-.9.3-.2.6-.5.9-.8 1.3-1.3 2.6-3.3 3.5-5.7 1-2.4 1.4-4.7 1.4-6.5 0-.4 0-.9-.1-1.2-.2-1.4-.7-2.5-1.6-2.8l-1.8-.7-2.2-.9-1.9-.8-.8-.3-2.8-1.1-1.9-.8c.7.3 1.1.9 1.4 1.8.6 2 .3 5.4-1.1 8.8-1.3 3.3-3.3 5.9-5.1 7-.9.6-1.8.7-2.5.4l1.5.6h.1c-.1.2-.3.3-.4.5-.1.1-.2.2-.2.3 2.5 1.1 4.9 3.4 5.4 5.8z" fill="url(#aj)" fill-rule="nonzero" transform="translate(81 15)"/><g fill-rule="nonzero"><path d="M283.2 146.6l-6.8.9-5.3-38.5c-.4-3.1 1.6-6 4.7-6.7.2-.1.5.1.5.4l6.9 43.9z" fill="#C8C8CC"/><path d="M292.8 107.4c.2-.2.5-.2.6 0 2.1 2.3 2.1 5.9-.1 8.2L266.8 144l-5-4.7 31-31.9z" fill="#E1E1E6"/><path d="M.9 10.6
c-.1 2.6.8 4.9 2.6 6.5.9.8 1.9 1.4 3 1.8 3.5 1.2 7.5 0 10.2-2.9l.6-.6 8.6-9.2c.4-.4.6-.9.5-1.4 0-.5-.2-1-.6-1.4L22.7.5c-.2-.2-.5-.4-.7-.4-.2-.1-.5-.1-.7-.1-.5 0-1 .2-1.4.6l-2.5 2.6-.4-.4c-.9-.8-1.9-1.4-3-1.8C10.5-.2 6.5 1 3.8 3.9 2 5.7 1 8.1.9 10.6zm5.8-4c1.6-1.7 4.1-2.5 6-1.8.6.2 1.1.5 1.5.9 1.5 1.4 1.7 3.7.8 5.8-.4.7-.9 1.5-1.7 2.3-1.6 1.4-3.8 2-5.5 1.4-.6-.2-1.1-.5-1.5-.9-.9-.9-1.4-2.1-1.3-3.5 0-1.5.6-3 1.7-4.2z" transform="translate(246 133)" fill="url(#ak)"/><path d="M.7 3.7l1.7 12.5c0 .3 0 .6.1.9C3 21 5.6 24.2 9 25.3c1.2.4 2.4.5 3.7.3 4.9-.7 8.2-5.6 7.5-11-.5-3.9-3.1-7.1-6.5-8.2-1.2-.4-2.4-.5-3.7-.3-.2 0-.4.1-.6.1l-.5-3.6c-.1-.8-.7-1.4-1.4-1.6-.3-.1-.6-.1-.9-.1l-4.2.6c-.5.1-1 .4-1.3.8-.3.3-.5.8-.4 1.4zm11.7 6.5c2 .6 3.4 2.6 3.7 4.9.4 3.2-1.4 6.1-4 6.4-.6.1-1.3 0-1.9-.2-1.8-.6-3.1-2.2-3.6-4.3v-.1c-.1-1.1-.2-2-.1-2.8.4-2.2 2-4 4-4.2.6 0 1.3.1 1.9.3z" transform="translate(274 137)" fill="url(#al)"/><path d="M277.1 126c1.2 0 2.3.9 2.3 2.2 0 1.2-.9 2.3-2.2 2.3-1.3 0-2.3-.9-2.3-2.2
0-1.2.9-2.2 2.2-2.3z" fill="#C8C8CC"/></g><path d="M36.2 88.9s.1 0 0 0l.2-.2.1-.1c.1-.2.3-.4.5-.6.2-.3.5-.7.8-1.2.3-.5.5-1 .7-1.5.2-.5.4-1.1.6-1.7 0 0 0-.1.1-.1.1-.2.2-.5.3-.7 0-.1.1-.1.1-.2h-.4c-1.4 0-2.8-.4-4.1-.7-1.1-.3-2-.8-2.8-1.3-.1.2-.1.4-.2.6-.1.4-.2.7-.3 1-.1.3-.2.6-.2.9-.1.3-.1.7-.2 1 0 .2-.1.4-.1.6v2.6c.1.7.5 1.3 1 1.7.6.5 1.4.8 2.3.6.1 0 .2-.1.3-.1.2-.1.4-.1.6-.2.4-.1.6-.3.7-.4z" fill="url(#am)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M176.3 36.6c-1.7.6-3.4 1.7-4.5 3 .2.2.2.4.1.6 0 0-1 2-.2 3.7.5 1.2 1.8 2 3.8 2.5.3.1.5.4.4.7-.1.3-.3.4-.5.4h-.1c-.1 0-.1 0-.2-.1l-4.8 4.1c-.1.1-.2.1-.3.2.5.9 1.5 1.5 2.5 1.5.3 0 .6 0 .9-.1l4.4-1.4c1.5-.5 2.3-2.1 1.8-3.6l-.3-.8c.4-.1.7-.1 1.1-.2.7-.2 1.4-.5 2-.9 3.7-2.4 3.3-8.5-2-10.3-.6-.2-1.8-.1-3.1.3-.2 0-.3.1-.5.2s-.3.1-.5.2z" fill="url(#an)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M166.8 122.9s-2.6 2.9-1.9 5.4c.4 1.4 1.8 2.5 4.2 3.2.7.1 1.5.1 2.3.1h.1c.9 0 1.7-.1 2.5-.3 1-.2 2-.6 2.7-1.2.5-.4.9-.9 1
.2-1.5 1-2.6-.4-4.6-2.6-5.8-1.6-.9-3.7-1.4-5.5-1.3-.7 0-1.4.2-2 .4-.3.1-.6.3-1 .6.1.1.1.3 0 .4z" fill="url(#ao)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M35.5 80.8c2.9.9 4.8.9 6.1.1 1-.6 1.7-1.8 2-3.6-.5-2.4-2.8-4.7-5.3-5.7-.8-.3-1.6-.6-2.3-.6-1.5-.1-4.1 1-5.2 3 .2.1.3.4.2.6-.1.2-1.2 4.5 4.5 6.2z" fill="url(#ap)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M6.9 125.8s-.1 2.1 1.4 3.3c1.2 1 3.1 1.2 5.6.7 1.7-.4 3.9-1.5 4.9-3.3.6-1 .7-2.2.3-3.4-.1-.2 0-.4.2-.6-.3-.5-.8-.9-1.3-1.2l-1.2-.6-.4-3.7c1.5-.7 2.7-1.7 3.7-2.9 1.7-2.1 2.6-4.8 2.3-7.6-.4-3.8-2.7-6.8-5.9-8.3l.8 7.7c0 .4-.1.8-.3 1.1-.3.3-.6.5-1 .6l-3.6.4-2 .2h-.2c-.8 0-1.5-.6-1.5-1.4l-.8-7.7c-.7.5-1.3 1.1-1.8 1.7-1.7 2.1-2.6 4.8-2.3 7.6.5 4.5 3.7 8 7.8 9.1l.3 2.9c-1.1.2-2.1.5-2.9 1-.2.1-.3.2-.5.3-.8.6-1.7 2-2 3.5.3.2.4.4.4.6z" fill="url(#aq)" fill-rule="nonzero" transform="translate(81 15)"/><path d="M170.9 39.7c0 .1-.4.9-.6 2-.1.6-.1 1.3.1 2 .1.2.1.4.2.7.2.4.5.8.8 1.2.4.4.8.7 1.3 1 .6.4 1.3.6 2.2.
9.1 0 .1 0 .2.1h.1c.3 0 .5-.2.5-.4.1-.3-.1-.6-.4-.7-1.9-.5-3.2-1.3-3.8-2.5-.8-1.7.2-3.7.2-3.7.1-.2.1-.5-.1-.6 0 0-.1-.1-.2-.1 0-.3-.3-.2-.5.1z" fill="url(#ar)" fill-rule="nonzero" transform="translate(81 15)"/></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/figure_customize.svg b/browser/extensions/onboarding/content/img/figure_customize.svg
new file mode 100644
index 000000000000..0c0cb30df5dc
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_customize.svg
@@ -0,0 +1,561 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="295" height="238">
+ <defs>
+ <linearGradient id="a" x1="-678.179817%" x2="218.03211%" y1="-1879.5122%" y2="503.09878%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="b" x1="-2438.15968%" x2="713.035484%" y1="-2346.83281%" y2="705.8875%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="c" x1="-1876.47349%" x2="477.431325%" y1="-2215.7169%" y2="536.030986%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="d" x1="-300.502319%" x2="326.878731%" y1="-277.869139%" y2="301.876261%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="e" x1="-556.386842%" x2="471.897895%" y1="-1050.94952%" y2="809.757143%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="f" x1="-2301.11875%" x2="1769.175%" y1="-4460.38%" y2="3354.584%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="g" x1="-14090.38%" x2="5447.03%" y1="-14085.94%" y2="5451.47%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="h" x1="-1245.88053%" x2="483.093805%" y1="-2962.82857%" y2="1024.39796%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="i" x1="-4762.32308%" x2="1072.27051%" y1="-2525.31233%" y2="591.799315%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="j" x1="-419.785061%" x2="175.867683%" y1="-263.047589%" y2="146.541719%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="k" x1="-13945.16%" x2="5592.25%" y1="-13931.16%" y2="5606.26%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="l" x1="-93.8791876%" x2="171.036409%" y1="-368.29%" y2="383.149231%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="m" x1="-105.119971%" x2="175.589943%" y1="-106.702736%" y2="160.566895%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="n" x1="-4526.45652%" x2="3968.06957%" y1="-3864.98889%" y2="3371.08889%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="o" x1="-1590.58053%" x2="2387.43252%" y1="-835.835705%" y2="1325.72397%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="p" x1="-1174.27536%" x2="1657.23333%" y1="-1275.87873%" y2="1781.26242%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="q" x1="-8557.56%" x2="10979.85%" y1="-4234.38%" y2="5534.325%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="r" x1="-949.737079%" x2="1245.47865%" y1="-1023.81277%" y2="1336.75514%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="s" x1="-850.555238%" x2="1010.15048%" y1="-759.279881%" y2="912.10717%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="t" x1="-2526.775%" x2="962.048214%" y1="-2513.94763%" y2="949.261152%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="u" x1="-953.117868%" x2="406.88755%" y1="-1083.71008%" y2="471.112383%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="v" x1="-1736.94827%" x2="671.463404%" y1="-2238.58822%" y2="855.656147%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="w" x1="-9592.54%" x2="9944.87%" y1="-9613.77%" y2="9923.64%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="x" x1="-546.9251%" x2="669.232184%" y1="-637.97868%" y2="716.339388%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="y" x1="-2626.25%" x2="2515.17368%" y1="-10166.57%" y2="9370.85%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="z" x1="-26076.58%" x2="9092.02%" y1="-26064.58%" y2="9104.02%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="A" x1="-11996.8348%" x2="3293.86087%" y1="-4084.84179%" y2="1164.20299%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="B" x1="-1988.44219%" x2="759.104687%" y1="-1576.81875%" y2="621.219375%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="C" x1="-4889.30185%" x2="1623.40185%" y1="-2351.25495%" y2="817.087387%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="D" x1="-2655.5559%" x2="951.48%" y1="-6714.61282%" y2="2302.97692%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="E" x1="-11418.996%" x2="2648.448%" y1="-28603.67%" y2="6564.93%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="F" x1="-1067.54883%" x2="792.163033%" y1="-899.682353%" y2="691.657014%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="G" x1="-3245.82558%" x2="2272.05861%" y1="-2753.32267%" y2="1935.824%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="H" x1="-835.133806%" x2="827.684161%" y1="-835.133806%" y2="827.684161%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="I" x1="-4541.82131%" x2="1223.52295%" y1="-2322.54576%" y2="657.84322%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="J" x1="-2057.47051%" x2="889.742903%" y1="-1738.77914%" y2="791.335971%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="K" x1="-1278.62667%" x2="1189.34526%" y1="-1278.9986%" y2="1188.97333%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="L" x1="-6112.0075%" x2="2680.1425%" y1="-6270.03333%" y2="2747.55641%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="M" x1="-1115.93023%" x2="572.391158%" y1="-1175.6355%" y2="582.7945%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="N" x1="-9656.07586%" x2="2471.02759%" y1="-9322.84667%" y2="2400.02%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="O" x1="-7887.73698%" x2="3321.17237%" y1="-6188.2325%" y2="2603.9175%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="P" x1="-984.783738%" x2="288.77261%" y1="-1902.68288%" y2="506.125342%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="Q" x1="-2522.67732%" x2="1102.95155%" y1="-5039.01837%" y2="2138.24694%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="R" x1="-5921.7225%" x2="2870.4275%" y1="-6075.45385%" y2="2942.1359%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="S" x1="-5881.53%" x2="2910.62%" y1="-5881.26%" y2="2910.89%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="T" x1="-5841.3375%" x2="2950.8125%" y1="-5841.4525%" y2="2950.6975%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="U" x1="-7423.23691%" x2="3785.67244%" y1="-5801.6425%" y2="2990.5075%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="V" x1="-4020.34%" x2="1003.74571%" y1="-2527.16182%" y2="669.983636%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="W" x1="-4517.96032%" x2="1064.35714%" y1="-5480.38654%" y2="1282.80577%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="X" x1="-3834.66828%" x2="2163.11753%" y1="-3992.49299%" y2="2248.99581%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="Y" x1="-132.800878%" x2="141.123835%" y1="-126.933901%" y2="145.268963%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="Z" x1="-8624.4%" x2="10913.01%" y1="-4751.06111%" y2="6103.05556%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aa" x1="-20576.83%" x2="14591.77%" y1="-11391.2944%" y2="8146.81667%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ab" x1="-3210.85073%" x2="1716.38147%" y1="-3721.57455%" y2="1963.19067%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ac" x1="-964.539164%" x2="305.324758%" y1="-1877.16986%" y2="531.638356%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ad" x1="-5971.9075%" x2="2820.24%" y1="-7463.6%" y2="3526.5875%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ae" x1="-3626.20024%" x2="2128.73795%" y1="-3780.54791%" y2="2217.23789%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="af" x1="-3545.17742%" x2="2127.17742%" y1="-3793.28448%" y2="2270.26724%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ag" x1="-8571.16538%" x2="4955.21923%" y1="-4812.20217%" y2="2833.14565%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ah" x1="-921.592388%" x2="295.314187%" y1="-948.070803%" y2="335.454745%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ai" x1="-1521.4596%" x2="706.721231%" y1="-1247.46875%" y2="591.922626%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aj" x1="-678.258824%" x2="423.307164%" y1="-682.475952%" y2="429.068947%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ak" x1="-6036.96%" x2="2755.19%" y1="-6038.3275%" y2="2753.82%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="al" x1="-876.033667%" x2="359.821607%" y1="-805.490909%" y2="336.346753%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="am" x1="-6523.57663%" x2="4813.74946%" y1="-5038.58141%" y2="3749.13318%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="an" x1="-2645.94937%" x2="963.166315%" y1="-6683.46667%" y2="2334.12564%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ao" x1="-6631.98345%" x2="4705.34265%" y1="-5121.96932%" y2="3665.74527%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ap" x1="-1435.66843%" x2="1068.42563%" y1="-2846.04456%" y2="2010.54343%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aq" x1="-2633.78646%" x2="975.329221%" y1="-6654.88205%" y2="2362.70769%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ar" x1="-2206.3925%" x2="2189.6825%" y1="-2444.83034%" y2="2406.01103%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="as" x1="-5385.00363%" x2="1874.66412%" y1="-10484.884%" y2="3582.556%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="at" x1="-2391.91311%" x2="1397.1783%" y1="-5593.4125%" y2="3198.7375%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="au" x1="-2264.71662%" x2="1521.15732%" y1="-5306.3925%" y2="3485.7575%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="av" x1="-8124.26538%" x2="5402.11923%" y1="-4560.45%" y2="3084.89783%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aw" x1="-651.882139%" x2="479.56521%" y1="-1403.71323%" y2="934.962067%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ax" x1="-782.651586%" x2="579.099454%" y1="-1688.18577%" y2="1133.37245%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ay" x1="-2808.00445%" x2="930.963547%" y1="-4874.39455%" y2="1519.89636%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="az" x1="-3080.27111%" x2="827.351111%" y1="-4651.45333%" y2="1209.98%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aA" x1="-17842.03%" x2="17326.57%" y1="-17824.13%" y2="17344.47%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aB" x1="-4927.80617%" x2="7466.4141%" y1="-2177.67416%" y2="3371.61183%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aC" x1="-20583.89%" x2="14584.71%" y1="-5842.07714%" y2="4206.09429%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aD" x1="-13953.96%" x2="21214.64%" y1="-2172.57143%" y2="3409.74603%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aE" x1="-13796.3%" x2="21372.3%" y1="-1986.00882%" y2="3185.84412%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aF" x1="-13888.17%" x2="21280.43%" y1="-2353.96379%" y2="3709.58793%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aG" x1="-9372.00909%" x2="6613.71818%" y1="-2958.36812%" y2="2138.53043%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aH" x1="-16384.5222%" x2="12067.4729%" y1="-4573.9%" y2="3418.96364%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aI" x1="-17462.5%" x2="5983.23333%" y1="-13777.5842%" y2="4732.21053%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aJ" x1="-7480.69%" x2="7500.95%" y1="-7483.33%" y2="7498.32%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aK" x1="-7021.27187%" x2="3968.91562%" y1="-20520.9909%" y2="11450.4636%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aL" x1="-9826.0913%" x2="5464.60435%" y1="-22671.15%" y2="12497.45%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aM" x1="-2964.13075%" x2="2873.3758%" y1="-3993.57709%" y2="3854.15587%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aN" x1="-2330.22879%" x2="2205.28384%" y1="-2914.60952%" y2="2667.70794%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aO" x1="-1407.98283%" x2="1424.97017%" y1="-1728.51863%" y2="1719.38333%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aP" x1="-1807.9102%" x2="1780.72245%" y1="-2740.56%" y2="2669.99385%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aQ" x1="-1472.82%" x2="1783.415%" y1="-4365.0426%" y2="5068.41814%">
+ <stop stop-color="#FFFBCC" offset="0%"/>
+ <stop stop-color="#FFC9D5" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aR" x1="-511.087979%" x2="436.292949%" y1="-431.133333%" y2="359.905%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aS" x1="-2336.83483%" x2="1396.15506%" y1="-7055.5%" y2="4019.03333%">
+ <stop stop-color="#FFE900" offset="18.75%"/>
+ <stop stop-color="#FF0039" offset="100%"/>
+ </linearGradient>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <path d="M149.5 168.5c-.1 0-.1.1-.2.1l-3.3 1.5c-.2.1-.3.1-.5.2.7.3 1.4.5 2.2.5 1.6 0 3.1-.7 4.2-1.9 1-1.1 1.4-2.5 1.3-4-.1-.9-.3-1.7-.7-2.4l-1.6 4.4c-.3.6-.8 1.2-1.4 1.6zM178.7 206.1c-.1-.1-.2-.3-.2-.4l-2 2.7 3.1 1.1-.8-2.6c-.1-.2-.1-.5-.1-.8zM240.6 207.9h0zM168.5 200.6h-.2c-.2.2-.5.3-.7.4l-2.5.7.2.8c1.1.7 2 1.7 2.5 2.9l1 .4 3.7-5c.9-1.2 2.2-1.9 3.7-2l-.1-.3-2.5.7c-.2.1-.4.1-.6.1h-.2c-.2.2-.5.3-.7.4l-3.1.9c-.1-.1-.3 0-.5 0zM146.9 159.8c.1.1.2.1.3.2 0-.1.1-.2.1-.3-.1 0-.2 0-.4.1zM143.3 112.9c.2-.3.4-.6.7-.8l4.4-2.8-.1-.1-4.2 2.7c-.3.2-.6.6-.8 1zM142.2 166c.3-.5.7-1 1.3-1.2h.1l.2-.1-1.9-.7c.2.4.2.8.2 1.3 0 .2.1.4.1.7zM200.9 117.6c-1.9 0-3.2 1-3.9 1.7.7-.7 2-1.7 3.9-1.7zM206.8 158.8c-.1 0-.1.1-.2.1.1 0 .1 0 .2-.1zM174.5 190.8c.2-.1.4-.1.6-.1h.2c.2-.2.5-.3.7-.4.5-.2 1-.2 1.6-.2 2.4 0 4.5 1.5 5.2 3.9.1.3.1.5.1.8.2.2.3.5.4.7l.9 3.1c.1.3.1.5.1.8.2.2.3.5.4.7l.3 1.1c.3.2.6.4.9.7-1.7-3.9-2.3-8.6-1.6-13.7-1.1.2-2.3.3-3.5.3-3.4 0-6.8-1-9.7-2.8-.7-.5-1.4-1-2.1-1.6 1.7 2.3 3.5 4.6 5.3 6.7h.2z
M143.4 119.9c-1.1-.3-2-.8-2.8-1.6l-.7.5v.1l.7-.4c.8.7 1.7 1.2 2.8 1.4.4.2.9.2 1.3.2 1.4 0 2.7-.5 3.8-1.3-1.1.8-2.4 1.3-3.7 1.3-.5 0-.9-.1-1.4-.2zM198.7 120.8c.4-.4 1.2-.9 2.2-.9-1 0-1.8.5-2.2.9zM213.3 214.1c-1 0-2 0-3-.1 1.2 4.1 1.9 6.8 2.2 8.8 3.2-.1 6.5-.2 9.9-.2-.1-1.7-.1-3.8-.1-6.6l-7-2c-.6.1-1.3.1-2 .1zM275.4 138.9l.9-.3c-.1-.7.1-1.4.4-2.1-1.5 2-3.5 3.6-5.8 4.5.1 0 .1.1.2.1.2-.2.5-.3.7-.4 1.1-.7 2.4-1.3 3.6-1.8zM139.9 151.5c.5-.3 1.1-.5 1.7-.5.3 0 .7.1 1 .2.7.3 1.3.8 1.6 1.5.1.1.1.3.1.4 1-.3 2-.4 3-.4-2.2-4.2-4.8-9.7-7.4-15.2v14z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M227.5 226.4c.1.1.1.1.2.1 0 0-.1 0-.2-.1z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M228.2 231c-1.2 0-2.4-.4-3.4-1.2-1.3-1.1-2.1-2-2.4-7.2-3.4 0-6.7.1-9.9.2.6 3.3.2 4.4-.7 5.6-1 1.4-2.6 2.2-4.3 2.2-2.9 0-5.3-2.1-9.6-7-15.1 1.3-25.3 3.8-25.3 6.6 0 4.3 23.1 7.7 51.6 7.7s51.6-3.4 51.6-7.7c0-3.6-16.7-6.7-39.3-7.5-2.3 5.7-5.1 8.3-8.3 8.3z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M158.9 75.5h13.4c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-13.4c-.3 0-.6.2-.6.6.1.4.3.6.6.6zM155.4 85.7c0-.3-.2-.6-.6-.6h-13.4c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h13.4c.3-.1.6-.3.6-.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M134.3 114.7l.6-.4.4-.2c0-.7.1-1.3.2-2 0-.1.1-.2.1-.4-.4-.9-.8-2-1.2-3v6h-.1zM131.8 102.3c-.1-.3 0-.6.3-.7.3-.1.6 0 .7.3l.3.9V67h-13c.7 2.2 1.8 5.2 3.1 8.8.1.3 0 .6-.3.7h-.2c-.2 0-.4-.1-.5-.4-1.3-3.8-2.4-7-3.2-9.2h-3.4c1.1 3.8 3.1 10.1 5.8 18.2l-.1-.5c1.6 4.4 8.9 24.1 11.5 31l.4-.3v-9.5c-.6-1.4-1.1-2.7-1.4-3.5zM121.2 91.2c-3.9-10.9-6.6-19.6-7.9-24.2H7.1v98.7c0 .6 0 .9.1 1 .1 0 .4.1 1 .1h124c.6 0 .9 0 1-.1 0-.1.1-.4.1-1v-38.4l-1.6 1-.4.2c-.3.2-.6.4-1 .6-.6.3-1.2.4-1.9.4h-.2c-2 0-3.8-1.2-4.6-3-1-2.2-.3-4.7 1.5-6 .2-.2.5-.3.7-.5l2.3-1.4 2.7-1.7c-2.5-6.4-7-18.6-9.6-25.7zm-25.6 27.1h-7.1c-.5 2.1-1.4 4-2.6 5.8l5.1 5.1c1.2 1.6 1.2 3.6.1 5.1-.8 1.1-2 1.7-3.4 1.7-.9 0-1.8-.3-2.5-.8L80 130c-1.8 1.1-3.8 1.8-5.8 2.3v7.1c0 2.3-1.9 4.2-4.2 4.2-2.3 0-4.2-1.9-4.2-4.2V132c-2-.4-4-1.2-5.8-2.3l-4.7 5.1c-.2.3-.5.6-.8.8-.7.6-1.6.8-2.5.8-1.3 0-2.6-.6-3.4-1.7-1.4-1.9-1-4.5.8-5.9l5-4.7c-1.1-1.8-1.8-3.7-2.3-5.8H45c-2.3 0-4.2-1.9-4.2-4.2 0-2.3 1.9-4.2 4.2-4.2h7.1c
.4-2.1 1.2-4 2.3-5.8l-5.1-4.7c-.9-.9-1.3-2-1.3-3.2 0-1.2.5-2.3 1.3-3.1.8-.8 2-1.3 3.1-1.3 1.2 0 2.3.5 3.1 1.3l4.7 5.1c1.8-1.1 3.7-1.8 5.8-2.3v-7.1c0-2.3 1.9-4.2 4.2-4.2 2.3 0 4.2 1.9 4.2 4.2v7.1c2.1.4 4 1.2 5.8 2.3l5.1-5.1c.8-.6 1.7-.9 2.6-.9.9 0 1.8.3 2.5.8.9.7 1.5 1.7 1.6 2.8.2 1.1-.1 2.2-.8 3.1l-5.1 5.1c1.1 1.8 1.8 3.8 2.3 5.8h7.1c2.3 0 4.2 1.9 4.2 4.2.2 2.4-1.7 4.3-4.1 4.3zm28.9-11.5c.3-.1.6.1.7.3l1.7 4.7c.1.3-.1.6-.3.7h-.2c-.2 0-.4-.1-.5-.4l-1.7-4.7c-.1-.2.1-.5.3-.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M70.3 103.8c-5.6 0-10.2 4.6-10.2 10.2s4.6 10.2 10.2 10.2 10.2-4.6 10.2-10.2c.1-5.6-4.5-10.2-10.2-10.2zM137.7 124.4l-.9.6.9 2.1v-2.7zM135.3 121.7s0 .1 0 0l2.4-1.5v-.1l-2.4 1.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M134.8 126.3l-.5.3v39.1c0 1.9-.3 2.2-2.2 2.2H8.1c-1.9 0-2.2-.3-2.2-2.2V65.8h107c-.2-.8-.4-1.4-.4-1.8-.1-.6.3-1.2.9-1.3.6-.1 1.2.3 1.3.9.1.4.3 1.2.6 2.2h3.4l-.8-2.4c-.1-.3.1-.6.4-.7.3-.1.6.1.7.4 0 0 .3 1 .9 2.7h14.5v39.7c.6 1.5 1.3 3.1 1.8 4.4.4-.9.9-1.6 1.6-2.3V49.7c0-2.3-1.9-4.2-4.2-4.2H6.8c-2.3 0-4.2 1.9-4.2 4.2v118c0 2 1.8 3.7 3.9 3.7h127.3c1 0 1.9-.4 2.6-.9-.8-1.6-1.2-3.4-1.3-5.3 0-1.5.9-2.7 2.2-3.3-.8-.8-1.1-2-.7-3.1l1.1-2.9v-23.4c-1-2.1-2-4.3-2.9-6.2zm-18.1-73.5c.3-.1.5 0 .6.3l1.9 5.3v.1c.1.3-.1.5-.4.6h-.1c-.2 0-.4-.1-.4-.3l-1.9-5.3c-.1-.4.1-.6.3-.7zm-1.7.4c0-.3.2-.5.5-.5s.5.2.5.5v5.3c0 .3-.2.5-.5.5s-.5-.2-.5-.5v-5.3zm-1.5.5c0-.3.2-.5.5-.5s.5.2.5.5v4.8c0 .3-.2.5-.5.5s-.5-.2-.5-.5v-4.8zm-1.4-1c0-.3.2-.5.5-.5s.5.2.5.5v5.8c0 .3-.2.5-.5.5s-.5-.2-.5-.5v-5.8zm-77.7 2.7c0-1.7 1.4-3.1 3.1-3.1h63.6c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.7-1.4 3.1-3.1 3.1H37.5c-1.7 0-3.1-1.4-3.1-3.1v-.3zM22 52.7c1.6 0 2.9 1.3 2.9 2.9 0 1.6-1.3 2.9-2.9 2.9-1.6 0-2.9-1.3
-2.9-2.9.1-1.6 1.3-2.9 2.9-2.9zm-9.2 0c1.6 0 2.9 1.3 2.9 2.9 0 1.6-1.3 2.9-2.9 2.9-1.6 0-2.9-1.3-2.9-2.9.1-1.6 1.3-2.9 2.9-2.9z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M129.1 125.6c-.1.1-.2.2-.4.2-.2.1-.4.1-.6.1.2 0 .4 0 .6-.1.2 0 .3-.1.4-.2l4.1-2.5v-.1l-4.1 2.6z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M137.7 120.2v.1l2.2-1.5M139 115.8c-.2-.5-.2-1-.3-1.5 0 .5.1 1 .3 1.5z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M133.8 171.4H6.5c-2.2 0-3.9-1.6-3.9-3.7v-118c0-2.3 1.9-4.2 4.2-4.2h126.6c2.3 0 4.2 1.9 4.2 4.2V107.6c.6-.7 1.4-1.3 2.2-1.8V81.2h27.6c.1-.2.2-.4.2-.6 0-.2.3-.2.3 0 .1.2.1.4.2.6h14.5c.6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1h-42.8V49.7c0-3.6-2.9-6.5-6.5-6.5H6.8c-3.6 0-6.5 2.9-6.5 6.5v118c0 3.3 2.8 5.9 6.1 5.9h127.3c1.4 0 2.7-.5 3.7-1.2-.4-.6-.8-1.3-1.1-1.9-.7.5-1.6.9-2.5.9z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M137.7 127.1l-.9-2.1-1.9 1.2c.9 2 1.9 4.1 2.9 6.3V156l1.2-3.2c.2-.5.6-1 1-1.3v-14.1c2.6 5.5 5.2 11 7.4 15.2h.4c.7 0 1.4.1 2.1.2-3.1-6.1-6.1-12.1-8.7-17.9-.2-.5-.7-1.5-1.2-2.7V123l-2.2 1.4v2.7h-.1z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M134.3 65.8h-14.5c-.6-1.7-.9-2.7-.9-2.7-.1-.3-.4-.4-.7-.4-.3.1-.4.4-.4.7l.8 2.4h-3.4c-.3-1-.5-1.8-.6-2.2-.1-.6-.7-1-1.3-.9-.6.1-1 .7-.9 1.3.1.4.2 1 .4 1.8H6v99.8c0 1.9.3 2.2 2.2 2.2h124c1.9 0 2.2-.3 2.2-2.2v-39.1l-1.1.7v38.4c0 .6 0 .9-.1 1-.1 0-.4.1-1 .1H8.2c-.6 0-.9 0-1-.1 0-.1-.1-.4-.1-1V67h106.2c1.3 4.6 4 13.3 7.9 24.2h.1c2.5 7.2 7.1 19.3 9.6 25.7l2-1.2c-2.7-6.9-9.9-26.7-11.5-31l.1.5c-2.8-8.1-4.7-14.4-5.8-18.2h3.4c.8 2.2 1.8 5.4 3.2 9.2.1.2.3.4.5.4h.2c.3-.1.4-.4.3-.7-1.3-3.6-2.3-6.6-3.1-8.8h13v35.8l-.3-.9c-.1-.3-.4-.4-.7-.3-.3.1-.4.4-.3.7.3.8.8 2.1 1.4 3.5v9.5l.2-.1.9-.6v-6c.4 1.1.8 2.1 1.2 3l.6-1.8c-.5-1.3-1.2-2.9-1.8-4.4V65.8h-.1zM12.8 58.4c1.6 0 2.9-1.3 2.9-2.9 0-1.6-1.3-2.9-2.9-2.9-1.6 0-2.9 1.3-2.9 2.9.1 1.7 1.3 2.9 2.9 2.9zM22 58.4c1.6 0 2.9-1.3 2.9-2.9 0-1.6-1.3-2.9-2.9-2.9-1.6 0-2.9 1.3-2.9 2.9.1 1.7 1.3 2.9 2.9 2.9zM37.5 58.8h63.6c1.7 0 3.1-1.4 3.1-3.1v-.3c0-1.7-1.4-3.1-3.1-3.1H37.5c-1.7 0-3.1 1.4-3.1 3.1v.3c0 1.7 1.4 3.1 3
.1 3.1z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M95.6 109.8h-7.1c-.4-2.1-1.2-4-2.3-5.8l5.1-5.1c.7-.9 1-2 .8-3.1-.2-1.1-.7-2.1-1.6-2.8-.7-.6-1.6-.8-2.5-.8-.9 0-1.8.3-2.6.9l-5.1 5.1c-1.8-1.1-3.7-1.8-5.8-2.3v-7.1c0-2.3-1.9-4.2-4.2-4.2-2.3 0-4.2 1.9-4.2 4.2v7.1c-2.1.4-4 1.2-5.8 2.3l-4.7-5.1c-.8-.8-2-1.3-3.1-1.3-1.2 0-2.3.5-3.1 1.3-.8.8-1.3 2-1.3 3.1 0 1.2.5 2.3 1.3 3.2l5.1 4.7c-1.1 1.8-1.8 3.7-2.3 5.8H45c-2.3 0-4.2 1.9-4.2 4.2 0 2.3 1.9 4.2 4.2 4.2h7.1c.4 2.1 1.2 4 2.3 5.8l-5 4.7c-1.9 1.4-2.2 4.1-.8 5.9.8 1.1 2 1.7 3.4 1.7.9 0 1.8-.3 2.5-.8.3-.2.6-.5.8-.8l4.7-5.1c1.8 1.1 3.7 1.8 5.8 2.3v7.4c0 2.3 1.9 4.2 4.2 4.2 2.3 0 4.2-1.9 4.2-4.2v-7.1c2.1-.4 4-1.2 5.8-2.3l5.1 5.1c.7.6 1.6.8 2.5.8 1.3 0 2.6-.6 3.4-1.7 1.1-1.5 1.1-3.6-.1-5.1l-5.1-5.1c1.2-1.8 2.1-3.7 2.6-5.8h7.1c2.3 0 4.2-1.9 4.2-4.2.2-2.3-1.7-4.2-4.1-4.2zm-25.3 14.5c-5.6 0-10.2-4.6-10.2-10.2s4.6-10.2 10.2-10.2 10.2 4.6 10.2 10.2c.1 5.6-4.5 10.2-10.2 10.2zM115.3 21.3h1.1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-1.1c-.3 0-.6.2-.6.6 0 .4.3.6.6.
6zM126.4 21.3h4.5c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-4.5c-.3 0-.6.2-.6.6.1.4.3.6.6.6zM34.1 20.6h13.4c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6H34.1c-.3 0-.6.2-.6.6.1.4.3.6.6.6zM82 8.5c.1.1.3.2.4.2.1 0 .2 0 .3-.1.2-.2.3-.5.1-.8-.7-.9-1.5-1.8-2.3-2.5-.2-.2-.6-.2-.8 0-.2.2-.2.6 0 .8.8.7 1.6 1.5 2.3 2.4zM109.7 21c.1.2.3.3.5.3h.6c.3 0 .6-.2.6-.6 0-.4-.2-.6-.6-.6h-.3c-.2-.4-.6-1.2-1.2-2.1-.2-.3-.5-.3-.8-.2-.3.2-.3.5-.2.8.9 1.3 1.3 2.2 1.4 2.4zM59.6 4.4c.1 0 .2 0 .3-.1 1.6-1.2 3.7-2.1 6.4-2.4 2.1-.3 4-.2 5.9.2.3.1.6-.1.7-.4.1-.3-.1-.6-.4-.7-2-.4-4.1-.5-6.3-.2-2.9.4-5.2 1.3-6.9 2.7-.2.2-.3.5-.1.8 0 0 .2.1.4.1zM91.5 7.8c1.3-.4 2.7-.5 4.3-.2 2.3.4 4.8 1.8 7.2 4.1.1.1.2.2.4.2.1 0 .3-.1.4-.2.2-.2.2-.6 0-.8-2.6-2.5-5.2-3.9-7.7-4.4-1.8-.3-3.4-.3-4.9.2-.3.1-.4.4-.4.7.1.4.4.5.7.4zM84.9 13c.1.2.3.3.5.3.1 0 .2 0 .2-.1.3-.1.4-.5.3-.7-.1-.3-.3-.6-.5-1-.1-.3-.5-.4-.8-.2-.3.1-.4.5-.2.8.2.3.3.7.5.9zM56.2 14.5c.1 0 .1 0 0 0 .4 0 .6-.3.6-.6 0-.4-.1-.7-.1-1.1 0-.3-.3-.5-.6-.5H56c-.2.1-.4.3-.4.6 0 .4.1.8.1 1.1 0 .1 0 .
1.1.2 0 .2.2.3.4.3zM58.3 20.4c.1-.2.1-.4 0-.5 0 0-.3-.7-.6-1.7-.1-.3-.4-.5-.7-.4-.3.1-.5.4-.4.7.1.4.3.7.4 1h-.7c-.2.1-.4.3-.4.5 0 .3.2.6.6.6H57.9c.2 0 .3-.1.4-.2z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M33.7 25.5h97.9c.6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1h-22.8c-2-3.7-7.1-11.7-13.4-12.9-8.4-1.6-10 6.7-10 6.7S79.8 2.6 65.8 4.5c-6.5.9-9 4.2-9.8 7.8h.1c.3 0 .6.2.6.5 0 .4.1.7.1 1.1 0 .3-.2.6-.5.6h-.1c-.2 0-.4-.1-.5-.3-.1 1.9.1 3.8.5 5.3H57c-.1-.3-.2-.6-.4-1-.1-.3.1-.6.4-.7.3-.1.6.1.7.4.3 1 .6 1.7.6 1.7.1.2.1.4 0 .5-.1.2-.3.3-.5.3h-1.3c.4 1.5.9 2.5.9 2.7H33.7c-.6 0-1.1.5-1.1 1.1 0 .5.5 1 1.1 1z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M205.5 42.3c.1 0 .3-.1.4-.2.6-.7 1.5-1.1 2.6-1.4.3-.1.5-.4.4-.7-.1-.3-.4-.5-.7-.4-1.3.4-2.4.9-3.1 1.7-.2.2-.2.6 0 .8.1.2.3.2.4.2zM212.7 40.5c.4.1.7.2 1 .3h.2c.2 0 .5-.1.5-.4.1-.3-.1-.6-.4-.7-.4-.1-.8-.2-1.1-.3-.3-.1-.6.1-.7.4 0 .4.2.7.5.7zM238.3 50.7h3.3c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-3.3c-.3 0-.6.2-.6.6 0 .4.3.6.6.6zM221.2 46.7c.3-1 1.2-3.2 3.8-3.2.3 0 .7 0 1 .1 1.6.3 3.2 1.3 4.8 3 .2.2.6.2.8 0 .2-.2.2-.6 0-.8-1.8-1.9-3.6-3-5.4-3.4-.4-.1-.8-.1-1.2-.1-3.5 0-4.6 3-4.9 4-.1.3.1.6.4.7h.2c.1 0 .2 0 .3-.1.1.1.2 0 .2-.2zM205.5 50.6c.1-.2.1-.4 0-.5l-.1-.1c-.1-.3-.4-.4-.7-.3-.1 0-.1.1-.2.1h-12.7c-.3 0-.6.2-.6.6 0 .3.2.6.6.6H205c.2-.1.4-.2.5-.4z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M191.7 54.6h54.4c.6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1h-12.9c-1.1-2.1-3.9-6.5-7.4-7.2-2.4-.5-3.8.5-4.6 1.6 0 .1-.1.2-.2.3-.6 1-.8 1.9-.8 1.9s-3.1-8-10.9-7c-5.7.8-6 5-5.4 7.8h.7s.1-.1.2-.1c.3-.1.6 0 .7.3l.1.1c.1.2.1.4 0 .5-.1.2-.3.3-.5.3h-.9c.2.9.5 1.4.5 1.5h-13.2.2c-.6 0-1.1.5-1.1 1.1-.1.6.4 1.1 1.1 1.1z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M107.4 231.1c-4 0-5.8-2.5-6.2-4.6l-.1-.5c-7 .5-12.1 2.1-12.1 4 0 2.3 7.3 4.1 16.3 4.1s16.3-1.8 16.3-4.1c0-1.4-2.7-2.6-6.7-3.3-.2.7-.6 1.3-1 1.9-2 2.4-5.7 2.5-6.5 2.5z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M227.3 225.7c-.1-.3-.1-.6-.1-1 0 .4 0 .7.1 1zM228 226.5h-.1.1zM226.9 216v0zM199.5 218.8c.3.3.5.6.8.9-.3-.3-.6-.6-.8-.9z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M237.7 208.7c1-.3 1.9-.5 2.8-.8h.1c6.5-2 12.4-4.7 17.4-7.6-7.2 3.5-15 5-20 5.6 0 1-.1 1.9-.3 2.8z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M241.9 163c.1-.2.2-.4.2-.6 0 .2-.1.4-.2.6zM234.1 70.2c-.3 0-.5-.1-.8-.1-.3 0-.7 0-1 .1.3 0 .7-.1 1-.1.2 0 .5 0 .8.1zM232 70.2c-2.5.4-4.6 2.2-5.5 4.5.9-2.3 3-4 5.5-4.5zM219.1 84.9c0-.1 0-.1 0 0 0-.1 0-.1 0 0zM221.2 79.8c.5-.5 1.1-.9 1.7-1.3-.6.3-1.2.8-1.7 1.3zM226 76.7c-.4.3-.7.7-1 1-.7.1-1.4.4-2.1.7.6-.3 1.3-.6 2.1-.7.3-.3.7-.6 1-1zM207.3 226.3s0-.1 0 0h-.1c0-.1.1 0 .1 0zM263.6 172.3c-.4.1-.8.3-1.2.4.4-.1.8-.2 1.2-.4zM248.7 65.6h.8c-.3.1-.5 0-.8 0zM237.3 69.6c1.3-.5 2.6-.9 4-1.2-1.4.4-2.7.8-4 1.2zM189.2 186.5v0zM252.5 139.1h-1c.3.1.6.1 1 0zM272.6 164c-.5 1.3-1.7 3.4-3.8 5.3 2.2-2 3.3-4.1 3.8-5.3zM262.6 67.9h-.6.6zM219.1 84.9c0 .3 0 .7.1 1-.2.3-.3.6-.5 1 .2-.3.3-.7.5-1 0-.3-.1-.6-.1-1zM202.8 96.1c.1.1.1.2.2.2.1.1.3.2.4.3-.1-.1-.3-.2-.4-.3-.1 0-.2-.1-.2-.2zM202.5 90.4c-.1-.1-.2-.1-.2-.2-.1-.1-.1-.2-.2-.3 0 .1.1.3.2.3l.2.2zM259.2 140.3h-.3.3zM277.1 177.5c-.1 0-.1 0 0 0-.1 0-.1 0 0 0-.1.1-.1 0 0 0zM274.7 180c0-.1 0-.1 0 0-.2 0-.4-.1-.6-.1.2 0
.4 0 .6.1z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M235.8 218c-.5 1.4-1.1 3.2-2 4.9-1.5 3.1-3.5 5.9-5.8 5.9-.7 0-1.3-.2-1.8-.6-.6-.5-1.2-.9-1.4-5.4-.1-1.5-.1-3.5-.1-6.2-.5 0-1-.1-1.6-.2l-.7-.2c0 2.8 0 4.9.1 6.6.2 5.1 1 6.1 2.4 7.2 1 .8 2.1 1.2 3.4 1.2 3.2 0 6-2.7 8.4-8.1.6-1.3 1.2-2.8 1.7-4.4.7-2 1.3-4.8 1.9-8.2-.9.3-1.9.5-2.9.8-.5 2.6-1.1 4.9-1.6 6.7zM265 198.7c-2.4 1.6-5 3.1-7.8 4.7 1.6-.7 3.1-1.4 4.6-2.3h.2c3.7 0 7.1-.5 10.2-1.4-1.7-.2-3.3-.6-4.7-1.3-.8.1-1.6.2-2.5.3z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M284.9 173c.8-.7 1.8-1.2 2.9-1.2.4 0 .7 0 1 .1h.1c-.7-.6-1.5-1.1-2.4-1.2-.3-.1-.6-.1-.8-.1-.8 0-1.6.2-2.3.6l-.2.2c.6.6 1.2 1.1 1.7 1.6zM287.7 188c.3-.6.6-1.1.9-1.7-.4.3-.8.6-1.3.8.1.4.3.6.4.9z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M266.3 154.9c-1.2.6-2.1.9-2.7 1.2-.3.1-.6.2-.8.3-.2.1-.3.1-.3.1-.2.1-.4.1-.7.1-.6 0-1.2-.3-1.7-.7-6.4 3.3-13.7 6.8-16.1 7.9-.1.2-.2.4-.2.6.8-.1 1.7-.1 2.5-.1 3.5 0 6.8.6 9.7 1.8 2.7 1.1 5 2.5 7 4.3 6.4-2.4 7.9-7.8 7.9-8 .2-.9.9-1.5 1.8-1.7h.3c.8 0 1.5.4 1.9 1.1.1.2 1.7 2.9 2.3 7.1 1 .2 2 .6 2.9 1-.5-5.5-2.5-9.1-2.9-9.7-.9-1.4-2.4-2.3-4-2.3-.2 0-.5 0-.7.1-1.9.3-3.4 1.7-3.9 3.5 0 .1-1 3.6-5.1 5.7-1.9-1.4-4-2.7-6.4-3.7-1.3-.6-2.8-1-4.2-1.3 5.1-2.5 10.1-5 13.8-7.1-.1-.1-.1-.2-.2-.2 0-.1-.1-.1-.2 0z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M265.3 137.7h.5-.5zM246.3 166.4h-.3H246.3z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M284.3 126.3l1.2-1.8c4.6-2.2 7.4-7.2 6.8-12.3v-.2c1.4-2.3 2-5 1.7-7.7-.3-2.4-1.3-4.6-2.8-6.4-.3-2.1-.7-4.1-1.3-6.1v-1c0-4-2-7.7-5.3-9.9-2.8-4.1-6.5-7.8-10.6-10.6-1.8-4.4-6.2-7.3-11-7.3-1.4 0-2.9.3-4.3.8-.8-.2-1.6-.4-2.4-.5-2.1-1.6-4.7-2.5-7.3-2.5-.5 0-1 0-1.5.1-2.2.3-4.4 1.2-6.1 2.6-2.1.4-4.2 1.1-6.2 1.9-.6-.1-1.1-.1-1.7-.1-5.2 0-9.9 3.5-11.4 8.4-4.4 1.8-7.4 6.2-7.4 11.1v.2c-.2.5-.4 1-.6 1.4-.4.4-.8.7-1.2 1.2-.1-2.2-1.1-4.2-2.2-6.3-.2-.4-.4-.8-.6-1.3-.9-1.8-2.7-3-4.6-3-3.8 0-5.5 3.8-6.2 5.3-1 2.1-2.3 5.9-1.3 9-.4 3.7.2 6.5 1.8 8.2.1.6.2 1.3.4 1.8-8.4 3.3-26.4 11.2-32.7 19.4-1.9 2.4-2.2 5.7-1 9.8 2.6 8.9 10.6 18.2 15.5 20.1 6.2 2.3 14.3 3.8 22.5 4.3-4.1 1.6-7.4 2.9-10 4.1.6.7 1.1 1.4 1.6 2.2 2.6-1.1 5.7-2.3 9.5-3.9 1.9-1.6 3.9-3.1 6-4.5h-2c-9.9 0-19.7-1.6-27.1-4.3-5.2-1.9-12.1-11.9-14-18.4-.9-3.3-.7-5.8.6-7.6 5.6-7.3 22.8-15.2 33.8-19.4-.6-1.4-.9-3-1.1-4.6l-.1-.1c-1.4-1.1-1.9-3.5-1.5-7.1-1.1-2.3.3-6 1.1-7.6 1.2-2.6 2.4-3.8 3.9-3.8 1 0 1
.9.6 2.4 1.6.2.5.5.9.7 1.3 1.2 2.3 2.2 4.3 1.8 6.3.7 1 1.3 2.1 1.4 3.4.7.6 1.3 1.1 1.9 1.7-.1-.3-.1-.7-.1-1.1 0-2 1-3.8 2.6-4.8.3-.8.7-1.7 1.1-2.5v-.7c0-4.3 2.9-8 7-9.1l.1-.1c.8-4.4 4.7-7.8 9.3-7.8.7 0 1.3.1 2 .2 2.3-1 4.6-1.7 7-2.1 1.5-1.4 3.3-2.2 5.3-2.5.4 0 .8-.1 1.2-.1 2.3 0 4.5.9 6.2 2.4 1.2.2 2.4.5 3.6.8 1.3-.6 2.7-.9 4.1-.9 4.1 0 7.7 2.6 9 6.4 4.3 2.8 8 6.5 10.8 10.8 2.8 1.7 4.6 4.8 4.6 8.1 0 .4 0 .8-.1 1.3.7 2.3 1.2 4.6 1.5 7 1.5 1.5 2.5 3.4 2.7 5.6.3 2.5-.4 4.9-1.8 6.8.1.4.2.7.2 1.1.5 4.3-2 8.5-6 10-.6 1-1.2 1.9-1.8 2.8-.5 3.2-2.7 5.8-5.7 6.9-1.6 4.5-5.8 7.5-10.7 7.5-.5 0-1 0-1.5-.1-1 1.6-2.8 2.7-4.9 2.7-1.4 0-2.7-.5-3.7-1.3-1.3.2-2.7.2-4 .2-.4 1.9-1 3.9-1.6 5.8 8.1-1.9 16.9-3.8 18-3.9h.8c.1-.1.3-.2.4-.3l.6-.5c.2-.2.4-.3.6-.4.4-.3.8-.6 1.2-.8-.1 0-.1-.1-.2-.1 2.3-1 4.3-2.5 5.8-4.5.2-.4.4-.7.7-.9.3-.5.5-.9.8-1.4 2.8-2 5.1-4.9 5.8-8.4z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M287.7 101.9c-.4-.6-.9-1.1-1.4-1.5.6.4 1 .9 1.4 1.5zM286.9 111.2c.2.6.4 1.2.5 1.9 0 .2 0 .5.1.7 0-.2 0-.5-.1-.7-.1-.7-.3-1.3-.5-1.9zM289 106c0-.3 0-.6-.1-.9 0-.4-.1-.7-.2-1.1.1.3.2.7.2 1.1.1.3.1.6.1.9zM263.6 137.5c-.3-.1-.7-.1-1-.2h-.1.1c.3.1.6.1 1 .2zM259.6 140.2c.4-.1.7-.2 1.1-.4-.4.2-.7.4-1.1.4zM188.5 192.2v0zM218.2 88.3c-.2.4-.4.9-.5 1.3-.2.1-.3.1-.5.2.1-.1.3-.2.5-.2.1-.4.3-.9.5-1.3zM186 170.6c0-.1-.1-.1-.1-.2 0 .1 0 .2.1.2zM215.8 97.7c0-.4.1-.9.2-1.3-.1.4-.1.8-.2 1.3z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M207.5 230.7c1.7 0 3.3-.8 4.3-2.2.9-1.2 1.3-2.3.7-5.6-.3-2-1.1-4.8-2.2-8.8 1 0 2 .1 3 .1h2.1l-3.8-1.1-4.8-.6c1.6 5.2 2.4 8.5 2.9 10.6.6 3.2.3 3.7-.2 4.3-.5.8-1.4 1.2-2.3 1.2-1.7 0-3.4-1.3-6.6-4.9-.8-.9-1.8-2-2.9-3.3-3.3-3.8-5.6-8.6-7.1-12.7-1-.5-2-1.1-2.9-1.7 1.6 4.8 4.3 11 8.4 15.8.6.8 1.3 1.5 1.8 2.1 4.4 4.8 6.7 6.8 9.6 6.8zM185.9 201.9c1.2.9 2.4 1.7 3.6 2.5l-.3-.9c-2.1-3-3.1-7-3-11.4-.4-.3-.8-.5-1.2-.8-.2-.2-.3-.5-.1-.8.2-.2.5-.3.8-.1.2.1.4.3.6.4.1-1 .2-2.1.3-3.2-.8.3-1.6.5-2.4.6-.5 5.1 0 9.8 1.7 13.7z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M206.8 158.8c.5-.4 1-.9 1.6-1.3-.6.4-1.1.9-1.6 1.3z"/>
+ <path fill="url(#a)" fill-rule="nonzero" d="M237.4 200.4c-.1 1-.2 2-.2 2.9 4.1-.4 10.5-1.6 17.1-4.5 1.7-.8 3.3-1.6 4.7-2.6-.7-.2-1.4-.6-1.9-1.1-3.5 1.9-8.3 4-14.2 4.8-1.9.2-3.7.4-5.5.5z"/>
+ <path fill="url(#b)" fill-rule="nonzero" d="M268.8 169.3c1.6-.6 3.4-.9 5.1-.9.4 0 .7 0 1.1.1-.4-2.3-1.1-4-1.5-4.9-.1-.3-.3-.5-.3-.6v-.1s0 .1-.1.3c0 .1-.1.2-.1.3-.1.1-.1.3-.2.5-.7 1.2-1.8 3.3-4 5.3z"/>
+ <path fill="url(#c)" fill-rule="nonzero" d="M274.9 176.9c-.3 0-.6-.1-.9-.1-2.6 0-5 1.4-6.3 3.6-.3.5-.7 1-1.1 1.4l1.6.4c0-.1.1-.2.2-.3l.9-.7c.2-.2.6-.1.8.1.2.2.1.6-.1.8l-.5.4.9.2c.8.2 1.5.6 2 1.2.7-1.4 1.3-2.8 1.8-4.1.2-1 .5-1.9.7-2.9z"/>
+ <path fill="url(#d)" fill-rule="nonzero" d="M189.9 156.3c-2.8-1.8-6-2.6-9.1-2.6-5.6 0-11.1 2.8-14.3 7.8-5 7.9-2.7 18.3 5.2 23.3 2.8 1.8 6 2.6 9.1 2.6 2.1 0 4.2-.4 6.1-1.1.3-1.5.7-3.1 1.2-4.6-.5 0-1-.1-1.5-.4-1.5-.8-2.1-2.6-1.3-4s2.6-1.9 4.1-1.1c.3.2.5.3.7.5.6-1.3 1.3-2.6 2-3.9-3.2.4-4.2.5-4.7.5h-.6c-1-.1-2.3-.6-2.9-1.8-.5-.8-.7-2.3.5-4.3.5-.7 1.1-1.9 10.6-5.9-1.4-1.9-3-3.7-5.1-5zm-14.1 2.1c1.7 0 3.1 1.3 3.1 2.9 0 1.6-1.4 2.9-3.1 2.9-1.7 0-3.1-1.3-3.1-2.9 0-1.6 1.4-2.9 3.1-2.9zm-8.7 10.8c.8-1.4 2.6-1.9 4.1-1.1 1.5.8 2.1 2.6 1.3 4s-2.6 1.9-4.1 1.1c-1.4-.8-2.1-2.6-1.3-4zm13.4 12.7c-.6 1-1.9 1.5-3.3 1.2l1.7 1.7c.2.2.2.6 0 .8-.1.1-.3.2-.4.2-.1 0-.3 0-.4-.1-3.1-2.9-6.2-6.2-9.2-9.8-.2-.2-.2-.6.1-.8.2-.2.6-.2.8.1 1.2 1.5 2.5 2.9 3.7 4.3 0-.4.1-.8.3-1.1.4-.7 1.1-1.2 2-1.3l-.9-1.1c-.2-.2-.2-.6.1-.8.2-.2.6-.2.8.1l1.6 1.9c.4.1.8.2 1.1.4 1.9.9 2.8 2.9 2 4.3zm8.2-19.6c-.8 1.3-2.6 1.5-4 .7-1.4-.9-1.9-2.6-1.1-3.9.8-1.3 2.6-1.5 4-.7 1.4.9 1.9 2.7 1.1 3.9z"/>
+ <path fill="url(#e)" fill-rule="nonzero" d="M204.7 160.7c-9.4 3.5-17.8 8.2-17.9 8.3-.1.1-.2.1-.3.1-.2 0-.4-.1-.5-.3-.2.3-.3.6-.3.9v.6c0 .1 0 .2.1.2 0 .1.1.1.1.2.4.5 1.2.5 1.2.5H188c.2 0 .4 0 .6-.1.3 0 .6-.1.9-.1h.2c.3 0 .6-.1.9-.1h.2c.4 0 .7-.1 1.1-.2h.1c.9-.1 2-.3 3.1-.5 2.9-4 5-6.2 5.1-6.4.2-.2.6-.2.8 0 .1.1.2.2.2.4 1.1-1.2 2.2-2.3 3.5-3.5z"/>
+ <path fill="url(#f)" fill-rule="nonzero" d="M187.9 167.1c-.1 0-.1.1-.2.1s-.1.1-.2.1c1.1-.6 2.7-1.4 4.8-2.5-1.8.9-3.4 1.7-4.4 2.3z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M213.3 204.7c-.7-.2-1.3-.7-1.7-1.2l-.4 1.3 1.9.5c.3-.1.7-.2 1-.3l-.8-.3z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M188.7 193.1c0 .1-.1.1-.1.1v1.6c0 .4.1.8.2 1.2 0 .2.1.4.1.5l.3 1.2c0 .2.1.3.1.5.1.4.3.8.4 1.2v.1c.8 1.6 2.9 4.5 8.2 5.4.3.1.5.3.4.6-.1.3-.3.5-.5.5h-.1c-2.7-.5-4.6-1.5-6-2.5l.3.9c.2.5.3 1 .5 1.5 1.4.7 2.7 1.2 4.1 1.7 2.4.8 4.8 1.4 7.2 1.9 0-.1-.1-.3-.1-.4 0-.1-.1-.3-.1-.4-.2-.5-.4-1-.5-1.5-.1-.3-.2-.6-.3-.8h.2c0-.6 0-1.1.2-1.7l1.2-4.1c-.7-.2-1.5-.4-2.2-.6-.3-.1-.5-.4-.4-.7.1-.3.4-.5.7-.4.7.2 1.5.4 2.2.6l4.1-14.3c.7-2.4 2.9-4 5.4-4 .5 0 1 .1 1.6.2l15.3 4.4c2-6.2 3.9-13.4 9.5-22.5.5-1.1 1.1-2.1 1.4-2.4.6-.4 12.5-5.9 18-8.5l.1-.1c.1-.2.3-.4.5-.7.3-.5.9-1.3 1.8-2.3.8-1 1.8-2 2.7-2.9l.6-.6c-3.9.8-12 2.6-19.4 4.4.4-.9.7-1.7 1-2.6.1-.2.1-.4.2-.6.5-1.4.9-2.9 1.3-4.3 1-5.6.1-9.3.1-9.4-.1-.3.1-.5.3-.6-.3-2.1-.8-3.8-1.6-5.3-3.1-1-5.4-3.9-5.4-7.4v-.1c-.8-1-1.4-2-2-2.9-.4-.4-.9-.9-1.3-1.4-2.1-2.7-3.1-5.6-3.5-7.3-.2-.4-.3-.7-.5-1.1-.7-.4-1.3-1-1.8-1.6-.8-.6-1.6-1.4-2-2.3-.5-1.3-.7-2.3-.6-3.2l-3.2-.1c-.2 0-.4-.2-.5-.4-.7 0-1.4 0-2.1.1-.4.6-1 1.2-1.7 1.5v
.1c0 .3-.2.6-.5.6h-.6c-1.5 0-2.7-.8-3.2-1.2l-1.4.4c1.1 1.2 2.1 2.8 2.1 4.8 0 4.6-4.6 6.2-4.7 6.2h-.2c-.2 0-.4-.1-.5-.3-.8.2-1.6.3-2.5.1-.2 0-.5-.2-.7-.3h-.2c-.2 0-4.3-.9-6.1-6.6-.1-.3 0-.5 0-.7-.2.1-.4.1-.6.2-.2.1-.3.1-.5.2-.3.1-.5.2-.8.3-.2.1-.4.1-.5.2-.3.1-.5.2-.8.3-.2.1-.4.1-.5.2-.3.1-.5.2-.8.3-.2.1-.4.2-.6.2-.3.1-.5.2-.8.3-.2.1-.4.2-.6.2-.3.1-.5.2-.8.3l-.6.3c-.3.1-.5.2-.8.3l-.6.3c-.3.1-.5.2-.8.3l-.6.3c-.5.2-.9.4-1.4.6-.3.1-.5.2-.8.3-.2.1-.4.2-.7.3-.2.1-.5.2-.7.3-.2.1-.5.2-.7.3-.2.1-.5.2-.7.3-.2.1-.4.2-.7.3-.2.1-.5.2-.7.3l-.6.3c-.2.1-.5.2-.7.4l-.6.3c-.2.1-.5.2-.7.4l-.6.3c-.2.1-.5.3-.7.4l-.6.3c-.2.1-.5.3-.7.4-.2.1-.4.2-.5.3-.3.1-.5.3-.7.4-.2.1-.3.2-.5.3-.3.2-.7.4-1 .6-.1.1-.2.1-.3.2-.3.2-.7.4-1 .6-.1.1-.2.2-.4.2-.2.2-.5.3-.7.5-.1.1-.3.2-.4.3-.2.1-.4.3-.6.4-.1.1-.3.2-.4.3-.2.1-.4.3-.6.4-.1.1-.3.2-.4.3-.2.1-.4.3-.5.4-.1.1-.3.2-.4.3-.2.1-.3.3-.5.4-.1.1-.2.2-.4.3-.2.1-.3.3-.5.4l-.3.3c-.2.1-.3.3-.4.4l-.3.3c-.2.2-.3.3-.4.5-.1.1-.1.2-.2.2-.2.2-.4.5-.6.7-.3.4-.5 1-.7 1.6v.1c.5 0 .9.4 1 .8
0 .1 6.4 15.3 12 18.1 5.1 2.5 24.4 4.5 39.2 3.2 9-1.8 12.1-3.7 19.4-11 2.3-2.3 3.5 6.1-.8 10.1-3.6 3.4-12.9 4.7-23.1 4.7-.8.4-1.6.9-2.4 1.4-.1.1-.3.2-.4.3-.6.3-1.1.7-1.6 1-.2.1-.4.3-.6.4-.8.5-1.6 1.1-2.3 1.6-.3.3-.7.5-1 .8-.4.3-.7.6-1.1.8-.5.4-1.1.9-1.6 1.3-.1 0-.1.1-.2.1-4.6 1.8-10.2 4-14.3 5.9-2.1 1-3.8 1.9-4.8 2.5-.6.4-1.1.7-1.2 1-.1.1-.1.3-.2.4.1.2.3.3.5.3.1 0 .2 0 .3-.1.1-.1 8.5-4.8 17.9-8.3-1.2 1.1-2.4 2.3-3.5 3.5 0 .2 0 .3-.2.4 0 0-2.4 2.4-5.4 6.8-.2.3-.4.6-.6.8-.1.2-.2.4-.3.5-.4.6-.7 1.2-1 1.8-.1.2-.3.5-.4.7-.3.5-.6 1.1-.8 1.6-.1.3-.2.5-.4.8-.2.5-.5 1-.7 1.5-.1.3-.2.6-.3.8-.2.5-.4 1-.5 1.4-.1.3-.2.6-.3.8-.2.5-.3.9-.4 1.4-.1.3-.2.6-.2.8-.1.5-.2.9-.3 1.4 0 .2-.1.4-.1.6v.2c-.1.5-.2.9-.2 1.3 0 .3-.1.5-.1.8-.1.4-.1.9-.1 1.3 0 .2 0 .5-.1.7V191.3c.5 1.2.5 1.5.4 1.8zm7.3-73.4c.5-.8 1.8-2 3.7-2.4 0-.1-.1-.2-.1-.3v-3c0-.7.6-1.3 1.3-1.3.7 0 1.3.6 1.3 1.3v3c0 .1 0 .2-.1.3 1.9.4 3.2 1.6 3.7 2.4.5.8.3 1.8-.5 2.3-.3.2-.6.3-.9.3-.5 0-1.1-.3-1.4-.7-.1-.1-.8-1.1-2.2-1.1-1.4 0-2.1 1.1-2.2 1.1
-.5.8-1.5 1-2.3.5-.6-.6-.8-1.7-.3-2.4zm12 18.1c0 .1-.1.1-.1.2l-.4.3c-.9.8-1.8 1.4-2.6 1.9-.9.5-1.7 1-2.5 1.3-1.6.7-3.1 1.2-4.6 1.5-.4.1-.8.1-1.2.2-2.4.3-4.7.1-6.9-.5h-.1-.1c-2.1-.7-4.2-1.8-6-3.3.2-.1.4-.1.6-.1-.2 0-.4.1-.6.1-.3-.3-.6-.5-.9-.8-1.1-1.1-2.1-2.3-3-3.8-.5-.8-.9-1.6-1.3-2.5-.4-.9-.8-1.9-1.2-3l-.1-.5c-.1-.2 0-.5.3-.5h.2c.5.1 1.1.2 1.6.4.3.1.5.1.8.2.3 1.3.6 2.7.7 2.9.2.3 2.7 1.8 3.1 1.5.2-.2.6-1.8.9-3.2l.6.1c.5.1.9.3 1.4.4-.4 1.6-.8 3.3-.7 3.5.2.3 3.1 1 3.5.8.5-.2 1.7-1.4 2.8-2.7.2.1.4.1.6.2l7.5 2.4 3.8 1.3c.7.3 1.5.5 2.2.8l1.5.6c.1-.1.3.1.2.3zm20.6-15.8c-.3.2-.6.3-.9.3-.5 0-1.1-.3-1.4-.7-.1-.1-.8-1.1-2.2-1.1-1.4 0-2.1 1.1-2.2 1.1-.5.8-1.5 1-2.3.5-.8-.5-1-1.5-.5-2.3.5-.8 1.8-2 3.7-2.4 0-.1-.1-.2-.1-.3v-3c0-.7.6-1.3 1.3-1.3.7 0 1.3.6 1.3 1.3v3c0 .1 0 .2-.1.3 1.9.4 3.2 1.6 3.7 2.4.7.7.4 1.7-.3 2.2zm-37.1 72.8c.1-.3.5-.4.8-.2.3.2.6.4 1 .5.3.1.4.5.2.8-.1.2-.3.3-.5.3-.1 0-.2 0-.3-.1-.3-.2-.7-.4-1-.5-.2-.2-.3-.5-.2-.8z"/>
+ <path fill="url(#g)" fill-rule="nonzero" d="M203.6 209.1c0-.1 0-.1 0 0-.1-.2-.2-.3-.2-.4.1.1.1.2.2.4z"/>
+ <path fill="url(#h)" fill-rule="nonzero" d="M222.3 203.8l-1.9-.6c0 .1 0 .2-.1.3-.4 1.3-1.6 2.2-2.9 2.2-.3 0-.6 0-.9-.1l-2.4-.7c-.3.1-.7.2-1 .3l10 2.9 1.3-4.5c-.4.2-.8.3-1.3.3-.2.1-.5 0-.8-.1z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M227.1 224.7c0 .4.1.7.1 1 0 .3.1.5.2.6 0 .1.1.1.1.1.1.1.1.1.2.1H228.3s.1 0 .1-.1c.1 0 .1-.1.2-.1l.1-.1c.1 0 .1-.1.2-.1l.1-.1.2-.2.1-.1c.1-.1.2-.2.2-.3l.1-.1c.1-.2.3-.3.4-.5v-.1c.1-.2.2-.3.4-.5 0-.1.1-.2.1-.2.1-.1.2-.3.3-.4.1-.1.1-.2.2-.3.1-.1.1-.2.2-.3-1.4 0-2.9-.1-4.3-.1v.9c.2.2.2.5.2.9z"/>
+ <path fill="url(#i)" fill-rule="nonzero" d="M230 212.6c-.5 1.6-1.6 2.8-3.1 3.5v7.5c0 .4.1.7.1 1.1 0 .4.1.7.1 1 0 .3.1.5.2.6 0 .1.1.1.1.1.1.1.1.1.2.1H228.2s.1 0 .1-.1c.1 0 .1-.1.2-.1l.1-.1c.1 0 .1-.1.2-.1l.1-.1.2-.2.1-.1c.1-.1.2-.2.2-.3l.1-.1c.1-.2.3-.3.4-.5v-.1c.1-.2.2-.3.4-.5 0-.1.1-.2.1-.2.1-.1.2-.3.3-.4.1-.1.1-.2.2-.3.1-.1.1-.2.2-.3 0 0 0-.1.1-.1.1-.1.1-.2.2-.3.1-.2.2-.3.2-.5.1-.1.1-.2.2-.4s.2-.4.2-.5c.1-.1.1-.3.2-.4.1-.2.2-.4.2-.6.1-.1.1-.3.2-.4.1-.2.2-.5.3-.7 0-.1.1-.2.1-.4.1-.4.3-.7.4-1.1.1-.4.3-.9.4-1.4.1-.5.3-1 .4-1.5v-.1c.1-.5.2-1 .3-1.6v-.1c.1-.3.1-.6.2-1-1.3.1-3 .4-4.7.7z"/>
+ <path fill="url(#j)" fill-rule="nonzero" d="M240.1 167.1c-.1.2-.3.3-.5.3h-.2c-.3-.1-.4-.4-.3-.7.4-.9.9-2.1 1.4-3.2-5.6 9-7.5 16.2-9.5 22.5l.9.3c1.4.4 2.6 1.4 3.3 2.7.7 1.3.9 2.8.5 4.3l-4.9 17.1c1.6-.3 3.2-.6 4.7-.9v-.1-.1c.1-.6.2-1.1.2-1.7v-.1c0-.2.1-.5.1-.7 0-.1-.1-.2 0-.3.5-4.5 1.9-23.7 1.9-23.9 0-.3.3-.5.6-.5s.5.3.5.6c0 .1-.7 9.5-1.3 16.7 1.7-.1 3.5-.2 5.3-.5 5.6-.8 10.3-2.8 13.7-4.7-.5-.9-.6-2-.4-3l1.9-7.3c.4-1.4 1.4-2.4 2.6-2.8-.9-1.2-1-2.9-.3-4.3.8-1.6 2-3.1 3.3-4.3-.4.1-.8.3-1.2.4-1.1.3-2.2.6-3.5.7-1-.8-2.2-1.2-3.6-1.3-.9 0-1.8.1-2.7.4-1.4-1.3-3.3-2-5.3-1.8-1.8.1-3.4.9-4.5 2.1-.9.1-1.8.2-2.6.4-.3 1.5-.5 2.7-.5 2.9 0 .3-.1.5-.4.6h-.2c-.2 0-.5-.1-.5-.4-.1-.2-.1-.4.9-5.1.3-1.6.7-3 1.1-4.4.1-.5.3-.9.4-1.3.1-.4.3-.8.4-1.2v-.1c.1-.4.3-.7.4-1.1 0 0 0-.1.1-.1.1-.2.1-.4.2-.5-.4.7-1.3 2.6-2 4.4zm2.2 29.4c3.9-1.5 8-3.4 12-5.7.3-.1.6-.1.8.2.1.3.1.6-.2.8-4.1 2.3-8.2 4.2-12.2 5.7h-.2c-.2 0-.4-.1-.5-.4-.1-.2 0-.5.3-.6z"/>
+ <path fill="url(#k)" fill-rule="nonzero" d="M202.7 206.4c.1.2.2.5.3.8 0-.3-.1-.5-.1-.8h-.2z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M194.4 210.8c.3.6.6 1.3 1 1.9 0 .1.1.1.1.2.3.6.7 1.3 1.1 1.9 0 .1.1.1.1.2l1.2 1.8.1.1c.5.6.9 1.3 1.5 1.9.3.3.5.6.8.9.1.1.1.2.2.2l.6.6c.1.1.2.2.2.3.2.2.3.4.5.5.1.1.2.2.2.3.2.2.3.3.4.5.1.1.2.2.2.3l.5.5.2.2.2.2.4.4.1.1.5.5.2.2.3.3.2.2.3.3c.1.1.1.1.2.1.1.1.2.1.3.2l.1.1c.1.1.2.1.3.2 0 0 .1 0 .1.1.1.1.2.1.3.2h.1c.1 0 .2.1.2.1h.6c.1 0 .2-.1.2-.2 0 0 .1-.1.1-.2v-.1-.3-.1c0-.2 0-.4-.1-.6v-.2c0-.2-.1-.4-.1-.6v-.2c0-.2-.1-.4-.1-.6v-.2-.1c-.1-.3-.1-.6-.2-.9 0-.1 0-.2-.1-.3-.1-.3-.1-.6-.2-.8 0-.1 0-.1-.1-.2-.1-.4-.2-.7-.3-1.1 0-.1-.1-.2-.1-.3-.1-.3-.2-.6-.2-.9 0-.1-.1-.2-.1-.3l-.3-1.2v-.1c-.1-.4-.2-.7-.3-1.1 0-.1-.1-.2-.1-.3-.1-.4-.2-.7-.3-1.1v-.1c-.1-.4-.2-.8-.4-1.2 0-.1 0-.1-.1-.2-.1-.2-.1-.4-.2-.6-2.8-.6-5.7-1.3-8.6-2.2-.8-.2-1.5-.5-2.3-.8.2.6.5 1.1.7 1.7-.1-.2-.1-.2-.1-.1zM196.5 122c.8.5 1.8.3 2.3-.5 0 0 .8-1.1 2.2-1.1 1.4 0 2.1 1 2.2 1.1.3.5.9.7 1.4.7.3 0 .6-.1.9-.3.8-.5 1-1.5.5-2.3-.5-.8-1.8-2-3.7-2.4-.4-.1-.8-.1-1.3-.1-.4 0-.9.1-1.3.1-1.9.4-
3.2 1.6-3.7 2.4-.5.8-.3 1.9.5 2.4zm0-2s.1-.2.3-.4l.3-.3c.7-.7 2-1.7 3.9-1.7 2.9 0 4.4 2.2 4.5 2.3.3.5.2 1.2-.3 1.5-.2.1-.4.2-.6.2-.4 0-.7-.2-.9-.5 0-.1-.9-1.3-2.6-1.3-1.1 0-1.8.5-2.2.9l-.4.4c-.3.5-1 .7-1.5.3-.7-.2-.9-.9-.5-1.4zM225.4 117.2c-.4-.1-.8-.1-1.3-.1-.4 0-.9.1-1.3.1-1.9.4-3.2 1.6-3.7 2.4-.5.8-.3 1.8.5 2.3.8.5 1.8.3 2.3-.5 0 0 .8-1.1 2.2-1.1 1.4 0 2.1 1 2.2 1.1.3.5.9.7 1.4.7.3 0 .6-.1.9-.3.8-.5 1-1.5.5-2.3-.5-.6-1.8-1.9-3.7-2.3zm2.9 4.3c-.2.1-.4.2-.6.2-.4 0-.7-.2-.9-.5l-.2-.2-.2-.2c-.4-.4-1.2-.9-2.3-.9-1.7 0-2.6 1.3-2.6 1.3-.3.5-1 .7-1.5.3-.5-.3-.7-1-.3-1.5.1-.1 1.5-2.3 4.5-2.3 1.4 0 2.5.5 3.2 1.1.1.1.2.2.3.2l.3.3c.4.4.6.7.7.8.2.4.1 1.1-.4 1.4z"/>
+ <path fill="url(#l)" fill-rule="nonzero" d="M241.8 136.3c-7.4 7.4-10.4 9.3-19.4 11-14.7 1.3-34.1-.7-39.2-3.2-5.6-2.7-12-17.9-12-18.1-.1-.5-.5-.8-1-.8-.4 2.5.9 6.1 2.9 9.7.3.6.7 1.2 1.1 1.8.6.9 1.2 1.8 1.8 2.6.4.6.8 1.1 1.2 1.6.4.5.8 1 1.3 1.5.2.2.4.5.6.7.4.4.8.8 1.3 1.2.2.2.4.3.6.5.8.6 1.6 1.1 2.3 1.4 6.8 2.5 16.4 4.1 26.3 4.1 1.7 0 3.4-.1 5.1-.2h.2c.1 0 12.1-1.3 17.8-3.6.3-.1.6 0 .7.3.1.3 0 .6-.3.7-3.8 1.5-10.1 2.6-14.2 3.2-.3.2-.6.3-1 .5 10.2 0 19.5-1.3 23.1-4.7 4.3-4 3.1-12.5.8-10.2z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M250.4 158.2c-3.6 1.7-6.5 3.1-7.6 3.6 2.1-1 4.8-2.2 7.6-3.6z"/>
+ <path fill="url(#m)" fill-rule="nonzero" d="M224.6 99.7c.7 0 1.4-.1 2.1-.1v-.2c0-.3.3-.6.6-.5l3.3.1c.3-1.1.7-1.7.8-1.7.2-.2.5-.3.8-.1.2.2.3.5.1.8-.1.1-1.4 1.9-.1 4.9.6 1.5 2.9 2.8 3.8 3.2.2.1.3.3.3.5 0 0 .4 4.6 3.5 8.4 3.4 4.2 8.4 5.7 8.5 5.7.2.1.4.2.4.4 0 0 .6 3.3 1.9 4.6.7.7 2.6 2.6 7.4 1.7.3-.1.6.1.6.4.1.3-.1.6-.4.6-1 .2-1.9.3-2.7.3-3.1 0-4.7-1.2-5.8-2.2-1.3-1.3-1.9-3.9-2.1-4.8-1.1-.4-4.5-1.7-7.4-4.6.6 1 1.2 1.9 2 2.9v.1c0 3.5 2.3 6.4 5.4 7.4.7 1.5 1.3 3.2 1.6 5.3h.1c.3-.1.6.1.7.4 0 .1.6 2.4.4 5.9h1.4c.3-1.1.6-2.3.9-3.5.2.1.5.1.8.2 1.6.2 3.1-.9 3.5-2.5h.2c.8.3 1.7.6 2.6.7 4.1.4 7.7-2.1 9-5.8 2.8-.2 5.1-2.2 5.5-5 .9-1.1 1.8-2.2 2.6-3.3 3.3-.5 5.8-3.4 5.7-6.9 0-.6-.1-1.2-.3-1.8 1.6-1.3 2.6-3.3 2.5-5.5 0-1.8-.8-3.5-2-4.7 0-1.5-.1-3-.3-4.4 1.3-1 2.2-2.5 2.5-4.2 0-.2.1-.5.1-.7V91v-.1c0-.3 0-.6-.1-.9v-.2c0-.3-.1-.5-.2-.7V89l-.3-.9s0-.1-.1-.1c-.1-.2-.2-.5-.4-.7 0 0 0-.1-.1-.1-.3-.5-.7-1-1.2-1.4-.5-.4-1-.8-1.6-1.1-1-.5-2-.8-3.2-.8-2.1-3.4-4.7-6.4-7.8-8.9 0-.4-.1-.9-.2-1.3s-.2-.8-.4-1
.1v-.1c-.1-.4-.3-.7-.5-1v-.1c-.2-.3-.4-.6-.7-.9-.3-.3-.5-.6-.8-.8l-.9-.6s-.1 0-.1-.1c-.3-.2-.6-.3-1-.4-.1 0-.1 0-.2-.1-.3-.1-.7-.2-1-.3h-.2c-.4-.1-.8-.1-1.2-.1h-1c-.2 0-.5.1-.7.2-.1 0-.2 0-.3.1-.6.2-1.2.5-1.8.8-1.6-.5-3.2-.9-4.9-1.1-.2-.2-.4-.4-.6-.5l-.2-.2c-.1-.1-.3-.2-.4-.3-.1-.1-.2-.1-.3-.2-.1-.1-.3-.2-.4-.2-.1 0-.2-.1-.3-.1-.1-.1-.3-.1-.4-.2-.1 0-.2-.1-.3-.1-.2-.1-.3-.1-.5-.1-.1 0-.2-.1-.3-.1-.2 0-.4-.1-.5-.1h-1c-.3 0-.6 0-.9.1-.9.1-1.7.4-2.5.8s-1.4.9-2 1.5c-.7.1-1.4.3-2.1.4-1.4.3-2.7.7-4 1.2-.6.2-1.3.5-1.9.8-.4-.1-.9-.2-1.3-.3-.3 0-.5-.1-.8-.1-.3 0-.7 0-1 .1h-.3c-2.5.4-4.6 2.2-5.5 4.5-.1.3-.2.7-.3 1-.1.3-.1.7-.2 1-.4.3-.7.7-1 1-.7.1-1.4.4-2.1.7-.6.3-1.2.8-1.7 1.3-.3.3-.6.6-.8.9-.5.7-.8 1.4-1.1 2.2-.2.6-.2 1.2-.3 1.8v.2c0 .3 0 .7.1 1-.2.3-.3.6-.5 1-.2.5-.4.9-.6 1.4-.2.4-.4.9-.5 1.3-.2.1-.3.1-.5.2-.1.1-.3.2-.4.3-.4.3-.7.7-.9 1.2-.2.5-.4 1-.4 1.5 0 .8.3 1.6.7 2.1-.1.4-.1.9-.2 1.3s-.1.9-.2 1.3c-.1.7-.1 1.4-.1 2.2.2.2.5.3.7.5l2.3-.7c.2-.1.4 0 .6.1 0 0 1.3 1.3 3.1 1.1.3 0 .5.1.6.3.6-
.3 1.2-.8 1.6-1.5zm37.2 25.8c.2-.2.6-.3.8-.1.1.1 2.3 1.9 4.9-.2 2.1-1.8 2.1-3.7 1.9-4.7-1.6 0-2.9-.6-3.7-1.2-.5-.4-.6-1-.3-1.6.4-.5 1-.6 1.6-.3.3.2 3.2 2.1 6.1-.9 3.4-3.4 1.7-6.8 1.7-6.8-.3-.5-.1-1.2.5-1.5.5-.3 1.2-.1 1.5.5.9 1.7 1.6 5.8-2.1 9.4-1.4 1.4-2.9 2-4.2 2.2.2 1.2.1 3.5-2.3 5.6-1.2 1-2.3 1.3-3.3 1.3-1.8 0-3.1-1.1-3.1-1.1-.2 0-.2-.4 0-.6zm-26-50.3c2.4-.3 3.9.7 4.7 1.7.1-.1.3-.1.4-.2 2.1-.9 3.9-.9 5.3-.4.6-1.2 1.9-2.7 4.7-3.1 4.2-.6 5.5 3.1 5.5 3.2.1.3-.1.6-.4.7-.3.1-.6-.1-.7-.4 0-.1-1-2.9-4.3-2.4-2.3.3-3.3 1.5-3.8 2.4 1.2.6 2 1.4 2.5 2.1.3.5.2 1.2-.3 1.5-.5.3-1.2.2-1.5-.3-.2-.3-2.3-3.1-6.1-1.4-4.4 2-4 5.8-4 5.8.1.6-.4 1.2-1 1.2h-.1c-.6 0-1-.4-1.1-1-.2-1.7.4-5.1 3.9-7.3-.6-.7-1.7-1.4-3.5-1.2-3.7.5-4.2 3.4-4.2 3.5 0 .3-.3.5-.5.5h-.1c-.3-.1-.5-.3-.5-.6 0 0 .6-3.7 5.1-4.3z"/>
+ <path fill="url(#n)" fill-rule="nonzero" d="M233 105.8c.5.6 1.1 1.2 1.8 1.6.1.3.3.7.5 1.1-.1-.6-.2-1.1-.3-1.4-.4-.3-1.2-.7-2-1.3z"/>
+ <path fill="url(#o)" fill-rule="nonzero" d="M202.5 90.4c1.3 1.2 3.4.6 4.4-.9v-.1c0-.1.3-5.4-2.2-7.4 0 0-.1 0-.1.1l-.2.2s-.1.1-.1.2c-.1.1-.1.2-.2.3 0 .1-.1.1-.1.2-.1.1-.1.2-.2.4 0 .1-.1.1-.1.2-.1.2-.2.3-.3.5 0 .1-.1.1-.1.2-.1.2-.2.5-.3.7 0 .1 0 .1-.1.2-.1.2-.2.4-.2.6 0 .1-.1.2-.1.3-.1.2-.1.3-.2.5 0 .1-.1.2-.1.3 0 .2-.1.3-.1.5 0 .1 0 .2-.1.3 0 .1-.1.3-.1.4V89.7c0 .1 0 .2.1.3v.2c0 .1.1.3.2.3.1-.2.1-.2.2-.1z"/>
+ <path fill="url(#p)" fill-rule="nonzero" d="M209.1 94.2V94c-.1-.5-.3-1.4-.7-2.6-.1-.3-.2-.5-.3-.7-.6 2.1-3.7 3.3-5.8 1.5 0 .4-.1.7-.1 1.1 0 .6 0 1.1.1 1.6s.2 1 .4 1.3c.1.1.1.2.2.2.1.1.3.2.4.3.1.1.3.1.4.2 2.1.7 4.6-.6 5.4-2.7z"/>
+ <path fill="url(#q)" fill-rule="nonzero" d="M204 98c0 .3.1.5.1.8-.1-.7-.2-1.3-.3-2 .1.4.1.8.2 1.2z"/>
+ <path fill="url(#r)" fill-rule="nonzero" d="M210.6 95.5c-.4 2.7-3.6 4.7-6.5 3.5v.2c.1.4.2.8.2 1.1.4 1.6 1 2.9 1.6 3.4 2.8.5 6.9-1.5 7.1-4.5v-.5c-.2-.6-.5-1.4-1.1-2.1-.4-.4-.9-.8-1.3-1.1z"/>
+ <path fill="url(#s)" fill-rule="nonzero" d="M214.2 112c-.1 0-.1-.1 0 0-.2-.4 0-.7.3-.8.2-.1 3.9-1.4 3.9-5.2 0-2.6-2.1-4.5-3.5-5.5.2 3.4-3.6 6.1-7 6 1.5 2.5 3.4 3 3.5 3 .6.1 1 .7.9 1.3-.1.5-.6.9-1.1.9.2.2.5.3.7.3.6.3 1.5.2 2.3 0z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M240.4 163.4c-.5 1.1-1 2.3-1.4 3.2-.1.3 0 .6.3.7h.2c.2 0 .4-.1.5-.3.7-1.7 1.6-3.7 2.1-4.6.1-.1.1-.3.2-.4.2-.1.3-.2.5-.2 1-.5 4-1.9 7.6-3.6 3-1.4 6.1-3 9-4.5 0-.3.1-.6.3-.9 0 0 0-.1.1-.2-5.5 2.5-17.4 8.1-18 8.5-.3.2-.8 1.2-1.4 2.3z"/>
+ <path fill="url(#t)" fill-rule="nonzero" d="M275.8 140c-.7.2-1.3.6-2 .9v.4c.4 1.9 1.8 3.4 3.5 4.2.5-.6.9-1.1 1.3-1.7.3-.5.6-.9.8-1.3-.8-.2-1.5-.6-2-1.1-.4-.5-.7-1-.9-1.5-.2-.1-.4 0-.7.1z"/>
+ <path fill="url(#u)" fill-rule="nonzero" d="M273.3 149.1c.1 0 .1-.1.2-.1l.6-.5c.2-.1.4-.3.6-.4.1-.1.2-.2.3-.2-.3-.2-.7-.4-1-.7-1.4-1.1-2.5-2.7-3-4.4-.1.1-.2.1-.3.2-.2.1-.4.3-.6.4l-.6.5c-.2.2-.4.3-.6.5-.6.5-1.2 1-1.7 1.5-.6.5-1.1 1-1.6 1.5-.9.9-1.8 1.9-2.6 2.9s-1.4 1.8-1.7 2.2c-.2.3-.3.5-.4.7l-.1.2c-.2.3-.2.7-.1 1 .1.4.3.7.6.8.3.2.7.2 1 .1 0 0 .1 0 .3-.1.2-.1.4-.1.7-.3.6-.2 1.4-.6 2.6-1.1h.1c-1.2-2.3-.6-5.1-.6-5.3.1-.6.7-1 1.3-.8.4.1.7.4.8.8 1.8-.4 4.1 0 5.8.6z"/>
+ <path fill="url(#v)" fill-rule="nonzero" d="M281.4 141.3c.9-.2 2.7-.9 4.2-3.5-1-.8-2.6.8-3.3-.6-.6-1.1.1-1.5-.4-2.1h-.6c-1.6 0-2.9.7-3.5 1.9-.6 1.1-.3 2.5.6 3.5.6.8 1.8 1.1 3 .8z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M267.5 148.5c.1.2.1.4 0 .6 0 0-.5 2.5.5 4.1.5.8 1.3 1.2 2.4 1.4 1.3.2 2.3 0 3.1-.6 1.2-.9 1.4-2.7 1.4-2.7 0-.4.3-.7.6-.9-.3-.3-.7-.5-1.1-.8-.3-.2-.7-.4-1.2-.5-1.6-.6-3.9-1-5.7-.6z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M148 139.7c-.3.1-.4.5-.3.7 2 4.3 4 8.2 6 12 .1.2.3.3.5.3.1 0 .2 0 .3-.1.3-.1.4-.5.2-.8-2-3.7-4-7.6-6-11.9-.1-.2-.4-.4-.7-.2zM160.4 163.3c.1 0 .2 0 .3-.1.3-.2.3-.5.2-.8-.6-.9-1.2-1.9-1.8-2.8-.1-.1-.2-.2-.4-.3.6 1.2 1 2.4 1.2 3.7.2.2.4.3.5.3zM143.3 129.9h-.2v.4l.4 1c.1.2.3.3.5.3h.2c.3-.1.4-.5.3-.7l-.4-1h-.8zM283.4 171.4c1.5-1.3 3.1-2.7 4.6-4.1.2-.2.2-.6 0-.8-.2-.2-.6-.2-.8 0-1.7 1.5-3.3 3-5 4.4.3.2.6.4.9.7.2-.1.2-.2.3-.2zM185 190.5c-.2.2-.1.6.1.8.4.3.8.5 1.2.8.5.4 1.1.8 1.6 1.1.1.1.2.1.3.1.1 0 .2-.1.3-.1l.1-.1c.2-.3.1-.6-.1-.8-.7-.5-1.5-1-2.2-1.5-.2-.1-.4-.3-.6-.4-.2-.2-.5-.1-.7.1zM242.5 197.6h.2c4-1.5 8-3.5 12.2-5.7.3-.1.4-.5.2-.8-.1-.3-.5-.4-.8-.2-4.1 2.2-8.1 4.1-12 5.7-.3.1-.4.4-.3.7.1.2.3.3.5.3zM270 181.4c-.2-.2-.5-.3-.8-.1l-.9.7c-.1.1-.2.2-.2.3l1.2.3.5-.4c.4-.2.4-.6.2-.8zM169.9 175c-.2-.2-.5-.3-.8-.1-.2.2-.3.5-.1.8 3 3.6 6 7 9.2 9.8.1.1.2.1.4.1.1 0 .3-.1.4-.2.2-.2.2-.6 0-.8-.6-.5-1.2-1.1-1.7-1.7-1.2-1.2-2.4-2.4-3.6-3.7-1.3-1.2-2.6-2
.7-3.8-4.2zM164 167l-.6-.9c-.2-.3-.5-.3-.8-.2-.3.2-.3.5-.2.8l.6.9c.1.2.3.2.5.2.1 0 .2 0 .3-.1.3-.1.3-.4.2-.7zM191.8 195.5c.3.2.7.4 1 .5.1 0 .2.1.3.1.2 0 .4-.1.5-.3.1-.3 0-.6-.2-.8-.3-.2-.6-.3-1-.5-.3-.1-.6-.1-.8.2-.2.4-.1.7.2.8zM202.4 198.9c-.3-.1-.6.1-.7.4-.1.3.1.6.4.7.7.2 1.5.4 2.2.6l.3-1.1c-.7-.1-1.5-.3-2.2-.6zM169.1 184.2c-1.7-2.3-3.4-4.7-5-7.1-1.6-2.4-3.2-4.9-4.7-7.4-.3.8-.7 1.5-1.2 2.3 4.5 7.3 9.2 13.9 14 19.6l2.3-.7c-1.9-2.1-3.7-4.3-5.4-6.7zM133.2 123l2.1-1.3-2.1 1.3zM271.7 191c.1 0 .2.1.3.1.6.1 1.2.2 1.8.2.3 0 .7 0 1-.1 3.4-2.9 5.2-5 5.3-5 0 0 0-.1.1-.1l-2.4-.6c-1 1-3.1 3-6.1 5.5zM193.6 208.9c.8.3 1.5.6 2.3.8 2.9.9 5.8 1.6 8.6 2.2.8.2 1.6.3 2.5.4 1.6.3 3.2.5 4.8.6l-4.8-1.4c-1.2-.3-2.2-1.1-2.9-2.1-.1 0-.2 0-.3-.1-2.4-.5-4.7-1.1-7.2-1.9-1.4-.4-2.8-1-4.1-1.7-1-.5-1.9-1-2.9-1.6-1.2-.7-2.4-1.6-3.6-2.5-.3-.2-.6-.4-.9-.7l.6 1.9c.1.3.1.5.1.8.2.2.3.5.4.7v.1c.5.4 1.1.7 1.6 1.1 1 .6 1.9 1.2 2.9 1.7.9.9 1.9 1.3 2.9 1.7zM266.3 197.8c-.7-.4-1.3-.8-2-1.3-1.9 1.3-4 2.6-6.2 3.9-5 2.9-10.9 5.
6-17.4 7.6h-.1c-.9.3-1.9.6-2.8.8-.8.2-1.6.4-2.3.6-1.5.4-3.1.7-4.7.9l-.7 2.3c1.7-.3 3.4-.5 5-.9l2.4-.6c1-.2 1.9-.5 2.9-.8 6.3-1.8 12-4.3 17-7 2.8-1.5 5.4-3.1 7.8-4.7.3-.2.7-.5 1.1-.8z"/>
+ <path fill="#FFFEFE" fill-rule="nonzero" d="M235.2 188.8c-.7-1.3-1.9-2.3-3.3-2.7l-.9-.3-15.3-4.4c-.5-.1-1-.2-1.6-.2-2.5 0-4.7 1.7-5.4 4l-4.1 14.3-.3 1.1-1.2 4.1c-.2.6-.2 1.1-.2 1.7 0 .3 0 .5.1.8.1.5.2 1 .5 1.5.1.1.1.2.1.3 0 0 0 .1.1.1.1.2.2.4.4.5.7 1 1.7 1.7 2.9 2.1l4.8 1.4 3.8 1.1 7 2 .7.2c.5.1 1 .2 1.6.2.8 0 1.5-.2 2.2-.5 1.5-.7 2.6-1.9 3.1-3.5l.7-2.3 4.9-17.1c.3-1.5.1-3.1-.6-4.4zm-1.7 3.7l-5.6 19.4c-.4 1.5-1.8 2.4-3.2 2.4-.3 0-.6 0-.9-.1l-16.2-4.7c-1.8-.5-2.8-2.4-2.3-4.2l5.6-19.4c.4-1.5 1.8-2.4 3.2-2.4.3 0 .6 0 .9.1l16.2 4.7c1.8.5 2.8 2.4 2.3 4.2z"/>
+ <path fill="#FFFEFE" fill-rule="nonzero" d="M228.7 191.1l-12.9-3.7c-.2 0-.3-.1-.5-.1-.7 0-1.4.5-1.6 1.2l-4.7 16.2c-.3.9.3 1.8 1.2 2.1l12.9 3.7c.2 0 .3.1.5.1.7 0 1.4-.5 1.6-1.2l4.7-16.2c.2-.9-.4-1.9-1.2-2.1zm-14.4 7.2c.1-.4.4-.6.8-.6h.2l8.1 2.3c.4.1.7.6.6 1-.1.4-.4.6-.8.6h-.2l-8.1-2.3c-.5-.1-.7-.5-.6-1zm-.9 3.2c.1-.4.4-.6.8-.6h.2l3.2.9c.4.1.7.6.6 1-.1.4-.4.6-.8.6h-.2l-3.2-.9c-.5 0-.8-.5-.6-1zm9.7 6.7l-10-2.9-1.9-.5.4-1.3c.4.6 1 1 1.7 1.2l.9.2 2.4.7c.3.1.6.1.9.1 1.4 0 2.6-.9 2.9-2.2 0-.1.1-.2.1-.3l1.9.6c.3.1.6.1.9.1.4 0 .9-.1 1.3-.3l-1.5 4.6zm1.8-10.3c-.1.4-.4.6-.8.6h-.2l-8.1-2.3c-.4-.1-.7-.6-.6-1 .1-.4.4-.6.8-.6h.2l8.1 2.3c.5.1.8.5.6 1zm1-3.3c-.1.4-.4.6-.8.6h-.2l-8.1-2.3c-.4-.1-.7-.6-.6-1 .1-.4.4-.6.8-.6h.2l8.1 2.3c.4.1.7.6.6 1zM275 168.4c-.4 0-.7-.1-1.1-.1-1.7 0-3.4.3-5.1.9-.7.3-1.4.5-2.1.9-1.1.6-2.1 1.3-3.1 2.2-1.3 1.2-2.5 2.7-3.3 4.3-.7 1.4-.6 3.1.3 4.3-1.3.4-2.3 1.5-2.6 2.8l-1.9 7.3c-.3 1-.1 2.1.4 3 0 .1 0 .1.1.2.2.3.4.5.6.8.5.5 1.2.9 1.9 1.1.3.1.7.1 1 .1 1.1 0 2.1-.4 2.9-1.2
.5.5.9.9 1.5 1.3.6.5 1.3.9 2 1.3l1.2.6c1.5.7 3.1 1.1 4.7 1.3.6.1 1.1.1 1.7.1 2.5 0 5-.6 7.2-1.8 2.8-1.5 5-3.7 6.4-6.5.5-1 .6-2.1.3-3.1 0-.1-.1-.2-.1-.3-.1-.3-.3-.6-.4-.8.5-.2.9-.5 1.3-.8.6-.5 1.1-1.2 1.3-2l1.9-7.3c.3-1.1.1-2.2-.4-3.1-.5-.9-1.4-1.6-2.4-1.9h-.1c-.3-.1-.7-.1-1-.1-1.1 0-2.1.4-2.9 1.2-.5-.6-1.1-1-1.7-1.5-.3-.2-.6-.5-.9-.7-.7-.4-1.4-.8-2.1-1.1-.9-.4-1.9-.7-2.9-1-1.1-.2-1.8-.3-2.6-.4zm10.6 22.1c-1.2 2.4-3.1 4.3-5.5 5.6-2 1-4.1 1.5-6.1 1.5-4.7 0-9.2-2.5-11.5-6.9l-.5 2c-.2.9-1 1.4-1.8 1.4-.2 0-.3 0-.5-.1-1-.3-1.6-1.3-1.4-2.3l1.9-7.3c.2-.9 1-1.4 1.8-1.4.2 0 .3 0 .5.1l7.3 1.9c1 .3 1.6 1.3 1.4 2.3-.2.9-1 1.4-1.8 1.4-.2 0-.3 0-.5-.1l-3.7-1c1.1 2.8 3.5 4.9 6.4 5.6.8.2 1.5.3 2.3.3 3.4 0 6.6-1.8 8.3-4.9.4-.6 1-.9 1.6-.9.3 0 .6.1.9.2h.1c.9.5 1.2 1.6.8 2.6zm-10.6-7c.6 1 1.4 1.6 2.5 1.9l.3.1 2.4.6 1 .3c-.4.3-.7.7-1 1.1v.1c-1.1 2-3.1 3.4-5.3 3.7-.3 0-.7.1-1 .1-.6 0-1.2-.1-1.8-.2-.1 0-.2-.1-.3-.1l-.9-.3c1.2-.5 2.2-1.5 2.5-2.8.4-1.4 0-2.8-1-3.8-.5-.6-1.2-1-2-1.2l-.9-.2-1.2-.3-1.6-.4c.5-.
4.8-.8 1.1-1.4 1.3-2.2 3.7-3.6 6.3-3.6.3 0 .6 0 .9.1.3 0 .6.1.9.2.4.1.8.3 1.2.4h-.1c-1 .4-1.9 1.3-2.3 2.4 0 .1-.1.2-.1.4-.3.8-.2 1.9.4 2.9zm10.4-6l.5-2c.2-.9 1-1.4 1.8-1.4.2 0 .3 0 .5.1 1 .3 1.6 1.3 1.4 2.3l-1.9 7.3c-.2.9-1 1.4-1.8 1.4-.2 0-.3 0-.5-.1l-7.3-1.9c-1-.3-1.6-1.3-1.4-2.3.2-.9 1-1.4 1.8-1.4.2 0 .3 0 .5.1l3.7 1c-1.1-2.8-3.5-4.9-6.4-5.6-.8-.2-1.6-.3-2.4-.3-3.3 0-6.5 1.8-8.2 4.8-.3.7-1 1.1-1.7 1.1-.2 0-.3 0-.5-.1l-.4-.1h-.1c-.9-.5-1.3-1.6-.8-2.5 1.2-2.4 3.1-4.3 5.5-5.6 2-1 4.1-1.5 6.1-1.5 4.8-.2 9.3 2.3 11.6 6.7zM160.2 164.9c0-.6-.1-1.3-.2-1.9-.2-1.3-.6-2.6-1.2-3.7-1.4-2.7-3.7-4.8-6.7-6-.7-.3-1.5-.5-2.3-.6-.7-.1-1.4-.2-2.1-.2h-.4c-1 0-2 .2-3 .4 0-.1-.1-.3-.1-.4-.3-.7-.9-1.2-1.6-1.5-.3-.1-.7-.2-1-.2-.6 0-1.2.2-1.7.5s-.8.8-1 1.3l-1.2 3.2-1.1 2.9c-.4 1.1-.1 2.3.7 3.1-1.3.5-2.2 1.8-2.2 3.3 0 1.9.5 3.7 1.3 5.3.3.7.7 1.3 1.1 1.9 2.3 3.2 6 5.2 10.2 5.2h.1c3.4 0 6.5-1.4 8.8-3.8.6-.6 1.1-1.2 1.6-1.9s.8-1.5 1.2-2.3c.5-1.3.8-2.9.8-4.6zm-12.5 10.5h-.1c-3.6 0-6.8-1.8-8.6-4.6-.6-.9-1.1-1.9
-1.3-3-.2-.8-.4-1.7-.4-2.6 0-.4.1-.7.4-.9.2-.2.6-.4.9-.4.7 0 1.3.6 1.3 1.3 0 2.2 1 4.4 2.7 5.9 1.5 1.3 3.3 1.9 5.1 1.9 2.2 0 4.3-.9 5.8-2.7 2.8-3.2 2.5-8.1-.7-10.9-1.5-1.3-3.3-1.9-5.1-1.9-2.2 0-4.3.9-5.8 2.7l3.7 1.4c.3.1.5.5.4.8-.1.3-.3.4-.6.4h-.2l-5.2-2-.8-.3c-.3-.1-.5-.5-.4-.8l1.2-3.2 1.1-2.8c.1-.3.3-.4.6-.4h.2c.3.1.5.5.4.8l-1.2 3.3c1.9-1.7 4.3-2.5 6.8-2.5 1.2 0 2.4.2 3.6.6 4 1.5 6.6 5.3 6.6 9.5-.1 5.7-4.7 10.3-10.4 10.4zm-5.8-11.5l1.9.7-.2.1h-.1c-.6.3-1 .7-1.3 1.2 0-.2-.1-.5-.1-.8 0-.3 0-.8-.2-1.2zm5.6 1.6l1.7-4.6c.1-.3.3-.4.6-.4h.2c.3.1.5.5.4.8l-1.8 4.8c0 .2-.1.3-.3.4L145 168l-.1-.2-.8-.3c-.1-.3 0-.7.3-.8l3.1-1.2zm-.6-5.7h.4c0 .1-.1.2-.1.3-.1-.2-.2-.3-.3-.3zm3.9 7l1.6-4.4c.4.7.7 1.5.7 2.4.1 1.5-.4 2.9-1.3 4-1 1.2-2.6 1.9-4.2 1.9-.8 0-1.5-.2-2.2-.5.2 0 .3-.1.5-.2l3.3-1.5c.1 0 .2-.1.2-.1.7-.3 1.2-.9 1.4-1.6zM185.7 204c0-.3 0-.5-.1-.8l-.6-1.9-.3-1.1c-.1-.3-.2-.5-.4-.7 0-.3 0-.5-.1-.8l-.9-3.1c-.1-.3-.2-.5-.4-.7 0-.3 0-.5-.1-.8-.7-2.3-2.8-3.9-5.2-3.9-.5 0-1.1.1-1.6.2-.3.1-.5.2-.7.4h-
.2c-.2 0-.4 0-.6.1h-.2l-2.3.7-.6.2c-.3.1-.5.2-.7.4h-.2c-.2 0-.4 0-.6.1l-3.1.9c-.3.1-.5.2-.7.4h-.2c-.2 0-.4 0-.6.1l-3.1.9c-.3.1-.5.2-.7.4h-.2c-.2 0-.4 0-.6.1-2.9.9-4.5 3.9-3.6 6.8.1.3.2.5.4.7 0 .3 0 .5.1.8l.1.2c-.7.7-1.2 1.5-1.5 2.5-.5 1.6-.4 3.3.3 4.8.7 1.4 1.8 2.4 3.2 3-.3.5-.6 1.1-.8 1.8-.9 3.3 1.1 6.7 4.5 7.6.5.1 1 .2 1.6.2 2.8 0 5.3-1.9 6-4.7.3-1 .3-2.1 0-3.1l.6-.8c.1.1.2.1.3.2l5.7 2.1h.1c.6.2 1.1.3 1.7.3 2.3 0 4.4-1.5 5.2-3.7v-.1c.3-1-.1-2-.9-2.5 2.1-1.2 3.2-3.8 2.5-6.2v-.1c-.2-.5-.3-.7-.5-.9zm-2.2-.2l-3.1.9-.9-3.1 3.1-.9.9 3.1zm-4 5.7l-3.1-1.1 2-2.7c.1.1.2.3.2.4 0 .3 0 .5.1.8l.8 2.6zm2.6-10.3l-3.1.9-.9-3.1 3.1-.9.9 3.1zm-4.4-6.8c1.4 0 2.6.9 3.1 2.3l-3.1.9-.9-3.1c.2-.1.5-.1.9-.1zm-2.5.6l.9 3.1-3.1.9-.9-3.1 3.1-.9zm-3 6.5c.3-.1.5-.2.7-.4h.2c.2 0 .4 0 .6-.1l2.5-.7.1.3c-1.5.1-2.8.9-3.7 2l-3.7 5-1-.4c-.5-1.2-1.4-2.2-2.5-2.9l-.2-.8 2.5-.7c.3-.1.5-.2.7-.4h.2c.2 0 .4 0 .6-.1l3-.8zm-1.6-5.2l.9 3.1-3.1.9-.9-3.1 3.1-.9zm-4.6 1.4l.9 3.1-3.1.9-.9-3.1 3.1-.9zm-4.6 1.4l.9 3.1-3.1.9c-.4-1.7.5
-3.5 2.2-4zm7.1 17.9c.1.2.2.5.2.8.2.7.2 1.5.1 2.2-.5 1.8-2.1 3-3.9 3-.3 0-.7 0-1-.1-2.1-.6-3.4-2.7-2.9-4.9.5-1.8 2.1-3 3.9-3 .3 0 .7 0 1 .1l1.7-2.2-2.3-.8c-.4.6-.9 1-1.5 1.4-.6.3-1.2.4-1.8.4-1.5 0-2.9-.8-3.6-2.2-1-2-.2-4.4 1.8-5.4l-.5-1.7 3.1-.9.7 2.3c1.2.4 2.1 1.4 2.5 2.6l.1.5 3.6 1.3 4.6-6.2c.6-.8 1.6-1.2 2.5-1.2.7 0 1.4.2 2 .7L168.5 215zm13.9-2.1c-.4 1.3-1.7 2.2-3 2.2.1.1.1.3 0 .4-.1.2-.3.4-.5.4h-.2l-3.8-1.3c-.3-.1-.4-.4-.4-.7 0-.1.1-.2.2-.3l-2.1-.8 2-2.6 7.8 2.7zm-.6-3.6l-.9-3.1 3.1-.9c.5 1.7-.5 3.5-2.2 4z"/>
+ <path fill="#FFFEFE" fill-rule="nonzero" d="M166.9 216.4c-.3-.9-1.1-1.5-2-1.5-.2 0-.4 0-.6.1-1.1.3-1.7 1.5-1.4 2.6.3.9 1.1 1.5 2 1.5.2 0 .4 0 .6-.1h.2c1-.3 1.6-1.4 1.3-2.4-.1-.1-.1-.2-.1-.2zM163.9 207.1c-.3-.8-1.1-1.3-1.9-1.3-.3 0-.5 0-.8.1-1.1.4-1.6 1.6-1.2 2.7.3.8 1.1 1.3 1.9 1.3.3 0 .5 0 .8-.1.1 0 .1 0 .2-.1 1-.4 1.5-1.5 1.1-2.5l-.1-.1zM136.1 109.9c-.3.6-.5 1.2-.6 1.8 0 .1-.1.2-.1.4-.1.7-.2 1.3-.2 2l-.4.2-.6.4-.9.6-.2.1-.4.3-2 1.2-2.7 1.7-2.3 1.4c-.3.1-.5.3-.7.5-1.8 1.4-2.5 3.9-1.5 6 .8 1.8 2.6 3 4.6 3h.2c.7 0 1.3-.2 1.9-.4.3-.2.7-.3 1-.6l.4-.2 1.6-1 1.1-.7.5-.3 1.9-1.2.9-.6 2.2-1.4.6-.4c.6.3 1.3.6 2 .7h.1c.7.2 1.4.2 2.1.2 4.5 0 8.4-3.1 9.4-7.5.3-1.4.3-2.9 0-4.4-.3-1.1-1-2-2.1-2.4h-.1c0-1.1-.5-2.1-1.3-2.8-1.1-.9-2.4-1.5-3.8-1.8h-.1c-.6-.1-1.3-.2-2-.2-1.8 0-3.4.5-4.9 1.4-.8.5-1.6 1.1-2.2 1.8-.4.6-1 1.4-1.4 2.2zm2.8 2.8c.6-2.9 3.2-4.9 6-4.9.4 0 .8 0 1.3.1.9.2 1.7.6 2.4 1.2l-.2.1.1.1-4.4 2.8c-.3.2-.6.5-.7.8-.2.6-.2 1.2.2 1.7.4.6 1 .9 1.7.9.4 0 .7-.1 1-.3l4.6-2.7c.2.9.2 1.9 0 2.8
-.3 1.5-1.2 2.7-2.2 3.5-1.1.8-2.4 1.3-3.8 1.3-.4 0-.9 0-1.3-.2-1-.3-2-.8-2.8-1.6l-.7.4-2.2 1.4-2.4 1.5-2.1 1.3-4 2.5c-.1.1-.2.2-.4.2-.2.1-.4.1-.6.1h-.1c-.6 0-1.1-.3-1.4-.9-.3-.8 0-1.7.8-2l11.5-7.3c-.1-.5-.2-1-.2-1.5-.3-.3-.3-.8-.1-1.3z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M154.8 144.4l-2.2-4.7c-.1-.3-.5-.4-.7-.3-.3.1-.4.5-.3.7l2.2 4.7c.1.2.3.3.5.3.1 0 .2 0 .2-.1.3 0 .4-.4.3-.6zM161 185.3c.1.2.3.2.5.2.1 0 .2 0 .3-.1.3-.2.3-.5.1-.8l-2.5-3.5c-.2-.3-.5-.3-.8-.1-.3.2-.3.5-.1.8l2.5 3.5z"/>
+ <path fill="#E1E1E6" fill-rule="nonzero" d="M179 214.8l-3.8-1.3c-.2-.1-.3 0-.5.1-.1.1-.2.2-.2.3-.1.3.1.6.4.7l3.8 1.3h.2c.2 0 .5-.1.5-.4v-.4c-.1-.2-.2-.3-.4-.3zM179.7 181.2c.1 0 .3 0 .4-.1.2-.2.3-.5.1-.8l-2.7-3.2-1.6-1.9c-.2-.2-.5-.3-.8-.1-.2.2-.3.5-.1.8l.9 1.1 3.3 4c.2.1.4.2.5.2z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M268.1 159.5l-6 5.5c-.2.2-.2.6 0 .8.1.1.3.2.4.2.1 0 .3 0 .4-.1l6-5.5c.2-.2.2-.6 0-.8-.2-.3-.5-.3-.8-.1zM125.9 112.2c.1.2.3.4.5.4h.2c.3-.1.4-.4.3-.7l-1.7-4.7c-.1-.3-.4-.4-.7-.3-.3.1-.4.4-.3.7l1.7 4.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M98.9 188.6c.6-.9 1.6-1.5 2.5-1.7-1.1.2-2.2.8-2.9 1.8-.2.2-.3.5-.4.7h.2c.2-.2.3-.5.6-.8zM113 187.5c-.7-.2-1.3-.4-2-.3-1.6 0-3.3.8-4.3 2.1 0 .1.1.2.1.3 1.4-2 3.9-2.8 6.2-2.1zM95.5 213.7c.3.6.7 1.2 1.3 1.6.5.4 1.1.6 1.7.6l-.1-.1c-.6-.1-1.2-.3-1.7-.7-.6-.4-1-.9-1.2-1.4zM90.5 210.7c-2-1.5-2.9-4-2.4-6.3-.6 2.4.3 5 2.4 6.5 1.1.8 2.4 1.1 3.6 1.1.3 0 .7 0 1-.1v-.2c-1.6.4-3.2.1-4.6-1zM91.6 191.8c.4-.5.8-1 1.3-1.4-.6.4-1.2.9-1.6 1.6-1.8 2.5-1.4 5.9.8 7.9.1 0 .2-.1.3-.1-2.3-2-2.7-5.5-.8-8zM116.4 197.4c.2.1.3.2.5.4-.2-.2-.4-.4-.7-.5-.2-.2-.5-.3-.8-.4.3.1.7.3 1 .5zM109.4 218.5l-.6-3.3h-.1l.5 3.3c.1.1.2.1.2 0zM108.5 214.1c.1 0 .1 0 0 0 .1 0 .1 0 0 0zM102.4 213.5c-.1.3-.2.5-.4.7l-.3.3s0 .1.1.1l.3-.3c.1-.2.2-.5.3-.8l.1.1c.3.2.6.3.9.5-.4-.1-.7-.3-1-.6 0 .1 0 0 0 0zM111.9 213.8c0 .1.1.2.2.4.2.4.4.9.5 1.4 0-.1 0-.1.1-.2-.2-.5-.4-1-.5-1.4-.1-.1-.2-.2-.3-.2 0-.3-.2-.5-.5-.5h-.2c-.1 0-.2.1-.2.2.1 0 .1-.1.2-.1.3 0 .6.1.7.4zM110.3 225.1c.1.3-.2.6-.6.8-.5.3-1.2.5
-1.8.5.7-.1 1.4-.3 2-.5.5-.2.8-.6.7-.9l-1-5.4h.1c-.1 0-.2.1-.2.1l.8 5.4zM99.7 215.7l.1.1h.1c-.1 0-.1 0-.2-.1zM104.3 217.3c-.7-.2-1.3-.5-1.9-.9.6.4 1.2.7 1.9.9z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M114.5 211.4c.3.1.5.4.5.7-.4 1.9-1 4.2-2.5 5.8l-.1.1c-.5.6-1.2 1.1-2 1.4.9-.4 1.6-.9 2.1-1.5l.1-.1c1.4-1.6 2-3.9 2.4-5.8.1-.3-.1-.6-.5-.7h-.1c-.3 0-.5.2-.6.5v.1c.1-.3.4-.5.7-.5z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M121.5 195.5c.4-1.4.5-2.9.2-4.4-.4-2.7-1.9-5.1-4.2-6.8-1.8-1.3-3.9-2-6.1-2-1.4 0-2.7.3-4 .8-1.4-.9-3.1-1.3-4.8-1.3-2.4 0-4.7.9-6.4 2.5-3.3.1-6.5 1.8-8.4 4.5-1.9 2.7-2.5 6.2-1.6 9.3-.3.3-.6.7-.9 1.1-3.5 4.9-2.4 11.7 2.5 15.2 1.2.8 2.5 1.4 3.8 1.8.6 1 1.4 1.9 2.4 2.6 1.2.9 2.6 1.4 4 1.5.7.6 1.5 1 2.4 1.5l.7 4.2.1.5c.3 2.1 2.2 4.6 6.2 4.6.7 0 4.4-.1 6.5-2.6.5-.6.8-1.2 1-1.9.2-.8.3-1.6.2-2.4l-.3-2.1c.4-.3.8-.7 1.2-1.1l.2-.2c2.2-2.5 3.1-5.7 3.5-7.9.1-.5.1-1.1.1-1.6.8-.6 1.5-1.4 2.1-2.2 1.8-2.4 2.5-5.4 2-8.4-.4-1.9-1.2-3.7-2.4-5.2zm-1.9 12.1c-.8 1.1-1.8 2-3 2.7.4.6.6 1.4.5 2.1-.4 1.9-1.1 4.8-2.8 6.8l-.1.1c-.6.7-1.3 1.2-2.1 1.7l.7 3.6c.1.5 0 1.1-.2 1.6-.1.3-.2.5-.4.7-1.1 1.3-3.1 1.8-4.6 1.8-2.4 0-3.6-1.2-3.8-2.5l-.1-.5-1-5.5c-1.5-.6-2.7-1.3-3.7-2.2-1.3 0-2.5-.3-3.5-1.1-1-.7-1.8-1.7-2.2-2.8-1.5-.1-2.9-.6-4.1-1.5-1.8-1.3-3.1-3.2-3.5-5.4-.4-2.2.1-4.4 1.4-6.3.5-.7 1.1-1.3 1.7-1.8-1.4-2.7-1.2-6 .6-8.6 1.5-2.2 4.1-3.6 6.8-3.6h.7c1.3-1.6 3.2-2.6 5.3
-2.6 1.4 0 2.8.4 4 1.2.2.2.4.3.6.5 1.2-.8 2.7-1.3 4.2-1.3 1.7 0 3.3.5 4.6 1.4 1.7 1.2 2.9 3 3.3 5.1.3 1.6.1 3.2-.6 4.6 1.5 1.3 2.4 3 2.8 5 .4 2.5-.1 4.9-1.5 6.8z"/>
+ <path fill="url(#w)" fill-rule="nonzero" d="M108.2 214.3c.1 0 .2-.1.3-.1-.1 0-.2 0-.3.1z"/>
+ <path fill="url(#x)" fill-rule="nonzero" d="M110.3 225.1l-.9-5.4c.1 0 .2-.1.2-.1.2-.1.5-.1.7-.2.8-.3 1.5-.8 2-1.4l.1-.1c1.4-1.6 2.1-3.9 2.5-5.8.1-.3-.1-.6-.5-.7-.3-.1-.6.1-.7.4-.2 1.2-.6 2.6-1.1 3.7v-.1c0 .1 0 .1-.1.2-.2-.5-.4-1-.5-1.4-.1-.2-.1-.3-.2-.4-.1-.3-.4-.5-.7-.4-.1 0-.1.1-.2.1-.1.2-.2.4-.1.6 0 .1.1.3.2.5.2.4.5 1 .6 1.6.2.6.1.9 0 .9l-.1.1c-.4.5-1 .9-1.6 1.1-.2.1-.3.1-.5.2h-.1l-.5-3.3c-.9.3-1.8.4-2.2.4h-.4c-.3 0-.5-.3-.5-.6 0-.1.1-.2.2-.3-.7 0-1.3-.2-2-.4h.1l.5 3s-.1 0-.1-.1c-.7-.2-1.3-.5-2-.9-.1 0-.2 0-.3-.1-1.2-.7-1.9-1.8-2.2-2.7v-.1-.2c-.1-.2-.1-.4-.1-.6v-.1c0-.1-.1-.3-.2-.4-.1-.1-.3-.1-.5 0-.3.1-.3.9-.1 1.8.2.6.6 1.2 1 1.7l.1.1c.3.4.7.7 1 1 1.1.9 2.5 1.4 3.8 1.8l1.3 7.2c1.3 0 2.6.1 3.8.1.1-.1.4-.3.3-.7z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M107.5 226.5h.4c.7-.1 1.4-.3 1.8-.5-1.2-.1-2.5-.1-3.8-.1v.1c.2.4.8.5 1.6.5z"/>
+ <path fill="url(#y)" fill-rule="nonzero" d="M107.5 226.5h.4c.7-.1 1.4-.3 1.8-.5-1.2-.1-2.5-.1-3.8-.1v.1c.2.4.8.5 1.6.5z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M105.2 203.6c.8-.3 1.5-.5 2.3-.8-.8.3-1.6.6-2.3.8zM102.8 204.3c-.7.2-1.5.3-2 .5.6-.2 1.3-.3 2-.5zM98.8 214s0 .1 0 0c.2.7.6 1.3.9 1.7h.1c-.5-.5-.8-1-1-1.7zM107.4 202.8c.7-.3 1.4-.6 1.9-.8-.5.2-1.2.5-1.9.8zM99.6 212.7s.1 0 0 0c.1.1.1 0 0 0z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M105.8 214.7c.1-.1.3-.2.4-.2 0 0 1 .1 2-.3.1 0 .2-.1.3-.1h.1c.4-.2.8-.5 1.2-.8l.1-.1.4-.4.5-.5c.1-.1.1-.2.2-.3.6-.9 1-2 1.1-3h.6c2 0 4-1 5.3-2.8 1.9-2.7 1.4-6.4-1-8.5-.1-.1-.3-.2-.5-.4-.3-.2-.6-.4-1-.6-.1 0-.1-.1-.2-.1.2-.2.4-.4.5-.6 1.8-2.6 1.2-6.1-1.4-7.9-.4-.3-.9-.5-1.3-.7-2.2-.7-4.8.1-6.2 2.1 0-.1-.1-.2-.1-.3-.1.1-.1.2-.2.2-.3-.8-.9-1.5-1.6-2-.8-.6-1.7-.8-2.7-.8-.3 0-.5.1-.8.1-1 .3-1.9.8-2.5 1.7-.2.3-.4.6-.5.9h-.2c0 .1-.1.1-.1.2-.6-.2-1.2-.2-1.8-.2-1.2 0-2.3.4-3.3 1-.5.4-1 .8-1.3 1.4-1.8 2.5-1.4 6 .8 8.1-.1 0-.2.1-.3.1l.1.1c-1.3.4-2.4 1.2-3.2 2.4-.2.3-.4.7-.6 1.1v.1l-.3.9c-.5 2.3.4 4.8 2.4 6.3 1.4 1 3.1 1.3 4.6 1.1v.2c0 .3 0 .6.1.9v.1c.1.2.1.4.2.6.3.6.7 1.1 1.2 1.4.5.4 1.1.6 1.7.7-.3-.4-.5-.9-.6-1.4-.7-2.4.3-3 .7-3.2.5-.2 1.1-.2 1.5.1.4.3.7.7.8 1.3 0 .5.3 1.3.9 2l.3-.3c.2-.2.3-.5.4-.7 0 0 .1 0 .1.1.3.2.6.4.9.5.1.1.3.1.4.2h.1c.5.2 1.1.3 1.8.3zm2.1-19.7c.6-.2 1.3.1 1.5.7l.8 2.4c-.8-.1-1.6.2-2.2.8l-.8-2.4c-.3-.7.1-1.3.7-1.5zM97 199.8c-.2
-.6.1-1.3.7-1.5.6-.2 1.3.1 1.5.7l.8 2.4c-.8-.1-1.6.2-2.2.8l-.8-2.4zm6.3 8.1c.1-.1.1-.2.2-.2-.1.1-.2.1-.2.2-.2 0-.4 0-.6-.1-.7-.1-1.4-.3-2.1-.6-.4-.2-.8-.3-1.1-.6-.4-.2-.8-.5-1.2-.8l-.2-.1c-.1-.1-.1-.2 0-.3 0 0 0-.1.1-.1.2-.1.5-.2.7-.3.3-.1.6-.3 1-.4l1.7-.6c1.1-.4 2.3-.8 3.4-1.2 1.2-.4 2.3-.7 3.5-1.1l1.7-.5c.3-.1.7-.2 1-.3.2-.1.5-.1.7-.2.1 0 .2 0 .2.1v.1l-.1.2c-.1.5-.3 1-.5 1.4-.2.4-.4.8-.6 1.1-.4.7-.9 1.3-1.3 1.8-.1.1-.3.2-.4.4-.8.8-1.7 1.3-2.7 1.6-1 .5-2.1.7-3.2.5z"/>
+ <path fill="url(#z)" fill-rule="nonzero" d="M203.6 209.1c.1.2.1.3.1.5.1 0 .2 0 .3.1-.1-.3-.3-.4-.4-.6z"/>
+ <path fill="url(#A)" fill-rule="nonzero" d="M227 221.9v-1.3-1.4-1.4-.7-1c-.7.3-1.5.5-2.2.5 0 2.6 0 4.6.1 6.2h2.2c-.1-.3-.1-.6-.1-.9z"/>
+ <path fill="url(#B)" fill-rule="nonzero" d="M203.3 223.1l-.2-.2-.5-.5c-.1-.1-.2-.2-.2-.3-.1-.2-.3-.3-.4-.5-.1-.1-.2-.2-.2-.3-.2-.2-.3-.4-.5-.5-.1-.1-.2-.2-.2-.3l-.6-.6c-.1-.1-.1-.2-.2-.2-.3-.3-.5-.6-.8-.9-.5-.6-1-1.2-1.5-1.9l-.1-.1-1.2-1.8c0-.1-.1-.1-.1-.2-.4-.6-.7-1.2-1.1-1.9 0-.1-.1-.1-.1-.2-.3-.6-.7-1.3-1-1.9 0-.1 0-.1-.1-.2-.3-.6-.5-1.1-.7-1.7-1-.4-2-.9-3-1.4 1.6 4.2 3.9 8.9 7.1 12.7 1.1 1.3 2 2.3 2.9 3.3.9-.1 1.9-.1 2.8-.2 0 0 0-.1-.1-.2z"/>
+ <path fill="url(#C)" fill-rule="nonzero" d="M204.7 212.6c0 .1 0 .1.1.2.1.4.2.8.4 1.2v.1c.1.4.2.7.3 1.1 0 .1.1.2.1.3.1.4.2.7.3 1.1v.1l.3 1.2c0 .1.1.2.1.3.1.3.2.6.2.9 0 .1.1.2.1.3.1.4.2.7.3 1.1 0 .1 0 .1.1.2.1.3.1.6.2.8 0 .1 0 .2.1.3.1.3.1.6.2.9V223c.7 0 1.5-.1 2.3-.1-.4-2.1-1.3-5.4-2.9-10.6-.8-.1-1.6-.3-2.5-.4.1.3.2.5.3.7z"/>
+ <path fill="url(#D)" fill-rule="nonzero" d="M214.9 199.4l8.1 2.3h.2c.4 0 .7-.2.8-.6.1-.4-.1-.9-.6-1l-8.1-2.3h-.2c-.4 0-.7.2-.8.6-.1.4.1.8.6 1z"/>
+ <path fill="url(#E)" fill-rule="nonzero" d="M267.5 198.4l-1.2-.6c-.4.3-.9.6-1.3.9.9-.1 1.7-.2 2.5-.3z"/>
+ <path fill="url(#F)" fill-rule="nonzero" d="M151.3 155.4c-1.2-.4-2.4-.6-3.6-.6-2.5 0-4.9.9-6.8 2.5l1.2-3.3c.1-.3 0-.7-.4-.8h-.2c-.3 0-.5.2-.6.4l-1.1 2.8v4.4l5.2 2h.2c.3 0 .5-.2.6-.4.1-.3 0-.7-.4-.8l-3.7-1.4c1.5-1.8 3.7-2.7 5.8-2.7 1.8 0 3.6.6 5.1 1.9 3.2 2.8 3.6 7.7.7 10.9-1.5 1.8-3.7 2.7-5.8 2.7-1.8 0-3.6-.6-5.1-1.9-1.7-1.5-2.7-3.6-2.7-5.9v2.5c0 1.1-.3 2.2-.9 3 1.9 2.8 5 4.6 8.6 4.6h.1c5.7-.1 10.3-4.7 10.2-10.4.2-4.2-2.4-8-6.4-9.5z"/>
+ <path fill="url(#G)" fill-rule="nonzero" d="M144.1 167.6l.8.3.1.2 3.3-1.5c.2-.1.3-.3.3-.4l1.8-4.8c.1-.3 0-.7-.4-.8h-.2c-.3 0-.5.2-.6.4l-1.7 4.6-3.1 1.3c-.3 0-.4.4-.3.7z"/>
+ <path fill="url(#H)" fill-rule="nonzero" d="M163 112.5c.1.5.7.5.8 0 1.2-4.8 5-8.6 9.8-9.8.5-.1.5-.7 0-.8-4.8-1.2-8.6-5-9.8-9.8-.1-.5-.7-.5-.8 0-1.2 4.8-5 8.6-9.8 9.8-.5.1-.5.7 0 .8 4.8 1.2 8.5 5 9.8 9.8z"/>
+ <path fill="url(#I)" fill-rule="nonzero" d="M234.8 212.7c-.1.5-.2 1.1-.3 1.6v.1c-.1.5-.2 1-.4 1.5-.1.5-.3.9-.4 1.4-.1.4-.3.8-.4 1.1 0 .1-.1.3-.1.4-.1.2-.2.5-.3.7-.1.1-.1.3-.2.4-.1.2-.2.4-.2.6-.1.1-.1.3-.2.4-.1.2-.2.4-.2.5-.1.1-.1.3-.2.4-.1.2-.2.3-.2.5-.1.1-.1.2-.2.3 0 0 0 .1-.1.1.8 0 1.7 0 2.5.1.8-1.7 1.5-3.5 2-4.9.6-1.7 1.1-4 1.6-6.9l-2.4.6c-.1.3-.1.6-.2 1l-.1.1z"/>
+ <path fill="url(#J)" fill-rule="nonzero" d="M191.9 204.4l-.3-.9c1.4 1.1 3.3 2 6 2.5h.1c.3 0 .5-.2.5-.5.1-.3-.1-.6-.4-.6-5.2-1-7.3-3.8-8.2-5.4-.1-.4-.3-.8-.4-1.2 0-.1-.1-.3-.1-.5l-.3-1.2c0-.2-.1-.4-.1-.5-.1-.4-.1-.8-.2-1.2v-.6-1c-.1.1-.2.1-.3.1-.1 0-.2 0-.3-.1-.5-.4-1.1-.7-1.6-1.1-.1 4.4.9 8.4 3 11.4l.3.9c1 .6 1.9 1.1 2.9 1.6-.3-.6-.4-1.2-.6-1.7z"/>
+ <path fill="url(#K)" fill-rule="nonzero" d="M178.1 85.3c-.1-.3-.5-.3-.6 0-.8 3.2-3.4 5.8-6.6 6.6-.3.1-.3.5 0 .6 3.2.8 5.8 3.4 6.6 6.6.1.3.5.3.6 0 .8-3.2 3.4-5.8 6.6-6.6.3-.1.3-.5 0-.6-3.3-.9-5.8-3.4-6.6-6.6z"/>
+ <path fill="url(#L)" fill-rule="nonzero" d="M180.4 204.7l3.1-.9-.9-3-3.1.9"/>
+ <path fill="url(#M)" fill-rule="nonzero" d="M176.8 200.9c-.9 0-1.9.4-2.5 1.2l-4.6 6.2-3.6-1.3-.1-.5c-.4-1.2-1.3-2.2-2.5-2.6l-.7-2.3-3.1.9.5 1.7c-2 1-2.8 3.4-1.8 5.4.7 1.4 2.1 2.2 3.6 2.2.6 0 1.2-.1 1.8-.4.6-.3 1.2-.8 1.5-1.4l2.3.8-1.7 2.2c-.3-.1-.7-.1-1-.1-1.8 0-3.4 1.2-3.9 3-.6 2.1.7 4.3 2.9 4.9.3.1.7.1 1 .1 1.8 0 3.4-1.2 3.9-3 .2-.7.2-1.5-.1-2.2-.1-.3-.1-.5-.2-.8l10.3-13.5c-.6-.3-1.3-.5-2-.5zm-13.9 8.8c-.1 0-.1 0-.2.1-.2.1-.5.1-.8.1-.8 0-1.6-.5-1.9-1.3-.4-1.1.1-2.3 1.2-2.7.2-.1.5-.1.8-.1.8 0 1.6.5 1.9 1.3 0 0 0 .1.1.1.4 1-.1 2.1-1.1 2.5zm2.8 9.2h-.2c-.2.1-.4.1-.6.1-.9 0-1.7-.6-2-1.5-.3-1.1.3-2.3 1.4-2.6.2-.1.4-.1.6-.1.9 0 1.7.6 2 1.5v.1c.4 1.1-.2 2.2-1.2 2.5z"/>
+ <path fill="url(#N)" fill-rule="nonzero" d="M274.7 179.9c.4-1.1 1.2-2 2.3-2.4-.4-.2-.8-.3-1.2-.4-.3-.1-.6-.1-.9-.2-.2 1-.4 1.9-.8 3h.6z"/>
+ <path fill="url(#O)" fill-rule="nonzero" d="M180.9 206.3l.9 3.1c1.7-.5 2.6-2.3 2.1-4l-3 .9z"/>
+ <path fill="url(#P)" fill-rule="nonzero" d="M284.7 187.9c-.4-.2-.7-.3-1-.3-.7 0-1.3.3-1.6.9-1.7 3.1-4.9 4.9-8.3 4.9-.8 0-1.5-.1-2.3-.3-2.9-.7-5.3-2.8-6.4-5.6l3.7 1c.2 0 .3.1.5.1.8 0 1.6-.6 1.8-1.4.3-1-.3-2-1.4-2.3l-7.3-1.9c-.2 0-.3-.1-.5-.1-.8 0-1.6.6-1.8 1.4l-1.9 7.3c-.3 1 .3 2 1.4 2.3.2 0 .3.1.5.1.8 0 1.6-.6 1.8-1.4l.5-2c2.4 4.4 6.9 6.9 11.5 6.9 2.1 0 4.2-.5 6.1-1.5 2.3-1.3 4.3-3.2 5.5-5.6.5-.9.2-2-.8-2.5z"/>
+ <path fill="url(#Q)" fill-rule="nonzero" d="M172.7 212.8l2.1.8c.1-.1.3-.1.5-.1l3.8 1.3c.2 0 .3.2.3.3 1.3 0 2.6-.9 3-2.2l-7.7-2.7-2 2.6z"/>
+ <path fill="url(#R)" fill-rule="nonzero" d="M176.1 196l-.9-3-3.1.9 1 3"/>
+ <path fill="url(#S)" fill-rule="nonzero" d="M171.5 197.4l-.9-3.1-3.1 1 1 3"/>
+ <path fill="url(#T)" fill-rule="nonzero" d="M166.9 198.8l-.9-3.1-3.1 1 1 3"/>
+ <path fill="url(#U)" fill-rule="nonzero" d="M162.3 200.2l-.9-3.1c-1.7.5-2.6 2.3-2.1 4l3-.9z"/>
+ <path fill="url(#V)" fill-rule="nonzero" d="M274.7 180c-.2 0-.4-.1-.6-.1-.4 1.3-1 2.7-1.8 4.1.9 1 1.3 2.4 1 3.8-.3 1.3-1.3 2.3-2.5 2.8l.9.3c3-2.5 5.1-4.5 6.1-5.5l-.3-.1c-1.1-.3-2-1-2.5-1.9-.6-1-.7-2.1-.4-3.1 0-.1.1-.2.1-.3z"/>
+ <path fill="url(#W)" fill-rule="nonzero" d="M274.9 191.2c2.2-.3 4.2-1.7 5.3-3.7v-.1c.3-.4.6-.8 1-1.1l-1-.3s0 .1-.1.1c0 .2-1.9 2.2-5.2 5.1z"/>
+ <path fill="url(#X)" fill-rule="nonzero" d="M187.6 158.4c-1.4-.9-3.2-.6-4 .7-.8 1.3-.3 3 1.1 3.9 1.4.9 3.2.6 4-.7.8-1.2.3-3-1.1-3.9z"/>
+ <path fill="url(#Y)" fill-rule="nonzero" d="M276.7 136.6c-.3.7-.4 1.4-.4 2.1l-.9.3c-1.2.5-2.5 1.1-3.7 1.8-.2.1-.4.3-.7.4-.4.2-.7.5-1.2.8-.2.1-.4.3-.6.4l-.6.5c-.1.1-.3.2-.4.3h-.8c-1.1.1-9.8 2-18 3.9.6-1.9 1.2-3.8 1.6-5.8 1.3 0 2.7-.1 4-.2 1 .9 2.3 1.3 3.7 1.3 2.1 0 3.9-1.1 4.9-2.7.5.1 1 .1 1.5.1 4.8 0 9.1-3 10.7-7.5 3-1 5.2-3.7 5.7-6.9.6-.9 1.2-1.8 1.8-2.8 4-1.5 6.6-5.7 6-10 0-.4-.1-.7-.2-1.1 1.5-1.9 2.1-4.4 1.8-6.8-.3-2.1-1.2-4.1-2.7-5.6-.3-2.4-.8-4.7-1.5-7 .1-.4.1-.9.1-1.3 0-3.3-1.7-6.4-4.6-8.1-2.8-4.3-6.6-8-10.8-10.8-1.3-3.8-4.8-6.4-9-6.4-1.4 0-2.8.3-4.1.9-1.2-.3-2.4-.6-3.6-.8-1.7-1.5-4-2.4-6.2-2.4-.4 0-.8 0-1.2.1-2 .2-3.8 1.1-5.3 2.5-2.4.5-4.8 1.2-7 2.1-.6-.1-1.3-.2-2-.2-4.6 0-8.5 3.4-9.3 7.8l-.1.1c-4.1 1.1-7 4.8-7 9.1v.7c-.4.8-.8 1.7-1.1 2.5-1.6 1-2.6 2.8-2.6 4.8 0 .4 0 .7.1 1.1-.6-.6-1.2-1.2-1.9-1.7-.2-1.3-.8-2.4-1.4-3.4.3-2-.6-3.9-1.8-6.3-.2-.4-.4-.9-.7-1.3-.5-1-1.4-1.6-2.4-1.6-1.5 0-2.7 1.2-3.9 3.8-.7 1.6-2.2 5.3-1.1 7.6-.5 3.6 0 6 1.5 7.1l.1.1c.2 1.6.6 3.2 1.1 4.6-11 4.2
-28.2 12.1-33.8 19.4-1.3 1.8-1.6 4.3-.6 7.6 1.9 6.5 8.8 16.5 14 18.4 7.3 2.7 17.2 4.3 27.1 4.3h2c-2.1 1.4-4.1 2.9-6 4.5-3.9 1.5-7 2.8-9.5 3.9-.5-.8-1-1.5-1.6-2.2-1.1-1.3-2.4-2.4-3.8-3.3-2.9-1.8-6.2-2.8-9.7-2.8-6.2 0-11.9 3.1-15.2 8.3-1.1 1.7-1.8 3.4-2.3 5.3l.6.9c.2.3.1.6-.1.8-.1.1-.2.1-.3.1-.2 0-.3-.1-.5-.2-.5 3.2-.1 6.5 1 9.4 1.6 2.5 3.3 4.8 5 7.1.6.6 1.3 1.1 2.1 1.6 2.9 1.8 6.2 2.8 9.7 2.8 1.2 0 2.4-.1 3.5-.3l2.4-.6c-.2 1.1-.3 2.1-.3 3.2.7.5 1.4 1 2.2 1.5v-.1-1.3c0-.2 0-.5.1-.7 0-.4.1-.9.1-1.3 0-.3.1-.5.1-.8.1-.4.2-.9.2-1.3v-.2c0-.2.1-.4.1-.6.1-.5.2-.9.3-1.4.1-.3.1-.6.2-.8.1-.5.3-.9.4-1.4.1-.3.2-.6.3-.8.2-.5.4-1 .5-1.4.1-.3.2-.6.3-.8.2-.5.4-1 .7-1.5.1-.3.2-.5.4-.8.3-.5.5-1.1.8-1.6.1-.2.2-.5.4-.7.3-.6.7-1.2 1-1.8.1-.2.2-.4.3-.5.2-.3.4-.6.6-.8 3-4.4 5.4-6.8 5.4-6.8.1-.1.2-.3.2-.4 0-.1-.1-.3-.2-.4-.2-.2-.6-.2-.8 0-.1.1-2.3 2.3-5.1 6.4-1.1.2-2.1.3-3.1.5h-.1c-.4.1-.8.1-1.1.2h-.2c-.3 0-.6.1-.9.1h-.2c-.3 0-.6.1-.9.1-.2 0-.4 0-.6.1h-.7-.2s-.8 0-1.2-.5c0-.1-.1-.1-.1-.2s-.1-.1-.1-.2v-.6c0-.
2.1-.5.3-.9.1-.1.1-.2.2-.4.2-.3.6-.6 1.2-1 .1 0 .1-.1.2-.1s.1-.1.2-.1c1.1-.6 2.6-1.4 4.4-2.2 4.1-1.9 9.7-4.1 14.3-5.9.1 0 .1-.1.2-.1.5-.4 1-.9 1.6-1.3.4-.3.7-.6 1.1-.8.3-.3.7-.5 1-.8.8-.6 1.5-1.1 2.3-1.6.2-.1.4-.3.6-.4.5-.3 1.1-.7 1.6-1 .1-.1.3-.2.4-.3.8-.5 1.6-.9 2.4-1.4.3-.2.6-.4 1-.5 4.1-.6 10.4-1.6 14.2-3.2.3-.1.4-.4.3-.7-.1-.3-.4-.4-.7-.3-5.7 2.3-17.7 3.6-17.8 3.6h-.2c-1.7.1-3.4.2-5.1.2-9.9 0-19.5-1.6-26.3-4.1-.7-.3-1.4-.7-2.3-1.4-.2-.2-.4-.3-.6-.5-.4-.4-.8-.8-1.3-1.2-.2-.2-.4-.4-.6-.7-.4-.5-.9-1-1.3-1.5s-.8-1.1-1.2-1.6c-.6-.8-1.2-1.7-1.8-2.6-.4-.6-.7-1.2-1.1-1.8-2-3.6-3.3-7.2-2.9-9.7v-.1c.1-.6.3-1.1.7-1.6.2-.2.4-.4.6-.7.1-.1.1-.2.2-.2.1-.2.3-.3.4-.5l.3-.3.4-.4.3-.3c.1-.1.3-.3.5-.4.1-.1.2-.2.4-.3.2-.1.3-.3.5-.4.1-.1.3-.2.4-.3.2-.1.3-.3.5-.4.1-.1.3-.2.4-.3.2-.1.4-.3.6-.4.1-.1.3-.2.4-.3.2-.1.4-.3.6-.4.1-.1.3-.2.4-.3.2-.2.5-.3.7-.5.1-.1.2-.2.4-.2.3-.2.7-.4 1-.6.1-.1.2-.1.3-.2.3-.2.7-.4 1-.6.2-.1.3-.2.5-.3.2-.1.5-.3.7-.4.2-.1.4-.2.5-.3.2-.1.5-.3.7-.4l.6-.3c.2-.1.5-.3.7-.4l.6-.3c.2-
.1.5-.2.7-.4l.6-.3c.2-.1.5-.2.7-.4l.6-.3c.2-.1.5-.2.7-.3.2-.1.4-.2.7-.3.2-.1.5-.2.7-.3.2-.1.5-.2.7-.3.2-.1.5-.2.7-.3.2-.1.4-.2.7-.3.3-.1.5-.2.8-.3.5-.2.9-.4 1.4-.6l.6-.3c.3-.1.5-.2.8-.3l.6-.3c.3-.1.5-.2.8-.3l.6-.3c.3-.1.5-.2.8-.3.2-.1.4-.2.6-.2.3-.1.5-.2.8-.3.2-.1.4-.2.6-.2.3-.1.5-.2.8-.3.2-.1.4-.1.5-.2.3-.1.5-.2.8-.3.2-.1.4-.1.5-.2.3-.1.5-.2.8-.3.2-.1.3-.1.5-.2s.4-.1.6-.2c-.1.2-.1.5 0 .7 1.8 5.7 5.9 6.6 6.1 6.6h.2c.5 0 1-.4 1.1-.9.1-.6-.3-1.2-.9-1.3-.1 0-2-.5-3.5-3 3.4.1 7.2-2.6 7-6 1.4 1 3.5 2.9 3.5 5.5 0 3.8-3.7 5.1-3.9 5.2-.3.1-.4.4-.4.7 0 0 0 .1.1.1.1.2.3.3.5.3h.2s4.6-1.6 4.7-6.2c0-2-1-3.6-2.1-4.8l1.4-.4c.5.4 1.7 1.2 3.2 1.2h.6c.3 0 .5-.3.5-.6v-.1c-.1-.2-.3-.4-.6-.3-1.7.2-3.1-1.1-3.1-1.1-.1-.1-.4-.2-.6-.1l-2.3.7c-.2-.2-.5-.4-.7-.5 0-.7.1-1.4.1-2.2 0-.4.1-.9.2-1.3s.1-.9.2-1.3c-.5-.6-.7-1.3-.7-2.1 0-.6.1-1.1.4-1.5.2-.5.5-.9.9-1.2.1-.1.3-.2.4-.3.1-.1.3-.2.5-.2.2-.5.3-.9.5-1.3.2-.5.4-.9.6-1.4.1-.3.3-.7.5-1 0-.3-.1-.7-.1-1v-.1-.1c0-.6.1-1.3.3-1.8.2-.8.6-1.6 1.1-2.2.2-.3.5-.7.8-.9.5-
.5 1.1-.9 1.7-1.3.6-.3 1.3-.6 2.1-.7.3-.4.7-.7 1-1 0-.3.1-.7.2-1 .1-.4.2-.7.3-1 .9-2.3 3-4 5.5-4.5h.3c.3 0 .7-.1 1-.1.3 0 .6 0 .8.1.5.1.9.1 1.3.3.6-.3 1.3-.5 1.9-.8 1.3-.5 2.6-.9 4-1.2.7-.2 1.4-.3 2.1-.4.6-.6 1.2-1.1 2-1.5.8-.4 1.6-.7 2.5-.8.3 0 .6-.1.9-.1h1c.2 0 .4.1.5.1.1 0 .2.1.3.1.2 0 .3.1.5.1.1 0 .2.1.3.1.1.1.3.1.4.2.1 0 .2.1.3.1.1.1.3.2.4.2.1.1.2.1.3.2.1.1.3.2.4.3l.2.2c.2.2.4.3.6.5 1.7.2 3.3.6 4.9 1.1.6-.3 1.2-.6 1.8-.8.1 0 .2 0 .3-.1.2-.1.5-.1.7-.2h1c.4 0 .8 0 1.2.1h.2c.4.1.7.2 1 .3.1 0 .1 0 .2.1.3.1.7.3 1 .4 0 0 .1 0 .1.1l.9.6c.3.2.6.5.8.8.3.3.5.6.7.9v.1c.2.3.4.7.5 1v.1c.1.4.3.7.4 1.1.1.4.2.8.2 1.3 3.1 2.5 5.8 5.5 7.8 8.9 1.2 0 2.2.3 3.2.8.6.3 1.1.7 1.6 1.1.5.4.9.9 1.2 1.4 0 0 0 .1.1.1.1.2.3.5.4.7 0 0 0 .1.1.1l.3.9v.1c.1.2.1.5.2.7v.2c0 .3.1.6.1.9V92.9c0 .2-.1.5-.1.7-.3 1.7-1.2 3.1-2.5 4.2.2 1.5.3 2.9.3 4.4 1.2 1.2 2 2.8 2 4.7.1 2.2-.9 4.2-2.5 5.5.2.6.3 1.2.3 1.8.1 3.4-2.4 6.3-5.7 6.9-.8 1.2-1.7 2.3-2.6 3.3-.5 2.8-2.8 4.8-5.5 5-1.2 3.7-4.9 6.2-9 5.8-.9-.1-1.8-.3-2.6-.7h-.2c-.
4 1.6-1.9 2.6-3.5 2.5-.3 0-.5-.1-.8-.2-.3 1.2-.6 2.4-.9 3.5h1-2.4c.2-3.6-.3-5.8-.4-5.9-.1-.3-.4-.5-.7-.4h-.1c-.2.1-.4.4-.3.6 0 0 .9 3.8-.1 9.4-.4 1.4-.8 2.8-1.3 4.3-.1.2-.1.4-.2.6-.3.9-.6 1.7-1 2.6 7.4-1.8 15.5-3.6 19.4-4.4l-.6.6c-.9.9-1.9 2-2.7 2.9-.8 1-1.4 1.8-1.8 2.3-.2.3-.4.5-.5.7 0 0 0 .1-.1.1-.1.1-.1.2-.1.2-.2.3-.2.6-.3.9-2.9 1.5-6 3.1-9 4.5-2.9 1.4-5.5 2.7-7.6 3.6-.2.1-.3.2-.5.2-.1.1-.1.3-.2.4-.1.2-.2.4-.2.6 0 0 0 .1-.1.1-.1.4-.3.7-.4 1.1v.1c-.1.4-.3.8-.4 1.2-.1.4-.3.9-.4 1.3-.4 1.4-.8 2.9-1.1 4.4-1 4.8-1 5-.9 5.1.1.2.3.4.5.4h.2c.3-.1.4-.3.4-.6s.2-1.4.5-2.9c.9-.2 1.8-.3 2.6-.4 1.2-1.2 2.8-2 4.5-2.1 2-.2 3.9.6 5.3 1.8.8-.3 1.7-.5 2.7-.4 1.3.1 2.6.5 3.6 1.3 1.3-.2 2.4-.4 3.5-.7.4-.1.8-.3 1.2-.4.9-.8 1.9-1.6 3.1-2.2.7-.4 1.4-.6 2.1-.9 2.1-1.9 3.3-4 3.8-5.3.1-.2.1-.3.2-.5 0-.1.1-.3.1-.3.1-.2.1-.3.1-.3v.1c.1.1.2.3.3.6.4.9 1.1 2.6 1.5 4.9.8.1 1.6.2 2.3.3-.6-4.3-2.2-7-2.3-7.1-.4-.7-1.1-1.1-1.9-1.1h-.3c-.9.1-1.6.8-1.8 1.7-.1.2-1.6 5.6-7.9 8-2-1.7-4.3-3.1-7-4.3-2.9-1.2-6.1-1.8-9.7-1.8
-.8 0-1.6 0-2.5.1.1-.2.2-.4.2-.6 2.4-1.1 9.7-4.6 16.1-7.9.5.4 1.1.7 1.7.7.2 0 .4 0 .7-.1 0 0 .1 0 .3-.1.2-.1.5-.2.8-.3.6-.2 1.5-.6 2.7-1.2.1 0 .1-.1.2-.1.1.1.1.2.2.2.8.9 2 1.5 3.4 1.7.5.1.9.1 1.3.1 1.3 0 2.5-.4 3.5-1.1 2-1.5 2.3-4.1 2.3-4.2.1-.6-.4-1.2-1-1.2-.2 0-.4 0-.6.1-.3.2-.6.5-.6.9 0 0-.2 1.8-1.4 2.7-.7.6-1.8.8-3.1.6-1.1-.2-1.9-.6-2.4-1.4-1.1-1.6-.6-4-.5-4.1v-.6c-.1-.4-.4-.7-.8-.8-.6-.1-1.2.2-1.3.8 0 .1-.7 2.9.6 5.3h-.1c-1.1.5-2 .9-2.6 1.1-.3.1-.6.2-.7.3-.2.1-.3.1-.3.1-.4.1-.7 0-1-.1-.3-.2-.6-.5-.6-.8-.1-.3-.1-.7.1-1l.1-.2c.1-.2.2-.4.4-.7.3-.4.8-1.2 1.7-2.2.8-1 1.7-2 2.6-2.9.5-.5 1-1 1.6-1.5.6-.5 1.1-1 1.7-1.5.2-.2.4-.3.6-.5l.6-.5c.2-.1.4-.3.6-.4.1-.1.2-.1.3-.2.5 1.7 1.6 3.3 3 4.4.3.2.7.5 1 .7-.1.1-.2.2-.3.2-.2.2-.4.3-.6.4l-.6.5c-.1 0-.1.1-.2.1.4.2.8.3 1.2.5l.3-.3c.2-.2.4-.3.6-.5.7-.5 1.2-1 1.7-1.5 1-1 1.9-2 2.6-3.1.5-.7.8-1.3 1.1-1.8.3 0 .6 0 .9-.1 1.3-.3 4.6-1.7 6.4-7.7.2-.5 0-1.1-.5-1.5-.4-.4-1-.4-1.5-.2-.9.5-2.5 1-4.4.9-1.7-.1-3.3.5-4.3 1.6-.4-.4-.6-.1-.8.3 0-.1 0 0 0 0zm1
2.3-31.5c0 .3.1.6.1.9-.1-.3-.1-.6-.1-.9 0-.4-.1-.7-.2-1.1.1.4.1.8.2 1.1zm-104.7 62.1c-1.2 2-.9 3.4-.5 4.3.7 1.2 1.9 1.7 2.9 1.8h.6c.5 0 1.5-.1 4.7-.5-.7 1.3-1.4 2.6-2 3.9-.2-.2-.4-.4-.7-.5-1.5-.8-3.3-.3-4.1 1.1-.8 1.4-.2 3.2 1.3 4 .5.3 1 .4 1.5.4-.5 1.6-.9 3.1-1.2 4.6-2 .8-4 1.1-6.1 1.1-3.1 0-6.3-.9-9.1-2.6-7.9-5-10.2-15.5-5.2-23.3 3.2-5.1 8.7-7.8 14.3-7.8 3.1 0 6.3.9 9.1 2.6 2.1 1.3 3.7 3.1 5 5-9.3 4-10 5.2-10.5 5.9zm17.8-77.5c0-.1 0-.2-.1-.3v-.2-.4-.3-.4-.3c0-.1.1-.3.1-.4 0-.1 0-.2.1-.3 0-.2.1-.3.1-.5 0-.1.1-.2.1-.3.1-.2.1-.3.2-.5 0-.1.1-.2.1-.3.1-.2.1-.4.2-.6 0-.1 0-.1.1-.2.1-.2.2-.5.3-.7 0-.1.1-.1.1-.2.1-.2.2-.3.3-.5 0-.1.1-.1.1-.2.1-.1.1-.2.2-.4 0-.1.1-.1.1-.2.1-.1.1-.2.2-.3 0-.1.1-.1.1-.2l.2-.2s.1 0 .1-.1c2.4 1.9 2.2 7.3 2.2 7.4v.1c-1.1 1.6-3.1 2.1-4.4.9-.1-.1-.2-.1-.2-.2-.1-.1-.1-.2-.2-.3v.1zM204 98c-.1-.4-.1-.8-.1-1.2-.1-.1-.3-.1-.4-.2-.1-.1-.3-.2-.4-.3-.1-.1-.2-.1-.2-.2-.2-.3-.3-.7-.4-1.3-.1-.5-.1-1-.1-1.6 0-.3 0-.7.1-1.1 2.1 1.8 5.2.5 5.8-1.5.1.2.2.4.3.7.4 1.2.6 2.2.7 2.6v
.2c-.8 2.2-3.3 3.4-5.3 2.7.1.7.2 1.3.3 2-.3-.2-.3-.5-.3-.8zm9.1 1.2c-.2 3-4.3 5-7.1 4.5-.7-.5-1.2-1.8-1.6-3.4-.1-.4-.2-.7-.2-1.1V99c2.9 1.2 6.1-.8 6.5-3.5.4.3.9.7 1.4 1.2.7.7 1 1.5 1.1 2.1-.1.1-.1.3-.1.4zm74.3 13.9c-.1-.7-.3-1.3-.5-1.9.2.6.4 1.2.5 1.9 0 .2 0 .5.1.7-.1-.3-.1-.5-.1-.7zm-1.1-12.7c.5.4 1 .9 1.4 1.5-.4-.6-.8-1.1-1.4-1.5zm-20.4 37.3h-.5.5zm-3.3-.4c.3.1.7.2 1 .2-.4-.1-.7-.1-1-.2-.1 0-.1 0 0 0-.1 0-.1 0 0 0zm-2 2.5c-.3.2-.7.3-1.1.4.5 0 .8-.2 1.1-.4zm-1.4.5h-.3.3zm-12.9 26.1h.1-.4.3zm31.4-29.4c.6-1.2 1.9-1.9 3.5-1.9h.6c.5.6-.2 1 .4 2.1.7 1.3 2.3-.3 3.3.6-1.5 2.6-3.3 3.3-4.2 3.5-1.2.3-2.5 0-3.1-.8-.8-1-1-2.4-.5-3.5zm-.2 4.3c.5.6 1.2.9 2 1.1-.2.4-.5.8-.8 1.3-.4.6-.9 1.2-1.3 1.7-1.7-.7-3.1-2.3-3.5-4.2v-.4c.7-.3 1.3-.7 2-.9.3-.1.5-.2.7-.3.2.7.5 1.2.9 1.7z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M219.1 84.8c0-.6.1-1.3.3-1.8-.2.5-.3 1.2-.3 1.8z"/>
+ <path fill="url(#Z)" fill-rule="nonzero" d="M219.1 84.8c0-.6.1-1.3.3-1.8-.2.5-.3 1.2-.3 1.8z"/>
+ <path fill="url(#aa)" fill-rule="nonzero" d="M219.1 84.8c0-.6.1-1.3.3-1.8-.2.5-.3 1.2-.3 1.8z"/>
+ <path fill="url(#ab)" fill-rule="nonzero" d="M178.6 177.5c-.4-.2-.8-.3-1.1-.4l2.7 3.2c.2.2.2.6-.1.8-.1.1-.2.1-.4.1s-.3-.1-.4-.2l-3.3-4c-.9.1-1.6.6-2 1.3-.2.3-.3.7-.3 1.1 1.2 1.3 2.4 2.6 3.6 3.7 1.4.3 2.7-.2 3.3-1.2.7-1.4-.2-3.4-2-4.4z"/>
+ <path fill="url(#ac)" fill-rule="nonzero" d="M267.8 172.1c-2.3 1.3-4.3 3.2-5.5 5.6-.5.9-.1 2.1.8 2.5h.1l.4.1c.2 0 .3.1.5.1.7 0 1.4-.4 1.7-1.1 1.7-3 4.9-4.8 8.2-4.8.8 0 1.6.1 2.4.3 2.9.7 5.3 2.8 6.4 5.6l-3.7-1c-.2 0-.3-.1-.5-.1-.8 0-1.6.6-1.8 1.4-.3 1 .3 2 1.4 2.3l7.3 1.9c.2 0 .3.1.5.1.8 0 1.6-.6 1.8-1.4l1.9-7.3c.3-1-.3-2-1.4-2.3-.2 0-.3-.1-.5-.1-.8 0-1.6.6-1.8 1.4l-.5 2c-2.4-4.4-6.9-6.9-11.5-6.9-2.2.2-4.3.7-6.2 1.7z"/>
+ <path fill="url(#ad)" fill-rule="nonzero" d="M180.7 194.6c-.4-1.4-1.7-2.3-3.1-2.3-.3 0-.6 0-.9.1l.9 3.1 3.1-.9z"/>
+ <path fill="url(#ae)" fill-rule="nonzero" d="M172.6 172.1c.8-1.4.2-3.2-1.3-4-1.5-.8-3.3-.3-4.1 1.1-.8 1.4-.2 3.2 1.3 4 1.5.8 3.3.3 4.1-1.1z"/>
+ <path fill="url(#af)" fill-rule="nonzero" d="M175.8 164.2c1.7 0 3.1-1.3 3.1-2.9 0-1.6-1.4-2.9-3.1-2.9-1.7 0-3.1 1.3-3.1 2.9 0 1.6 1.4 2.9 3.1 2.9z"/>
+ <path fill="url(#ag)" fill-rule="nonzero" d="M224.1 117.1c.4 0 .9.1 1.3.1 0-.1.1-.2.1-.3v-3c0-.7-.6-1.3-1.3-1.3-.7 0-1.3.6-1.3 1.3v3c0 .1 0 .2.1.3.2-.1.7-.1 1.1-.1z"/>
+ <path fill="url(#ah)" fill-rule="nonzero" d="M237.5 199.2c.6-7.2 1.2-16.6 1.3-16.7 0-.3-.2-.6-.5-.6s-.6.2-.6.5c0 .2-1.4 19.4-1.9 23.9v.3c0 .2-.1.5-.1.7v.1c-.1.6-.2 1.1-.2 1.7v.2c.8-.2 1.6-.4 2.3-.6.1-.9.3-1.8.4-2.8 5.1-.6 12.8-2.1 20-5.6 2.3-1.3 4.3-2.6 6.2-3.9-.5-.4-1-.8-1.5-1.3-.8.7-1.8 1.2-2.9 1.2-.3 0-.7 0-1-.1-1.4.9-3 1.8-4.7 2.6-6.6 3-13 4.1-17.1 4.5.1-.9.2-1.8.2-2.9 1.8-.1 3.6-.2 5.5-.5 5.9-.9 10.7-2.9 14.2-4.8-.2-.2-.4-.5-.6-.8 0 0 0-.1-.1-.2-3.4 1.9-8 3.8-13.7 4.7-1.8.2-3.5.4-5.2.4z"/>
+ <path fill="url(#ai)" fill-rule="nonzero" d="M264.9 127.4c1 0 2.1-.3 3.3-1.3 2.4-2 2.5-4.3 2.3-5.6 1.4-.2 2.8-.8 4.2-2.2 3.6-3.7 2.9-7.8 2.1-9.4-.3-.5-1-.8-1.5-.5-.5.3-.8 1-.5 1.5 0 0 1.7 3.4-1.7 6.8-2.9 2.9-5.8 1.1-6.1.9-.5-.4-1.2-.2-1.6.3-.4.5-.2 1.2.3 1.6.8.5 2.1 1.1 3.7 1.2.2.9.2 2.9-1.9 4.7-2.6 2.1-4.8.3-4.9.2-.2-.2-.6-.2-.8.1-.2.2-.2.6.1.8 0-.2 1.2.9 3 .9z"/>
+ <path fill="url(#aj)" fill-rule="nonzero" d="M249.6 126.6c1 1 2.7 2.2 5.8 2.2.8 0 1.7-.1 2.7-.3.3-.1.5-.3.4-.6-.1-.3-.3-.5-.6-.4-4.9.9-6.7-1-7.4-1.7-1.3-1.3-1.9-4.5-1.9-4.6 0-.2-.2-.4-.4-.4-.1 0-5.1-1.5-8.5-5.7-3.1-3.9-3.5-8.4-3.5-8.4 0-.2-.1-.4-.3-.5-.8-.4-3.2-1.7-3.8-3.2-1.3-3.1.1-4.9.1-4.9.2-.2.2-.6-.1-.8-.2-.2-.6-.2-.8.1 0 0-.5.6-.8 1.7l-3.3-.1c-.3 0-.6.2-.6.5v.2c.1.2.3.4.5.4l3.2.1c0 .9.1 2 .6 3.2.4.9 1.2 1.7 2 2.3.8.6 1.6 1.1 2.1 1.3 0 .3.1.8.3 1.4.4 1.8 1.3 4.7 3.5 7.3.4.5.8 1 1.3 1.4 2.9 2.9 6.4 4.2 7.4 4.6.2 1 .8 3.6 2.1 4.9z"/>
+ <path fill="url(#ak)" fill-rule="nonzero" d="M179 200.2l3.1-1-.9-3-3.1.9"/>
+ <path fill="url(#al)" fill-rule="nonzero" d="M231.2 188.3l-16.2-4.7c-.3-.1-.6-.1-.9-.1-1.5 0-2.8 1-3.2 2.4l-5.6 19.4c-.5 1.8.5 3.7 2.3 4.2l16.2 4.7c.3.1.6.1.9.1 1.5 0 2.8-1 3.2-2.4l5.6-19.4c.5-1.8-.5-3.7-2.3-4.2zm-1.4 4.9l-4.7 16.2c-.2.7-.9 1.2-1.6 1.2-.2 0-.3 0-.5-.1l-12.9-3.7c-.9-.3-1.4-1.2-1.2-2.1l4.7-16.2c.2-.7.9-1.2 1.6-1.2.2 0 .3 0 .5.1l12.9 3.7c.9.2 1.5 1.2 1.2 2.1z"/>
+ <path fill="url(#am)" fill-rule="nonzero" d="M99.3 199.1c-.2-.6-.9-1-1.5-.7-.6.2-1 .9-.7 1.5l.8 2.4c.6-.6 1.4-.9 2.2-.8l-.8-2.4z"/>
+ <path fill="url(#an)" fill-rule="nonzero" d="M224.4 196.8l-8.1-2.3h-.2c-.4 0-.7.2-.8.6-.1.4.1.9.6 1l8.1 2.3h.2c.4 0 .7-.2.8-.6.1-.4-.2-.8-.6-1z"/>
+ <path fill="url(#ao)" fill-rule="nonzero" d="M108 198.9c.6-.6 1.4-.9 2.2-.8l-.8-2.4c-.2-.6-.9-1-1.5-.7-.6.2-1 .9-.7 1.5l.8 2.4z"/>
+ <path fill="url(#ap)" fill-rule="nonzero" d="M106.2 206.7c1-.5 2-1 3.1-.7.1-.1.3-.2.4-.4.5-.5.9-1.1 1.3-1.8.2-.4.4-.7.6-1.1.2-.4.3-.9.5-1.4l.1-.2v-.1c0-.1-.1-.2-.2-.1-.2.1-.5.1-.7.2-.3.1-.7.2-1 .3l-1.7.5c-1.2.3-2.3.7-3.5 1.1-1.1.4-2.3.8-3.4 1.2l-1.7.6c-.3.1-.6.3-1 .4-.2.1-.5.2-.7.3 0 0-.1 0-.1.1-.1.1 0 .2 0 .3l.2.1c.4.3.8.6 1.2.8.4.2.8.4 1.1.6.7.3 1.4.5 2.1.6.2 0 .4 0 .5.1.1-.1.1-.2.2-.2.7-.9 1.7-1 2.7-1.2zm-5.4-1.9c.6-.1 1.3-.3 2-.5-.7.2-1.4.3-2 .5zm6.6-2c.7-.3 1.4-.6 1.9-.8-.5.2-1.2.5-1.9.8-.7.3-1.5.6-2.3.8.8-.2 1.6-.5 2.3-.8z"/>
+ <path fill="url(#aq)" fill-rule="nonzero" d="M225.3 193.6l-8.1-2.3h-.2c-.4 0-.7.2-.8.6-.1.4.1.9.6 1l8.1 2.3h.2c.4 0 .7-.2.8-.6.1-.4-.2-.9-.6-1z"/>
+ <path fill="url(#ar)" fill-rule="nonzero" d="M164 84.3c-.2 0-.2.3 0 .3 1.8.5 3.3 1.9 3.7 3.7 0 .2.3.2.3 0 .5-1.8 1.9-3.3 3.7-3.7.2 0 .2-.3 0-.3-1.6-.4-2.9-1.6-3.5-3.1h-.7c-.6 1.5-1.9 2.7-3.5 3.1z"/>
+ <path fill="url(#as)" fill-rule="nonzero" d="M213.9 202.6l3.2.9h.2c.4 0 .7-.2.8-.6.1-.4-.1-.9-.6-1l-3.2-.9h-.2c-.4 0-.7.2-.8.6-.1.4.2.9.6 1z"/>
+ <path fill="url(#at)" fill-rule="nonzero" d="M227.9 119.2l-.3-.3c-.1-.1-.2-.2-.3-.2-.7-.5-1.8-1.1-3.2-1.1-2.9 0-4.4 2.2-4.5 2.3-.3.5-.2 1.2.3 1.5.5.3 1.2.2 1.5-.3 0 0 .9-1.3 2.6-1.3 1.1 0 1.9.5 2.3.9l.2.2.2.2c.2.3.6.5.9.5.2 0 .4-.1.6-.2.5-.3.7-1 .3-1.5.1 0-.1-.3-.6-.7z"/>
+ <path fill="url(#au)" fill-rule="nonzero" d="M196.8 121.5c.5.3 1.2.2 1.5-.3 0 0 .1-.2.4-.4.4-.4 1.2-.9 2.2-.9 1.7 0 2.6 1.3 2.6 1.3.2.3.6.5.9.5.2 0 .4-.1.6-.2.5-.3.7-1 .3-1.5-.1-.1-1.5-2.3-4.5-2.3-1.9 0-3.2 1-3.9 1.7l-.3.3c-.2.2-.3.4-.3.4-.2.4 0 1.1.5 1.4z"/>
+ <path fill="url(#av)" fill-rule="nonzero" d="M200.9 117.1c.4 0 .9.1 1.3.1 0-.1.1-.2.1-.3v-3c0-.7-.6-1.3-1.3-1.3-.7 0-1.3.6-1.3 1.3v3c0 .1 0 .2.1.3.3-.1.7-.1 1.1-.1z"/>
+ <path fill="url(#aw)" fill-rule="nonzero" d="M207.7 137.3l-1.5-.6c-.7-.3-1.5-.5-2.2-.8l-3.8-1.3-7.5-2.4c-.2-.1-.4-.1-.6-.2-1.1 1.2-2.3 2.4-2.8 2.7-.4.2-3.4-.5-3.5-.8-.1-.2.3-1.9.7-3.5-.5-.1-.9-.3-1.4-.4l-.6-.1c-.3 1.4-.7 3.1-.9 3.2-.4.3-2.9-1.2-3.1-1.5-.1-.2-.5-1.6-.7-2.9-.3-.1-.5-.1-.8-.2-.5-.1-1.1-.2-1.6-.4h-.2c-.2.1-.3.3-.3.5l.1.5c.3 1.1.7 2.2 1.2 3 .4.9.9 1.7 1.3 2.5.9 1.5 1.9 2.7 3 3.8.3.3.6.5.9.8.2-.1.4-.1.6-.1-.2 0-.4.1-.6.1 1.9 1.6 3.9 2.7 6 3.3h.2c2.2.6 4.4.8 6.9.5.4 0 .8-.1 1.2-.2 1.5-.3 3-.8 4.6-1.5.8-.4 1.6-.8 2.5-1.3.8-.5 1.7-1.1 2.6-1.9l.4-.3c0-.1.1-.1.1-.2.2 0 0-.2-.2-.3z"/>
+ <path fill="url(#ax)" fill-rule="nonzero" d="M231.2 80.2c.4 0 .6-.2.6-.5 0-.1.5-3 4.2-3.5 1.8-.3 2.9.5 3.5 1.2-3.5 2.2-4.1 5.7-3.9 7.3.1.6.6 1 1.1 1h.1c.6-.1 1-.6 1-1.2 0 0-.4-3.8 4-5.8 3.8-1.7 5.8 1 6.1 1.4.3.5 1 .6 1.5.3s.6-1 .3-1.5c-.5-.7-1.3-1.5-2.5-2.1.5-.9 1.6-2.1 3.8-2.4 3.3-.5 4.2 2.3 4.3 2.4.1.3.4.5.7.4.3-.1.5-.4.4-.7 0 0-1.3-3.8-5.5-3.2-2.8.4-4.1 2-4.7 3.1-1.5-.5-3.3-.5-5.3.4-.1.1-.3.1-.4.2-.8-1-2.2-2.1-4.7-1.7-4.5.6-5.1 4.4-5.2 4.4 0 .2.3.5.6.5z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M207.7 223.7v.2c0 .2.1.4.1.6v.2c0 .2.1.4.1.6v.5c0 .1 0 .2-.1.2l-.2.2H207.3h-.1-.1c-.1 0-.1 0-.2-.1h-.1c-.1 0-.2-.1-.3-.2 0 0-.1 0-.1-.1-.1-.1-.2-.1-.3-.2l-.1-.1c-.1-.1-.2-.1-.3-.2-.1 0-.1-.1-.2-.1l-.3-.3-.2-.2-.3-.3-.2-.2-.5-.5-.1-.1-.4-.4c-1 .1-1.9.1-2.8.2 3.3 3.6 5 4.9 6.6 4.9.9 0 1.8-.4 2.3-1.2.4-.6.8-1.1.2-4.3-.8 0-1.5.1-2.3.1.1.4.1.6.2.8z"/>
+ <path fill="url(#ay)" fill-rule="nonzero" d="M207.7 223.7v.2c0 .2.1.4.1.6v.2c0 .2.1.4.1.6v.5c0 .1 0 .2-.1.2l-.2.2H207.3h-.1-.1c-.1 0-.1 0-.2-.1h-.1c-.1 0-.2-.1-.3-.2 0 0-.1 0-.1-.1-.1-.1-.2-.1-.3-.2l-.1-.1c-.1-.1-.2-.1-.3-.2-.1 0-.1-.1-.2-.1l-.3-.3-.2-.2-.3-.3-.2-.2-.5-.5-.1-.1-.4-.4c-1 .1-1.9.1-2.8.2 3.3 3.6 5 4.9 6.6 4.9.9 0 1.8-.4 2.3-1.2.4-.6.8-1.1.2-4.3-.8 0-1.5.1-2.3.1.1.4.1.6.2.8z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M231.2 223.1c-.1.1-.1.2-.2.3-.1.2-.2.3-.3.4 0 .1-.1.2-.1.2-.1.2-.2.4-.4.5v.1c-.1.2-.3.4-.4.5 0 .1-.1.1-.1.1-.1.1-.2.2-.2.3 0 .1-.1.1-.1.1l-.2.2-.1.1c-.1.1-.1.1-.2.1l-.1.1c-.1 0-.1.1-.2.1 0 0-.1 0-.1.1h-.2-.1-.1-.1c-.1 0-.2-.1-.2-.1l-.1-.1c-.1-.1-.1-.3-.2-.6s-.1-.6-.1-1c0-.3-.1-.7-.1-1.1v-.9h-2.2c.2 4.5.8 4.9 1.4 5.4.5.4 1.2.6 1.8.6 2.3 0 4.3-2.8 5.8-5.9-.8 0-1.6 0-2.5-.1-.3.4-.4.5-.4.6z"/>
+ <path fill="url(#az)" fill-rule="nonzero" d="M231.2 223.1c-.1.1-.1.2-.2.3-.1.2-.2.3-.3.4 0 .1-.1.2-.1.2-.1.2-.2.4-.4.5v.1c-.1.2-.3.4-.4.5 0 .1-.1.1-.1.1-.1.1-.2.2-.2.3 0 .1-.1.1-.1.1l-.2.2-.1.1c-.1.1-.1.1-.2.1l-.1.1c-.1 0-.1.1-.2.1 0 0-.1 0-.1.1h-.2-.1-.1-.1c-.1 0-.2-.1-.2-.1l-.1-.1c-.1-.1-.1-.3-.2-.6s-.1-.6-.1-1c0-.3-.1-.7-.1-1.1v-.9h-2.2c.2 4.5.8 4.9 1.4 5.4.5.4 1.2.6 1.8.6 2.3 0 4.3-2.8 5.8-5.9-.8 0-1.6 0-2.5-.1-.3.4-.4.5-.4.6z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M167.7 80.6c-.1.2-.1.4-.2.6h.7c-.1-.2-.2-.4-.2-.6 0-.2-.3-.2-.3 0z"/>
+ <path fill="url(#aA)" fill-rule="nonzero" d="M167.7 80.6c-.1.2-.1.4-.2.6h.7c-.1-.2-.2-.4-.2-.6 0-.2-.3-.2-.3 0z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M118.4 58.7c.1.2.2.3.4.3h.1c.3-.1.4-.3.4-.6v-.1l-1.9-5.3c-.1-.3-.4-.4-.6-.3-.3.1-.4.4-.3.6l1.9 5.4z"/>
+ <path fill="url(#aB)" fill-rule="nonzero" d="M118.4 58.7c.1.2.2.3.4.3h.1c.3-.1.4-.3.4-.6v-.1l-1.9-5.3c-.1-.3-.4-.4-.6-.3-.3.1-.4.4-.3.6l1.9 5.4z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M134.3 121.9c.2-.2.5-.4.9-.2v.1l2.4-1.5v-3.5l-3.4 2.1v3h.1zM137.7 164.3c-.2.2-.4.6-.4.9 0 .9.1 1.8.4 2.6v-3.5z"/>
+ <path fill="url(#aC)" fill-rule="nonzero" d="M137.7 164.3c-.2.2-.4.6-.4.9 0 .9.1 1.8.4 2.6v-3.5z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M115.5 59c.3 0 .5-.2.5-.5v-5.3c0-.3-.2-.5-.5-.5s-.5.2-.5.5v5.3c0 .3.2.5.5.5z"/>
+ <path fill="url(#aD)" fill-rule="nonzero" d="M115.5 59c.3 0 .5-.2.5-.5v-5.3c0-.3-.2-.5-.5-.5s-.5.2-.5.5v5.3c0 .3.2.5.5.5z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M112.6 59c.3 0 .5-.2.5-.5v-5.8c0-.3-.2-.5-.5-.5s-.5.2-.5.5v5.8c0 .3.2.5.5.5z"/>
+ <path fill="url(#aE)" fill-rule="nonzero" d="M112.6 59c.3 0 .5-.2.5-.5v-5.8c0-.3-.2-.5-.5-.5s-.5.2-.5.5v5.8c0 .3.2.5.5.5z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M114 59c.3 0 .5-.2.5-.5v-4.8c0-.3-.2-.5-.5-.5s-.5.2-.5.5v4.8c0 .3.3.5.5.5z"/>
+ <path fill="url(#aF)" fill-rule="nonzero" d="M114 59c.3 0 .5-.2.5-.5v-4.8c0-.3-.2-.5-.5-.5s-.5.2-.5.5v4.8c0 .3.3.5.5.5z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M129.1 125.6l4.1-2.6v-.5c0-.1-.1-.1-.1-.2 0 0 .1 0 .1.1v-2.9l-5.6 3.6c-.8.3-1.1 1.2-.8 2 .2.6.8.9 1.3.9.2 0 .4 0 .6-.1.1-.1.2-.2.4-.3z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M139 115.8l-1.3.9v3.5l2.2-1.4v-8.3c-.5.7-.9 1.5-1.1 2.3-.1.5-.1 1-.1 1.4.1.6.1 1.1.3 1.6zM139.9 165.2c0-.7-.6-1.3-1.3-1.3-.4 0-.7.1-.9.4v3.5c.3 1.1.7 2.1 1.3 3 .6-.9.9-1.9.9-3v-2.6z"/>
+ <path fill="url(#aG)" fill-rule="nonzero" d="M139.9 165.2c0-.7-.6-1.3-1.3-1.3-.4 0-.7.1-.9.4v3.5c.3 1.1.7 2.1 1.3 3 .6-.9.9-1.9.9-3v-2.6z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M138.7 159.7c-.1.3 0 .7.4.8l.8.3v-4.4l-1.2 3.3z"/>
+ <path fill="url(#aH)" fill-rule="nonzero" d="M138.7 159.7c-.1.3 0 .7.4.8l.8.3v-4.4l-1.2 3.3z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M198 217c.5.6.9 1.3 1.5 1.9-.5-.7-1-1.3-1.5-1.9z"/>
+ <path fill="url(#aI)" fill-rule="nonzero" d="M198 217c.5.6.9 1.3 1.5 1.9-.5-.7-1-1.3-1.5-1.9z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M207.8 226l-.2.2c.1-.1.2-.1.2-.2z"/>
+ <path fill="url(#aJ)" fill-rule="nonzero" d="M207.8 226l-.2.2c.1-.1.2-.1.2-.2z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M224.1 117.6c1.4 0 2.5.5 3.2 1.1-.7-.5-1.8-1.1-3.2-1.1z"/>
+ <path fill="url(#aK)" fill-rule="nonzero" d="M224.1 117.6c1.4 0 2.5.5 3.2 1.1-.7-.5-1.8-1.1-3.2-1.1z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M224.1 119.9c1.1 0 1.9.5 2.3.9-.4-.4-1.2-.9-2.3-.9z"/>
+ <path fill="url(#aL)" fill-rule="nonzero" d="M224.1 119.9c1.1 0 1.9.5 2.3.9-.4-.4-1.2-.9-2.3-.9z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M134.3 121.9v-3.1l-1.1.7v2.9s-.1 0-.1-.1c0 .1.1.1.1.2v.5l2.1-1.3v-.1c-.5-.1-.8 0-1 .3z"/>
+ <path fill="url(#aM)" fill-rule="nonzero" d="M150.7 112.6l-4.5 2.7c-.3.2-.7.3-1 .3-.6 0-1.3-.3-1.6-.9-.4-.6-.4-1.3-.1-1.8.1-.4.4-.7.8-1l4.2-2.7c-.7-.5-1.5-.9-2.3-1.1-.4-.1-.8-.1-1.3-.1-2 0-3.8 1-4.9 2.5-.5.7-.9 1.5-1.1 2.3-.1.5-.1 1-.1 1.4 0 .5.1 1 .3 1.5v.1l-1.3.8-3.4 2.1-1.1.7-5.6 3.6c-.8.3-1.1 1.2-.8 2 .2.6.8.9 1.3.9.2 0 .4 0 .6-.1.1-.1.3-.1.4-.2l4.1-2.6 2.1-1.3 2.4-1.5 2.2-1.4.7-.5c.8.8 1.7 1.3 2.8 1.6.5.1.9.2 1.4.2 1.4 0 2.7-.5 3.7-1.3s1.8-2 2.1-3.4c.2-1 .2-1.9 0-2.8z"/>
+ <path fill="#FFFEFE" fill-rule="nonzero" d="M143.5 114.7c.4.6 1 .9 1.6.9.4 0 .7-.1 1-.3l4.5-2.7c.2.9.2 1.9 0 2.8-.3 1.4-1.1 2.6-2.1 3.4 1.1-.8 1.9-2.1 2.2-3.5.2-.9.2-1.9 0-2.8l-4.6 2.7c-.3.2-.7.3-1 .3-.6 0-1.3-.3-1.7-.9-.3-.5-.4-1.2-.2-1.7-.1.5-.1 1.2.3 1.8z"/>
+ <path fill="url(#aN)" fill-rule="nonzero" d="M143.5 114.7c.4.6 1 .9 1.6.9.4 0 .7-.1 1-.3l4.5-2.7c.2.9.2 1.9 0 2.8-.3 1.4-1.1 2.6-2.1 3.4 1.1-.8 1.9-2.1 2.2-3.5.2-.9.2-1.9 0-2.8l-4.6 2.7c-.3.2-.7.3-1 .3-.6 0-1.3-.3-1.7-.9-.3-.5-.4-1.2-.2-1.7-.1.5-.1 1.2.3 1.8z"/>
+ <path fill="#FFFEFE" fill-rule="nonzero" d="M126.8 125.1c-.3-.8 0-1.7.8-2l5.6-3.6 1.1-.7 3.4-2.1 1.3-.8v-.1l-11.5 7.3c-.8.3-1.1 1.3-.8 2 .3.6.8.9 1.4.9h.1c-.7 0-1.2-.3-1.4-.9z"/>
+ <path fill="url(#aO)" fill-rule="nonzero" d="M126.8 125.1c-.3-.8 0-1.7.8-2l5.6-3.6 1.1-.7 3.4-2.1 1.3-.8v-.1l-11.5 7.3c-.8.3-1.1 1.3-.8 2 .3.6.8.9 1.4.9h.1c-.7 0-1.2-.3-1.4-.9z"/>
+ <path fill="#FFFEFE" fill-rule="nonzero" d="M139.9 110.5c1.1-1.5 2.9-2.5 4.9-2.5.4 0 .8 0 1.3.1.8.2 1.6.6 2.3 1.1l.2-.1c-.7-.6-1.5-1-2.4-1.2-.4-.1-.8-.1-1.3-.1-2.8 0-5.4 2-6 4.9-.1.5-.1 1-.1 1.6 0-.5 0-1 .1-1.4.1-1 .5-1.7 1-2.4z"/>
+ <path fill="url(#aP)" fill-rule="nonzero" d="M139.9 110.5c1.1-1.5 2.9-2.5 4.9-2.5.4 0 .8 0 1.3.1.8.2 1.6.6 2.3 1.1l.2-.1c-.7-.6-1.5-1-2.4-1.2-.4-.1-.8-.1-1.3-.1-2.8 0-5.4 2-6 4.9-.1.5-.1 1-.1 1.6 0-.5 0-1 .1-1.4.1-1 .5-1.7 1-2.4z"/>
+ <path fill="url(#aQ)" fill-rule="nonzero" d="M106.4 207.6c.1 0 .1 0 0 0h.1c1-.3 1.9-.9 2.7-1.6-1.1-.3-2 .2-3.1.7-1 .2-2 .3-2.7 1l-.2.2c1.2.2 2.3 0 3.2-.3z"/>
+ <path fill="url(#aR)" fill-rule="nonzero" d="M118.3 196.1c.7-1.4.9-3 .6-4.6-.4-2.1-1.5-3.9-3.3-5.1-1.4-1-3-1.4-4.6-1.4-1.5 0-3 .5-4.2 1.3-.2-.2-.4-.3-.6-.5-1.2-.8-2.5-1.2-4-1.2-2.1 0-4 1-5.3 2.6h-.7c-2.7 0-5.2 1.4-6.8 3.6-1.8 2.6-1.9 5.9-.6 8.6-.7.5-1.2 1.1-1.7 1.8-1.3 1.8-1.8 4.1-1.4 6.3.4 2.2 1.6 4.1 3.5 5.4 1.2.9 2.6 1.4 4.1 1.5.4 1.1 1.2 2.1 2.2 2.8 1 .7 2.2 1.1 3.5 1.1 1 .9 2.2 1.6 3.7 2.2l1 5.5h2.3l-1.3-7.2c-1.3-.4-2.7-1-3.8-1.8-.4-.3-.7-.6-1-1h-.1l-.1-.1c-.4-.4-.7-1-.9-1.6v-.1c-.3-.9-.2-1.7.1-1.8.2-.1.4-.1.5 0 .1.1.2.3.2.4v.2c0 .2.1.4.1.6V213.9c.3.9 1 2 2.2 2.7.1 0 .2.1.3.1.6.4 1.3.6 1.9.9 0 0 .1 0 .1.1l-.5-3h-.1-.1c-.1-.1-.3-.1-.4-.2-.3-.1-.6-.3-.9-.5 0 0-.1 0-.1-.1-.1.3-.2.5-.4.7l-.3.3s0-.1-.1-.1c-.6-.7-.9-1.5-.9-2-.1-.6-.3-1-.8-1.3-.4-.3-1-.3-1.5-.1-.5.2-1.4.8-.7 3.2.1.5.4 1 .6 1.4l.1.1c-.6-.1-1.2-.3-1.7-.6-.6-.4-1-1-1.3-1.6-.1-.2-.2-.4-.2-.6v-.1c-.1-.3-.1-.6-.1-.9-.3.1-.7.1-1 .1-1.2 0-2.5-.3-3.6-1.1-2.2-1.5-3-4.1-2.4-6.5l.3-.9v-.1c.2-.4.4-.7.6-1.1.8-1.2 2-2 3.2-2.4l-.
1-.1c-2.1-2.1-2.5-5.4-.8-7.9.5-.7 1-1.2 1.6-1.6 1-.7 2.2-1 3.3-1 .6 0 1.2.1 1.8.2 0-.1.1-.1.1-.2.1-.3.2-.5.4-.7.7-1 1.8-1.6 2.9-1.8.3 0 .5-.1.8-.1.9 0 1.8.2 2.7.8.7.5 1.3 1.2 1.6 2 .1-.1.1-.2.2-.2 1.1-1.4 2.7-2.1 4.3-2.1.7 0 1.3.1 2 .3.5.2.9.4 1.3.7 2.6 1.8 3.2 5.3 1.4 7.9-.2.2-.3.4-.5.6.1 0 .1.1.2.1.3.1.5.3.8.4.2.2.4.3.7.5 2.4 2.2 2.9 5.8 1 8.5-1.2 1.8-3.2 2.8-5.3 2.8h-.6c-.1 1.1-.4 2.1-1.1 3-.1.1-.1.2-.2.3-.1.2-.3.3-.5.5l-.4.4-.1.1c-.4.3-.8.6-1.2.8h-.1c-.1 0-.2.1-.3.1-1 .4-2 .3-2 .3-.2 0-.3.1-.4.2-.1.1-.2.2-.2.3 0 .3.2.6.5.6h.4c.5 0 1.3-.1 2.2-.4h.1l.6 3.3c.2-.1.4-.1.5-.2.6-.3 1.2-.7 1.6-1.1l.1-.1c.1-.1.1-.3 0-.9-.1-.6-.4-1.2-.6-1.6-.1-.2-.1-.3-.2-.5s0-.4.1-.6l.2-.2h.2c.2 0 .5.1.6.4 0 .1.1.2.2.4.2.4.4.9.5 1.4v.1c.6-1.2.9-2.5 1.1-3.7v-.1c.1-.3.3-.5.6-.5h.1c.3.1.5.4.5.7-.4 1.9-1 4.2-2.4 5.8l-.1.1c-.6.6-1.3 1.2-2.1 1.5-.2.1-.5.2-.7.2h-.1l1 5.4c.1.3-.2.7-.7.9l2.7.3c.2-.5.3-1 .2-1.6l-.7-3.6c.8-.4 1.4-1 2.1-1.7l.1-.1c1.8-2.1 2.5-4.9 2.8-6.8.1-.8 0-1.5-.5-2.1 1.2-.6 2.2-1.5 3-2.7 1.3-1.9
1.8-4.2 1.4-6.5.2-2.4-.8-4.2-2.2-5.4z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M107.9 226.5h-.4c-.8 0-1.5-.2-1.5-.6v-.1h-2.3l.1.5c.2 1.2 1.3 2.5 3.8 2.5 1.5 0 3.5-.5 4.6-1.8.2-.2.3-.5.4-.7l-2.7-.3c-.5.2-1.3.4-2 .5z"/>
+ <path fill="url(#aS)" fill-rule="nonzero" d="M107.9 226.5h-.4c-.8 0-1.5-.2-1.5-.6v-.1h-2.3l.1.5c.2 1.2 1.3 2.5 3.8 2.5 1.5 0 3.5-.5 4.6-1.8.2-.2.3-.5.4-.7l-2.7-.3c-.5.2-1.3.4-2 .5z"/>
+ <path d="M-30-28h352v303H-30z"/>
+ </g>
+</svg>
diff --git a/browser/extensions/onboarding/content/img/figure_default.svg b/browser/extensions/onboarding/content/img/figure_default.svg
new file mode 100644
index 000000000000..c52e4b8500f7
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_default.svg
@@ -0,0 +1 @@
+<svg width="272" height="247" viewBox="0 0 272 247" xmlns="http://www.w3.org/2000/svg"><title>default-browser</title><defs><linearGradient x1="-12.708%" y1="-28.803%" x2="102.994%" y2="115.824%" id="a"><stop stop-color="#FFCCD7" offset="40.06%"/><stop stop-color="#EDBEE2" offset="100%"/></linearGradient><linearGradient x1="-78.121%" y1="-55.724%" x2="136.609%" y2="135.651%" id="b"><stop stop-color="#FFE900" offset="28.07%"/><stop stop-color="#FFCC07" offset="32.21%"/><stop stop-color="#FF8119" offset="41.22%"/><stop stop-color="#FF0B36" offset="54.35%"/><stop stop-color="#FF0039" offset="55.5%"/><stop stop-color="#ED00B5" offset="85.24%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M-36-18h352v303H-36z"/><g fill-rule="nonzero"><g fill="#D7D7DB"><path d="M116.6 201.9H42.1c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h74.6c.6 0 1.1.5 1.1 1.1-.1.6-.6 1.1-1.2 1.1zM104 195.9H71c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h33c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zM109.7 206.7h-3.3c-.3 0-.6-.
2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zm-12.2 0H84.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-23.5 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6H74c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zm-5.5 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-12.3 0H42.8c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-23.4 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5.6 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-12.3 0H1.5c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6z"/></g><path d="M138.8 171.9c-2.8 0-5-2.1-5-4.8V49.7c0-2.9 2.4-5.3 5.3-5.3h126.1c2.9 0 5.3 2.4 5.3 5.3v117.4c0 2.6-2.2 4.8-5 4.8H138.8z" fill="#FFF"/><path d="M265.2 45.4c2.3 0 4.2 1.9 4.2 4.2V167c0 2-1.7 3.7-3.9 3.7H138.8c-2.2 0-3.9-1.6-3.9-3.7V49.7c0-2.3 1.9-4.2 4.2-4.2h126.1v-.1zm0-2.2H139.1c-3.5 0-6.4 2.9-6.4 6.4V167c0 3.2 2.8 5.9 6.1 5.9h126.7c3.4 0 6.1-2.6 6.1-5.9V49.7c0-3.
6-2.9-6.5-6.4-6.5z" fill="#D7D7DB"/><path d="M264.8 66.4V165c0 .9-.1 1.2-.1 1.2s-.3.1-1.2.1H140.8c-.9 0-1.2-.1-1.2-.1s-.1-.3-.1-1.2V66.4h125.3zm1.1-1.1H138.3V165c0 2 .4 2.4 2.4 2.4h122.7c2 0 2.4-.4 2.4-2.4V65.3h.1z" fill="#D7D7DB"/><g fill="#D7D7DB"><circle cx="2.9" cy="3.3" r="2.8" transform="translate(143 52)"/><circle cx="3.1" cy="3.3" r="2.8" transform="translate(152 52)"/><path d="M233.8 58.5h-63.4c-1.7 0-3.1-1.4-3.1-3.1v-.3c0-1.7 1.4-3.1 3.1-3.1h63.4c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.7-1.4 3.1-3.1 3.1z"/><g><circle cx="3.2" cy="3.3" r="2.8" transform="translate(246 52)"/><circle cx="3.4" cy="3.3" r="2.8" transform="translate(255 52)"/></g></g><path d="M21.8 23.4h23.9S38.2 6.7 54.1 4.5c14.2-1.9 19.8 12.6 19.8 12.6s1.7-8.4 10.1-6.8c8.3 1.6 14.5 15 14.5 15h20.8" fill="#F9F9FA"/><path d="M119.7 21.4h-5.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h5.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-15.3 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5.5-.1c-.2 0-.4-.1-.5-.3-.2-.3-.7-1.
4-1.7-2.9-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2 1 1.5 1.6 2.6 1.7 2.9.1.3 0 .6-.2.8-.2.1-.3.1-.3.1zm-52.8-.6h-1.6c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h.8c-.1-.2-.2-.5-.3-.9-.1-.3.1-.6.4-.7.3-.1.6.1.7.4.3 1 .6 1.6.6 1.6.1.2.1.4 0 .5-.2.2-.4.3-.6.3zm-10.5 0H22.2c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm8.9-6c-.3 0-.5-.2-.6-.5 0-.4-.1-.8-.1-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.1 1.1.1.3-.1.6-.5.6.1 0 0 0 0 0zM73.6 13c-.2 0-.4-.1-.5-.3-.1-.3-.3-.6-.5-1-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.2.4.4.7.5 1 .1.3 0 .6-.2.8-.1 0-.2.1-.3.1zm17.9-1.5c-.1 0-.3 0-.4-.1-2.3-2.1-4.6-3.4-6.8-3.8-.7-.1-1.4-.2-2-.2-1 0-2 .2-2.8.5-.3.1-.6 0-.7-.3-.1-.3 0-.6.3-.7 1-.4 2.1-.6 3.3-.6.7 0 1.4.1 2.2.2 2.4.5 4.9 1.8 7.3 4 .2.2.2.6 0 .8-.1.2-.3.2-.4.2zM70.6 8.3c-.2 0-.3-.1-.4-.2-.7-.9-1.5-1.6-2.3-2.3-.2-.2-.3-.6-.1-.8.2-.2.6-.3.8-.1.8.7 1.6 1.6 2.4 2.5.2.2.2.6-.1.8-.1.1-.2.1-.3.1zm-23-3.8c-.2 0-.3-.1-.4-.2-.2-.2-.2-.6.1-.8C49.1 2 51.5 1.1 54.5.6c2.1-.3 4.1-.2 6 .1.3.1.5.4.4.7-.1.3-.3.5-.7.4-1.8-.4-3.7-
.4-5.6-.1-2.8.4-5 1.3-6.6 2.6-.1.2-.2.2-.4.2z" fill="#D7D7DB"/><path d="M120.4 25.6H21.8c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h98.6c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1z" fill="#F9F9FA"/><path d="M15.2 181.9c-2.8 0-5-2.1-5-4.8V59.7c0-2.9 2.4-5.3 5.3-5.3h126.1c2.9 0 5.3 2.4 5.3 5.3v117.4c0 2.6-2.2 4.8-5 4.8H15.2z" fill="#FFF"/><path d="M141.6 55.5c2.3 0 4.2 1.9 4.2 4.2V177.1c0 2-1.7 3.7-3.9 3.7H15.2c-2.2 0-3.9-1.6-3.9-3.7V59.7c0-2.3 1.9-4.2 4.2-4.2h126.1zm0-2.2H15.5c-3.5 0-6.4 2.9-6.4 6.4V177.1c0 3.2 2.8 5.9 6.1 5.9h126.7c3.4 0 6.1-2.6 6.1-5.9V59.7c0-3.5-2.9-6.4-6.4-6.4z" fill="#D7D7DB"/><path d="M141.2 76.4V175c0 .9-.1 1.2-.1 1.2s-.3.1-1.2.1H17.2c-.9 0-1.2-.1-1.2-.1s-.1-.3-.1-1.2V76.4h125.3zm1.1-1.1H14.8V175c0 2 .4 2.4 2.4 2.4h122.7c2 0 2.4-.4 2.4-2.4V75.3z" fill="#D7D7DB"/><g fill="#D7D7DB"><circle cx="3.3" cy="3.3" r="2.8" transform="translate(19 62)"/><circle cx="3.5" cy="3.3" r="2.8" transform="translate(28 62)"/><path d="M110.2 68.6H46.9c-1.7 0-3.1-1.4-3.1-3.1v-.3c0-1.7 1.4
-3.1 3.1-3.1h63.4c1.7 0 3.1 1.4 3.1 3.1v.3c-.1 1.7-1.5 3.1-3.2 3.1z"/><g><circle cx="3.6" cy="3.3" r="2.8" transform="translate(122 62)"/><circle cx="2.8" cy="3.3" r="2.8" transform="translate(132 62)"/></g></g><path d="M210 28.8h13.3s-4.2-9.3 4.7-10.5c7.9-1.1 11 7 11 7s.9-4.7 5.6-3.8c4.6.9 8 8.3 8 8.3h11.6" fill="#F9F9FA"/><path d="M223.7 27.3h-13.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.3v.5l.5-.2c.1.2.1.4 0 .6-.2.2-.3.3-.5.3zm36.5-.2h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-20.8-3.3h-.1c-.3-.1-.5-.4-.4-.7.1-.4 1.1-4.3 5-4.3.4 0 .8 0 1.2.1 1.7.3 3.5 1.4 5.2 3.1.2.2.2.6 0 .8-.2.2-.6.2-.8 0-1.6-1.6-3.1-2.5-4.6-2.8-.4-.1-.7-.1-1-.1-3 0-3.8 2.8-3.9 3.4-.1.3-.4.5-.6.5zm-15.3-5.1c-.1 0-.3 0-.4-.1-.2-.2-.2-.6 0-.8.8-.8 1.8-1.5 3.1-1.8.3-.1.6.1.7.4.1.3-.1.6-.4.7-1.1.3-2 .8-2.6 1.5-.1.1-.3.1-.4.1zm8.3-1.6h-.2c-.3-.1-.7-.2-1-.2-.3-.1-.5-.3-.5-.6.1-.3.3-.5.6-.5l1.2.3c.3.1.5.4.4.7 0 .1-.2.3-.5.3z" fill="#D7D7DB"/><path d="M265.1 31h-54.9c-.6 0-1.1-.5-1.1-1.1 0-.6.
5-1.1 1.1-1.1h54.9c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1zM237.9 58H87.8c-5.8 0-10.6 4.8-10.6 10.6v139.9c0 5.5 4.6 9.9 10.2 9.9h150.9c5.6 0 10.2-4.5 10.2-9.9V68.6c0-5.8-4.7-10.6-10.6-10.6z" fill="#F9F9FA"/><ellipse fill="#EDEDF0" cx="164.5" cy="239.7" rx="82" ry="6.8"/><path d="M148.2 68.3c-.5.4-1.1.6-1.8.6s-1.3-.2-1.8-.6l-6.3-5.1-.2-.2H87.7c-2.8 0-5 2.2-5 5v140c0 2.4 2.1 4.4 4.6 4.4h150.9c2.6 0 4.6-1.9 4.6-4.4V68.1c0-2.8-2.2-5-5-5h-83.3c-.1 0-.1.1-.2.2l-6.1 5zm-41.4 3.1c1.9 0 3.4 1.5 3.4 3.4s-1.5 3.4-3.4 3.4-3.4-1.5-3.4-3.4 1.5-3.4 3.4-3.4zm-10.9 0c1.9 0 3.4 1.5 3.4 3.4s-1.5 3.4-3.4 3.4-3.4-1.5-3.4-3.4 1.5-3.4 3.4-3.4zm133.9 0c1.9 0 3.4 1.5 3.4 3.4s-1.5 3.4-3.4 3.4-3.4-1.5-3.4-3.4 1.6-3.4 3.4-3.4zm-10.9 0c1.9 0 3.4 1.5 3.4 3.4s-1.5 3.4-3.4 3.4-3.4-1.5-3.4-3.4 1.6-3.4 3.4-3.4zm-18.3-.4c2 0 3.7 1.6 3.7 3.7v.3c0 2-1.6 3.7-3.7 3.7h-5.8c.9 2.6.9 5.5-.2 8h44.3v118.7c0 2.4-.5 2.9-2.9 2.9H89.8c-2.4 0-2.9-.5-2.9-2.9V86.7h73.3c-1.1-2.6-1.1-5.5-.2-8h-34.9c-2 0-3.7-1.6-3.7-3.7v-.3c0-2 1.6-3.7
3.7-3.7h75.5z" fill="#FFF"/><path d="M190.6 91.5l-11.1 9c-.6.5-1.3.7-2.1.7s-1.5-.3-2.1-.7l-11.1-9c-1.3-.8-2.3-1.9-3.1-3.1-.4-.6-.7-1.1-.9-1.7H86.9v118.7c0 2.4.5 2.9 2.9 2.9H236c2.4 0 2.9-.5 2.9-2.9V86.7h-44.3c-.3.6-.6 1.2-1 1.8-.8 1.2-1.8 2.2-3 3zm10.1 24c7.4 8.8 8.2 21.5 1.8 31.1-1.9 2.9-4.3 5.3-7.2 7.3l-30.2 24.7c-.9.7-2.1 1.1-3.3 1.1-1.2 0-2.4-.4-3.3-1.2l-30.4-24.6c-3-2-5.6-4.5-7.5-7.5-6.7-10.3-5.3-24 3.4-32.7 4.9-4.9 11.4-7.6 18.3-7.6 7 0 13.5 2.7 18.4 7.6.3.3.6.4.8.4.2 0 .5-.1.9-.4 4.9-4.9 11.4-7.6 18.3-7.6 7.8.2 15 3.5 20 9.4z" fill="url(#a)"/><path d="M162.5 113.8c-.3.3-.7.4-.9.4-.2 0-.5-.1-.8-.4-4.9-4.9-11.4-7.6-18.4-7.6-6.9 0-13.4 2.7-18.3 7.6-8.7 8.6-10.1 22.4-3.4 32.7 1.9 3 4.4 5.5 7.5 7.5l30.4 24.6c.9.7 2.1 1.2 3.3 1.2 1.2 0 2.3-.4 3.3-1.1l30.2-24.7c2.9-2 5.3-4.4 7.2-7.3 6.3-9.6 5.6-22.3-1.8-31.1-5-5.9-12.2-9.3-19.9-9.3-7 0-13.5 2.7-18.4 7.5zM199 117c6.7 8 7.4 19.7 1.6 28.4-1.8 2.8-4.2 5-6.7 6.7l-30.3 24.7c-.6.4-1.2.7-1.9.7s-1.3-.2-1.9-.7l-30.5-24.7c-2.6-1.7-5-4-6.9-6.9-
6.1-9.3-4.8-22 3.1-29.9 4.6-4.6 10.7-6.9 16.8-6.9 6.1 0 12.2 2.3 16.8 7 .7.7 1.5 1 2.4 1 .9 0 1.7-.3 2.4-1 4.6-4.6 10.7-6.9 16.8-6.9 6.8 0 13.5 2.8 18.3 8.5z" fill="#FFF"/><path d="M138 115.4c-7.6 1.7-13.2 8.1-13.8 15.8-.2 2.2 1.5 4.1 3.6 4.3h.3c2.1 0 3.8-1.6 3.9-3.6.4-4.3 3.4-7.8 7.6-8.7 2.2-.5 3.5-2.6 3-4.7-.3-2.2-2.4-3.6-4.6-3.1z" fill="#F9F9FA"/><path d="M184.5 71.4c-2.6 0-5.1.9-7.1 2.6-2-1.7-4.5-2.6-7.1-2.6-2.9 0-5.7 1.1-7.7 3.2-1.2 1.2-2 2.5-2.6 4-.9 2.6-.9 5.5.2 8 .3.6.6 1.2.9 1.7.8 1.2 1.8 2.3 3.1 3.1l11.1 9c.6.5 1.3.7 2.1.7s1.5-.3 2.1-.7l11.1-9c1.2-.8 2.2-1.8 3-3 .4-.6.7-1.2 1-1.8 1.1-2.6 1.1-5.5.2-8-.4-1.2-1.1-2.3-1.9-3.3-2.1-2.5-5.2-3.9-8.4-3.9zm7.3 15.8c-.7 1-1.5 1.8-2.5 2.5l-11.2 9.1c-.2.2-.4.2-.7.2-.2 0-.5-.1-.7-.2l-11.2-9.1c-1-.6-1.9-1.5-2.6-2.5-2.2-3.4-1.8-8.1 1.1-11 1.7-1.7 3.9-2.5 6.2-2.5 2.2 0 4.5.9 6.2 2.6.2.2.6.4.9.4.3 0 .6-.1.9-.4 1.7-1.7 3.9-2.6 6.2-2.6 2.5 0 4.9 1 6.7 3.1 2.5 2.9 2.8 7.2.7 10.4z" fill="#FFF"/><path d="M168.7 76.2c-2.8.6-4.8 3-5.1 5.8-.1.8.5 1
.5 1.3 1.6h.1c.8 0 1.4-.6 1.5-1.3.1-1.6 1.3-2.9 2.8-3.2.8-.2 1.3-1 1.1-1.7-.1-.9-.9-1.4-1.7-1.2zM138.1 63l.2.2 6.3 5.1c.5.4 1.1.6 1.8.6.6 0 1.3-.2 1.8-.6l6.2-5.1c.1 0 .1-.1.2-.2.7-.5 1.3-1.1 1.7-1.8.1-.1.2-.3.2-.4 1.5-2.6 1.2-5.9-.7-8.1-1.4-1.6-3.4-2.6-5.5-2.6-1.4 0-2.8.4-4 1.2-1.2-.8-2.6-1.2-4-1.2-1.9 0-3.7.7-5.1 2.1-2.3 2.3-2.7 5.8-1.2 8.6.1.1.1.3.2.4.6.7 1.2 1.3 1.9 1.8zm.8-9.2c1-1 2.2-1.4 3.5-1.4 1.3 0 2.5.5 3.5 1.5.1.1.3.2.5.2s.4-.1.5-.2c1-1 2.2-1.4 3.5-1.4 1.4 0 2.8.6 3.8 1.8 1.4 1.7 1.5 4.1.3 5.9-.4.6-.9 1-1.4 1.4l-6.3 5.1c-.1.1-.3.1-.4.1-.1 0-.3 0-.4-.1l-6.3-5.1c-.5-.4-1-.8-1.4-1.4-1.3-2.2-1.1-4.8.6-6.4z" fill="#F9F9FA"/><path d="M139.3 58c.1 0 .1 0 0 0 .5 0 .9-.3.9-.8.1-.9.7-1.6 1.6-1.8.4-.1.7-.5.6-1-.1-.4-.5-.7-1-.6-1.6.4-2.7 1.7-2.9 3.3 0 .4.4.8.8.9z" fill="#F9F9FA"/><path d="M245.2 68.1V208c0 3.6-3.1 6.6-6.9 6.6H87.4c-3.8 0-6.9-3-6.9-6.6V68.1c0-4 3.2-7.2 7.2-7.2h48.4c.1.1.1.3.2.4.5.7 1.1 1.3 1.8 1.8H87.7c-2.8 0-5 2.2-5 5V208c0 2.4 2.1 4.4 4.6 4.4h150.9c2.6 0 4.6-1.9 4.6-
4.4V68.1c0-2.8-2.2-5-5-5h-83.3c.7-.5 1.3-1.1 1.7-1.8.1-.1.2-.3.2-.4h81.4c4.1-.1 7.4 3.2 7.4 7.2zM95.9 78.2c1.9 0 3.4-1.5 3.4-3.4s-1.5-3.4-3.4-3.4-3.4 1.5-3.4 3.4 1.5 3.4 3.4 3.4zm10.9 0c1.9 0 3.4-1.5 3.4-3.4s-1.5-3.4-3.4-3.4-3.4 1.5-3.4 3.4 1.5 3.4 3.4 3.4zm14.6-3.6v.3c0 2 1.6 3.7 3.7 3.7H160c.5-1.5 1.4-2.8 2.6-4 2.1-2.1 4.8-3.2 7.7-3.2 2.6 0 5.1.9 7.1 2.6 2-1.7 4.5-2.6 7.1-2.6 3.2 0 6.3 1.4 8.4 3.9.8 1 1.5 2.1 1.9 3.3h5.8c2 0 3.7-1.6 3.7-3.7v-.3c0-2-1.6-3.7-3.7-3.7h-75.5c-2 .1-3.7 1.7-3.7 3.7zm97.5 3.6c1.9 0 3.4-1.5 3.4-3.4s-1.5-3.4-3.4-3.4-3.4 1.5-3.4 3.4 1.6 3.4 3.4 3.4zm10.9 0c1.9 0 3.4-1.5 3.4-3.4s-1.5-3.4-3.4-3.4-3.4 1.5-3.4 3.4 1.6 3.4 3.4 3.4zm-49 30.3c6.7 0 13.4 2.8 18.2 8.5 6.7 8 7.4 19.7 1.6 28.4-1.8 2.8-4.2 5-6.7 6.7l-30.3 24.7c-.6.4-1.2.7-1.9.7s-1.3-.2-1.9-.7l-30.5-24.7c-2.6-1.7-5-4-6.9-6.9-6.1-9.3-4.8-22 3.1-29.9 4.6-4.6 10.7-6.9 16.8-6.9 6.1 0 12.2 2.3 16.8 7 .7.7 1.5 1 2.4 1 .9 0 1.7-.3 2.4-1 4.8-4.6 10.9-6.9 16.9-6.9zm-38 9.9c-.5-2.2-2.6-3.5-4.7-3-7.6 1.7-13.2 8.1-1
3.8 15.8-.2 2.2 1.5 4.1 3.6 4.3h.3c2.1 0 3.8-1.6 3.9-3.6.4-4.3 3.4-7.8 7.6-8.7 2.2-.5 3.6-2.7 3.1-4.8zm48.4-41.6c2.5 2.9 2.7 7.3.6 10.5-.7 1-1.5 1.8-2.5 2.5l-11.2 9.1c-.2.2-.4.2-.7.2-.2 0-.5-.1-.7-.2l-11.2-9.1c-1-.6-1.9-1.5-2.6-2.5-2.2-3.4-1.8-8.1 1.1-11 1.7-1.7 3.9-2.5 6.2-2.5 2.2 0 4.5.9 6.2 2.6.2.2.6.4.9.4.3 0 .6-.1.9-.4 1.7-1.7 3.9-2.6 6.2-2.6 2.5-.1 5 .9 6.8 3zm-20.7.5c-.2-.8-1-1.3-1.7-1.1-2.8.6-4.8 3-5.1 5.8-.1.8.5 1.5 1.3 1.6h.1c.8 0 1.4-.6 1.5-1.3.1-1.6 1.3-2.9 2.8-3.2.7-.2 1.2-1 1.1-1.8zM138.2 60c-1.3-1.9-1-4.6.6-6.2 1-1 2.2-1.4 3.5-1.4 1.3 0 2.5.5 3.5 1.5.1.1.3.2.5.2s.4-.1.5-.2c1-1 2.2-1.4 3.5-1.4 1.4 0 2.8.6 3.8 1.8 1.4 1.7 1.5 4.1.3 5.9-.4.6-.9 1-1.4 1.4l-6.3 5.1c-.1.1-.3.1-.4.1-.1 0-.3 0-.4-.1l-6.3-5.1c-.5-.5-1-1-1.4-1.6zm.4-2.9c0 .5.3.9.8.9h.1c.4 0 .8-.3.8-.8.1-.9.7-1.6 1.6-1.8.4-.1.7-.5.6-1-.1-.4-.5-.7-1-.6-1.6.3-2.8 1.7-2.9 3.3zM158 42.4c-2.1-3.2-1.6-7.5 1.1-10.2 1.6-1.6 3.6-2.4 5.7-2.4s4.2.8 5.7 2.4c.2.2.5.3.8.3.3 0 .6-.1.8-.3 1.6-1.6 3.7-2.4 5.7-2.4 2.3 0 4.6 1 6.2
2.9 2.3 2.7 2.5 6.7.6 9.7-.6 1-1.4 1.7-2.3 2.3L172 53.2c-.2.2-.4.2-.6.2-.2 0-.5-.1-.6-.2l-10.4-8.4c-1-.7-1.8-1.4-2.4-2.4zm.6-4.8c-.1.7.5 1.4 1.2 1.5h.1c.7 0 1.3-.5 1.3-1.2.1-1.5 1.2-2.7 2.6-3 .7-.2 1.2-.9 1-1.6-.2-.7-.9-1.2-1.6-1-2.5.5-4.4 2.6-4.6 5.3z" fill="url(#b)"/><path d="M159 46.5l10.3 8.4c.6.5 1.3.7 2 .7s1.5-.3 2-.7l10.3-8.4c1.1-.8 2.1-1.7 2.8-2.8 2.5-3.8 2.2-8.9-.7-12.4-2-2.3-4.9-3.7-7.9-3.7-2.4 0-4.7.8-6.6 2.3-1.9-1.5-4.2-2.4-6.6-2.4-2.8 0-5.3 1.1-7.3 3-3.5 3.4-4 8.9-1.4 13 1 1.3 1.9 2.2 3.1 3zm0-14.3c1.6-1.6 3.6-2.4 5.7-2.4s4.2.8 5.7 2.4c.2.2.5.3.8.3.3 0 .6-.1.8-.3 1.6-1.6 3.7-2.4 5.7-2.4 2.3 0 4.6 1 6.2 2.9 2.3 2.7 2.5 6.7.6 9.7-.6 1-1.4 1.7-2.3 2.3L172 53.2c-.2.2-.4.2-.6.2-.2 0-.5-.1-.6-.2l-10.4-8.4c-.9-.6-1.7-1.4-2.4-2.4-2.1-3.2-1.7-7.5 1-10.2z" fill="#F9F9FA"/><path d="M159.8 39.1h.1c.7 0 1.3-.5 1.3-1.2.1-1.5 1.2-2.7 2.6-3 .7-.2 1.2-.9 1-1.6-.2-.7-.9-1.2-1.6-1-2.6.6-4.5 2.8-4.7 5.4 0 .6.6 1.3 1.3 1.4z" fill="#F9F9FA"/></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/figure_library.svg b/browser/extensions/onboarding/content/img/figure_library.svg
new file mode 100644
index 000000000000..aad20181b996
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_library.svg
@@ -0,0 +1,689 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="267" height="240">
+ <defs>
+ <linearGradient id="a" x1="-287.251713%" x2="363.382118%" y1="-127.999431%" y2="247.172106%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="b" x1="-8347.28%" x2="11424.26%" y1="-8337.33%" y2="11434.21%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="c" x1="-2354.3122%" x2="2468.01463%" y1="-738.5544%" y2="843.1688%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="d" x1="-11316.73%" x2="8454.81%" y1="-5346.60952%" y2="4068.40952%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="e" x1="-156.148629%" x2="205.305484%" y1="-480.49483%" y2="430.938303%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="f" x1="-11777.11%" x2="7994.43%" y1="-1542.90541%" y2="1128.92432%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="g" x1="-1966.10678%" x2="1385.00169%" y1="-2646.49545%" y2="1847.03636%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="h" x1="-1259.26087%" x2="945.558937%" y1="-1283.95691%" y2="942.373333%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="i" x1="-4828.28387%" x2="3895.46452%" y1="-2550.56897%" y2="2112.12414%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="j" x1="-1420.34388%" x2="1159.68716%" y1="-3565.4194%" y2="2819.67133%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="k" x1="-6578.28%" x2="13193.26%" y1="-6566.33%" y2="13205.21%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="l" x1="-690.589109%" x2="1266.98911%" y1="-1068.60597%" y2="1882.37015%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="m" x1="-3693.78418%" x2="6240.18862%" y1="-1360.99327%" y2="2373.67085%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="n" x1="-51.4002563%" x2="99.3496099%" y1="-59.6430664%" y2="133.087695%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="o" x1="-47.4074974%" x2="121.810771%" y1="-106.87209%" y2="132.306567%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="p" x1="-701.943676%" x2="609.202314%" y1="-537.964802%" y2="487.22249%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="q" x1="-1074.53%" x2="834.91%" y1="-358.218519%" y2="348.981481%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="r" x1="-5230.64688%" x2="3222.21875%" y1="-2856.73793%" y2="1806.91207%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="s" x1="-1536.40601%" x2="955.898444%" y1="-3896.2795%" y2="2345.49035%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="t" x1="-2573.03736%" x2="4141.82528%" y1="-7694%" y2="12077.54%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="u" x1="-105.756%" x2="253.726545%" y1="-959.543678%" y2="1313.04713%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="v" x1="-113.495628%" x2="246.641894%" y1="-1951.93556%" y2="2441.74%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="w" x1="-203.741261%" x2="362.77851%" y1="-8794.04%" y2="10977.5%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="x" x1="-8901.65455%" x2="9072.47273%" y1="-4629.9%" y2="4785.11905%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="y" x1="-135.885507%" x2="273.463147%" y1="-6854.87692%" y2="8354%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="z" x1="-237.240755%" x2="222.496119%" y1="-950.902381%" y2="659.16369%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="A" x1="-323.294457%" x2="276.418625%" y1="-16784.12%" y2="10262.94%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="B" x1="-324.50885%" x2="273.863496%" y1="-16876.15%" y2="10170.29%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="C" x1="-8757.43409%" x2="-13250.9636%" y1="-25788.3267%" y2="-38969.3533%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="D" x1="-4977.81154%" x2="-7512.62308%" y1="-21732.3667%" y2="-32716.5611%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="E" x1="-778.197863%" x2="-1200.66709%" y1="-2873.70382%" y2="-4382.98244%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="F" x1="-3162.7925%" x2="-4810.42083%" y1="-25654.4533%" y2="-38835.4867%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="G" x1="-1053.32338%" x2="1514.40909%" y1="-4984.71765%" y2="6645.6%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="H" x1="-5039.72338%" x2="-7607.45714%" y1="-23040.7706%" y2="-34671.0941%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="I" x1="143.631333%" x2="-4.86%" y1="790.352632%" y2="-381.952632%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="J" x1="-2552.41333%" x2="-3870.516%" y1="-20494.2053%" y2="-30900.2789%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="K" x1="-1250.60304%" x2="-1918.56115%" y1="-38487.33%" y2="-58258.87%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="L" x1="-37598.9%" x2="-57370.44%" y1="-17879.1857%" y2="-27294.2048%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="M" x1="-882.727251%" x2="-1363.78637%" y1="-29434.6846%" y2="-44643.5692%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="N" x1="-268.313828%" x2="273.677355%" y1="-882.118713%" y2="699.481287%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="O" x1="-420.455862%" x2="943.098621%" y1="-4784.28571%" y2="9338.24286%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="P" x1="-587.656122%" x2="1429.84796%" y1="-3859.74375%" y2="8497.475%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="Q" x1="-597.567708%" x2="1461.96771%" y1="-6217.96%" y2="13553.58%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="R" x1="-989.3%" x2="1835.20571%" y1="-6563.19091%" y2="11410.9364%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="S" x1="-1683.03158%" x2="3520.00526%" y1="-4061.93125%" y2="8295.28125%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="T" x1="-289.56383%" x2="551.778298%" y1="-736.619802%" y2="1220.95842%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="U" x1="-8102.24%" x2="11669.3%" y1="-8112.37%" y2="11659.17%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="V" x1="-527.27218%" x2="959.309774%" y1="-7671.89%" y2="12099.65%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="W" x1="-563.298261%" x2="1155.96609%" y1="-4360.425%" y2="7996.7875%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="X" x1="-595.656881%" x2="1218.24587%" y1="-7031.95%" y2="12739.59%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="Y" x1="-4261.16471%" x2="7369.15294%" y1="-5186.16429%" y2="8936.36429%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="Z" x1="-7291.52%" x2="12480.03%" y1="-7323.1%" y2="12448.44%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aa" x1="-46.8866667%" x2="106.777333%" y1="-610.354545%" y2="437.354545%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="ab" x1="-954.992%" x2="1681.21333%" y1="-6801.97273%" y2="11172.1545%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ac" x1="-53.1965517%" x2="108.827586%" y1="-138.8375%" y2="154.825%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="ad" x1="-2268.40345%" x2="4549.36897%" y1="-4153.9%" y2="8203.3125%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ae" x1="-134.196822%" x2="349.214914%" y1="-7485.96%" y2="12285.58%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="af" x1="-203.129153%" x2="467.092542%" y1="-7412.3%" y2="12359.24%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ag" x1="-8254.16%" x2="11517.38%" y1="-4829.67647%" y2="6800.64118%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ah" x1="-261.207831%" x2="281.860241%" y1="-1137.19462%" y2="943.173846%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="ai" x1="-353.298433%" x2="352.892428%" y1="-15403.61%" y2="11643.5%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aj" x1="-355.267885%" x2="350.914099%" y1="-15487.8%" y2="11558.97%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="ak" x1="-2084.69358%" x2="-3141.99572%" y1="-5548.86479%" y2="-8333.58732%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="al" x1="-2136.94011%" x2="-3223.28791%" y1="-39758.41%" y2="-59529.95%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="am" x1="-8671.43111%" x2="-13065.1111%" y1="-39159.26%" y2="-58930.8%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="an" x1="42.05%" x2="39.02%" y1="40.85%" y2="37.83%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ao" x1="-1655.02189%" x2="-2503.58541%" y1="-18008.5045%" y2="-26995.5636%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ap" x1="26.16%" x2="23.82%" y1="17.93%" y2="15.58%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aq" x1="-7321.04%" x2="-10915.8655%" y1="-26976.66%" y2="-40157.6867%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ar" x1="-3806.45143%" x2="-5689.45619%" y1="-33702.4583%" y2="-50178.75%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="as" x1="-719.07449%" x2="1298.42959%" y1="-4375.10588%" y2="7255.21176%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="at" x1="-4193.87653%" x2="-6211.37959%" y1="-24406.3118%" y2="-36036.6294%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="au" x1="-524.679508%" x2="1095.93852%" y1="-4333.45%" y2="8023.7625%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="av" x1="-3315.91393%" x2="-4936.53115%" y1="-25616.6063%" y2="-37973.8188%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aw" x1="-1422.94082%" x2="2612.06735%" y1="-5115.85714%" y2="9006.67143%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ax" x1="-8372.54082%" x2="-12407.5531%" y1="-29439.4643%" y2="-43561.9929%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="ay" x1="-2040.6303%" x2="3950.74545%" y1="-6860.53%" y2="12911.01%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="az" x1="-12359.7364%" x2="-18351.1091%" y1="-40913.58%" y2="-60685.12%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aA" x1="-1005.75152%" x2="1989.93788%" y1="-6296.96364%" y2="11677.1727%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aB" x1="-6165.30303%" x2="-9160.98939%" y1="-37254.2727%" y2="-55228.4%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aC" x1="-2871.84%" x2="5036.776%" y1="-4515.63125%" y2="7841.58125%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aD" x1="-16493.056%" x2="-24401.672%" y1="-25798.7875%" y2="-38156%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aE" x1="-4836.46667%" x2="8344.56%" y1="-7269.91%" y2="12501.63%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aF" x1="-27538.4933%" x2="-40719.52%" y1="-41322.96%" y2="-61094.5%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aG" x1="123.979381%" x2="7.09896907%" y1="645.125%" y2="-299.65%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aH" x1="-4143.41443%" x2="-6181.71959%" y1="-33849.65%" y2="-50325.925%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aI" x1="110.22963%" x2="13.6574074%" y1="263.406667%" y2="-84.2533333%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aJ" x1="-7493.57037%" x2="-11154.9667%" y1="-27110.28%" y2="-40291.3067%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aK" x1="-1314.06588%" x2="-1982.02331%" y1="-40374.36%" y2="-60145.89%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aL" x1="-39504.49%" x2="-59276.05%" y1="-23215.4176%" y2="-34845.7353%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aM" x1="-935.697066%" x2="-1419.10856%" y1="-40260.71%" y2="-60032.24%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aN" x1="-239.365731%" x2="302.59479%" y1="-1057.81832%" y2="1006.59618%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aO" x1="-195.98196%" x2="188.238494%" y1="-262.20413%" y2="218.292299%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aP" x1="-148.239568%" x2="156.504317%" y1="-236.10625%" y2="205.1375%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aQ" x1="-684.479137%" x2="737.933813%" y1="-1012.53646%" y2="1046.99896%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="aR" x1="-802.736152%" x2="689.739334%" y1="-1056.80385%" y2="890.777014%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aS" x1="-1124.88665%" x2="549.535228%" y1="-1423.71471%" y2="673.128094%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aT" x1="-465.885211%" x2="339.528169%" y1="-152.931663%" y2="157.298039%">
+ <stop stop-color="#FFE900" offset="28.07%"/>
+ <stop stop-color="#FFCC07" offset="32.21%"/>
+ <stop stop-color="#FF8119" offset="41.22%"/>
+ <stop stop-color="#FF0B36" offset="54.35%"/>
+ <stop stop-color="#FF0039" offset="55.5%"/>
+ <stop stop-color="#ED00B5" offset="85.24%"/>
+ </linearGradient>
+ <linearGradient id="aU" x1="-632.473239%" x2="759.889437%" y1="-217.098158%" y2="319.212821%">
+ <stop stop-color="#FFCCD7" offset="40.06%"/>
+ <stop stop-color="#EDBEE2" offset="100%"/>
+ </linearGradient>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <path d="M150.1 145.9v-.2.2zM152.6 147.1c0 .9.3 1.9.9 2.8-.6-.9-.9-1.9-.9-2.8zM149.7 154.2c0-.2-.1-.5-.3-.6.2.2.3.4.3.6 0 0-.1.7.8 1.8-.9-1-.8-1.8-.8-1.8zM229.2 188.9c.4-1.5.7-3 .8-4.4 0-.5.1-1 .1-1.5 0 .5-.1 1-.1 1.5-.1 1.4-.4 2.9-.8 4.4zM103.1 216.7h.8l-.3-.3c-.1.2-.3.3-.5.3zM235.1 153.6v.2c.4.1.8.3 1.1.6.8.7 1 1.8.7 2.7.1-.2.1-.4.1-.6.1-1.3-.7-2.5-2-2.9v-.2l-.1-.9c-1.5-.1-3-.2-4.6-.4l-.3 3.3 5.1-1.8zM245.1 143.8c6.7-3.5 11.1-12.3 10.9-20.8.3 8.5-4.2 17.3-10.9 20.8-3.5 1.8-8.8 2.6-14.2 2.7 5.4-.1 10.7-.8 14.2-2.7zM228.5 173.5l-.1 1.1c.6.3 1.3.5 1.9.8v.1c.1 0 .1.1.2.1-.1-1.3-.2-2.8-.4-4.3.1 1 .1 2 .2 2.9-.6-.2-1.2-.4-1.8-.7zM147.3 150.3l1-2.8-.1.1-.9 2.7c-.2.3 0 .6.3.7h.1c-.4-.1-.5-.4-.4-.7zM210.1 73.1c.5.1 1 .2 1.6.4-.5-.1-1-.3-1.6-.4zM155.1 180c0 .1.5 2.8 1.3 6.9h.1c-.8-4.1-1.3-6.9-1.3-7 0-.2.1-.4.2-.5-.2.1-.4.3-.3.6zM160 204.4h.2c-1.2-5.1-2.3-10.7-3.2-15.3h-.1c.8 4.6 1.9 10.2 3.1 15.3z"/>
+ <path d="M239.9 150.3c-.8.1-1.6.2-2.4.2-.1-.1-.3-.1-.4-.1-2.1-.1-4.3-.2-6.4-.4v.1c2.1.2 4.2.4 6.3.5.1 0 .3 0 .4.1.8 0 1.6-.1 2.4-.2 6.9-.9 11-3.2 15.3-8.7 1.4-1.7 3-4.6 4.1-7.8-1.2 3.2-2.7 5.9-4.1 7.7-4.3 5.4-8.4 7.7-15.2 8.6zM104 200.6c0-.1 0-.1 0 0 0-.1 0-.1 0 0zM145.8 157.9l-.2-.3v-.1l.1.1M140.7 165.2h-.1l-.6.9v.1M252 110.6c-2.8-4.7-6.4-9.1-8.6-11.7 2.2 2.6 5.8 7 8.6 11.7zM206.9 117.5c-.2-.3-.5-.5-.7-.7-.6-.5-1.4-.7-2.1-.7 1 0 2.1.5 2.8 1.4.5.8 1.5 1 2.3.5.1-.1.2-.1.3-.2-.1.1-.2.1-.3.2-.8.5-1.8.3-2.3-.5zM218.4 218.6c-.2 3.3-.2 5.7-.2 7.4h.1c-.1-1.7 0-4.1.1-7.4-6.4 1.4-13 2.3-19.7 2.4-7.5.1-14.9-.8-22.2-2.6v.1c7.2 1.8 14.6 2.7 22.1 2.6 6.7-.2 13.3-1 19.8-2.5zM209 117.5h-.1.1zM244.8 117.2c-.5.4-1.2.3-1.6-.2-.2-.3-.4-.5-.7-.7-.7.4-1.4.6-2.2.6-1 0-1.9-.3-2.6-.9-.4.3-.8.6-1.1 1-.1.2-.3.4-.6.4.2.2.5.4.7.6 2.9 2 6.8 1.3 8.8-1.6.3-.5.2-1.2-.3-1.5-.3-.2-.6-.2-1-.1.3.3.6.6.8 1 .4.5.2 1.1-.2 1.4zM241.5 113.3c.3-.3.4-.6.4-1.1v-3.5c0-.7-.4-1.3-1.1-1.5.4.3.7.8.7 1.3v3.5c0 .2-.1.5-.2.7-.5-.
1-1.1-.2-1.6-.2-.3 0-.6 0-.9.1.1.2.1.4.3.5.7 0 1.6 0 2.4.2zM200.6 117.5l.3-.3.6-.6c-.2.2-.4.4-.6.7 0 0-.1.1-.3.2zM208.1 114.6c-.1 0-.1-.1-.2-.2-1.5-1.1-3.3-1.4-5-1 1.8-.4 3.7.1 5.2 1.2zM209.5 116.7c0-.2 0-.5-.1-.7l-.3-.3.3.3c.1.2.2.5.1.7zM159.7 206.8c.7 3.1 1.5 6.2 2.6 9.2.3.9 2.2 6 4.6 10.2h.1c-2.5-4.2-4.3-9.3-4.7-10.3-1-3-1.9-6-2.6-9.1-1.2.1-2.5.1-3.8.1-4-.1-7.9-.5-11.8-1.2v.1c3.9.7 7.8 1.1 11.7 1.1 1.3 0 2.6 0 3.9-.1zM198.4 115.7c1.1-1.5 2.7-2.5 4.4-2.8-.1-.2-.1-.4-.1-.6v-3.5c0-.9.7-1.6 1.6-1.6-.9 0-1.6.7-1.6 1.6v3.5c0 .2 0 .4.1.6-1.8.2-3.4 1.3-4.4 2.8-.5.7-.3 1.5.2 2.1-.6-.6-.7-1.5-.2-2.1zM156.8 110.8c.3-.1.4-.4.3-.7l-1.2-2.9V106.9l-.3-1 .3.9v.1l-.3-1 .4 1.1v.2l1.2 2.9c0 .3-.1.6-.4.7h-.3c.2.1.3.1.3 0zM164.8 90.6l-.1 4.1M164.9 97.3l-.3-2.4c.1.8.2 1.7.3 2.5V97.3zM184.8 79.4l.2-.2 2.6-1.1h-.1l-2.4 1c-.2.1-.3.2-.3.3z"/>
+ <path d="M214.8 223.5v-.9c-1.3.2-2.6.4-3.8.6-4.1.6-8.2 1-12.4 1-6.3 0-12.6-.5-18.8-1.7 0 1.3 0 2.3-.1 3.3 4.7-.1 9.6-.2 14.7-.2 7.1 0 13.9.1 20.4.3v-2.4zM159.1 216.9c-.7-1.9-1.3-4.2-2-6.8h-1.3c-3.9-.1-7.9-.4-11.7-1.1v1.9h1c1 0 1.9 1 1.9 2.2v1.4c0 1.2-.8 2.1-1.7 2.2h.2l.4.3c.2-.2.4-.3.7-.3h.8c1.9.1 3.1.4 3.6.9 1.6 1.3 2.6 4.2 2.6 7.5 0 .5-.1 1.2-.2 1.9 3.1-.2 6.3-.4 9.8-.6-.6-1-1.1-2.1-1.6-3.2-.9-1.9-1.8-4.1-2.5-6.3zM235.4 114.9c-.2.1-.3.3-.3.4.1-.1.2-.2.3-.4.1 0 .1 0 0 0zM150.3 134.7c0-12.6 1.1-21.9 3.3-27.6l-.2-.5c-.4-1.2.3-2.4 1.5-2.8l.3-.1c2-3.6 4.4-6.9 7.3-9.9l.1-3.3c0-1.2 1-2.2 2.2-2.2l3.5.1c3.3-2.6 6.8-5 10.5-7.1l1.4-5.3c.3-1.2 1.5-1.8 2.6-1.6h-.1c-1.2-.3-2.4.4-2.7 1.6l-1.4 5.3c-3.7 2-7.2 4.4-10.5 7.1l-3.5-.1c-1.2 0-2.2 1-2.2 2.2l-.1 3.3c-2.8 3-5.3 6.3-7.3 9.9l-.3.1c-1.2.4-1.8 1.6-1.5 2.8l.2.5c-2.2 5.7-3.3 15-3.3 27.6-.6 3.6-1.3 7.2-2.2 10.6l-4.8 2.9 5-2.8c.9-3.5 1.6-7.1 2.2-10.7zM149.2 158.3c.7.7 1.6 1.5 2.8 2.1-1.2-.6-2.1-1.3-2.8-2.1zM206.5 72.8c.6 0 1.3.1 1.9.1.6 0 1.1.
1 1.7.2-.7-.1-1.3-.2-1.9-.3-.6-.1-1.2-.1-1.9-.1-5.7.2-11.4 1.3-16.7 3.4l.2.1c5.3-2 10.9-3.2 16.7-3.4zM140.8 153.8c-.5-.9-.6-1.9-.4-2.8-.3.9-.2 1.9.4 2.8l2.6 4.3-2.6-4.3zM227.3 212.8c-1.9 1.7-4.1 3-6.5 4v.1c2.3-1 4.5-2.3 6.5-4.1-.1.1-.1.1 0 0zM162.3 170.7l-.1-1.2c-2.4.6-4.8 1.4-7.2 2.3-.4-2.9-.8-5.5-1.1-7.6.3 2.1.7 4.8 1.1 7.7-.1 0-.2.1-.4.2.4 2.2 1.1 5.1 1.5 7.4-.3-2.2-.7-4.4-1-6.4 2.4-1.1 4.7-1.9 7.2-2.4zM174.5 205.9v2.9"/>
+ <path d="M152.3 147.3c-.2-3.1-.3-6.4-.4-9.8.2-1 .4-1.9.5-2.8 0-10.7.9-20.1 2.9-26v-.1c-2 5.9-2.9 15.3-2.9 26.1-.2.9-.3 1.8-.5 2.8v.2c0-.1 0-.2.1-.3 0 3.5.1 6.8.3 9.9 0 .1 0 .1 0 0zM236.4 182.5c-.4 15.2-3.8 25.4-5.2 29-.3 1.4-.7 2.7-1.1 3.8-1.6 4.5-3.5 8.5-5.2 11.1 1.7-2.6 3.7-6.6 5.3-11.2.4-1.1.7-2.4 1.1-3.8 1.4-3.6 4.8-13.7 5.2-29v-2.3s-.1 0-.1-.1v2.5zM149 153.6c.1-.6.3-1.3.6-1.9-.3.6-.6 1.2-.6 1.9h.2c-.1-.1-.2-.1-.2 0zM174.2 215.2v.2h-.1l.1-.2-.1.3c.1 2.1.1 4.1.1 6 0 1.7 0 3.2-.1 4.5h.1c.1-1.3.1-2.9.1-4.6 0-1.9-.1-3.9-.1-6h.1v-.2l-.2-5.8c0-.1 0-.2.1-.3-.1.1-.2.3-.2.4l.2 5.7zM236.5 172.8v-2.2c-.1-.7-.1-1.6-.2-2.4.1 1.5.2 3 .2 4.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M7.7 72.3v98.1c0 1 .1 1.2.1 1.2s.2.1 1.2.1h121.1l-.6-1.9c-.9-3.1.3-6.3 2.9-7.9V72.3H7.7zm45.8 65.5c0 1.8-1.5 3.3-3.3 3.3-1.8 0-3.3-1.5-3.3-3.3V98.4c0-1.8 1.5-3.3 3.3-3.3 1.8 0 3.3 1.5 3.3 3.3v39.4zm9.8 0c0 1.8-1.5 3.3-3.3 3.3-1.8 0-3.3-1.5-3.3-3.3V105c0-1.8 1.5-3.3 3.3-3.3 1.8 0 3.3 1.5 3.3 3.3v32.8zm9.9 0c0 1.8-1.5 3.3-3.3 3.3-1.8 0-3.3-1.5-3.3-3.3v-36.1c0-1.8 1.5-3.3 3.3-3.3 1.8 0 3.3 1.5 3.3 3.3v36.1zm20.8 3.1c-.4.1-.8.2-1.1.2-1.3 0-2.6-.8-3.1-2.2l-13.1-36.1c-.6-1.7.3-3.6 2-4.2 1.7-.6 3.6.3 4.2 2L96 136.7c.6 1.7-.3 3.5-2 4.2zM133.5 171.4c-.1 0-.1 0 0 0l.5 1.7-.5-1.7z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M127.3 173.2l1.8.1c.1-.2.3-.4.5-.5H9c-2 0-2.5-.4-2.5-2.5V71.2h127v90.2c.2-.1.4-.2.7-.2l3.6-1.1v-4.8c-1.3-2.3-1.2-5 0-7.1V55.4c0-2.3-1.9-4.2-4.2-4.2H6.5c-2.3 0-4.2 1.9-4.2 4.2v118.3c0 2 1.8 3.7 3.9 3.7h90c.3-.6.6-1.2 1.1-1.5.9-.7 2.6-.8 3.8-.8.5 0 .9.2 1.2.5l.5-.4h19.1c1.3-1.2 3-2 4.9-2h.5zm9.1-13.5l-.1-.2.1.2zm-.1-.3v.4l-.3-.9.3.5zm-9.6-101.2c1.6 0 2.9 1.3 2.9 2.9 0 1.6-1.3 2.9-2.9 2.9-1.6 0-2.9-1.3-2.9-2.9 0-1.6 1.3-2.9 2.9-2.9zm-9.2 0c1.6 0 2.9 1.3 2.9 2.9 0 1.6-1.3 2.9-2.9 2.9-1.6 0-2.9-1.3-2.9-2.9 0-1.6 1.3-2.9 2.9-2.9zM35 61c0-1.7 1.4-3.1 3.1-3.1H102c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.7-1.4 3.1-3.1 3.1H38.1c-1.7 0-3.1-1.4-3.1-3.1V61zm-12.4-2.8c1.6 0 2.9 1.3 2.9 2.9 0 1.6-1.3 2.9-2.9 2.9-1.6 0-2.9-1.3-2.9-2.9 0-1.6 1.3-2.9 2.9-2.9zm-9.3 0c1.6 0 2.9 1.3 2.9 2.9 0 1.6-1.3 2.9-2.9 2.9-1.6 0-2.9-1.3-2.9-2.9 0-1.6 1.4-2.9 2.9-2.9zM136.4 173.1l-.1-.3-.2-.6-1.1-3.7c-.2-.8.2-1.6 1-1.8-.8.2-1.2 1.1-1 1.8l1.1 3.7.3.9.1.5c-.5.6-.9 1.1-1.4 1.7.5-.6 1-1
.1 1.4-1.7l-.1-.5z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M138.7 159.7c.3-.5.6-1.1.8-1.7l-1.7-2.8v4.7l.9-.2zM6.2 177.5c-2.2 0-3.9-1.6-3.9-3.7V55.4c0-2.3 1.9-4.2 4.2-4.2h127.1c2.3 0 4.2 1.9 4.2 4.2V148c.5-.9 1.3-1.7 2.2-2.3V55.4c0-3.6-2.9-6.5-6.5-6.5H6.5c-3.6 0-6.5 2.9-6.5 6.5v118.3c0 3.3 2.8 5.9 6.2 5.9h89.2c.2-.8.4-1.5.7-2.2H6.2v.1zM139 167.8l1.1-1.6v-.1l-1.1 1.7c-.2.1-.2.4 0 .5-.1-.1-.1-.3 0-.5z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M6.5 71.2v99.2c0 2 .4 2.5 2.5 2.5h120.5c.2-.2.4-.5.7-.7l-.1-.4H9c-1 0-1.2-.1-1.2-.1s-.1-.2-.1-1.2V72.3h124.7V162c.3-.2.7-.4 1.1-.6V71.2H6.5zM132.8 169.2c-.2-.7-.2-1.4 0-2.1-.3.6-.3 1.4 0 2.1l.7 2.3v-.1l-.7-2.2zM13.3 64c1.6 0 2.9-1.3 2.9-2.9 0-1.6-1.3-2.9-2.9-2.9-1.6 0-2.9 1.3-2.9 2.9 0 1.6 1.4 2.9 2.9 2.9zM22.6 64c1.6 0 2.9-1.3 2.9-2.9 0-1.6-1.3-2.9-2.9-2.9-1.6 0-2.9 1.3-2.9 2.9 0 1.6 1.3 2.9 2.9 2.9zM38.1 64.3H102c1.7 0 3.1-1.4 3.1-3.1V61c0-1.7-1.4-3.1-3.1-3.1H38.1c-1.7 0-3.1 1.4-3.1 3.1v.3c0 1.7 1.4 3 3.1 3zM117.5 64c1.6 0 2.9-1.3 2.9-2.9 0-1.6-1.3-2.9-2.9-2.9-1.6 0-2.9 1.3-2.9 2.9 0 1.6 1.3 2.9 2.9 2.9zM126.7 64c1.6 0 2.9-1.3 2.9-2.9 0-1.6-1.3-2.9-2.9-2.9-1.6 0-2.9 1.3-2.9 2.9 0 1.6 1.3 2.9 2.9 2.9z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M60 101.6c-1.8 0-3.3 1.5-3.3 3.3v32.8c0 1.8 1.5 3.3 3.3 3.3 1.8 0 3.3-1.5 3.3-3.3v-32.8c0-1.8-1.4-3.3-3.3-3.3zM69.9 98.4c-1.8 0-3.3 1.5-3.3 3.3v36.1c0 1.8 1.5 3.3 3.3 3.3 1.8 0 3.3-1.5 3.3-3.3v-36.1c0-1.9-1.5-3.3-3.3-3.3zM50.2 95.1c-1.8 0-3.3 1.5-3.3 3.3v39.4c0 1.8 1.5 3.3 3.3 3.3 1.8 0 3.3-1.5 3.3-3.3V98.4c0-1.8-1.5-3.3-3.3-3.3zM82.8 100.5c-.6-1.7-2.5-2.6-4.2-2-1.7.6-2.6 2.5-2 4.2l13.1 36.1c.5 1.3 1.7 2.2 3.1 2.2.4 0 .8-.1 1.1-.2 1.7-.6 2.6-2.5 2-4.2l-13.1-36.1zM122.5 21.4h1.1c.3 0 .6-.2.6-.6 0-.4-.2-.6-.6-.6h-1.1c-.3 0-.6.2-.6.6 0 .4.3.6.6.6zM133.7 21.4h4.5c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-4.5c-.3 0-.6.2-.6.6 0 .3.2.6.6.6zM116.9 21.1c.1.2.3.3.5.3h.6c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-.3c-.2-.4-.6-1.2-1.2-2.1-.2-.3-.5-.3-.8-.2-.3.2-.3.5-.2.8.9 1.3 1.3 2.1 1.4 2.4zM66.7 4.5c.1 0 .2 0 .3-.1 1.6-1.2 3.7-2.1 6.4-2.4 2.1-.3 4-.2 5.9.2.3.1.6-.1.7-.4.1-.3-.1-.6-.4-.7-2-.4-4.1-.5-6.3-.2-2.9.4-5.2 1.3-6.9 2.7-.2.2-.3.5-.1.8.1 0 .3.1.4.1zM41.3
20.7h13.4c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6H41.3c-.3 0-.6.2-.6.6 0 .3.3.6.6.6zM98.6 7.9c1.3-.4 2.7-.5 4.3-.2 2.3.4 4.8 1.8 7.2 4.1.1.1.2.2.4.2.1 0 .3-.1.4-.2.2-.2.2-.6 0-.8-2.6-2.5-5.2-3.9-7.7-4.4-1.8-.3-3.4-.3-4.9.2-.3.1-.4.4-.4.7.1.3.5.5.7.4zM92.1 13.1c.1.2.3.3.5.3.1 0 .2 0 .2-.1.3-.1.4-.5.3-.7-.1-.3-.3-.6-.5-1-.1-.3-.5-.4-.8-.2-.3.1-.4.5-.2.8.2.3.3.6.5.9zM89.1 8.5c.1.1.3.2.4.2.1 0 .2 0 .3-.1.2-.2.3-.5.1-.8-.7-.9-1.5-1.8-2.3-2.5-.2-.2-.6-.2-.8 0-.2.2-.2.6 0 .8.9.7 1.6 1.5 2.3 2.4zM63.4 14.6s.1 0 0 0c.4 0 .6-.3.6-.6 0-.4-.1-.7-.1-1.1 0-.3-.3-.5-.6-.5h-.1c-.2.1-.4.3-.4.6 0 .4.1.8.1 1.1 0 .1 0 .1.1.2 0 .2.2.3.4.3zM65.5 20.4c.1-.2.1-.4 0-.5 0 0-.3-.7-.6-1.7-.1-.3-.4-.5-.7-.4-.3.1-.5.4-.4.7.1.4.3.8.4 1h-.7c-.2.1-.4.3-.4.5 0 .3.2.6.6.6H65.1c.1.1.3 0 .4-.2z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M40.9 25.6h97.9c.6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1H116c-2-3.7-7.1-11.7-13.4-12.9-8.4-1.6-10 6.7-10 6.7S87 2.7 73 4.6c-6.5.9-9 4.2-9.8 7.8h.1c.3 0 .6.2.6.5 0 .4.1.7.1 1.1 0 .3-.2.6-.5.6h-.1c-.2 0-.4-.1-.5-.3-.1 1.9.1 3.8.5 5.3h.7c-.1-.3-.2-.6-.4-1-.1-.3.1-.6.4-.7.3-.1.6.1.7.4.3 1 .6 1.7.6 1.7.1.2.1.4 0 .5-.1.2-.3.3-.5.3h-1.3c.4 1.5.9 2.5.9 2.7H40.7c-.6 0-1.1.5-1.1 1.1.1.5.6 1 1.3 1z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M229.2 52.9c.3-1 1.2-3.2 3.8-3.2.3 0 .7 0 1 .1 1.6.3 3.2 1.3 4.8 3 .2.2.6.2.8 0 .2-.2.2-.6 0-.8-1.8-1.9-3.6-3-5.4-3.4-.4-.1-.8-.1-1.2-.1-3.5 0-4.6 3-4.9 4-.1.3.1.6.4.7h.2c.1 0 .2 0 .3-.1.1 0 .2-.1.2-.2zM213.5 48.4c.1 0 .3-.1.4-.2.6-.7 1.5-1.1 2.6-1.4.3-.1.5-.4.4-.7-.1-.3-.4-.5-.7-.4-1.3.4-2.4.9-3.1 1.7-.2.2-.2.6 0 .8.1.2.3.2.4.2zM246.3 56.9h3.3c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-3.3c-.3 0-.6.2-.6.6 0 .3.3.6.6.6zM220.7 46.6c.4.1.7.2 1 .3h.2c.2 0 .5-.1.5-.4.1-.3-.1-.6-.4-.7-.4-.1-.8-.2-1.1-.3-.3-.1-.6.1-.7.4 0 .4.2.7.5.7zM213.5 56.8c.1-.2.1-.4 0-.5l-.1-.1c-.1-.3-.4-.4-.7-.3-.1 0-.1.1-.2.1h-12.7c-.3 0-.6.2-.6.6 0 .3.2.6.6.6H213c.2-.2.4-.3.5-.4z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M199.6 60.7h54.5c.6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1h-12.9c-1.1-2.1-3.9-6.5-7.4-7.2-2.4-.5-3.8.5-4.6 1.6 0 .1-.1.2-.2.3-.6 1-.8 1.9-.8 1.9s-3.1-8-10.9-7c-5.8.8-6 5-5.4 7.8h.7s.1-.1.2-.1c.3-.1.6 0 .7.3l.1.1c.1.2.1.4 0 .5-.1.2-.3.3-.5.3h-.9c.2.9.5 1.4.5 1.5h-13.2.2c-.6 0-1.1.5-1.1 1.1-.1.6.4 1.1 1 1.1z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M173.7 229.1c-.1.2-.1.4-.2.5 0 0-.1 0-.1.1.1 0 .2-.1.3-.1.3-.3.5-1.6.6-3.6h-.1c-.2 1.5-.3 2.6-.5 3.1zM173.1 232c.5 0 1-.1 1.5-.4-.4.2-.9.4-1.5.4-2.1 0-4.3-2.7-6.1-5.8h-.1c1.8 3.2 4 5.8 6.2 5.8z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M231.1 226.7c-2.6 4.8-5.9 8.5-9.7 8.5-1.4 0-2.9-.5-4-1.4-1.7-1.4-2.5-2.9-2.6-7.8-6.4-.2-13.3-.3-20.4-.3-5 0-9.9.1-14.7.2-.2 5.1-1 6.6-2.7 7.9-1.1.9-2.5 1.4-4 1.4-4 0-6.8-3.6-8.7-6.8-.4-.6-.8-1.3-1.1-2-3.4.2-6.7.4-9.8.6-.3 2-1.1 4.5-2.2 5.4-1.1.9-3.1 1.1-4.5 1.1-.6 0-1-.3-1.4-.6l-.6.6H97.4c-1 0-1.9-.7-2.2-1.7l-.3-1.1v-.2c-5.9.7-9.4 1.5-9.4 2.4 0 2.1 17.6 3.7 39.4 3.7 3.5 0 6.8 0 10-.1 12.2 2.1 34.3 3.4 59.5 3.4 38.5 0 69.7-3.2 69.7-7.1 0-2.6-13.2-4.8-33-6.1z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M219.5 231.3c.5.4 1.2.7 1.9.7.6 0 1.3-.2 1.9-.6-.6.4-1.2.6-1.8.6-.7 0-1.4-.3-2-.7-.6-.6-1.2-1.1-1.3-5.3h-.1c.2 4.3.8 4.8 1.4 5.3zM223.3 228.4c.5-.5 1-1.2 1.5-2-.5.8-1 1.4-1.5 2z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M102.1 188.2l-.3-.2c-.1.2-.3.3-.6.3h-.7c-1.6-.1-2.6-.3-3.1-.7l-.6-.6H83c-.6 0-1.1.5-1.1 1.1 0 .6.5 1.1 1.1 1.1h19.4c.1-.4.2-.7.5-.9h-.8v-.1zM156.8 189.1h.1c-.2-.8-.3-1.5-.4-2.2h-.1c.1.7.3 1.4.4 2.2zM27.3 194.1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6H24c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h3.3zM19.5 193h-1.1c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h1.1c.3 0 .6-.2.6-.6 0-.3-.3-.6-.6-.6zM68.5 194.1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-3.3c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h3.3zM49.6 194.1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6H36.2c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h13.4zM102 194.1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-1.1c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h1.1zM60.7 194.1c.3 0 .6-.2.6-.6 0-.3-.2-.6-.6-.6h-1.1c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h1.1zM91.4 193.6c0-.3-.2-.6-.6-.6H77.4c-.3 0-.6.2-.6.6 0 .3.2.6.6.6h13.4c.3-.1.6-.3.6-.6z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M65.7 230.4c-.3.9-.6 1.7-1.1 2.1-.8.8-2.3.9-3.4.9-.4 0-.8-.3-1-.6l-.5.5H24.5h-.1c2.2 1.6 12.1 2.7 24 2.7 13.5 0 24.4-1.5 24.4-3.4 0-.7-2.7-1.6-7.1-2.2z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M28.3 224.9h32.9c.1 0 .1 0 .2.1-.1-.4-.1-.7-.3-1H27.2v4.6h33.7c.2-.3.3-.7.4-1.1h-33c-.2 0-.4-.2-.4-.4s.2-.4.4-.4h32.9c.1 0 .2 0 .2.1v-1.1c-.1.1-.2.1-.3.1H28.3c-.2 0-.4-.2-.4-.4s.2-.5.4-.5z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M59.2 231.8l.8-.9.3.1c.3.1.5.3.6.5.1.1.2.3.3.3 1.2 0 2.1-.2 2.5-.6.6-.5 1.3-3.3 1.3-5.1 0-2.6-.7-4.6-1.4-5.2-.1-.1-.8-.3-1.9-.4-.1.4-.2.7-.7.8h-.3l-.9-.9H24.3c-.1 0-.3.1-.3.3v1.2c0 .2.1.3.3.3H62l.2.4c1.3 2.4.8 5.9-.4 7.3l-.2.2H24.3c-.1 0-.2 0-.2.1s-.1.2 0 .3l.2 1c0 .1.1.2.2.2h34.7v.1z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M59.7 233.4l.5-.5c.2.3.6.6 1 .6 1.1 0 2.6-.2 3.4-.9.4-.4.8-1.2 1.1-2.1.5-1.5.7-3.3.7-4.3 0-2.8-.8-5.4-1.9-6.5-.4-.4-1.3-.7-2.7-.8h-.6c-.3 0-.4.1-.5.3l-.3-.3h-36c-.9 0-1.7.9-1.7 2v1.2c0 1.1.7 2 1.7 2h.9v4.6h-.9c-.5 0-1 .3-1.3.8-.3.5-.4 1.1-.3 1.7l.2 1c.2.8.8 1.4 1.5 1.5h35.2v-.3zm-35.5-1.8l-.2-1v-.3c0-.1.1-.1.2-.1h37.2l.2-.2c1.3-1.4 1.7-4.9.4-7.3l-.2-.4H24.3c-.1 0-.3-.1-.3-.3v-1.2c0-.2.1-.3.3-.3h35.5l.9.9h.3c.4-.1.6-.5.7-.8 1.2.1 1.8.3 1.9.4.7.7 1.4 2.7 1.4 5.2 0 1.8-.7 4.6-1.3 5.1-.4.3-1.3.6-2.5.6-.1-.1-.2-.3-.3-.3-.2-.2-.3-.5-.6-.5l-.3-.1-.8.9H24.5l-.3-.3zm4.1-5.9h32.9c.1 0 .2-.1.3-.1v1.1c-.1-.1-.1-.1-.2-.1h-33c-.2 0-.4.2-.4.4s.2.4.4.4h33c-.1.4-.2.8-.4 1.1H27.2v-4.6h33.9c.1.3.2.7.3 1-.1 0-.1-.1-.2-.1H28.3c-.2 0-.4.2-.4.4s.2.5.4.5z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M174.2 215.4v-.2M236.7 157.9c.2-.2.3-.4.3-.6.1-.2.1-.5.1-.7 0 .2-.1.4-.1.6-.1.2-.2.4-.3.7zM161.3 204.2v.1h.1v-.1h-.1zM173.7 229.1c-.1.1-.1.2-.2.3-.4.3-1 .1-1.7-.5-.1 0-.1-.1-.2-.2-.3-.2-.5-.5-.8-.9.9 1.1 1.7 1.8 2.3 1.8h.2s.1 0 .1-.1c.1 0 .2-.1.3-.4z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M233.4 212.2c-.3 1.4-.7 2.7-1.1 3.8-.5 1.4-4.6 12.7-9 15.4-.6.4-1.3.6-1.9.6-.7 0-1.3-.2-1.9-.7-.7-.5-1.3-1-1.3-5.3 0-1.7 0-4.1.2-7.4-6.5 1.5-13.1 2.3-19.7 2.4-7.4.1-14.9-.7-22.1-2.6.2 11.4-.6 12-1.5 12.8-.1.1-.3.2-.5.3-.5.3-1 .4-1.5.4-2.2 0-4.4-2.6-6.2-5.8-2.5-4.2-4.3-9.3-4.6-10.2-1-3-1.9-6.1-2.6-9.2-1.3.1-2.6.1-3.9.1-3.9-.1-7.9-.5-11.7-1.1v3.2c3.9.7 7.8 1 11.7 1.1h1.3c.7 2.7 1.3 5 2 6.8.8 2.2 1.6 4.3 2.6 6.3.5 1.1 1 2.1 1.6 3.2.4.7.7 1.3 1.1 2 2 3.2 4.7 6.8 8.7 6.8 1.4 0 2.9-.5 4-1.4 1.6-1.3 2.4-2.9 2.7-7.9 0-1 .1-2.1.1-3.3 6.2 1.2 12.5 1.8 18.8 1.7 4.1 0 8.3-.4 12.4-1 1.2-.2 2.5-.4 3.8-.6v3.4c.1 4.9.9 6.4 2.6 7.8 1.1.9 2.5 1.4 4 1.4 3.8 0 7.1-3.7 9.7-8.5.2-.4.5-.8.7-1.3 1.4-2.8 2.6-5.6 3.6-8.5.4-1.1.8-2.4 1.2-3.9 1.5-4 4.8-14.1 5.4-29-1-1.2-2.1-2.3-3.3-3.3v1.8c-.5 15.4-3.9 25.8-5.4 29.7z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M137.8 148.1c-1.2 2.1-1.3 4.8 0 7.1v.1l1.7 2.8c-.3.6-.6 1.1-.8 1.7l-.8.3-3.6 1.1c-.2.1-.5.2-.7.2-.4.2-.8.4-1.1.6-2.5 1.7-3.8 4.9-2.9 7.9l.6 1.9.1.4c-.2.3-.4.5-.7.7-.2.2-.3.4-.5.5l-1.8-.1h-.6c-1.9 0-3.6.8-4.9 2h10.3l1.8-2.1-.5-1.7-.7-2.2c-.2-.7-.2-1.5 0-2.2.3-1.1 1.2-2.1 2.4-2.5l5.8-1.8c.8-1.4 1.6-3 2.3-4.7l-2.6-4.3c-.5-.9-.7-1.9-.4-2.8.2-.9.8-1.8 1.7-2.3l1.1-.7 4.8-2.9c.9-3.3 1.7-6.9 2.2-10.6 0-12.6 1.1-21.9 3.3-27.6l-.2-.5c-.4-1.2.3-2.4 1.5-2.8l.3-.1c2-3.6 4.4-6.9 7.3-9.9l.1-3.3c0-1.2 1-2.2 2.2-2.2l3.5.1c3.3-2.6 6.8-5 10.5-7.1l1.4-5.3c.3-1.2 1.6-1.9 2.7-1.6h.2l6.5 1.8c5.3-2.1 11-3.2 16.7-3.4.6 0 1.3 0 1.9.1.6 0 1.3.1 1.9.3h.1c.5.1 1 .2 1.6.4 3.9 1.1 8.5 3.5 13.9 7.2 6.2 4.5 12.1 9.4 17.5 14.7.7 0 1.3.3 1.8.8 3.5 3.3 6.7 7 9.7 10.8 3 3.2 6.8 8.1 8.1 13.3 2 7.8-2.2 17.9-5.9 22.5-4.7 5.9-9.2 8.5-16.7 9.5-.7.1-1.5.2-2.4.2 1.9 1.8 2.1 4.8.5 6.9 1 1.5 1.1 3.3.2 4.8-.1.1-.1.3-.2.5.2 4.9.4 10.9.4 14.4 1.1.9 2.2 1.9 3.2 3 .2-6.2 0-12.5-.4-18.7
l-.3.1c-.3 0-.5-.2-.5-.5s.2-.6.5-.6c.2 0 .4-.1.5-.2 0-.6-.1-1.2-.1-1.8 1-1.6 1.5-3.6 1.3-5.5l1-.2c.2-.3.5-.3.8-.2.9-.2 1.7-.4 2.5-.7 0-.3.2-.6.5-.6.2 0 .4.1.5.2 4.5-1.7 8.1-4.5 11.6-9 3.8-4.7 8.8-15.6 6.6-25 0-.1 0-.3-.1-.4-.1-.1-.1-.5-.2-.7-.6-1.8-1.3-3.5-2.2-5.2-.4-.7-.8-1.5-1.3-2.2-1.2-1.8-2.5-3.6-3.9-5.2-.3-.4-.6-.7-1-1.1l-.1-.2c-3-4-6.3-7.7-9.9-11.1-.7-.7-1.6-1.2-2.5-1.4-8-7.7-24.5-22.1-36.2-22.9-.7 0-1.4-.1-2.1-.1-5.8.1-11.5 1.2-16.9 3.2l-5.7-1.6c-3-.8-6 .9-6.8 3.9l-1.1 3.9c-3 1.8-6 3.7-8.7 5.9H165c-3 0-5.5 2.4-5.6 5.4v2c-2.4 2.6-4.5 5.5-6.3 8.5-2.1 1.2-3.3 3.6-2.8 5.9-2.1 6.1-3.2 15.3-3.2 27.5-.5 3-1.1 5.9-1.8 8.7l-4.8 2.9c-.1 0-.1.1-.2.1-1.2 1.2-2 2-2.5 3z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M136.3 159.7v-.3l-.2-.5.2.9M155.9 106.8l-.3-.9.3 1"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M230.3 174.3c0-1-.1-2-.2-2.9-.1-.7-.2-1.4-.2-2.1-.3-.1-.6-.1-1-.2l-.4 4.5c.6.2 1.2.4 1.8.7zM242.5 116.3c-.7-.6-1.6-.9-2.6-1-.8 0-1.6.2-2.3.7.7.6 1.7.9 2.6.9.9 0 1.7-.2 2.3-.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M174.5 205.9c9.6 4.4 20.4 5.7 30.8 3.8 14.7-2.9 21.6-12.6 23.9-20.8.4-1.5.7-3 .8-4.4 0-.5.1-1 .1-1.5.2-2.5.2-5 .2-7.5v-.1c-.6-.3-1.3-.6-1.9-.8l-1.1 11.7c-.1.9-.8 1.5-1.7 1.5l-22.1 3.1c-.9.9-2.9 2.3-6.5 2.5h-.8c-3.3 0-5.3-1.4-6.2-2.3l-24.9-3.6c-.9 0-1.6-.7-1.6-1.5l-1.2-15.4c-2.4.6-4.8 1.4-7.1 2.3.3 2 .6 4.2 1 6.4.1.1.2.2.2.4l.2.9c.6 3.2 2.6 14.1 4.8 23.4v.1h.1v.1h.1c.8 3.7 1.7 7.3 2.9 10.9 2 5.6 4.5 10.3 6.4 12.7.3.3.6.6.8.9.1 0 .1.1.2.2.7.6 1.3.8 1.7.5.1 0 .1-.1.2-.3.2-.5.3-1.6.4-3.2.1-1.3.1-2.8.1-4.5 0-1.9 0-3.9-.1-6v-.2h.1l-.2-5.8c0-.2.1-.3.2-.4.1-.1.2-.2.3-.2l-.1-2.9z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M152 137.6c.1 3.3.2 6.6.4 9.8l.3-.3v.1c-.1.9.3 1.9.8 2.9.8 1.4 2.1 2.7 3.2 3.7 1.8-1 3.3-1.2 4-1.2l-.3-4.3c0-.5.1-1 .5-1.3.3-.3.8-.5 1.3-.5h.3l1.4-6.1c.1-.4.4-.8.8-.8.4-.1 10.5-2.3 19.1 1.5 7.1 3.1 11.3 7.9 13.1 10.5 1.5-2.6 5.2-7.4 12.7-11 6.3-3.1 15.5-3.4 16.7-2.9.3.1.6.4.7.7.2.6 1.3 4.5 1.9 7.1h.2c.5 0 1 .1 1.3.5.2.2.4.5.4.8 5.4-.1 10.7-.9 14.2-2.7 6.7-3.5 11.1-12.3 10.9-20.7 0-1.2-.2-2.4-.4-3.6-.6-2.9-2-5.9-3.7-8.9-2.8-4.7-6.4-9.1-8.6-11.7-.3-.3-.5-.6-.8-.9 0 0-.1 0-.1.1C231 87.2 216.6 76.1 208 75.5c-.6 0-1.1-.1-1.7-.1-5.7.2-11.3 1.4-16.6 3.5l-.5-.1-3.8 1.7h-.1c-.3.1-.6 0-.7-.3-.1-.2 0-.4.1-.6 0-.1.1-.2.2-.3l2.4-1-5.1-1.4-1.7 6.2c-4.1 2.2-8 4.8-11.6 7.8l-4.3-.1-.1 4.1v.1l-.1.1.3 2.4v.3c0 .2-.2.4-.4.5h-.2c-.2 0-.4-.2-.5-.4l-.3-1.8c-2.7 2.9-5 6.1-6.8 9.6l-1.1.3.3 1V107.3l1.2 2.9c.1.3 0 .6-.3.7h-.3c-.2 0-.4-.1-.5-.4l-.7-1.7c-2 5.9-2.9 15.3-2.9 26 .1.9 0 1.8-.2 2.8zm82.7-21.8c.1-.2.2-.3.4-.4.1-.2.2-.3.3-.4.3-.2.5-.5.8-.7.8-.6 1.8-.9 2.
7-1.1-.1-.2-.2-.3-.3-.5h-.3c-.1-.2-.1-.4-.1-.6v-3.5c0-.9.7-1.6 1.6-1.6.3 0 .6.1.9.3.6.2 1.1.8 1.1 1.5v3.5c0 .4-.2.8-.4 1.1 1 .3 2 .8 2.8 1.5.3-.1.7-.1 1 .1.5.3.7 1 .3 1.5-2 2.9-5.9 3.6-8.8 1.6-.3-.2-.5-.4-.7-.6-.3.1-.7.1-1-.1-.5-.4-.6-1.1-.3-1.6zm-36.4-.2c1.1-1.5 2.7-2.5 4.5-2.8-.1-.2-.1-.4-.1-.6v-3.5c0-.9.7-1.6 1.6-1.6.9 0 1.6.7 1.6 1.6v3.5c0 .2-.1.5-.2.7 1.6.4 3 1.4 4 2.7.4.7.3 1.6-.2 2.1-.1.1-.2.2-.3.2-.8.5-1.8.3-2.3-.5-.7-.9-1.7-1.4-2.8-1.5H203.5c-.2 0-.4.1-.5.1h-.1c-.6.2-1.2.6-1.6 1.2-.5.8-1.5 1-2.3.5-.1-.1-.2-.1-.3-.2-.7-.3-.8-1.2-.4-1.9zM236.2 154.4c-.3-.3-.7-.5-1.1-.6v-.2l-5 1.9v.1h.4c.1 0 3-.3 6.2 2.3.1-.2.2-.5.3-.7.3-1 0-2-.8-2.8z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M161.7 166.1c-3.6.4-6.2-.6-7.8-1.9.3 2.1.7 4.7 1.1 7.6 2.3-.9 4.7-1.7 7.2-2.3l-.1-.8c-.2-.9-.4-1.7-.4-2.6z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M136.4 159.7l-.1-.3"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M156.4 186.9H145c-.1.3-.2.5-.4.7h.8l.3.2c.1-.2.3-.3.6-.3h.7c1.6.1 2.6.3 3.1.7.3.2.5.5.8.8h6c-.2-.7-.4-1.4-.5-2.1zM150.2 182.9c0-.3-.2-.6-.6-.6h-7.5v1.1h7.5c.3 0 .6-.2.6-.5z"/>
+ <path fill="url(#a)" fill-rule="nonzero" d="M252 110.6c1.7 3 3.1 6 3.7 8.9.2 1.2.4 2.4.4 3.6.2 8.5-4.2 17.3-10.9 20.8-3.5 1.9-8.8 2.6-14.2 2.7v.5l-.3 2.9c2.1.2 4.2.4 6.4.4.1 0 .3 0 .4.1.8 0 1.6-.1 2.4-.2 6.9-.9 11-3.2 15.3-8.7 1.4-1.7 2.9-4.5 4.1-7.7 1.5-4.1 2.4-8.8 1.3-12.8-1.2-4.7-4.7-9.3-7.7-12.5-2.9-3.8-6-7.3-9.5-10.6-.1-.1-.3-.2-.5-.2-.1 0-.3.1-.4.1.2.3.5.6.8.9 2.3 2.7 5.9 7.1 8.7 11.8z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M242.6 98c.2.3.5.6.8.9-.3-.3-.6-.6-.8-.9z"/>
+ <path fill="url(#b)" fill-rule="nonzero" d="M242.6 98c.2.3.5.6.8.9-.3-.3-.6-.6-.8-.9z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M252 110.6c1.7 3 3.1 6 3.7 8.9.2 1.2.4 2.4.4 3.6 0-1.2-.2-2.4-.4-3.6-.6-2.9-2-6-3.7-8.9z"/>
+ <path fill="url(#c)" fill-rule="nonzero" d="M252 110.6c1.7 3 3.1 6 3.7 8.9.2 1.2.4 2.4.4 3.6 0-1.2-.2-2.4-.4-3.6-.6-2.9-2-6-3.7-8.9z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M229.9 169.3c.1.7.1 1.4.2 2.1 0-.8-.1-1.5-.2-2.1z"/>
+ <path fill="url(#d)" fill-rule="nonzero" d="M229.9 169.3c.1.7.1 1.4.2 2.1 0-.8-.1-1.5-.2-2.1z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M220.4 226.2c0 1.8.2 3.1.5 3.3.1.1.3.2.5.2.5 0 1.2-.5 1.9-1.3.5-.5 1-1.2 1.5-2-1.4-.1-2.9-.2-4.4-.2z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M205.3 209.7c-10.4 1.9-21.2.6-30.8-3.8 9.6 4.4 20.3 5.8 30.8 3.8 14.7-2.8 21.6-12.5 23.9-20.8-2.3 8.3-9.2 17.9-23.9 20.8z"/>
+ <path fill="url(#e)" fill-rule="nonzero" d="M205.3 209.7c-10.4 1.9-21.2.6-30.8-3.8 9.6 4.4 20.3 5.8 30.8 3.8 14.7-2.8 21.6-12.5 23.9-20.8-2.3 8.3-9.2 17.9-23.9 20.8z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M230.1 183c.2-2.5.3-5 .2-7.4 0 2.4 0 4.9-.2 7.4z"/>
+ <path fill="url(#f)" fill-rule="nonzero" d="M230.1 183c.2-2.5.3-5 .2-7.4 0 2.4 0 4.9-.2 7.4z"/>
+ <path fill="url(#g)" fill-rule="nonzero" d="M236.4 180.1v-1c-1.9-1.3-3.9-2.4-5.9-3.4 0 .7.1 1.3.1 1.8 2 .8 3.9 1.4 5.8 2.6z"/>
+ <path fill="url(#h)" fill-rule="nonzero" d="M236.5 172.8c-.1-1.6-.1-3.1-.2-4.6-1.4 1-3.6 1.6-6.4 1.1.1.7.2 1.4.2 2.1.2 1.5.3 3 .4 4.3-.1 0-.1-.1-.2-.1 0 2.5 0 5-.2 7.4 0 .5-.1 1-.1 1.5-.1 1.4-.4 2.9-.8 4.4-2.3 8.3-9.2 18-23.9 20.8-10.4 1.9-21.2.6-30.8-3.8v2.9h.1c.3 0 .6.2.6.5l.3 6.4c2.9.9 10.8 3 23.3 3 7.3-.2 14.5-1.1 21.5-2.9 2.3-.9 4.4-2.2 6.3-3.8.2-.2.6-.2.8 0 .2.2.2.6 0 .8h-.1v.1c-1.9 1.7-4.1 3-6.4 4-.2 2.9-.3 5.7-.3 7.9v1.4c0 1.8.2 3.1.5 3.3.1.1.3.2.5.2.5 0 1.2-.5 1.9-1.3.5-.5 1-1.2 1.5-2 1.7-2.6 3.6-6.5 5.2-11.1.4-1.1.8-2.4 1.1-3.8 1.4-3.6 4.8-13.8 5.2-29V180s.1 0 .1.1v-1.2c-.2-1.5-.1-4.1-.1-6.1z"/>
+ <path fill="url(#i)" fill-rule="nonzero" d="M202.7 108.7v3.5c0 .2 0 .4.1.6.4-.1.8-.1 1.2-.1.5 0 1.1.1 1.6.2.1-.2.2-.5.2-.7v-3.5c0-.9-.7-1.6-1.6-1.6-.8 0-1.5.7-1.5 1.6z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M202.8 112.8c-1.8.3-3.4 1.3-4.5 2.8-.4.7-.3 1.5.2 2.1.1.1.2.2.3.2.8.5 1.8.3 2.3-.5.4-.6 1-1 1.6-1.2h.1c.2-.1.4-.1.5-.1H203.9c.7 0 1.5.2 2.1.7.3.2.5.4.7.7.5.8 1.5 1 2.3.5.1-.1.2-.1.3-.2.6-.5.7-1.4.2-2.1-1-1.4-2.4-2.3-4-2.7-.5-.1-1.1-.2-1.6-.2-.3-.1-.7 0-1.1 0zm5.1 1.6c.1 0 .1.1.2.2s.3.2.4.4c.2.1.3.3.5.5.1.1.2.2.2.3l.3.3c.1.2.1.5.1.7v.1c0 .1-.1.2-.1.2 0 .1 0 .1-.1.2 0 .1-.1.1-.1.1l-.1.1h-.1-.1c-.1 0-.2.1-.2.1h-.1c-.4 0-.7-.1-1-.4-.8-1-2-1.7-3.3-1.7H203.8c-.2 0-.4.1-.6.1-.1 0-.3.1-.4.2-.1.1-.3.1-.4.2-.2.1-.4.2-.5.4l-.1.1-.6.6-.3.3c-.4.3-.9.3-1.2 0-.5-.3-.7-1-.3-1.5.2-.3.4-.5.6-.7l.1-.1c.2-.2.5-.5.8-.7h.1c.1-.1.3-.2.5-.3h.1c.2-.1.3-.2.5-.2h.1c.2-.1.3-.1.5-.2s.4-.1.6-.2c1.3-.4 3.1-.1 4.6.9z"/>
+ <path fill="url(#j)" fill-rule="nonzero" d="M202.9 113.4c-.2 0-.4.1-.6.2-.2.1-.4.1-.5.2h-.1c-.2.1-.3.2-.5.2h-.1c-.2.1-.3.2-.5.3h-.1c-.3.2-.5.4-.8.7l-.1.1c-.2.2-.4.5-.6.7-.3.5-.2 1.2.3 1.5.4.3.9.2 1.2 0l.3-.3c.2-.2.4-.5.6-.7l.1-.1c.2-.1.4-.3.5-.4.1-.1.2-.1.4-.2.1-.1.3-.1.4-.2.2-.1.4-.1.6-.1H204c1.3 0 2.5.6 3.3 1.7.2.3.6.4 1 .4h.1c.1 0 .2 0 .2-.1.1 0 .1 0 .2-.1h.1l.1-.1.1-.1s.1-.1.1-.2.1-.1.1-.2v-.1c0-.2 0-.5-.1-.7l-.3-.3c-.1-.1-.1-.2-.2-.3-.1-.2-.3-.3-.5-.5-.1-.1-.3-.2-.4-.4-1.2-.8-3.1-1.3-4.9-.9z"/>
+ <path fill="url(#k)" fill-rule="nonzero" d="M140 165.4v.7l.6-.9"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M137.8 166.1l-1.9.6c-.8.2-1.2 1.1-1 1.8l1.1 3.7.2.6.1.2v.1l.1.4c-.5.6-1 1.1-1.4 1.7h2.4c.2-.4.3-.9.3-1.4v-7.7h.1z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M140 168.2l-.1.2c-.2.3-.5.3-.8.2l-.2-.2c-.1-.2-.1-.4 0-.6l1.1-1.6v-.7l-2.2.7v7.7c0 .5-.1 1-.3 1.4h2.3c.1-.5.2-.9.2-1.4v-5.7z"/>
+ <path fill="url(#l)" fill-rule="nonzero" d="M154.4 170.6c-3.5 1.5-6.8 3.4-9.9 5.6.1.1.1.2.2.4l.2.7c3.1-2 6.3-3.8 9.7-5.2-.1-.6-.1-1.1-.2-1.5z"/>
+ <path fill="url(#m)" fill-rule="nonzero" d="M156.8 189.1c-.2-.8-.3-1.5-.4-2.2-.8-4.1-1.3-6.9-1.3-6.9 0-.3.1-.5.4-.6.1-.1.2-.1.2-.1.2 0 .3 0 .4.1-.4-2.2-1.1-5.2-1.5-7.4.1-.1.2-.1.4-.2-.4-2.9-.8-5.5-1.1-7.7-1.5-1.3-2.1-2.8-2-3.7v-.1c-1.2-.6-2.1-1.4-2.8-2.1-1.4-1.5-1.7-3-1.7-3.2v-.4c.1-.4.5-.8.9-.8h.3l.2-.2c.1-.6.3-1.3.6-1.9.8-1.9 2.1-3.5 2.7-4.3-.1-3.2-.2-6.5-.3-9.9 0 .1 0 .2-.1.3l-.6 3c-.1.2-.1.5-.2.7-.3 1.1-.5 2.3-.9 3.5-.1.2-.1.4-.2.6v.2l-.1.2-.1.5h-.1l-1.5 4.1c-.1.2-.3.4-.6.3h-.1-.1c-.3-.1-.4-.4-.3-.7l1-2.7-.3.2-4.7 2.9c-.7.4-.9 1.3-.5 2l2.9 4.7.1.1.1.1.2.3v.1c-1 2.3-2.1 4.5-3.3 6.7h-.1l-2.4 3.5-.1.2c-.2.3-.5.3-.8.2l-.2-.2c-.1-.2-.1-.4 0-.6l1.1-1.6v-.7l-2.2.7-1.9.6c-.8.2-1.2 1.1-1 1.8l1.1 3.7.2.6.1.2v.1l.1.4c-.5.6-1 1.1-1.4 1.7H142.6c.7 0 1.3.4 1.7.9.1.1.1.2.2.4l.2.7.1.2c.1.5 0 1.1-.3 1.5-.4.4-.9.7-1.5.7h-1v4h1c1 0 1.9.8 1.9 1.7v1.1c0 .1 0 .3-.1.4-.1.3-.2.5-.4.7h.8l.3.2c.1-.2.3-.3.6-.3h.7c1.6.1 2.6.3 3.1.7.3.2.5.5.8.8.9 1.2 1.4 3 1.4 5 0 1.5-.7 4.7-2 5.7-.9.7-2.6.8-3.8.8h-.2c.
2.3.4.6.5 1.1l.2 1.1c.1.4.1.7 0 1.1 3 .4 6 .7 9 .7 1.4 0 2.8-.1 4.1-.2-1.1-4.9-2.2-10.5-3.1-15.1z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M149.2 153.6s0-.1 0 0c.2 0 .2 0 .3.1.2.1.3.3.3.6 0 0-.1.7.8 1.8.5.6 1.3 1.2 2.5 1.9.2-.9.7-1.7 1.5-2.5s1.5-1.3 2.3-1.7c-1.2-1.1-2.4-2.4-3.2-3.7-.6-.9-.9-1.9-.9-2.8v-.1l-.3.3c-.6.7-1.9 2.4-2.7 4.3-.3.6-.5 1.3-.6 1.9-.2-.2-.1-.2 0-.1z"/>
+ <path fill="url(#n)" fill-rule="nonzero" d="M136.3 173.1l-.3-.9-1.1-3.7c-.2-.8.2-1.6 1-1.8l1.9-.6 2.2-.7.6-.2h.1l-.7 1-1.1 1.6c-.1.2-.1.4 0 .5 0 .1.1.2.2.2.3.2.6.1.8-.2l.1-.2 2.4-3.5h.1c1.2-2.2 2.4-4.4 3.3-6.7v-.1l-.2-.3-.1-.2-.1-.1-2.9-4.7c-.4-.7-.2-1.6.5-2l4.7-2.9.3-.2.1-.1-1 2.8c-.1.3.1.6.3.7h.1c.2 0 .5-.1.6-.3l1.5-4.1h.1l.1-.5.1-.2v-.2c.1-.2.1-.4.2-.6.3-1.2.6-2.3.9-3.5.1-.2.1-.5.2-.7l.6-3v-.2c.2-.9.3-1.9.5-2.8 0-10.8.9-20.2 2.9-26.1v.1l.7 1.7c.1.2.3.3.5.4h.2c.3-.1.4-.4.3-.7l-1.2-2.9v-.2l-.4-1.1 1.1-.3c1.8-3.5 4.1-6.7 6.8-9.6 0 .6.1 1.2.3 1.8.1.2.3.4.5.4h.2c.2-.1.4-.3.4-.5v-.2c-.1-.8-.2-1.7-.3-2.5l.1-.1v-.1l.1-4.1 4.3.1c3.6-3 7.5-5.6 11.6-7.8l1.7-6.2 5.1 1.4h.1l-2.6 1.1c-.1 0-.2.1-.2.2-.1.1-.2.4-.1.6.1.3.4.4.7.3h.1l3.8-1.7.5.1c5.3-2.1 10.9-3.3 16.6-3.5.6 0 1.2 0 1.7.1 8.6.6 23 11.7 34.3 22.9 0 0 .1 0 .1-.1.1-.1.3-.1.4-.1.2 0 .4.1.5.2 3.4 3.3 6.6 6.8 9.5 10.6 2.9 3.2 6.5 7.7 7.7 12.5 1 4 .2 8.7-1.3 12.8-1.2 3.2-2.8 6-4.1 7.8-4.3 5.5-8.4 7.8-15.3 8.7-.8.1-1.6.2-2.4.2-.1-.1-.3-.
1-.4-.1-2.1-.1-4.2-.2-6.3-.5l-.2 2.1c1.5.2 3 .3 4.6.4l.1.9v.2c1.3.4 2.1 1.6 2 2.9 0 .2 0 .5-.1.7l-.3.6.6.6c.3.3.6.7.9 1.1 1.6-2.1 1.5-5-.5-6.9.8 0 1.6-.1 2.4-.2 7.5-1 12.1-3.6 16.7-9.5 3.7-4.6 7.9-14.7 5.9-22.5-1.3-5.2-5.1-10.1-8.1-13.3-2.9-3.9-6.1-7.5-9.7-10.8-.5-.5-1.2-.8-1.8-.8-5.4-5.4-11.3-10.3-17.5-14.7-5.4-3.7-10-6.2-13.9-7.2-.5-.2-1.1-.3-1.6-.4h-.1c-.6-.1-1.2-.2-1.7-.2-.6 0-1.2-.1-1.9-.1-5.7.2-11.4 1.3-16.7 3.4l-.2-.1-6.5-1.8h-.1c-1.2-.3-2.3.4-2.6 1.6l-1.4 5.3c-3.7 2-7.2 4.4-10.5 7.1l-3.5-.1c-1.2 0-2.2 1-2.2 2.2l-.1 3.3c-2.8 3-5.3 6.3-7.3 9.9l-.3.1c-1.2.4-1.8 1.6-1.5 2.8l.2.5c-2.2 5.7-3.3 15-3.3 27.6-.6 3.6-1.4 7.2-2.2 10.6l-5 2.8-1.1.7c-.9.5-1.4 1.4-1.7 2.3-.2.9-.1 1.9.4 2.8l2.6 4.3c-.7 1.6-1.5 3.2-2.3 4.7l-5.8 1.8c-1.2.4-2.1 1.3-2.4 2.5-.2.7-.2 1.4 0 2.1l.7 2.2.5 1.7-1.8 2.1h2.9c.5-.6 1-1.1 1.4-1.7l-.2-.8z"/>
+ <path fill="url(#o)" fill-rule="nonzero" d="M237.3 167.2c-.2.3-.6.7-1 1 0 .9.1 1.7.2 2.4.1.5 0 1.3 0 2.2 0 2-.2 4.6 0 6.1v3.5c-.4 15.3-3.8 25.4-5.2 29-.4 1.4-.7 2.6-1.1 3.8-1.6 4.6-3.6 8.6-5.3 11.2-.5.8-1.1 1.5-1.5 2-.7.8-1.4 1.3-1.9 1.3-.2 0-.3-.1-.5-.2-.3-.3-.5-1.5-.5-3.3v-1-.3-.1c0-2.2.2-5.1.3-7.9v-.1c2.4-.9 4.6-2.3 6.5-4h.1c.2-.2.2-.6 0-.8-.2-.2-.6-.2-.8 0-1.9 1.6-4 2.9-6.3 3.8-7.1 1.8-14.3 2.7-21.5 2.9-12.5 0-20.4-2.1-23.3-3l-.3-6.4c0-.3-.3-.5-.6-.5h-.1c-.1 0-.2.1-.3.2-.1.1-.1.2-.1.3l.2 5.8v.2h-.1c0 2.1.1 4.1.1 6 0 1.7 0 3.3-.1 4.6-.1 2-.3 3.3-.6 3.6-.1.1-.2.1-.3.1h-.2c-.6 0-1.4-.6-2.3-1.8-2-2.4-4.5-7.1-6.4-12.7-1.2-3.6-2.1-7.2-2.9-10.9h-.2v-.2c-2.2-9.3-4.2-20.2-4.8-23.4l-.2-.9c0-.1-.1-.3-.2-.4-.1-.1-.3-.1-.4-.1-.1 0-.2.1-.2.1-.2.1-.2.3-.2.5 0 .1.5 2.9 1.3 7 .1.7.3 1.5.4 2.2.9 4.6 2 10.2 3.2 15.3h-.2c-1.4.1-2.7.2-4.1.2-3 0-6-.3-9-.7-.1.3-.2.6-.3.8-.4.5-.9.9-1.5.9h-1v.2c3.9.7 7.8 1.1 11.8 1.2 1.3 0 2.6 0 3.9-.1.7 3.1 1.5 6.2 2.6 9.2.3.9 2.2 6.1 4.7 10.3 1.8 3.1 4 5.7 6.2 5.7
.5 0 1-.1 1.4-.4.2-.1.3-.2.5-.3.9-.8 1.7-1.4 1.5-12.8v-.1c7.2 1.8 14.7 2.7 22.2 2.6 6.6-.1 13.3-.9 19.7-2.4-.2 3.3-.3 5.7-.2 7.5.1 4.2.7 4.7 1.3 5.2.5.4 1.2.7 1.9.7.6 0 1.2-.2 1.8-.6 4.4-2.7 8.5-14 9-15.4.4-1.1.8-2.4 1.1-3.8 1.5-3.9 4.9-14.2 5.3-29.7v-1.8-1.3c-.1-3.6-.2-9.6-.4-14.4-.4.6-.7 1.7-1.1 2.2z"/>
+ <path fill="url(#p)" fill-rule="nonzero" d="M152 160.4c.2-.2 1.1.2 1-.1-.2-.8-.2-1.6 0-2.4-1.2-.7-2-1.3-2.5-1.9-.9-1-.8-1.8-.8-1.8 0-.2-.1-.4-.2-.6-.1 0-.1-.1-.2-.1H149c-.1 0-.2.1-.2.2h-.3c-.5.1-.8.4-.9.8v.4c0 .2.3 1.7 1.7 3.2.6 1 1.5 1.7 2.7 2.3z"/>
+ <path fill="url(#q)" fill-rule="nonzero" d="M161.9 166s-.1 0-.2.1c.1.9.2 1.8.4 2.6l-.2-2.7z"/>
+ <path fill="url(#r)" fill-rule="nonzero" d="M241.3 112.7c.1-.2.2-.5.2-.7v-3.5c0-.5-.3-1-.7-1.3-.3-.2-.6-.3-.9-.3-.9 0-1.6.7-1.6 1.6v3.5c0 .2 0 .4.1.6h.3c.3 0 .6-.1.9-.1.6 0 1.2.1 1.7.2z"/>
+ <path fill="url(#s)" fill-rule="nonzero" d="M235.1 117.3c.3.2.7.2 1 .1.2-.1.4-.2.6-.4.3-.4.7-.7 1.1-1 .7-.4 1.4-.7 2.3-.7 1 0 1.9.4 2.6 1 .3.2.5.4.7.7.4.5 1.1.6 1.6.2.4-.3.6-.9.3-1.4-.2-.4-.5-.7-.8-1-.8-.8-1.8-1.3-2.8-1.5-.8-.2-1.6-.2-2.4-.1-1 .1-1.9.5-2.7 1.1-.3.2-.6.4-.8.7l-.4.4-.4.4c-.6.5-.5 1.2.1 1.5z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M102.5 224.6c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h44.2c.1 0 .2 0 .2.1-.1-.4-.2-.8-.4-1.2H101v5.2h45.2c.2-.3.4-.8.6-1.3H102.4c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h44.2c.1 0 .2 0 .3.1.1-.4.1-.8 0-1.3-.1.1-.2.2-.3.2h-44.1v.2z"/>
+ <path fill="url(#t)" fill-rule="nonzero" d="M96.8 230.3c.9-.1 1.9-.2 2.9-.3v-.3h-2.6c-.1 0-.2 0-.3.1 0 .2-.1.3 0 .5z"/>
+ <path fill="url(#u)" fill-rule="nonzero" d="M151.8 225.1c0-2.9-1-5.2-1.9-6-.2-.1-1-.4-2.6-.5-.1.4-.3.9-.9.9l-.4.1-1.2-1H97.1c-.2 0-.3.2-.3.3v1.4c0 .2.2.3.3.3h15.6l34.2-.6.6.6h.1l.2.3 1.1 1.1-.2 1.1c.3 1.4.2 3-.2 4.2l3-.3c.2-.6.3-1.3.3-1.9z"/>
+ <path fill="#EDEDF0" fill-rule="nonzero" d="M142.6 230.1h-43v-.1c-1 .1-2 .2-2.9.3l.3 1c0 .2.2.3.3.3H144l1.1-1 .5.1c.4.1.6.3.8.6l.4.4c1.6 0 2.8-.3 3.3-.7.5-.4 1.1-2.1 1.5-3.8l-3 .3c-.2.5-.4 1-.6 1.4l-.2 1-5.2.2z"/>
+ <path fill="url(#v)" fill-rule="nonzero" d="M142.6 230.1h-43v-.1c-1 .1-2 .2-2.9.3l.3 1c0 .2.2.3.3.3H144l1.1-1 .5.1c.4.1.6.3.8.6l.4.4c1.6 0 2.8-.3 3.3-.7.5-.4 1.1-2.1 1.5-3.8l-3 .3c-.2.5-.4 1-.6 1.4l-.2 1-5.2.2z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M112.7 220.7h34.9l-.7-.6"/>
+ <path fill="url(#w)" fill-rule="nonzero" d="M112.7 220.7h34.9l-.7-.6"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M147.9 221l.1.1c.4.6.7 1.3.8 2l.2-1.1-1.1-1z"/>
+ <path fill="url(#x)" fill-rule="nonzero" d="M147.9 221l.1.1c.4.6.7 1.3.8 2l.2-1.1-1.1-1z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M99.7 230.1h43l5.1-.3.2-1c-.2.3-.4.5-.6.7l-.3.3H99.7v.3z"/>
+ <path fill="url(#y)" fill-rule="nonzero" d="M99.7 230.1h43l5.1-.3.2-1c-.2.3-.4.5-.6.7l-.3.3H99.7v.3z"/>
+ <path fill="url(#z)" fill-rule="nonzero" d="M95.2 231.8c.2 1 1.1 1.7 2.2 1.7h47.3l.6-.6c.3.3.8.6 1.4.6 1.5 0 3.4-.2 4.5-1.1 1.1-.9 1.9-3.4 2.2-5.4.1-.7.2-1.4.2-1.9 0-3.2-1-6.2-2.6-7.5-.6-.4-1.8-.7-3.6-.9h-.8c-.3 0-.6.1-.7.3l-.4-.3H97c-1.2 0-2.2 1-2.2 2.2v1.4c0 1.2 1 2.2 2.2 2.2h1.2v5.2H97c-.7 0-1.3.3-1.8.9-.4.5-.5 1.1-.4 1.7v.2l.4 1.3zm1.6-1.9c.1-.1.2-.1.3-.1h50l.3-.3c.2-.2.4-.4.6-.7.3-.4.5-.9.6-1.4.4-1.3.5-2.8.2-4.2-.2-.7-.4-1.4-.8-2l-.1-.1-.2-.3H97.2c-.2 0-.3-.2-.3-.3v-1.4c0-.2.2-.3.3-.3h47.7l1.2 1 .4-.1c.6-.1.8-.5.9-.9 1.6.1 2.4.4 2.6.5.9.8 1.9 3.1 1.9 6 0 .6-.1 1.4-.2 2.1-.3 1.7-.9 3.4-1.5 3.8-.5.4-1.8.6-3.3.7l-.4-.4c-.2-.3-.4-.5-.8-.6l-.5-.1-1.1 1H97.5c-.2 0-.3-.1-.3-.3l-.3-1v-.1c-.2-.3-.1-.4-.1-.5zm50.2-4.1c.1.1.2.2.2.4s-.1.4-.3.4c-.1.5-.3.9-.6 1.3H101v-5.2h45.5c.2.4.3.8.4 1.2.1.1.2.2.2.4 0 .1-.1.2-.1.3.1.3.1.8 0 1.2z"/>
+ <path fill="url(#A)" fill-rule="nonzero" d="M147 223.8c-.1 0-.2-.1-.2-.1h-44.2c-.3 0-.5.2-.5.5s.2.5.5.5h44.2c.1 0 .3-.1.3-.2.1-.1.1-.2.1-.3 0-.2-.1-.3-.2-.4z"/>
+ <path fill="url(#B)" fill-rule="nonzero" d="M102.5 225.6c-.3 0-.5.2-.5.5s.2.5.5.5H146.9c.2-.1.3-.2.3-.4 0-.1-.1-.3-.2-.4-.1-.1-.2-.1-.3-.1h-44.2v-.1z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M103 210.8h38.8v-5.2h-38.5c-.8 1.1-1 3.5-.3 5.2z"/>
+ <path fill="url(#C)" fill-rule="nonzero" d="M134.5 203.4c-1.4-.5-2.8-.9-4.2-1.5h-.2l4.2 1.5h.2z"/>
+ <path fill="url(#D)" fill-rule="nonzero" d="M145.3 203.6c-2.5-.5-5.1-1-7.6-1.8h-.2c2.5.8 5.1 1.4 7.8 1.8z"/>
+ <path fill="url(#E)" fill-rule="nonzero" d="M103.2 213.9l.4-.1 1 1h40.6c.2 0 .3-.2.3-.3v-1.4c0-.2-.1-.3-.3-.3h-13.3l-29.1.6-.5-.6h-.1l-.2-.3-.9-1.1.1-1.1c-.4-2-.1-4.2.7-5.6l.1-1 4.4-.3h18.5c-.8-.4-1.7-.9-2.6-1.5h-17.1l-.9 1-.4-.1c-.3-.1-.5-.3-.7-.6-.1-.1-.2-.3-.3-.4-1.3 0-2.4.3-2.8.7-.7.6-1.4 3.8-1.4 5.9 0 2.9.8 5.2 1.6 6 .1.1.9.4 2.2.5 0-.5.2-.9.7-1z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M134.3 203.4c-1.4-.5-2.8-.9-4.2-1.5h-7.8c.9.6 1.8 1.1 2.6 1.5h9.4z"/>
+ <path fill="url(#F)" fill-rule="nonzero" d="M134.3 203.4c-1.4-.5-2.8-.9-4.2-1.5h-7.8c.9.6 1.8 1.1 2.6 1.5h9.4z"/>
+ <path fill="url(#G)" fill-rule="nonzero" d="M145.3 203.6c.1-.1.1-.2.1-.3l-.2-1.1c0-.2-.1-.3-.3-.3h-7.2c2.5.7 5 1.3 7.6 1.7z"/>
+ <path fill="url(#H)" fill-rule="nonzero" d="M145.3 203.6c.1-.1.1-.2.1-.3l-.2-1.1c0-.2-.1-.3-.3-.3h-7.2c2.5.7 5 1.3 7.6 1.7z"/>
+ <path fill="url(#I)" fill-rule="nonzero" d="M142.9 203.4v.3h2.2c.1 0 .1 0 .2-.1-2.6-.4-5.2-1-7.8-1.8h-7.2l4.2 1.5h8.4v.1z"/>
+ <path fill="url(#J)" fill-rule="nonzero" d="M142.9 203.4v.3h2.2c.1 0 .1 0 .2-.1-2.6-.4-5.2-1-7.8-1.8h-7.2l4.2 1.5h8.4v.1z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M131.8 212.7h-29.6l.5.7"/>
+ <path fill="url(#K)" fill-rule="nonzero" d="M131.8 212.7h-29.6l.5.7"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M101.9 212.4l-.1-.1c-.3-.6-.6-1.3-.7-2l-.1 1.1.9 1z"/>
+ <path fill="url(#L)" fill-rule="nonzero" d="M101.9 212.4l-.1-.1c-.3-.6-.6-1.3-.7-2l-.1 1.1.9 1z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M134.5 203.4h-28.1l-4.4.3-.1 1c.1-.3.3-.5.5-.7l.2-.3H143v-.3h-8.5z"/>
+ <path fill="url(#M)" fill-rule="nonzero" d="M134.5 203.4h-28.1l-4.4.3-.1 1c.1-.3.3-.5.5-.7l.2-.3H143v-.3h-8.5z"/>
+ <path fill="url(#N)" fill-rule="nonzero" d="M103 216.8h.2c.2 0 .4-.1.5-.3l.3.3H145.4c1-.1 1.7-1.1 1.7-2.2v-1.4c0-1.2-.9-2.2-1.9-2.2h-1v-5.5h1c.6 0 1.1-.3 1.5-.9.2-.3.3-.5.3-.8.1-.3.1-.7 0-1.1l-.2-1.1c-.1-.4-.3-.8-.5-1.1-.4-.1-.7-.3-1-.5l-.5.4h-40.1c-.2 0-.3 0-.5-.1-.4-.1-.7-.3-.9-.6h-.2c-1.2 0-2.9.2-3.9 1.1-1.3 1.3-2 5.5-2 7.4 0 3.2.9 6.2 2.2 7.5.5.4 1.5.7 3.1.9.1.1.3.2.5.2zm-2.8-2.5c-.8-.8-1.6-3.1-1.6-6 0-2.1.8-5.3 1.4-5.9.4-.4 1.5-.6 2.8-.7.1.1.3.3.3.4.2.3.4.5.7.6l.4.1.9-1H144.8c.1 0 .2.1.3.3l.2 1.1c0 .1 0 .2-.1.3l-.1.1s-.1.1-.2.1h-42.6l-.2.3c-.2.2-.3.4-.5.7-.8 1.4-1.1 3.6-.7 5.6.1.7.4 1.4.7 2l.1.1.2.3h43c.2 0 .3.2.3.3v1.4c0 .2-.1.3-.3.3h-40.6l-1-1-.4.1c-.5.1-.7.5-.8.9-1 0-1.8-.2-1.9-.4zm41.5-8.7v5.2H103c-.7-1.7-.5-4.1.3-5.2h38.4z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M108.9 193.8c-.2 0-.4-.2-.4-.4s.2-.4.4-.4h37.5c.1 0 .1 0 .2.1l-.3-.9h-38.6v4.1H146c.2-.3.4-.6.5-1h-37.6c-.2 0-.4-.2-.4-.4s.2-.4.4-.4h37.5c.1 0 .2 0 .3.1 0-.3.1-.7 0-1-.1.1-.2.1-.3.1h-37.5v.1z"/>
+ <path fill="url(#O)" fill-rule="nonzero" d="M104.3 198.9c0 .1.1.2.3.2h13.9c-.4-.4-.9-.8-1.3-1.1h-10.7v-.3h-2.2c-.1 0-.2 0-.2.1-.1.1-.1.1-.1.2l.3.9z"/>
+ <path fill="url(#P)" fill-rule="nonzero" d="M104.2 189.1c-.1 0-.2.1-.2.2v1.1c0 .1.1.3.3.3h9.3c0-.6.1-1.1.2-1.6h-9.6z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M113.8 189.1h-9.5-.1 9.6z"/>
+ <path fill="url(#Q)" fill-rule="nonzero" d="M113.8 189.1h-9.5-.1 9.6z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M117.2 198c.4.4.8.8 1.3 1.1h5.7c-.7-.4-1.4-.7-2-1.1h-5z"/>
+ <path fill="url(#R)" fill-rule="nonzero" d="M117.2 198c.4.4.8.8 1.3 1.1h5.7c-.7-.4-1.4-.7-2-1.1h-5z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M113.8 189.1c-.1.5-.2 1.1-.2 1.6h3.4c.1-.6.2-1.1.4-1.6h-3.6z"/>
+ <path fill="url(#S)" fill-rule="nonzero" d="M113.8 189.1c-.1.5-.2 1.1-.2 1.6h3.4c.1-.6.2-1.1.4-1.6h-3.6z"/>
+ <path fill="url(#T)" fill-rule="nonzero" d="M142.9 198h-15.8c.9.4 1.7.8 2.6 1.1h14.4l.9-.8.4.1c.3.1.5.3.7.5.1.1.2.3.3.3 1.3 0 2.4-.2 2.8-.5.7-.5 1.4-2.9 1.4-4.6 0-2.3-.8-4-1.6-4.6-.1-.1-.8-.3-2-.4h-.2c-.1.3-.3.6-.7.7h-.3l-1-.7h-13.3c-.4.5-.7.9-1.1 1.4l16.2-.3.5.5h.1l.2.2.9.8-.1.9c.4 1.6.1 3.2-.7 4.3l-.1.8-4.5.3z"/>
+ <path fill="url(#T)" fill-rule="nonzero" d="M142.9 198h-15.8c.9.4 1.7.8 2.6 1.1h14.4l.9-.8.4.1c.3.1.5.3.7.5.1.1.2.3.3.3 1.3 0 2.4-.2 2.8-.5.7-.5 1.4-2.9 1.4-4.6 0-2.3-.8-4-1.6-4.6-.1-.1-.8-.3-2-.4h-.2c-.1.3-.3.6-.7.7h-.3l-1-.7h-13.3c-.4.5-.7.9-1.1 1.4l16.2-.3.5.5h.1l.2.2.9.8-.1.9c.4 1.6.1 3.2-.7 4.3l-.1.8-4.5.3z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M146.8 189.1h.2-.2z"/>
+ <path fill="url(#U)" fill-rule="nonzero" d="M146.8 189.1h.2-.2zM146.8 189.1h.2-.2z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M144.8 189.1h-13.3 13.3z"/>
+ <path fill="url(#V)" fill-rule="nonzero" d="M144.8 189.1h-13.3 13.3zM144.8 189.1h-13.3 13.3z"/>
+ <path fill="url(#W)" fill-rule="nonzero" d="M119.8 189.1c-.3.5-.5 1-.6 1.6l10.5-.2c.3-.5.7-.9 1-1.4h-10.9z"/>
+ <path fill="url(#W)" fill-rule="nonzero" d="M119.8 189.1c-.3.5-.5 1-.6 1.6l10.5-.2c.3-.5.7-.9 1-1.4h-10.9z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M130.8 189.1h-10.9 10.9z"/>
+ <path fill="url(#X)" fill-rule="nonzero" d="M130.8 189.1h-10.9 10.9zM130.8 189.1h-10.9 10.9z"/>
+ <path fill="url(#Y)" fill-rule="nonzero" d="M129.7 190.5h.6c.4-.5.7-.9 1.1-1.4h-.7c-.3.5-.6.9-1 1.4z"/>
+ <path fill="url(#Y)" fill-rule="nonzero" d="M129.7 190.5h.6c.4-.5.7-.9 1.1-1.4h-.7c-.3.5-.6.9-1 1.4z"/>
+ <path fill="url(#Y)" fill-rule="nonzero" d="M129.7 190.5h.6c.4-.5.7-.9 1.1-1.4h-.7c-.3.5-.6.9-1 1.4z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M131.5 189.1h-.7.7z"/>
+ <path fill="url(#Z)" fill-rule="nonzero" d="M131.5 189.1h-.7.7zM131.5 189.1h-.7.7zM131.5 189.1h-.7.7z"/>
+ <path fill="url(#aa)" fill-rule="nonzero" d="M122.2 198c.6.4 1.3.8 2 1.1h5.5c-.9-.4-1.8-.7-2.6-1.1h-4.9z"/>
+ <path fill="url(#ab)" fill-rule="nonzero" d="M122.2 198c.6.4 1.3.8 2 1.1h5.5c-.9-.4-1.8-.7-2.6-1.1h-4.9z"/>
+ <path fill="url(#ac)" fill-rule="nonzero" d="M119.8 189.1h-2.5c-.2.5-.3 1-.4 1.6h2.3c.1-.6.3-1.1.6-1.6z"/>
+ <path fill="url(#ad)" fill-rule="nonzero" d="M119.8 189.1h-2.5c-.2.5-.3 1-.4 1.6h2.3c.1-.6.3-1.1.6-1.6z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M117.2 198H142.9l4.4-.2.1-.8c-.1.2-.3.4-.5.5l-.2.2h-40.2v.3h10.7z"/>
+ <path fill="url(#ae)" fill-rule="nonzero" d="M117.2 198H142.9l4.4-.2.1-.8c-.1.2-.3.4-.5.5l-.2.2h-40.2v.3h10.7z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M130.3 190.5h-.6l-10.5.2h-1.6 29.5l-.5-.5"/>
+ <path fill="url(#af)" fill-rule="nonzero" d="M130.3 190.5h-.6l-10.5.2h-1.6 29.5l-.5-.5"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M147.4 191l.1.1c.3.5.6 1 .7 1.6l.1-.9-.9-.8z"/>
+ <path fill="url(#ag)" fill-rule="nonzero" d="M147.4 191l.1.1c.3.5.6 1 .7 1.6l.1-.9-.9-.8z"/>
+ <path fill="url(#ah)" fill-rule="nonzero" d="M104.1 200.5c.2 0 .3.1.5.1h40.1l.5-.4c.2.2.6.4 1 .5h.2c1.2 0 2.9-.2 3.8-.8 1.3-1 2-4.2 2-5.7 0-2-.6-3.8-1.4-5-.2-.3-.5-.6-.8-.8-.5-.3-1.5-.6-3.1-.7h-.7c-.3 0-.5.1-.6.3l-.3-.2h-.8c-.3.4-.8.6-1.4.6h-40.2c-.2.3-.4.6-.5.9v1.3c0 1 .8 1.7 1.9 1.7h1v4.1h-1c-.6 0-1.1.2-1.5.7-.4.4-.5 1-.3 1.5l.2.9c.1.3.2.5.4.7.2 0 .5.2 1 .3-.1 0-.1 0 0 0zm0-2.7c.1-.1.1-.1.2-.1H146.7l.2-.2.5-.5c.8-1.1 1.1-2.8.7-4.3-.1-.6-.4-1.1-.7-1.6l-.1-.1-.2-.2h-42.8c-.2 0-.3-.1-.3-.3v-1.1c0-.1.1-.2.2-.2h40.6l1 .7h.3c.5-.1.7-.4.7-.7h.2c1.2.1 1.9.3 2 .4.8.6 1.6 2.4 1.6 4.6 0 1.6-.8 4.1-1.4 4.6-.4.3-1.5.5-2.8.5-.1-.1-.3-.2-.3-.3-.2-.2-.4-.4-.7-.5l-.4-.1-.9.8h-39.5c-.1 0-.2-.1-.3-.2l-.3-1s0-.1.1-.2zm42.5-3.2c.1.1.1.2.1.3 0 .2-.1.3-.3.3-.1.4-.3.7-.5 1h-38.4v-4.1h38.6l.3.9c.1.1.2.2.2.3 0 .1 0 .2-.1.3.2.4.2.7.1 1z"/>
+ <path fill="url(#ai)" fill-rule="nonzero" d="M146.6 193.1c-.1 0-.1-.1-.2-.1h-37.5c-.2 0-.4.2-.4.4s.2.4.4.4h37.5c.1 0 .2 0 .3-.1.1-.1.1-.2.1-.3 0-.1-.1-.2-.2-.3z"/>
+ <path fill="url(#aj)" fill-rule="nonzero" d="M108.9 194.6c-.2 0-.4.2-.4.4s.2.4.4.4h37.6c.2 0 .3-.2.3-.3 0-.1-.1-.2-.1-.3-.1-.1-.2-.1-.3-.1h-37.5v-.1z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M101.1 183.6h38.6v-4.1h-38.4c-.6 1-.8 2.8-.2 4.1z"/>
+ <path fill="url(#ak)" fill-rule="nonzero" d="M98.4 186.4c.1.1.9.3 2.2.4.1-.3.3-.7.8-.7h.3l1 .8h11.9c.2-.5.5-1 .8-1.4l-14.6.2-.5-.5h-.1l-.2-.2-.9-.8.1-.9c-.3-1.2-.2-2.5.2-3.5H97c-.2.7-.3 1.4-.3 2 .1 2.2.9 4 1.7 4.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M120.7 176.7h-17.3l-.9.8h17.9c0-.3.1-.5.3-.8z"/>
+ <path fill="url(#al)" fill-rule="nonzero" d="M120.7 176.7h-17.3l-.9.8h17.9c0-.3.1-.5.3-.8z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M102 177.4c-.3-.1-.5-.3-.7-.5-.1-.1-.2-.3-.3-.3-1.3 0-2.4.2-2.8.5l-.3.3h4.5-.4z"/>
+ <path fill="url(#am)" fill-rule="nonzero" d="M102 177.4c-.3-.1-.5-.3-.7-.5-.1-.1-.2-.3-.3-.3-1.3 0-2.4.2-2.8.5l-.3.3h4.5-.4z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M133 177.5c.2-.3.5-.5.8-.8l-.8.8z"/>
+ <path fill="url(#an)" fill-rule="nonzero" d="M133 177.5c.2-.3.5-.5.8-.8l-.8.8z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M100 178.9l.1-.8 4.4-.2h15.6c0-.1.1-.2.2-.4H97.9c-.3.5-.7 1.3-.9 2.2h2.5c.2-.3.3-.6.5-.8z"/>
+ <path fill="url(#ao)" fill-rule="nonzero" d="M100 178.9l.1-.8 4.4-.2h15.6c0-.1.1-.2.2-.4H97.9c-.3.5-.7 1.3-.9 2.2h2.5c.2-.3.3-.6.5-.8z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M133 177.5c-.2.1-.3.2-.4.4l.4-.4z"/>
+ <path fill="url(#ap)" fill-rule="nonzero" d="M133 177.5c-.2.1-.3.2-.4.4l.4-.4z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M120.2 185.3l-4.7.1c-.3.4-.6.9-.8 1.4h4.1c.3-.6.8-1.1 1.4-1.5z"/>
+ <path fill="url(#aq)" fill-rule="nonzero" d="M120.2 185.3l-4.7.1c-.3.4-.6.9-.8 1.4h4.1c.3-.6.8-1.1 1.4-1.5z"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M120.1 177.9h4c.7-.7 1.6-1.1 2.6-1.1h.3l3.3.3c.1-.1.2-.2.3-.4h-10c-.1.3-.3.5-.4.8 0 .1 0 .2-.1.4z"/>
+ <path fill="url(#ar)" fill-rule="nonzero" d="M120.1 177.9h4c.7-.7 1.6-1.1 2.6-1.1h.3l3.3.3c.1-.1.2-.2.3-.4h-10c-.1.3-.3.5-.4.8 0 .1 0 .2-.1.4z"/>
+ <path fill="url(#as)" fill-rule="nonzero" d="M143.1 186.7c.2 0 .3-.1.3-.3v-1.1c0-.1-.1-.3-.3-.3h-7.9l-1.6 1.6h9.5v.1z"/>
+ <path fill="url(#at)" fill-rule="nonzero" d="M143.1 186.7c.2 0 .3-.1.3-.3v-1.1c0-.1-.1-.3-.3-.3h-7.9l-1.6 1.6h9.5v.1z"/>
+ <path fill="url(#au)" fill-rule="nonzero" d="M122 186.7h10.7c.3-.3.6-.6.8-.9l.7-.7h-4.4l-5.8.1c-.7.6-1.4 1.1-2 1.5z"/>
+ <path fill="url(#av)" fill-rule="nonzero" d="M122 186.7h10.7c.3-.3.6-.6.8-.9l.7-.7h-4.4l-5.8.1c-.7.6-1.4 1.1-2 1.5z"/>
+ <path fill="url(#aw)" fill-rule="nonzero" d="M140.9 177.9v.3h1c.4-.3.9-.7 1.3-1l-.1-.2c0-.1-.1-.2-.3-.2h-3.6c-.2.4-.5.8-.9 1.1h2.6z"/>
+ <path fill="url(#ax)" fill-rule="nonzero" d="M140.9 177.9v.3h1c.4-.3.9-.7 1.3-1l-.1-.2c0-.1-.1-.2-.3-.2h-3.6c-.2.4-.5.8-.9 1.1h2.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M133.9 177.5c.9 0 1.7-.3 2.4-.8h-2.5c-.2.3-.5.5-.8.8h.9z"/>
+ <path fill="url(#ay)" fill-rule="nonzero" d="M133.9 177.5c.9 0 1.7-.3 2.4-.8h-2.5c-.2.3-.5.5-.8.8h.9z"/>
+ <path fill="url(#az)" fill-rule="nonzero" d="M133.9 177.5c.9 0 1.7-.3 2.4-.8h-2.5c-.2.3-.5.5-.8.8h.9z"/>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M133 177.5l-.4.4h5.7c.3-.3.6-.7.9-1.1h-3c-.7.5-1.5.8-2.4.8h-.8v-.1z"/>
+ <path fill="url(#aA)" fill-rule="nonzero" d="M133 177.5l-.4.4h5.7c.3-.3.6-.7.9-1.1h-3c-.7.5-1.5.8-2.4.8h-.8v-.1z"/>
+ <path fill="url(#aB)" fill-rule="nonzero" d="M133 177.5l-.4.4h5.7c.3-.3.6-.7.9-1.1h-3c-.7.5-1.5.8-2.4.8h-.8v-.1z"/>
+ <path fill="url(#aC)" fill-rule="nonzero" d="M132.7 186.7h.9c.5-.6 1.1-1.1 1.6-1.6h-.9l-.7.7-.9.9z"/>
+ <path fill="url(#aC)" fill-rule="nonzero" d="M132.7 186.7h.9c.5-.6 1.1-1.1 1.6-1.6h-.9l-.7.7-.9.9z"/>
+ <path fill="url(#aD)" fill-rule="nonzero" d="M132.7 186.7h.9c.5-.6 1.1-1.1 1.6-1.6h-.9l-.7.7-.9.9z"/>
+ <path fill="url(#aE)" fill-rule="nonzero" d="M143.1 178.1c.1 0 .2 0 .2-.1.1-.1.1-.1.1-.2l-.2-.7c-.4.3-.9.7-1.3 1h1.2z"/>
+ <path fill="url(#aE)" fill-rule="nonzero" d="M143.1 178.1c.1 0 .2 0 .2-.1.1-.1.1-.1.1-.2l-.2-.7c-.4.3-.9.7-1.3 1h1.2z"/>
+ <path fill="url(#aF)" fill-rule="nonzero" d="M143.1 178.1c.1 0 .2 0 .2-.1.1-.1.1-.1.1-.2l-.2-.7c-.4.3-.9.7-1.3 1h1.2z"/>
+ <path fill="url(#aG)" fill-rule="nonzero" d="M127 176.8h-.3c-1 0-1.9.4-2.6 1.1h8.5l.4-.4c.2-.3.5-.5.8-.8h-3c-.1.1-.2.2-.3.4l-3.5-.3z"/>
+ <path fill="url(#aH)" fill-rule="nonzero" d="M127 176.8h-.3c-1 0-1.9.4-2.6 1.1h8.5l.4-.4c.2-.3.5-.5.8-.8h-3c-.1.1-.2.2-.3.4l-3.5-.3z"/>
+ <path fill="url(#aI)" fill-rule="nonzero" d="M120.2 185.3c-.6.5-1.1 1-1.5 1.5h3.4c.6-.5 1.3-1 2-1.5h-3.9z"/>
+ <path fill="url(#aJ)" fill-rule="nonzero" d="M120.2 185.3c-.6.5-1.1 1-1.5 1.5h3.4c.6-.5 1.3-1 2-1.5h-3.9z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M115.4 185.3h4.8l3.9-.1 5.8-.1h-29.6l.6.5"/>
+ <path fill="url(#aK)" fill-rule="nonzero" d="M115.4 185.3h4.8l3.9-.1 5.8-.1h-29.6l.6.5"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M100.1 184.9l-.1-.1c-.3-.5-.6-1-.7-1.6l-.1.9.9.8z"/>
+ <path fill="url(#aL)" fill-rule="nonzero" d="M100.1 184.9l-.1-.1c-.3-.5-.6-1-.7-1.6l-.1.9.9.8z"/>
+ <path fill="#FAFAFA" fill-rule="nonzero" d="M138.4 177.9h-33.8l-4.4.2-.1.8c.1-.2.3-.4.5-.5l.2-.2H141v-.3h-2.6z"/>
+ <path fill="url(#aM)" fill-rule="nonzero" d="M138.4 177.9h-33.8l-4.4.2-.1.8c.1-.2.3-.4.5-.5l.2-.2H141v-.3h-2.6z"/>
+ <path fill="url(#aN)" fill-rule="nonzero" d="M97.4 187.5c.5.3 1.5.6 3.1.7h.7c.3 0 .5-.1.6-.3l.3.2h41c.6 0 1.1-.2 1.4-.6.2-.2.4-.5.4-.7 0-.1.1-.3.1-.4v-1.1c0-1-.8-1.7-1.9-1.7h-1v-4h1c.6 0 1.1-.2 1.5-.7.4-.4.5-1 .3-1.5l-.1-.2-.2-.7c0-.1-.1-.3-.2-.4-.3-.6-.9-.9-1.7-.9h-40l-.5.4c-.3-.2-.7-.5-1.2-.5-1.2 0-2.9.2-3.8.8-.4.3-.8.8-1.1 1.5-.3.7-.6 1.5-.7 2.2-.2.8-.3 1.5-.3 2 0 2.1.6 4 1.6 5.2.2.3.4.5.7.7zm-.4-7.8c.2-.9.5-1.8.9-2.2l.3-.3c.4-.3 1.5-.5 2.8-.5.1.1.3.2.3.3.2.2.4.4.7.5l.4.1.9-.8h39.4c.1 0 .2.1.3.2l.1.2.2.7c0 .1 0 .2-.1.2-.1.1-.1.1-.2.1H100.6l-.2.2-.5.5c-.2.3-.3.5-.5.8-.4 1-.5 2.3-.2 3.5.1.6.4 1.1.7 1.6l.1.1.2.2H143c.2 0 .3.1.3.3v1.1c0 .1-.1.3-.3.3h-40.4l-1-.8h-.3c-.5.1-.7.4-.8.7-1.3-.1-2.1-.3-2.2-.4-.8-.6-1.6-2.4-1.6-4.6.1-.6.2-1.3.3-2zm42.8-.1v4.1h-38.6c-.7-1.3-.5-3.2.3-4.1h38.3z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M190.1 151.1c-8.6-5.4-23.3-5.4-23.5-5.4-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6.1 0 7.6-.1 15.1 1.8 5.8 1.5 10 3.7 12.6 6.7h.2c-9.2-10.9-26.7-9.7-26.9-9.6-.3 0-.6-.2-.6-.5s.2-.6.5-.6c.2 0 15.7-1.1 25.6 7.7-2.1-2.3-5.5-5.2-10.1-7.3-6.7-2.9-14.7-1.9-17-1.5l-1.2 5.3 25.1 4.3c0 .3.1.3.2.3zM210.5 142.3c-5 2.4-8.1 5.4-10 7.7 8.8-8.7 22.6-8.9 22.7-8.9.3 0 .6.2.6.6 0 .3-.2.6-.6.6-.2 0-15.1.2-23.3 10 .2-.1.4-.2.6-.4 2.3-2.2 5.4-4 9.5-5.5 6.9-2.5 14.1-3.1 14.2-3.1.3 0 .6.2.6.5s-.2.6-.5.6c-.2 0-12 1-19.8 5.9l22.3-4.7c-.7-2.4-1.4-5-1.7-6.2-2.1 0-9.4.4-14.6 2.9z"/>
+ <path fill="url(#aO)" fill-rule="nonzero" d="M230.9 147v-.5c-.1-.3-.2-.6-.4-.8-.3-.4-.8-.5-1.3-.5h-.2c-.7-2.6-1.7-6.5-1.9-7.1-.1-.3-.4-.6-.7-.7-1.2-.5-10.5-.2-16.7 2.9-7.5 3.7-11.2 8.5-12.7 11-1.8-2.6-6-7.4-13.1-10.5-8.6-3.7-18.7-1.6-19.1-1.5-.4.1-.8.4-.8.8l-1.4 6.1h-.3c-.5 0-.9.2-1.3.5-.3.3-.5.8-.5 1.3l.3 4.3h.5l.4.1.5 4.9c1.6-.1 6-.5 6.5-.5.8 0 1.3.5 1.4 1.4.2 1.9-1.9 5-7.1 6.2-.3.1-.9.6-1.1.8-.1.1.2.6-.1.8l.2 2.7.1.8.1 1.2 1.2 15.4c.1.9.8 1.5 1.6 1.5l24.9 3.6c.9.9 2.9 2.3 6.2 2.3h.8c3.6-.2 5.6-1.6 6.5-2.5l22.1-3.1c.9 0 1.6-.7 1.7-1.5l1.1-11.7.1-1.1.4-4.5c-.3-.1-.7-.2-1-.3-.8-.3 1.5-.1.4-.3-3.5-.8-5.4-2.9-6.2-4.7l-10.6 1.6h-.2c-.3 0-.5-.1-.7-.3-.2-.2-.4-.5-.4-.9l.1-5.5c0-.5.4-1 .9-1.1l11.5-1.8c.3 0 .7 0 .9.3.2.2.4.5.4.9l.1 3c1.5.1 4.3.3 5.5.5l.5-4.9h.1v-.1l.3-3.3.2-2.1v-.1l.3-3zm-66.3-.2l1.2-5.3c2.4-.4 10.3-1.4 17 1.5 4.7 2 8 4.9 10.1 7.3-9.9-8.9-25.4-7.8-25.6-7.7-.3 0-.5.3-.5.6s.3.5.6.5c.2 0 17.7-1.3 26.9 9.6h-.2c-2.6-2.9-6.8-5.2-12.6-6.7-7.5-1.9-15-1.8-15.1-1.8-.3 0-.6.3-.6.
6s.3.5.6.6c.2 0 14.9-.1 23.5 5.4-.1 0-.2-.1-.3-.1l-25-4.5zm38.5 40.8s-1.4 3.6-6.7 3.1c-5.3-.5-6.4-2.8-6.4-2.8l-.3-33.2s3.3 2 7.5 1.7c4.2-.3 6.7-2.5 6.7-2.5l-.8 33.7zm1.3-37.2c7.9-4.9 19.6-5.9 19.8-5.9.3 0 .5-.3.5-.6s-.3-.5-.6-.5c-.1 0-7.2.6-14.2 3.1-4.1 1.5-7.2 3.3-9.5 5.5-.2.1-.4.2-.6.4 8.2-9.8 23.1-10 23.3-10 .3 0 .6-.3.6-.6s-.3-.6-.6-.6c-.2 0-14 .2-22.7 8.9 1.9-2.3 5.1-5.3 10-7.7 5.2-2.5 12.4-2.9 14.5-2.8.3 1.2 1 3.8 1.7 6.2l-22.2 4.6z"/>
+ <path fill="url(#aP)" fill-rule="nonzero" d="M223.7 156.1c-.2-.2-.6-.3-.9-.3l-11.5 1.8c-.5.1-.9.5-.9 1.1l-.1 5.5c0 .3.1.6.4.9.2.2.5.3.7.3h.2l10.6-1.6c-.4-.9-.5-1.8-.4-2.4.1-.8.6-1.4 1.4-1.4.1 0 .5 0 .9.1l.1-3.1c-.2-.4-.3-.7-.5-.9z"/>
+ <path fill="url(#aQ)" fill-rule="nonzero" d="M223.7 156.1c-.2-.2-.6-.3-.9-.3l-11.5 1.8c-.5.1-.9.5-.9 1.1l-.1 5.5c0 .3.1.6.4.9.2.2.5.3.7.3h.2l10.6-1.6c-.4-.9-.5-1.8-.4-2.4.1-.8.6-1.4 1.4-1.4.1 0 .5 0 .9.1l.1-3.1c-.2-.4-.3-.7-.5-.9z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M162.8 163.3c4.7-1 6.4-3.7 6.3-5 0-.4-.2-.4-.3-.4-.4 0-4.4.3-6.9.6h-.5l-.6-5.1c-.9 0-3.2.4-5.5 2.6-1.4 1.3-1.7 3.1-.9 4.6.9 2 3.7 3.8 8.4 2.7z"/>
+ <path fill="url(#aR)" fill-rule="nonzero" d="M161.7 166.1c.1 0 .2 0 .2-.1.3-.2 0-.7.1-.8.2-.2.8-.7 1.1-.8 5.2-1.1 7.3-4.3 7.1-6.2-.1-.8-.6-1.4-1.4-1.4-.5 0-4.9.4-6.5.5l-.5-4.9-.4-.1h-.5c-.8 0-2.3.2-4 1.2-.7.4-1.5 1-2.3 1.7-.8.7-1.3 1.6-1.5 2.5-.2.8-.2 1.6 0 2.4.1.3-.8-.1-1 .1v.1c-.1.9.5 2.4 2 3.7 1.4 1.5 3.9 2.5 7.6 2.1zm-6.5-9.9c2.3-2.3 4.6-2.6 5.5-2.6l.6 5.1h.5c2.6-.2 6.5-.6 6.9-.6.1 0 .2 0 .3.4.1 1.2-1.6 3.9-6.3 5-4.7 1-7.5-.7-8.5-2.5-.7-1.7-.3-3.4 1-4.8z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M231.1 156.6l-.6 5.1h-.5c-2.6-.2-6.5-.6-6.9-.6-.1 0-.2 0-.3.4-.1 1.2 1.6 3.9 6.3 5 4.7 1 7.5-.7 8.5-2.5.8-1.5.5-3.3-.9-4.6-2.5-2.4-4.7-2.7-5.6-2.8z"/>
+ <path fill="url(#aS)" fill-rule="nonzero" d="M236.7 157.9c-3.2-2.7-6.1-2.4-6.2-2.4h-.5l-.5 4.9c-1.2-.1-4-.3-5.5-.5-.5 0-.8-.1-.9-.1-.8 0-1.3.5-1.4 1.4-.1.6.1 1.5.4 2.4.8 1.9 2.7 4 6.2 4.7 1 .2-1.2 0-.4.3.4.1.7.2 1 .3.3.1.6.2 1 .2 2.8.5 5.1-.1 6.4-1.1.4-.3.8-.6 1-1 .4-.5.7-1.6.9-2.2.1-.2.2-.4.2-.5.8-1.6.7-3.3-.2-4.8-.2-.4-.5-.7-.9-1.1-.2-.1-.4-.3-.6-.5zm.8 6c-1 1.8-3.8 3.5-8.5 2.5s-6.4-3.7-6.3-5c0-.4.2-.4.3-.4.4 0 4.4.3 6.9.6h.5l.6-5.1c.9 0 3.2.4 5.5 2.6 1.5 1.5 1.8 3.2 1 4.8z"/>
+ <path fill="url(#aT)" fill-rule="nonzero" d="M189.7 154.7l.3 33.2s1.1 2.2 6.4 2.8c5.3.6 6.7-3.1 6.7-3.1l.8-33.7s-2.5 2.2-6.7 2.5c-4.2.3-7.5-1.7-7.5-1.7z"/>
+ <path fill="url(#aU)" fill-rule="nonzero" d="M189.7 154.7l.3 33.2s1.1 2.2 6.4 2.8c5.3.6 6.7-3.1 6.7-3.1l.8-33.7s-2.5 2.2-6.7 2.5c-4.2.3-7.5-1.7-7.5-1.7z"/>
+ <path d="M-31-22h352v303H-31z"/>
+ </g>
+</svg>
diff --git a/browser/extensions/onboarding/content/img/figure_performance.svg b/browser/extensions/onboarding/content/img/figure_performance.svg
new file mode 100644
index 000000000000..f7c5c219aada
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_performance.svg
@@ -0,0 +1 @@
+<svg width="297" height="245" viewBox="0 0 297 245" xmlns="http://www.w3.org/2000/svg"><title>performance</title><defs><linearGradient x1="-920.838%" y1="-294.992%" x2="891.374%" y2="366.984%" id="a"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-162.81%" y1="-242.422%" x2="179.364%" y2="239.183%" id="b"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-347.431%" y1="-836.5%" x2="1777.43%" y2="3692.808%" id="c"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-494.697%" y1="-397.029%" x2="2194.58%" y2="1809.556%" id="d"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-358.927%" y1="-240.795%" x2="1727.185%" y2="1250.312%" id="e"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="1
00%"/></linearGradient><linearGradient x1="-626.22%" y1="-1767.938%" x2="1375.102%" y2="3610.616%" id="f"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-2092.13%" y1="-2092.3%" x2="2102.26%" y2="2102.09%" id="g"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-10687.27%" y1="-10695.62%" x2="6524.09%" y2="6515.75%" id="h"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-235.943%" y1="-613.083%" x2="463.706%" y2="1010.631%" id="i"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-10998.63%" y1="-10974.25%" x2="6212.73%" y2="6237.11%" id="j"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-73.995%" y1="-65.306%" x2="120.692%" y2="159.00
8%" id="k"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-21.918%" y1="-53.508%" x2="187.863%" y2="264.044%" id="l"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-489.211%" y1="-179.924%" x2="521.605%" y2="253.611%" id="m"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-7695.347%" y1="-543.989%" x2="5437.677%" y2="468.444%" id="n"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-871.152%" y1="-248.513%" x2="1179.248%" y2="414.667%" id="o"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-737.21%" y1="-1393.274%" x2="549.019%" y2="955.49%" id="p"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></li
nearGradient><linearGradient x1="-638.104%" y1="-1298.114%" x2="447.684%" y2="806.622%" id="q"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-1950.055%" y1="-1089.986%" x2="3277.839%" y2="1905.929%" id="r"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-575.859%" y1="-1406.193%" x2="985.226%" y2="2277.098%" id="s"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-1033.963%" y1="-1091.623%" x2="2289.262%" y2="2403.036%" id="t"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-2408.138%" y1="-454.703%" x2="4538.159%" y2="962.257%" id="u"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-998.9%" y1="-1143.058%" x2="1755.168%" y2="1997.85
%" id="v"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-4669.755%" y1="-4076.6%" x2="8549.086%" y2="7499.45%" id="w"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-195.59%" y1="-922.704%" x2="389.831%" y2="1341.95%" id="x"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient><linearGradient x1="-343.613%" y1="-263.57%" x2="487.353%" y2="406.119%" id="y"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-27.659%" y1="2.333%" x2="125.482%" y2="104.574%" id="z"><stop stop-color="#D7B600" offset="0%"/><stop stop-color="#05A700" offset="100%"/></linearGradient><linearGradient x1="-651.262%" y1="-472.878%" x2="435.248%" y2="317.591%" id="A"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGr
adient><linearGradient x1="-548.021%" y1="-473.693%" x2="248.049%" y2="204.898%" id="B"><stop stop-color="#FFFBCC" offset="0%"/><stop stop-color="#CEF7C6" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M-24-20h352v303H-24z"/><g fill-rule="nonzero"><path d="M13.6 181.6c-2.8 0-5.1-2.2-5.1-4.8V58.3c0-3 2.4-5.4 5.4-5.4h127.2c3 0 5.4 2.4 5.4 5.4v118.5c0 2.6-2.3 4.8-5 4.8H13.6z" fill="#FFF"/><path d="M141.1 54c2.3 0 4.2 1.9 4.2 4.2v118.5c0 2-1.8 3.7-3.9 3.7H13.6c-2.2 0-3.9-1.7-3.9-3.7V58.3c0-2.3 1.9-4.2 4.2-4.2h127.2V54zm0-2.2H13.9c-3.6 0-6.5 2.9-6.5 6.5v118.4c0 3.3 2.8 5.9 6.2 5.9h127.8c3.4 0 6.2-2.7 6.2-5.9V58.3c-.1-3.6-3-6.5-6.5-6.5z" fill="#D7D7DB"/></g><path d="M139.9 75.2v98.2c0 1-.1 1.2-.1 1.2s-.2.1-1.2.1H16.4c-1 0-1.2-.1-1.2-.1s-.1-.2-.1-1.2V75.2h124.8zM141 74H13.9v99.3c0 2 .4 2.5 2.5 2.5h122.2c2 0 2.5-.4 2.5-2.5V74h-.1z" fill-rule="nonzero" fill="#D7D7DB"/><g fill-rule="nonzero" fill="#D7D7DB"><circle cx="3.7" cy="3" r="2.9" transform="translat
e(17 61)"/><circle cx="3" cy="3" r="2.9" transform="translate(27 61)"/><path d="M109.4 67.2H45.5c-1.7 0-3.1-1.4-3.1-3.1v-.3c0-1.7 1.4-3.1 3.1-3.1h63.9c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.7-1.3 3.1-3.1 3.1z"/><g><circle cx="3" cy="3" r="2.9" transform="translate(122 61)"/><circle cx="3.2" cy="3" r="2.9" transform="translate(131 61)"/></g></g><g fill-rule="nonzero"><path d="M39.9 22.9h23.8S56.3 6.3 72.1 4.1c14.1-1.9 19.7 12.6 19.7 12.6s1.7-8.4 10.1-6.8c8.3 1.6 14.4 14.9 14.4 14.9H137" fill="#F9F9FA"/><path d="M137.2 20.9h-4.5c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h4.5c.3 0 .6.3.6.6s-.2.6-.6.6zm-14.5 0h-1.1c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .3-.3.6-.6.6zm-5.5 0h-.6c-.2 0-.4-.1-.5-.3-.1-.2-.6-1.1-1.3-2.3-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.6.9 1 1.7 1.2 2.1h.3c.3 0 .6.2.6.6 0 .4-.4.5-.7.5zm-53.1-.7h-1.5c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h.6c-.1-.3-.2-.6-.4-1-.1-.3.1-.6.4-.7.3-.1.6.1.7.4.3 1 .6 1.7.6 1.7.1.2.1.4 0 .5 0 .2-.2.3-.4.3zm-10.4 0H40.3c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h13.4c.3 0 .6.3.6.6s-.3
.6-.6.6zm8.8-6.1c-.3 0-.5-.2-.6-.5 0-.4-.1-.8-.1-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.1 1.1.1.3-.1.6-.5.6zm29.1-1.2c-.2 0-.4-.1-.5-.3-.1-.3-.3-.6-.5-1-.1-.3 0-.6.2-.8.3-.1.6 0 .8.2.2.4.4.7.5 1 .1.3 0 .6-.3.7 0 .2-.1.2-.2.2zm18-1.4c-.1 0-.3-.1-.4-.2-2.4-2.3-4.8-3.7-7.2-4.1-1.6-.3-3.1-.2-4.3.2-.3.1-.6-.1-.7-.4-.1-.3.1-.6.4-.7 1.4-.5 3.1-.6 4.9-.2 2.6.5 5.2 2 7.7 4.4.2.2.2.6 0 .8-.1.2-.2.2-.4.2zM88.7 8.2c-.2 0-.3-.1-.4-.2-.7-.9-1.4-1.7-2.2-2.4-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0 .8.8 1.6 1.6 2.3 2.5.2.2.2.6-.1.8-.2.1-.3.1-.4.1zM65.8 4c-.2 0-.3-.1-.4-.2-.2-.2-.2-.6.1-.8C67.2 1.6 69.6.7 72.4.3c2.2-.3 4.3-.2 6.3.2.3.1.5.4.4.7-.1.3-.4.5-.7.4-1.9-.4-3.9-.5-5.9-.2-2.7.4-4.8 1.2-6.4 2.4-.1.1-.2.2-.3.2z" fill="#D7D7DB"/><path d="M137.9 25.1h-98c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h98c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1z" fill="#F9F9FA"/></g><path d="M261.4 80.6c.2-.3.6-1 .2-1.3-.3-.2-.6-.3-1-.3-.8 0-1.6.3-2.3.8-1.4 1-2.6 2.7-2.3 3.5 2.5-.5 4.6-1.5 5.4-2.7z"/><path d="M59.3 94.4c4.3.1 8.5-1 12
.1-3.3 3.3-2.1 7.2-3.1 11.1-3 3.9-.1 7.8 1 11.1 3 7.5 4.4 16.8 4.4 24.3 0 6.8-4 15.3-4 22.2 0 7.5 4.4 16.8 4.4 24.3 0 6.8-4 15.3-4 22.2 0 3.6 2.2 7.9 3.4 12.1 3.3.6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1-3.9.1-7.8-.9-11.1-3-7.5-4.4-16.8-4.4-24.3 0-6.8 4-15.3 4-22.2 0-7.5-4.4-16.8-4.4-24.3 0-6.8 4-15.3 4-22.2 0-3.6-2.2-7.9-3.4-12.1-3.3-4.3-.1-8.5 1-12.1 3.3-3.3 2.1-7.2 3.1-11.1 3-3.9.1-7.8-.9-11.1-3-3.6-2.2-7.9-3.4-12.1-3.3-.6 0-1.1.5-1.1 1.1 0 .6.5 1.1 1.1 1.1 3.9-.1 7.8.9 11.1 3 3.6 2.3 7.8 3.4 12.1 3.3zM269.2 82.1c-.2-.2-.5-.3-.8-.1-3.1 2-6.6 3.2-10.3 3.5-1.4.2-2.8.2-4.2 0 2.2-.7 4.2-1.7 5.1-2.9 1.1-1.5.4-2.4.1-2.7-1-.9-3.1-.7-4.7.4-1.2.9-3.2 3-2.8 4.7-1.8.4-3.6.7-5.4.8-.3 0-.6.2-.6.6 0 .4.2.6.6.6 2-.1 4-.4 6-.9 1 .8 2.9 1 6 .7 7-.8 10.7-3.6 10.8-3.8.3-.3.4-.6.2-.9zm-14.1-.9c.7-.5 1.5-.8 2.3-.8.4 0 .7.1 1 .3.3.3 0 1-.2 1.3-.8 1.2-3 2.1-5.4 2.8-.3-1 .9-2.6 2.3-3.6z" fill="#D7D7DB" fill-rule="nonzero"/><path d="M154.6 87.1c-.3 0-.6-.3-.7-.6 0-.4.2-.7.6-.7 1.4-.1 2.8-.4 4-.9.3-.1.7.1.9
.4.1.3-.1.7-.4.9-1.4.4-2.8.7-4.4.9zM202.6 86.9c-.3 0-.6-.2-.7-.6-.1-.4.2-.7.5-.8 3.4-.6 5.5-1.9 7.5-3.3.3-.2.7-.1.9.2.2.3.1.7-.2.9-2.1 1.3-4.4 2.8-8 3.4.1.2 0 .2 0 .2zM148.2 86.8h-.1c-3.5-.6-5.7-2.1-7.9-3.5l-.1-.1c-.3-.2-.4-.6-.2-.9.2-.3.6-.4.9-.2l.1.1c2.2 1.4 4.2 2.7 7.4 3.3.4.1.6.4.5.8 0 .3-.3.5-.6.5zM241.1 86.7h-.1c-3.2-.7-5.4-2.1-7.5-3.4l-.5-.3c-.3-.2-.4-.6-.2-.9.2-.3.6-.4.9-.2l.4.3c2.1 1.3 4 2.6 7 3.2.4.1.6.4.5.8.1.3-.2.5-.5.5zM194.1 86.7h-.2c-.4-.1-.7-.2-1.1-.3-.4-.1-.6-.5-.4-.8.1-.4.5-.6.8-.4.3.1.6.2 1 .3.4.1.6.4.5.8 0 .2-.3.4-.6.4zM189.2 84.7c-.1 0-.2 0-.3-.1-.7-.4-1.4-.8-2-1.3-.5-.3-1.1-.7-1.6-1-.3-.2-.4-.6-.2-.9.2-.3.6-.4.9-.2.6.3 1.1.7 1.6 1 .6.4 1.3.8 2 1.2.3.2.4.6.2.9-.1.3-.4.4-.6.4zM162.6 84.3c-.2 0-.4-.1-.6-.3-.2-.3-.1-.7.2-.9l.9-.6c.3-.2.7-.1.9.2.2.3.1.7-.2.9l-.9.6c-.1 0-.2.1-.3.1zM216.1 80.6c-.3 0-.5-.2-.6-.5-.1-.4.1-.7.4-.8 1.4-.4 2.8-.7 4.3-.8.4 0 .7.2.7.6 0 .4-.2.7-.6.7-1.5.1-2.8.4-4 .8h-.2zM123.2 80.5c-.3 0-.6-.2-.6-.5-.1-.4.1-.7.5-.8 1.4-.4 2.8-.6 4.4-.7.4 0 .7
.3.7.6 0 .4-.3.7-.6.7-1.5.1-2.8.3-4.1.7h-.3zM171.2 80.1c-.3 0-.6-.2-.7-.5-.1-.4.2-.7.5-.8 1.4-.3 2.9-.4 4.5-.4 1.5 0 2.9.1 4.2.4.4.1.6.4.5.8-.1.4-.4.6-.8.5-1.2-.2-2.5-.4-4-.4-1.6 0-2.9.1-4.2.4.1 0 0 0 0 0zM132.7 80h-.1c-.3-.1-.7-.1-1-.1-.4 0-.6-.4-.6-.7 0-.4.4-.6.7-.6.4 0 .7.1 1.1.2.4.1.6.4.5.8 0 .2-.3.4-.6.4zM225.6 79.9h-.1c-.3-.1-.7-.1-1-.1-.4 0-.6-.4-.6-.7 0-.4.4-.6.7-.6.4 0 .7.1 1.1.1.4.1.6.4.6.8-.1.3-.4.5-.7.5z" fill="#D7D7DB" fill-rule="nonzero"/><g fill-rule="nonzero" fill="#D7D7DB"><path d="M12 200.6c4.3.1 8.5-1 12.1-3.3 6.8-4 15.3-4 22.2 0 7.5 4.4 16.8 4.4 24.3 0 3.3-2.1 7.2-3.1 11.1-3 .6 0 1.1-.5 1.1-1.1 0-.6-.5-1.1-1.1-1.1-4.3-.1-8.5 1-12.1 3.3-6.8 4-15.3 4-22.2 0-7.5-4.4-16.8-4.4-24.3 0-3.3 2.1-7.2 3.1-11.1 3-3.6.1-7.2-.8-10.3-2.6-.3.7-.7 1.3-1.2 1.9 3.5 2 7.5 3 11.5 2.9zM61.3 208.7c-.3 0-.6-.2-.7-.6-.1-.4.2-.7.5-.8 3.4-.6 5.5-1.9 7.5-3.3.3-.2.7-.1.9.2.2.3.1.7-.2.9-2.1 1.3-4.4 2.8-8 3.4v.2zM52.8 208.5h-.2c-.4-.1-.7-.2-1.1-.3-.4-.1-.6-.5-.4-.8.1-.4.5-.6.8-.4.3.1.6.2 1 .3.
4.1.6.4.5.8-.1.2-.3.4-.6.4zM47.8 206.5c-.1 0-.2 0-.3-.1-.7-.4-1.4-.8-2-1.3-.5-.3-1.1-.7-1.6-1-.3-.2-.4-.6-.2-.9.2-.3.6-.4.9-.2.6.3 1.1.7 1.6 1 .6.4 1.3.8 2 1.2.3.2.4.6.2.9-.1.3-.3.4-.6.4zM74.7 202.4c-.3 0-.5-.2-.6-.5-.1-.4.1-.7.4-.8 1.4-.4 2.8-.7 4.3-.8.4 0 .7.2.7.6 0 .4-.2.7-.6.7-1.5.1-2.8.4-4 .8h-.2z"/><path d="M29.8 202c-.3 0-.6-.2-.7-.5-.1-.4.2-.7.5-.8 1.4-.3 2.9-.4 4.5-.4 1.5 0 2.9.1 4.2.4.4.1.6.4.5.8-.1.4-.4.6-.8.5-1.2-.2-2.5-.4-4-.4-1.6 0-2.9.1-4.2.4.1-.1 0 0 0 0zM84.2 201.8h-.1c-.3-.1-.7-.1-1-.1-.4 0-.6-.4-.6-.7 0-.4.4-.6.7-.6.4 0 .7.1 1.1.1.4.1.6.4.6.8-.1.2-.4.5-.7.5z"/></g><path d="M112.1 196.9c-.2-.2-.5-.3-.8-.1-3.1 2-6.6 3.2-10.3 3.5-1.4.2-2.8.2-4.2 0 2.2-.7 4.2-1.7 5.1-2.9 1.1-1.5.4-2.4.1-2.7-1-.9-3.1-.7-4.7.4-1.2.9-3.2 3-2.8 4.7-1.8.4-3.6.7-5.4.8-.3 0-.6.2-.6.6 0 .3.2.6.6.6 2-.1 4-.4 6-.9 1 .8 2.9 1 6 .7 7-.8 10.7-3.6 10.8-3.8.3-.2.4-.6.2-.9zm-14.2-.9c.7-.5 1.5-.8 2.3-.8.4 0 .7.1 1 .3.3.3 0 1-.2 1.3-.8 1.2-3 2.1-5.4 2.8-.3-1 1-2.6 2.3-3.6z" fill="#D7D7DB" fill-rule="no
nzero"/><g fill-rule="nonzero" fill="#D7D7DB"><path d="M77 97.8c-14.9 0-27 12.1-27 27 0 4 .9 8 2.6 11.6.7 1.7 2.6 2.6 4.4 1.9 1.7-.7 2.6-2.6 1.9-4.4-.1-.2-.1-.3-.2-.4-1.3-2.7-2-5.7-2-8.7 0-11.2 9-20.3 20.2-20.3s20.3 9 20.3 20.2c0 3-.7 6-2 8.8-.8 1.7-.1 3.7 1.6 4.5 1.7.8 3.7.1 4.5-1.6 6.4-13.5.7-29.6-12.7-36-3.5-1.8-7.5-2.7-11.6-2.6z"/><path d="M89.8 118.3c-.8-.5-1.8-.3-2.3.5l-8.3 13.1c-3.6-1.2-7.4.8-8.5 4.3-1.2 3.6.8 7.4 4.3 8.5 2 .6 4.2.3 5.9-.8.7-.5 1.3-1.1 1.8-1.8 1.8-2.6 1.5-6.1-.7-8.4l8.3-13.1c.5-.8.3-1.8-.5-2.3z"/></g><g fill-rule="nonzero"><path d="M251.2 231.9l-13.4-1.7c-.5-.1-.9-.5-.9-1l-1.1-27.6-2.6 1.1c-.1.1-.3.1-.4.1-.2 0-.5-.1-.6-.2-.3-.2-.4-.6-.3-1l.8-3.6-3.6.6h-.2c-.3 0-.7-.2-.9-.5-.2-.3-.2-.8.1-1.1l4.2-5.6c.1-.1.2-.2.4-.3l7-3.3c.1-.1.3-.1.4-.1.2 0 .3 0 .4.1l7.8 3.9c.4.2.6.6.5 1 0 .4-.3.8-.7.9l-4.2 1.3 2 4c.2.3.1.7-.1 1-.2.3-.5.4-.8.4h-.2l-3.1-.5 10.3 30.8c.1.3 0 .7-.2 1-.2.2-.5.4-.8.4.3-.1.2-.1.2-.1z" fill="#F5F5F7"/><path d="M240.2 188.8l7.8 3.9-5.3 1.7 2.5 5-4.7-.8
10.9 32.4-13.4-1.7-1.1-29-3.9 1.7 1.1-5-5 .8 4.2-5.6 6.9-3.4zm0-2c-.3 0-.6.1-.9.2l-7 3.3c-.3.1-.5.3-.7.6l-4.2 5.6c-.5.7-.5 1.5-.1 2.2.4.6 1 1 1.7 1h.3l2.1-.3-.5 2.1c-.2.7.1 1.5.7 2 .4.3.8.5 1.3.5.3 0 .5-.1.8-.2l1.2-.5 1 26.1c0 1 .8 1.8 1.8 1.9l13.4 1.7h.2c.6 0 1.2-.3 1.5-.7.4-.5.6-1.3.3-1.9l-9.8-29.2 1.4.3h.3c.6 0 1.2-.3 1.6-.8.5-.6.5-1.4.2-2.1l-1.5-2.9 3.1-1c.8-.2 1.3-.9 1.4-1.7.1-.8-.4-1.6-1.1-1.9l-7.8-3.9c-.1-.3-.4-.4-.7-.4z" fill="#D7D7DB"/></g><g fill-rule="nonzero"><path d="M199.7 227.4c-.2 0-.5-.1-.7-.3-.2-.2-.3-.4-.3-.7l-1.1-24.8-2.6 1.1c-.1.1-.3.1-.4.1-.2 0-.5-.1-.6-.2-.3-.2-.4-.6-.3-1l.8-3.6-3.6.6h-.2c-.3 0-.7-.2-.9-.5-.2-.3-.2-.8.1-1.1l4.2-5.6c.1-.1.2-.2.4-.3l7-3.3c.1-.1.3-.1.4-.1.2 0 .3 0 .4.1l7.8 3.9c.4.2.6.6.5 1 0 .4-.3.8-.7.9l-4.2 1.3 2 4c.2.3.1.7-.1 1-.2.3-.5.4-.8.4h-.2l-3.2-.6 7.4 25.8c.1.3 0 .6-.1.9-.2.2-.5.4-.8.4.2.1-10.2.6-10.2.6z" fill="#F5F5F7"/><path d="M202 188.8l7.8 3.9-5.3 1.7 2.5 5-4.7-.8 7.8 27.3-10.3.6-1.1-26.2-3.9 1.7 1.1-5-5 .8 4.2-5.6 6.9-3.4zm0-2c-.
3 0-.6.1-.9.2l-7 3.3c-.3.1-.5.3-.7.6l-4.2 5.6c-.5.7-.5 1.5-.1 2.2.4.6 1 1 1.7 1h.3l2.1-.3-.5 2.1c-.2.7.1 1.5.7 2 .4.3.8.5 1.3.5.3 0 .5-.1.8-.2l1.2-.5 1 23.3c0 .5.3 1 .7 1.4.4.3.8.5 1.3.5h.1l10.3-.6c.6 0 1.2-.3 1.5-.8.3-.5.5-1.1.3-1.7l-6.9-24.3 1.6.3h.3c.6 0 1.2-.3 1.6-.8.5-.6.5-1.4.2-2.1l-1.5-2.9 3.1-1c.8-.2 1.3-.9 1.4-1.7.1-.8-.4-1.6-1.1-1.9l-7.8-3.9c-.2-.2-.5-.3-.8-.3z" fill="#D7D7DB"/></g><path d="M201.4 210.6l1.4 17.5" stroke="#D7D7DB" stroke-linecap="round" stroke-linejoin="round"/><path d="M203.6 221.7l2 11.7" stroke="#EAEAEE" stroke-linecap="round" stroke-linejoin="round"/><path d="M240.2 207.5l5 19" stroke="#D7D7DB" stroke-linecap="round" stroke-linejoin="round"/><path d="M236.5 220.6l1.2 10.9" stroke="#EAEAEE" stroke-linecap="round" stroke-linejoin="round"/><g transform="translate(153 210)" fill-rule="nonzero"><ellipse fill="#EDEDF0" cx="72.1" cy="27" rx="71.5" ry="7.9"/><ellipse fill="#F9F9FA" cx="72.2" cy="25.5" rx="56.8" ry="6.3"/><path d="M20.7 24.2l-.2-.2S12.4 7.7 28.1
4.9c14-2.5 20.1 11.8 20.1 11.8s1.4-8.4 9.8-7.1c8.3 1.3 14.9 14.3 14.9 14.3h.2" fill="#F9F9FA"/><path d="M79.4 19.7h-1.1c-.3 0-.6-.2-.6-.5s.2-.6.5-.6h1.1c.3 0 .6.2.6.5 0 .4-.2.6-.5.6zm-5.6.2h-.6c-.2 0-.4-.1-.5-.3-.1-.2-.6-1.1-1.4-2.3-.2-.3-.1-.6.1-.8.3-.2.6-.1.8.1.6.9 1.1 1.7 1.3 2.1h.3c.3 0 .6.2.6.5s-.3.7-.6.7zm-53 1.4l-1.5.1c-.3 0-.6-.2-.6-.5s.2-.6.5-.6h.6c-.1-.3-.3-.6-.4-1-.1-.3 0-.6.3-.7.3-.1.6 0 .7.3.4 1 .7 1.7.7 1.7.1.2.1.4 0 .5 0 .1-.2.2-.3.2zm-1.9-6.1c-.3 0-.5-.2-.6-.5-.1-.4-.1-.8-.1-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.1 1.1.1.3-.1.6-.5.6zM48 13c-.2 0-.4-.1-.5-.3-.1-.3-.3-.6-.5-1-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.2.4.4.7.6 1 .1.3 0 .6-.2.8-.2 0-.3.1-.4.1zm17.9-2.1c-.1 0-.3 0-.4-.1-2.5-2.2-5-3.5-7.3-3.9-1.6-.2-3.1-.1-4.3.3-.3.1-.6 0-.7-.3-.1-.3 0-.6.3-.7 1.4-.5 3.1-.7 4.9-.4 2.6.4 5.2 1.8 7.9 4.1.2.2.3.6 0 .8-.1.1-.2.2-.4.2zM44.8 8.4c-.2 0-.3-.1-.4-.2-.7-.8-1.5-1.6-2.3-2.3-.2-.2-.3-.6-.1-.8.2-.2.6-.3.8-.1.9.7 1.7 1.5 2.4 2.4.2.2.2.6-.1.8 0 .1-.2.2-.3.2zM21.8 5c-.2 0-.3-.1-.4-.2
-.2-.2-.2-.6.1-.8 1.7-1.4 4-2.4 6.8-2.9 2.2-.4 4.3-.4 6.3 0 .3.1.5.3.4.6-.1.3-.3.5-.6.4-1.9-.3-3.9-.3-5.9 0-2.7.5-4.8 1.4-6.3 2.7-.1.2-.3.2-.4.2z" fill="#D7D7DB"/><g><path d="M119.8 27l.2-.2s8.2-16.3-7.5-19.2C98.5 5 92.3 19.2 92.3 19.2S91 10.8 82.6 12c-8.3 1.2-15 14.2-15 14.2h-.2" fill="#F9F9FA"/><path d="M60.6 21.4c0-.3.3-.5.6-.5l1.1.1c.3 0 .5.3.5.6s-.3.5-.6.5l-1.1-.1c-.3 0-.5-.3-.5-.6zm5.5.3c0-.3.3-.5.6-.5h.3c.2-.4.7-1.1 1.3-2 .2-.3.5-.3.8-.1.3.2.3.5.1.8-.8 1.2-1.3 2-1.4 2.3-.1.2-.3.3-.5.3h-.6c-.3-.3-.6-.5-.6-.8zm53.2 2.1c-.1-.2-.1-.4 0-.5 0 0 .3-.6.7-1.7.1-.3.4-.4.7-.3.3.1.4.4.3.7-.1.4-.3.7-.4 1h.6c.3 0 .5.3.5.6s-.3.5-.6.5l-1.5-.1c-.1 0-.3-.1-.3-.2zm2.2-5.8c-.3-.1-.5-.3-.5-.6.1-.4.1-.7.1-1.1 0-.3.3-.5.6-.5s.5.3.5.6c0 .4-.1.8-.2 1.1.1.3-.1.5-.5.5.1 0 .1 0 0 0zm-29.2-2.6c-.3-.1-.4-.5-.2-.8.2-.3.3-.6.6-1 .2-.3.5-.3.8-.2.3.2.3.5.2.8-.2.4-.4.7-.5.9-.1.2-.3.3-.5.3-.2.1-.3.1-.4 0zm-18.1-2.3c-.2-.2-.2-.6.1-.8 2.7-2.3 5.3-3.7 7.9-4.1 1.8-.3 3.5-.1 4.9.4.3.1.4.4.3.7-.1.3-.4.4-.7.3-1.2-.5-2
.7-.6-4.3-.4-2.4.3-4.8 1.6-7.4 3.8-.1.1-.3.1-.4.1-.1.1-.3.1-.4 0zm21.2-2.3c-.2-.2-.3-.6 0-.8.8-.9 1.6-1.7 2.5-2.4.2-.2.6-.2.8.1.2.2.2.6-.1.8-.8.7-1.6 1.4-2.3 2.3-.1.1-.3.2-.4.2-.3-.1-.4-.1-.5-.2zm23-3.2c-1.5-1.3-3.6-2.2-6.3-2.7-2-.4-4-.4-5.9-.1-.3 0-.6-.2-.6-.5-.1-.3.2-.6.5-.6 2-.3 4.1-.3 6.3.1 2.9.5 5.1 1.5 6.8 3 .2.2.3.6.1.8-.1.1-.3.2-.4.2-.3-.1-.4-.1-.5-.2z" fill="#D7D7DB"/></g></g><g transform="translate(159 16)" fill-rule="nonzero"><path d="M125.2 89.7c-.8-4.6-5-4.7-14.4-4.7-7.5 0-17.8-.1-23.3-2.4-9.6-4-17.5-13.4-17.6-13.6-.6-.7-1.4-1.2-2.3-1.5l-.6 1.2c2.7 2.8 5 5.7 7 8.6 3.3 2.9 7.6 6 12.2 7.9 6.1 2.5 16.8 2.6 24.5 2.6 8.4.1 10.8.1 11.1 1.9.3 1.7-2 3.5-6.5 6.6-2.2 1.6-5.9 4.2-6.1 5.1 0 3.4-5.1 9.2-12.9 10-2.6.3-4.8.3-6.5.3-3.2.1-5.2.1-7.6 1.4-.3.2-.8.3-1.3.4-.4 1.1-.9 2.4-1.5 3.8 1.9 0 3.4-.3 4.4-.9 1.6-.9 2.8-.9 6-1 1.8 0 4-.1 6.8-.3 8.4-.8 14.8-6.8 15.8-12 1-.9 3.3-2.6 4.8-3.7 5.2-3.4 8.6-5.8 8-9.7z" fill="#F9F9FA"/><path d="M34.7 63.9h0zM37.6 63.9h-.4.4zM42.2 67.5c.8-1.1 1.
7-2.3 2.6-3.4-.9 1.2-1.8 2.3-2.6 3.4zM40.4 63.6H40c.1.1.2.1.4 0zM43.2 63.3c-.1 0-.3 0-.4.1.1-.1.3-.1.4-.1z" fill="#FFF"/><path d="M62.4 149.2c-.8-1-1.6-2-2.4-3.1-3.6 1-7.5 1.5-11.2 1.5-.8 0-1.6 0-2.4-.1.2.2.3.5.4.8v.1c0 .1.1.2.1.3v.2c.1.3.1.6 0 .9v1.2h1.5c3.2 0 6.6-.4 9.8-1.1.6.7 1.1 1.4 1.7 2.2.5-1.1 1.3-2.2 2.5-2.9z" fill="#F9F9FA"/><path d="M59.6 143.9c-.1 0-.3.1-.4.1.1 0 .3-.1.4-.1z" fill="#FFF"/><path d="M27.9 147c-.7-2.4-1.3-5.4-1.9-8.9-1.6-2.2-2.9-4.8-3.7-7.8-.9 0-1.9-.3-2.7-.8-1.9-1.1-2.9-3.2-2.7-5.4l-3.7-9.6c-.3-.8-.3-1.7 0-2.5-.8-3-1.3-7.3-.4-12.6 1.9-10.4 8.8-19.8 20.6-28.1.1-.4.3-.8.7-1.1l3.3-3c.4-.4 1-.6 1.5-.6.3 0 .6.1.9.2.2-.3.5-.7.7-1-2 .2-4 .3-5.9.3-14.8 0-23-6.5-23.3-18.3 0-2.7.3-5.5 1-8.4-2.9-2.4-4.8-5.3-5.7-8.5-.5-.9-1-1.9-1.3-2.9-2.4-7.5 1.8-15.5 9.3-17.9 1.4-.4 2.8-.7 4.3-.7 1.7 0 3.4.3 5 .9 2-.4 4-.6 6.1-.6h1.2c.6 0 1.2.1 1.8.1 3.3-2.2 6.7-3.9 10.1-4.9 3.7-1.1 7.5-1.7 11.3-1.7 7.4 0 14.8 2.3 20.9 6.4 13 2.2 22.3 11.2 22.3 21.6 0 10.2-8.8 18.9-21.5 21.4-2.1 1.6
-4.5 3-7 4.4-1.6 2.9-3.1 5.8-4.4 8.6.7.5 1.4 1.3 1.7 2.4.3.9.4 1.8.4 2.4.1 0 .1.1.2.1 0 .1 2.6 3.2 6.7 6.6-2-2.9-4.3-5.8-7-8.6l.6-1.2c1.2-2.6 2.5-5.2 4-7.9 2.1-1.2 4.1-2.4 5.9-3.7 13.9-3 23.4-12.9 23.4-24.5 0-11.8-10.2-22.1-24.4-24.7C69.6 2.3 61.8 0 54 0c-4.1 0-8.3.6-12.3 1.9-3.4 1.1-6.7 2.6-10 4.7h-2.2c-1.9 0-3.9.2-5.8.5-1.7-.5-3.5-.8-5.3-.8-1.8 0-3.5.3-5.3.8-4.5 1.4-8.2 4.5-10.3 8.7C.6 20 .2 24.7 1.6 29.2c.3 1.1.8 2.1 1.3 3.2.9 3.1 2.6 5.9 5.1 8.4-.5 2.5-.7 4.9-.6 7.2.1 5.4 1.7 9.9 4.7 13.5.4.4.7.8 1.1 1.2.8.8 1.6 1.5 2.6 2.1 3.6 2.5 8.3 4.1 13.9 4.6-11.9 8.6-19 18.5-21 29.5-1 5.4-.5 9.9.2 13.2-.2 1.2-.1 2.5.4 3.7l3.4 9c0 3.1 1.6 6 4.3 7.7.6.4 1.2.6 1.8.9.8 2.3 1.9 4.4 3.1 6.2.7 4 1.4 7.4 2.2 9.9 1.3-1.2 2.4-2.1 3.8-2.5z" fill="#F9F9FA"/><circle fill="#FFF" transform="rotate(-26.565 9.428 30.382)" cx="8.978" cy="29.932" r="1"/><path d="M7.2 22.9c-.1 1.5 0 3.1.5 4.7-.5-1.6-.7-3.2-.5-4.7zM22.6 128h.4-.6.2zM25.1 131.3c.2.6.4 1.2.7 1.8-.3-.6-.5-1.2-.7-1.8-.1 0 0 0 0 0zM22.7 119.8v-.7l
-1.4-1 1.4 1.7zM21.5 127.8c-.2-.1-.5-.2-.7-.3.2.2.5.3.7.3zM22.3 128c-.2 0-.5-.1-.7-.1.2 0 .5.1.7.1zM15.3 113v-.1.1zM15.3 113.3v-.1.1zM19.2 124.9v-.5c0 .2-.1.3 0 .5zM19.2 124.4v-.3.3zM50.5 145.3h-.1.1zM53.9 145h-.3.3zM28.5 138.9v-.1c-.1 0-.1 0 0 .1zM57 144.5c-.2 0-.3.1-.5.1.1 0 .3-.1.5-.1zM58.3 144.2c-.2 0-.3.1-.5.1.2 0 .4 0 .5-.1zM55.5 144.8c-.1 0-.3.1-.4.1.1-.1.3-.1.4-.1zM38.9 145.2c0 .1 0 .1 0 0 0 .1 0 .1 0 0zM48.8 145.4h.1-.2c.1-.1.1 0 .1 0zM41.5 144.6h-.2.2zM44 145h-.2.2zM95.7 31.4c0 1.8-.3 3.5-.9 5.1.6-1.6.9-3.3.9-5.1zM14.8 53.7c0-.1-.1-.2-.1-.3 0 .1 0 .2.1.3zM15.5 55.4c0-.1-.1-.2-.1-.3 0 .1.1.2.1.3zM16.3 56.7c-.1-.1-.1-.2-.1-.2 0 .1.1.2.1.2zM17.4 58.1c-.1-.1-.1-.2-.2-.2.1.1.2.1.2.2zM14.3 52c0-.1 0-.1-.1-.2 0 .1 0 .1.1.2zM14.4 41.2c0-.1.1-.3.1-.4 0 .1-.1.3-.1.4zM13.9 50.1v-.4.4zM13.8 45.9v-.5.5zM30.5 63.7h-.3.3zM18.5 59.2l-.1-.1s.1 0 .1.1zM28.6 63.5c-.1 0-.2 0-.4-.1.1 0 .3.1.4.1zM14.1 38l-.3-.3.3.3zM24.7 62.6c-.1 0-.2 0-.2-.1.1 0 .2 0 .2.1zM26.5 63.1c-.1 0-.2-.1-.3-.1.1 0 .2 0
.3.1zM19.9 60.3c-.1-.1-.2-.1-.3-.2.2.1.3.1.3.2zM23 61.9c-.1 0-.2-.1-.3-.1.1 0 .2.1.3.1zM8.3 29s0-.1-.1-.1c0 0 0 .1.1.1zM27.7 12.4c.4 0 .7-.1 1.1-.1-.3 0-.7 0-1.1.1zM18.1 11.9h.8-.8zM25.5 12.6h.2-.2zM30.3 12.2h-.7 1.8-1.1zM93.7 23.9c.2.4.5.9.7 1.4-.3-.5-.5-.9-.7-1.4zM89.5 18.7l.8.8c-.2-.3-.5-.6-.8-.8zM91.5 20.8c.5.5.9 1.1 1.3 1.7-.4-.6-.8-1.2-1.3-1.7zM10.6 34.1c-.1-.2-.2-.4-.3-.5.1.2.2.4.3.5zM9.3 31.6c-.1-.2-.2-.5-.2-.7.1.2.1.4.2.7zM12.9 37l-.3-.3.3.3zM17 12.1c.2 0 .5-.1.7-.1-.2 0-.5.1-.7.1zM11.9 35.9s0-.1 0 0c0-.1 0 0 0 0zM9.9 32.9l-.3-.6.3.6zM32.8 63.9h-.4.4zM11.4 14.7c.6-.5 1.2-1 1.9-1.3-.7.4-1.3.8-1.9 1.3zM15.6 12.4c.4-.1.7-.2 1.1-.3-.4.1-.8.2-1.1.3zM81.2 139.8h-1.1 1.1zM72.5 139.6c-.2 0-.4 0-.6-.1.2 0 .4 0 .6.1zM82.7 139.7c-.3 0-.6 0-1 .1.4-.1.7-.1 1-.1zM84.3 139.6c-.3 0-.6.1-1 .1.3-.1.6-.1 1-.1zM76.3 139.8h-.5.5zM74.4 139.7h-.6.6zM78.2 139.9h1.5-1.5zM92 138.5c-.3.1-.6.1-.9.2.3-.1.6-.1.9-.2zM90.6 138.8c-.3.1-.6.1-.9.1.3 0 .6-.1.9-.1zM85.9 139.4c-.3 0-.7.1-1 .1.3 0 .6 0 1-.1zM93.
4 138.2c-.3.1-.6.1-.9.2.3-.1.6-.1.9-.2zM89.2 139c-.4.1-.8.1-1.1.2.3-.1.7-.2 1.1-.2zM87.7 139.2c-.5.1-1 .1-1.4.2.5-.1 1-.1 1.4-.2zM69.2 121.2c-.3-.1-.5-.1-.8-.2l-1.3.8c.3.2.6.3.8.5l.6.3.7-1.4zM23.3 107.4v-.1.1zM23.2 105.3v-.1.1zM23.2 106.4v-.1.1zM71.5 141.8c.9 1.7 1.7 3.3 2.2 4.7-.5-1.4-1.3-3-2.2-4.7zM65.9 150c-1.8-2.3-3.6-4.6-5.1-6.4 1.5 1.8 3.2 4.1 5.1 6.4zM95 137.9l-1.2.3c.4-.2.8-.2 1.2-.3zM65 117.8c-.8.4-1.5.5-2.4.7.8.6 1 .9 1.9 1.5l1.3-.8c-.2-.2-.3-.4-.4-.6-.2-.2-.3-.4-.4-.8zM19.2 125c.1 1 .7 1.9 1.6 2.5-.9-.5-1.5-1.5-1.6-2.5zM38.9 144.1c0-.1 0-.1 0 0 0-.1 0-.1 0 0zM22.4 121.2l-2-2.5 1 2.7c.3-.2.6-.2 1-.2zM25.9 133.3c.7 1.4 1.4 2.7 2.3 3.9 0 .2.1.4.1.6 0-.2-.1-.4-.1-.6-.9-1.2-1.7-2.5-2.3-3.9zM96.3 137.5l-1.2.3c.5-.1.9-.2 1.2-.3zM105.8 134c-.2.1-.3.2-.5.3.2-.1.4-.2.5-.3zM106.2 133.7c-.1.1-.2.2-.3.2.1 0 .2-.1.3-.2zM105.2 134.4c-.1.1-.3.2-.4.2.1 0 .2-.1.4-.2zM106.6 133.5l-.2.2c0-.1.1-.2.2-.2zM104.5 134.8c-.1.1-.3.1-.4.2.1-.1.2-.2.4-.2zM106.8 133.2c0 .1-.1.1-.1.2 0-.1.1-.2.1-.2zM106
.9 132.9c0 .1 0 .1-.1.2.1-.1.1-.1.1-.2zM103.8 135.1c-.2.1-.3.1-.5.2.1 0 .3-.1.5-.2zM106.9 132.6v0zM95.8 130.5h.2-.2zM98.7 136.9c-.2.1-.5.1-.7.2.2-.1.5-.1.7-.2zM97.5 137.2c-.3.1-.5.1-.8.2.3 0 .6-.1.8-.2zM99.8 136.6c-.2.1-.5.1-.7.2.3-.1.5-.2.7-.2zM101 136.2c-.3.1-.5.2-.8.3.2-.1.5-.2.8-.3zM102.1 135.8l-.9.3.9-.3zM103 135.4c-.2.1-.4.2-.6.2.2 0 .4-.1.6-.2zM59.3 111.8h-.1.3-.2zM58.4 111.9h.2-.2zM57.6 112.2c-.1.1-.2.2-.3.2.1 0 .2-.1.3-.2zM74.2 116.6v0zM61 112.2c.1 0 .1.1.2.1-.1 0-.2 0-.2-.1zM65.4 114l.1-.1-.1.1zM61.6 112.8l.2.2c0-.1-.1-.2-.2-.2zM62.7 115.2c.7-.2 1.5-.4 2.3-.5-.8.1-1.5.3-2.3.5 0-.5-.1-1.1-.4-1.6.3.5.4 1 .4 1.6zM60.1 111.9h0zM64.3 111.8c.1-.1.1-.2.2-.3l-1.2-.3c.3.3.5.6.7.9l.3-.3z" fill="#FFF"/><path d="M79.1 113.9c-.5 0-1 0-1.5-.1-.3.9-.8 1.9-1.2 2.9 0 .4-.1.9-.3 1.3l-1.9 4.4c0 .1 0 .2-.1.3 0 .1 0 .1-.1.2.4.2.8.3 1.1.5 10.3 4.3 18.9 4.8 24.5 5.2 4.9.3 8.1.5 9.2 3.2.3.9.2 1.8-.3 2.7-2.3 3.4-17.1 7.7-30.4 7.7-1.4 0-2.8 0-4.1-.1.6 1.1 1 2.1 1.4 3 .1 0 .1 0 .2-.1.6-.1 3.7-.3 5.5
.4 7.3-.3 13.6-1.7 16.9-2.6 10.5-2.8 12.4-5.5 13-6.5 1.2-1.8 1.4-3.9.7-5.8-1.9-4.7-6.8-5-12.1-5.3-5.1-.3-12.6-.8-21.5-4.1l.7-1.7c.2-.6.4-1.1.5-1.7 0-.1 0-.1.1-.2.6-1.3 1.1-2.6 1.5-3.8-.5.2-1.1.2-1.8.2z" fill="#F9F9FA"/><path d="M56.8 110.8c.1.3.1.5.2.8 0-.3-.1-.5-.2-.8zM66.7 112c-.3.6-.6 1-.7 1.2.1-.2.4-.6.7-1.2z" fill="#FFF"/><path d="M58.4 107.7c2.3.6 4.7 1.2 7 1.8 1.7-4.3 3.2-13.6-7-26-1.7 7.8-1.7 15.9 0 24.2z" fill="url(#a)"/><path d="M81.2 111.4c2.9-1.6 5.3-1.6 8.6-1.7 1.8 0 3.8-.1 6.3-.3 6.8-.7 10.9-5.8 10.9-7.8 0-.4.1-.7.3-1.1-1.7.2-3.2.2-4.6.2-6.7 0-10.6-1.5-10.8-1.6-.3-.1-.4-.4-.3-.7.1-.3.4-.4.7-.3.1 0 6 2.4 15.9 1.2 1.2-1.2 3.1-2.7 5.8-4.6 1.8-1.3 4.4-3.1 5.3-4.2-1.5-.3-5.2-.3-8.6-.3-8-.1-18.9-.1-25.4-2.8C78.5 84.6 72.6 79.5 69 76c11 13.8 11.5 25.8 9.7 33.9 0 0-.2.7-.5 1.8 1.5.1 2.5 0 3-.3z" fill="url(#b)"/><path d="M28.3 16.1c1.8-1.9 3-3.1 3.9-3.7-.2 0-.5 0-.7-.1H29c-.4 0-.7 0-1.1.1-.7.1-1.4.1-2.1.2h-.2l-1.5.3c1.5.7 3 1.8 4.2 3.2z" fill="url(#c)"/><path d="M60.1 146.8s-4.
3 5.9-3.1 9c1.2 3.1 9.3 12.9 9.3 12.9s-1.2 8.1-.8 9.6c.4 1.5 4.2 5.8 12.7 2.5s8.8-8.3 8.9-12.3c0-1.6.3-4.2.1-7.8 0-.3 3.5-4.3 1.7-11.3-.8-3.1-2.5-4.3-2.8-4.3-1.1 0-.4 0-.7-.6-1.1-2.2-25.3 2.3-25.3 2.3z" fill="#F9F9FA"/><path d="M8.9 30.2c.1.2.1.4.2.7.1.2.1.5.2.7.1.2.2.5.3.7l.3.6c.1.2.2.5.4.7.1.2.2.4.3.5.4.6.8 1.2 1.2 1.7.2.3.5.5.7.8l.3.3c.3.3.5.5.8.7l.3.3s.1 0 .1.1c.4-1 .8-1.9 1.3-2.7-2.6-.8-4.9-2.6-6.4-5.1z" fill="url(#d)"/><path d="M16.6 30.2c-.3.5-1 .7-1.5.3-.5-.3-.7-1-.3-1.5.1-.1 1.8-2.7 5.1-2.7h.4c-.6-.2-1.1-.8-1.1-1.5l.1-3.5c0-.9.7-1.5 1.6-1.5.9 0 1.5.7 1.5 1.6l-.1 2.4c.9-1.3 1.9-2.5 2.9-3.7-.1-.2-.2-.5 0-.7 1.1-1.4 2.1-2.5 3-3.4-1.2-1.4-2.7-2.4-4.3-3.2-1.5-.7-3.1-1-4.8-1h-1.5c-.2 0-.5.1-.7.1-.1 0-.2 0-.3.1-.4.1-.7.2-1.1.3-.8.2-1.5.6-2.2 1-.7.4-1.4.8-1.9 1.3-1.5 1.3-2.6 2.9-3.4 4.7-.4 1.1-.7 2.3-.8 3.5-.1 1.5 0 3.1.5 4.7.1.5.3.9.5 1.3 0 0 0 .1.1.1l.6 1.2c1.5 2.5 3.8 4.3 6.5 5.2.7-1.3 1.4-2.2 1.4-2.3.1-.1.2-.2.3-.2.6-1.4 1.4-2.9 2.2-4.3-1.7.3-2.6 1.6-2.7 1.7z" fill="#F9F9FA"/><
path d="M20.9 19.8c-.9 0-1.6.7-1.6 1.5l-.1 3.5c0 .7.4 1.3 1.1 1.5h-.4c-3.4 0-5 2.5-5.1 2.7-.3.5-.2 1.2.3 1.5.5.3 1.2.2 1.5-.3 0 0 .9-1.3 2.6-1.6.9-1.6 1.9-3.2 3.1-4.7l.1-2.4c0-.9-.6-1.6-1.5-1.7z" fill="url(#e)"/><path d="M77.5 13.6c2.2 0 4.2.6 6 1.6-1.1-.8-2-1.3-2.6-1.6-1.9-.7-3.9-1.2-6-1.6.8.9 1.6 1.6 2.6 1.6z" fill="url(#f)"/><path fill="url(#g)" d="M19.1 113.1v-.1l-.1.1"/><path d="M68 122.3c.2.1.4.2.6.4-.2-.2-.4-.3-.6-.4z" fill="url(#h)"/><path d="M46.2 67.8c.6 0 1.3 0 2-.1 6.3-.4 13.8-2.8 13.9-2.9.2-.1.5-.1.7-.1h.3c1.3-2.7 2.6-5.2 3.8-7.5-3.4 1.7-10.3 4.6-22 6.8-.9 1.1-1.7 2.2-2.6 3.4.9.3 2.2.4 3.9.4z" fill="url(#i)"/><path d="M24.7 143.9s-4.7 5.6-3.8 8.8c.9 3.2 8.4 13.7 8.4 13.7s-1.8 8.1-1.5 9.6c.3 1.5 3.8 6.1 12.6 3.5 8.8-2.6 8.9-6.7 9.3-10.7.4-4 1-16.3.7-18.8-.3-2.5-25.7-6.1-25.7-6.1z" fill="#F9F9FA"/><path d="M69.7 127.3c.1-.2.1-.5.3-.8l-.3.6v.2z" fill="url(#j)"/><path d="M65.9 150c.8.3 2.4.4 5.3-.3 1.7-.4 2.7-.9 3.3-1.3l-.6-1.8c-.6-1.4-1.3-3.1-2.2-4.8-2.1-3.4-3.7-6.1-3.7-6.
1-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2 0 0 1.1 1.8 2.6 4.3.2 0 .4.1.6.1.2 0 .4 0 .6.1.4 0 .9.1 1.3.1h.6c.4 0 .9.1 1.4.1h6c.3 0 .6 0 1-.1h.6c.3 0 .6-.1 1-.1h.5c.4 0 .7-.1 1-.1h.4c.5-.1 1-.1 1.4-.2h.3c.4-.1.8-.1 1.1-.2.2 0 .3-.1.5-.1.3 0 .6-.1.9-.1.2 0 .4-.1.5-.1.3-.1.6-.1.9-.2.2 0 .3-.1.5-.1.3-.1.6-.1.9-.2.1 0 .3-.1.4-.1l1.2-.3h.1l1.2-.3c.1 0 .3-.1.4-.1.3-.1.5-.1.8-.2.2 0 .3-.1.4-.1.2-.1.5-.1.7-.2.1 0 .3-.1.4-.1.2-.1.5-.1.7-.2.1 0 .3-.1.4-.1.3-.1.5-.2.8-.3.1 0 .1 0 .2-.1l.9-.3c.1 0 .2-.1.2-.1.2-.1.4-.2.6-.2.1 0 .2-.1.3-.1.2-.1.3-.1.5-.2.1 0 .2-.1.3-.1.2-.1.3-.1.4-.2.1 0 .2-.1.2-.1.2-.1.3-.2.4-.2.1 0 .1-.1.2-.1.2-.1.4-.2.5-.3 0 0 .1 0 .1-.1.1-.1.2-.2.3-.2l.1-.1.2-.2.1-.1c0-.1.1-.1.1-.2 0 0 0-.1.1-.1 0-.1 0-.1.1-.2v-.1-.2c-.7-1.8-4.7-1.6-10.9-2.1h-.2c-5.6-.5-12.9-1.5-21.4-5.1-.4-.2-.8-.3-1.2-.5-.7 1.6-1.3 3.1-1.3 3.5-.1 1-1.2 2.7-2.7 3.6-.8.5-1.6.7-2.5.7-.5 0-1-.1-1.5-.3-.5-.2-.8-.8-.7-1.3-1.6-.8-2.2-2.3-2.3-3.2 0-.3.2-.6.5-.6h.1c.1-1.1.7-2.2 1.8-2.8 1-.5 2.1-.5 3-.1l.4-.9-.1-.1c-.4-.2-.7-.4
-1.1-.6l-.4-.2-.5-.3-1.7 1c-.3 1.3-1.3 3.4-3.5 3.5h-.2c-3 0-3.8-1.9-4.2-3.3-.1-.3.1-.6.4-.7h.1c0-.4 0-.8.1-1.2.5-1.8 2.5-2.9 4.3-2.3.8.2 1.4.7 1.9 1.4l.2-.1c-.3-.3-.6-.5-.8-.7-.2-.2-.4-.4-.7-.6l-.9-.7c-.9.2-1.8.3-2.6.3-.5 0-.9-.1-1.2-.2-2.3-.9-2.3-3.8-2.3-3.9 0-.3.3-.5.6-.6.2 0 .3.1.4.2.1-.9.6-1.7 1.4-2.2-.1-.3-.2-.6-.2-.9-.1-.3-.1-.5-.2-.8-.1-.4-.2-.9-.3-1.3 0-.2-.1-.4-.1-.6-.1-.6-.3-1.2-.4-1.8v-.1c-1.5-8.1-1.7-17.2 1-26.8-.9-1.2-1.5-1.9-2-2.4-2 .4-4.1.6-6.5.6h-.2c-1.3 3.8-2 7.3-2.3 10.5l2.3.1c.4 0 .8.3 1 .7.2.4 0 .9-.3 1.2l-3.1 2.9c.3 6.4 2.1 11.8 3.5 16 .4 1.2.8 2.4 1.1 3.4 2.8 9.4 2.6 17.3-.4 22.2-1.7 2.7-4.1 4.4-7.1 4.9-.4.1-.9.1-1.4.1-2.3 0-4.8-1-7-2.7-2.8-2.3-7.7-7.9-8.2-20.8C26 108.9 28 101 30.6 94c-.4-.1-.7-.3-.8-.6-.2-.3-.1-.7.1-1.1l6.2-10.2c1.1-2.1 2.2-3.9 3.1-5.3-2.9-1-4.3-2.4-5-3.3-4.3 3.1-8 6.3-10.9 9.7 0 0 0 .1-.1.2 1.2-1.4 2-2.2 2.1-2.3.3-.3.7-.3 1 0 .3.3.3.7 0 1 0 0-2.8 2.8-5.2 6.6-1.3 3.7-2.7 8.5-2.6 12.2.1 4.7 1.3 7.8 2.1 9.3.9.3 1.9.5 2.9.8-.1.8-.3 1.8-.3 2.9-.5-
.1-1-.3-1.4-.4.5.3.9.6 1.4.8.2-1.5.4-2.5.4-2.7.1-.3.3-.5.6-.5.3.1.5.3.5.6 0 .1-2 11.3.5 19.2.2.6.5 1.2.7 1.8 0 .1.1.1.1.2.7 1.4 1.4 2.7 2.3 3.9 0 .2.1.4.1.6.1.3.1.6.2 1v.1c.6 3.6 1.4 7.2 2.3 9.8.8.4 2.2.6 4.7.5 2-.1 3-.5 3.6-.8 0-1 0-2-.1-3v-.1c-4.5-1.2-6.1-2.9-6.2-3-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0 0 0 1.5 1.5 5.4 2.6v-.1l2.4.6h.2c.8.2 1.6.3 2.4.4h.2c1.6.2 3.2.3 4.7.3h1.7c1.1 0 2.1-.1 3.1-.3h.3c.4 0 .8-.1 1.1-.2.1 0 .3 0 .4-.1.3-.1.6-.1 1-.2.2 0 .3-.1.5-.1.3-.1.6-.1.9-.2.2 0 .3-.1.5-.1.3-.1.6-.1.9-.2.1 0 .3-.1.4-.1l1.2-.3c1.3 2.3 3 4.6 4.9 6.9zm8-22.2c.1-.2.3-.4.5-.5.4-.1.8.1 1.2.3 4.8 2.9 14 4.5 27.2 4.6.1 0 .6 0 .8.4.1.2.1.5-.1.8-.5.7-8.8 1.8-15.3 1.8-2 0-3.8-.1-5.2-.3-5.8-1-8-3.7-8.6-4.9-.6-.8-.7-1.6-.5-2.2zm-49.7-17.2c0 .3-.3.5-.6.5s-.5-.3-.5-.6c0-.9.1-1.8.3-2.7 0-.2-.1-.3-.1-.5v-.1c0-.3-.1-.6-.1-.9v-.1-1-.1-1.1-.1c.2-3.2 1.2-7.3 4.2-11.8l.1-.1c.3-.5.7-1 1-1.5.8-2 1.5-3.3 1.5-3.5.1-.3.5-.4.7-.3.3.1.4.5.3.7-.1.4-6.3 13.7-6.8 23.2z" fill="url(#k)"/><path d="M37.2 63.9h.4c.8 0 1.6-.
1 2.4-.2h.4l2.4-.3c.1 0 .3 0 .4-.1.5-.1 1-.2 1.5-.2 13.5-2.6 20.6-6 23.1-7.5.1-.1.2-.1.4-.2.5-.3.7-.4.7-.5.1-.1.2-.1.3-.1 1.7-1 3.4-2 4.9-3.1-4.2-.1-7.5-1.9-7.7-2-.3-.1-.4-.5-.2-.8.1-.3.5-.4.8-.2 0 0 4.6 2.4 9.5 1.7 1.1-.2 2.2-.5 3.2-.8 6.7-2.1 12-6.3 14.5-11.6.2-.5.5-1.1.7-1.6.6-1.6.9-3.3.9-5.1 0-2.2-.5-4.2-1.3-6.2-.2-.5-.4-.9-.7-1.4l-.9-1.5c-.4-.6-.8-1.1-1.3-1.7-.4-.4-.8-.9-1.2-1.3l-.8-.8c.9 1.6 1.5 3.4 1.7 5.6.9 1.4 1.6 2.9 1.8 4.6 1.4 7.8-5.3 15.4-14.8 17.1-3.2.6-6.3.4-9-.4-6.2 3.4-14.2 5.7-22.1 6.6-16.5 1.9-29.8-1.4-28.8-13.1.8-8.9 9.4-22.1 19.5-29.1-.5.3-1.1.6-1.6.9-.8.5-1.6 1-2.4 1.6 0 0-2.4 1.2-7.7 7.7-.1.1-.3.2-.4.2-.1 0-.2 0-.4-.1l-.1-.1c-1 1.2-2 2.4-2.9 3.7-1.1 1.5-2.1 3.1-3.1 4.7-.8 1.4-1.5 2.8-2.2 4.3.2 0 .3 0 .5.1.3.2.3.5.1.8 0 0-2.2 3.2-3 6.3-.1.3-.1.6-.2.8 0 .1-.1.3-.1.4-.1.7-.3 1.4-.4 2.1-.1.7-.2 1.4-.2 2v.5c0 .7-.1 1.3 0 2 0 .6.1 1.2.1 1.8v.4c.1.6.2 1.1.3 1.7 0 .1 0 .1.1.2.1.5.3.9.4 1.4 0 .1.1.2.1.3.2.5.4.9.6 1.4 0 .1.1.2.1.3.2.4.4.8.7 1.1 0 .1.1.2.1.2.3.4.6.8.9 1.
1.1.1.1.2.2.2l.9.9.1.1 1.2.9c.1.1.2.1.3.2.4.3.8.5 1.3.8h.1c.4.2.9.4 1.3.7.1 0 .2.1.3.1l1.5.6c.1 0 .2.1.2.1.5.1.9.3 1.4.4.1 0 .2.1.3.1.6.1 1.1.2 1.7.3.1 0 .2 0 .4.1.5.1 1.1.2 1.6.2h.3c.6.1 1.2.1 1.9.1h2.4c1 .6 1.8.6 2.6.6z" fill="url(#l)"/><path d="M68.1 113.9c1.7-2.1 3.7-5.6 4.9-11.1 1.6-7-3-17.6-6.6-24.5-1-1.3-2-2.5-2.8-3.4-1.7.9-4.2 1.9-7.3 2.6.4.5.9 1.1 1.5 1.8 14.4 15.6 11.4 27.5 9.3 32-.1.3-.2.5-.4.7-.3.6-.6 1-.7 1.2-.2.2-.3.4-.5.6l-.1.1c-.1.2-.3.4-.4.7 1.1-.2 2.1-.4 3.1-.7z" fill="url(#m)"/><path d="M76.4 110.7c.2-.8.3-1.3.3-1.3 1.2-5.5.8-10.8-.6-15.7 1.7 6.5 1.4 12.4.3 17z" fill="url(#n)"/><path d="M30.7 86.9c-.3-.1-.6 0-.7.3-.1.2-.7 1.5-1.5 3.5-.4.5-.7 1-1 1.5l-.1.1c-3 4.5-4 8.6-4.2 11.8V106.5c0 .3.1.6.1.9v.1c0 .2 0 .3.1.5l-.3 2.7c0 .3.2.6.5.6s.5-.2.6-.5c.4-9.5 6.7-22.8 6.7-23 .2-.4.1-.8-.2-.9z" fill="url(#o)"/><path d="M32.7 105.7c-.2 0-.4-.1-.6-.2-.4-.3-.6-.8-.4-1.3l3.6-9.5-4.5-.6c-2.6 6.9-4.5 14.9-4.2 22.8.6 12.8 5.4 18.5 8.2 20.8 2.2 1.7 4.7 2.7 7 2.7.5 0 .9 0 1.4-.1 3-.
5 5.4-2.2 7.1-4.9 3-4.9 3.2-12.8.4-22.2-.3-1-.7-2.2-1.1-3.4-1.4-4.2-3.2-9.5-3.5-16l-12.5 11.6c-.4.2-.7.3-.9.3zM36.2 82.1c.2-.3.6-.6 1-.5l7.8.4c.4 0 .8.3 1 .6.2.4.1.8-.1 1.2l-3.9 5 4.1.2c.3-3.3 1-6.8 2.3-10.5-1.1 0-2.1-.1-3.2-.2-2.5-.2-4.5-.7-6-1.2-.9 1.4-1.9 3.2-3.1 5.3l.1-.3zM82.9 134.9c1.4.2 3.2.3 5.2.3 6.5 0 14.8-1.1 15.3-1.8.2-.2.2-.5.1-.8-.2-.4-.6-.4-.8-.4-13.2-.1-22.3-1.7-27.2-4.6-.5-.3-.8-.5-1.2-.3-.2.1-.4.3-.5.5-.2.5 0 1.3.4 2.2.7 1.1 2.9 3.9 8.7 4.9zM69.5 120.6h-.4l-1.9 1.2 1.3-.8c.2.1.5.2.8.2l-.6 1.4.8-2zM65.4 118.7c.1.2.2.4.4.6h.1c-.2-.3-.4-.4-.5-.6z" fill="#F9F9FA"/><path d="M57.3 112.5c-.8.5-1.2 1.4-1.4 2.2.1.1.1.2.1.3 0 0 0 2.2 1.6 2.8 1.2.5 5.3-.7 7.5-1.5h.3l.2-.1.4 1.2c.1.4.3.6.6 1l.9 1-1.1.7-1.4.9-.6.4-.6-.4c-.1-.1-.3-.2-.4-.3l-.2.1c-.4-.6-1.1-1.1-1.9-1.4-1.8-.5-3.8.5-4.3 2.3-.1.4-.1.8-.1 1.2.3 0 .5.1.6.4.4 1.5 1.1 2.5 3.3 2.5 2-.1 2.5-2.8 2.5-2.8 0-.2.1-.3.3-.4l4.5-2.8c.1 0 .1-.1.2-.1l.2-.1.3-.2h.6l1.9-.2-.8 1.8-.9 2.1-.5 1.1-1-.5-.4.9c-.9-.4-2.1-.4-3 .1-1.1.6-1.7
1.6-1.8 2.8.2 0 .5.2.5.5 0 .1.3 1.9 2.1 2.5h.5c.3.1.5.1.8.1h.3c.3-.1.6-.2.9-.4.6-.4 1-.9 1.3-1.3.3-.5.4-1 .4-1.1 0-.1 0-.3.1-.4v-.2l.3-.6c.4-1 1-2.3 1.4-3.1l2.7-6.2c0-.1.1-.2.1-.3v-.2-.3c1.1-2 1.8-4.2 2.2-5.6 1.1-4.7 1.4-10.5-.2-17-2.2-7.6-6.7-14.2-11.3-19.4-.3.2-.7.4-1.2.6.9 1 1.8 2.2 2.8 3.4 3.6 6.8 8.2 17.5 6.6 24.5-1.2 5.4-3.2 8.9-4.9 11.1-1 .2-2 .5-3 .7-.8.2-1.6.4-2.3.5 0-.5-.1-1.1-.4-1.6-.1-.3-.3-.5-.5-.7l-.2-.2c-.2-.1-.3-.3-.5-.4-.1 0-.1-.1-.2-.1-.2-.1-.5-.2-.7-.3h-.1c-.2-.1-.4-.1-.7-.1h-.3c-.2 0-.4 0-.5.1h-.2c-.3.1-.5.2-.7.3-.5 0-.6.1-.7.2zM64.4 123.5l1.7-1-1.7 1zM18.4 39.1c-1.1 11.7 12.3 15 28.8 13.1 7.9-.9 15.9-3.2 22.1-6.6 2.8.8 5.8 1 9 .4 9.5-1.7 16.1-9.3 14.8-17.1-.3-1.7-.9-3.2-1.8-4.6.2 2.6-.3 5.5-2 8.7-.1.2-.2.3-.4.4-2 4.2-6.7 7-12 6.6-4.3-.4-7.9-2.8-9.8-6.2-2.6-3.7-1.8-7.3-1.7-7.5.1-.3.4-.5.7-.4.3.1.5.4.4.7 0 .1-.4 1.5.1 3.5 1.7 4.1 5.3 7 10.3 7.2.1-.1.2-.1.4-.1.4 0 10.5-.3 11.6-9.9.7-6.3-2.5-10-5.2-12-1.8-1-3.8-1.6-6-1.6-1 0-1.8-.7-2.6-1.5h-.2c-5.5-3.8-12.5-6.3-20.1
-6.3-3.4 0-7 .5-10.6 1.6-2.1.6-4.1 1.5-6.1 2.6-10.3 6.9-18.9 20-19.7 29zM60 42c-.1 0-.2.1-.2.1-.2 0-.4-.1-.5-.3-2.6-5.6-.5-10.6-.4-10.8.1-.3.4-.4.7-.3.3.1.4.5.3.7 0 0-2 4.7.4 9.9.1.2 0 .6-.3.7zm25.3-12.3c.3.5.2 1.2-.3 1.5-.2.1-.4.2-.6.2-.4 0-.7-.2-.9-.5 0-.1-1.1-1.6-3.2-1.6s-3.2 1.6-3.2 1.6c-.3.5-1 .7-1.5.3-.5-.3-.7-1-.3-1.5.1-.1 1.8-2.7 5.1-2.7 3.2.1 4.9 2.6 4.9 2.7zm-17.2-.9h-.2c-.2 0-.5-.1-.5-.4l-.1-.3c-.1-.3.1-.6.4-.7.3-.1.6.1.7.4l.1.3c.1.3-.1.6-.4.7zm5.6 6.2h-.1c-.1 0-2.9-.6-5.1-4.3-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2 2 3.3 4.4 3.8 4.4 3.8.3.1.5.3.4.6-.1.4-.3.5-.6.5zm8.1-12.2l-.1 3.5v.3c-.4-.1-.9-.2-1.4-.2-.6 0-1.1.1-1.6.2 0-.1-.1-.3 0-.4l.1-3.5c0-.9.7-1.5 1.6-1.5.7 0 1.4.7 1.4 1.6zM72.7 14c.1.3 0 .6-.3.7 0 0-2.4.9-3.6 3.3-.1.2-.3.3-.5.3-.1 0-.2 0-.2-.1-.3-.1-.4-.5-.2-.7 1.4-2.8 4.1-3.8 4.2-3.9.2-.1.5.1.6.4zM23.4 111.2c-1-.3-2-.6-2.9-.8-.8-1.5-2-4.7-2.1-9.3-.1-3.7 1.3-8.5 2.6-12.2 2.4-3.8 5.2-6.6 5.2-6.6.3-.3.3-.7 0-1-.3-.3-.7-.3-1 0-.1.1-1 .9-2.1 2.3.1-.1.1-.2.1-.2-4.4 5.1-7.1 10.6
-8.2 16.4-1 5.3-.2 9.7.6 12.4-.1.1-.1.2-.2.3v.1c0 .1-.1.1-.1.2v.4c0 .1 0 .2.1.3l3.9 10.1v1.3c.1 1 .7 1.9 1.6 2.5.2.1.5.2.7.3h.1c.2.1.5.1.7.1H23.3c-.4-2.2-.5-4.5-.5-6.6-.1 0-.2-.1-.2-.2l-.1-.1c-.3 0-.7.1-1 .2l-1-2.7-1-1.2c-.2-.2-.2-.6.1-.8.2-.2.6-.2.8.1l1.1 1.3 1.4 1c.1-1.2.1-2.3.2-3.3-1.6-.9-3.3-2-3.6-2.1-.3-.1-.4-.4-.3-.6v-.1c.1-.3.4-.4.7-.3.2.1 1 .5 1.9 1.1.4.1.9.3 1.4.4-.1-.9 0-1.9.2-2.7z" fill="#F9F9FA"/><path d="M64.4 121.4l.6-.4 1.4-.9 1.1-.7-.9-1c-.4-.4-.5-.6-.6-1l-.4-1.2-.2.1h-.3c-2.2.8-6.3 2-7.5 1.5-1.6-.6-1.6-2.8-1.6-2.8 0-.1-.1-.3-.1-.3-.1-.1-.2-.2-.4-.2-.3 0-.6.2-.6.6 0 .1 0 3 2.3 3.9.3.1.7.2 1.2.2.8 0 1.7-.1 2.6-.3l.9.7c.3.2.5.4.7.6.2.2.5.4.8.7.1.1.2.2.4.3l.6.2zm1.4-2.1l-1.3.8c-.9-.6-1.1-.9-1.9-1.5.9-.2 1.6-.3 2.4-.7.1.4.2.6.4.9.1.1.3.2.4.5z" fill="url(#p)"/><path d="M69.6 123.1l.9-2.1.8-1.8-1.9.2h-.6l-.3.2-.2.1c-.1 0-.1 0-.2.1l-4.5 2.8c-.1.1-.2.2-.3.4 0 0-.4 2.8-2.5 2.8-2.2 0-2.9-1-3.3-2.5-.1-.3-.3-.4-.6-.4h-.1c-.3.1-.5.4-.4.7.4 1.4 1.3 3.3 4.2 3.3h.2c2.2-.1 3.2-2.2 3.
5-3.5l1.6-1 .5.3.4.2c.4.2.7.4 1.1.6l.1.1 1 .5.6-1zm-1-.4c-.2-.1-.4-.2-.6-.4-.3-.2-.6-.3-.8-.5l1.9-1.2h.4l-.9 2.1z" fill="url(#q)"/><path d="M78.7 22.7l-.1 3.5v.4c.5-.1 1-.2 1.6-.2.5 0 .9.1 1.4.2v-.3l.1-3.5c0-.9-.7-1.6-1.5-1.6-.8-.1-1.5.6-1.5 1.5z" fill="url(#r)"/><path d="M80.2 27.1c-3.4 0-5 2.5-5.1 2.7-.3.5-.2 1.2.3 1.5.5.3 1.2.2 1.5-.3 0 0 1.1-1.6 3.2-1.6s3.2 1.6 3.2 1.6c.2.3.6.5.9.5.2 0 .4-.1.6-.2.5-.3.7-1 .3-1.5.2-.2-1.5-2.7-4.9-2.7z" fill="url(#s)"/><path d="M67.8 17.5c-.1.3 0 .6.2.7.1 0 .2.1.2.1.2 0 .4-.1.5-.3 1.2-2.4 3.6-3.3 3.6-3.3.3-.1.4-.4.3-.7-.1-.3-.4-.4-.7-.3 0 0-2.7 1-4.1 3.8z" fill="url(#t)"/><path d="M59.9 31.3c.1-.3 0-.6-.3-.7-.3-.1-.6 0-.7.3-.1.2-2.2 5.2.4 10.8.1.2.3.3.5.3.1 0 .2 0 .2-.1.3-.1.4-.5.3-.7-2.4-5.1-.4-9.8-.4-9.9z" fill="url(#u)"/><path d="M73.8 33.9s-2.4-.5-4.4-3.8c-.2-.3-.5-.3-.8-.2-.3.2-.4.5-.2.8 2.3 3.8 5 4.3 5.1 4.3h.1c.3 0 .5-.2.5-.5.2-.2 0-.5-.3-.6z" fill="url(#v)"/><path d="M68.5 28.1l-.1-.3c-.1-.3-.4-.4-.7-.4-.3.1-.4.4-.4.7l.1.3c.1.2.3.4.5.4h.2c
.3-.1.5-.4.4-.7z" fill="url(#w)"/><path d="M65 71.5s0-1.4-.4-2.6c0-.2-.1-.3-.2-.4-1.4.6-6.2 2.4-15.4 3.3-6.1.6-9.9-.8-11.5-1.6l-1.9 1.7s1.1 3.3 9.7 4.1c1.1.1 2.2.1 3.2.1 10.4 0 16.5-4.6 16.5-4.6z" fill="url(#x)"/><path d="M49 71.8c9.2-.9 14-2.7 15.4-3.3-.5-.9-1.7-1.4-1.7-1.4s-7.8 2.6-14.5 3c-.7 0-1.4.1-2.1.1-5.2 0-7.2-1.2-7.2-1.2l-1.4 1.3c1.6.7 5.4 2.1 11.5 1.5z" fill="#FFF"/><path d="M47.9 83.5c.3-.3.3-.8.1-1.2-.2-.4-.5-.6-1-.6l-7.8-.4c-.4 0-.8.2-1 .5l-.1.2-6.2 10.2c-.2.3-.2.7-.1 1.1.2.3.5.6.8.6l4.5.6-3.6 9.5c-.2.5 0 1 .4 1.3.2.1.4.2.6.2.3 0 .5-.1.8-.3l12.5-11.6 3.1-2.9c.3-.3.4-.8.3-1.2-.2-.4-.5-.7-1-.7l-2.3-.1-4.1-.2 4.1-5z" fill="url(#y)"/><path d="M77.3 148.2c-.5 1.6-2.3 2.8-5.6 3.7-3.5.9-6 .8-7.5-.3-.2-.2-.4-.3-.6-.5-1.1.7-1.6 1.7-1.3 2.4.5 1.4 3.5 2.3 9.2.9 8.2-2 9.3-4.8 9.5-5.6.1-.8-.2-1.2-.3-1.3-.5-.3-1.9-.5-3.2-.4-.1.3-.1.7-.2 1.1z" fill="#FFF"/><path d="M75.7 144.9c-.1 0-.2 0-.2.1-.4-.9-.8-1.9-1.4-3 1.3.1 2.7.1 4.1.1 13.4 0 28.1-4.3 30.4-7.7.6-.8.7-1.8.3-2.7-1.1-2.7-4.3-2.
9-9.2-3.2-5.7-.4-14.2-.9-24.5-5.2-.4-.2-.8-.3-1.1-.5 0-.1 0-.1.1-.2 0-.1.1-.2.1-.3l1.9-4.4c.2-.4.3-.9.3-1.3.5-1 .9-2 1.2-2.9.5 0 1 .1 1.5.1.7 0 1.3 0 1.8-.1s1-.2 1.3-.4c2.4-1.3 4.4-1.4 7.6-1.4 1.7 0 3.8-.1 6.5-.3 7.8-.8 12.9-6.6 12.9-10 .2-.9 3.9-3.5 6.1-5.1 4.5-3.2 6.8-4.9 6.5-6.6-.3-1.8-2.7-1.9-11.1-1.9-7.8-.1-18.4-.1-24.5-2.6-4.7-1.9-8.9-5-12.2-7.9-4-3.5-6.6-6.6-6.7-6.6 0-.1-.1-.1-.2-.1 0-.6-.2-1.5-.4-2.4-.3-1.1-1.1-1.9-1.7-2.4 1.3-2.8 2.8-5.7 4.4-8.6 2.5-1.4 4.9-2.8 7-4.4C89.2 50.6 98 41.8 98 31.6c0-10.4-9.4-19.4-22.3-21.6-6.1-4.1-13.5-6.4-20.9-6.4-3.8 0-7.6.6-11.3 1.7-3.4 1.1-6.8 2.7-10.1 4.9-.6-.1-1.2-.1-1.8-.1h-1.2c-2 0-4.1.2-6.1.6-1.6-.6-3.3-.9-5-.9-1.4 0-2.9.2-4.3.7-7.5 2.4-11.7 10.4-9.3 17.9.3 1 .7 1.9 1.3 2.9.8 3.2 2.8 6.1 5.7 8.5-.7 2.9-1 5.7-1 8.4.2 11.8 8.5 18.3 23.3 18.3 1.9 0 3.8-.1 5.9-.3-.3.3-.5.7-.7 1-.3-.1-.6-.2-.9-.2-.5 0-1.1.2-1.5.6l-3.3 3c-.3.3-.6.7-.7 1.1C22 79.9 15.1 89.3 13.2 99.8c-1 5.2-.4 9.6.4 12.6-.3.8-.3 1.7 0 2.5l3.7 9.6c-.2 2.1.8 4.2 2.7 5.4.8.5 1.7.
8 2.7.8.9 3 2.1 5.6 3.7 7.8.6 3.6 1.2 6.5 1.9 8.9-1.4.4-2.5 1.3-3.1 2.3-.4.7-.6 1.5-.5 2.3.1.4.3 1.2.9 1.9 3.4 5.5 7 11.8 7.1 12.9 0 .4-.2 1.1-.3 1.9-.5 2.4-1.1 5.5-.3 7.3.4 1.1 1.8 1.6 3.8 1.6h.5c3.2-.1 8.6-1.8 9.9-6 1.4-4.1 1.2-15.5 1.1-20.3v-1.2-.9-.1-.1c0-.1 0-.2-.1-.3v-.1c-.1-.3-.2-.6-.4-.8.8 0 1.6.1 2.4.1 3.7 0 7.5-.5 11.2-1.5.9 1.1 1.7 2.1 2.4 3.1-1.2.8-2 1.8-2.3 2.9-.2.7-.2 1.4 0 2.1 0 .1-.1.1-.1.2-.1.4 0 .8.2 1 4.2 5.2 8.7 11.3 9 12.4 0 .4-.1 1.1-.2 1.9-.3 2.5-.7 5.6.3 7.3.6 1.1 2.1 1.4 3.5 1.4.6 0 1.1-.1 1.6-.1 4-.5 8.5-2.8 9.5-6.5.7-2.6.5-8 .2-12.9.9-.5 1.8-1.3 2.2-2.4 1.6-4.2 0-7.3 0-7.4-.1-.2-.3-.3-.5-.3s-.4.1-.5.3c-.4.9-1 2.3-1.8 3.3-.2-1.9-.4-3.1-.4-3.3.2-1.6-.5-2.8-1.3-3.3l-.6-.3c-2.3-1.2-5.3-.9-6-.9zm5.7 13.8c-.3.1-.5.4-.4.7.1.3.4.5.7.4 0 0 .1 0 .3-.1.3 4.5.4 9.2-.2 11.4-.5 1.9-2.6 3.5-5.6 4.4-2.6.8-4.6.6-4.9.3-.6-1.1-.3-4.1 0-5.9.1-.6.1-1.1.2-1.5.7.2 1.3.3 1.9.3 1.7 0 2.8-.7 2.9-.8.3-.2.3-.5.2-.8-.2-.3-.5-.3-.8-.2 0 0-1.8 1.1-4.3.2-.6-1.8-3.6-6-6.8-10 .6.1 1.2.1 1.
9.1 1.5 0 3.3-.2 5.6-.8 4.9-1.2 7.7-2.7 9.3-4.2 0 .4.1.9.2 1.5-1.2.4-2.8.9-3.4 2.8-.7 2.4.8 4.1.9 4.2.1.1.3.2.4.2.1 0 .3 0 .4-.1.2-.2.2-.6 0-.8 0-.1-1.2-1.3-.6-3.1.4-1.4 1.6-1.8 2.8-2.1.2-.1.3-.1.5-.2 0 .1 0 .1.1.2.1.2.3.3.5.3.1 0 .2 0 .3-.1.6-.4 2.5-1.6 2.6-2.8 0-.3-.2-.6-.5-.6h-.1c.2-.3.3-.6.5-.9.3 1.2.4 3-.4 5.2-1.1 2-4.2 2.8-4.2 2.8zm-.8-11.2c.1.1.5.5.3 1.3-.1.8-1.2 3.6-9.5 5.6-5.7 1.4-8.7.5-9.2-.9-.2-.7.2-1.7 1.3-2.4.2.2.3.3.6.5 1.5 1 4 1.1 7.5.3 3.3-.8 5.1-2 5.6-3.7.1-.4.1-.8.1-1.1 1.4 0 2.8.1 3.3.4zM69.1 76c3.5 3.5 9.4 8.6 16.3 11.4 6.5 2.7 17.4 2.8 25.4 2.8 3.4 0 7.1 0 8.6.3-.9 1-3.5 2.9-5.3 4.2-2.7 1.9-4.7 3.3-5.8 4.6-9.9 1.2-15.8-1.2-15.9-1.2-.3-.1-.6 0-.7.3-.1.3 0 .6.3.7.2.1 4 1.6 10.8 1.6 1.4 0 3-.1 4.6-.2-.2.4-.3.7-.3 1.1 0 2.1-4.1 7.1-10.9 7.8-2.6.3-4.5.3-6.3.3-3.3.1-5.7.1-8.6 1.7-.5.3-1.5.4-2.8.3.3-1.1.5-1.8.5-1.8 1.7-8.1 1.1-20.1-9.9-33.9zM44.8 64.2c11.7-2.2 18.6-5 22-6.8-1.2 2.2-2.5 4.8-3.8 7.5h-.3c-.2 0-.5 0-.7.1-.1 0-7.6 2.5-13.9 2.9-.7 0-1.3.1-2 .1-1.7 0-3-.1-4-.
3.9-1.3 1.8-2.4 2.7-3.5zm3.7 11.9c-1 0-2.1 0-3.2-.1-8.5-.8-9.7-4.1-9.7-4.1l1.9-1.7 1.4-1.3s2.1 1.2 7.2 1.2c.6 0 1.3 0 2.1-.1 6.7-.4 14.5-3 14.5-3s1.1.5 1.7 1.4c.1.1.1.3.2.4.4 1.2.4 2.6.4 2.6s-6.1 4.7-16.5 4.7zM34.7 63.9h-2.3c-.6 0-1.3-.1-1.9-.1h-.3c-.5-.1-1.1-.1-1.6-.2-.1 0-.2 0-.4-.1-.6-.1-1.1-.2-1.7-.3-.1 0-.2-.1-.3-.1-.5-.1-1-.3-1.4-.4-.1 0-.2 0-.2-.1l-1.5-.6c-.1 0-.2-.1-.3-.1-.5-.2-.9-.4-1.3-.7h-.1c-.4-.2-.9-.5-1.3-.8-.1-.1-.2-.1-.3-.2l-1.2-.9-.1-.1-.9-.9c-.1-.1-.1-.2-.2-.2-.3-.4-.6-.7-.9-1.1-.1-.1-.1-.2-.1-.2-.2-.4-.5-.7-.7-1.1 0-.1-.1-.2-.1-.3-.2-.4-.4-.9-.6-1.4 0-.1-.1-.2-.1-.3-.2-.5-.3-.9-.4-1.4 0-.1 0-.1-.1-.2-.1-.5-.2-1.1-.3-1.7V50c-.1-.6-.1-1.2-.1-1.8v-2-.5c0-.7.1-1.3.2-2s.2-1.4.4-2.1c0-.1.1-.3.1-.4.1-.3.1-.6.2-.8.8-3.1 3-6.2 3-6.3.2-.3.1-.6-.1-.8-.1-.1-.3-.1-.5-.1-.1 0-.2.1-.3.2 0 .1-.7 1-1.4 2.3-.4.8-.9 1.7-1.3 2.7 0 0-.1 0-.1-.1l-.3-.3c-.3-.2-.5-.5-.8-.7l-.3-.3c-.2-.3-.5-.5-.7-.8-.5-.5-.9-1.1-1.2-1.7-.1-.2-.2-.4-.3-.5-.1-.2-.3-.5-.4-.7l-.3-.6c-.1-.2-.2-.5-.3-.7-.1-.2-.
2-.5-.2-.7-.1-.2-.1-.4-.2-.7-.2-.4-.5-.8-.6-1.2 0 0 0-.1-.1-.1-.2-.4-.4-.9-.5-1.3-.5-1.6-.6-3.1-.5-4.7.1-1.2.4-2.4.8-3.5.7-1.8 1.9-3.4 3.4-4.7.6-.5 1.2-1 1.9-1.3.7-.4 1.4-.7 2.2-1 .4-.1.7-.2 1.1-.3.1 0 .2 0 .3-.1.2 0 .5-.1.7-.1H19.4c1.7 0 3.3.4 4.8 1l1.5-.3h.2c.7-.1 1.4-.2 2.1-.2.4 0 .7-.1 1.1-.1h2.5c.2 0 .5 0 .7.1-.8.7-2.1 1.8-3.9 3.7-.9.9-1.8 2.1-3 3.4-.2.2-.2.5 0 .7l.1.1c.1.1.2.1.4.1s.3-.1.4-.2c5.3-6.5 7.6-7.7 7.7-7.7.8-.6 1.6-1.1 2.4-1.6.5-.3 1.1-.6 1.6-.9 2-1.1 4-2 6.1-2.6 3.6-1.1 7.2-1.6 10.6-1.6 7.6 0 14.5 2.4 20.1 6.3h.2c2.1.3 4.1.9 6 1.6.6.3 1.6.8 2.6 1.6 2.7 2 5.9 5.7 5.2 12-1.1 9.6-11.2 9.9-11.6 9.9-.1 0-.3.1-.4.1-5-.2-8.6-3.1-10.3-7.2-.5-1.9-.1-3.3-.1-3.5.1-.3-.1-.6-.4-.7-.3-.1-.6.1-.7.4 0 .2-.9 3.8 1.7 7.5 1.8 3.4 5.5 5.9 9.8 6.2 5.3.4 10-2.3 12-6.6.2-.1.3-.2.4-.4 1.7-3.3 2.2-6.2 2-8.7-.2-2.1-.8-4-1.7-5.6l.8.8c.4.4.8.9 1.2 1.3.5.5.9 1.1 1.3 1.7l.9 1.5c.2.4.5.9.7 1.4.8 1.9 1.3 4 1.3 6.2 0 1.8-.3 3.5-.9 5.1-.2.5-.4 1.1-.7 1.6-2.5 5.2-7.7 9.4-14.5 11.6-1 .3-2.1.6-3.2.8-4.9
.7-9.5-1.7-9.5-1.7-.3-.1-.6 0-.8.2-.1.3 0 .6.2.8.2.1 3.5 1.8 7.7 2-1.6 1.1-3.2 2.1-4.9 3.1-.1 0-.2 0-.3.1 0 0-.2.2-.7.5-.1.1-.2.1-.4.2-2.5 1.4-9.6 4.9-23.1 7.5-.5.1-1 .2-1.5.2-.1 0-.3 0-.4.1l-2.4.3h-.4c-.8.1-1.6.1-2.4.2h-.4c-.8 0-1.6.1-2.4.1v-.8zm9.2 106.6c-.9 2.8-4.7 3.9-5.8 4.2-2.5.6-4 .2-4.2 0-.5-1.2.1-4.2.4-6l.3-1.5c.8.3 1.5.4 2.1.4 1.4 0 2.3-.5 2.3-.6.3-.2.3-.5.2-.8-.2-.3-.5-.3-.8-.2 0 0-1.7 1-3.8-.1-.4-1.9-3.1-6.6-5.5-10.6 1.1.2 2.4.4 4 .4.6 0 1.2 0 1.9-.1 5.1-.3 8.1-1.4 9.8-2.7.2 5.6.1 14.4-.9 17.6zm.7-21.7c.1.1.3.6.1 1.2-.3.7-1.8 3.2-9.8 3.7-5.5.4-8.2-1-8.4-2.3-.1-.7.5-1.5 1.6-2 .1.2.3.4.4.6 1.2 1.2 3.6 1.8 7 1.5 3.2-.2 5.2-1 5.9-2.5.2-.3.3-.7.3-1 1.3.1 2.5.4 2.9.8zm16.2-5.3l-1.2.3c-.1 0-.3.1-.4.1-.3.1-.6.2-.9.2-.2 0-.3.1-.5.1-.3.1-.6.1-.9.2-.2 0-.3.1-.5.1-.3.1-.6.1-1 .2-.1 0-.3.1-.4.1-.4.1-.8.1-1.1.2h-.3c-1 .1-2 .2-3.1.3H49h-.1-.1c-1.5 0-3.1-.1-4.7-.3h-.2c-.8-.1-1.6-.2-2.4-.4h-.2l-2.4-.6v.1c-3.9-1.1-5.3-2.6-5.4-2.6-.2-.2-.6-.2-.8 0-.2.2-.2.6 0 .8.1.1 1.8 1.8 6.2 3v.1c0 1 .1
2 .1 3-.5.3-1.6.7-3.6.8-2.5.2-3.9-.1-4.7-.5-.9-2.6-1.7-6.2-2.3-9.8v-.1c-.1-.3-.1-.6-.2-1 0-.2-.1-.4-.1-.6-.9-1.2-1.7-2.5-2.3-3.9 0-.1-.1-.1-.1-.2-.3-.6-.5-1.2-.7-1.8-2.5-7.9-.5-19.1-.5-19.2.1-.3-.1-.6-.5-.6-.3-.1-.6.1-.6.5 0 .1-.2 1.1-.4 2.7-.5-.3-1-.6-1.4-.8-.9-.6-1.7-1-1.9-1.1-.3-.1-.6.1-.7.3v.1c-.1.3.1.5.3.6.2.1 2 1.1 3.6 2.1-.1 1-.2 2.1-.2 3.3v.7l-1.4-1.7-1.1-1.3c-.2-.2-.5-.3-.8-.1-.2.2-.3.5-.1.8l1 1.2 2 2.5.1.1.2.2c0 2.1.1 4.4.5 6.6h-.8-.1c-.2 0-.5-.1-.7-.1h-.1c-.2-.1-.5-.2-.7-.3-.9-.6-1.5-1.5-1.6-2.5v-.1-.5-.1-.3-.3l-3.9-10.1c0-.1-.1-.2-.1-.3v-.1-.2-.1c0-.1 0-.1.1-.2v-.1c.1-.1.1-.2.2-.3-.8-2.8-1.5-7.1-.6-12.4 1.1-5.8 3.8-11.3 8.2-16.4 2.9-3.4 6.5-6.6 10.9-9.7.7 1 2.1 2.3 5 3.3 1.5.5 3.5 1 6 1.2 1.1.1 2.2.1 3.2.2h.2c2.4 0 4.6-.2 6.5-.6.4.5 1.1 1.2 2 2.4-2.7 9.6-2.5 18.7-1 26.8v.1c.1.6.2 1.2.4 1.8 0 .2.1.4.1.6.1.4.2.9.3 1.3.1.3.1.5.2.8.1.3.2.6.2.9.1-.1.2-.2.3-.2.2-.1.5-.2.7-.3h.2c.2 0 .4-.1.5-.1h.2c.2 0 .5 0 .7.1h.1c.3.1.5.2.7.3.1 0 .1.1.2.1.2.1.3.2.5.4l.2.2c.2.2.4.4.5.7.3.5.4
1 .4 1.6.7-.2 1.5-.4 2.3-.5.1-.2.2-.5.4-.7 0-.1.1-.1.1-.1.1-.2.3-.4.5-.6.1-.2.4-.6.7-1.2.1-.2.2-.5.4-.7 2.1-4.5 5.1-16.4-9.3-32-.6-.8-1.1-1.4-1.5-1.8 3.1-.7 5.6-1.7 7.3-2.6.5-.2.9-.4 1.2-.6 4.6 5.2 9.2 11.8 11.3 19.4 1.4 4.9 1.8 10.2.6 15.7 0 0-.1.5-.3 1.3-.4 1.4-1.1 3.6-2.2 5.6v.5c0 .1 0 .2-.1.3l-2.7 6.2c-.4.8-1 2.1-1.4 3.1-.1.3-.2.6-.3.8 0 .2-.1.3-.1.4 0 .1-.1.6-.4 1.1-.3.4-.7.9-1.3 1.3-.3.2-.6.3-.9.4h-.3c-.3 0-.5 0-.8-.1-.2-.1-.3-.1-.5 0-1.8-.6-2.1-2.4-2.1-2.5 0-.3-.2-.4-.5-.5h-.1c-.3 0-.5.3-.5.6.1.8.7 2.4 2.3 3.2-.1.5.2 1.1.7 1.3.5.2 1 .3 1.5.3.8 0 1.7-.2 2.5-.7 1.5-.9 2.6-2.6 2.7-3.6.1-.4.6-1.9 1.3-3.5.4.2.8.3 1.2.5 8.5 3.5 15.9 4.6 21.4 5.1h.2c6.3.5 10.2.3 10.9 2.1V133.5c0 .1 0 .1-.1.2 0 0 0 .1-.1.1 0 .1-.1.1-.1.2l-.1.1-.2.2-.1.1c-.1.1-.2.2-.3.2 0 0-.1 0-.1.1-.2.1-.3.2-.5.3-.1 0-.1.1-.2.1-.1.1-.3.2-.4.2-.1 0-.2.1-.2.1-.1.1-.3.1-.4.2-.1 0-.2.1-.3.1-.2.1-.3.1-.5.2-.1 0-.2.1-.3.1-.2.1-.4.2-.6.2-.1 0-.2.1-.2.1l-.9.3c-.1 0-.1 0-.2.1-.3.1-.5.2-.8.3-.1 0-.2.1-.4.1-.2.1-.5.1-.7.2-.1 0
-.3.1-.4.1-.2.1-.5.1-.7.2-.1 0-.3.1-.4.1-.3.1-.5.1-.8.2-.1 0-.3.1-.4.1l-1.2.3h-.1l-1.2.3c-.1 0-.3.1-.4.1-.3.1-.6.1-.9.2-.2 0-.3.1-.5.1-.3.1-.6.1-.9.2-.2 0-.4.1-.5.1-.3.1-.6.1-.9.1-.2 0-.3.1-.5.1-.4.1-.8.1-1.1.2h-.3c-.5.1-1 .1-1.4.2h-.4c-.3 0-.7.1-1 .1h-.5c-.3 0-.6.1-1 .1h-.6c-.3 0-.6 0-1 .1h-6c-.5 0-.9 0-1.4-.1h-.6c-.4 0-.9-.1-1.3-.1-.2 0-.4 0-.6-.1-.2 0-.4-.1-.6-.1-1.5-2.5-2.6-4.3-2.6-4.3-.2-.3-.5-.4-.8-.2-.3.2-.4.5-.2.8 0 0 1.6 2.7 3.7 6.1.9 1.7 1.7 3.3 2.2 4.7l.6 1.8c-.6.4-1.6.9-3.3 1.3-2.8.7-4.4.6-5.3.3-1.4-2.6-3.1-4.9-4.6-6.8zm3.7-32c-.1.1-.1.2-.2.3l-.3.3c-.2-.3-.5-.6-.7-.9l1.2.3zm1-2c-2.4-.6-4.8-1.2-7-1.8-1.7-8.3-1.7-16.4 0-24.2 10.1 12.4 8.6 21.7 7 26z" fill="url(#z)"/><path d="M35 155.9c-.7 0-1.3.1-1.9.1-1.6 0-3-.2-4-.4 2.4 4 5 8.7 5.5 10.6 2.2 1.1 3.8.1 3.8.1.3-.2.6-.1.8.2.2.3.1.6-.2.8-.1 0-1 .6-2.3.6-.6 0-1.3-.1-2.1-.4-.1.4-.2.9-.3 1.5-.3 1.8-.9 4.8-.4 6 .2.2 1.8.5 4.2 0 1.1-.3 4.8-1.3 5.8-4.2 1.1-3.2 1.1-12 1-17.3-1.8 1-4.7 2-9.9 2.4z" fill="url(#A)"/><path d="M41.5 148.8
c-.8 1.5-2.7 2.3-5.9 2.5-3.4.2-5.8-.3-7-1.5-.2-.2-.3-.4-.4-.6-1.1.5-1.7 1.3-1.6 2 .2 1.4 2.9 2.7 8.4 2.3 8-.5 9.5-2.9 9.8-3.7.2-.6 0-1.1-.1-1.2-.4-.4-1.6-.7-2.8-.9-.1.5-.2.8-.4 1.1z" fill="#FFF"/><path d="M85.3 156c.8-2.2.7-4.1.4-5.2-.1.3-.3.6-.5.9h.1c.3 0 .5.3.5.6-.2 1.1-2.1 2.4-2.6 2.8-.1.1-.2.1-.3.1-.2 0-.4-.1-.5-.3 0-.1-.1-.1-.1-.2-.2.1-.3.1-.5.2-1.1.4-2.3.7-2.8 2.1-.6 1.7.6 3 .6 3.1.2.2.2.6 0 .8-.1.1-.2.1-.4.1s-.3-.1-.4-.2c-.1-.1-1.6-1.8-.9-4.2.6-1.9 2.2-2.4 3.4-2.8-.1-.5-.1-1-.2-1.5-1.6 1.5-4.4 3-9.3 4.2-2.3.6-4.1.8-5.6.8-.7 0-1.3-.1-1.9-.1 3.2 4.1 6.2 8.2 6.8 10 2.5 1 4.3-.2 4.3-.2.3-.2.6-.1.8.2.2.3.1.6-.2.8-.1 0-1.2.8-2.9.8-.6 0-1.2-.1-1.9-.3 0 .4-.1 1-.2 1.5-.2 1.8-.6 4.8 0 5.9.3.3 2.3.5 4.9-.3 3-.9 5.1-2.6 5.6-4.4.6-2.2.5-6.9.2-11.4-.2 0-.3.1-.3.1-.3.1-.6-.1-.7-.4-.1-.3.1-.6.4-.7.3-.1 3.4-.9 4.2-2.8z" fill="url(#B)"/></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/figure_private.svg b/browser/extensions/onboarding/content/img/figure_private.svg
new file mode 100644
index 000000000000..f90163e4b4d7
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_private.svg
@@ -0,0 +1 @@
+<svg width="289" height="237" viewBox="0 0 289 237" xmlns="http://www.w3.org/2000/svg"><title>private-browsing</title><defs><linearGradient x1="12.376%" y1="17.359%" x2="82.943%" y2="91.352%" id="a"><stop stop-color="#E60024" offset="0%"/><stop stop-color="#ED00B5" offset="51.53%"/><stop stop-color="#8000D7" offset="100%"/></linearGradient><linearGradient x1="-3.914%" y1=".14%" x2="98.417%" y2="106.522%" id="b"><stop stop-color="#E60024" offset="0%"/><stop stop-color="#ED00B5" offset="51.53%"/><stop stop-color="#8000D7" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M-30-29h352v303H-30z"/><g fill-rule="nonzero"><g><ellipse fill="#EDEDF0" cx="226.9" cy="229.8" rx="54.2" ry="6.7"/><g fill="#D7D7DB"><path d="M195.6 79.5h-76.5c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h76.5c.6 0 1.1.5 1.1 1.1 0 .6-.4 1.1-1.1 1.1zM148.7 73.8h-19.2c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h19.2c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zM260.7 84.5h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0
.6.2.6.6 0 .4-.3.6-.6.6zm-5.6 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-12.3 0h-13.4c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-23.4 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5.6 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-12.3 0h-13.4c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zm-23.4 0H177c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5.6 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-12.2 0h-13.4c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6z"/></g><g transform="translate(171 26)"><path d="M31.5 4.5c0 .1 0 .1-.1.2l-3.7.6-2.3.4c-.1 0-.1 0-.2-.1l-.7-4.2c0-.1 0-.1.1-.2l6-.9c.1 0 .1 0 .2.1l.7 4.1z" fill="#D7D7DB"/><path d="M35 26.7L5.2 31.4c-.8.1-1.5-.4-1.7-1.2L.2 9.2c-.1-.8.4-1.5 1.2-1.7l29.8-4.7c.8-.1 1.5.4 1.7 1.2l3.3 21c.1.8-.4 1.5-1.2 1.7z" fill="#D7D7DB"/><path d="
M32.1 9.4s-.1.1 0 0l-4.8.8h-.1l-.3-1.9s0-.1.1-.1l4.7-.7h.1l.3 1.9z" fill="#F9F9FA"/><circle transform="rotate(-8.946 119.14 -7.38)" cx="2.592" cy="2.794" r="1.7" fill="#F9F9FA"/><circle transform="rotate(-8.946 52.95 -31.036)" cx="11.1" cy="10.705" r="9.3" fill="#F9F9FA"/><path d="M17.2 10.9c-3.2.5-5.4 3.5-4.9 6.7s3.5 5.4 6.7 4.9 5.4-3.5 4.9-6.7c-.5-3.3-3.5-5.4-6.7-4.9z" fill="#D7D7DB"/><circle fill="#F9F9FA" transform="rotate(-8.946 19.487 14.795)" cx="19.487" cy="14.795" r="1.1"/></g><g transform="translate(46)"><path d="M30.4 4.8c0 .1 0 .1-.1.1l-3.6.3-2.2.2c-.1 0-.1 0-.1-.1L24 1.2c0-.1 0-.1.1-.1l5.8-.5c.1 0 .1 0 .1.1l.4 4.1z" fill="#D7D7DB"/><path d="M32.3 26.2L3.5 28.7c-.8.1-1.4-.5-1.5-1.3L.2 7.1c-.1-.8.5-1.4 1.3-1.5l28.8-2.5c.8-.1 1.4.5 1.5 1.3l1.8 20.3c0 .7-.6 1.4-1.3 1.5z" fill="#D7D7DB"/><path d="M30.6 9.4c0 .1 0 .1 0 0l-4.7.5c-.1 0-.1 0-.1-.1l-.2-1.9s0-.1.1-.1l4.6-.4c.1 0 .1 0 .1.1l.2 1.9z" fill="#F9F9FA"/><circle transform="rotate(-4.97 187.782 -12.435)" cx="2.497" cy="2.6
01" r="1.7" fill="#E1E1E6"/><circle transform="rotate(-4.97 70.888 -67.624)" cx="9.799" cy="10.501" r="8.9" fill="#F9F9FA"/><path d="M16.3 9.9c-3.1.3-5.4 3-5.1 6.1.3 3.1 3 5.4 6.1 5.1 3.1-.3 5.4-3 5.1-6.1-.3-3.1-3-5.4-6.1-5.1z" fill="#D7D7DB"/><circle fill="#F9F9FA" transform="rotate(-4.97 18.195 13.8)" cx="18.195" cy="13.8" r="1"/></g><path d="M170.8 55.2h24.5s-7.7-17.2 8.6-19.4c14.5-2 20.3 13 20.3 13s1.7-8.6 10.4-7c8.5 1.6 14.8 15.3 14.8 15.3h21.4" fill="#F9F9FA"/><path d="M271.2 53.1h-8.6c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h8.6c.3 0 .6.2.6.6 0 .3-.3.6-.6.6zm-18.6 0h-1.1c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1.1c.3 0 .6.2.6.6-.1.3-.3.6-.6.6zm-56.9-.7h-2.2c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1.4c0-.1-.1-.2-.1-.3-.1-.3 0-.6.3-.7.3-.1.6 0 .7.3.2.6.4 1 .4 1 .1.2.1.4 0 .5-.1.3-.3.4-.5.4zm-11.1 0h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm63.8-1.8c-.2 0-.4-.1-.5-.3-.6-1-1.2-1.9-1.9-2.7-.2-.2-.1-.6.1-.8.2-.2.6-.1.8.1.7.9 1.3 1.8 1.9 2.8.2.3.1.6-.2.8 0 .1-.1.1-.2.1zm-5
4.2-3.5c-.3 0-.5-.2-.5-.5-.1-.4-.1-.7-.2-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.2 1.1 0 .2-.2.5-.6.6zm28.8-4.2c-.2 0-.4-.1-.5-.3l-.6-.9c-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.2.3.4.7.6 1 .2.3.1.6-.2.8-.1-.1-.2 0-.3 0zm17.3-1.4c-.1 0-.2 0-.3-.1-1.7-1.2-3.4-2-5.1-2.4-.7-.1-1.4-.2-2-.2-1.8 0-3.3.5-4.6 1.5-.2.2-.6.2-.8-.1-.2-.2-.2-.6.1-.8 1.5-1.2 3.3-1.8 5.3-1.8.7 0 1.5.1 2.2.2 1.8.4 3.7 1.2 5.6 2.5.2.2.3.5.1.8-.1.3-.3.4-.5.4zm-20.7-3.1c-.1 0-.3-.1-.4-.2-.8-.8-1.6-1.5-2.4-2.1-.2-.2-.3-.5-.1-.8.2-.2.5-.3.8-.1.9.7 1.8 1.4 2.6 2.3.2.2.2.6 0 .8-.2.1-.3.1-.5.1zm-23.1-1.8c-.1 0-.3 0-.4-.2-.2-.2-.2-.6 0-.8 1.8-2 4.6-3.2 8.2-3.7 1.6-.2 3.2-.2 4.7-.1.3 0 .5.3.5.6s-.3.5-.6.5c-1.4-.2-2.9-.1-4.5.1-3.3.5-5.9 1.6-7.5 3.4-.1.1-.2.2-.4.2z" fill="#D7D7DB"/><path d="M271.9 57.4H170.8c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1H272c.6 0 1.1.5 1.1 1.1-.1.6-.6 1.1-1.2 1.1z" fill="#F9F9FA"/><g><path d="M26.5 27h13.7s-4.3-9.5 4.8-10.8c8.1-1.1 11.3 7.2 11.3 7.2s1-4.8 5.8-3.9c4.7.9 8.2 8.5 8.2 8.5h11.9" fill="#F9F9FA"/><pat
h d="M40.3 25.5H26.9c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm41.5-.2h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5.6 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-19.6-3.4c-.2 0-.4-.1-.5-.4 0 0-.1-.4-.4-.9-.1-.3 0-.6.2-.8.2-.1.4-.1.6 0 .7-1.5 2.2-3.2 4.7-3.2.4 0 .8 0 1.3.1 1.4.3 2.9 1 4.3 2.2.2.2.3.6.1.8-.2.2-.6.3-.8.1-1.3-1.1-2.5-1.7-3.8-2-.4-.1-.7-.1-1.1-.1-3.3 0-4 3.4-4 3.5 0 .2-.2.4-.4.4-.1.3-.1.3-.2.3zm-16-4.8c-.1 0-.2 0-.3-.1-.3-.2-.3-.5-.1-.8.7-1 1.7-1.7 2.9-2.1.3-.1.6 0 .7.3.1.3 0 .6-.3.7-1 .4-1.8 1-2.4 1.7-.2.3-.4.3-.5.3zm8.1-2.3h-.1c-.3-.1-.7-.1-1-.1-.3 0-.5-.3-.5-.6s.3-.5.6-.5c.4 0 .8.1 1.2.2.3.1.5.4.4.7-.1.1-.3.3-.6.3z" fill="#D7D7DB"/><path d="M83 29.3H26.7c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1H83c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1z" fill="#F9F9FA"/></g><g><path d="M6.5 172.2c-2.8 0-5-2.1-5-4.8v-118c0-2.9 2.4-5.3 5.3-5.3h126.7c2.9 0 5.3 2.4 5.3 5.3v118c0 2.6-2.3 4.8-5 4.8H6.5z" f
ill="#FFF"/><path d="M133.5 45.1c2.3 0 4.2 1.9 4.2 4.2v118c0 2-1.8 3.7-3.9 3.7H6.5c-2.2 0-3.9-1.6-3.9-3.7V49.4c0-2.3 1.9-4.2 4.2-4.2h126.7v-.1zm0-2.2H6.8c-3.6 0-6.5 2.9-6.5 6.5v118c0 3.3 2.8 5.9 6.2 5.9h127.3c3.4 0 6.2-2.6 6.2-5.9v-118c0-3.6-2.9-6.5-6.5-6.5z" fill="#D7D7DB"/><path d="M133.1 66.2v99.1c0 1-.1 1.2-.1 1.2s-.3.1-1.2.1H8.5c-1 0-1.2-.1-1.2-.1s-.1-.3-.1-1.2V66.2h125.9zm1.2-1.1H6.1v100.2c0 2.1.4 2.5 2.5 2.5h123.3c2.1 0 2.5-.4 2.5-2.5V65.1h-.1z" fill="#D7D7DB"/><g fill="#D7D7DB"><circle cx="3.6" cy="3" r="2.9" transform="translate(10 52)"/><circle cx="2.9" cy="3" r="2.9" transform="translate(20 52)"/><path d="M102 58.3H38.3c-1.7 0-3.1-1.4-3.1-3.1v-.3c0-1.7 1.4-3.1 3.1-3.1H102c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.7-1.4 3.1-3.1 3.1z"/><g><circle cx="3.5" cy="3" r="2.9" transform="translate(114 52)"/><circle cx="3.7" cy="3" r="2.9" transform="translate(123 52)"/></g></g><path d="M88.2 127.5c-7.2 0-12.1-8.6-19-8.6s-12.2 8.6-19 8.6c-8.8 0-15.4-8.3-15.5-22.6-.1-8.9 2.6-11.7 14.1-11.7s14.8
4.7 20.4 4.7c5.6 0 8.9-4.7 20.4-4.7 11.5 0 14.1 2.8 14.1 11.7-.1 14.3-6.7 22.6-15.5 22.6zm-33.8-23.4c-7 .3-9.8 4.4-9.8 5.5 0 1 4.6 3.9 9.1 3.9s9.8-1.7 9.8-3.1c.1-1.7-2.5-6.6-9.1-6.3zm29.6 0c-6.6-.3-9.1 4.6-9.1 6.2 0 1.5 5.3 3.1 9.8 3.1 4.5 0 9.1-2.9 9.1-3.9 0-.9-2.8-5.1-9.8-5.4z" fill="#D7D7DB"/></g></g><path d="M215.6 218.3c.2.5.4.9.6 1.4.4.9.8 1.6 1.2 2.2-.4-.6-.7-1.4-1.2-2.2-.2-.5-.4-.9-.6-1.4z" fill="#FFF"/><g transform="translate(78 151)"><ellipse fill="#EDEDF0" cx="25.2" cy="77.6" rx="21.9" ry="4.3"/><circle fill="#D7D7DB" cx="24.7" cy="37.4" r="6.9"/><path d="M30.2 80.7c-.6 0-1-.4-1.1-1l-4.6-39.3c-4.8 15.4-10.8 34.9-11 36.3 0 .6-.5 1.1-1.1 1.1-.6 0-1.1-.5-1.1-1.2 0-1.3 8.8-29.7 12.7-41.9.2-.5.7-.8 1.2-.8s.9.5 1 1l5.3 44.5c.1.6-.4 1.2-1 1.2-.2.1-.3.1-.3.1z" fill="#D7D7DB"/><path d="M35 75.4c-.5 0-1-.3-1.1-.8L23.8 35.3c-.2-.6.2-1.2.8-1.4.6-.2 1.2.2 1.4.8L36.1 74c.2.6-.2 1.2-.8 1.4H35zM38.9 5.7c0 .1 0 .2-.1.2l-4.6.9-2.8.6c-.1 0-.2 0-.2-.1l-1-5.3c0-.1 0-.2.1-.2L37.7.3c.1 0 .2 0 .
2.1l1 5.3z" fill="#D7D7DB"/><path d="M44.4 33.2l-37 7.3c-1 .2-1.9-.4-2.1-1.4L.1 13c-.2-1 .4-1.9 1.4-2.1l37-7.3c1-.2 1.9.4 2.1 1.4l5.2 26.1c.2 1-.4 1.9-1.4 2.1z" fill="#D7D7DB"/><path d="M39.5 9.7c0 .1 0 .1-.1.1L33.5 11c-.1 0-.1 0-.2-.1l-.6-3.2c0-.1 0-.1.1-.1l5.9-1.2c.1 0 .1 0 .2.1l.6 3.2z" fill="#F9F9FA"/><circle transform="rotate(-11.21 127.568 -5.075)" cx="3.292" cy="3.304" r="2.2" fill="#F9F9FA"/><circle transform="rotate(-11.21 54.056 -27.865)" cx="13.892" cy="14.489" r="11.7" fill="#F9F9FA"/><path d="M21.4 14.3c-4 .8-6.5 4.6-5.8 8.6.8 4 4.6 6.5 8.6 5.8 4-.8 6.5-4.6 5.8-8.6-.7-4-4.6-6.6-8.6-5.8z" fill="#D7D7DB"/><path d="M21.8 16.1c-2.9.6-4.8 3.4-4.3 6.4.6 2.9 3.4 4.8 6.4 4.3 2.9-.6 4.8-3.4 4.3-6.4-.6-3-3.5-4.9-6.4-4.3zm2.9 4.4c-.7.1-1.4-.3-1.6-1-.2-.7.3-1.4 1-1.6.7-.1 1.4.3 1.6 1 .2.7-.3 1.4-1 1.6z" fill="#F9F9FA"/></g><g><path d="M281 118c.4-.9 1.4-1.3 2.3-.9.2.1.4.2.5.4-.1-.2-.3-.3-.5-.4-.2-.1-.5-.2-.7-.2-.7 0-1.3.4-1.6 1.1l-.1.1.1-.1zM265.6 124.8c0 .1 0 .1.1.2h-.1.1c0-.1-.1-
.2-.1-.2zM277.6 116.2c.1-.9.9-1.7 1.8-1.6.4 0 .6.2.8.4-.2-.2-.4-.3-.8-.4h-.1c-.9 0-1.6.7-1.7 1.6 0 0 0 .5-.1 1.2.1-.7.1-1.1.1-1.2zM179.4 147.8c-.4-.1-.7-.3-1-.6.2.3.6.5 1 .6zM184.1 82.5c2.8-1.7 11.1.7 17.1 3.9 1.5.8 3.4 1.9 5.1 3.4 3-1.1 6.5-2.1 10.9-2.9 4.4-.8 8.2-1 11.4-.8 1.2-2 2.6-3.8 3.8-5.1 4.6-5.1 11.6-10.1 14.7-9.5 3.7.7 10.7 12.6 10.2 25.1l.1.1c.5-12.6-6.5-24.6-10.3-25.3-.2 0-.4-.1-.6-.1-3.5 0-9.9 4.8-14.2 9.6-1.2 1.3-2.6 3.1-3.8 5.1h-1.7c-2.8 0-5.9.2-9.5.9-4.3.8-7.9 1.8-10.8 2.9-1.8-1.4-3.7-2.6-5.2-3.4-4.6-2.5-10.6-4.5-14.4-4.5-1.2 0-2.1.2-2.8.6-3.3 2-5.8 15.5-1.1 27.1 0-.1.1-.1.1-.2-4.7-11.6-2.3-25 1-26.9zM272.8 116.3c-.5-.9-.1-2.1.8-2.5.9-.5 1.6.7 2.1 1.3.5.5.9.7 1.3 1.4-.4-.7-.8-.8-1.3-1.4-.4-.5-1-1.4-1.7-1.4-.1 0-.3 0-.4.1-.9.4-1.3 1.6-.8 2.5l1.4 2.9.6 1.3-.6-1.3-1.4-2.9zM266.8 122.7c.7-.3 1.2-.9 1.6-1.2.7-.5 2.4-.8 3.3-.6 1 .2 2 .4 2.8.8-.9-.4-1.8-.6-2.8-.8h-.5c-.9 0-2.2.3-2.8.7-.4.2-.9.8-1.6 1.1-.3.1-.6.3-.9.5.3-.2.6-.4.9-.5zM180.6 127.8c0 .3.1.6.1.9.1.6.2 1.2.4 1.7-
.1-.6-.3-1.1-.4-1.7 0-.4 0-.7-.1-.9zM183.5 110.6c0 .1-.1.1-.1.2-.1.2-.1.3-.2.5.1-.2.2-.5.3-.7zM206.3 174.4c-1.3 3.9-2.3 7.7-2.9 11.2.6-3.6 1.6-7.6 3-11.5-.1.2-.1.2-.1.3zM166.4 141.2c-.3-.4-.3-.7-.7-1.3.4.6.4.9.7 1.3zM168.8 133.7h-.2c.3 0 .6 0 .8.1-.1-.1-.4-.1-.6-.1zM171 135.2c.2-1 .6-1.3.9-2 .3-.7.6-2 1.7-1.9.5.1.9.4 1.2.8-.3-.4-.7-.7-1.2-.8h-.2c-.9 0-1.2 1.2-1.5 1.9-.4.7-.8.9-.9 2 0 .2-.1.4-.1.7 0-.3 0-.5.1-.7zM167.8 137.6c-.1-.5-.1-1.2-.2-1.8-.2-.9-.3-1.6.6-2 .1 0 .1 0 .2-.1h-.2c-.9.3-.8 1.1-.6 2 .1.7.1 1.3.2 1.9l-.1-.1c-.3-.4-.8-.6-1.3-.6h-.2c.5-.1 1.1.1 1.5.6l.1.1zM199.5 161.1l-.2.2c-.5.4-1.2.7-1.8.7-.8 0-1.6-.4-2.2-1-.1-.1-2.7-3.3-4.4-7.2-.6-1.5-1.2-3-1.7-4.4-.4.9-.8 1.7-1.4 2.4.1.3.1.6.1.9 0 .3.5 6.4 6.5 8.9 1.8.8 3.6 1.1 5.4 1.1 3.3 0 6-1.2 7.9-2.4-2.8.5-5.5.8-7.5.8h-.7zM171.2 146.5s.1 0 0 0c.1 0 0 0 0 0zM259.3 150.6c-1.4.6-3.2 1.1-5.1 1.5 1.9-.1 3.7-.5 5.4-1.3-.2-.1-.2-.2-.3-.2zM266.1 138.4c-.1-.3-.1-.6-.2-1-.2-.1-.4-.3-.6-.5 0 1.3-.1 2.6-.1 3.9-.1 2.4-.6 4.6-1 6.2 2.9-3.9 1
.9-8.4 1.9-8.6zM172.9 149.4c.1.3.3.5.5.7-.2-.2-.4-.5-.5-.7zM185 139.2l-.6.1.6-.1zM180.7 137.2c.5.1 1.2.6 1.9.6.5.1 1.2.1 1.6.7-.4-.6-1-.6-1.6-.7-.7-.1-1.4-.5-1.9-.6-.3-.1-.6-.1-.9-.1-.9 0-1.9.2-2.4.5-.6.3-1.1.6-1.6 1 .5-.4 1.1-.7 1.6-1 .8-.5 2.5-.7 3.3-.4zM165.3 137.3c.1-.1.1-.1.2-.1-.1 0-.2 0-.2.1-.6.5-.6 1.2-.1 1.9-.5-.7-.5-1.3.1-1.9zM154.9 192c0-.2.1-.3.2-.5.3-.2 4.6-3.8 12.5-6.1.1-.2.2-.3.4-.4.3-.1.6-.1.9 0 2.2-.6 4.7-1 7.5-1.3l.3-.3c.5-.3 1.1-.2 1.4.2.3 0 .7-.1 1-.1 2.2-.1 4.3 0 6.3.1.3-.2.6-.3.9-.3.1 0 .3.1.6.3 3 .2 5.6.7 7.8 1.2.4-.4 1-.4 1.4-.1 0 0 .3.2.6.6 2.7.7 4.5 1.4 5.5 1.9v-.1c-.9-.4-2.7-1.1-5.3-1.8-.4-.4-.7-.6-.7-.7-.2-.2-.5-.3-.8-.3-.3 0-.6.1-.9.4-2.1-.5-4.7-.9-7.6-1.1-.3-.3-.5-.4-.7-.4h-.2c-.3 0-.6.1-.9.3-1.2-.1-2.5-.1-3.8-.1H179c-.3 0-.6 0-.9.1-.2-.3-.6-.5-1-.5-.2 0-.4.1-.7.2-.2.1-.3.2-.4.4-2.6.2-5.1.7-7.3 1.2-.2-.1-.4-.2-.6-.2-.2 0-.3 0-.5.1s-.4.3-.5.5c-7.8 2.3-12.1 5.9-12.4 6.1.2.3.1.5.2.7-2.4 1.7-4.1 3.7-4.5 5.9-.1.5-.1 1.1-.1 1.6 0-.5 0-1 .1-1.6.5-2.2 2.2-4.2 4
.5-5.9zM246.5 220.3c.1-1.9.2-5.6.3-9.1-.1 3.4-.2 7.2-.3 9.1 0 1 0 1.8.2 2.3-.1-.6-.2-1.4-.2-2.3zM208.9 217.4c.2.5.4.9.6 1.4.4.9.8 1.6 1.2 2.2-.4-.6-.7-1.4-1.2-2.2-.2-.4-.4-.9-.6-1.4z" fill="#FFF"/><path d="M285.4 113.6c-.4-.2-.7-.3-1.1-.4-1.3-2.1-3.4-2.4-4.3-2.5h-.5c-.6 0-1.2.1-1.8.3-.8-.6-2-1.2-3.4-1.2-.8 0-1.6.2-2.4.6-.7.3-1.2.7-1.7 1.2-1.3-5.5-4.1-10.6-8.1-14.9.3-13.8-7.2-27.9-13.9-29.2-.5-.1-1-.1-1.5-.1-6 0-13.9 7-17.6 11.1-.8.9-1.9 2.2-2.9 3.6-3.1 0-6.3.4-9.6.9-3.3.6-6.4 1.3-9.3 2.3-1.4-1-2.8-1.8-3.8-2.3-4.3-2.3-11.2-5-16.5-5-2.1 0-3.8.4-5.1 1.2-5.8 3.5-8.1 19.3-3.1 32.2-2.3 5.4-3.1 11.2-2.5 16.8-.6-.3-1.2-.5-1.9-.6-.3-.1-.6-.1-.9-.1-1.4 0-3.1.5-4.5 2.4-.8 0-1.5.1-2.2.4-.8.3-2.7 1.3-3.3 3.6-.3.2-.6.4-.9.7-2.1 1.8-3 5.1-.3 8.4v.1c.2.4.5 1.1 1.1 1.9.1.1.3.4.6.7 1 1.2 1.8 2.1 2.3 2.7l.7.7.6.6c.4 1 .9 1.8 1.5 2.6.1.1.2.3.3.4.2.3.4.5.5.8 1.4 1.9 2.9 3.2 4.5 4.2 1.1 4.9 4.5 13.3 14.6 17.6 3.6 1.5 7.3 2.3 11.1 2.3h.9c-.5 1.6-.8 3.1-1.2 4.6-.1 0-.2-.1-.3-.1-.1-.1-.1-.1-.2-.1-1-.8-2.3-1
.3-3.6-1.3-.5 0-.9.1-1.4.2-1.8-.3-3.7-.6-5.6-.8-.4-.2-.9-.4-1.3-.5-.4-.1-.7-.1-1.1-.1-.6 0-1.2.1-1.8.3-1 0-1.9-.1-2.9-.1h-2.1c-.7-.3-1.4-.4-2.1-.4-1 0-2 .3-2.8.8-1.9.2-3.7.5-5.5 1h-.6c-.8 0-1.6.2-2.4.5-.4.2-.7.4-1 .6-7.9 2.5-12.4 6.2-12.9 6.6-.4.3-.8.7-1 1.2-2.8 2.3-4.5 4.9-5.1 7.7-1.3 6.3 3.3 12.9 12.1 17.4.2.4.5.9.8 1.2 1.1 1.3 2.7 2 4.3 2 .7 0 1.3-.1 1.9-.3 2.3.7 4.7 1.3 7.1 1.6l.1.1c1 .8 2.3 1.3 3.6 1.3 1.1 0 2.2-.3 3.2-.9.8 0 1.6-.1 2.4-.1 1.9-.2 3.7-.4 5.6-.8.1 0 .2.1.3.1.8.3 1.6.5 2.4.5 1.9 0 3.7-1 4.8-2.6 1.4-.5 2.7-1 4.1-1.5.6.2 1.3.3 1.9.3.9 0 1.8-.2 2.6-.6.7 2.3 1.5 4.3 2.4 6.2 2.8 5.5 4.9 8.5 8.3 8.5 1.3 0 2.6-.5 3.6-1.5 1.6-1.7 1.8-4 1.7-6.1 0-1.1-.1-2.8-.1-4.7 1.2.2 2.4.3 3.7.4 1.9.2 3.9.2 5.7.2 4.9 0 9.6-.5 13.8-1.5 0 1.6-.1 3-.1 4-.1 2.1.1 4.4 1.7 6.1.9 1 2.2 1.5 3.6 1.5 3.4 0 5.5-3 8.3-8.5 2.5-5 3.6-10.7 4.1-14.8 3-8.3.5-23.5-2.4-31.9-.7-2.1-1.5-4.2-2.2-6.2 6.1-.3 11.7-2.5 16.6-6.6 8.3-7.1 9.1-16.1 8.8-21.1 1.2-1.3 2.3-3.1 3-5.3l.3-.9c.1-.2.1-.3.2-.5.3-.9.5-1.9.7-2.
9l.5-.9.4-.8c.3-.7.8-1.8 1.5-3.2.1-.3.3-.6.3-.8.4-.9.5-1.7.5-2.1v-.1c1.5-4.3-.3-7.2-2.8-8.3z" fill="#F9F9FA"/><path d="M183.3 144.3c.3 1.5-.5 2.9-1.9 3.5-.4.2-.8.2-1.2.2h-.5c.5.1 1.1 0 1.6-.2 1.5-.6 2.3-2.1 2-3.5-.1-.7.1-1.3.4-1.8-.3.4-.5 1.1-.4 1.8zM164.1 212.7c-.2.2-.5.3-.7.3-.3 0-.6-.1-.8-.4-.3-.3-.3-.8-.2-1.2 0 0-.1 0-.1-.1-.2.4-.1 1 .2 1.3.2.3.6.4 1 .4.1.1.4 0 .6-.3.1.1.3-.1.6-.4h-.1c-.3.3-.5.4-.5.4zM176.9 215.2c-.2.3-.5.4-.9.4-.2 0-.5-.1-.7-.3-.2-.2-.3-.4-.4-.7h-.2c0 .3.2.6.4.8.2.2.5.3.8.3.5.1.9-.1 1-.5.1 0 .3-.1.4-.4h-.1c-.1.3-.2.4-.3.4zM205.9 205.9c.1 1.1.3 2.3.6 3.6-.2-1.3-.4-2.5-.6-3.6.1 0 0 0 0 0zM190.8 213.7c-.2.4-.6.7-1 .7-.2 0-.3 0-.5-.1-.3-.2-.6-.5-.6-.8h-.1c.1.4.3.7.7.9.2.1.3.1.5.1.5 0 .9-.3 1.1-.7 0-.1.2-.4.4-1h-.2c-.1.5-.2.9-.3.9zM201.6 210c-.2.4-.6.6-1 .6-.2 0-.3 0-.5-.1-.3-.2-.5-.5-.6-.9 0 0-.1 0-.1.1.1.4.3.7.6.9.2.1.4.1.6.1.5 0 .9-.2 1.1-.7 0-.1.4-.8.8-2-.1 0-.1.1-.2.1-.4 1.2-.7 1.8-.7 1.9zM271.1 131.8h-.3c-.9-.1-1.7-.6-2.3-1.3.5.7 1.3 1.2 2.3 1.3 1.7.1 3.2-1.1
3.4-2.9.1-.8-.2-1.7-.6-2.4.5.7.7 1.6.6 2.4-.1 1.7-1.5 2.9-3.1 2.9zM197.7 158.4c.1.2.2.3.2.3.2.2.2.6 0 .8-.1.1-.2.2-.4.2-.1 0-.3-.1-.4-.2 0 0-.4-.4-.8-1 .4.6.7.9.8 1 .1.1.3.2.5.2.1 0 .3 0 .4-.1.3-.2.3-.6.1-.9.6.1 1.4.2 2.3.2 3 0 7.6-.7 12-1.9l-.1-.1c-4.6 1.2-9 1.9-11.9 1.9-1.2-.1-2.1-.2-2.7-.4zM191.5 146.3c.5 1.6 1.1 3.4 1.8 5.2-.5-1.5-.9-3-1.2-4.7-.2-.1-.4-.3-.6-.5zM181.1 143.8h-1.5c-.2.4-.2.9-.1 1.4.2.4.5.6.8.6.1 0 .2 0 .3-.1.4-.2.6-.6.5-1v-.9zM244.6 151s0 .1-.1.1c6.9-.5 13.9-2.1 15.9-3.7-.1.3-.2.5-.2.5-.1.3.1.7.4.8h.2c.3 0 .5-.2.6-.4 0-.1.6-1.6 1-3.8-.5 2.1-1 3.6-1.1 3.7-.1.2-.3.4-.5.4h-.2c-.3-.1-.4-.4-.3-.7 0 0 .1-.4.3-1 0 0 0 .1-.1.1-1.3 1.7-8.3 3.5-15.9 4zM264.4 132.1c.1.2.2.5.3.7-.1-.2-.2-.4-.3-.7-.3-.6.1-1.8 0-2.5 0-.3-.1-.6-.1-.8 0 .3 0 .5.1.8.1.8-.2 1.9 0 2.5zM212.1 159.6c.3-.7.6-1.3.9-1.9-.3.6-.6 1.2-.9 1.9zM262.1 133.6c-.1.2-.2.4-.4.6.2 1.7.3 3.4.4 4.9.1-2 0-3.9 0-5.5z" fill="#FFF"/><path d="M271.1 129.6c.5 0 .9-.4 1-.8 0-.5-.2-1-.5-1.3l-1.5.5c.1.3.1.5.2.8 0 .4.3.8.8.8z"
fill="#FFF"/><path d="M196.3 184.9c-.4-.3-1-.3-1.4.1-2.2-.5-4.8-.9-7.8-1.2-.2-.2-.4-.3-.6-.3-.3-.1-.7 0-.9.3-1.9-.1-4-.1-6.3-.1-.4 0-.7 0-1 .1-.4-.4-1-.5-1.4-.2l-.3.3c-2.7.3-5.2.7-7.5 1.3-.3-.1-.6-.2-.9 0-.2.1-.3.2-.4.4-7.8 2.3-12.2 5.9-12.5 6.1-.1.1-.2.3-.2.5 0 .1 0 .2.1.3.1.1.3.2.4.2.1 0 .3 0 .4-.1.1 0 4.2-3.5 11.7-5.7.3.8 2.2 5.7.6 13.1-1.7 7.9-5.5 11.3-5.5 11.3-.1.1-.2.2-.3.4-.2.4-.1.9.2 1.2.2.3.5.4.8.4.3 0 .5-.1.7-.3l.4-.4c1.1-1.2 4.2-4.9 5.8-12.1 1.6-7.4 0-12.6-.6-14.1 2-.5 4.3-.9 6.7-1.2v.1c0 .1 3.5 5.6 2.9 15-.6 9.3-4.1 13.8-4.2 13.8-.2.3-.3.6-.2.9 0 .3.2.5.4.7.2.2.5.3.7.3.3 0 .6-.1.9-.4 0 0 .1-.2.3-.4.9-1.3 3.9-6.1 4.4-14.7.5-7.9-1.7-13.3-2.7-15.4h.4c2.1-.1 4 0 5.9.1.1.2.2.5.5.7.1.1.1.1.2.1.9.9 4.4 5 5 11.8.8 8.8-2 15.3-2.1 15.3-.1.2-.1.4-.1.6.1.4.3.7.6.8.1.1.3.1.5.1.4 0 .8-.2 1-.7 0-.1.2-.4.4-.9.8-2.2 2.6-8 1.9-15.5-.6-5.8-3-10.1-4.8-12.2 2.4.2 4.5.6 6.3 1 .1.2.2.4.4.6 0 0 4.1 3.3 5.5 9.6 1.7 7.6-.8 12.7-.8 12.8-.1.2-.1.4-.1.6 0 .4.2.7.6.9.2.1.3.1.5.1.4 0 .8-.2 1-.6 0-.1.4
-.7.7-1.8.7-2.3 1.6-6.7.3-12.5-.9-4-2.7-6.9-4.2-8.7 2.3.7 3.7 1.3 4.1 1.5 0-.5-.1-.9-.1-1.3-1-.4-2.8-1.2-5.5-1.9-.5-.5-.8-.7-.8-.7zM240.9 161.8c-2.2 1.7-5.8 3.7-11 4.4-5.7.8-10.2-.7-12.9-2.1-4.7 6.9-9.4 17.7-9.1 27.9.4 16.8 14.5 19.1 23.7 18.7 6-.3 11.7-2.4 15.5-6.7v-.1l.1-.1c2-2.3 3.4-5.1 4.1-8.6 1.9-10.3-2.7-20.6-6.9-28.5-1.1-1.9-2.3-3.6-3.5-4.9zM183.7 110.2c-.1.1-.1.2-.2.3.1 0 .2-.1.2-.3zM185.2 84.4c.3-.2.8-.3 1.5-.3 2.7 0 8.1 1.4 13.4 4.2 1.4.8 2.7 1.6 3.8 2.4-7.2 3.2-9.7 6.7-9.8 6.9-.2.3-.1.6.1.8.1.1.2.1.3.1.2 0 .3-.1.5-.2.1-.1 5.2-7.3 22.4-10.3 17.1-3 24.8 2.9 24.9 3 .2.2.6.2.8-.1.2-.2.2-.6-.1-.8-.2-.2-4-3.1-11.9-3.9.8-1.2 1.8-2.5 3-3.8 4.8-5.3 10.5-8.8 12.4-8.8h.2c2.1.4 8.4 10.1 8.4 21.3.7.5 1.4 1 2.2 1.6.5-12.5-6.4-24.3-10.2-25.1-3.2-.6-10.2 4.4-14.7 9.5-1.2 1.3-2.6 3.1-3.8 5.1-3.2-.1-7 .1-11.4.8-4.4.8-7.9 1.8-10.9 2.9-1.8-1.4-3.7-2.6-5.1-3.4-6-3.2-14.3-5.5-17.1-3.9-3.2 2-5.7 15.3-1.1 26.8.5-.8 1-1.6 1.5-2.2-3.7-10.4-1.1-21.5.7-22.6zM193.3 151.5c.1.2.2.4.3.7 1.2 2.9 3.4 5.5
4.1 6.3.6.2 1.5.3 2.6.3 2.9 0 7.3-.6 11.9-1.9-1.4-1.8-1.6-3.8-1.6-3.8v-.1c0-.1-.1-.3-.1-.4l-.1-1.2v-.4c-1.1.3-2.2.4-3.4.2l-2.5.4c-6.1 1.1-11.9-3-12.9-9l-.2-1.3h-.2c.2 1.8.5 3.8.9 5.6.3 1.6.8 3.1 1.2 4.6z" fill="#F9F9FA"/><path d="M196.3 124.7c.7-5 5.3-8.5 10.3-7.9l4.9.7c3.3.5 6 2.7 7.2 5.6 1.1-.8 2.4-1.4 3.8-1.6 1.4-.2 2.7-.2 4 .2.3-2.3 1.5-4.6 3.5-6.1l4-3c4-3.1 9.8-2.3 12.8 1.7l3.8 5 4.7-.8c.8-.1 1.6.4 1.8 1.2.1.7-.2 1.3-.8 1.6.8.6 1.4 1.7 1.7 3.3l1 5.8c1.1 6.1-3 11.9-9 12.9l-1.7.3c-1.1.4-2.3.6-3.5.6l-.5.1h-.3s0 .1.1.1l.1.1c0 .1.1.2.1.3l.2.5s.1.2.1.3l.1.4c0 .2.1.3.1.4l.1.6V148.4c0 .9-.2 1.7-.4 2.5 7.7-.5 14.6-2.3 16-3.9 0 0 0-.1.1-.1.5-1.5 1.3-4.6 1.4-7.3v-.6c0-1.6-.1-3.2-.4-4.9-.2-1.8-.6-3.6-1-5.4l-1.8.3-.5-3 1.4-.3c-.5-1.6-1.2-3.2-2.1-4.7 0-.2 0-.4-.1-.6-2.6-14.6-19.6-23.8-38-20.6-17.4 3.1-29.9 16.2-29 30l5.1-.9.7-4.2z" fill="#F9F9FA"/><path d="M210.5 150.9v-.1-.3h-.2l-3.2.6c1.1.1 2.3 0 3.4-.2zM245 144.3c1.2 0 2.3-.2 3.5-.6l-3.5.6zM229.5 159.8s.1 0 0 0z" fill="#D9EBFF"/><path d="
M43.7 146.5h-.1c-1.7.4-3.6.8-5.4 1h-.1c-.6.1-1.2.2-1.9.2-1 .1-1.9.1-2.9.1h-.9-.1c.9-1.3 3.9-6.1 4.4-14.7.5-7.9-1.7-13.3-2.7-15.4h.4c2.1-.1 4 0 5.9.1.1.2.2.5.5.7.1.1.1.1.2.1.9.9 4.4 5 5 11.8.8 8.8-2 15.3-2.1 15.3-.2.3-.2.5-.2.8zm-26.1-2.4s3.8-3.4 5.5-11.3c1.6-7.3-.2-12.3-.6-13.1-7.5 2.3-11.6 5.7-11.7 5.7-.1.1-.2.1-.4.1s-.3-.1-.4-.2c-.1-.1-.1-.2-.1-.3-2.4 1.7-4.1 3.7-4.5 5.9-.1.5-.1 1-.1 1.6v.1c0 .2 0 .4.1.6v.3c0 .2.1.4.1.6 0 .1.1.2.1.3.1.2.1.3.2.5.1.1.1.3.2.4.1.1.1.3.2.4l.3.6c.1.1.1.2.2.3 2 3 5.8 5.8 10.4 7.9 0 0 .1 0 .1.1.2-.3.3-.4.4-.5zm37-2.1s2.6-5.2.8-12.8c-1.4-6.3-5.4-9.6-5.5-9.6-.2-.2-.3-.4-.4-.6-1.8-.4-3.9-.8-6.3-1 1.8 2.2 4.3 6.4 4.8 12.2.7 7.5-1.1 13.4-1.9 15.5h.2c2.9-.9 5.6-1.9 8-3.1 0 0 .1 0 .1-.1.1-.1.1-.3.2-.5zm-24.4 4.8s3.6-4.5 4.2-13.8c.6-9.4-2.9-14.9-2.9-15v-.1c-2.4.2-4.7.6-6.7 1.2.6 1.5 2.2 6.7.6 14.1-1.6 7.2-4.7 10.9-5.8 12.1h.1c3.2 1.2 6.7 2 10.2 2.3h.2c-.2-.2-.1-.5.1-.8zm108.6-96.3c.3.4.3 1.1 0 1.9-.4 1.1-.2 1.4-.5 2-.3.7-1.3 3-1.7 3.8-.1.2-.7 1.2-1.3 2.5 0 .9-.2
1.8-.5 2.7-.1.2-.1.4-.2.6l-.3.9c-.7 1.9-1.8 4-3.6 4.9.5 2.6 1.6 12.4-6.9 19.6-5.1 4.3-10.5 5.6-15.1 5.6-1.4 0-2.8-.1-4-.3-1.2-2.5-2.8-4.8-2.9-4.9-.2-.2-.5-.3-.8-.1-.2.2-.3.5-.1.8 0 0 2.1 2.8 3.2 5.7 0 0 0 .1.1.1.1.2.1.4.2.6l.1.1c1.4 3.4 2.6 6.9 3.7 10.1 2.9 8.6 4.9 23.1 2.2 29.4-.4 3.7-1.4 9.2-3.7 13.9-2.2 4.3-3.5 6-4.3 6h-.2l-.1-.1-.1-.1s0-.1-.1-.1c0-.1-.1-.2-.1-.3-.2-.5-.2-1.3-.2-2.3.1-1.9.2-5.6.3-9.1 2.8-1.3 4.6-2.8 4.6-2.9.2-.2.2-.6 0-.8-.2-.2-.6-.2-.8 0 0 0-1.8 1.6-4.4 2.7-4.6 1.8-10.6 3-17.9 3-1.7 0-3.5-.1-5.4-.2-3.4-.3-6.3-.8-8.7-1.5v.2c-2.1-.9-3.8-2.3-3.8-2.4-.2-.2-.6-.2-.8 0-.2.2-.2.6 0 .8.1.1 2.1 1.9 4.6 2.7.1 3.4.2 7 .3 8.9.1 1.8-.2 3-.8 3-.1 0-.2 0-.3-.1-.1 0-.2-.1-.3-.2l-.1-.1-.3-.3-.1-.1c-.1-.1-.2-.3-.3-.4l-.2-.2c-.1-.1-.2-.3-.3-.5-.1-.1-.2-.2-.2-.4-.1-.2-.2-.3-.3-.5-.1-.2-.2-.3-.3-.5-.1-.1-.2-.3-.2-.4-.4-.6-.7-1.4-1.2-2.2-.2-.5-.4-.9-.6-1.4 0-.1 0-.1-.1-.1-.2-.4-.4-.9-.5-1.3 0-.1-.1-.2-.1-.2-.2-.5-.3-.9-.5-1.4 0-.1 0-.1-.1-.2-.1-.5-.3-.9-.4-1.4 0-.1 0-.1-.1-.2-.1-.5-.
2-.9-.4-1.4v-.1c-.1-.5-.2-1-.3-1.4v-.1c-.2-1.3-.4-2.5-.6-3.5-1 .7-2.2 1.4-3.5 2.1-.1 0-.1.1-.2.1.7-2.3 1.6-6.7.3-12.5-.9-4-2.7-6.9-4.2-8.7 2.3.7 3.7 1.3 4.1 1.5.2 3 .7 7.5 1.4 11.6 0 .3.3.5.5.5h.1c.3-.1.5-.3.5-.6-1-5.8-1.5-12.1-1.6-14.3.6-3.6 1.6-7.6 3-11.5 2.2-6.1 4.2-8.1 4.2-8.1.2-.2.2-.6 0-.8-.2-.2-.6-.2-.8 0-.1.1-1.7 1.7-3.6 6.3-1.9.5-4 .9-6.3.9-2.9 0-6-.6-9.3-2-10.2-4.4-12.1-14.1-12.4-16.7-2-.4-3.6-2-4.8-3.6-.2-.2-.3-.5-.5-.7-.1-.1-.3-.3-.4-.5-.2-.3-.5-.7-.7-1.1 0-.1-.1-.1-.1-.2-.2-.4-.3-.7-.5-1.1v-.1l-2-2c-.6-.6-2.2-2.6-2.7-3.1-.1-.1-.1-.1-.1-.2-.3-.4-.3-.7-.7-1.3-.1-.1-.1-.2-.2-.3-.1-.1-.2-.2-.2-.3-.5-.7-.6-1.4.1-1.9.1-.1.1-.1.2-.1l.1-.1c.1-.1.3-.1.5-.2h.1c.5-.1 1.1.1 1.5.6l.1.1c-.1-.5-.1-1.2-.2-1.8-.2-.9-.3-1.6.6-2 .1 0 .1 0 .2-.1h.2c.3 0 .6 0 .8.1 0 0 .1 0 .1.1.1 0 .2.1.2.1.1.1.2.2.3.2l.1.1c.1.1.2.3.2.4 0 0 .2.5.4 1.1 0-.3.1-.5.1-.7.2-1 .6-1.3.9-2 .3-.7.6-2 1.7-1.9.5.1.9.4 1.2.8.3.4.4.9.3 1.4l-.5 3.2-.4 2.3c-.5.9-1.2 2.1-1.7 3.4-.1.3.1.6.3.7h.2c.2 0 .4-.1.5-.4.7-1.9 1.7-3.5
2.2-4.2.5-.4 1.1-.7 1.6-1 .8-.4 2.5-.6 3.4-.4.5.1 1.2.6 1.9.6.5.1 1.2.1 1.6.7.1.2.2.4.2.8l-.7.1c-.8.1-1.4.9-1.2 1.8 0 .1.1.2.1.3-.2.1-.4.1-.7.1l-3.2-.1c-1.4.7-1.9 2.9-1.3 4.4.1.2.2.4.3.5 0 .1.1.1.1.1.1.1.1.2.2.3l.2.2c.1.1.1.1.2.1.3.3.7.4 1 .6.1 0 .3.1.4.1.5.1 1.1 0 1.6-.2 1.4-.6 2.2-2 1.9-3.5-.1-.7 0-1.3.4-1.9h.5l2.2-.4c.2.4.3 1.1.5 1.7.1.7.8 1.7.8 2.4-.2 1.9-1.2 3.9-2.5 5 .3.5.5 1 .5 1.6 0 .3.6 7.7 7.9 10.8 2.2 1 4.3 1.3 6.3 1.3 6.5 0 11.2-4.1 12.1-5 0-.1.1-.2.1-.3.3-.7.6-1.3.9-1.9.7.6 1.7 1.2 2.9 1.5 3.5 1 5.2.8 5.9.6.7.7 2.8 2.3 5.9 2.3.5 0 1.1-.1 1.7-.2 4.1-.8 6.3-3.7 6.8-4.5 1.1-.3 5.8-2 7.8-5.6l.9.3c.3.1 3.9 2 8.5 2 3.2 0 6.9-.9 10.4-3.8 6.1-5.2 4.4-12.6 4.3-12.6-.1-.6-.1-1.1 0-1.7-.9-.4-1.9-1.2-2.7-2.1-.1-.2-.3-.4-.4-.5-.1-.2-.2-.3-.3-.5 0 0 0-.1-.1-.1-.1-.2-.2-.4-.3-.7-.3-.7.1-1.8 0-2.5 0-.3-.1-.6-.1-.8-.4 1-.8 1.9-1.3 2.9-.1-1.3-.2-2.1-.2-2.1 0-.3-.3-.5-.6-.5s-.5.3-.5.6c0 0 .2 1.6.3 3.9-.1.2-.2.4-.4.6-.2-1.8-.6-3.6-1-5.4l4.9-.9c.5-.1.9-.4 1.1-.8.2.1.3.2.4.3.1.1.2.2.3.4 0 0
0 .1.1.1.1.1.2.3.2.4v.1c.1.2.1.4.1.6.1.6.3 1.1.6 1.5.5.7 1.3 1.2 2.3 1.3 1.7.1 3.2-1.1 3.4-2.9.1-.8-.2-1.7-.6-2.4-.5-.7-1.1-1.3-1.9-1.4l-3.1 1c-.2 0-.4.1-.7.1-.4 0-.8-.1-1.1-.2-.2-.5-.6-.9-1.1-1 0-.1-.1-.1-.1-.2v.2h-.5l-5.2.9c-.5-1.6-1.2-3.2-2.1-4.7 0-.2 0-.4-.1-.6-2.6-14.6-19.6-23.8-38-20.6-17.4 3.1-29.9 16.2-29 30h-.1c-.8.1-1.4.9-1.2 1.8.1.8.9 1.3 1.7 1.3-.5.9-.7 2-.4 3.6l.3 1.5-5.9 1c-.9-1.4-1.7-2.9-2.4-4.4-.1-.3-.2-.5-.3-.8-.1-.2-.1-.4-.2-.6-.1-.4-.3-.7-.4-1.1 0-.1-.1-.3-.1-.4-.1-.5-.3-1-.4-1.5-.1-.6-.3-1.1-.4-1.7-.1-.3-.1-.6-.1-.9 0-.3-.1-.7-.1-1 0-.4-.1-.7-.1-1.1v-.9-1.1-.9c0-.6.1-1.2.1-1.8 0-.3.1-.7.1-1 .1-.3.1-.7.2-1 .1-.3.1-.6.2-1 .1-.3.1-.7.2-1 .1-.4.2-.7.3-1.1.1-.3.2-.6.3-1 .2-.6.4-1.1.6-1.7.1-.3.2-.6.4-.9.1-.3.3-.7.4-1l.3-.6c.1-.1.1-.3.2-.4 2.7-4.5 5.9-7.4 6-7.4.2-.2.3-.6 0-.8-.2-.2-.6-.3-.8 0-.1.1-2.2 2-4.5 5.1-3.7-10.5-1.1-21.6.7-22.7.3-.2.8-.3 1.5-.3 2.7 0 8.1 1.4 13.4 4.2 1.4.8 2.7 1.6 3.8 2.4-7.2 3.2-9.7 6.7-9.8 6.9-.2.3-.1.6.1.8.1.1.2.1.3.1.2 0 .3-.1.5-.2.1-.1 5.2
-7.3 22.4-10.3 17.1-3 24.8 2.9 24.9 3 .2.2.6.2.8-.1.2-.2.2-.6-.1-.8-.2-.2-4-3.1-11.9-3.9.8-1.2 1.8-2.5 3-3.8 4.8-5.3 10.5-8.8 12.4-8.8h.2c2.1.4 8.4 10.1 8.4 21.3-2.6-1.7-4.9-2.6-5-2.7-.3-.1-.6 0-.7.3-.1.3 0 .6.3.7.1 0 5.2 2.1 9.1 6l.2.2c1 1.1 1.9 2.3 2.7 3.5 0 .1.1.1.1.2.4.6.7 1.2 1.1 1.7l.1.1c.7 1.3 1.3 2.6 1.8 4 0 .1.1.2.1.3.2.6.4 1.2.6 1.9 0 .1 0 .2.1.3.2.7.3 1.4.5 2.2l.3 2.4c.2 2.4.1 4.8-.3 7.1.3-.2.6-.4.9-.5.7-.3 1.2-.9 1.6-1.2.7-.5 2.4-.8 3.3-.6 1 .2 2 .4 2.8.8 1.8 1.5 3.5 3 3.7 3.4.1.2.3.3.5.3.1 0 .2 0 .2-.1.3-.1.4-.5.2-.7-.4-.8-3.1-3-4.4-4.2L129 52l-1.5-2.9c-.5-.9-.1-2.1.8-2.5.9-.5 1.6.7 2.1 1.3.5.5.9.7 1.3 1.4.1.1.1.2.2.3l.3.6c0-.7.1-1.1.1-1.2.1-.9.9-1.7 1.8-1.6.4 0 .6.2.8.4.3.3.3.8.4 1.4 0 .1 0 .3.1.4 0 .1 0 .2.1.3.1.4.2.7.2 1.1l.1-.1c.4-.9 1.4-1.3 2.3-.9.4.2.6.3.7.5zM99.3 99.7c-1.1-2-2.2-3.6-3.4-5-2.2 1.7-5.8 3.7-11 4.4-5.7.8-10.2-.7-12.9-2.1-4.7 6.9-9.4 17.7-9.1 27.9.4 16.8 14.5 19.1 23.7 18.7 6-.3 11.7-2.4 15.5-6.7v-.1l.1-.1c2-2.3 3.4-5.1 4.1-8.6 1.8-10.2-2.8-20.5-7-28.
4zM66.6 50.5l-4.9-.7c-5-.7-9.6 2.9-10.3 7.9l-.6 4.4 20.9-3.7c.6-.9 1.3-1.6 2.2-2.3-1.3-2.9-4-5.2-7.3-5.6zm22.5-5l-4 3c-2 1.5-3.2 3.7-3.5 6.1 1.1.3 2.1.8 3 1.4l21.2-3.8-3.8-5c-3.1-3.9-8.9-4.7-12.9-1.7zM66.6 85.3l-.1-1.1v-.3-.4l.1-.3c5.3-1.7 8.6-7 7.6-12.6l-.1-.3c.1 0 .2-.1.4-.1l1 5.5c.1.8.9 1.3 1.7 1.2.8-.1 1.3-.9 1.2-1.7l-1.3-7c2.4-1.3 5.4-1.4 7.9 0 .3.2.7.2 1 .2.1 0 .2-.1.3-.1l.1.3c1 5.6 5.9 9.4 11.4 9.2l.2.3c0 .1.1.1.1.2v.1c0 .1.1.2.1.2l.1.4c0 .1.1.2.1.3l.1.5c0 .1 0 .2.1.4v2.6c-.5 2.6-2.6 4.5-5.9 5.2h-.1H92.3c-.1 0-.3.1-.4.1-.5.1-1 .4-1.5.7-.5.3-.9.7-1.2 1.1-.4.4-.7.8-1.1 1.1-.3.4-.7.7-1.1 1l-.9.5-.2.1c-.1 0-.1.1-.2.1l-.2.1h-.1l-.2.1h-.1l-.3.1-.4.1H83c-.5 0-1-.1-1.4-.2-.5-.1-.9-.3-1.4-.5-.5-.2-.9-.5-1.4-.7-.5-.2-1-.5-1.5-.6-.5-.1-1.1-.2-1.7-.1H75.3h-.1-.1-.1c-3.4.6-6.1-.5-7.5-2.8l-.1-.1-.1-.3v-.1l-.1-.1s0-.1-.1-.1l-.1-.4c0-.1 0-.1-.1-.2v-.1-.1l-.2-1c0-.2 0-.3-.1-.4zm9.5-1c.2 1 1 2.3 2.2 2.9.3.2.6.2.9.1.4-.1.8-.3 1-.8.4-.7.1-1.6-.6-2-.3-.2-.6-.7-.7-.8-.2-.8-.9-1.3-1.7-1.2-.7.3-1.3
1-1.1 1.8zm-2.4-17.5l.3-.3-.1-.4c-.1-.8.4-1.6 1.2-1.7.6-.1 1.1.1 1.4.6 3-1.4 6.4-1.4 9.4 0l-.4-2.4c-.3-1.6-.1-2.8.4-3.6l-14.2 2.5c.8.6 1.3 1.7 1.6 3.3l.4 2zm4.1-11.2c-1.8.3-3.4 1.2-4.5 2.5l9.7-1.7c-1.6-.9-3.4-1.2-5.2-.8z" fill="url(#a)" opacity=".2" transform="translate(145 67)"/><path d="M228.8 160c0-.1 0 0 0 0z" fill="#59ACFF"/><path d="M223.3 154.2c.3.2.6.2.9.1.4-.1.8-.3 1-.8.4-.7.1-1.6-.6-2-.3-.2-.6-.7-.7-.8-.2-.8-.9-1.3-1.7-1.2-.8.1-1.3.9-1.2 1.7.2 1.1 1.1 2.4 2.3 3zM220.1 131.4c-.8.1-1.3.9-1.2 1.7l.1.4c.8-.6 1.6-1.2 2.5-1.6-.3-.4-.9-.6-1.4-.5zM222.3 143.8c.8-.1 1.3-.9 1.2-1.7l-1.3-7c-.8.4-1.6 1-2.2 1.8-.1.1-.3.2-.4.3l1 5.5c.1.7.9 1.2 1.7 1.1z" fill="#F9F9FA"/><path d="M265.6 125c.1 0 .1 0 0 0v-.2.2z" fill="#59ACFF"/><path d="M113.9 62.2l1.8-.3 4.9-.9c.5-.1.9-.4 1.1-.8.2.1.3.2.4.3.1.1.2.2.3.4 0 0 0 .1.1.1.1.1.2.3.2.4v.1c.1.2.1.4.1.6.1.6.3 1.1.6 1.5.5.7 1.3 1.2 2.3 1.3h.3c1.6 0 3-1.2 3.1-2.9.1-.8-.2-1.7-.6-2.4-.5-.7-1.1-1.3-1.9-1.4l-3.1 1c-.2 0-.4.1-.7.1-.4 0-.8-.1-1.1-.2-.2-.5-
.6-.9-1.1-1h-.6l-5.2.9-1.4.3.5 2.9zm12.6-1.7c.2.3.5.8.5 1.3s-.4.8-.9.8h-.1c-.4 0-.8-.4-.8-.8 0-.3-.1-.6-.2-.8l1.5-.5zM38.7 72.4c-.8.1-1.4.9-1.2 1.8 0 .1.1.2.1.3-.2.1-.4.1-.7.1l-3.2-.1c-1.4.7-1.9 2.9-1.3 4.4.1.2.2.4.3.5 0 .1.1.1.1.1.1.1.1.2.2.3l.2.2c.1.1.1.1.2.1.3.2.7.4 1 .6.1 0 .3.1.4.1h.5c.4 0 .8-.1 1.2-.2 1.4-.6 2.2-2 1.9-3.5-.1-.7 0-1.3.4-1.8h.5l2.2-.4c.2.4.3 1.1.5 1.7.1.7.8 1.7.8 2.4-.2 1.9-1.2 3.9-2.5 5 .3.5.5 1 .5 1.6 0 .3.6 7.7 7.9 10.8 2.2 1 4.3 1.3 6.3 1.3 6.5 0 11.2-4.1 12.1-5 0-.1.1-.2.1-.3.3-.7.6-1.3.9-2 .7.6 1.7 1.2 2.9 1.5 3.5 1 5.2.8 5.9.6.7.7 2.8 2.3 5.9 2.3.5 0 1.1-.1 1.7-.2 4.1-.8 6.3-3.7 6.8-4.5 1.1-.3 5.8-2 7.8-5.6l.9.3c.3.1 3.9 2 8.5 2 3.2 0 6.9-.9 10.4-3.8 6.1-5.2 4.4-12.6 4.3-12.6-.1-.6-.1-1.1 0-1.7-.9-.4-1.9-1.2-2.7-2.1-.1-.2-.3-.4-.4-.5-.1-.2-.2-.3-.3-.5 0 0 0-.1-.1-.1-.1-.2-.2-.5-.3-.7-.3-.7.1-1.8 0-2.5 0-.3-.1-.5-.1-.8-.4 1-.8 1.9-1.3 2.9-.1-1.3-.2-2.1-.2-2.1 0-.3-.3-.5-.6-.5s-.5.3-.5.6c0 0 .2 1.6.3 3.9.1 1.6.1 3.5 0 5.5v.6c-.1 2.7-1 5.8-1.4 7.3-.2.6-.3.9-
.3 1-.1.3.1.6.3.7h.2c.2 0 .4-.1.5-.4 0-.1.6-1.7 1.1-3.7-.4 2.1-1 3.7-1 3.8-.1.3-.3.4-.6.4h-.2c-.3-.1-.5-.5-.4-.8 0 0 .1-.2.2-.5-1.9 1.7-9 3.3-15.9 3.7 0 0 0-.1.1-.1.3-.8.4-1.6.4-2.5v-.4-.8-.1-.1l-.1-.6c0-.1-.1-.3-.1-.4l-.1-.4c0-.1-.1-.2-.1-.3l-.2-.5c0-.1-.1-.2-.1-.3l-.1-.1s0-.1-.1-.1h.3l.5-.1 3.5-.6 1.7-.3c6.1-1.1 10.1-6.9 9-12.9l-1-5.8c-.3-1.7-.9-2.7-1.7-3.3.5-.3.9-.9.8-1.6-.1-.8-.9-1.4-1.8-1.2l-4.7.8L84.5 56c-.9-.6-1.9-1.1-3-1.4-1.3-.3-2.6-.4-4-.2-1.4.3-2.7.8-3.8 1.6-.9.6-1.6 1.4-2.2 2.3L50.6 62l-5.1.9h-.1c-.8.1-1.4.9-1.2 1.8.1.8.9 1.3 1.7 1.3-.5.9-.7 2-.4 3.6l.3 1.5-5.9 1-.6.1-.6.2zm-3.1 6.3c-.1 0-.2.1-.3.1-.3 0-.7-.2-.8-.6-.2-.4-.1-1 .1-1.4h1.5c0 .3 0 .6.1.8 0 .5-.2.9-.6 1.1zm84.6-4.9c.1-1.3.1-2.6.1-3.9.2.2.4.3.6.5 0 .3.1.6.2 1 0 .2 1 4.7-1.9 8.6.4-1.6.8-3.8 1-6.2zm-5.9 9.8c.1.1.2.1.3.2-1.7.8-3.5 1.3-5.4 1.3 1.9-.5 3.7-1 5.1-1.5zm-59.4 12c-1.8 0-3.6-.4-5.4-1.1-6-2.5-6.5-8.7-6.5-8.9 0-.3-.1-.6-.1-.9.5-.7 1-1.5 1.4-2.4.5 1.4 1.1 3 1.7 4.4 1.7 4 4.3 7.1 4.4 7.2.6.7 1.4 1 2.2 1 .7 0
1.3-.2 1.8-.7l.2-.2h.7c2 0 4.7-.3 7.5-.8-1.9 1.2-4.7 2.4-7.9 2.4zm22.9-40c1.8-.3 3.6 0 5.2.8l-9.7 1.7c1.1-1.3 2.7-2.2 4.5-2.5zm8.1 3.3c-.5.9-.7 2-.4 3.6l.4 2.4c-3-1.4-6.5-1.4-9.4 0-.9.4-1.7.9-2.5 1.6l-.3.3-.4-2.1c-.3-1.6-.8-2.6-1.6-3.3l14.2-2.5zM66.6 83.8v-.4l.1-.3c5.3-1.7 8.6-7 7.6-12.6l-.1-.3c.1 0 .2-.1.4-.1.2-.1.3-.2.4-.3.6-.7 1.4-1.3 2.2-1.8 2.4-1.3 5.4-1.4 7.9 0 .3.2.7.2 1 .2.1 0 .2-.1.3-.1l.1.3c1 5.6 5.9 9.4 11.4 9.2l.2.3c0 .1.1.1.1.2v.1c0 .1.1.2.1.2l.1.4c0 .1.1.2.1.3l.1.5c0 .1 0 .2.1.4v2.6c-.5 2.6-2.6 4.5-5.9 5.2h-.1H92.4c-.1 0-.3.1-.4.1-.5.1-1 .4-1.5.7-.5.3-.9.7-1.2 1.1-.4.4-.7.8-1.1 1.1-.3.4-.7.7-1.1 1l-.9.5-.2.1c-.1 0-.1.1-.2.1l-.2.1h-.1l-.2.1h-.1l-.3.1-.4.1H83.1c-.5 0-1-.1-1.4-.2-.5-.1-.9-.3-1.4-.5-.5-.2-.9-.5-1.4-.7-.5-.2-1-.5-1.5-.6-.5-.1-1.1-.2-1.7-.1H75.4h-.1-.1-.1c-3.4.6-6.1-.5-7.5-2.8l-.1-.1-.1-.3v-.1l-.1-.1s0-.1-.1-.1l-.1-.4c0-.1 0-.1-.1-.2v-.1-.1l-.2-1c0-.1 0-.2-.1-.4l-.1-1.1v-.2zm-20.4-9.6h.2l.2 1.3c1.1 6.1 6.9 10.1 12.9 9l2.5-.4 3.2-.6h.2v.8l.1 1.2c0 .1 0 .3.1.
4v.1s.2 2 1.6 3.8c0 0 0 .1.1.1-4.5 1.2-9 1.9-12 1.9-.9 0-1.7-.1-2.3-.2.2.3.2.7-.1.9-.1.1-.3.1-.4.1-.2 0-.4-.1-.5-.2 0 0-.3-.4-.8-1 .5.6.8.9.8 1 .1.1.3.2.4.2.1 0 .3-.1.4-.2.2-.2.2-.6 0-.8 0 0-.1-.1-.2-.3-.7-.8-2.9-3.4-4.1-6.3-.1-.2-.2-.4-.3-.7-.7-1.8-1.3-3.6-1.8-5.2-.8-2.4-1.2-4.3-1.2-4.3-.1-.3-.4-.5-.7-.4-.3.1-.5.4-.4.7 0 0 .3 1.1.7 2.6-1-1-2-2-2.9-3l4.3-.5zm93-26.2c-.5-.2-1-.3-1.6-.3-.6-1.8-1.8-2.3-2.9-2.3h-.3c-.8 0-1.6.3-2.3.7-.6-.7-1.5-1.7-3-1.7-.5 0-1 .1-1.4.3-2 1-2.9 3.5-1.9 5.5l.7 1.3h-.2c-.8 0-1.8.1-2.7.4 0-1.9-.1-3.9-.4-5.8-1.1-6-4-11.7-8.5-16.3.7-13.5-6.9-26.8-12.1-27.9-.3-.1-.7-.1-1.1-.1-4.9 0-12.2 6.2-15.9 10.3-.9 1-2.2 2.6-3.4 4.4h-.5c-3.1 0-6.5.3-9.9.9-3.6.6-7 1.5-10 2.6-1.7-1.2-3.3-2.2-4.5-2.8-4.4-2.4-10.9-4.7-15.5-4.7-1.7 0-3 .3-4 .9-4.5 2.7-7.1 17.8-1.8 30.3-2.7 5.9-3.5 12.2-2.5 18.3.4 2 .9 3.9 1.7 5.8h-.4c-.8 0-1.9.1-2.8.4l.2-1.5c.4-2.2-1.1-4.4-3.4-4.7h-.5c-2 0-2.9 1.7-3.3 2.6-.4-.1-.8-.2-1.2-.2-.5 0-1 .1-1.4.3-1 .4-2.1 1.2-2.1 3.1-.6.2-1.1.4-1.5.8-1.2 1.1-1.9 3-.1
5.3.2.2.2.4.3.6.1.3.3.8.8 1.3.1.1.3.4.6.7.9 1.1 1.8 2.1 2.2 2.5l.6.6 1 1c.4 1 .8 1.8 1.4 2.5.1.2.2.3.4.5.2.3.3.5.5.8 1.5 1.9 3 3.3 4.6 4 .8 4.2 3.6 12.8 13.5 17.1 3.3 1.4 6.8 2.1 10.2 2.1 1.3 0 2.7-.1 4-.3-1.2 3.7-2.1 7.1-2.6 10-.9-.3-1.9-.7-3.1-1-.3-.2-.4-.4-.5-.4-.6-.5-1.4-.8-2.2-.8-.4 0-.9.1-1.3.2-2.1-.4-4.2-.7-6.4-.9-.4-.2-.7-.4-1.1-.5-.2 0-.4-.1-.7-.1-.5 0-1 .1-1.4.3-1.1-.1-2.2-.1-3.3-.1h-2.6c-.5-.3-1.1-.4-1.6-.4-.7 0-1.3.2-1.8.5-.1 0-.1.1-.2.1-2.1.2-4.2.6-6.2 1.1-.2 0-.4-.1-.7-.1-.5 0-1 .1-1.4.3-.3.1-.6.3-.9.6-7.7 2.4-12.1 5.9-12.5 6.3-.3.3-.6.6-.7.9-2.6 2.1-4.2 4.3-4.7 6.7-1.1 5.5 3.4 11.3 11.7 15.4.1.5.4 1 .7 1.4.7.8 1.6 1.2 2.6 1.2.6 0 1.2-.2 1.8-.5 2.7.9 5.5 1.5 8.3 1.9.1.2.3.3.4.4.6.5 1.4.8 2.2.8.9 0 1.7-.3 2.4-.9 1 0 2-.1 2.9-.1 2.1-.2 4.1-.5 6.2-1 .2.2.5.3.7.5.5.2.9.3 1.4.3 1.4 0 2.6-.8 3.2-2.1 0 0 0-.1.1-.1 1.9-.6 3.8-1.3 5.6-2.1.1.1.2.1.3.2.5.3 1.1.4 1.6.4 1.3 0 2.5-.7 3.1-1.9 0-.1.3-.6.6-1.5.6 3.2 1.6 6.9 3.3 10.2 2.7 5.4 4.3 7.3 6.3 7.3.7 0 1.4-.3 2-.8.8-.9 1.2-2.2
1.1-4.5 0-1.6-.1-4.5-.2-7.4 1.9.4 3.9.7 6.2.9 1.9.1 3.7.2 5.6.2 5.9 0 11.4-.8 16.1-2.2-.1 2.8-.2 5.5-.2 7-.1 2.3.3 3.6 1.1 4.5.5.5 1.2.8 2 .8 2 0 3.6-1.8 6.3-7.3 2.4-4.8 3.4-10.4 3.9-14.3 2.9-7.6.4-22.8-2.3-30.7-1.1-3.3-2.2-6.3-3.3-9.1.6 0 1.2.1 1.8.1 6.2 0 11.8-2.1 16.6-6.1 8.2-6.9 8.4-16.1 7.9-20.3 1.3-1.2 2.4-2.9 3.3-5.2l.3-.9c.1-.2.2-.4.2-.5.3-.9.5-1.8.6-2.8l.9-1.8.2-.3c.3-.6.8-1.7 1.4-3.1.1-.3.3-.6.3-.8.3-.6.3-1.1.4-1.5 0-.2 0-.4.2-.6 1.2-2.7 0-4.4-1.5-5.1zm-.5 4.3c-.4 1.1-.2 1.4-.5 2-.3.7-1.3 3-1.7 3.8-.1.2-.7 1.2-1.3 2.5 0 .9-.2 1.8-.5 2.7-.1.2-.1.4-.2.6l-.3.9c-.7 1.9-1.8 4-3.6 4.9.5 2.6 1.6 12.4-6.9 19.6-5.1 4.3-10.5 5.6-15.1 5.6-1.4 0-2.8-.1-4-.3-1.2-2.5-2.8-4.8-2.9-4.9-.2-.2-.5-.3-.8-.1-.2.2-.3.5-.1.8 0 0 2.1 2.8 3.2 5.7 0 0 0 .1.1.1.1.2.1.4.2.6l.1.1c1.4 3.4 2.6 6.9 3.7 10.1 2.9 8.6 4.9 23.1 2.2 29.4-.4 3.7-1.4 9.2-3.7 13.9-2.2 4.3-3.5 6-4.3 6h-.2l-.1-.1-.1-.1s0-.1-.1-.1c0-.1-.1-.2-.1-.3-.2-.5-.2-1.3-.2-2.3.1-1.9.2-5.6.3-9.1 2.8-1.3 4.6-2.8 4.6-2.9.2-.2.2-.6 0-.8-.2-.2-.6-
.2-.8 0 0 0-1.8 1.6-4.4 2.7-4.6 1.8-10.6 3-17.9 3-1.7 0-3.5-.1-5.4-.2-3.4-.3-6.3-.8-8.7-1.5v.2c-2.1-.9-3.8-2.3-3.8-2.4-.2-.2-.6-.2-.8 0-.2.2-.2.6 0 .8.1.1 2.1 1.9 4.6 2.7.1 3.4.2 7 .3 8.9.1 1.8-.2 3-.8 3-.1 0-.2 0-.3-.1-.1 0-.2-.1-.3-.2l-.1-.1-.3-.3-.1-.1c-.1-.1-.2-.3-.3-.4l-.2-.2c-.1-.1-.2-.3-.3-.5-.1-.1-.2-.2-.2-.4-.1-.2-.2-.3-.3-.5-.1-.2-.2-.3-.3-.5-.1-.1-.2-.3-.2-.4-.4-.7-.8-1.4-1.2-2.2-.2-.4-.4-.9-.6-1.4 0-.1 0-.1-.1-.1-.2-.4-.4-.9-.5-1.3 0-.1-.1-.2-.1-.2-.2-.5-.3-.9-.5-1.4 0-.1 0-.1-.1-.2-.1-.5-.3-.9-.4-1.4 0-.1 0-.1-.1-.2-.1-.5-.2-.9-.4-1.4v-.1c-.1-.5-.2-1-.3-1.4v-.1c-.2-1.3-.4-2.5-.6-3.6-1 .7-2.2 1.4-3.5 2.1-.4 1.2-.7 1.9-.8 2-.2.4-.7.7-1.1.7-.2 0-.4 0-.6-.1-.4-.2-.6-.5-.6-.9-2.4 1.1-5 2.2-8 3.1-.2.6-.4 1-.4 1-.2.5-.7.7-1.1.7-.2 0-.3 0-.5-.1-.4-.2-.6-.5-.7-.9-1.7.4-3.6.8-5.4 1h-.1c-.6.1-1.2.2-1.9.2-1 .1-1.9.1-2.9.1h-.9c-.2.3-.3.4-.3.5-.2.3-.6.5-1 .5-.3 0-.6-.1-.8-.3-.3-.2-.4-.5-.4-.8-3.5-.3-7-1.1-10.2-2.3l-.5.5c-.2.2-.5.3-.8.3-.4 0-.7-.1-1-.4-.3-.4-.4-.9-.2-1.3-4.6-2.1-8.4-4
.9-10.4-7.9-.1-.1-.1-.2-.2-.3l-.3-.6c-.1-.1-.1-.3-.2-.4-.1-.1-.1-.3-.2-.4-.1-.2-.1-.3-.2-.5 0-.1-.1-.2-.1-.3-.1-.2-.1-.4-.1-.6v-.3c0-.2-.1-.4-.1-.6v-.1c0-.5 0-1.1.1-1.6.4-2.2 2.1-4.1 4.4-5.8 0-.2 0-.4.2-.6.3-.2 4.6-3.8 12.4-6.1.1-.2.3-.4.5-.5.2-.1.3-.1.5-.1s.4.1.6.2c2.2-.6 4.6-1 7.3-1.2.1-.2.2-.3.4-.4.2-.1.4-.2.7-.2.4 0 .7.2 1 .5.3 0 .6 0 .9-.1h2.3c1.3 0 2.6 0 3.8.1.2-.2.5-.3.9-.3h.2c.1 0 .4.2.7.4 2.9.2 5.4.6 7.6 1.1.2-.2.6-.4.9-.4.3 0 .5.1.8.3l.7.7c2.6.7 4.3 1.4 5.3 1.8v.1c0 .4.1.8.1 1.3.2 3 .7 7.5 1.4 11.6 0 .3.3.5.5.5h.1c.3-.1.5-.3.5-.6-1-5.8-1.5-12.1-1.6-14.3.5-3.5 1.6-7.4 2.9-11.2 0-.1.1-.2.1-.3 2.2-6.1 4.2-8.1 4.2-8.1.2-.2.2-.6 0-.8-.2-.2-.6-.2-.8 0-.1.1-1.7 1.7-3.6 6.3-1.9.5-4 .9-6.3.9-2.9 0-6-.6-9.3-2-10.2-4.4-12.1-14.1-12.4-16.7-2-.4-3.6-2-4.8-3.6-.2-.2-.3-.5-.5-.7-.1-.1-.3-.3-.4-.5-.2-.3-.5-.7-.7-1.1 0-.1-.1-.1-.1-.2-.2-.4-.3-.7-.5-1.1v-.1l-2-2c-.6-.6-2.2-2.6-2.7-3.1-.1-.1-.1-.1-.1-.2-.3-.4-.3-.7-.7-1.3-.1-.1-.1-.2-.2-.3-.1-.1-.2-.2-.2-.3-.5-.8-.6-1.4 0-2 .1-.1.1-.1.2-.1l.
1-.1c.1-.1.3-.1.5-.2H21.6c.5 0 1 .2 1.3.6l.1.1c-.1-.5-.1-1.2-.2-1.8-.2-.9-.3-1.6.6-2H24c.2 0 .4.1.7.1 0 0 .1 0 .1.1.1 0 .2.1.2.1.1.1.2.2.3.2l.1.1c.1.1.2.3.2.4 0 0 .2.5.4 1.1 0-.3.1-.5.1-.7.2-1 .6-1.3.9-2 .3-.7.6-1.9 1.5-1.9h.2c.5.1.9.4 1.2.8.3.4.4.9.3 1.4l-.5 3.2-.4 2.3c-.5.9-1.2 2.1-1.7 3.4-.1.3.1.6.3.7h.2c.2 0 .4-.1.5-.4.7-1.9 1.7-3.5 2.2-4.2.5-.3 1-.7 1.6-1 .6-.3 1.6-.5 2.4-.5.3 0 .7 0 .9.1.5.1 1.2.6 1.9.6.5.1 1.2.1 1.6.7.1.2.2.4.2.8l.6-.1c-.9-1.4-1.7-2.9-2.4-4.4-.1-.3-.2-.5-.3-.8-.1-.2-.1-.4-.2-.6-.1-.4-.3-.7-.4-1.1 0-.1-.1-.3-.1-.4-.1-.5-.3-1-.4-1.5-.1-.6-.3-1.1-.4-1.7-.1-.3-.1-.6-.1-.9 0-.3-.1-.7-.1-1 0-.4-.1-.7-.1-1.1v-.9V57v-.9c0-.6.1-1.2.1-1.8 0-.3.1-.7.1-1 .1-.3.1-.7.2-1 .1-.3.1-.6.2-1 .1-.3.1-.7.2-1 .1-.4.2-.7.3-1.1.1-.3.2-.6.3-1 .2-.6.4-1.1.6-1.7.1-.3.2-.6.4-.9.1-.3.3-.7.4-1 .1-.2.1-.3.2-.5 0-.1.1-.1.1-.2.1-.1.1-.2.2-.3 2.7-4.5 5.9-7.4 6-7.4.2-.2.3-.6 0-.8-.2-.2-.6-.3-.8 0-.1.1-2.2 2-4.5 5.1-.5.7-1 1.4-1.5 2.2 0 .1-.1.1-.1.2-4.7-11.6-2.2-25.2 1.1-27.1.7-.4 1.6-.6 2.8-.6
3.8 0 9.8 2 14.4 4.5 1.5.8 3.4 2 5.2 3.4 2.9-1.1 6.5-2.1 10.8-2.9 3.6-.6 6.7-.9 9.5-.9h1.7c1.2-2 2.6-3.8 3.8-5.1 4.3-4.8 10.7-9.6 14.2-9.6.2 0 .4 0 .6.1 3.8.8 10.8 12.8 10.3 25.3l-.1-.1c-.7-.6-1.5-1.1-2.2-1.6-2.6-1.7-4.9-2.6-5-2.7-.3-.1-.6 0-.7.3-.1.3 0 .6.3.7.1 0 5.2 2.1 9.1 6l.2.2c1 1.1 1.9 2.3 2.7 3.5 0 .1.1.1.1.2.4.6.7 1.2 1.1 1.7l.1.1c.7 1.3 1.3 2.6 1.8 4 0 .1.1.2.1.3.2.6.4 1.2.6 1.9 0 .1 0 .2.1.3.2.7.3 1.4.5 2.2l.3 2.4c.2 2.4.1 4.8-.3 7.1.3-.2.6-.4.9-.5.7-.3 1.2-.9 1.6-1.2.6-.4 1.9-.7 2.8-.7h.5c1 .2 2 .4 2.8.8 1.8 1.5 3.5 3 3.7 3.4.1.2.3.3.5.3.1 0 .2 0 .2-.1.3-.1.4-.5.2-.7-.4-.8-3.1-3-4.4-4.2l-.6-1.3-1.5-2.9c-.5-.9-.1-2.1.8-2.5.1-.1.3-.1.4-.1.7 0 1.3.9 1.7 1.4.5.5.9.7 1.3 1.4.1.1.1.2.2.3l.3.6c0-.7.1-1.1.1-1.2.1-.9.8-1.6 1.7-1.6h.1c.4 0 .6.2.8.4.3.3.3.8.4 1.4 0 .1 0 .3.1.4 0 .1 0 .2.1.3.1.4.2.7.2 1.1l.1-.1c.3-.6.9-1 1.6-1 .2 0 .5 0 .7.2.2.1.4.2.5.4.3.1.3.7-.1 1.5z" fill="url(#b)" transform="translate(145 67)"/></g></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/figure_screenshots.svg b/browser/extensions/onboarding/content/img/figure_screenshots.svg
new file mode 100644
index 000000000000..f4930d09f7af
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_screenshots.svg
@@ -0,0 +1,191 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="281" height="233">
+ <defs>
+ <linearGradient id="a" x1="-26.7072552%" x2="121.200691%" y1="-8.21456664%" y2="115.364749%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="b" x1="-171.534367%" x2="377.694136%" y1="-258.916232%" y2="507.082022%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="c" x1="-275.615152%" x2="393.814483%" y1="-214.880097%" y2="329.931438%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="d" x1="-71.2230562%" x2="141.268437%" y1="-46.5567621%" y2="122.213199%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="e" x1="-912.187374%" x2="706.872366%" y1="-223.131903%" y2="247.7375%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="f" x1="-636.509606%" x2="265.115932%" y1="-364.308744%" y2="178.753736%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="g" x1="-96.7324958%" x2="214.858961%" y1="-489.128132%" y2="600.29142%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="h" x1="-370.226425%" x2="176.655533%" y1="-420.236682%" y2="206.08556%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="i" x1="-1573.85207%" x2="2621.18334%" y1="-918.807829%" y2="1582.542%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="j" x1="-1977.10979%" x2="2217.92561%" y1="-1158.35597%" y2="1342.99386%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="k" x1="-635.169191%" x2="1018.69953%" y1="-1184.44408%" y2="1785.60576%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="l" x1="-278.76866%" x2="377.256589%" y1="-697.981967%" y2="835.635246%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="m" x1="-553.131633%" x2="647.619338%" y1="-1374.34047%" y2="1418.49315%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="n" x1="-450.59361%" x2="546.286439%" y1="-895.950857%" y2="958.91224%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="o" x1="-511.211278%" x2="295.07392%" y1="-745.273546%" y2="396.265912%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="p" x1="-871.182847%" x2="303.781403%" y1="-595.928571%" y2="241.5435%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="q" x1="-450.336951%" x2="307.764971%" y1="-505.416691%" y2="315.448433%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="r" x1="-2519.79056%" x2="1944.50093%" y1="-1090.70814%" y2="890.815528%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="s" x1="-134.127826%" x2="165.330874%" y1="-297.102666%" y2="260.202663%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="t" x1="-1132.52358%" x2="304.180944%" y1="-1559.01765%" y2="393.843988%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="u" x1="-1884.94918%" x2="1592.74001%" y1="-342.289711%" y2="381.222953%">
+ <stop stop-color="#E6FCFF" offset="0%"/>
+ <stop stop-color="#B5F2FF" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="v" x1="-109.932792%" x2="195.629347%" y1="-425.144051%" y2="431.622036%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="w" x1="-813.648281%" x2="368.736119%" y1="-1076.38789%" y2="459.249729%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="x" x1="-1092.12785%" x2="635.82518%" y1="-4587.46665%" y2="2425.66052%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="y" x1="-415.250984%" x2="1490.35841%" y1="-442.448072%" y2="1582.67684%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="z" x1="-167.167389%" x2="492.546376%" y1="-2085.55413%" y2="4392.09342%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="A" x1="-2989.85248%" x2="1926.86535%" y1="-1363.11821%" y2="921.90878%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ <linearGradient id="B" x1="-2586.45105%" x2="2652.41027%" y1="-792.93501%" y2="883.790987%">
+ <stop stop-color="#00C8D7" offset="0%"/>
+ <stop stop-color="#008EA4" offset="100%"/>
+ </linearGradient>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <g fill="#D7D7DB" fill-rule="nonzero">
+ <path d="M204.3 76.7h-77c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h77c.6 0 1.1.5 1.1 1.1 0 .6-.4 1.1-1.1 1.1zM193.9 71h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zM176.4 81.7H163c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zm-22.2 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-7.8 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-11.2 0h-13.4c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-22.2 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-7.8 0H104c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.2.6-.5.6zm-11.2 0H80.6c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6H94c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-22.3 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-7.8 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6z"/>
+ </g>
+ <g fill-rule="nonzero">
+ <path fill="#F9F9FA" d="M152.3 47.8h23.8s-7.4-16.6 8.3-18.8c14.1-1.9 19.6 12.5 19.6 12.5s1.7-8.3 10-6.7c8.3 1.6 14.3 14.8 14.3 14.8H249"/>
+ <path fill="#D7D7DB" d="M249.5 45.8H245c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h4.5c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm-14.5 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5.6 0h-.6c-.2 0-.4-.1-.5-.3-.1-.2-.6-1.1-1.3-2.3-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.6.9 1 1.7 1.2 2.1h.3c.3 0 .6.2.6.6 0 .4-.4.5-.7.5zm-52.9-.7H175c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h.6c-.1-.3-.2-.6-.4-1-.1-.3.1-.6.4-.7.3-.1.6.1.7.4.3 1 .6 1.7.6 1.7.1.2.1.4 0 .5-.1.1-.3.3-.4.3zm-10.4 0h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm8.7-6.1c-.3 0-.5-.2-.6-.5 0-.4-.1-.8-.1-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.1 1.1.1.3-.1.6-.5.6.1 0 .1 0 0 0zm29.2-1.1c-.2 0-.4-.1-.5-.3-.1-.3-.3-.6-.5-1-.1-.3 0-.6.2-.8.3-.1.6 0 .8.2.2.4.4.7.5 1 .1.3 0 .6-.3.7-.1.2-.2.2-.2.2zm17.9-1.4c-.1 0-.3-.1-.4-.2-2.4-2.3-4.8-3.7-7.2-4.1-1.6-.3-3.1-.2-4.3.2-.3.1-.6-.1-.7-.4-.1-.3.1-.6.4-.7 1.4-.5 3.1-.6 4.9-.2 2.6.5 5.2 2 7.7 4.4.2.2.2.6 0 .8-.1.1-.2.2-.4.2zM201 33.2c-.2 0-.3-.1-.4-.2-.7-.9-1.4-1.7-2.2-2
.4-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0 .8.7 1.6 1.6 2.3 2.5.2.2.2.6-.1.8-.2 0-.3.1-.4.1zm-22.8-4.3c-.2 0-.3-.1-.4-.2-.2-.2-.2-.6.1-.8 1.7-1.4 4.1-2.3 6.9-2.7 2.2-.3 4.3-.2 6.3.2.3.1.5.4.4.7-.1.3-.4.5-.7.4-1.9-.4-3.9-.5-5.9-.2-2.7.4-4.8 1.2-6.4 2.4-.1.2-.2.2-.3.2z"/>
+ <path fill="#F9F9FA" d="M250.2 50.1h-97.9c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h97.9c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1z"/>
+ </g>
+ <g fill-rule="nonzero">
+ <path fill="#F9F9FA" d="M49.3 29.4h13.2s-4.1-9.2 4.6-10.4c7.8-1.1 10.9 7 10.9 7s.9-4.6 5.6-3.8c4.6.9 8 8.3 8 8.3h11.5"/>
+ <path fill="#D7D7DB" d="M62.9 27.9H49.7c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h12.8s.1-.1.2-.1c.3-.1.6 0 .7.3l.1.1c.1.2.1.4 0 .5-.2.3-.4.4-.6.4zm36.6-.1h-3.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .3-.3.6-.6.6zm-20.9-3.6h-.2c-.3-.1-.5-.4-.4-.7.3-.9 1.5-4 4.9-4 .4 0 .8 0 1.2.1 1.8.3 3.6 1.5 5.4 3.4.2.2.2.6 0 .8-.2.2-.6.2-.8 0-1.6-1.7-3.2-2.7-4.8-3-.4-.1-.7-.1-1-.1-2.6 0-3.5 2.2-3.8 3.2-.1.1-.3.3-.5.3zm-15.2-4.9c-.1 0-.3-.1-.4-.2-.2-.2-.2-.6 0-.8.8-.8 1.8-1.4 3.1-1.7.3-.1.6.1.7.4.1.3-.1.6-.4.7-1.1.3-2 .8-2.6 1.4-.1.2-.3.2-.4.2zm8.4-1.5h-.2c-.3-.1-.7-.2-1-.3-.3-.1-.5-.3-.4-.7.1-.3.4-.5.7-.4.4.1.8.2 1.1.3.3.1.5.4.4.7-.2.3-.4.4-.6.4z"/>
+ <path fill="#F9F9FA" d="M104 31.6H49.6c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1H104c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1z"/>
+ </g>
+ <g fill-rule="nonzero">
+ <path fill="#FFF" d="M19.6 169.1c-2.8 0-5-2.2-5-4.8V46c0-3 2.4-5.4 5.4-5.4h127c3 0 5.4 2.4 5.4 5.4v118.3c0 2.6-2.3 4.8-5 4.8H19.6z"/>
+ <path fill="#D7D7DB" d="M146.9 41.8c2.3 0 4.2 1.9 4.2 4.2v118.3c0 2-1.8 3.7-3.9 3.7H19.6c-2.2 0-3.9-1.6-3.9-3.7V46c0-2.3 1.9-4.2 4.2-4.2h127zm0-2.2h-127c-3.6 0-6.5 2.9-6.5 6.5v118.3c0 3.3 2.8 5.9 6.2 5.9h127.6c3.4 0 6.2-2.7 6.2-5.9V46c0-3.5-2.9-6.4-6.5-6.4z"/>
+ </g>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M145.8 62.9V161c0 1-.1 1.2-.1 1.2s-.2.1-1.2.1h-122c-1 0-1.2-.1-1.2-.1s-.1-.2-.1-1.2V62.9h124.6zm1.1-1.2H20v99.2c0 2 .4 2.5 2.5 2.5h122c2 0 2.5-.4 2.5-2.5V61.7h-.1z"/>
+ <g fill="#D7D7DB" fill-rule="nonzero">
+ <circle cx="3.8" cy="3.7" r="2.9" transform="translate(23 48)"/>
+ <circle cx="3" cy="3.7" r="2.9" transform="translate(33 48)"/>
+ <path d="M115.3 54.9H51.5c-1.7 0-3.1-1.4-3.1-3.1v-.3c0-1.7 1.4-3.1 3.1-3.1h63.8c1.7 0 3.1 1.4 3.1 3.1v.3c0 1.8-1.4 3.1-3.1 3.1z"/>
+ <g>
+ <circle cx="3.8" cy="3.7" r="2.9" transform="translate(127 48)"/>
+ <circle cx="3.1" cy="3.7" r="2.9" transform="translate(137 48)"/>
+ </g>
+ </g>
+ <g transform="translate(149 84)">
+ <ellipse cx="42.7" cy="142" fill="#EDEDF0" fill-rule="nonzero" rx="42.5" ry="6.5"/>
+ <path fill="#F9F9FA" fill-rule="nonzero" d="M121.2 99.6c-1.3-3.1-4.3-5.2-7.7-5.2-.7 0-1.4.1-2.1.3-.8 0-3.1-.3-7.2-2-1.7-.7-4.8-3.9-8.4-10.5 5.2-19.9 5.5-36.8.7-50.3-.4-1-.9-2.1-1.5-3.2l-.3-1.4 2-1.7c1.6-1.4 2.3-3.5 1.7-5.6-.3-1.2-1-2.2-2-2.9 0-.3 0-.6-.1-.9-.4-2.3-2.2-4.1-4.5-4.4-.4-.1-10.6-1.7-17.1-1.7h-.4l-1.7-2.8C70 3.1 65.5.6 60.5.6c-2.6 0-5.2.7-7.5 2.1-2.6 1.6-4.5 3.9-5.7 6.7-6 .7-12.1 2.3-18.2 4.7l-3.4-1.4c-1.7-.7-3.5-1.1-5.4-1.1-5.8 0-10.9 3.5-13.1 8.8-2.7 6.6-.1 14 5.8 17.5-1.1 5.9-1.5 12.4-1 19.6.6 9-2.2 13.5-5.1 18.2-4.4 7.1-9.4 15.1 0 33.8 0 2.2.1 4.2.2 5.8 1.3 11.8 4.6 17.7 10 17.7.9 0 1.9-.2 2.7-.6 2.2-1.1 3.3-2.6 5-9.9 9.3 3.1 21.2 5.8 30.9 6.9-1.7 7.6-1.5 9.4 0 11.4 1.2 1.5 3 2.4 5 2.4 4.1 0 8.8-4.1 14-12.1 1.3-2.1 2.8-5 4.4-8.5 1.4-2.4 5.5-9.7 10-20.9 2.8 2.9 5.6 5 8.6 6.2 5.2 2.1 9.8 3.2 13.5 3.2 2.5 0 4.2-.5 5.1-.9 4.6-1.5 6.6-6.4 4.9-10.6z"/>
+ <path d="M115.2 101.4c-.4-.9-1.5-1.4-2.4-1-.2.1-.6.1-1.2.1-1.4 0-4.6-.3-9.8-2.4-5.5-2.2-10.3-10.6-12.7-15.5-.1-.2-.1-.5-.1-.8 5.4-19.5 5.9-35.8 1.4-48.4-.3-.8-.7-1.8-1.3-2.7-.1-.1-.1-.2-.1-.3L87.7 25c-.1-.4 0-.8.4-1.1l2.6-2.2-5.8-.9c-.5-.1-.9-.4-.9-.9s.2-.9.6-1.2l3-1.6c-3.5-.5-8.9-1.1-12.7-1.1-1.1 0-2 .1-2.6.2l-.4.1c-.4.1-.9-.1-1.1-.5l-3.4-5.5C66 8 63.5 6.7 60.9 6.7c-1.4 0-2.8.4-4.1 1.2-2.2 1.4-3.5 3.7-3.6 6.3 0 .6-.5 1-1.1 1.1-7.2.4-14.7 2.2-22.2 5.4-.3.1-.6.1-.9 0l-5.4-2.2c-.9-.4-1.9-.6-2.9-.6-3.1 0-5.9 1.9-7.1 4.8-1.6 3.9.3 8.4 4.2 10l2.3.9c.5.2.8.8.6 1.3-1.8 6.2-2.4 13.6-1.8 21.9.7 11.1-2.9 16.9-6.1 22.1-4.3 6.9-7.7 12.3.9 28.6.1.2.1.4.1.5-.1 2.6 0 4.7.2 6.3.8 7.8 2.6 11.1 3.4 11.8.4-.8 1.2-3.3 2.9-11.3.1-.3.3-.6.6-.8.2-.1.3-.1.5-.1.1 0 .3 0 .4.1 10.8 4.5 29.6 8.7 41.2 9.1.3 0 .7.2.9.4.2.3.3.6.2.9-2.1 8.3-2.5 11-2.5 11.9 1.1-.3 4.2-2.7 8.3-9.1 1.2-1.9 2.5-4.5 4-7.9 0 0 0-.1.1-.1 3.3-5.6 8.7-16.6 13-29.4.1-.4.5-.7.9-.8.4 0 .9.2 1.1.5 3.7 6.2 7.8 10.4 11.7 12 5.5 2.2 9.1 2.7
11.1 2.7 1.6 0 2.4-.3 2.7-.4.6-.4 1-1.5.7-2.4z"/>
+ <path fill="url(#a)" fill-rule="nonzero" d="M114.6 98c-.8-2.1-2.9-3.4-5.1-3.4-.6 0-1.1.1-1.7.3-.7 0-3.4 0-8.7-2.2-3-1.2-6.8-6-10.3-12.8 5.4-19.8 5.7-36.5 1-49.7-.3-1-.8-2-1.4-3l-.9-3.4 3.3-2.8c.8-.7 1.1-1.7.8-2.7-.3-1-1.1-1.7-2.1-1.9l-.7-.1c.5-.6.8-1.4.6-2.2-.2-1.1-1-2-2.1-2.1-.1 0-10.3-1.6-16.7-1.6-.7 0-1.3 0-1.9.1l-2.6-4.2C64 2.9 60.4.9 56.4.9c-2.1 0-4.2.6-6 1.7-2.5 1.6-4.3 4.1-5 6.9-6.6.6-13.5 2.3-20.3 5.1l-4.4-1.8c-1.4-.6-2.8-.8-4.3-.8-4.7 0-8.8 2.8-10.6 7.1-2.4 5.8.4 12.5 6.2 14.9l.2.1c-1.4 6.1-1.9 13.2-1.4 20.9.7 9.9-2.5 15-5.6 19.9-4.3 6.9-8.7 14 .4 31.7 0 2.4 0 4.5.2 6.2.6 5.7 2.4 15.2 7.2 15.2.5 0 1-.1 1.5-.4 1.3-.6 2.1-1.5 4.2-11.1 10.3 3.8 25.5 7.2 36.4 8.1-2.6 10.4-2 11.1-1.2 12.2.7.9 1.7 1.4 2.8 1.4 4.1 0 9-6.8 11.6-10.8 1.3-2 2.7-4.8 4.2-8.3C75.5 114 80 104.9 84 94c3.4 4.5 6.9 7.6 10.6 9.1 4.9 2 9.1 3 12.5 3 2 0 3.3-.4 4.1-.7 3.2-1.4 4.5-4.6 3.4-7.4zm-4.4 3.8c-.3.1-1.1.4-2.7.4-2 0-5.6-.5-11.1-2.7-3.9-1.6-8-5.7-11.7-12-.2-.4-.6-.6-1.1-.5-.4 0-.8.3-.9.8-4.3 12.8-9.
7 23.9-13 29.4 0 0 0 .1-.1.1-1.5 3.4-2.8 6.1-4 7.9-4.1 6.4-7.1 8.8-8.3 9.1 0-.9.4-3.6 2.5-11.9.1-.3 0-.7-.2-.9-.2-.3-.5-.4-.9-.4-11.6-.4-30.4-4.6-41.2-9.1-.1-.1-.3-.1-.4-.1-.2 0-.4 0-.5.1-.3.2-.5.4-.6.8-1.7 8.1-2.5 10.6-2.9 11.3-.8-.7-2.6-4-3.4-11.8-.2-1.7-.2-3.8-.2-6.3 0-.2 0-.4-.1-.5-8.5-16.3-5.2-21.7-.9-28.6 3.2-5.1 6.8-11 6.1-22.1-.5-8.3.1-15.7 1.8-21.9.2-.5-.1-1.1-.6-1.3l-2.3-.9c-3.9-1.6-5.8-6.1-4.2-10 1.2-2.9 4-4.8 7.1-4.8 1 0 2 .2 2.9.6l5.4 2.2c.3.1.6.1.9 0 7.5-3.2 15-5 22.2-5.4.6 0 1-.5 1.1-1.1.1-2.6 1.5-4.9 3.6-6.3 1.2-.8 2.6-1.2 4.1-1.2 2.7 0 5.1 1.4 6.5 3.6l3.4 5.5c.2.4.7.6 1.1.5l.4-.1c.7-.1 1.6-.2 2.6-.2 3.8 0 9.2.6 12.7 1.1l-3 1.6c-.4.2-.7.7-.6 1.2.1.5.5.8.9.9l5.8.9-2.6 2.2c-.3.3-.5.7-.4 1.1l1.3 5.4c0 .1.1.2.1.3.6 1 1 1.9 1.3 2.7 4.5 12.7 4 29-1.4 48.4-.1.3 0 .5.1.8 2.4 4.8 7.1 13.2 12.7 15.5 5.2 2.1 8.4 2.4 9.8 2.4.6 0 1 0 1.2-.1.9-.4 2 .1 2.4 1 .6.9.2 2-.7 2.4z" transform="translate(4 2)"/>
+ <path fill="url(#b)" fill-rule="nonzero" d="M36.6 40.6c-1.1 0-2.2-.2-3.3-.7l-16.2-6.6c-4.5-1.8-6.7-7-4.8-11.5 1.8-4.5 7-6.7 11.5-4.8L40 23.6c4.5 1.8 6.7 7 4.8 11.5-1.4 3.4-4.7 5.5-8.2 5.5z"/>
+ <path fill="url(#c)" fill-rule="nonzero" d="M70.8 39.3c-2.9 0-5.8-1.5-7.5-4.2L53.1 18.6c-2.6-4.1-1.3-9.6 2.8-12.1C60 3.9 65.5 5.2 68 9.3l10.2 16.5c2.6 4.1 1.3 9.6-2.8 12.1-1.4 1-3 1.4-4.6 1.4z"/>
+ <path fill="url(#d)" fill-rule="nonzero" d="M28.6 19.4c-2.2.9-12.8 10.5-11.1 37.1 1.7 26.2-21.6 21.8-3.8 53.4 3.9 6.9 50.2 17.7 58.6 12.7 2.5-1.5 31.6-54.6 19.1-89.8-4.1-11.5-28.5-28-62.8-13.4z"/>
+ <path fill="url(#e)" fill-rule="nonzero" d="M14.3 87.5s-2.6 17.8-1.7 26.6c1 8.8 3.3 13.7 5.1 12.8 1.7-.8 6.2-26.8 6.2-26.8l-9.6-12.6z"/>
+ <path fill="url(#f)" fill-rule="nonzero" d="M80.7 103s-5.5 17.1-10.3 24.6c-4.8 7.5-9.1 10.8-10.2 9.3-1.2-1.5 6.2-26.8 6.2-26.8l14.3-7.1z"/>
+ <path fill="url(#g)" fill-rule="nonzero" d="M33.5 19c7.8-4 28.9-2.7 38.4-4.1C77 14.1 91 16.3 91 16.3l-6 3.2 8.2 1.2-4.5 3.8 1.8 7.3-1.3-.7-46.3-12.8-9.4.7z"/>
+ <path fill="url(#h)" fill-rule="nonzero" d="M111.4 105.1c-2.3 0-6-.6-11.5-2.8-10-4-16.7-20.9-17.4-22.9-.6-1.5.2-3.2 1.7-3.8 1.5-.6 3.2.2 3.8 1.7 1.7 4.5 7.7 16.9 14.1 19.5 7.1 2.9 10.2 2.3 10.2 2.3 1.5-.6 3.2.1 3.8 1.6.6 1.5-.1 3.2-1.6 3.8-.4.3-1.4.6-3.1.6z"/>
+ <path fill="#FFF" fill-rule="nonzero" d="M35.4 29.8c-8.3 5.5-3.2 72.6 2.7 79.8 9.5 11.8 31.7 9.3 34.6 3 1.1-2.3 26-48.2 14.3-79.8-3-8-22.5-22.3-51.6-3z"/>
+ <path fill="url(#i)" fill-rule="nonzero" d="M50.3 43.8c.9.2 1.4 1.1 1.2 1.9l-.8 3.5c-.2.9-1.1 1.4-1.9 1.2-.9-.2-1.4-1.1-1.2-1.9l.8-3.5c.2-.9 1.1-1.4 1.9-1.2z"/>
+ <path fill="url(#j)" fill-rule="nonzero" d="M81.4 44.8c.9.2 1.4 1.1 1.2 1.9l-.8 3.5c-.2.9-1.1 1.4-1.9 1.2-.9-.2-1.4-1.1-1.2-1.9l.8-3.5c.2-.9 1-1.4 1.9-1.2z"/>
+ <path fill="url(#k)" fill-rule="nonzero" d="M48.9 57.6c-.5 0-1-.1-1.5-.2-3.5-.8-4.7-3.9-4.7-4.1-.3-.8.1-1.6.9-1.9.8-.3 1.6.1 1.9.9 0 .1.7 1.8 2.6 2.2 1.9.5 3.3-.8 3.3-.8.6-.6 1.5-.5 2.1 0 .6.6.5 1.5 0 2.1-.2.1-2 1.8-4.6 1.8z"/>
+ <path fill="url(#l)" fill-rule="nonzero" d="M56.6 69.2c-.8 0-1.4-.6-1.5-1.3-.1-.8.5-1.5 1.3-1.6 8.9-.7 17.1-2.5 18-3.8 1-1.7 1.2-4 1.2-4.1 0-.8.7-1.4 1.4-1.4.8 0 1.4.5 1.5 1.3.1 1.3.6 3.4 1.2 4.1 1.1 1.3 2.3 1.2 2.3 1.2.8 0 1.5.6 1.6 1.4.1.8-.6 1.5-1.4 1.6-1 .1-3.2-.3-4.8-2.3-.1-.2-.3-.4-.4-.6-.1.1-.1.2-.2.3-2 3.3-14.8 4.7-20.3 5.2h.1z"/>
+ <g fill-rule="nonzero">
+ <path fill="url(#m)" d="M2.4 4.3C1.3 5 7.7 8.2 8.6 8.2c1.3 0 7.8-2.8 7.6-5C16 2.1 6.8 1.3 2.4 4.3z" transform="translate(70 52)"/>
+ <path fill="url(#n)" d="M8.6 9.7C7.5 9.7 1.5 7 .9 5c-.2-.8.1-1.5.7-2C5.8.2 13.9.3 16.3 1.4c1 .4 1.2 1.1 1.3 1.6.1.9-.2 1.7-1 2.6-1.8 2.1-6.4 4.1-8 4.1zm-3.9-5c1.3.8 3.5 1.9 4.1 2 .9-.1 4.3-1.7 5.5-2.8-2-.4-6.5-.5-9.6.8z" transform="translate(70 52)"/>
+ </g>
+ <g fill-rule="nonzero">
+ <path fill="#C8C8CC" d="M115 92.8l-7.2.1-.5-40.7c0-3.3 2.5-6.1 5.7-6.3.3 0 .5.2.5.4l1.5 46.5z"/>
+ <path fill="#E1E1E6" d="M130.1 53.3c.2-.2.5-.1.7.1 1.9 2.7 1.4 6.4-1.1 8.5l-31.3 26-4.6-5.5 36.3-29.1z"/>
+ <path fill="url(#o)" d="M.7 10c-.4 2.6.2 5.2 1.9 7.1.8 1 1.8 1.7 2.9 2.3 3.5 1.6 7.8 1 11-1.7.2-.2.5-.4.7-.6l10.1-8.4c.4-.4.7-.9.8-1.4.1-.6-.1-1.1-.5-1.5l-2.9-3.4c-.2-.2-.4-.4-.7-.6-.2-.1-.5-.2-.7-.2-.6-.1-1.1.1-1.5.5l-2.9 2.4c-.1-.2-.2-.3-.4-.5-.8-1-1.8-1.7-2.9-2.3-3.5-1.6-7.8-1-11 1.7C2.5 5.1 1.2 7.5.7 10zm6.6-3.4c1.9-1.6 4.5-2.1 6.5-1.1.6.3 1.1.7 1.5 1.1 1.4 1.6 1.3 4.1.1 6.1-.5.7-1.1 1.4-2 2.1-1.9 1.3-4.2 1.5-5.9.7-.6-.3-1.1-.7-1.5-1.1-.8-1-1.2-2.4-.9-3.8 0-1.5.9-2.9 2.2-4z" transform="translate(77 75)"/>
+ <path fill="url(#p)" d="M0 2.5l.2 13.2v.9c.1 4.1 2.3 7.8 5.7 9.4 1.2.6 2.5.9 3.8.8 5.1-.1 9.3-4.7 9.2-10.4-.1-4.1-2.3-7.8-5.7-9.4-1.2-.6-2.5-.9-3.8-.8h-.6V2.4c0-.8-.5-1.5-1.2-1.9C7.3.4 7 .3 6.7.3L2.2.4C1.6.4 1.1.6.7 1 .2 1.4 0 2 0 2.5zm11.3 8.3c1.9.9 3.2 3.1 3.3 5.6 0 3.4-2.2 6.1-5 6.2-.7 0-1.3-.1-1.9-.4-1.8-.8-3-2.7-3.2-4.9v-.1c0-1.2.1-2.1.3-2.9.7-2.2 2.5-3.9 4.7-3.9.5 0 1.2.1 1.8.4z" transform="translate(107 83)"/>
+ <path fill="#C8C8CC" d="M111.3 70.6c1.3.1 2.2 1.3 2.1 2.5-.1 1.3-1.3 2.2-2.5 2.1-1.3-.1-2.2-1.3-2.1-2.5.1-1.2 1.2-2.2 2.5-2.1z"/>
+ </g>
+ <path fill="url(#q)" fill-rule="nonzero" d="M1.4 2.1L.3 5.7c-1 3.1.7 6.4 3.8 7.4 3.1 1 6.4-.7 7.4-3.8L14.4.1l-13 2z" transform="translate(57 67)"/>
+ <path fill="url(#r)" fill-rule="nonzero" d="M63.3 74.7h-.2c-.4-.1-.6-.5-.5-.9l2.2-6.8c.1-.4.5-.6.9-.5.4.1.6.5.5.9L64 74.2c-.1.3-.4.5-.7.5z"/>
+ <path fill="url(#s)" fill-rule="nonzero" d="M58.7 98.1c-17.5 0-33-27.8-33.6-29-.8-1.4-.3-3.2 1.2-4 1.4-.8 3.2-.3 4 1.2 4.2 7.6 17.5 27 29.4 25.9 15.2-1.4 22.4-6.9 22.4-7 1.3-1 3.1-.8 4.1.5 1 1.3.8 3.1-.4 4.1-.3.3-8.5 6.7-25.6 8.2-.5.1-1 .1-1.5.1z"/>
+ <path fill="url(#t)" fill-rule="nonzero" d="M112.5 97.8s-8 3.2-8.1 5.9c-.1 2.7 8.2 6 11.8.7 3.6-5.2-2.3-7.2-3.7-6.6z"/>
+ <path fill="url(#u)" fill-rule="nonzero" d="M30.5 65.3s.7 5.9 4.4 9.2c3.7 3.3-4.8 8.1-4.4 15.4.4 7.4 0-24.6 0-24.6z"/>
+ <path fill="url(#v)" fill-rule="nonzero" d="M58.8 98.9h-1.1C44 98.5 32 81 31.5 80.2c-.2-.3-.1-.8.2-1 .3-.2.8-.1 1 .2.1.2 12.1 17.7 25 18 12.8.3 25.3-6.2 27.1-7.7.5-.4.9-2.6.2-3.7-.7-1-2.4-.3-3.6.5-.3.2-.8.1-1-.2-.2-.3-.1-.8.2-1 3.4-2.1 4.9-.9 5.6-.1 1.2 1.6.8 4.7-.4 5.7-1.2 1-13.4 8-27 8z"/>
+ <path fill="url(#w)" fill-rule="nonzero" d="M110.8 108.3c-1.3 0-2.8-.3-4.4-1.3-1.9-1-2.8-2.2-2.7-3.6.2-2.7 4.7-4.5 5.2-4.7.4-.1.8 0 1 .4.1.4 0 .8-.4 1-1.6.6-4.2 2.1-4.3 3.5-.1.9 1 1.7 1.9 2.2 2.2 1.2 4.3 1.4 6.1.6 2.1-1 3.1-2.8 3.2-3.2.1-.6.5-2.4-.5-3.5-.7-.8-2.1-1.1-4.1-.9-.4 0-.8-.3-.8-.7 0-.4.3-.8.7-.8 2.5-.2 4.3.2 5.3 1.4 1.5 1.6 1 4 .8 4.7-.2.9-1.6 3.2-4 4.3-.8.3-1.8.6-3 .6z"/>
+ <path fill="url(#x)" fill-rule="nonzero" d="M61.1 125.5c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7 3.2 0 8.1-1 8.2-1 .4-.1.8.2.9.6.1.4-.2.8-.6.9-.2-.1-5.1.9-8.5.9z"/>
+ <path fill="url(#y)" fill-rule="nonzero" d="M23 25.4h-.2c-.4-.1-.6-.5-.5-.9.2-.7 2.4-5 7.8-7.4.4-.2.8 0 1 .4.2.4 0 .8-.4 1-4.7 2-6.7 5.8-6.9 6.4-.2.3-.5.5-.8.5z"/>
+ <path fill="url(#z)" fill-rule="nonzero" d="M68.5 14.8c-8.9 0-18.2-1.2-18.3-1.2-.4-.1-.7-.4-.6-.8.1-.4.4-.7.8-.6.1 0 14.1 1.8 24.1 1 .4 0 .8.3.8.7 0 .4-.3.8-.7.8-2 0-4 .1-6.1.1z"/>
+ <path fill="url(#A)" fill-rule="nonzero" d="M88.8 89h-.2c-.4-.1-.6-.5-.5-.9l2-6c.1-.4.5-.6.9-.5.4.1.6.5.5.9l-2 6c-.1.3-.4.5-.7.5z"/>
+ <path fill="url(#B)" fill-rule="nonzero" d="M21 119.1h-.1c-.4-.1-.7-.5-.6-.9l1.7-8.6c.1-.4.5-.7.9-.6.4.1.7.5.6.9l-1.7 8.6c-.2.4-.5.6-.8.6z"/>
+ </g>
+ <path fill="#D7D7DB" fill-rule="nonzero" d="M70.8 82.4c-3.7 0-6.6 3-6.6 6.6h6.6v-6.6zm20 0h-6.6V89h6.6v-6.6zm13.3 0V89h6.6c0-3.6-3-6.6-6.6-6.6zm-23.3 0h-6.6V89h6.6v-6.6zm19.9 0h-6.6V89h6.6v-6.6zm3.4 16.6h6.6v-6.6h-6.6V99zm0 20c3.7 0 6.6-3 6.6-6.6h-6.6v6.6zm0-10h6.6v-6.6h-6.6v6.6zm-1.5-7.2c-2.1-3-6.2-3.7-9.3-1.6l-12.7 9.4-6.5-4.6c0-.3.1-.6.1-1 0-2.7-1.3-5.1-3.3-6.6v-5h-6.6v3.5c-3.8.8-6.6 4.1-6.6 8.1 0 4.6 3.7 8.3 8.3 8.3 1.8 0 3.5-.6 4.8-1.6l4.1 2.9-4.6 3.3c-1.3-.8-2.7-1.2-4.3-1.2-4.6 0-8.3 3.7-8.3 8.3 0 4.6 3.7 8.3 8.3 8.3 4.6 0 8.3-3.7 8.3-8.3 0-.6-.1-1.1-.2-1.6l28.5-20.6zm-36.7 6.4c-2.3 0-4.2-1.9-4.2-4.2 0-2.3 1.9-4.2 4.2-4.2 2.3 0 4.2 1.9 4.2 4.2-.1 2.3-1.9 4.2-4.2 4.2zm0 19.9c-2.3 0-4.2-1.9-4.2-4.2 0-2.3 1.9-4.2 4.2-4.2 2.3 0 4.2 1.9 4.2 4.2-.1 2.4-1.9 4.2-4.2 4.2zm17.9-8l10 7.6c3 2.1 7.2 1.4 9.3-1.6L89.6 116l-5.8 4.1z"/>
+ <g fill="#D7D7DB" fill-rule="nonzero">
+ <path d="M17.5 26.8l-.1-.1.1.1zM266.5 1.5v4.4c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5V3h-2.9c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h4.4c.8 0 1.5.7 1.5 1.5zM266.5 14.4v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17V40c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.6 1.5 1.4zm0 17.1V57c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17V74c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17V91c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17.1v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17.1v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.6 1.5 1.5zm0 17v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5
1.5zM266.5 184.8v4.4c0 .8-.7 1.5-1.5 1.5h-4.4c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h2.9v-2.9c0-.8.7-1.5 1.5-1.5s1.5.6 1.5 1.5zM253.3 189.2c0 .8-.7 1.5-1.5 1.5H243c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5H208c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.4.7 1.4 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8
c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5H94c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5H59c.8 0 1.4.7 1.4 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zM7.8 189.2c0 .8-.7 1.5-1.5 1.5H2c-.8 0-1.5-.7-1.5-1.5v-4.4c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5v2.9h2.9c.8 0 1.4.7 1.4 1.5zM3.4 14.4v8.5c0 .8-.7 1.5-1.5 1.5S.4 23.7.4 22.9v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17V40c0 .8-.7 1.5-1.5 1.5S.4 40.8.4 40v-8.5c0-.8.7-1.5 1.5-1.5s1.5.6 1.5 1.4zm0 17.1V57c0 .8-.7 1.5-1.5 1.5S.4 57.8.4 57v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17V74c0 .8-.7 1.5-1.5 1.5S.4 74.8.4 74v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17V91c0 .8-.7 1.5-1.5 1.5S.4 91.8.4 91v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17.1v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7
-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17.1v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.6 1.5 1.5zm0 17v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm0 17v8.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-8.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zM7.8 1.5c0 .8-.7 1.5-1.5 1.5H3.4v2.9c0 .8-.7 1.5-1.5 1.5S.4 6.7.4 5.9V1.5C.4.7 1.1 0 1.9 0h4.4c.9 0 1.5.7 1.5 1.5zM253.3 1.5c0 .8-.7 1.5-1.5 1.5H243c-.8 0-1.5-.7-1.5-1.5S242.2 0 243 0h8.8c.8 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5H208c-.8 0-1.5-.7-1.5-1.5S207.2 0 208 0h8.8c.8 0 1.4.7 1.4 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5h-8.8c-
.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5S137 0 137.8 0h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5S84.4 0 85.2 0H94c.9 0 1.5.7 1.5 1.5zM78 1.5c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5S66.9 0 67.7 0h8.8c.8 0 1.5.7 1.5 1.5zm-17.6 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5S49.3 0 50.1 0H59c.8 0 1.4.7 1.4 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5S31.8 0 32.6 0h8.8c.9 0 1.5.7 1.5 1.5zm-17.5 0c0 .8-.7 1.5-1.5 1.5h-8.8c-.8 0-1.5-.7-1.5-1.5S14.3 0 15.1 0h8.8c.8 0 1.5.7 1.5 1.5z"/>
+ </g>
+ <path d="M-18-32h352v303H-18z"/>
+ </g>
+</svg>
diff --git a/browser/extensions/onboarding/content/img/figure_singlesearch.svg b/browser/extensions/onboarding/content/img/figure_singlesearch.svg
new file mode 100644
index 000000000000..9be029397ccf
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_singlesearch.svg
@@ -0,0 +1 @@
+<svg width="303" height="253" viewBox="0 0 303 253" xmlns="http://www.w3.org/2000/svg"><title>search</title><defs><linearGradient x1="-18.632%" y1="-397.383%" x2="117.795%" y2="492.152%" id="a"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-312.046%" y1="-3945.649%" x2="293.266%" y2="2768.992%" id="b"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-291.258%" y1="-362.215%" x2="267.9%" y2="331.228%" id="c"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-145.39%" y1="-145.464%" x2="148.231%" y2="148.054%" id="d"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-760.952%" y1="-957.112%" x2="540.851%" y2="637.214%" id="e"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></
linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M-18-9h352v303H-18z"/><g fill-rule="nonzero"><g fill="#D7D7DB"><path d="M262.3 209.3H138.8c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h123.5c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1zM245.6 203.7h-31c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h31c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zM217.5 214.1h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-22.3 0h-3.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-7.8 0h-1.1c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-11.1 0h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm-22.4 0h-3.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zm-7.8 0H145c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-11.1 0h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6H135c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm-22.3 0h-3.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h3.3c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm-7.8 0h-1.1c-.3 0-.6-.2-.6
-.6 0-.3.2-.6.6-.6h1.1c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm-11.2 0H80.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-22.3 0H68c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.2.6-.5.6zm-7.8 0h-1.1c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1.1c.3 0 .6.2.6.6-.1.4-.3.6-.6.6zm-11.2 0H39c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6z"/></g><path d="M6.3 148.8c-2.8 0-5.1-2.3-5.1-5.1v-27.2c0-2.8 2.3-5.1 5.1-5.1h245.8c2.8 0 5.1 2.3 5.1 5.1v27.2c0 2.8-2.3 5.1-5.1 5.1H6.3z" fill="#FFF"/><path d="M252.1 2.4c2.2 0 4 1.8 4 4v27.2c0 2.2-1.8 4-4 4H6.3c-2.2 0-4-1.8-4-4V6.4c0-2.2 1.8-4 4-4h245.8zm0-2.2H6.3C2.9.2.1 3 .1 6.4v27.2c0 3.4 2.8 6.2 6.2 6.2h245.8c3.4 0 6.2-2.8 6.2-6.2V6.4c.1-3.4-2.7-6.2-6.2-6.2z" fill="url(#a)" transform="translate(0 110)"/><path d="M157 23.5h24.1s-7.5-16.9 8.5-19c14.3-1.9 19.9 12.7 19.9 12.7s1.7-8.5 10.2-6.8c8.4 1.6 14.6 15.1 14.6 15.1h21" fill="#F9F9FA"/><path d="M255.6 21.4h-6.2c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h6.2c.3 0 .6.2.6.6 0 .
4-.3.6-.6.6zm-16.2 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-57.9-.6h-1.8c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h1c-.1-.2-.2-.4-.3-.7-.1-.3.1-.6.3-.7.3-.1.6.1.7.3.3.9.5 1.4.5 1.4.1.2.1.4 0 .5 0 .3-.2.4-.4.4zm-10.7 0h-13.4c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.4c.3 0 .6.2.6.6-.1.3-.3.6-.6.6zm63.4-.1c-.2 0-.4-.1-.5-.3-.4-.6-.9-1.6-1.7-2.8-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.8 1.2 1.4 2.2 1.8 2.9.2.3.1.6-.2.8h-.4zM179.9 15c-.3 0-.5-.2-.6-.5-.1-.4-.1-.8-.1-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.1 1.1.1.2-.1.5-.5.6.1 0 0 0 0 0zm29.1-2.5c-.2 0-.4-.1-.5-.3-.2-.3-.3-.6-.5-1-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.2.4.4.7.6 1 .1.3 0 .6-.2.8-.3.1-.3.1-.4.1zm17.7-1.4c-.1 0-.3 0-.4-.1-2.1-1.8-4.3-3-6.3-3.4-2-.4-3.8-.2-5.3.6-.3.1-.6 0-.8-.2-.1-.3 0-.6.2-.8 1.7-.9 3.8-1.1 6.1-.7 2.3.4 4.6 1.6 6.9 3.6.2.2.3.6.1.8-.2.1-.4.2-.5.2zm-20.9-3.2c-.2 0-.3-.1-.4-.2-.7-.8-1.5-1.6-2.3-2.3-.2-.2-.3-.6-.1-.8.2-.2.5-.3.8-.1.9.7 1.7 1.5 2.4 2.4.2.2.2.6-.1.8 0 .2-.2.2-.3.2zm-23-3.2c-.2 0-.3-.1-.4-.2-.2-.
2-.2-.6 0-.8 1.8-1.6 4.3-2.7 7.5-3.1 1.9-.3 3.8-.2 5.7.1.3.1.5.3.5.6-.1.3-.3.5-.6.5-1.7-.3-3.5-.3-5.3-.1-2.9.4-5.3 1.3-6.9 2.8-.2.1-.4.2-.5.2z" fill="#D7D7DB"/><path d="M256.3 25.7H157c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h99.4c.6 0 1.1.5 1.1 1.1 0 .6-.6 1.1-1.2 1.1zM4 46.5h13.4s-4.2-9.4 4.7-10.6C30 34.8 33.2 43 33.2 43s.9-4.7 5.7-3.8c4.7.9 8.1 8.4 8.1 8.4h11.7" fill="#F9F9FA"/><path d="M17.8 45H4.5c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.7.6zm41.3-.1h-.5c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h.5c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-5 0h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-20.4-3.4c-.2 0-.4-.2-.5-.4L33 41c-.1-.3 0-.6.2-.7.5-1.6 2-3.8 4.9-3.8.4 0 .8 0 1.3.1 1.7.3 3.3 1.3 5 2.9.2.2.2.6 0 .8-.2.2-.6.2-.8 0-1.5-1.4-3-2.3-4.4-2.6-.4-.1-.7-.1-1-.1-3.2 0-3.9 3.3-4 3.5-.1.2-.3.4-.5.4zm-15.6-4.9c-.1 0-.3 0-.4-.1-.2-.2-.3-.6-.1-.8.7-.9 1.8-1.5 3.1-1.9.3-.1.6.1.7.4.1.3-.1.6-.4.7-1.1.3-1.9.9-2.5 1.6 0 0-.2.1-.4.1zm8.3-1.9h-.1c-.3-.1-.7-.2-1-.2-.3
0-.5-.3-.5-.6s.3-.5.6-.5c.4.1.8.1 1.2.2.3.1.5.4.4.7-.1.2-.3.4-.6.4z" fill="#D7D7DB"/><path d="M59.5 48.8H4.3c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h55.3c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.2 1.1z" fill="#F9F9FA"/><g><path d="M210 92.1v-9.5c0-2-1.6-3.6-3.6-3.6H38.3c-2 0-3.6 1.6-3.6 3.6v9.5c0 2 1.6 3.6 3.6 3.6h168.1c2 0 3.6-1.6 3.6-3.6zm0-34.8v-9.5c0-2-1.6-3.6-3.6-3.6H38.3c-2 0-3.6 1.6-3.6 3.6v9.5c0 2 1.6 3.6 3.6 3.6h168.1c2 0 3.6-1.6 3.6-3.6zm0 121.3v-9.5c0-2-1.6-3.6-3.6-3.6H38.3c-2 0-3.6 1.6-3.6 3.6v9.5c0 2 1.6 3.6 3.6 3.6h168.1c2 0 3.6-1.6 3.6-3.6z" fill="#FFF"/><path d="M206 44.2c2.2 0 4 1.8 4 4v8.7c0 2.2-1.8 4-4 4H38.8c-2.2 0-4-1.8-4-4v-8.7c0-2.2 1.8-4 4-4H206zm0 34.8c2.2 0 4 1.8 4 4v8.7c0 2.2-1.8 4-4 4H38.8c-2.2 0-4-1.8-4-4V83c0-2.2 1.8-4 4-4H206zm0 86.5c2.2 0 4 1.8 4 4v8.7c0 2.2-1.8 4-4 4H38.8c-2.2 0-4-1.8-4-4v-8.7c0-2.2 1.8-4 4-4H206zm0-123.6H38.8c-3.4 0-6.2 2.8-6.2 6.2v8.7c0 3.4 2.8 6.2 6.2 6.2H206c3.4 0 6.2-2.8 6.2-6.2v-8.7c0-3.4-2.8-6.2-6.2-6.2zm0 34.8H38.8c-3.4 0-6.2 2.8-6.
2 6.2v8.7c0 3.4 2.8 6.2 6.2 6.2H206c3.4 0 6.2-2.8 6.2-6.2V83c0-3.5-2.8-6.3-6.2-6.3zm0 86.6H38.8c-3.4 0-6.2 2.8-6.2 6.2v8.7c0 3.4 2.8 6.2 6.2 6.2H206c3.4 0 6.2-2.8 6.2-6.2v-8.7c0-3.4-2.8-6.2-6.2-6.2z" fill="#D7D7DB"/></g><path d="M300.8 176.6l-.1-.1-4.7-4.3c-.2-1.2-.8-2.3-1.7-3.1l-17.4-16c-.9-.8-2-1.3-3.2-1.4l-8.3-7.6c-1-1-2.2-1.7-3.5-2.1 10.8-18 8.1-41.3-6.9-56.4-8.7-8.7-20.3-13.5-32.6-13.5s-23.9 4.8-32.6 13.5c-18 18-18 47.3 0 65.2 8.7 8.7 20.3 13.5 32.6 13.5 8.3 0 16.6-2.3 23.7-6.6.4 1.3 1.2 2.6 2.2 3.6l7.6 8.3c.1 1.2.6 2.3 1.4 3.2l16 17.4c.8.9 1.9 1.5 3.1 1.7l4.2 4.6.1.1c1.5 1.5 3.4 2.3 5.7 2.3 3.6 0 7.8-2 11.2-5.4 5.7-5.8 7.1-13 3.2-16.9z" fill="#F9F9FA"/><g><path d="M224.1 88.7c-10.7 0-20.3 5.1-26.3 13h52.6c-6.1-7.9-15.6-13-26.3-13z" fill="#F9F9FA"/><path d="M248.9 152.7c.5-1.5 1.4-3.1 3.1-4.8 1.6-1.6 3.2-2.6 4.8-3.1l-2.5-2.5c12-15.9 10.8-38.6-3.7-53.1-7.9-7.9-18.3-11.9-28.7-11.9-10.4 0-20.8 4-28.7 11.9-15.8 15.8-15.8 41.5 0 57.4 7.9 7.9 18.3 11.9 28.7 11.9 8.6 0 17.2-2.7 24.4-8
.2l2.6 2.4zm-27-1.8c-11.8 0-22.1-6.2-28-15.4.1.1.1.3.2.4-1-1.6-1.9-3.3-2.7-5.1v-.1c-.2-.4-.4-.9-.5-1.3l-.6-1.8v-.1c-.9-3-1.4-6.2-1.4-9.6 0-3.8.7-7.5 1.8-10.9.6-1.8 1.4-3.6 2.4-5.3h.2c5.7-10 16.4-16.7 28.8-16.7 12.3 0 23.1 6.7 28.7 16.7h.1c.9 1.7 1.7 3.4 2.4 5.3 1.2 3.4 1.8 7 1.8 10.9-.1 18.2-14.9 33-33.2 33z" fill="#CCEDF0"/><path d="M253.2 107h-58.7c-2.2 4.4-3.5 9.5-3.5 14.8 0 4.9 1.1 9.6 3 13.7 5.9 9.3 16.2 15.4 28 15.4 18.3 0 33.1-14.8 33.1-33.1-.1-3.8-.7-7.4-1.9-10.8zM190.8 107h-.1c-1.2 3.4-1.8 7-1.8 10.9 0 3.3.5 6.5 1.4 9.6-.9-3-1.3-6.1-1.3-9.3-.1-4 .6-7.8 1.8-11.2zM190.9 129.3l-.6-1.8.6 1.8z" fill="#FFF"/><path d="M71.3 26.7H18.7c-1.3 1.6-2.4 3.4-3.3 5.3h58.7c-.6-1.8-1.4-3.6-2.4-5.3h-.1c.4.7.8 1.5 1.2 2.2-.4-.7-.9-1.5-1.5-2.2z" fill="url(#b)" transform="translate(179 75)"/><path d="M193.3 101.7h-.2c-.9 1.7-1.7 3.4-2.4 5.3h.1c.7-1.9 1.5-3.6 2.5-5.3z" fill="#E9E9EE"/><path d="M15.5 32c.9-1.9 2-3.6 3.3-5.3 6-7.9 15.6-13 26.3-13 10.7 0 20.2 5.1 26.3 13 .5.7 1.1 1.5 1.6 2.2-.4-.8-.
7-1.5-1.2-2.2C66.1 16.7 55.4 10 43.1 10S20 16.7 14.3 26.7c-1 1.7-1.8 3.4-2.4 5.3-1.2 3.5-1.9 7.2-1.9 11.1 0 3.2.5 6.4 1.3 9.3v.1l.6 1.8c.2.5.3.9.5 1.3v.1c.7 1.8 1.6 3.5 2.7 5.1-.1-.1-.1-.3-.2-.4-1.9-4.2-3-8.8-3-13.7.1-5.3 1.4-10.3 3.6-14.7z" fill="url(#c)" opacity=".4" transform="translate(179 75)"/><path d="M119.1 103.6l-5.7-5.2c0-.2.1-.3.1-.5 0-.6-.3-1.2-.7-1.6l-17.4-16c-.4-.4-1-.6-1.5-.6-.2 0-.4 0-.7.1l-9.4-8.6c-.8-.8-1.8-1.3-3-1.5l-2.5-2.5c11.6-16.8 9.5-39.9-5-54.5C65.2 4.6 54.5.2 43 .2S20.8 4.7 12.7 12.7C-4 29.4-4 56.5 12.7 73.2c8.1 8.1 18.8 12.5 30.2 12.5 8.6 0 17.1-2.7 24.2-7.5l2.6 2.6c.2 1.2.8 2.2 1.6 3l8.6 9.4c-.2.7-.1 1.6.5 2.2l16 17.4c.4.4 1 .7 1.6.7.2 0 .3 0 .5-.1l5.2 5.7c.8.8 2 1.3 3.3 1.3 2.7 0 6.1-1.7 8.8-4.5 4.4-4.5 5.8-9.8 3.3-12.3zM14.3 71.5C-1.5 55.7-1.5 30 14.3 14.1 22.2 6.2 32.6 2.2 43 2.2c10.4 0 20.8 4 28.7 11.9 14.5 14.5 15.7 37.2 3.7 53.1l2.5 2.5c-1.6.5-3.2 1.5-4.8 3.1-1.7 1.7-2.7 3.3-3.1 4.8l-2.5-2.5c-7.2 5.5-15.8 8.2-24.4 8.2-10.5.1-20.9-3.9-28.8-11.8zm96.9
26.3L98 111.1 82 93.7l11.8-11.8 17.4 15.9z" fill="url(#d)" transform="translate(179 75)"/><path fill="#CCEDF0" d="M277 186.1l13.2-13.3-17.4-15.9-11.8 11.8"/></g><ellipse fill="#EDEDF0" cx="242.1" cy="246.7" rx="57.2" ry="5.8"/><g><path d="M21.3 33.9c-.6 0-1.3-.2-1.8-.6L7.1 23.2c-1.3-.9-2.4-2-3.2-3.2C1 15.5 1.6 9.5 5.4 5.8c2.1-2.1 5-3.3 8-3.3s5.8 1.1 7.9 3.2c2.1-2 4.9-3.2 7.9-3.2 3.3 0 6.5 1.5 8.7 4 3.2 3.8 3.5 9.4.8 13.5-.8 1.3-1.9 2.3-3.2 3.2l-12.3 10c-.6.5-1.2.7-1.9.7z" fill="url(#e)" transform="translate(201 113)"/><path d="M214.4 117c2.5 0 5 1 6.9 2.9.3.3.6.4 1 .4s.7-.1 1-.4c1.9-1.9 4.4-2.8 6.9-2.8 2.7 0 5.5 1.2 7.5 3.5 2.8 3.3 3 8.1.7 11.7-.8 1.1-1.7 2-2.7 2.7l-12.4 10.1c-.2.2-.5.3-.8.3-.3 0-.5-.1-.8-.3L209.2 135c-1.1-.7-2.1-1.6-2.8-2.8-2.5-3.8-2-9 1.3-12.2 1.7-2 4.2-3 6.7-3zm0-3.1c-3.4 0-6.7 1.3-9.1 3.8-4.3 4.3-5 11.1-1.7 16.2.9 1.4 2.2 2.7 3.6 3.7l12.4 10c.8.6 1.8 1 2.8 1 1 0 2-.3 2.7-1l12.3-10.1c1.4-1 2.6-2.1 3.5-3.5 3.1-4.7 2.8-11.1-.9-15.4-2.5-2.9-6.1-4.6-9.9-4.6-2.9 0-5.
6.9-7.9 2.7-2.2-1.9-4.9-2.8-7.8-2.8z" fill="#FFF"/><path d="M208.6 128.1h-.1c-.9-.1-1.6-.9-1.5-1.8.3-3.2 2.5-5.8 5.7-6.5.9-.2 1.8.4 1.9 1.2.2.9-.4 1.8-1.2 1.9-1.7.4-3 1.8-3.1 3.6-.2 1-.9 1.6-1.7 1.6z" fill="#F9F9FA"/></g></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/figure_sync.svg b/browser/extensions/onboarding/content/img/figure_sync.svg
new file mode 100644
index 000000000000..74562d37236d
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/figure_sync.svg
@@ -0,0 +1 @@
+<svg width="279" height="212" viewBox="0 0 279 212" xmlns="http://www.w3.org/2000/svg"><title>sync</title><defs><linearGradient x1="-424.525%" y1="-219.797%" x2="201.215%" y2="136.157%" id="a"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1416.558%" y1="-1417.275%" x2="631.855%" y2="631.14%" id="b"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1909.4%" y1="-1924.057%" x2="675.504%" y2="691.989%" id="c"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1453.558%" y1="-828.355%" x2="354.762%" y2="235.706%" id="d"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-608.073%" y1="-599.552%" x2="1804.502%" y2="1813.024%" id="e"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"
/></linearGradient><linearGradient x1="-55.527%" y1="-25.138%" x2="334.297%" y2="252.524%" id="f"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-359.418%" y1="-359.43%" x2="1512.409%" y2="1512.397%" id="g"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-393.876%" y1="-203.242%" x2="1247.254%" y2="755.651%" id="h"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-772.819%" y1="-773.412%" x2="1098.573%" y2="1098.414%" id="i"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-1129.33%" y1="-1133.526%" x2="1256.735%" y2="1279.05%" id="j"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-78.929%" y1="-156.663%" x2="182.03%" y2="261.703%" id
="k"><stop stop-color="#CCFBFF" offset="0%"/><stop stop-color="#C9E4FF" offset="100%"/></linearGradient><linearGradient x1="-2.965%" y1="-86.281%" x2="110.352%" y2="213.059%" id="l"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-833.673%" y1="-459.972%" x2="807.063%" y2="498.921%" id="m"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient><linearGradient x1="-17.606%" y1="-93.916%" x2="104.414%" y2="177.35%" id="n"><stop stop-color="#00C8D7" offset="0%"/><stop stop-color="#0A84FF" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M-37-28h352v268H-37z"/><g fill-rule="nonzero"><g><path d="M23 23.1h23.9S39.4 6.4 55.3 4.2c14.2-1.9 19.8 12.6 19.8 12.6s1.7-8.4 10.1-6.8c8.3 1.6 14.5 15 14.5 15h20.8" fill="#F9F9FA"/><path d="M121 21.1h-5.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h5.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-15.4 0h-1.1c-.3 0-.6-.2-.6-.6 0-.4
.2-.6.6-.6h1.1c.3 0 .6.2.6.6 0 .4-.2.6-.6.6zm-5.5-.1c-.2 0-.4-.1-.5-.3-.2-.3-.7-1.4-1.7-2.9-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2 1 1.5 1.6 2.6 1.7 2.9.1.3 0 .6-.2.8-.1.1-.2.1-.3.1zm-52.7-.6h-1.6c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h.8c-.1-.2-.2-.5-.3-.9-.1-.3.1-.6.4-.7.3-.1.6.1.7.4.3 1 .6 1.6.6 1.6.1.2.1.4 0 .5-.3.2-.5.3-.6.3zm-10.6 0H23.4c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h13.4c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm8.9-5.9c-.3 0-.5-.2-.6-.5 0-.4-.1-.8-.1-1.1 0-.3.2-.6.5-.6s.6.2.6.5c0 .4.1.7.1 1.1.1.2-.1.5-.5.6.1-.1.1 0 0 0zm29.2-1.8c-.2 0-.4-.1-.5-.3-.1-.3-.3-.6-.5-1-.2-.3-.1-.6.2-.8.3-.2.6-.1.8.2.2.4.4.7.5 1 .1.3 0 .6-.2.8-.2.1-.2.1-.3.1zm17.8-1.4c-.1 0-.3 0-.4-.1-2.3-2.1-4.6-3.4-6.8-3.8-.7-.1-1.4-.2-2-.2-1 0-2 .2-2.8.5-.3.1-.6 0-.7-.3-.1-.3 0-.6.3-.7 1-.4 2.1-.6 3.3-.6.7 0 1.4.1 2.2.2 2.4.5 4.9 1.8 7.3 4 .2.2.2.6 0 .8-.1.1-.2.2-.4.2zM71.8 8c-.2 0-.3-.1-.4-.2-.7-.9-1.5-1.6-2.3-2.3-.2-.2-.3-.6-.1-.8.2-.2.6-.3.8-.1.8.7 1.6 1.6 2.4 2.5.2.2.2.6-.1.8-.1.1-.2.1-.3.1zM48.9 4.2c-.2 0-.3-.1-.4-.2-.2-.2-.2-.6.
1-.8C50.4 1.7 52.8.8 55.8.3c2.1-.3 4.1-.2 6 .1.3.1.5.4.4.7-.1.3-.3.5-.7.4-1.8-.4-3.7-.4-5.6-.1-2.8.4-5 1.3-6.6 2.6-.2.2-.3.2-.4.2z" fill="#D7D7DB"/><path d="M121.6 25.3H23c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h98.6c.6 0 1.1.5 1.1 1.1 0 .6-.4 1.1-1.1 1.1zM222.4 31.5h13.3s-4.2-9.3 4.7-10.5c7.9-1.1 11 7 11 7s.9-4.7 5.6-3.8c4.6.9 8 8.3 8 8.3h11.6" fill="#F9F9FA"/><path d="M236.1 30h-13.3c-.3 0-.6-.2-.6-.6 0-.3.2-.6.6-.6h13.3v.5l.5-.2c.1.2.1.4 0 .6-.2.2-.3.3-.5.3zm36.5-.2h-3.3c-.3 0-.6-.2-.6-.6 0-.4.2-.6.6-.6h3.3c.3 0 .6.2.6.6 0 .4-.3.6-.6.6zm-20.8-3.3h-.1c-.3-.1-.5-.4-.4-.7.1-.4 1.1-4.3 5-4.3.4 0 .8 0 1.2.1 1.7.3 3.5 1.4 5.2 3.1.2.2.2.6 0 .8-.2.2-.6.2-.8 0-1.6-1.6-3.1-2.5-4.6-2.8-.4-.1-.7-.1-1-.1-3 0-3.8 2.8-3.9 3.4-.1.3-.4.5-.6.5zm-15.3-5.1c-.1 0-.3 0-.4-.1-.2-.2-.2-.6 0-.8.8-.8 1.8-1.5 3.1-1.8.3-.1.6.1.7.4.1.3-.1.6-.4.7-1.1.3-2 .8-2.6 1.5-.1.1-.3.1-.4.1zm8.3-1.6h-.2c-.3-.1-.7-.2-1-.2-.3-.1-.5-.3-.5-.6.1-.3.3-.5.6-.5l1.2.3c.3.1.5.4.4.7 0 .1-.2.3-.5.3z" fill="#D7D7DB"/><path d="M277.5
33.7h-54.9c-.6 0-1.1-.5-1.1-1.1 0-.6.5-1.1 1.1-1.1h54.9c.6 0 1.1.5 1.1 1.1 0 .6-.5 1.1-1.1 1.1z" fill="#F9F9FA"/><ellipse fill="#EDEDF0" cx="144.1" cy="206.4" rx="59.7" ry="5.2"/><path d="M187.8 21.6h.1c.7 0 1.3-.5 1.3-1.2.1-1.5 1.2-2.7 2.6-3 .7-.2 1.2-.9 1-1.6-.2-.7-.9-1.2-1.6-1-2.6.6-4.5 2.8-4.7 5.4 0 .7.6 1.4 1.3 1.4z" fill="#F9F9FA"/><ellipse fill="#EDEDF0" cx="248.8" cy="206.4" rx="25.7" ry="4.5"/><ellipse fill="#EDEDF0" cx="35.7" cy="206.4" rx="35" ry="4.5"/></g><path d="M173 63.2c-.1-.3-.5-.5-.9-.4-.9.4-1.8.7-2.7 1.1-.2.1-.3.3-.4.5h2.7c.3-.1.6-.3.9-.4.4-.1.6-.5.4-.8zM231.7 155.7c.1.1.3.2.5.2s.3-.1.5-.2c.2-.2.4-.5.7-.7h-1.8c-.1.2-.1.5.1.7zM149.2 63.7c.3-.2.3-.7.1-.9-.2-.3-.7-.3-.9-.1-.3.3-.7.6-1 .8-.3.2-.3.6-.1.9h1.1c.2-.2.5-.4.8-.7zM65.2 62.8c-.2.1-.3.1-.5.2.5 0 .9.1 1.3.2-.1-.4-.5-.5-.8-.4zM129.2 63.9c.1.1.3.2.4.2.2 0 .4-.1.5-.2.2-.3.2-.7-.1-.9-.3-.3-.7-.6-1-.8-.3-.2-.7-.2-.9.1-.2.3-.2.7.1.9.3.1.6.4 1 .7zM42.3 62.8c-.2-.3-.7-.3-.9-.1l-.3.3h1.4c-.1-.1-.1-.2-.2-.2z" fill="#F3
F3F7"/><path d="M196.2 171.5c0 .4-.3.7-.6.7-1 .1-2 .1-2.9.1h-.1c-3.9 0-7.9-.4-11.7-1.2-.4-.1-.6-.4-.5-.8.1-.4.4-.6.8-.5 3.7.8 7.6 1.2 11.4 1.2 1 0 2 0 2.9-.1.4-.1.7.2.7.6zm10.5-109.3c3.7 1 7.4 2.4 10.8 4.1.1 0 .2.1.3.1.2 0 .5-.1.6-.4.2-.3 0-.7-.3-.9-3.5-1.8-7.2-3.2-11.1-4.2-.4-.1-.7.1-.8.5 0 .3.2.7.5.8zm-11.3-3.1c-4.9-.2-9.9.2-14.7 1.2-.4.1-.6.4-.5.8.1.3.3.5.7.5h.1c4.7-1 9.6-1.4 14.4-1.2.4 0 .7-.3.7-.6-.1-.4-.3-.7-.7-.7zm-25.5 108.4c.3 0 .5-.1.6-.4.2-.3 0-.7-.3-.9-.6-.3-1.1-.5-1.7-.8h-2.9c1.3.7 2.7 1.4 4.1 2 0 0 .1.1.2.1zM223.3 68c-.3-.2-.7-.1-.9.2-.2.3-.1.7.2.9.8.5 1.6 1.1 2.4 1.6.1.1.3.1.4.1.2 0 .4-.1.5-.3.2-.3.1-.7-.2-.9-.8-.5-1.6-1-2.4-1.6zm-.6 94c-3.2 2.1-6.7 3.9-10.3 5.3-.3.1-.5.5-.4.9.1.3.4.4.6.4h.2c3.7-1.4 7.2-3.2 10.5-5.4.3-.2.4-.6.2-.9 0-.4-.5-.5-.8-.3zm-15.8 7c-.9.2-1.9.5-2.8.7-.4.1-.6.4-.5.8.1.3.3.5.7.5h.1c1-.2 1.9-.4 2.9-.7.4-.1.6-.5.5-.8-.1-.3-.5-.6-.9-.5zM192.6 54.7c16.8 0 32 6.8 43.1 17.9h3.7C227.7 60 211.1 52 192.6 52c-14.1 0-27.1 4.6-37.7 12.4h4.7c9.6-6.1 20.9-9.7
33-9.7zm0 121.8c-13.1 0-25.2-4.1-35.1-11.2H153c10.9 8.7 24.6 13.9 39.6 13.9 20.2 0 38.3-9.5 49.9-24.3H239c-11.1 13.2-27.8 21.6-46.4 21.6zm11.8 5.8c-5 .9-10.2 1.2-15.2.9-.3 0-.7.3-.7.6 0 .4.3.7.6.7 1.2.1 2.3.1 3.5.1 4 0 8.1-.4 12-1 .4-.1.6-.4.5-.8 0-.4-.3-.6-.7-.5zm-25.4-.4c-1.2-.3-2.5-.5-3.7-.9-.4-.1-.7.1-.8.5-.1.4.1.7.5.8 1.3.3 2.5.6 3.8.9h.1c.3 0 .6-.2.7-.5 0-.3-.2-.7-.6-.8zm37.7-3c-.4.2-.8.3-1.2.4-.3.1-.5.5-.4.9.1.3.4.4.6.4h.2c.4-.1.8-.3 1.2-.5.3-.1.5-.5.4-.9-.1-.3-.5-.5-.8-.3zm19.4-115c.1.1.3.2.4.2.2 0 .4-.1.5-.2.2-.3.2-.7-.1-.9-.3-.3-.7-.6-1-.8-.3-.2-.7-.2-.9.1-.2.3-.2.7.1.9.4.1.7.4 1 .7zm-65.7 115.7c-.4-.1-.8-.3-1.2-.4-.3-.1-.7 0-.9.4-.1.3 0 .7.4.9.4.2.8.3 1.2.4h.2c.3 0 .5-.2.6-.5.3-.3.1-.7-.3-.8zm54.4-4.4c-1.1.6-2.3 1.2-3.4 1.7-.3.2-.5.6-.3.9.1.2.4.4.6.4.1 0 .2 0 .3-.1 1.2-.6 2.3-1.1 3.5-1.8.3-.2.4-.6.3-.9-.3-.3-.7-.4-1-.2zm19.6-16.1c-3.3 3.9-7 7.4-11.1 10.5-.3.2-.4.6-.1.9.1.2.3.3.5.3.1 0 .3 0 .4-.1 4.1-3.1 7.9-6.7 11.3-10.7.2-.3.2-.7-.1-.9-.2-.3-.6-.3-.9 0zm.9-88c-.2-.3-.7-.
3-.9-.1-.3.2-.3.7-.1.9.2.2.3.4.5.6h1.7c-.4-.4-.8-.9-1.2-1.4zm-87-13.9c.1 0 .2 0 .3-.1 4.4-2.6 9.1-4.6 14-6.1.4-.1.6-.5.4-.8-.1-.4-.5-.6-.8-.4-5 1.5-9.8 3.6-14.3 6.3-.3.2-.4.6-.2.9.1.1.3.2.6.2zm45.8-8.2c5 .9 10 2.3 14.7 4.3.1 0 .2.1.3.1.3 0 .5-.2.6-.4.1-.3 0-.7-.4-.9-4.8-2-9.8-3.5-15-4.4-.4-.1-.7.2-.8.5 0 .3.3.7.6.8zm23.8 8.9c1.1.7 2.2 1.4 3.2 2.1.1.1.3.1.4.1.2 0 .4-.1.6-.3.2-.3.1-.7-.2-.9-1.1-.7-2.2-1.5-3.3-2.1-.3-.2-.7-.1-.9.2-.2.3-.1.7.2.9zM191.4 48h1.3c.4 0 .6-.3.6-.7 0-.4-.4-.7-.7-.7h-1.2c-.4 0-.7.3-.7.7 0 .4.3.7.7.7zm-45.8 118.2c3.8 3.5 8 6.7 12.5 9.3.1.1.2.1.3.1.2 0 .5-.1.6-.3.2-.3.1-.7-.2-.9-4.3-2.5-8.4-5.5-12.1-8.9h-1.2c-.1.1-.1.5.1.7zm36.8-117.5c.1 0 .1 0 0 0 1.3-.2 2.6-.3 3.9-.5.4 0 .6-.4.6-.7 0-.4-.4-.6-.7-.6-1.3.1-2.6.3-3.9.5-.4.1-.6.4-.6.8.1.3.4.5.7.5zM97.3 171h.1c1-.2 1.9-.4 2.9-.7.4-.1.6-.5.5-.8-.1-.4-.5-.6-.8-.5-.9.2-1.9.5-2.8.7-.4.1-.6.4-.5.8 0 .3.3.5.6.5zm2-109.6c-.1.4.1.7.5.8 2.3.6 4.5 1.4 6.7 2.3h3.3c-3.1-1.5-6.4-2.7-9.7-3.6-.4-.1-.7.1-.8.5zm-25.6-1.1c-.4.1-.6.4-
.5.8.1.3.3.5.7.5h.1c4.7-1 9.6-1.4 14.4-1.2.4 0 .7-.3.7-.6 0-.4-.3-.7-.6-.7-5-.3-10 .1-14.8 1.2zm-.3 110c-.1.4.2.7.5.8 3.8.8 7.8 1.2 11.7 1.2h.1c1 0 2 0 2.9-.1.4 0 .7-.3.6-.7 0-.4-.3-.7-.7-.6-1 0-1.9.1-2.9.1-3.9 0-7.7-.4-11.4-1.2-.4-.2-.7.1-.8.5zm31.7-2.2c.1.3.4.4.6.4h.2c2.3-.9 4.6-2 6.7-3.1h-2.9c-1.4.7-2.8 1.3-4.3 1.9-.3.1-.5.5-.3.8zm-42.2-.6c.3 0 .5-.1.6-.4.2-.3 0-.7-.3-.9-1.8-.8-3.6-1.7-5.3-2.7h-2.6c2.3 1.5 4.8 2.8 7.3 3.9.1 0 .2.1.3.1zM85.6 54.7c12.1 0 23.4 3.6 32.9 9.7h4.7C112.7 56.6 99.7 52 85.6 52 72.4 52 60.1 56 50 62.9h5.1c9-5.2 19.4-8.2 30.5-8.2zm0 121.8c-14.2 0-27.2-4.9-37.6-13.1h-4.2c11.2 9.8 25.8 15.7 41.8 15.7 15 0 28.7-5.2 39.6-13.9h-4.5c-9.9 7.2-22 11.3-35.1 11.3zm32.2-1.3c-1.1.6-2.3 1.2-3.4 1.7-.3.2-.5.6-.3.9.1.2.4.4.6.4.1 0 .2 0 .3-.1 1.2-.6 2.3-1.1 3.5-1.8.3-.2.4-.6.3-.9-.3-.3-.7-.4-1-.2zm3.1-117.3c1.1.7 2.2 1.4 3.2 2.1.1.1.3.1.4.1.2 0 .4-.1.6-.3.2-.3.1-.7-.2-.9-1.1-.7-2.2-1.5-3.3-2.1-.3-.2-.7-.1-.9.2-.2.3-.1.7.2.9zM97.4 182.3c-5 .9-10.2 1.2-15.2.9-.4 0-.7.3-.7.6 0
.4.3.7.6.7 1.2.1 2.3.1 3.5.1 4 0 8.1-.4 12-1 .4-.1.6-.4.5-.8 0-.4-.3-.6-.7-.5zm-34-2.7c-.4-.1-.8-.3-1.2-.4-.3-.1-.7 0-.9.4-.1.3 0 .7.4.9.4.2.8.3 1.2.4h.2c.3 0 .5-.2.6-.5.3-.3.1-.7-.3-.8zm8.7 2.3c-1.2-.3-2.5-.5-3.7-.9-.4-.1-.7.1-.8.5-.1.4.1.7.5.8 1.3.3 2.5.6 3.8.9h.1c.3 0 .6-.2.7-.5 0-.3-.3-.7-.6-.8zm54.3-12.3c-.3.2-.4.6-.1.9.1.2.3.3.5.3.1 0 .3 0 .4-.1 2.2-1.7 4.3-3.4 6.2-5.3h-2c-1.6 1.5-3.3 2.9-5 4.2zm-16.7 9.3c-.4.2-.8.3-1.2.4-.3.1-.5.5-.4.9.1.3.4.4.6.4h.2c.4-.1.8-.3 1.2-.5.3-.1.5-.5.4-.9-.1-.3-.5-.5-.8-.3zM97.1 49c5 .9 10 2.3 14.7 4.3.1 0 .2.1.3.1.3 0 .5-.2.6-.4.1-.3 0-.7-.4-.9-4.8-2-9.8-3.5-15-4.4-.4-.1-.7.2-.8.5 0 .3.3.7.6.8zm-12.7-1h1.3c.4 0 .6-.3.6-.7 0-.4-.4-.7-.7-.7h-1.2c-.4 0-.7.3-.7.7.1.4.4.7.7.7zm-33.1 9.2c.1 0 .2 0 .3-.1 4.4-2.6 9.1-4.6 14-6.1.4-.1.6-.5.4-.8-.1-.4-.5-.6-.8-.4-5 1.5-9.8 3.6-14.3 6.3-.3.2-.4.6-.2.9.1.1.3.2.6.2zm.6 117.1c-4.4-2.5-8.6-5.6-12.3-9.1-.3-.3-.7-.2-1 0-.3.3-.2.7 0 1 3.8 3.5 8 6.7 12.5 9.3.1.1.2.1.3.1.2 0 .5-.1.6-.3.3-.4.2-.8-.1-1zM75.4 48.7c.1 0
.1 0 0 0 1.3-.2 2.6-.3 3.9-.5.4 0 .6-.4.6-.7 0-.4-.4-.6-.7-.6-1.3.1-2.6.3-3.9.5-.4.1-.6.4-.6.8.1.3.4.5.7.5z" fill="#D7D7DB"/><path d="M261.6 34.4h-30.1c-1.3 0-2.3 1-2.3 2.3v56.4c0 1.3 1 2.3 2.3 2.3h30.1c1.3 0 2.3-1 2.3-2.3V36.7c0-1.2-1-2.3-2.3-2.3zm-15.5 4.9c4.2 0 7.7 3.5 7.7 7.7s-3.5 7.7-7.7 7.7-7.7-3.5-7.7-7.7 3.5-7.7 7.7-7.7zm-7.5 23.1c.1-.4.5-.8 1-.9l3.7-.7 2.1-4.1.8-.1c.5 0 .9.3 1.1.7l1.7 3.5 4.4.8.3.7c.1.4 0 .9-.3 1.3l-2.6 2.8.7 4.7-.6.5c-.4.3-.9.3-1.3.1l-3.3-1.7-4 2.1-.7-.4c-.4-.3-.6-.7-.5-1.2l.6-3.9-3.1-3.4v-.8zm8.2 17.3c0-.7.5-1.2 1.2-1.2h1.3c-.8-.9-1.9-1.4-3.2-1.4-2 0-3.8 1.4-4.3 3.3-.1.5-.6.9-1.1.9h-.3c-.6-.2-1-.8-.9-1.4.8-3 3.4-5.1 6.6-5.1 1.6 0 3.2.6 4.4 1.7V76c0-.7.5-1.2 1.2-1.2s1.2.5 1.2 1.2v3.7c0 .7-.5 1.2-1.2 1.2H248c-.7 0-1.2-.5-1.2-1.2zm-.7 8.7c-1.6 0-3.2-.6-4.4-1.7v.5c0 .7-.5 1.2-1.2 1.2s-1.2-.5-1.2-1.2v-3.7c0-.7.5-1.2 1.2-1.2h3.7c.7 0 1.2.5 1.2 1.2s-.5 1.2-1.2 1.2h-1.3c.8.9 1.9 1.4 3.2 1.4 2 0 3.8-1.4 4.3-3.3.2-.6.8-1 1.4-.9.6.2 1 .8.9 1.4-.8 3-3.5 5.1-6.6 5.1z"
fill="url(#a)" transform="translate(1 46)"/><path d="M246.1 52.4c2.9 0 5.3-2.4 5.3-5.3s-2.4-5.3-5.3-5.3-5.3 2.4-5.3 5.3 2.4 5.3 5.3 5.3zm-1.1-8.6c0-.4.3-.7.7-.7.4 0 .7.3.7.7v3.1h3.1c.4 0 .7.3.7.7 0 .4-.3.7-.7.7h-3.7c-.4 0-.7-.3-.7-.7v-3.8h-.1z" fill="url(#b)" transform="translate(1 46)"/><path fill="url(#c)" d="M243.6 68.7l2.5-1.3 2.6 1.3-.5-3 2.1-2.2-2.9-.5-1.3-2.6-1.3 2.6-2.9.5 2.1 2.2" transform="translate(1 46)"/><path d="M240.9 70.5c-.1.5.1.9.5 1.2l.7.4 4-2.1 3.3 1.7c.4.2.9.2 1.3-.1l.6-.5-.7-4.7 2.6-2.8c.3-.3.4-.8.3-1.3l-.3-.7-4.4-.8-1.7-3.5c-.2-.4-.7-.7-1.1-.7l-.8.1-2.1 4.1-3.7.7c-.5.1-.8.4-1 .9l-.2.8 3.1 3.4-.4 3.9zm3.9-7.5l1.3-2.6 1.3 2.6 2.9.5-2.1 2.2.4 3-2.5-1.3-2.5 1.3.4-3-2.1-2.2 2.9-.5z" fill="url(#d)" transform="translate(1 46)"/><path fill="url(#e)" d="M35 60.4l-1.4 2.8-3.1.6 2.2 2.4-.4 3.2 2.7-1.5 2.7 1.5-.4-3.2 2.2-2.4-3.1-.6" transform="translate(1 46)"/><path d="M10.2 103.3h50.7c1.4 0 2.5-1.1 2.5-2.5V27.6c0-1.4-1.1-2.5-2.5-2.5H10.2c-1.4 0-2.5 1.1-2.5 2.5v73.2c.1
1.4 1.2 2.5 2.5 2.5zm32.1-14.5c-.8 3.3-3.8 5.7-7.3 5.7-1.8 0-3.5-.7-4.8-1.8v.4c0 .7-.6 1.3-1.3 1.3-.7 0-1.3-.6-1.3-1.3V89c0-.7.6-1.3 1.3-1.3H33c.7 0 1.3.6 1.3 1.3 0 .7-.6 1.3-1.3 1.3h-1.3c.9.9 2.1 1.4 3.4 1.4 2.2 0 4.1-1.5 4.6-3.6.2-.7.9-1.2 1.6-1 .7.2 1.1 1 1 1.7zm.2-3.9c0 .7-.6 1.3-1.3 1.3h-4.1c-.7 0-1.3-.6-1.3-1.3 0-.7.6-1.3 1.3-1.3h1.3c-.9-.9-2.1-1.4-3.4-1.4-2.2 0-4.1 1.5-4.6 3.6-.2.6-.7 1-1.3 1h-.3c-.7-.2-1.2-.9-1-1.6.8-3.3 3.8-5.7 7.3-5.7 1.8 0 3.5.7 4.8 1.8v-.4c0-.7.6-1.3 1.3-1.3.7 0 1.3.6 1.3 1.3v4zm.5-21L40.1 67l.7 5.1-.7.6c-.4.3-1 .4-1.5.1L35 71l-4.4 2.3-.8-.5c-.4-.3-.7-.8-.6-1.4l.6-4.3-3.4-3.7.2-.9c.2-.5.6-.9 1.1-1l4-.7 2.3-4.6.9-.1c.6 0 1 .3 1.3.8l1.9 3.8 4.8.9.3.8c.3.6.2 1.2-.2 1.5zm-8-30.2c4.7 0 8.5 3.8 8.5 8.5s-3.8 8.5-8.5 8.5-8.5-3.8-8.5-8.5 3.8-8.5 8.5-8.5z" fill="url(#f)" transform="translate(1 46)"/><path d="M29.2 42.2c0 3.2 2.6 5.8 5.8 5.8 3.2 0 5.8-2.6 5.8-5.8 0-3.2-2.6-5.8-5.8-5.8-3.2 0-5.8 2.6-5.8 5.8zm4.6-3.6c0-.4.3-.7.7-.7.4 0 .7.3.7.7V42h3.4c.4 0 .7.3.7.7 0
.4-.3.7-.7.7h-4.1c-.4 0-.7-.3-.7-.7v-4.1z" fill="url(#g)" transform="translate(1 46)"/><path d="M43 61.7l-4.8-.9-1.9-3.8c-.2-.5-.7-.8-1.3-.8l-.9.1-2.3 4.6-4 .7c-.5.1-1 .5-1.1 1l-.2.9 3.4 3.7-.6 4.3c-.1.5.1 1.1.6 1.4l.8.5L35 71l3.6 1.9c.5.3 1.1.2 1.5-.1l.7-.6-.7-5.1L43 64c.4-.4.5-.9.3-1.4l-.3-.9zm-5.7 4.5l.4 3.2L35 68l-2.7 1.4.4-3.2-2.2-2.4 3.1-.6 1.4-2.8 1.4 2.8 3.1.6-2.2 2.4z" fill="url(#h)" transform="translate(1 46)"/><path d="M119.4 59.6c3.2 0 5.8-2.6 5.8-5.8 0-3.2-2.6-5.8-5.8-5.8-3.2 0-5.8 2.6-5.8 5.8-.1 3.1 2.6 5.8 5.8 5.8zm-1.2-9.5c0-.4.3-.7.7-.7.4 0 .7.3.7.7v3.4h3.4c.4 0 .7.3.7.7 0 .4-.3.7-.7.7h-4.1c-.4 0-.7-.3-.7-.7v-4.1z" fill="url(#i)" transform="translate(1 46)"/><path fill="url(#j)" d="M143.4 52.3l-1.3-2.8-1.4 2.8-3.2.6 2.3 2.4-.5 3.2 2.8-1.4 2.7 1.4-.5-3.2 2.3-2.4" transform="translate(1 46)"/><path d="M102.8 81.1h77.6c1.6 0 2.8-1.3 2.8-2.8V32c0-1.6-1.3-2.8-2.8-2.8h-77.6c-1.6 0-2.8 1.3-2.8 2.8v46.3c-.1 1.6 1.2 2.8 2.8 2.8zm44.4-24.9l.7 5.1-.7.6c-.4.3-1 .4-1.5.1l-3.6-1
.9-4.4 2.3-.8-.5c-.4-.3-.7-.8-.6-1.4l.6-4.3-3.4-3.7.2-.9c.2-.5.6-.9 1.1-1l4-.7 2.3-4.6.9-.1c.5 0 1 .3 1.3.8l1.9 3.8 4.8.9.3.8c.2.5 0 1.1-.3 1.4l-2.8 3.3zm10.3-4.3c.8-3.3 3.8-5.7 7.3-5.7 1.8 0 3.5.7 4.8 1.8v-.4c0-.7.6-1.3 1.3-1.3.7 0 1.3.6 1.3 1.3v4.1c0 .7-.6 1.3-1.3 1.3h-4.1c-.7 0-1.3-.6-1.3-1.3 0-.7.6-1.3 1.3-1.3h1.3c-.9-.9-2.1-1.4-3.4-1.4-2.2 0-4.1 1.5-4.6 3.6-.2.6-.7 1-1.3 1h-.3c-.8-.2-1.2-1-1-1.7zm-.3 3.9c0-.7.6-1.3 1.3-1.3h4.1c.7 0 1.3.6 1.3 1.3 0 .7-.6 1.3-1.3 1.3h-1.3c.9.9 2.1 1.4 3.4 1.4 2.2 0 4.1-1.5 4.6-3.6.2-.7.9-1.2 1.6-1 .7.2 1.2.9 1 1.6-.8 3.3-3.8 5.7-7.3 5.7-1.8 0-3.5-.7-4.8-1.8v.4c0 .7-.6 1.3-1.3 1.3-.7 0-1.3-.6-1.3-1.3v-4zm-37.8-10.6c4.7 0 8.5 3.8 8.5 8.5s-3.8 8.5-8.5 8.5-8.5-3.8-8.5-8.5c-.1-4.7 3.8-8.5 8.5-8.5z" fill="url(#k)" transform="translate(1 46)"/><path d="M264.7 75.3h-34.4c-2.6 0-4.6 2.1-4.6 4.6v67.7c0 2.6 2.1 4.6 4.6 4.6h34.4c2.6 0 4.6-2.1 4.6-4.6V79.9c.1-2.5-2-4.6-4.6-4.6zm-11.8 71.1c0 1.2-.9 2.1-2.1 2.1h-6.7c-1.2 0-2.1-.9-2.1-2.1v-.1c0-1.2.9-2.1 2.1-2.1
h6.7c1.2.1 2.1 1 2.1 2.2zm12-7.3c0 1.3-1 2.3-2.3 2.3h-30.1c-1.3 0-2.3-1-2.3-2.3V82.7c0-1.3 1-2.3 2.3-2.3h30.1c1.3 0 2.3 1 2.3 2.3v56.4zM9 160.8h55.2c2.7 0 4.9-2.2 4.9-4.9V70.6c0-2.7-2.2-4.9-4.9-4.9H9c-2.7 0-4.9 2.2-4.9 4.9v85.3c-.1 2.7 2.1 4.9 4.9 4.9zm19.4-5.3v-1.7c0-1 .8-1.8 1.8-1.8H43c1 0 1.8.8 1.8 1.8v1.7c0 1-.8 1.8-1.8 1.8H30.2c-1 0-1.8-.9-1.8-1.8zM8.8 73.6c0-1.4 1.1-2.5 2.5-2.5H62c1.4 0 2.5 1.1 2.5 2.5v73.2c0 1.4-1.1 2.5-2.5 2.5H11.2c-1.4 0-2.5-1.1-2.5-2.5V73.6h.1zm92.4 57.9h82.7c2.6 0 4.8-2.1 4.8-4.8V71.9c0-2.6-2.1-4.8-4.8-4.8h-82.7c-2.6 0-4.8 2.1-4.8 4.8v54.8c0 2.7 2.2 4.8 4.8 4.8zM141 71c0-.9.7-1.6 1.6-1.6.9 0 1.6.7 1.6 1.6 0 .9-.7 1.6-1.6 1.6-.9 0-1.6-.7-1.6-1.6zm-40.1 7c0-1.6 1.3-2.8 2.8-2.8h77.6c1.6 0 2.8 1.3 2.8 2.8v46.3c0 1.6-1.3 2.8-2.8 2.8h-77.6c-1.6 0-2.8-1.3-2.8-2.8V78zm94.8 84.7c1.6 0 3-1.2 3-2.6v-1.4c0-.3-.1-.7-.2-1l-9.9-21.7c-.5-1-1.5-1.7-2.8-1.7H98.7c-1.2 0-2.4.7-2.8 1.7l-9.3 21.7c-.1.3-.2.6-.2.9v1.4c0 1.5 1.3 2.6 3 2.6h106.3v.1zm-11.4-20.2l.5 1.5c.1.4-.5.9-1.2
.9h-5c-.4 0-.8-.2-.8-.4-.1-.6-.2-.9-.5-1.5-.2-.4.4-.9 1.1-.9h5c.4 0 .8.1.9.4zm-7.4-5.3h4.7c.4 0 .7.2.8.4.1.6.2.9.4 1.5.1.4-.4.8-1 .8h-4.6c-.4 0-.8-.2-.9-.4l-.5-1.5c-.2-.4.4-.8 1.1-.8zm-4.3 5.3c.1.6.2.9.3 1.5.1.4-.6.9-1.3.9h-5.1c-.5 0-.8-.2-.9-.5-.2-.6-.2-.9-.4-1.5-.1-.4.5-.9 1.3-.9h5.3c.4.1.8.3.8.5zm-7.1-5.3h5c.4 0 .8.2.8.4.1.6.2.9.3 1.5.1.4-.5.8-1.2.8h-4.9c-.4 0-.8-.2-.8-.4-.2-.6-.2-.9-.4-1.5-.1-.4.5-.8 1.2-.8zm-5.8 5.5c.1.6.1.9.2 1.6.1.4-.5.8-1.2.8h-5.3c-.5 0-.9-.2-1-.5-.1-.6-.2-.9-.3-1.6-.1-.4.5-.8 1.2-.8h5.5c.4-.1.8.1.9.5zm-6.8-5.5h5.2c.5 0 .9.2.9.5.1.6.1.9.2 1.5.1.4-.5.8-1.1.8H153c-.5 0-.9-.2-.9-.5-.1-.6-.2-.9-.3-1.5-.1-.4.5-.8 1.1-.8zm-13.4.6c.1-.3.5-.5 1.1-.5h4.7c.5 0 1 .2 1 .5.1.6.1.9.2 1.5.1.4-.4.7-1.1.7h-5.3c-.6 0-1.1-.3-1-.7.2-.6.2-.9.4-1.5zm-.4 5c.1-.3.5-.6 1.1-.6h5c.6 0 1 .2 1.1.6.1.6.2.9.3 1.6.1.4-.5.8-1.1.8H140c-.7 0-1.2-.4-1.1-.8 0-.6.1-1 .2-1.6zm-11.4-5.5h5.2c.7 0 1.2.4 1.1.8l-.5 1.5c-.1.3-.5.5-1 .5h-5.1c-.6 0-1.2-.4-1.1-.8.1-.6.2-.9.3-1.5.2-.3.6-.5 1.1-.5zm-2 5.5c.
1-.3.5-.5 1-.5h5.5c.7 0 1.3.4 1.1.8-.2.6-.3 1-.4 1.6-.1.3-.5.5-1 .5h-5.3c-.7 0-1.3-.4-1.2-.8.1-.6.2-.9.3-1.6zm-17.7.4c-.3.6-.4 1-.5 1.6-.1.3-.4.5-.8.5h-5c-.7 0-1.3-.4-1.2-.9.2-.6.3-1 .5-1.6.1-.3.5-.5.9-.5h5c.7 0 1.2.5 1.1.9zm1.2-3.5c-.1.3-.5.4-.9.4h-4.6c-.6 0-1.1-.4-.9-.8l.5-1.5c.1-.3.4-.4.8-.4h4.7c.7 0 1.2.4 1.1.8-.3.6-.5.9-.7 1.5zm10.5 5.1c-.1.3-.4.5-.9.5h-5.1c-.7 0-1.3-.4-1.2-.9.1-.6.2-1 .4-1.6.1-.3.4-.5.9-.5h5.3c.7 0 1.3.4 1.2.9-.3.6-.4 1-.6 1.6zm1.1-5.1c-.1.3-.4.4-.9.4H115c-.7 0-1.2-.4-1.1-.8.2-.6.3-.9.4-1.5.1-.3.4-.4.9-.4h5c.7 0 1.2.4 1.1.8l-.5 1.5zm3.1 14.6c.4-2.3.6-3.5 1.1-5.9 0-.3.4-.6.9-.6 13.6-.1 20.5-.2 34.1-.3.5 0 .9.2.9.6.3 2.4.5 3.6.6 6.1 0 .4-.6.8-1.2.8h-35.4c-.6.1-1.1-.3-1-.7z" fill="#FFF"/><path d="M263.7 26.6h-.2v-1.3c0-.6-.5-1.2-1.2-1.2h-6.5c-.6 0-1.2.5-1.2 1.2v1.3h-25.4c-4 0-7.3 3.3-7.3 7.3v67.7c0 4 3.3 7.3 7.3 7.3h34.4c4 0 7.3-3.3 7.3-7.3V33.9c.1-4-3.1-7.3-7.2-7.3zm4.7 75c0 2.6-2.1 4.6-4.6 4.6h-34.4c-2.6 0-4.6-2.1-4.6-4.6V33.9c0-2.6 2.1-4.6 4.6-4.6h34.4c2.6 0 4
.6 2.1 4.6 4.6v67.7zm-16.5-1.2c0 1.2-.9 2.2-2.1 2.2h-6.7c-1.2 0-2.1-.9-2.1-2.1v-.1c0-1.2.9-2.1 2.1-2.1h6.7c1.2 0 2.1.9 2.1 2.1zM54.3 117.5h8.8c4.2 0 7.6-3.4 7.6-7.6V24.6c0-3.6-2.4-6.5-5.7-7.4-.4-.1-.9-.2-1.3-.2H8C3.8 17 .4 20.4.4 24.6v85.3c0 4.2 3.4 7.6 7.6 7.6h46.3zM3 24.6c0-2.7 2.2-4.9 4.9-4.9h55.2c2.7 0 4.9 2.2 4.9 4.9v85.3c0 2.7-2.2 4.9-4.9 4.9H8c-2.7 0-4.9-2.2-4.9-4.9V24.6H3zm26.2 86.7c-1 0-1.8-.8-1.8-1.8v-1.7c0-1 .8-1.8 1.8-1.8H42c1 0 1.8.8 1.8 1.8v1.7c0 1-.8 1.8-1.8 1.8H29.2zm135.3 8.1H194.6c3.1 0 5.7-2.4 5.7-5.3v-1.4c0-.7-.2-1.4-.5-2.1l-9.9-21.7c-.5-1-1.2-1.8-2.2-2.4 1.6-1.4 2.6-3.4 2.6-5.6V26.1c0-4.1-3.4-7.5-7.5-7.5h-82.5c-4.1 0-7.5 3.4-7.5 7.5v54.8c0 2.1.9 4.1 2.3 5.4-1.2.6-2.1 1.5-2.6 2.7l-9.3 21.7c-.3.6-.4 1.3-.4 2v1.4c0 2.9 2.5 5.3 5.7 5.3h76zm-76-2.7c-1.6 0-3-1.2-3-2.6v-1.4c0-.3.1-.6.2-.9L95 90.1c.4-1 1.5-1.7 2.8-1.7h87.1c1.2 0 2.3.7 2.8 1.7l9.9 21.7c.1.3.2.6.2 1v1.4c0 1.5-1.3 2.6-3 2.6H88.5v-.1zm6.9-35.9V26c0-2.6 2.1-4.8 4.8-4.8h82.7c2.6 0 4.8 2.1 4.8 4.8v54.8c0 2.6-2
.1 4.8-4.8 4.8h-82.7c-2.6-.1-4.8-2.2-4.8-4.8zm27.5 27.5c.4-2.3.6-3.5 1.1-5.9 0-.3.4-.6.9-.6 13.6-.1 20.5-.2 34.1-.3.5 0 .9.2.9.6.3 2.4.5 3.6.6 6.1 0 .4-.6.8-1.2.8h-35.4c-.6.1-1.1-.3-1-.7zm-3.8-11.1c-.2.6-.3 1-.5 1.6-.1.3-.4.5-.9.5h-5.1c-.7 0-1.3-.4-1.2-.9.1-.6.2-1 .4-1.6.1-.3.4-.5.9-.5h5.3c.7 0 1.3.5 1.1.9zm5.3 1.2c.1-.6.2-1 .3-1.6.1-.3.5-.5 1-.5h5.5c.7 0 1.3.4 1.1.8-.2.6-.3 1-.4 1.6-.1.3-.5.5-1 .5h-5.3c-.7 0-1.2-.4-1.2-.8zm33.3-2.3c.5 0 .9.2 1 .5.1.6.1.9.2 1.6.1.4-.5.8-1.2.8h-5.3c-.5 0-.9-.2-1-.5-.1-.6-.2-.9-.3-1.6-.1-.4.5-.8 1.2-.8h5.4zm-19.9 2.3c.1-.6.2-.9.3-1.6.1-.3.5-.6 1.1-.6h5c.6 0 1 .2 1.1.6.1.6.2.9.3 1.6.1.4-.5.8-1.1.8H139c-.8-.1-1.3-.4-1.2-.8zm27.7-2.3h5.3c.5 0 .8.2.9.5.1.6.2.9.3 1.5.1.4-.6.9-1.3.9h-5.1c-.5 0-.8-.2-.9-.5-.2-.6-.2-.9-.4-1.5-.2-.5.5-.9 1.2-.9zm-45.1-3.9l-.5 1.5c-.1.3-.4.4-.9.4h-4.9c-.7 0-1.2-.4-1.1-.8.2-.6.3-.9.4-1.5.1-.3.4-.4.9-.4h5c.7 0 1.2.4 1.1.8zm6.3-.9h5.2c.7 0 1.2.4 1.1.8l-.5 1.5c-.1.3-.5.5-1 .5h-5.1c-.6 0-1.2-.4-1.1-.8.1-.6.2-.9.3-1.5.2-.3.6-.5 1.1-.
5zm24.4 2.2c-.1-.6-.2-.9-.3-1.5-.1-.4.5-.8 1.1-.8h5.2c.5 0 .9.2.9.5.1.6.1.9.2 1.5.1.4-.5.8-1.1.8H152c-.4 0-.8-.2-.9-.5zm-13-.2c.1-.6.2-.9.4-1.5.1-.3.5-.5 1.1-.5h4.7c.5 0 1 .2 1 .5.1.6.1.9.2 1.5.1.4-.4.7-1.1.7h-5.3c-.6 0-1.1-.3-1-.7zm25.6.2c-.2-.6-.2-.9-.4-1.5-.1-.4.5-.8 1.2-.8h5c.4 0 .8.2.8.4.1.6.2.9.3 1.5.1.4-.5.8-1.2.8h-4.9c-.4 0-.7-.1-.8-.4zM107 97.2c-.3.6-.4 1-.5 1.6-.1.3-.4.5-.8.5h-5c-.7 0-1.3-.4-1.2-.9.2-.6.3-1 .5-1.6.1-.3.5-.5.9-.5h5c.7 0 1.2.5 1.1.9zm1.8-5c-.2.6-.3.9-.6 1.5-.1.3-.5.4-.9.4h-4.6c-.6 0-1.1-.4-.9-.8l.5-1.5c.1-.3.4-.4.8-.4h4.7c.6 0 1.1.4 1 .8zm68.5 3.9h5c.4 0 .8.2.9.5l.5 1.5c.1.4-.5.9-1.2.9h-5c-.4 0-.8-.2-.8-.4-.1-.6-.2-.9-.5-1.5-.1-.6.4-1 1.1-1zm-2.1-2.6l-.5-1.5c-.1-.4.5-.8 1.2-.8h4.7c.4 0 .7.2.8.4.1.6.2.9.4 1.5.1.4-.4.8-1 .8h-4.6c-.5 0-.9-.2-1-.4zm-33.6-66.9c-.9 0-1.6-.7-1.6-1.6 0-.9.7-1.6 1.6-1.6.9 0 1.6.7 1.6 1.6-.1.9-.8 1.6-1.6 1.6z" fill="url(#l)" transform="translate(1 46)"/><path d="M150.4 51.6l-.3-.8-4.8-.9-1.9-3.8c-.2-.5-.7-.8-1.3-.8l-.9.1-2.3 4.6-4 .7c
-.5.1-1 .5-1.1 1l-.2.9 3.4 3.7-.6 4.3c-.1.5.2 1.1.6 1.4l.8.5 4.4-2.3 3.6 1.9c.5.3 1.1.2 1.5-.1l.7-.6-.7-5.1 2.9-3.1c.3-.5.4-1.1.2-1.6zm-6.1 3.7l.4 3.2-2.7-1.4-2.7 1.4.4-3.2-2.2-2.4 3.1-.6 1.4-2.8 1.4 2.8 3.1.6-2.2 2.4z" fill="url(#m)" transform="translate(1 46)"/><path d="M238.4 47c0 4.2 3.5 7.7 7.7 7.7s7.7-3.5 7.7-7.7-3.5-7.7-7.7-7.7-7.7 3.5-7.7 7.7zm7.7-5.3c2.9 0 5.3 2.4 5.3 5.3s-2.4 5.3-5.3 5.3-5.3-2.4-5.3-5.3 2.4-5.3 5.3-5.3zm-1.1 5.8v-3.7c0-.4.3-.7.7-.7.4 0 .7.3.7.7v3.1h3.1c.4 0 .7.3.7.7 0 .4-.3.7-.7.7h-3.7c-.5-.1-.8-.4-.8-.8zm3 33.4c-.7 0-1.2-.5-1.2-1.2s.5-1.2 1.2-1.2h1.3c-.8-.9-1.9-1.4-3.2-1.4-2 0-3.8 1.4-4.3 3.3-.1.5-.6.9-1.1.9h-.3c-.6-.2-1-.8-.9-1.4.8-3 3.4-5.1 6.6-5.1 1.6 0 3.2.6 4.4 1.7V76c0-.7.5-1.2 1.2-1.2s1.2.5 1.2 1.2v3.7c0 .7-.5 1.2-1.2 1.2H248zm-1.9 7.5c-1.6 0-3.2-.6-4.4-1.7v.5c0 .7-.5 1.2-1.2 1.2s-1.2-.5-1.2-1.2v-3.7c0-.7.5-1.2 1.2-1.2h3.7c.7 0 1.2.5 1.2 1.2s-.5 1.2-1.2 1.2h-1.3c.8.9 1.9 1.4 3.2 1.4 2 0 3.8-1.4 4.3-3.3.2-.6.8-1 1.4-.9.6.2 1 .8.9 1.4-.8 3-3.5 5.1-6.
6 5.1zM35 50.7c4.7 0 8.5-3.8 8.5-8.5s-3.8-8.5-8.5-8.5-8.5 3.8-8.5 8.5 3.8 8.5 8.5 8.5zm0-14.3c3.2 0 5.8 2.6 5.8 5.8 0 3.2-2.6 5.8-5.8 5.8-3.2 0-5.8-2.6-5.8-5.8 0-3.2 2.6-5.8 5.8-5.8zm-1.2 6.3v-4.1c0-.4.3-.7.7-.7.4 0 .7.3.7.7V42h3.4c.4 0 .7.3.7.7 0 .4-.3.7-.7.7h-4.1c-.4 0-.7-.3-.7-.7zm8.7 38.1v4.1c0 .7-.6 1.3-1.3 1.3h-4.1c-.7 0-1.3-.6-1.3-1.3 0-.7.6-1.3 1.3-1.3h1.3c-.9-.9-2.1-1.4-3.4-1.4-2.2 0-4.1 1.5-4.6 3.6-.2.6-.7 1-1.3 1h-.3c-.7-.2-1.2-.9-1-1.6.8-3.3 3.8-5.7 7.3-5.7 1.8 0 3.5.7 4.8 1.8v-.4c0-.7.6-1.3 1.3-1.3.7-.1 1.3.5 1.3 1.2zm-.2 8c-.8 3.3-3.8 5.7-7.3 5.7-1.8 0-3.5-.7-4.8-1.8v.4c0 .7-.6 1.3-1.3 1.3-.7 0-1.3-.6-1.3-1.3V89c0-.7.6-1.3 1.3-1.3H33c.7 0 1.3.6 1.3 1.3 0 .7-.6 1.3-1.3 1.3h-1.3c.9.9 2.1 1.4 3.4 1.4 2.2 0 4.1-1.5 4.6-3.6.2-.7.9-1.2 1.6-1 .7.2 1.1 1 1 1.7zm77.1-26.5c4.7 0 8.5-3.8 8.5-8.5s-3.8-8.5-8.5-8.5-8.5 3.8-8.5 8.5c-.1 4.6 3.8 8.5 8.5 8.5zm0-14.4c3.2 0 5.8 2.6 5.8 5.8 0 3.2-2.6 5.8-5.8 5.8-3.2 0-5.8-2.6-5.8-5.8-.1-3.2 2.6-5.8 5.8-5.8zm-1.2 6.3v-4.1c0-.4.3-.7.7-.7.4 0
.7.3.7.7v3.4h3.4c.4 0 .7.3.7.7 0 .4-.3.7-.7.7h-4.1c-.4 0-.7-.3-.7-.7zm39 5.7v-4.1c0-.7.6-1.3 1.3-1.3h4.1c.7 0 1.3.6 1.3 1.3 0 .7-.6 1.3-1.3 1.3h-1.3c.9.9 2.1 1.4 3.4 1.4 2.2 0 4.1-1.5 4.6-3.6.2-.7.9-1.2 1.6-1 .7.2 1.2.9 1 1.6-.8 3.3-3.8 5.7-7.3 5.7-1.8 0-3.5-.7-4.8-1.8v.4c0 .7-.6 1.3-1.3 1.3-.7.1-1.3-.5-1.3-1.2zm.3-8c.8-3.3 3.8-5.7 7.3-5.7 1.8 0 3.5.7 4.8 1.8v-.4c0-.7.6-1.3 1.3-1.3.7 0 1.3.6 1.3 1.3v4.1c0 .7-.6 1.3-1.3 1.3h-4.1c-.7 0-1.3-.6-1.3-1.3 0-.7.6-1.3 1.3-1.3h1.3c-.9-.9-2.1-1.4-3.4-1.4-2.2 0-4.1 1.5-4.6 3.6-.2.6-.7 1-1.3 1h-.3c-.8-.2-1.2-1-1-1.7z" fill="url(#n)" transform="translate(1 46)"/></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_addons.svg b/browser/extensions/onboarding/content/img/icons_addons.svg
new file mode 100644
index 000000000000..6b27dea39252
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_addons.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="8 8 16 16"><title>Icons / Extension</title><g fill="none"><path d="M0 0h16v16H0z"/><path d="M22.5 16c-1 0-1 1-1.7 1-.5 0-.8-.3-.8-.7V13c0-.6-.4-1-1-1h-3.2c-.5 0-.8-.3-.8-.7 0-.8 1-.8 1-1.8 0-.9-.9-1.5-2-1.5s-2 .6-2 1.5c0 1 1 1 1 1.8 0 .4-.3.7-.7.7H9c-.6 0-1 .4-1 1v2.3c0 .4.3.7.8.7.7 0 .7-1 1.7-1 .9 0 1.5.9 1.5 2s-.6 2-1.5 2c-1 0-1-1-1.7-1-.5 0-.8.3-.8.8V23c0 .6.4 1 1 1h3.3c.4 0 .7-.3.7-.7 0-.8-1-.8-1-1.8 0-.9.9-1.5 2-1.5s2 .6 2 1.5c0 1-1 1-1 1.8 0 .4.3.7.8.7H19c.6 0 1-.4 1-1v-3.2c0-.5.3-.8.8-.8.7 0 .7 1 1.7 1 .9 0 1.5-.9 1.5-2s-.6-2-1.5-2z" fill="#3E3D40"/></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_customize.svg b/browser/extensions/onboarding/content/img/icons_customize.svg
new file mode 100644
index 000000000000..ae0a9409fa5c
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_customize.svg
@@ -0,0 +1 @@
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><title>Glyph / Customize</title><g id="Symbols" fill="none" fill-rule="evenodd"><g id="Glyph-/-Customize" fill-rule="nonzero" fill="#3E3D40"><path d="M4 10c-.886.002-1.665.59-1.91 1.44 0 .01-.015.015-.018.025-.362 1.135-.705 2.11-1.76 2.573l-.022.012-.024.012c-.162.086-.265.254-.266.438 0 .276.224.5.5.5 1.74.12 3.46-.414 4.825-1.5.006-.006.007-.013.013-.02.62-.55.832-1.428.534-2.202C5.575 10.504 4.83 9.995 4 10zM15.693.307c-.365-.363-.95-.383-1.338-.046l-8.03 7c-.206.18-.327.435-.336.707-.01.27.093.535.285.727l1.032 1.03c.184.185.433.288.693.288h.033c.272-.01.527-.13.706-.335l7-8.03c.338-.39.318-.975-.047-1.34z" id="Shape"/></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_default.svg b/browser/extensions/onboarding/content/img/icons_default.svg
new file mode 100644
index 000000000000..235f7d65b685
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_default.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><title>default-browser-16</title><path fill="context-fill" d="M8,6s0-4,3.5-4S15,5,15,6c0,4.5-7,9-7,9Z"/><path fill="context-fill" d="M8,6S8,2,4.5,2,1,5,1,6c0,4.5,7,9,7,9L9,9Z"/></svg>
diff --git a/browser/extensions/onboarding/content/img/icons_library.svg b/browser/extensions/onboarding/content/img/icons_library.svg
new file mode 100644
index 000000000000..064c2e619486
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_library.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg width="92px" height="92px" viewBox="0 0 92 92" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>Tip / Icon / Library</title><desc>Created with Sketch.</desc><defs></defs><g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Tip-/-Icon-/-Library" fill-rule="nonzero" fill="#0C0C0D"><g id="Icon-/-Library-/-Web"><path d="M28.7405828,17.2350375 C25.5662458,17.2350375 22.9929371,19.8060508 22.9929371,22.9775563 L22.9929371,80.402744 C22.9929371,83.5742496 25.5662458,86.1452628 28.7405828,86.1452628 C31.9149199,86.1452628 34.4882285,83.5742496 34.4882285,80.402744 L34.4882285,22.9775563 C34.4882285,19.8060508 31.9149199,17.2350375 28.7405828,17.2350375 Z M45.98352,11.4925188 C42.8091829,11.4925188 40.2358743,14.063532 40.2358743,17.2350375 L40.2358743,80.402744 C40.2358743,83.5742496 42.8091829,86.1452628 45.98352,86.1452628 C49.157857,86.1452628 51.7311657,83.574249
6 51.7311657,80.402744 L51.7311657,17.2350375 C51.7311657,14.063532 49.157857,11.4925188 45.98352,11.4925188 Z M91.6140792,78.4388026 L68.6234964,15.2710961 C67.9500245,13.3049026 66.2658683,11.8556604 64.2198302,11.4816739 C62.1737921,11.1076875 60.0851643,11.8673187 58.7585671,13.4679283 C57.4319699,15.0685378 57.0744241,17.2603443 57.8236701,19.198979 L80.814253,82.3666855 C81.4877249,84.332879 83.1718811,85.7821212 85.2179192,86.1561076 C87.2639573,86.5300941 89.3525851,85.7704629 90.6791823,84.1698533 C92.0057794,82.5692438 92.3633253,80.3774372 91.6140792,78.4388026 L91.6140792,78.4388026 Z M11.4976457,5.75 C8.32330864,5.75 5.75,8.32101323 5.75,11.4925188 L5.75,80.402744 C5.75,83.5742496 8.32330864,86.1452628 11.4976457,86.1452628 C14.6719828,86.1452628 17.2452914,83.5742496 17.2452914,80.402744 L17.2452914,11.4925188 C17.2452914,8.32101323 14.6719828,5.75 11.4976457,5.75 Z" id="Shape"></path></g></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_performance.svg b/browser/extensions/onboarding/content/img/icons_performance.svg
new file mode 100644
index 000000000000..ad23ba27400c
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_performance.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="context-fill" d="M8 1a8.009 8.009 0 0 0-8 8 7.917 7.917 0 0 0 .78 3.43 1 1 0 1 0 1.8-.86A5.943 5.943 0 0 1 2 9a6 6 0 1 1 11.414 2.571 1 1 0 1 0 1.807.858A7.988 7.988 0 0 0 8 1z"/><path fill="context-fill" d="M11.769 7.078a.5.5 0 0 0-.69.153L8.616 11.1a2 2 0 1 0 .5 3.558 2.011 2.011 0 0 0 .54-.54 1.954 1.954 0 0 0-.2-2.479l2.463-3.871a.5.5 0 0 0-.15-.69z"/></svg>
diff --git a/browser/extensions/onboarding/content/img/icons_private.svg b/browser/extensions/onboarding/content/img/icons_private.svg
new file mode 100755
index 000000000000..7d4d2c416801
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_private.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="8 8 16 16"><title>Icons / Private Browsing</title><g fill="none"><path d="M0 0h32v32H0z"/><path d="M20.4 20c-1.7 0-2.8-2-4.4-2-1.6 0-2.8 2-4.4 2-2 0-3.5-2-3.5-5.3-.1-2 .6-2.7 3.2-2.7s3.4 1.1 4.7 1.1c1.3 0 2.1-1.1 4.7-1.1s3.3.7 3.2 2.7c0 3.3-1.5 5.3-3.5 5.3zm-7.8-5.4c-1.6 0-2.3 1-2.3 1.2 0 .3 1.1.9 2.1.9 1.1 0 2.3-.4 2.3-.7-.2-1-1.1-1.6-2.1-1.4zm6.8 0c-1-.2-1.9.4-2.1 1.4 0 .3 1.2.7 2.3.7 1 0 2.1-.6 2.1-.9 0-.2-.7-1.2-2.3-1.2z" fill="#3E3D40"/></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_screenshots.svg b/browser/extensions/onboarding/content/img/icons_screenshots.svg
new file mode 100644
index 000000000000..8d219dce78b5
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_screenshots.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg width="92px" height="92px" viewBox="0 0 92 92" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>Tip / Icon / Screenshots</title><desc>Created with Sketch.</desc><defs></defs><g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Tip-/-Icon-/-Screenshots" fill-rule="nonzero" fill="#0C0C0D"><g id="Icon-/-Screenshot-/-Web"><path d="M23.0526905,5.75 C16.7062659,5.75 11.5614723,10.8982866 11.5614723,17.2490201 L23.0526905,17.2490201 L23.0526905,5.75 Z M57.5263453,5.75 L46.035127,5.75 L46.035127,17.2490201 L57.5263453,17.2490201 L57.5263453,5.75 Z M80.5087818,5.75 L80.5087818,17.2490201 L92,17.2490201 C92,10.8982866 86.8552063,5.75 80.5087818,5.75 Z M40.2895179,5.75 L28.7982997,5.75 L28.7982997,17.2490201 L40.2895179,17.2490201 L40.2895179,5.75 Z M74.7631726,5.75 L63.2719544,5.75 L63.2719544,17.2490201 L74.7631726,17.2490201 L74.7631726,5.75 Z M80.5087818,34.4975502
L92,34.4975502 L92,22.9985301 L80.5087818,22.9985301 L80.5087818,34.4975502 Z M80.5087818,68.9946104 C86.8552063,68.9946104 92,63.8463237 92,57.4955903 L80.5087818,57.4955903 L80.5087818,68.9946104 Z M80.5087818,51.7460803 L92,51.7460803 L92,40.2470602 L80.5087818,40.2470602 L80.5087818,51.7460803 Z M77.9749681,39.286892 C74.3364854,34.0846734 67.1729138,32.8182928 61.9734467,36.4581331 L39.9390357,52.734996 L28.631677,44.8006721 C28.7205927,44.2448747 28.7762328,43.6842562 28.7982997,43.1218152 C28.7892628,38.6172543 26.6604054,34.3800822 23.0526905,31.6860398 L23.0526905,22.9985301 L11.5614723,22.9985301 L11.5614723,29.0355156 C5.79583786,30.1835386 1.31120668,34.7313256 0.240775953,40.5156383 C-0.829654779,46.2999509 1.73019662,52.1531434 6.70268981,55.2910372 C11.675183,58.4289309 18.0565494,58.2180974 22.811375,54.7588235 L29.9474215,59.7551477 L21.9035687,65.4011666 C16.3310302,62.0167647 9.17796578,62.8225007 4.49677041,67.3619045 C-0.184424965,71.9013083 -1.21401,79.0303725
1.99130168,84.710299 C5.19661336,90.3902255 11.8290284,93.1895755 18.1311131,91.5224455 C24.4331979,89.8553154 28.8167193,84.1418505 28.7982997,77.6188754 C28.7959008,76.6687877 28.699673,75.721263 28.5110192,74.7901165 L77.9749681,39.286892 Z M14.4342769,50.3087028 C10.4677615,50.3087028 7.25226545,47.0910236 7.25226545,43.1218152 C7.25226545,39.1526068 10.4677615,35.9349277 14.4342769,35.9349277 C18.4007922,35.9349277 21.6162883,39.1526068 21.6162883,43.1218152 C21.6162883,47.0910236 18.4007922,50.3087028 14.4342769,50.3087028 Z M14.4342769,84.805763 C10.4677615,84.805763 7.25226545,81.5880838 7.25226545,77.6188754 C7.25226545,73.649667 10.4677615,70.4319879 14.4342769,70.4319879 C18.4007922,70.4319879 21.6162883,73.649667 21.6162883,77.6188754 C21.6162883,81.5880838 18.4007922,84.805763 14.4342769,84.805763 Z M45.4605661,70.8402031 L62.7950688,84.0640762 C67.9945359,87.7039165 75.1581075,86.4375358 78.7965902,81.2353172 L55.457926,63.8200513 L45.4605661,70.8402031 Z" id="Shape"><
/path></g></g></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_singlesearch.svg b/browser/extensions/onboarding/content/img/icons_singlesearch.svg
new file mode 100644
index 000000000000..3e06a3852288
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_singlesearch.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="8 8 16 16 "><title>Icons / Search</title><g fill="none"><path d="M0 0h32v32H0z"/><path d="M23.7 22.3l-4.8-4.8c1.8-2.5 1.4-6.1-1-8.1s-5.9-1.9-8.1.4c-2.3 2.2-2.4 5.7-.4 8.1 2 2.4 5.6 2.8 8.1 1l4.8 4.8c.4.4 1 .4 1.4 0 .4-.4.4-1 0-1.4zM14 18c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4c0 1.1-.4 2.1-1.1 2.9-.8.7-1.8 1.1-2.9 1.1z" fill="#3E3D40"/></g></svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/icons_sync.svg b/browser/extensions/onboarding/content/img/icons_sync.svg
new file mode 100644
index 000000000000..286422275aa7
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_sync.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="8 8 16 16"><title> Icons / Sync</title><desc> Created with Sketch.</desc><g fill="none"><rect width="32" height="32"/><path d="M22 9C21.4 9 21 9.4 21 10L21 11.1C19.2 9.3 16.6 8.6 14.2 9.2 11.7 9.9 9.8 11.8 9.2 14.3 9.1 14.7 9.2 15 9.5 15.3 9.8 15.5 10.1 15.6 10.5 15.5 10.8 15.4 11.1 15.1 11.2 14.8 11.7 12.6 13.7 11 16 11 17.6 11 19 11.7 20 13L18 13C17.4 13 17 13.4 17 14 17 14.6 17.4 15 18 15L22 15C22.6 15 23 14.6 23 14L23 10C23 9.4 22.6 9 22 9ZM22 16.5C21.8 16.4 21.5 16.5 21.3 16.6 21.1 16.7 20.9 17 20.8 17.2 20.3 19.4 18.3 21 16 21 14.4 21 13 20.3 12 19L14 19C14.6 19 15 18.6 15 18 15 17.4 14.6 17 14 17L10 17C9.4 17 9 17.4 9 18L9 22C9 22.6 9.4 23 10 23 10.6 23 11 22.6 11 22L11 20.9C12.8 22.7 15.4 23.4 17.8 22.8 20.3 22.1 22.2 20.2 22.8 17.7 22.9 17.2 22.6 16.6 22 16.5Z" fill="#3E3D40"/></g></svg>
diff --git a/browser/extensions/onboarding/content/img/icons_tour-complete.svg b/browser/extensions/onboarding/content/img/icons_tour-complete.svg
new file mode 100644
index 000000000000..173e72c332df
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/icons_tour-complete.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 44.1 (41455) - http://www.bohemiancoding.com/sketch -->
+ <title>Tip / Check</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Tips-/-Navigation" transform="translate(-30.000000, -117.000000)" stroke-width="2">
+ <g id="Group">
+ <g id="Tip-/-Check" transform="translate(30.000000, 117.000000)">
+ <circle id="Oval-2" stroke="#FFFFFF" fill="#33F70C" fill-rule="evenodd" cx="10" cy="10" r="9"></circle>
+ <polyline id="Path-31" stroke="#165866" stroke-linecap="round" stroke-linejoin="round" points="5.5 10.5 8.5 13.5 14.5 6.5"></polyline>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/browser/extensions/onboarding/content/img/watermark.svg b/browser/extensions/onboarding/content/img/watermark.svg
new file mode 100644
index 000000000000..c9345ed2ba1d
--- /dev/null
+++ b/browser/extensions/onboarding/content/img/watermark.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><title>newtab-firefox-gry</title><path d="M31.359,14.615h0c-.044-.289-.088-.459-.088-.459s-.113.131-.3.378A10.77,10.77,0,0,0,30.6,12.5a13.846,13.846,0,0,0-.937-2.411,10.048,10.048,0,0,0-.856-1.468q-.176-.263-.359-.51c-.57-.931-1.224-1.5-1.981-2.576a7.806,7.806,0,0,1-.991-2.685A10.844,10.844,0,0,0,25,4.607c-.777-.784-1.453-1.341-1.861-1.721C21.126,1.006,21.36.031,21.36.031h0S17.6,4.228,19.229,8.6a8.4,8.4,0,0,0,2.8,3.733c1.576,1.3,3.273,2.323,4.168,4.937a8.377,8.377,0,0,0-3.144-3.317,7.573,7.573,0,0,1,.6,3,7.124,7.124,0,0,1-8.711,6.94,6.561,6.561,0,0,1-1.765-.6,7.183,7.183,0,0,1-2.115-1.955l-.01-.017.126.046a6.5,6.5,0,0,0,.9.241,5.628,5.628,0,0,0,3.583-.423c1.126-.625,1.808-1.088,2.361-.905l.01,0c.54.172.966-.352.58-.9a2.94,2.94,0,0,0-2.848-1.112c-1.127.164-2.16.965-3.637.189a3.129,3.129,0,0,1-.277-.163c-.1-.057.317.087.22.022a7.33,7.33,0,0,1-.928-.554c-.022-.018.223.07.2.052a3.581,3.581,0,0,1-.968-.979
,1.741,1.741,0,0,1-.066-1.554,1.371,1.371,0,0,1,.6-.564c.191.094.309.165.309.165s-.087-.16-.134-.244c.017-.006.032,0,.049-.011.167.072.537.26.732.375a1.016,1.016,0,0,1,.335.3s.067-.033.017-.173a.9.9,0,0,0-.346-.424l.016,0a2.94,2.94,0,0,1,.426.265,2.079,2.079,0,0,0,.17-.9,1.178,1.178,0,0,0-.069-.5c-.053-.1.03-.14.123-.035a.976.976,0,0,0-.079-.238v-.008h0s.053-.069.077-.094a1.43,1.43,0,0,1,.216-.176,9.973,9.973,0,0,1,1.465-.747c.414-.181.757-.319.827-.359a2.3,2.3,0,0,0,.293-.225,1.968,1.968,0,0,0,.66-1.14,1.6,1.6,0,0,0,.017-.178v-.05l0-.03v0l0-.012v0l0-.013h0c-.06-.225-.448-.394-2.476-.584a1.773,1.773,0,0,1-1.45-1.36l0,.009c-.029.074-.055.149-.081.225.026-.075.052-.15.081-.225l0-.016a5.138,5.138,0,0,1,1.986-2.466c.052-.042-.208.011-.156-.032a5.156,5.156,0,0,1,.53-.224c.091-.038-.39-.222-.815-.177a2.2,2.2,0,0,0-.756.178c.1-.086.4-.2.329-.2a4.865,4.865,0,0,0-1.542.583.314.314,0,0,1,.03-.14,2.4,2.4,0,0,0-.964.744,1.275,1.275,0,0,0,.01-.174,2.876,2.876,0,0,0-.473.444l-.009.007a6.285,6.285
,0,0,0-3.517-.3l-.01-.009.012,0a2.943,2.943,0,0,1-.625-.7L6.1,5.852,6.081,5.83c-.077-.114-.156-.243-.237-.387-.058-.1-.117-.217-.176-.338,0-.008-.009-.011-.013-.012-.024,0-.041.111-.061.082l0-.006a4.308,4.308,0,0,1-.283-1.687l-.016.008a1.884,1.884,0,0,0-.714.934c-.061.137-.1.212-.14.287,0,.006,0-.01,0-.035.009-.069.039-.211.032-.2s-.012.019-.019.029a1.733,1.733,0,0,0-.251.372,2.355,2.355,0,0,0-.15.382c-.006.021,0-.018,0-.064s.009-.128,0-.111l-.022.043a9.5,9.5,0,0,0-.8,3.035A3.022,3.022,0,0,0,3.2,8.7v.016a6.628,6.628,0,0,0-.817,1.1,15.606,15.606,0,0,0-1.727,4.23,10.351,10.351,0,0,1,.925-1.621,15,15,0,0,0-1.045,5.5,14.233,14.233,0,0,1,.45-1.629A13.807,13.807,0,0,0,2.234,22.76a15.037,15.037,0,0,0,5.951,6.748h0a13.016,13.016,0,0,0,3.468,1.662c.162.059.326.117.494.173-.053-.021-.1-.044-.153-.067a15.7,15.7,0,0,0,4.5.662c5.394,0,7.175-2.054,7.339-2.259h0a2.73,2.73,0,0,0,.637-.856h0q.156-.064.315-.137l.067-.03.121-.057a11.312,11.312,0,0,0,2.277-1.426,5.5,5.5,0,0,0,2.123-3.1h0a1.938,1.938,0,
0,0,.029-1.428q.083-.131.171-.28a12.706,12.706,0,0,0,1.907-6.181v-.006c0-.059,0-.118,0-.177A7.731,7.731,0,0,0,31.359,14.615Z" fill="context-fill"/></svg>
diff --git a/browser/extensions/onboarding/content/onboarding-tour-agent.js b/browser/extensions/onboarding/content/onboarding-tour-agent.js
new file mode 100644
index 000000000000..d60a41b2c9f5
--- /dev/null
+++ b/browser/extensions/onboarding/content/onboarding-tour-agent.js
@@ -0,0 +1,94 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* globals Mozilla */
+
+(function() {
+"use strict";
+
+let onCanSetDefaultBrowserInBackground = () => {
+ Mozilla.UITour.getConfiguration("appinfo", config => {
+ let canSetInBackGround = config.canSetDefaultBrowserInBackground;
+ let btn = document.getElementById("onboarding-tour-default-browser-button");
+ btn.setAttribute("data-cansetbg", canSetInBackGround);
+ btn.textContent = canSetInBackGround ? btn.getAttribute("data-bg") : btn.getAttribute("data-panel");
+ });
+};
+
+let onClick = evt => {
+ switch (evt.target.id) {
+ case "onboarding-tour-addons-button":
+ Mozilla.UITour.showHighlight("addons");
+ break;
+ case "onboarding-tour-customize-button":
+ Mozilla.UITour.showHighlight("customize");
+ break;
+ case "onboarding-tour-default-browser-button":
+ Mozilla.UITour.getConfiguration("appinfo", (config) => {
+ let isDefaultBrowser = config.defaultBrowser;
+ let btn = document.getElementById("onboarding-tour-default-browser-button");
+ let msg = document.getElementById("onboarding-tour-is-default-browser-msg");
+ let canSetInBackGround = btn.getAttribute("data-cansetbg") === "true";
+ if (isDefaultBrowser || canSetInBackGround) {
+ btn.classList.add("onboarding-hidden");
+ msg.classList.remove("onboarding-hidden");
+ if (canSetInBackGround) {
+ Mozilla.UITour.setConfiguration("defaultBrowser");
+ }
+ } else {
+ btn.disabled = true;
+ Mozilla.UITour.setConfiguration("defaultBrowser");
+ }
+ });
+ break;
+ case "onboarding-tour-library-button":
+ Mozilla.UITour.showHighlight("library");
+ break;
+ case "onboarding-tour-private-browsing-button":
+ Mozilla.UITour.showHighlight("privateWindow");
+ break;
+ case "onboarding-tour-singlesearch-button":
+ Mozilla.UITour.showMenu("urlbar");
+ break;
+ case "onboarding-tour-sync-button":
+ let emailInput = document.getElementById("onboarding-tour-sync-email-input");
+ if (emailInput.checkValidity()) {
+ Mozilla.UITour.showFirefoxAccounts(null, emailInput.value);
+ }
+ break;
+ case "onboarding-tour-sync-connect-device-button":
+ Mozilla.UITour.showConnectAnotherDevice();
+ break;
+ }
+ let classList = evt.target.classList;
+ // On keyboard navigation the target would be .onboarding-tour-item.
+ // On mouse clicking the target would be .onboarding-tour-item-container.
+ if (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container")) {
+ Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to change to other tours.
+ }
+};
+
+let overlay = document.getElementById("onboarding-overlay");
+overlay.addEventListener("submit", e => e.preventDefault());
+overlay.addEventListener("click", onClick);
+overlay.addEventListener("keypress", e => {
+ let { target, key } = e;
+ let classList = target.classList;
+ if ((key == " " || key == "Enter") &&
+ // On keyboard navigation the target would be .onboarding-tour-item.
+ // On mouse clicking the target would be .onboarding-tour-item-container.
+ (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container"))) {
+ Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to change to other tours.
+ }
+});
+let overlayObserver = new MutationObserver(mutations => {
+ if (!overlay.classList.contains("onboarding-opened")) {
+ Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to close the dialog.
+ }
+});
+overlayObserver.observe(overlay, { attributes: true });
+document.getElementById("onboarding-overlay-button").addEventListener("Agent:Destroy", () => Mozilla.UITour.hideHighlight());
+document.addEventListener("Agent:CanSetDefaultBrowserInBackground", onCanSetDefaultBrowserInBackground);
+
+})();
diff --git a/browser/extensions/onboarding/content/onboarding.css b/browser/extensions/onboarding/content/onboarding.css
new file mode 100644
index 000000000000..8f2431477634
--- /dev/null
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -0,0 +1,589 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#onboarding-overlay * {
+ box-sizing: border-box;
+}
+
+#onboarding-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ /* Ensuring we can put the overlay over elements using
+ z-index on original page */
+ z-index: 20999;
+ color: #4d4d4d;
+ background: var(--newtab-overlay-color, rgb(245, 245, 247, 0.9)); /* #f7f7f5, 0.9 opacity */
+ display: none;
+}
+
+#onboarding-overlay.onboarding-opened {
+ display: block;
+}
+
+#onboarding-overlay-button {
+ padding: 10px 0 0 0;
+ position: fixed;
+ cursor: pointer;
+ top: 4px;
+ inset-inline-start: 12px;
+ border: none;
+ /* Set to none so no grey contrast background in the high-contrast mode */
+ background: none;
+ /* make sure the icon stay above the activity-stream searchbar */
+ /* We want this always under #onboarding-overlay */
+ z-index: 10;
+}
+
+/* Keyboard focus styling */
+#onboarding-overlay-button:-moz-focusring {
+ outline: solid 2px rgba(0, 0, 0, 0.1);
+ -moz-outline-radius: 5px;
+ outline-offset: 5px;
+ transition: outline-offset 150ms;
+}
+
+#onboarding-overlay-button > img {
+ width: 32px;
+ vertical-align: top;
+}
+
+#onboarding-overlay-button::after {
+ content: " ";
+ border-radius: 50%;
+ margin-top: -1px;
+ margin-inline-start: -13px;
+ border: 2px solid #f2f2f2;
+ background: #0A84FF;
+ padding: 0;
+ width: 10px;
+ height: 10px;
+ min-width: unset;
+ max-width: unset;
+ display: block;
+ box-sizing: content-box;
+ float: inline-end;
+ position: relative;
+}
+
+#onboarding-overlay-button:hover::after,
+#onboarding-overlay-button.onboarding-speech-bubble::after {
+ background: #0060df;
+ font-size: 13px;
+ text-align: center;
+ color: #fff;
+ box-sizing: content-box;
+ font-weight: 400;
+ content: attr(aria-label);
+ border: 1px solid transparent;
+ border-radius: 2px;
+ padding: 10px 16px;
+ width: auto;
+ height: auto;
+ min-width: 100px;
+ max-width: 140px;
+ white-space: pre-line;
+ margin-inline-start: 4px;
+ margin-top: -10px;
+ box-shadow: -2px 0 5px 0 rgba(74, 74, 79, 0.25);
+}
+
+#onboarding-overlay-button:dir(rtl)::after {
+ box-shadow: 2px 0 5px 0 rgba(74, 74, 79, 0.25);
+}
+
+#onboarding-overlay-button-watermark-icon {
+ -moz-context-properties: fill;
+ fill: var(--newtab-icon-tertiary-color, #d7d7db);
+}
+
+#onboarding-overlay-button-watermark-icon,
+#onboarding-overlay-button.onboarding-watermark::after,
+#onboarding-overlay-button.onboarding-watermark:not(:hover) > #onboarding-overlay-button-icon {
+ display: none;
+}
+
+#onboarding-overlay-button.onboarding-watermark:not(:hover) > #onboarding-overlay-button-watermark-icon {
+ display: block;
+}
+
+#onboarding-overlay-dialog,
+.onboarding-hidden,
+#onboarding-tour-sync-page[data-login-state=logged-in] .show-on-logged-out,
+#onboarding-tour-sync-page[data-login-state=logged-out] .show-on-logged-in {
+ display: none;
+}
+
+.onboarding-close-btn {
+ position: absolute;
+ top: 15px;
+ inset-inline-end: 15px;
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+ border: none;
+ background: none;
+ padding: 0;
+ }
+
+.onboarding-close-btn::before {
+ content: url("chrome://global/skin/icons/close.svg");
+ -moz-context-properties: fill, fill-opacity;
+ fill-opacity: 0;
+ fill: var(--newtab-icon-primary-color, currentColor);
+}
+
+.onboarding-close-btn:-moz-any(:hover, :active, :focus, :-moz-focusring)::before {
+ fill-opacity: 0.1;
+}
+
+#onboarding-overlay.onboarding-opened > #onboarding-overlay-dialog {
+ width: 960px;
+ height: 510px;
+ background: #fff;
+ border: 1px solid rgba(9, 6, 13, 0.2); /* #09060D, 0.2 opacity */
+ border-radius: 3px;
+ position: relative;
+ margin: 0 calc(50% - 480px);
+ top: calc(50% - 255px);
+ display: grid;
+ grid-template-rows: [dialog-start] 70px [page-start] 1fr [footer-start] 30px [dialog-end];
+ grid-template-columns: [dialog-start] 230px [page-start] 1fr [dialog-end];
+ box-shadow: 0 3px rgba(0, 0, 0, 0.04);
+}
+
+#onboarding-overlay.onboarding-opened > #onboarding-overlay-dialog:-moz-focusring {
+ outline: none;
+}
+
+@media (max-height: 510px) {
+ #onboarding-overlay.onboarding-opened > #onboarding-overlay-dialog {
+ top: 0;
+ }
+}
+
+#onboarding-overlay-dialog > header {
+ grid-row: dialog-start / page-start;
+ grid-column: dialog-start / tour-end;
+ margin-top: 22px;
+ margin-bottom: 0;
+ margin-inline-end: 0;
+ margin-inline-start: 36px;
+ font-size: 22px;
+ font-weight: 200;
+}
+
+#onboarding-overlay-dialog > nav {
+ grid-row: dialog-start / footer-start;
+ grid-column-start: dialog-start;
+ margin-top: 40px;
+ margin-bottom: 0;
+ margin-inline-end: 0;
+ margin-inline-start: 0;
+ padding: 0;
+}
+
+#onboarding-overlay-dialog > footer {
+ grid-column: dialog-start / tour-end;
+ font-size: 13px;
+}
+
+#onboarding-skip-tour-button {
+ margin-inline-start: 27px;
+ margin-bottom: 27px;
+}
+
+/* Onboarding tour list */
+#onboarding-tour-list {
+ margin: 40px 0 0 0;
+ padding: 0;
+ margin-inline-start: 16px;
+}
+
+#onboarding-tour-list .onboarding-tour-item-container {
+ list-style: none;
+ outline: none;
+ position: relative;
+}
+
+#onboarding-tour-list .onboarding-tour-item {
+ pointer-events: none;
+ display: list-item;
+ padding-inline-start: 49px;
+ padding-top: 14px;
+ padding-bottom: 14px;
+ margin-bottom: 9px;
+ font-size: 16px;
+ cursor: pointer;
+ max-height: 54px;
+ --onboarding-tour-item-active-color: #0A84FF;
+}
+
+#onboarding-tour-list .onboarding-tour-item:dir(rtl) {
+ background-position-x: right 17px;
+}
+
+#onboarding-tour-list .onboarding-tour-item.onboarding-complete::before {
+ content: url("img/icons_tour-complete.svg");
+ position: relative;
+ inset-inline-start: 3px;
+ top: -10px;
+ float: inline-start;
+}
+
+#onboarding-tour-list .onboarding-tour-item.onboarding-complete {
+ padding-inline-start: 29px;
+}
+
+#onboarding-tour-list .onboarding-tour-item::after {
+ content: "";
+ display: block;
+ width: 48px;
+ height: 48px;
+ position: absolute;
+ inset-inline-start: 0px;
+ top: 0px;
+ background-color: #3E3D40;
+ mask-repeat: no-repeat;
+ mask-position: left 17px top 14px;
+ mask-size: 20px;
+}
+
+#onboarding-tour-list .onboarding-tour-item:dir(rtl)::after {
+ mask-position: right 17px top 14px;
+}
+
+#onboarding-tour-list .onboarding-tour-item.onboarding-active::after,
+#onboarding-tour-list .onboarding-tour-item-container:hover .onboarding-tour-item::after {
+ background-color: var(--onboarding-tour-item-active-color);
+}
+
+#onboarding-tour-list .onboarding-tour-item.onboarding-active,
+#onboarding-tour-list .onboarding-tour-item-container:hover .onboarding-tour-item {
+ color: var(--onboarding-tour-item-active-color);
+ /* With 1px transparent outline, could see a border in the high-constrast mode */
+ outline: 1px solid transparent;
+}
+
+/* Default browser tour */
+#onboarding-tour-is-default-browser-msg {
+ font-size: 16px;
+ line-height: 21px;
+ float: inline-end;
+ margin-inline-end: 26px;
+ margin-top: -32px;
+ text-align: center;
+}
+
+/* Sync tour */
+#onboarding-tour-sync-page form {
+ text-align: center;
+}
+
+#onboarding-tour-sync-page form > h3 {
+ text-align: center;
+ margin: 0;
+ font-size: 22px;
+ font-weight: normal;
+}
+
+#onboarding-tour-sync-page form > p {
+ text-align: center;
+ margin: 3px 0 0 0;
+ font-size: 15px;
+ font-weight: normal;
+}
+
+#onboarding-tour-sync-page form > input {
+ margin-top: 10px;
+ height: 40px;
+ width: 80%;
+ padding: 7px;
+}
+
+#onboarding-tour-sync-page form > #onboarding-tour-sync-button {
+ padding: 10px 20px;
+ min-width: 40%;
+ margin: 15px 0;
+ float: none;
+}
+
+/* Onboarding tour pages */
+.onboarding-tour-page {
+ grid-row: page-start / footer-end;
+ grid-column: page-start;
+ display: grid;
+ grid-template-rows: [tour-page-start] 393px [tour-button-start] 1fr [tour-page-end];
+ grid-template-columns: [tour-page-start] 368px [tour-content-start] 1fr [tour-page-end];
+}
+
+.onboarding-tour-description {
+ grid-row: tour-page-start / tour-page-end;
+ grid-column: tour-page-start / tour-content-start;
+ font-size: 15px;
+ line-height: 22px;
+ padding-inline-start: 40px;
+ padding-inline-end: 28px;
+ max-height: 360px;
+ overflow: auto;
+}
+
+.onboarding-tour-description > h1 {
+ font-size: 36px;
+ margin-top: 16px;
+ font-weight: 300;
+ line-height: 44px;
+}
+
+.onboarding-tour-content {
+ grid-row: tour-page-start / tour-button-start;
+ grid-column: tour-content-start / tour-page-end;
+ padding: 0;
+ text-align: end;
+}
+
+.onboarding-tour-content > img {
+ width: 352px;
+ margin: 0;
+}
+
+/* These illustrations need to be stuck on the right side to the border. Thus we
+ need to flip them horizontally on RTL . */
+.onboarding-tour-content > img:dir(rtl) {
+ transform: scaleX(-1);
+}
+
+.onboarding-tour-content > iframe {
+ width: 100%;
+ height: 100%;
+ border: none;
+}
+
+.onboarding-tour-button-container {
+ /* Get higher z-index in order to ensure buttons within container are selectable */
+ z-index: 2;
+ grid-row: tour-button-start / tour-page-end;
+ grid-column: tour-content-start / tour-page-end;
+}
+
+.onboarding-tour-action-button {
+ background: #0060df;
+ /* With 1px transparent border, could see a border in the high-constrast mode */
+ border: 1px solid transparent;
+ border-radius: 2px;
+ padding: 10px 20px;
+ font-size: 14px;
+ font-weight: 600;
+ line-height: 16px;
+ color: #fff;
+ float: inline-end;
+ margin-inline-end: 26px;
+ margin-top: -32px;
+}
+
+/* Remove default dotted outline around buttons' text */
+#onboarding-overlay button::-moz-focus-inner,
+#onboarding-overlay-button::-moz-focus-inner {
+ border: 0;
+}
+
+/* Keyboard focus specific outline */
+#onboarding-overlay button:-moz-focusring,
+.onboarding-action-button:-moz-focusring,
+#onboarding-tour-list .onboarding-tour-item:focus {
+ outline: 2px solid rgba(0,149,221,0.5);
+ outline-offset: 1px;
+ -moz-outline-radius: 2px;
+}
+
+.onboarding-tour-action-button:hover:not([disabled]) {
+ background: #003eaa;
+ cursor: pointer;
+}
+
+.onboarding-tour-action-button:active:not([disabled]) {
+ background: #002275;
+}
+
+.onboarding-tour-action-button:disabled {
+ opacity: 0.5;
+}
+
+/* Tour Icons */
+#onboarding-tour-singlesearch.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-singlesearch] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_singlesearch.svg");
+}
+
+#onboarding-tour-private-browsing.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-private-browsing] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_private.svg");
+}
+
+#onboarding-tour-addons.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-addons] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_addons.svg");
+}
+
+#onboarding-tour-customize.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-customize] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_customize.svg");
+}
+
+#onboarding-tour-default-browser.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-default-browser] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_default.svg");
+}
+
+#onboarding-tour-sync.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-sync] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_sync.svg");
+}
+
+#onboarding-tour-library.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-library] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_library.svg");
+}
+
+#onboarding-tour-performance.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-performance] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_performance.svg");
+}
+
+#onboarding-tour-screenshots.onboarding-tour-item::after,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-screenshots] #onboarding-notification-tour-title::before {
+ mask-image: url("img/icons_screenshots.svg");
+}
+
+a#onboarding-tour-screenshots-button,
+a#onboarding-tour-screenshots-button:hover,
+a#onboarding-tour-screenshots-button:visited {
+ color: #fff;
+ text-decoration: none;
+}
+
+/* Tour Notifications */
+#onboarding-notification-bar {
+ position: fixed;
+ z-index: 20998; /* We want this always under #onboarding-overlay */
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: 100px;
+ min-width: 640px;
+ background: var(--newtab-snippets-background-color, rgba(255, 255, 255, 0.97));
+ border-top: 1px solid var(--newtab-snippets-hairline-color, #e9e9e9);
+ box-shadow: 0 -1px 4px 0 rgba(12, 12, 13, 0.1);
+ transition: transform 0.8s;
+ transform: translateY(122px);
+}
+
+#onboarding-notification-bar.onboarding-opened {
+ transition: none;
+ transform: translateY(0px);
+}
+
+#onboarding-notification-close-btn {
+ position: absolute;
+ inset-block-start: 50%;
+ inset-inline-end: 24px;
+ transform: translateY(-50%);
+}
+
+#onboarding-notification-message-section {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+#onboarding-notification-body {
+ width: 500px;
+ margin: 0 18px;
+ color: var(--newtab-text-primary-color, #0c0c0d);
+ display: inline-block;
+ max-height: 120px;
+ overflow: auto;
+ padding: 15px 0;
+ box-sizing: border-box;
+}
+
+#onboarding-notification-body * {
+ font-size: 12px;
+ font-weight: normal;
+ margin-top: 5px;
+}
+
+#onboarding-notification-tour-title {
+ margin: 0;
+ font-weight: bold;
+ color: var(--newtab-text-primary-color, #0f1126);
+ font-size: 14px;
+}
+
+#onboarding-notification-tour-title::before {
+ content: "";
+ background-color: var(--newtab-text-primary-color, #0f1126);
+ mask-repeat: no-repeat;
+ mask-size: 14px;
+ height: 16px;
+ width: 16px;
+ float: inline-start;
+ margin-top: 2px;
+ margin-inline-end: 2px;
+}
+
+#onboarding-notification-tour-icon {
+ min-width: 64px;
+ height: 64px;
+ background-size: 64px;
+ background-repeat: no-repeat;
+ background-image: url("chrome://branding/content/icon64.png");
+}
+
+.onboarding-action-button {
+ background: #fbfbfb;
+ /* With 1px border, could see a border in the high-constrast mode */
+ border: 1px solid #c1c1c1;
+ border-radius: 2px;
+ padding: 10px 20px;
+ font-size: 14px;
+ font-weight: 600;
+ line-height: 16px;
+ color: #202340;
+ min-width: 130px;
+}
+
+.onboarding-action-button:hover {
+ background-color: #ebebeb;
+ cursor: pointer;
+}
+
+.onboarding-action-button:active {
+ background-color: #dadada;
+}
+
+#onboarding-notification-bar .onboarding-action-button {
+ background-color: var(--newtab-button-secondary-color);
+ border-color: var(--newtab-border-primary-color);
+ border-radius: 4px;
+ color: var(--newtab-text-primary-color);
+}
+
+#onboarding-notification-bar .onboarding-action-button:hover,
+#onboarding-notification-bar .onboarding-action-button:active {
+ background-color: var(--newtab-button-secondary-color);
+ box-shadow: 0 0 0 5px var(--newtab-card-active-outline-color);
+ transition: box-shadow 150ms;
+}
+
+@media (min-resolution: 2dppx) {
+ #onboarding-notification-tour-icon {
+ background-image: url("chrome://branding/content/icon128.png");
+ }
+}
diff --git a/browser/extensions/onboarding/content/onboarding.js b/browser/extensions/onboarding/content/onboarding.js
new file mode 100644
index 000000000000..c67bd8876201
--- /dev/null
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env mozilla/frame-script */
+
+"use strict";
+
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.defineModuleGetter(this, "Onboarding", "resource://onboarding/Onboarding.jsm");
+
+const ABOUT_HOME_URL = "about:home";
+const ABOUT_NEWTAB_URL = "about:newtab";
+const ABOUT_WELCOME_URL = "about:welcome";
+
+// Load onboarding module only when we enable it.
+if (Services.prefs.getBoolPref("browser.onboarding.enabled", false)) {
+ addEventListener("load", function onLoad(evt) {
+ if (!content || evt.target != content.document) {
+ return;
+ }
+
+ let window = evt.target.defaultView;
+ let location = window.location.href;
+ if (location == ABOUT_NEWTAB_URL || location == ABOUT_HOME_URL || location == ABOUT_WELCOME_URL) {
+ // We just want to run tests as quickly as possible
+ // so in the automation test, we don't do `requestIdleCallback`.
+ if (Cu.isInAutomation) {
+ new Onboarding(this, window);
+ return;
+ }
+ window.requestIdleCallback(() => {
+ new Onboarding(this, window);
+ });
+ }
+ }, true);
+}
diff --git a/browser/extensions/onboarding/data_events.md b/browser/extensions/onboarding/data_events.md
new file mode 100644
index 000000000000..3fc5ffa41b86
--- /dev/null
+++ b/browser/extensions/onboarding/data_events.md
@@ -0,0 +1,154 @@
+# Metrics we collect
+
+We adhere to [Activity Stream's data collection policy](https://github.com/mozilla/activity-stream/blob/master/docs/v2-syst…. Data about your specific browsing behavior or the sites you visit is **never transmitted to any Mozilla server**. At any time, it is easy to **turn off** this data collection by [opting out of Firefox telemetry](https://support.mozilla.org/kb/share-telemetry-data-mozilla-help….
+
+## User event pings
+
+The Onboarding system add-on sends 2 types of pings(HTTPS POST) to the backend [Onyx server](https://github.com/mozilla/onyx) :
+- a `session` ping that describes the ending of an Onboarding session (a new tab is closed or refreshed, an overlay is closed, a notification bar is closed), and
+- an `event` ping that records specific data about individual user interactions while interacting with Onboarding
+
+For reference, Onyx is a Mozilla owned service to serve tiles for the current newtab in Firefox. It also receives all the telemetry from the about:newtab and about:home page as well as Activity Stream. It's operated and monitored by the Cloud Services team.
+
+# Example Onboarding `session` Log
+
+```js
+{
+ // These fields are sent from the client
+ "addon_version": "1.0.0",
+ "category": ["onboarding-interactions"|"overlay-interactions"|"notification-interactions"],
+ "client_id": "374dc4d8-0cb2-4ac5-a3cf-c5a9bc3c602e",
+ "locale": "en-US",
+ "type": ["onboarding_session" | "overlay_session" | "notification_session"],
+ "page": ["about:newtab" | "about:home" | "about:welcome"],
+ "parent_session_id": "{45cddbeb-2bec-4f3a-bada-fb87d4b79a6c}",
+ "root_session_id": "{45cddbeb-2bec-4f3a-bada-fb87d4b79a6c}",
+ "session_begin": 1505440017018,
+ "session_end": 1505440021992,
+ "session_id": "{12dasd-213asda-213dkakj}",
+ "tour_type" ["new" | "update"],
+
+ // These fields are generated on the server
+ "date": "2016-03-07",
+ "ip": "10.192.171.13",
+ "ua": "python-requests/2.9.1",
+ "receive_at": 1457396660000
+}
+```
+
+| KEY | DESCRIPTION | |
+|-----|-------------|:-----:|
+| `addon_version` | [Required] The version of the Onboarding addon. | :one:
+| `category` | [Required] Either ["", "overlay-interactions", "notification-interactions"] to identify which kind of the interaction | :one:
+| `client_id` | [Required] An identifier generated by [ClientID](https://github.com/mozilla/gecko-dev/blob/master/toolkit/modules/… module to provide an identifier for this device. This data is automatically appended by `ping-centre` module | :one:
+| `ip` | [Auto populated by Onyx] The IP address of the client. Onyx does use (with the permission) the IP address to infer user's geo-information so that it could prepare the corresponding tiles for the country she lives in. However, Ping-centre will NOT store IP address in the database, where only authorized Mozilla employees can access the telemetry data, and all the raw logs are being strictly managed by the Ops team and will expire according to the Mozilla's data retention policy.| :two:
+| `locale` | The browser chrome's language (e.g. en-US). | :two:
+| `page` | [Required] One of ["about:newtab", "about:home", "about:welcome"]| :one:
+| `parent_session_id` | [Required] The unique identifier generated by `gUUIDGenerator` service to identify this event belongs to which parent session. Events happen upon overlay will have the `overlay session uuid` as its `parent_session_id`. Events happen upon notification will have the `notification session uuid` as its `parent_session_id`. | :one:
+| `root_session_id` | [Required] The unique identifier generated by `gUUIDGenerator` service to identify this event belongs to which root session. Every event will have the same `onboarding session uuid` as its `root_session_id` when interact in the same tab. | :one:
+| `session_begin` | [Required] Timestamp in (integer) milliseconds when onboarding/overlay/notification becoming visible. | :one:
+| `session_end` | [Required] Timestamp in (integer) milliseconds when onboarding/overlay/notification losing focus. | :one:
+| `session_id` | [Required] The unique identifier generated by `gUUIDGenerator` service to identify the specific user session. We will log different uuid when onboarding is inited/when the overlay is opened/when notification is shown. | :one:
+| `tour_type` | [Required] One of ["new", "update"] indicates the user is a `new` user or the `update` user upgrade from the older version | :one:
+| `type` | [Required] The type of event. Allowed event strings are defined in the below section | :one:
+| `ua` | [Auto populated by Onyx] The user agent string. | :two:
+| `ver` | [Auto populated by Onyx] The version of the Onyx API the ping was sent to. | :one:
+
+# Example Onboarding `event` Log
+
+```js
+{
+ "addon_version": "1.0.0",
+ "bubble_state": ["bubble" | "dot" | "hide"],
+ "category": ["logo-interactions"|"overlay-interactions"|"notification-interactions"],
+ "client_id": "374dc4d8-0cb2-4ac5-a3cf-c5a9bc3c602e",
+ "locale": "en-US",
+ "logo_state": ["logo" | "watermark"],
+ "notification_impression": [1-8],
+ "notification_state": ["show" | "hide" | "finished"],
+ "page": ["about:newtab" | "about:home" | "about:welcome"],
+ "parent_session_id": "{45cddbeb-2bec-4f3a-bada-fb87d4b79a6c}",
+ "root_session_id": "{45cddbeb-2bec-4f3a-bada-fb87d4b79a6c}",
+ "current_tour_id": ["onboarding-tour-private-browsing" | "onboarding-tour-addons"|...], // tour ids defined in 'onboardingTourset'
+ "target_tour_id": ["onboarding-tour-private-browsing" | "onboarding-tour-addons"|...], // tour ids defined in 'onboardingTourset',
+ "tour_id": ["onboarding-tour-private-browsing" | "onboarding-tour-addons"|...], // tour ids defined in 'onboardingTourset'
+ "timestamp": 1505440017019,
+ "tour_type" ["new" | "update"],
+ "type": ["notification-cta-click" | "overlay-cta-click" | "overlay-nav-click" | "overlay-skip-tour"...],
+ "width": 950,
+
+ // These fields are generated on the server
+ "ip": "10.192.171.13",
+ "ua": "python-requests/2.9.1",
+ "receive_at": 1457396660000,
+ "date": "2016-03-07",
+}
+```
+
+
+| KEY | DESCRIPTION | |
+|-----|-------------|:-----:|
+| `addon_version` | [Required] The version of the Onboarding addon. | :one:
+| `bubble_state` | [Optional] | One of ["bubble", "dot", "hide"] indicates the current visual state of the speach bubble (content dialog besides the onboarding logo). | :one:
+| `category` | [Required] Either ("overlay-interactions", "notification-interactions") to identify which kind of the interaction | :one:
+| `client_id` | [Required] An identifier generated by [ClientID](https://github.com/mozilla/gecko-dev/blob/master/toolkit/modules/… module to provide an identifier for this device. This data is automatically appended by `ping-centre` module | :one:
+| `current_tour_id` | [Optional] id of the current tour. We put "" when this field is not relevant to this event. | :one:
+| `ip` | [Auto populated by Onyx] The IP address of the client. Onyx does use (with the permission) the IP address to infer user's geo-information so that it could prepare the corresponding tiles for the country she lives in. However, Ping-centre will NOT store IP address in the database, where only authorized Mozilla employees can access the telemetry data, and all the raw logs are being strictly managed by the Ops team and will expire according to the Mozilla's data retention policy.| :two:
+| `locale` | The browser chrome's language (e.g. en-US). | :two:
+| `logo_state` | [Optional] One of ["logo", "watermark"] indicates the overlay is opened while in the default or the watermark state. | :one:
+| `notification_impression` | [Optional] An integer to record how many times the current notification tour is shown to the user. Each Notification tour can show not more than 8 times. We put `-1` when this field is not relevant to this event | :one:
+| `notification_state` | [Optional] One of ["show", "hide", "finished"] indicates the current notification bar state. | :one:
+| `page` | [Required] One of ["about:newtab", "about:home"]| :one:
+| `parent_session_id` | [Required] The unique identifier generated by `gUUIDGenerator` service to identify this event belongs to which parent session. Events happen upon overlay will have the `overlay session uuid` as its `parent_session_id`. Events happen upon notification will have the `notification session uuid` as its `parent_session_id`. | :one:
+| `root_session_id` | [Required] The unique identifier generated by `gUUIDGenerator` service to identify this event belongs to which root session. Every event will have the same `onboarding session uuid` as its `root_session_id` when interact in the same tab. | :one:
+| `target_tour_id` | [Optional] id of the target switched tour. We put "" when this field is not relevant to this event. | :one:
+| `timestamp` | [Required] Timestamp in (integer) milliseconds when the event triggered | :one:
+| `tour_type` | [Required] One of ["new", "update"] indicates the user is a `new` user or the `update` user upgrade from the older version | :one:
+| `type` | [Required] The type of event. Allowed event strings are defined in the below section | :one:
+| `ua` | [Auto populated by Onyx] The user agent string. | :two:
+| `ver` | [Auto populated by Onyx] The version of the Onyx API the ping was sent to. | :one:
+| `width` | [Required] Current browser window width rounded by 50 pixels. Collecting rounded values reduces the risk to use these values to derive a unique user identifier. | :one:
+
+**Where:**
+
+:one: Firefox data
+:two: HTTP protocol data
+
+## Event types
+
+Here are all allowed event `type` strings that defined in `OnboardingTelemetry::EVENT_WHITELIST`.
+
+### Onboarding events
+
+| EVENT | DESCRIPTION |
+|-----------|---------------------|
+| `onboarding-logo-click` | event is triggered when a user clicks the logo to open the overlay. |
+| `onboarding-register-session` | internal event triggered when loading the onboarding module, will not send out any data. |
+| `onboarding-session` | event is sent when the tab unload to track the start and end time of the onboarding session. |
+| `onboarding-session-begin` | internal event triggered when the onboarding starts, will not send out any data. |
+| `onboarding-session-end` | internal event triggered when the onboarding ends, `onboarding-session` event is the actual event that send to the server. |
+
+### Overlay events
+
+| EVENT | DESCRIPTION |
+|-----------|---------------------|
+| `overlay-close-button-click` | event is triggered when a user clicks close overlay button. |
+| `overlay-close-outside-click` | event is triggered when a user clicks outside the overlay area to end the tour. |
+| `overlay-cta-click` | event is triggered when a user clicks overlay's Call-To-Action button. |
+| `overlay-current-tour` | event is sent when a tour is shown in the overlay. |
+| `overlay-nav-click` | event is sent when a user clicks a navigation button in the overlay. |
+| `overlay-session` | event is sent when an overlay is closed to track the start and end time of the overlay session. |
+| `overlay-session-begin` | internal event triggered when open the overlay, will not send out any data. |
+| `overlay-session-end` | internal event is triggered when an overlay session ends. `overlay-session` event is the actual event that send to the server. |
+| `overlay-skip-tour` | event is sent when a user clicks `Skip Tour` button in the overlay. |
+
+### Notification events
+
+| EVENT | DESCRIPTION |
+|-----------|---------------------|
+| `notification-appear` | event is sent when a notification appears. |
+| `notification-close-button-click` | event is sent when a user clicks close notification button. |
+| `notification-cta-click` | event is sent when a user clicks the notification's Call-To-Action button. |
+| `notification-session` | event is sent when user closes the notification to track the start and end time of the notification session. |
+| `notification-session-begin` | internal event triggered when user open the notification, will not send out any data. |
+| `notification-session-end` | internal event is triggered when a notification session ends. `notification-session` event is the actual event that send to the server. |
diff --git a/browser/extensions/onboarding/jar.mn b/browser/extensions/onboarding/jar.mn
new file mode 100644
index 000000000000..1d580be9861f
--- /dev/null
+++ b/browser/extensions/onboarding/jar.mn
@@ -0,0 +1,14 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+[features/onboarding(a)mozilla.org] chrome.jar:
+ # resource://onboarding/ is referenced in about:home about:newtab and about:welcome,
+ # so make it content-accessible.
+% resource onboarding %content/ contentaccessible=yes
+ content/ (content/*)
+ # Package UITour-lib.js in here rather than under
+ # /browser/components/uitour to avoid "unreferenced files" error when
+ # Onboarding extension is not built.
+ content/lib/UITour-lib.js (/browser/components/uitour/UITour-lib.js)
+ content/modules/ (*.jsm)
diff --git a/browser/extensions/onboarding/locales/en-US/onboarding.properties b/browser/extensions/onboarding/locales/en-US/onboarding.properties
new file mode 100644
index 000000000000..cc545222a107
--- /dev/null
+++ b/browser/extensions/onboarding/locales/en-US/onboarding.properties
@@ -0,0 +1,126 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# LOCALIZATION NOTE(onboarding.overlay-title2): This string will be used in the overlay title.
+onboarding.overlay-title2=Let’s get started
+onboarding.skip-tour-button-label=Skip Tour
+#LOCALIZATION NOTE(onboarding.button.learnMore): this string is used as a button label, displayed near the message, and shared across all the onboarding notifications.
+onboarding.button.learnMore=Learn More
+# LOCALIZATION NOTE(onboarding.overlay-icon-tooltip2): This string will be used
+# to show the tooltip alongside the notification icon in the overlay tour. %S is
+# brandShortName. The tooltip is designed to show in two lines. Please use \n to
+# do appropriate line breaking.
+onboarding.overlay-icon-tooltip2=New to %S?\nLet’s get started.
+# LOCALIZATION NOTE(onboarding.overlay-icon-tooltip-updated2): %S is
+# brandShortName. The tooltip is designed to show in two lines. Please use \n to
+# do appropriate line breaking.
+onboarding.overlay-icon-tooltip-updated2=%S is all new.\nSee what you can do!
+# LOCALIZATION NOTE(onboarding.overlay-close-button-tooltip): The overlay close button is an icon button. This tooltip would be shown when mousing hovering on the button.
+onboarding.overlay-close-button-tooltip=Close
+onboarding.notification-icon-tooltip-updated=See what’s new!
+# LOCALIZATION NOTE(onboarding.notification-close-button-tooltip): The notification close button is an icon button. This tooltip would be shown when mousing hovering on the button.
+onboarding.notification-close-button-tooltip=Dismiss
+
+# LOCALIZATION NOTE(onboarding.complete): This string is used to describe an
+# onboarding tour item that is complete.
+onboarding.complete=Complete
+
+onboarding.tour-private-browsing=Private Browsing
+onboarding.tour-private-browsing.title2=Browse by yourself.
+# LOCALIZATION NOTE(onboarding.tour-private-browsing.description3): This string will be used in the private-browsing tour description. %S is brandShortName.
+onboarding.tour-private-browsing.description3=Want to keep something to yourself? Use Private Browsing with Tracking Protection. %S will block online trackers while you browse and won’t remember your history after you’ve ended your session.
+onboarding.tour-private-browsing.button=Show Private Browsing in Menu
+onboarding.notification.onboarding-tour-private-browsing.title=Browse by yourself.
+onboarding.notification.onboarding-tour-private-browsing.message2=Want to keep something to yourself? Use Private Browsing with Tracking Protection.
+
+onboarding.tour-addons=Add-ons
+onboarding.tour-addons.title2=Get more done.
+# LOCALIZATION NOTE(onboarding.tour-addons.description2): This string will be used in the add-on tour description. %S is brandShortName
+onboarding.tour-addons.description2=Add-ons let you add features to %S, so your browser works harder for you. Compare prices, check the weather or express your personality with a custom theme.
+onboarding.tour-addons.button=Show Add-ons in Menu
+onboarding.notification.onboarding-tour-addons.title=Get more done.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-addons.message): This string will be used in the notification message for the add-ons tour. %S is brandShortName.
+onboarding.notification.onboarding-tour-addons.message=Add-ons are small apps you can add to %S that do lots of things — from managing to-do lists, to downloading videos, to changing the look of your browser.
+
+onboarding.tour-customize=Customize
+onboarding.tour-customize.title2=Rearrange your toolbar.
+# LOCALIZATION NOTE(onboarding.tour-customize.description2): This string will be used in the customize tour description. %S is brandShortName
+onboarding.tour-customize.description2=Put the tools you use most right at your fingertips. Drag, drop, and reorder %S’s toolbar and menu to fit your needs. Or choose a compact theme to make more room for tabbed browsing.
+onboarding.tour-customize.button=Show Customize in Menu
+onboarding.notification.onboarding-tour-customize.title=Rearrange your toolbar.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-customize.message): This string will be used in the notification message for Customize tour. %S is brandShortName.
+onboarding.notification.onboarding-tour-customize.message=Put the tools you use most right at your fingertips. Add more options to your toolbar. Or select a theme to make %S reflect your personality.
+
+onboarding.tour-default-browser=Default Browser
+# LOCALIZATION NOTE(onboarding.tour-default-browser.title2): This string will be used in the default browser tour title. %S is brandShortName
+onboarding.tour-default-browser.title2=Make %S your go-to browser.
+# LOCALIZATION NOTE(onboarding.tour-default-browser.description2): This string will be used in the default browser tour description. %1$S is brandShortName
+onboarding.tour-default-browser.description2=Love %1$S? Set it as your default browser. Open a link from another application, and %1$S will be there for you.
+# LOCALIZATION NOTE(onboarding.tour-default-browser.button): Label for a button to open the OS default browser settings where it's not possible to set the default browser directly. (OSX, Linux, Windows 8 and higher)
+onboarding.tour-default-browser.button=Open Default Browser Settings
+# LOCALIZATION NOTE(onboarding.tour-default-browser.win7.button): Label for a button to directly set the default browser (Windows 7). %S is brandShortName
+onboarding.tour-default-browser.win7.button=Make %S Your Default Browser
+# LOCALIZATION NOTE(onboarding.tour-default-browser.is-default.message): Label displayed when Firefox is already set as default browser. followed on a new line by "tour-default-browser.is-default.2nd-message".
+onboarding.tour-default-browser.is-default.message=You’ve got this!
+# LOCALIZATION NOTE(onboarding.tour-default-browser.is-default.2nd-message): Label displayed when Firefox is already set as default browser. %S is brandShortName
+onboarding.tour-default-browser.is-default.2nd-message=%S is already your default browser.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-default-browser.title): This string will be used in the notification title for the default browser tour. %S is brandShortName.
+onboarding.notification.onboarding-tour-default-browser.title=Make %S your go-to browser.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-default-browser.message): This string will be used in the notification message for the default browser tour. %1$S is brandShortName
+onboarding.notification.onboarding-tour-default-browser.message=It doesn’t take much to get the most from %1$S. Just set %1$S as your default browser and put control, customization, and protection on autopilot.
+
+onboarding.tour-sync2=Sync
+onboarding.tour-sync.title2=Pick up where you left off.
+onboarding.tour-sync.description2=Sync makes it easy to access bookmarks, passwords, and even open tabs on all your devices. Sync also gives you control of the types of information you want, and don’t want, to share.
+onboarding.tour-sync.logged-in.title=You’re signed in to Sync!
+# LOCALIZATION NOTE(onboarding.tour-sync.logged-in.description): %1$S is brandShortName.
+onboarding.tour-sync.logged-in.description=Sync works when you’re signed in to %1$S on more than one device. Have a mobile device? Install the %1$S app and sign in to get your bookmarks, history, and passwords on the go.
+# LOCALIZATION NOTE(onboarding.tour-sync.form.title): This string is displayed
+# as a title and followed by onboarding.tour-sync.form.description.
+onboarding.tour-sync.form.title=Create a Firefox Account
+# LOCALIZATION NOTE(onboarding.tour-sync.form.description): The description
+# continues after onboarding.tour-sync.form.title to create a complete sentence.
+# If it's not possible for your locale, you can translate this string as
+# "Continue to Firefox Sync" instead.
+onboarding.tour-sync.form.description=to continue to Firefox Sync
+onboarding.tour-sync.button=Next
+onboarding.tour-sync.connect-device.button=Connect Another Device
+onboarding.tour-sync.email-input.placeholder=Email
+onboarding.notification.onboarding-tour-sync.title=Pick up where you left off.
+onboarding.notification.onboarding-tour-sync.message=Still sending yourself links to save or read on your phone? Do it the easy way: get Sync and have the things you save here show up on all of your devices.
+
+onboarding.tour-library=Library
+onboarding.tour-library.title=Keep it together.
+# LOCALIZATION NOTE (onboarding.tour-library.description2): This string will be used in the library tour description. %1$S is brandShortName
+onboarding.tour-library.description2=Check out the new %1$S library in the redesigned toolbar. The library puts the things you’ve seen and saved to %1$S — your browsing history, bookmarks, Pocket list, and synced tabs — in one convenient place.
+onboarding.tour-library.button2=Show Library Menu
+onboarding.notification.onboarding-tour-library.title=Keep it together.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-library.message): This string will be used in the notification message for the library tour. %S is brandShortName
+onboarding.notification.onboarding-tour-library.message=The new %S library puts the great things you’ve discovered on the web in one convenient place.
+
+onboarding.tour-singlesearch=Address Bar
+onboarding.tour-singlesearch.title=Find it faster.
+# LOCALIZATION NOTE(onboarding.tour-singlesearch.description): %S is brandShortName
+onboarding.tour-singlesearch.description=The address bar might be the most powerful tool in the sleek new %S toolbar. Start typing, and see suggestions based on your browsing and search history. Go to a web address, search the whole web with your default search engine, or send your query directly to a single site with one-click search.
+onboarding.tour-singlesearch.button=Show Address Bar
+onboarding.notification.onboarding-tour-singlesearch.title=Find it faster.
+onboarding.notification.onboarding-tour-singlesearch.message=The unified address bar is the only tool you need to find your way around the web.
+
+onboarding.tour-performance=Performance
+onboarding.tour-performance.title=Browse with the best of ‘em.
+# LOCALIZATION NOTE(onboarding.tour-performance.description): %1$S is brandShortName.
+onboarding.tour-performance.description=It’s a whole new %1$S, built for faster page loading, smoother scrolling, and more responsive tab switching. These performance upgrades come paired with a modern, intuitive design. Start browsing and experience it for yourself: the best %1$S yet.
+onboarding.notification.onboarding-tour-performance.title=Browse with the best of ‘em.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-performance.message): %S is brandShortName.
+onboarding.notification.onboarding-tour-performance.message=Prepare yourself for the fastest, smoothest, most reliable %S yet.
+
+# LOCALIZATION NOTE (onboarding.tour-screenshots): "Screenshots" is the name of the Firefox Screenshots feature and should not be localized.
+onboarding.tour-screenshots=Screenshots
+onboarding.tour-screenshots.title=Take better screenshots.
+# LOCALIZATION NOTE(onboarding.tour-screenshots.description): %S is brandShortName.
+onboarding.tour-screenshots.description=Take, save and share screenshots — without leaving %S. Capture a region or an entire page as you browse. Then save to the web for easy access and sharing.
+# LOCALIZATION NOTE (onboarding.tour-screenshots.button): "Screenshots" is the name of the Firefox Screenshots feature and should not be localized.
+onboarding.tour-screenshots.button=Open Screenshots Website
+onboarding.notification.onboarding-tour-screenshots.title=Take better screenshots.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-screenshots.message): %S is brandShortName.
+onboarding.notification.onboarding-tour-screenshots.message=Take, save and share screenshots — without leaving %S.
diff --git a/browser/extensions/onboarding/locales/jar.mn b/browser/extensions/onboarding/locales/jar.mn
new file mode 100644
index 000000000000..0801f8512775
--- /dev/null
+++ b/browser/extensions/onboarding/locales/jar.mn
@@ -0,0 +1,8 @@
+#filter substitution
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+[features/onboarding(a)mozilla.org] @AB_CD@.jar:
+% locale onboarding @AB_CD@ %locale/@AB_CD@/
+ locale/@AB_CD@/onboarding.properties (%onboarding.properties)
diff --git a/browser/extensions/onboarding/locales/moz.build b/browser/extensions/onboarding/locales/moz.build
new file mode 100644
index 000000000000..aac3a838c4c2
--- /dev/null
+++ b/browser/extensions/onboarding/locales/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ['jar.mn']
diff --git a/browser/extensions/onboarding/manifest.json b/browser/extensions/onboarding/manifest.json
new file mode 100644
index 000000000000..fcf46b444c9b
--- /dev/null
+++ b/browser/extensions/onboarding/manifest.json
@@ -0,0 +1,26 @@
+{
+ "manifest_version": 2,
+ "name": "Onboarding",
+ "version": "1.0",
+
+ "applications": {
+ "gecko": {
+ "id": "onboarding(a)mozilla.org"
+ }
+ },
+
+ "background": {
+ "scripts": ["background.js"]
+ },
+
+ "experiment_apis": {
+ "onboarding": {
+ "schema": "schema.json",
+ "parent": {
+ "scopes": ["addon_parent"],
+ "script": "api.js",
+ "events": ["startup"]
+ }
+ }
+ }
+ }
diff --git a/browser/extensions/onboarding/moz.build b/browser/extensions/onboarding/moz.build
new file mode 100644
index 000000000000..d2f73eb8fd74
--- /dev/null
+++ b/browser/extensions/onboarding/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+with Files("**"):
+ BUG_COMPONENT = ("Firefox", "Tours")
+
+DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
+DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
+
+DIRS += ['locales']
+
+FINAL_TARGET_FILES.features['onboarding(a)mozilla.org'] += [
+ 'background.js',
+ 'manifest.json',
+ 'schema.json',
+]
+
+FINAL_TARGET_PP_FILES.features['onboarding(a)mozilla.org'] += [
+ 'api.js',
+]
+
+BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
+
+XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
+
+JAR_MANIFESTS += ['jar.mn']
diff --git a/browser/extensions/onboarding/schema.json b/browser/extensions/onboarding/schema.json
new file mode 100644
index 000000000000..fe51488c7066
--- /dev/null
+++ b/browser/extensions/onboarding/schema.json
@@ -0,0 +1 @@
+[]
diff --git a/browser/extensions/onboarding/test/browser/.eslintrc.js b/browser/extensions/onboarding/test/browser/.eslintrc.js
new file mode 100644
index 000000000000..9236696e5732
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "plugin:mozilla/browser-test"
+ ],
+};
diff --git a/browser/extensions/onboarding/test/browser/browser.ini b/browser/extensions/onboarding/test/browser/browser.ini
new file mode 100644
index 000000000000..abc2e915d551
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser.ini
@@ -0,0 +1,18 @@
+[DEFAULT]
+support-files =
+ head.js
+
+[browser_onboarding_accessibility.js]
+[browser_onboarding_keyboard.js]
+skip-if = debug || os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
+[browser_onboarding_notification.js]
+[browser_onboarding_notification_2.js]
+[browser_onboarding_notification_3.js]
+[browser_onboarding_notification_4.js]
+[browser_onboarding_notification_5.js]
+[browser_onboarding_notification_click_auto_complete_tour.js]
+[browser_onboarding_select_default_tour.js]
+[browser_onboarding_skip_tour.js]
+[browser_onboarding_tours.js]
+[browser_onboarding_tourset.js]
+[browser_onboarding_uitour.js]
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_accessibility.js b/browser/extensions/onboarding/test/browser/browser_onboarding_accessibility.js
new file mode 100644
index 000000000000..37abbd3541d4
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_accessibility.js
@@ -0,0 +1,89 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ "use strict";
+
+add_task(async function test_onboarding_overlay_button() {
+ resetOnboardingDefaultState();
+
+ info("Wait for onboarding overlay loaded");
+ let tab = await openTab(ABOUT_HOME_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+
+ info("Test accessibility and semantics of the overlay button");
+ await ContentTask.spawn(tab.linkedBrowser, {}, function() {
+ let doc = content.document;
+ let button = doc.body.firstElementChild;
+ is(button.id, "onboarding-overlay-button",
+ "First child is an overlay button");
+ ok(button.getAttribute("aria-label"),
+ "Onboarding button has an accessible label");
+ is(button.getAttribute("aria-haspopup"), "true",
+ "Onboarding button should indicate that it triggers a popup");
+ is(button.getAttribute("aria-controls"), "onboarding-overlay-dialog",
+ "Onboarding button semantically controls an overlay dialog");
+ is(button.firstElementChild.getAttribute("role"), "presentation",
+ "Onboarding button icon should have presentation only semantics");
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_onboarding_notification_bar() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+
+ info("Test accessibility and semantics of the notification bar");
+ await ContentTask.spawn(tab.linkedBrowser, {}, function() {
+ let doc = content.document;
+ let footer = doc.getElementById("onboarding-notification-bar");
+
+ is(footer.getAttribute("aria-labelledby"), doc.getElementById("onboarding-notification-tour-title").id,
+ "Notification bar should be labelled by the notification tour title text");
+
+ is(footer.getAttribute("aria-live"), "polite",
+ "Notification bar should be a live region");
+ // Presentational elements
+ [
+ "onboarding-notification-message-section",
+ "onboarding-notification-tour-icon",
+ "onboarding-notification-body",
+ ].forEach(id =>
+ is(doc.getElementById(id).getAttribute("role"), "presentation",
+ "Element is only used for presentation"));
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_onboarding_overlay_dialog() {
+ resetOnboardingDefaultState();
+
+ info("Wait for onboarding overlay loaded");
+ let tab = await openTab(ABOUT_HOME_URL);
+ let browser = tab.linkedBrowser;
+ await promiseOnboardingOverlayLoaded(browser);
+
+ info("Test accessibility and semantics of the dialog overlay");
+ await assertModalDialog(browser, { visible: false });
+
+ info("Click on overlay button and check modal dialog state");
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button",
+ {}, browser);
+ await promiseOnboardingOverlayOpened(browser);
+ await assertModalDialog(browser,
+ { visible: true, focusedId: "onboarding-overlay-dialog" });
+
+ info("Close the dialog and check modal dialog state");
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-close-btn",
+ {}, browser);
+ await promiseOnboardingOverlayClosed(browser);
+ await assertModalDialog(browser, { visible: false });
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_keyboard.js b/browser/extensions/onboarding/test/browser/browser_onboarding_keyboard.js
new file mode 100644
index 000000000000..ab9d2ed6afbc
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_keyboard.js
@@ -0,0 +1,137 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ "use strict";
+
+function assertOverlayState(browser, args) {
+ return ContentTask.spawn(browser, args, ({ tourId, focusedId, visible }) => {
+ let { document: doc, window} = content;
+ if (tourId) {
+ let items = [...doc.querySelectorAll(".onboarding-tour-item")];
+ items.forEach(item => is(item.getAttribute("aria-selected"),
+ item.id === tourId ? "true" : "false",
+ "Active item should have aria-selected set to true and inactive to false"));
+ }
+ if (focusedId) {
+ let focused = doc.getElementById(focusedId);
+ is(focused, doc.activeElement, `Focus should be set on ${focusedId}`);
+ }
+ if (visible !== undefined) {
+ let overlay = doc.getElementById("onboarding-overlay");
+ is(window.getComputedStyle(overlay).getPropertyValue("display"),
+ visible ? "block" : "none",
+ `Onboarding overlay should be ${visible ? "visible" : "invisible"}`);
+ }
+ });
+}
+
+const TOUR_LIST_TEST_DATA = [
+ { key: "VK_DOWN", expected: { tourId: TOUR_IDs[1], focusedId: TOUR_IDs[1] }},
+ { key: "VK_DOWN", expected: { tourId: TOUR_IDs[2], focusedId: TOUR_IDs[2] }},
+ { key: "VK_DOWN", expected: { tourId: TOUR_IDs[3], focusedId: TOUR_IDs[3] }},
+ { key: "VK_DOWN", expected: { tourId: TOUR_IDs[4], focusedId: TOUR_IDs[4] }},
+ { key: "VK_UP", expected: { tourId: TOUR_IDs[3], focusedId: TOUR_IDs[3] }},
+ { key: "VK_UP", expected: { tourId: TOUR_IDs[2], focusedId: TOUR_IDs[2] }},
+ { key: "VK_TAB", expected: { tourId: TOUR_IDs[2], focusedId: TOUR_IDs[3] }},
+ { key: "VK_TAB", expected: { tourId: TOUR_IDs[2], focusedId: TOUR_IDs[4] }},
+ { key: "VK_RETURN", expected: { tourId: TOUR_IDs[4], focusedId: TOUR_IDs[4] }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { tourId: TOUR_IDs[4], focusedId: TOUR_IDs[3] }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { tourId: TOUR_IDs[4], focusedId: TOUR_IDs[2] }},
+ // VK_SPACE does not work well with EventUtils#synthesizeKey use " " instead
+ { key: " ", expected: { tourId: TOUR_IDs[2], focusedId: TOUR_IDs[2] }},
+];
+
+const BUTTONS_TEST_DATA = [
+ { key: " ", expected: { focusedId: TOUR_IDs[0], visible: true }},
+ { key: "VK_ESCAPE", expected: { focusedId: "onboarding-overlay-button", visible: false }},
+ { key: "VK_RETURN", expected: { focusedId: TOUR_IDs[1], visible: true }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { focusedId: TOUR_IDs[0], visible: true }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { focusedId: "onboarding-overlay-close-btn", visible: true }},
+ { key: " ", expected: { focusedId: "onboarding-overlay-button", visible: false }},
+ { key: "VK_RETURN", expected: { focusedId: TOUR_IDs[1], visible: true }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { focusedId: TOUR_IDs[0], visible: true }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { focusedId: "onboarding-overlay-close-btn", visible: true }},
+ { key: "VK_TAB", expected: { focusedId: TOUR_IDs[0], visible: true }},
+ { key: "VK_TAB", options: { shiftKey: true }, expected: { focusedId: "onboarding-overlay-close-btn", visible: true }},
+ { key: "VK_RETURN", expected: { focusedId: "onboarding-overlay-button", visible: false }},
+];
+
+add_task(async function test_tour_list_keyboard_navigation() {
+ resetOnboardingDefaultState();
+
+ info("Display onboarding overlay on the home page");
+ let tab = await openTab(ABOUT_HOME_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button",
+ {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+
+ info("Checking overall overlay tablist semantics");
+ await assertOverlaySemantics(tab.linkedBrowser);
+
+ info("Set initial focus on the currently active tab");
+ await ContentTask.spawn(tab.linkedBrowser, {}, () =>
+ content.document.querySelector(".onboarding-active").focus());
+ await assertOverlayState(tab.linkedBrowser,
+ { tourId: TOUR_IDs[0], focusedId: TOUR_IDs[0] });
+
+ for (let { key, options = {}, expected } of TOUR_LIST_TEST_DATA) {
+ info(`Pressing ${key} to select ${expected.tourId} and have focus on ${expected.focusedId}`);
+ await BrowserTestUtils.synthesizeKey(key, options, tab.linkedBrowser);
+ await assertOverlayState(tab.linkedBrowser, expected);
+ }
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_buttons_keyboard_navigation() {
+ resetOnboardingDefaultState();
+
+ info("Wait for onboarding overlay loaded");
+ let tab = await openTab(ABOUT_HOME_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+
+ info("Set keyboard focus on the onboarding overlay button");
+ await ContentTask.spawn(tab.linkedBrowser, {}, () =>
+ content.document.getElementById("onboarding-overlay-button").focus());
+ await assertOverlayState(tab.linkedBrowser,
+ { focusedId: "onboarding-overlay-button", visible: false });
+
+ for (let { key, options = {}, expected } of BUTTONS_TEST_DATA) {
+ info(`Pressing ${key} to have ${expected.visible ? "visible" : "invisible"} overlay and have focus on ${expected.focusedId}`);
+ await BrowserTestUtils.synthesizeKey(key, options, tab.linkedBrowser);
+ await assertOverlayState(tab.linkedBrowser, expected);
+ }
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_overlay_dialog_keyboard_navigation() {
+ resetOnboardingDefaultState();
+
+ info("Wait for onboarding overlay loaded");
+ let tab = await openTab(ABOUT_HOME_URL);
+ let browser = tab.linkedBrowser;
+ await promiseOnboardingOverlayLoaded(browser);
+
+ info("Test accessibility and semantics of the dialog overlay");
+ await assertModalDialog(browser, { visible: false });
+
+ info("Set keyboard focus on the onboarding overlay button");
+ await ContentTask.spawn(browser, {}, () =>
+ content.document.getElementById("onboarding-overlay-button").focus());
+ info("Open dialog with keyboard and check the dialog state");
+ await BrowserTestUtils.synthesizeKey(" ", {}, browser);
+ await promiseOnboardingOverlayOpened(browser);
+ await assertModalDialog(browser,
+ { visible: true, keyboardFocus: true, focusedId: TOUR_IDs[0] });
+
+ info("Close the dialog and check modal dialog state");
+ await BrowserTestUtils.synthesizeKey("VK_ESCAPE", {}, browser);
+ await promiseOnboardingOverlayClosed(browser);
+ await assertModalDialog(browser,
+ { visible: false, keyboardFocus: true, focusedId: "onboarding-overlay-button" });
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_notification.js b/browser/extensions/onboarding/test/browser/browser_onboarding_notification.js
new file mode 100644
index 000000000000..b3e7fc788681
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(3);
+
+add_task(async function test_show_tour_notifications_in_order() {
+ resetOnboardingDefaultState();
+ Preferences.set("browser.onboarding.notification.max-prompt-count-per-tour", 1);
+ skipMuteNotificationOnFirstSession();
+
+ let tourIds = TOUR_IDs;
+ let tab = null;
+ let targetTourId = null;
+ let expectedPrefUpdates = null;
+ await loopTourNotificationQueueOnceInOrder();
+ await loopTourNotificationQueueOnceInOrder();
+
+ expectedPrefUpdates = Promise.all([
+ promisePrefUpdated("browser.onboarding.notification.finished", true),
+ promisePrefUpdated("browser.onboarding.state", ICON_STATE_WATERMARK),
+ ]);
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await expectedPrefUpdates;
+ await assertWatermarkIconDisplayed(tab.linkedBrowser);
+ let tourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ ok(!tourId, "Should not prompt each tour for more than 2 chances.");
+ BrowserTestUtils.removeTab(tab);
+
+ async function loopTourNotificationQueueOnceInOrder() {
+ for (let i = 0; i < tourIds.length; ++i) {
+ if (tab) {
+ await reloadTab(tab);
+ } else {
+ tab = await openTab(ABOUT_NEWTAB_URL);
+ }
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(targetTourId, tourIds[i], "Should show tour notifications in order");
+ }
+ }
+});
+
+add_task(async function test_open_target_tour_from_notification() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-action-btn", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+ let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
+
+ is(targetTourId, activeNavItemId, "Should navigate to the target tour item.");
+ is(`${targetTourId}-page`, activePageId, "Should display the target tour page.");
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js
new file mode 100644
index 000000000000..966102099f50
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(3);
+
+add_task(async function test_not_show_notification_for_completed_tour() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tourIds = TOUR_IDs;
+ // Make only the last tour uncompleted
+ let lastTourId = tourIds[tourIds.length - 1];
+ for (let id of tourIds) {
+ if (id != lastTourId) {
+ setTourCompletedState(id, true);
+ }
+ }
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(targetTourId, lastTourId, "Should not show notification for completed tour");
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_skip_notification_for_completed_tour() {
+ resetOnboardingDefaultState();
+ Preferences.set("browser.onboarding.notification.max-prompt-count-per-tour", 1);
+ skipMuteNotificationOnFirstSession();
+
+ let tourIds = TOUR_IDs;
+ // Make only 2nd tour completed
+ await setTourCompletedState(tourIds[1], true);
+
+ // Test show notification for the 1st tour
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(targetTourId, tourIds[0], "Should show notification for incompleted tour");
+
+ // Test skip the 2nd tour and show notification for the 3rd tour
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(targetTourId, tourIds[2], "Should skip notification for the completed 2nd tour");
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_mute_notification_on_1st_session() {
+ resetOnboardingDefaultState();
+
+ // Test no notifications during the mute duration on the 1st session
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ // The tour notification would be prompted on idle, so we wait idle twice here before proceeding
+ await waitUntilWindowIdle(tab.linkedBrowser);
+ await waitUntilWindowIdle(tab.linkedBrowser);
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await waitUntilWindowIdle(tab.linkedBrowser);
+ await waitUntilWindowIdle(tab.linkedBrowser);
+ let promptCount = Preferences.get("browser.onboarding.notification.prompt-count", 0);
+ is(0, promptCount, "Should not prompt tour notification during the mute duration on the 1st session");
+
+ // Test notification prompted after the mute duration on the 1st session
+ let muteTime = Preferences.get("browser.onboarding.notification.mute-duration-on-first-session-ms");
+ let lastTime = Math.floor((Date.now() - muteTime - 1) / 1000);
+ Preferences.set("browser.onboarding.notification.last-time-of-changing-tour-sec", lastTime);
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ promptCount = Preferences.get("browser.onboarding.notification.prompt-count", 0);
+ is(1, promptCount, "Should prompt tour notification after the mute duration on the 1st session");
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js
new file mode 100644
index 000000000000..0010cd90263b
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(3);
+
+add_task(async function test_move_on_to_next_notification_when_reaching_max_prompt_count() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+ let maxCount = Preferences.get("browser.onboarding.notification.max-prompt-count-per-tour");
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let previousTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+
+ let currentTourId = null;
+ for (let i = maxCount - 1; i > 0; --i) {
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(previousTourId, currentTourId, "Should not move on to next tour notification until reaching the max prompt count per tour");
+ }
+
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ isnot(previousTourId, currentTourId, "Should move on to next tour notification when reaching the max prompt count per tour");
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_move_on_to_next_notification_when_reaching_max_life_time() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let previousTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+
+ let maxTime = Preferences.get("browser.onboarding.notification.max-life-time-per-tour-ms");
+ let lastTime = Math.floor((Date.now() - maxTime - 1) / 1000);
+ Preferences.set("browser.onboarding.notification.last-time-of-changing-tour-sec", lastTime);
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ isnot(previousTourId, currentTourId, "Should move on to next tour notification when reaching the max life time per tour");
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_move_on_to_next_notification_after_interacting_with_notification() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let previousTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-close-btn", {}, tab.linkedBrowser);
+
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ isnot(previousTourId, currentTourId, "Should move on to next tour notification after clicking #onboarding-notification-close-btn");
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-action-btn", {}, tab.linkedBrowser);
+ previousTourId = currentTourId;
+
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ currentTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ isnot(previousTourId, currentTourId, "Should move on to next tour notification after clicking #onboarding-notification-action-btn");
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js
new file mode 100644
index 000000000000..57e8ce840f2a
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(3);
+
+add_task(async function test_remove_all_tour_notifications_through_close_button() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tourIds = TOUR_IDs;
+ let tab = null;
+ let targetTourId = null;
+ await closeTourNotificationsOneByOne();
+
+ let expectedPrefUpdates = [
+ promisePrefUpdated("browser.onboarding.notification.finished", true),
+ promisePrefUpdated("browser.onboarding.state", ICON_STATE_WATERMARK),
+ ];
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await Promise.all(expectedPrefUpdates);
+ await assertWatermarkIconDisplayed(tab.linkedBrowser);
+
+ let tourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ ok(!tourId, "Should not prompt tour notifications any more after closing all notifcations.");
+ BrowserTestUtils.removeTab(tab);
+
+ async function closeTourNotificationsOneByOne() {
+ for (let i = 0; i < tourIds.length; ++i) {
+ if (tab) {
+ await reloadTab(tab);
+ } else {
+ tab = await openTab(ABOUT_NEWTAB_URL);
+ }
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(targetTourId, tourIds[i], `Should show tour notifications of ${targetTourId}`);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-close-btn", {}, tab.linkedBrowser);
+ await promiseTourNotificationClosed(tab.linkedBrowser);
+ }
+ }
+});
+
+add_task(async function test_remove_all_tour_notifications_through_action_button() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tourIds = TOUR_IDs;
+ let tab = null;
+ let targetTourId = null;
+ await clickTourNotificationActionButtonsOneByOne();
+
+ let expectedPrefUpdates = [
+ promisePrefUpdated("browser.onboarding.notification.finished", true),
+ promisePrefUpdated("browser.onboarding.state", ICON_STATE_WATERMARK),
+ ];
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await Promise.all(expectedPrefUpdates);
+ await assertWatermarkIconDisplayed(tab.linkedBrowser);
+
+ let tourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ ok(!tourId, "Should not prompt tour notifcations any more after taking actions on all notifcations.");
+ BrowserTestUtils.removeTab(tab);
+
+ async function clickTourNotificationActionButtonsOneByOne() {
+ for (let i = 0; i < tourIds.length; ++i) {
+ if (tab) {
+ await reloadTab(tab);
+ } else {
+ tab = await openTab(ABOUT_NEWTAB_URL);
+ }
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is(targetTourId, tourIds[i], `Should show tour notifications of ${targetTourId}`);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-notification-action-btn", {}, tab.linkedBrowser);
+ await promiseTourNotificationClosed(tab.linkedBrowser);
+ }
+ }
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_5.js b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_5.js
new file mode 100644
index 000000000000..9fd2f25dfe4f
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_5.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_finish_tour_notifcations_after_total_max_life_time() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+
+ let totalMaxTime = Preferences.get("browser.onboarding.notification.max-life-time-all-tours-ms");
+ Preferences.set("browser.onboarding.notification.last-time-of-changing-tour-sec", Math.floor((Date.now() - totalMaxTime) / 1000));
+ let expectedPrefUpdates = Promise.all([
+ promisePrefUpdated("browser.onboarding.notification.finished", true),
+ promisePrefUpdated("browser.onboarding.state", ICON_STATE_WATERMARK),
+ ]);
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await expectedPrefUpdates;
+ await assertWatermarkIconDisplayed(tab.linkedBrowser);
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_notification_click_auto_complete_tour.js b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_click_auto_complete_tour.js
new file mode 100644
index 000000000000..c505b62f7d38
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_notification_click_auto_complete_tour.js
@@ -0,0 +1,33 @@
+add_task(async function test_show_click_auto_complete_tour_in_notification() {
+ resetOnboardingDefaultState();
+ skipMuteNotificationOnFirstSession();
+ // the second tour is an click-auto-complete tour
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "customize,library"],
+ ]});
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+
+ // Trigger CTA button to mark the tour as complete
+ let expectedPrefUpdates = [
+ promisePrefUpdated(`browser.onboarding.tour.onboarding-tour-customize.completed`, true),
+ ];
+ BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize", {}, tab.linkedBrowser);
+ BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-customize-button", {}, tab.linkedBrowser);
+ await Promise.all(expectedPrefUpdates);
+
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-close-btn", {}, gBrowser.selectedBrowser);
+ let { activeNavItemId } = await getCurrentActiveTour(tab.linkedBrowser);
+ is("onboarding-tour-customize", activeNavItemId, "the active tour should be the previous shown tour");
+
+ await reloadTab(tab);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await promiseTourNotificationOpened(tab.linkedBrowser);
+ let targetTourId = await getCurrentNotificationTargetTourId(tab.linkedBrowser);
+ is("onboarding-tour-library", targetTourId, "correctly show the click-autocomplete-tour in notification");
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js b/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js
new file mode 100644
index 000000000000..37f345f515fa
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const OVERLAY_ICON_ID = "#onboarding-overlay-button";
+const PRIVATE_BROWSING_TOUR_ID = "#onboarding-tour-private-browsing";
+const ADDONS_TOUR_ID = "#onboarding-tour-addons";
+const CUSTOMIZE_TOUR_ID = "#onboarding-tour-customize";
+const CLASS_ACTIVE = "onboarding-active";
+
+add_task(async function test_default_tour_open_the_right_page() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.tour-type", "new"],
+ ["browser.onboarding.tourset-version", 1],
+ ["browser.onboarding.seen-tourset-version", 1],
+ ["browser.onboarding.newtour", "private,addons,customize"],
+ ]});
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter(OVERLAY_ICON_ID, {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+
+ info("Make sure the default tour is active and open the right page");
+ let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
+ is(`#${activeNavItemId}`, PRIVATE_BROWSING_TOUR_ID, "default tour is active");
+ is(activePageId, "onboarding-tour-private-browsing-page", "default tour page is shown");
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_select_first_uncomplete_tour() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.tour-type", "new"],
+ ["browser.onboarding.tourset-version", 1],
+ ["browser.onboarding.seen-tourset-version", 1],
+ ["browser.onboarding.newtour", "private,addons,customize"],
+ ]});
+ setTourCompletedState("onboarding-tour-private-browsing", true);
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter(OVERLAY_ICON_ID, {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+
+ info("Make sure the first uncomplete tour is selected");
+ let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
+ is(`#${activeNavItemId}`, ADDONS_TOUR_ID, "default tour is active");
+ is(activePageId, "onboarding-tour-addons-page", "default tour page is shown");
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_select_first_tour_when_all_tours_are_complete() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.tour-type", "new"],
+ ["browser.onboarding.tourset-version", 1],
+ ["browser.onboarding.seen-tourset-version", 1],
+ ["browser.onboarding.newtour", "private,addons,customize"],
+ ]});
+ setTourCompletedState("onboarding-tour-private-browsing", true);
+ setTourCompletedState("onboarding-tour-addons", true);
+ setTourCompletedState("onboarding-tour-customize", true);
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter(OVERLAY_ICON_ID, {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+
+ info("Make sure the first tour is selected when all tours are completed");
+ let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
+ is(`#${activeNavItemId}`, PRIVATE_BROWSING_TOUR_ID, "default tour is active");
+ is(activePageId, "onboarding-tour-private-browsing-page", "default tour page is shown");
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_skip_tour.js b/browser/extensions/onboarding/test/browser/browser_onboarding_skip_tour.js
new file mode 100644
index 000000000000..58b2870ce7e6
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_skip_tour.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+ "use strict";
+
+add_task(async function test_skip_onboarding_tours() {
+ resetOnboardingDefaultState();
+
+ let tourIds = TOUR_IDs;
+ let expectedPrefUpdates = [
+ promisePrefUpdated("browser.onboarding.notification.finished", true),
+ promisePrefUpdated("browser.onboarding.state", ICON_STATE_WATERMARK),
+ ];
+ tourIds.forEach((id, idx) => expectedPrefUpdates.push(promisePrefUpdated(`browser.onboarding.tour.${id}.completed`, true)));
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+
+ let overlayClosedPromise = promiseOnboardingOverlayClosed(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-skip-tour-button", {}, tab.linkedBrowser);
+ await overlayClosedPromise;
+ await Promise.all(expectedPrefUpdates);
+ await assertWatermarkIconDisplayed(tab.linkedBrowser);
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_hide_skip_button_via_perf() {
+ resetOnboardingDefaultState();
+ Preferences.set("browser.onboarding.skip-tour-button.hide", true);
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ let browser = tab.linkedBrowser;
+ await promiseOnboardingOverlayLoaded(browser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, browser);
+ await promiseOnboardingOverlayOpened(browser);
+
+ let hasTourButton = await ContentTask.spawn(browser, null, () => {
+ return content.document.querySelector("#onboarding-skip-tour-button") != null;
+ });
+
+ ok(!hasTourButton, "should not render the skip button");
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js b/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
new file mode 100644
index 000000000000..612c06ea6e25
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
@@ -0,0 +1,115 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+ "use strict";
+
+requestLongerTimeout(2);
+
+function assertTourCompleted(tourId, expectComplete, browser) {
+ return ContentTask.spawn(browser, { tourId, expectComplete }, function(args) {
+ let item = content.document.querySelector(`#${args.tourId}.onboarding-tour-item`);
+ let completedTextId = `onboarding-complete-${args.tourId}-text`;
+ let completedText = item.querySelector(`#${completedTextId}`);
+ if (args.expectComplete) {
+ ok(item.classList.contains("onboarding-complete"), `Should set the complete #${args.tourId} tour with the complete style`);
+ ok(completedText, "Text label should be present for a completed item");
+ is(completedText.id, completedTextId, "Text label node should have a unique id");
+ ok(completedText.getAttribute("aria-label"), "Text label node should have an aria-label attribute set");
+ is(item.getAttribute("aria-describedby"), completedTextId,
+ "Completed item should have aria-describedby attribute set to text label node's id");
+ } else {
+ ok(!item.classList.contains("onboarding-complete"), `Should not set the incomplete #${args.tourId} tour with the complete style`);
+ ok(!completedText, "Text label should not be present for an incomplete item");
+ ok(!item.hasAttribute("aria-describedby"), "Incomplete item should not have aria-describedby attribute set");
+ }
+ });
+}
+
+add_task(async function test_set_right_tour_completed_style_on_overlay() {
+ resetOnboardingDefaultState();
+
+ let tourIds = TOUR_IDs;
+ // Mark the tours of even number as completed
+ for (let i = 0; i < tourIds.length; ++i) {
+ setTourCompletedState(tourIds[i], i % 2 == 0);
+ }
+
+ let tabs = [];
+ for (let url of URLs) {
+ let tab = await openTab(url);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+ tabs.push(tab);
+ }
+
+ for (let i = tabs.length - 1; i >= 0; --i) {
+ let tab = tabs[i];
+ await assertOverlaySemantics(tab.linkedBrowser);
+ for (let j = 0; j < tourIds.length; ++j) {
+ await assertTourCompleted(tourIds[j], j % 2 == 0, tab.linkedBrowser);
+ }
+ BrowserTestUtils.removeTab(tab);
+ }
+});
+
+add_task(async function test_click_action_button_to_set_tour_completed() {
+ resetOnboardingDefaultState();
+ const CUSTOM_TOUR_IDs = [
+ "onboarding-tour-private-browsing",
+ "onboarding-tour-addons",
+ "onboarding-tour-customize",
+ ];
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "private,addons,customize"],
+ ]});
+
+ let tourIds = CUSTOM_TOUR_IDs;
+ let tabs = [];
+ for (let url of URLs) {
+ let tab = await openTab(url);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+ tabs.push(tab);
+ }
+
+ let completedTourId = tourIds[0];
+ let expectedPrefUpdate = promisePrefUpdated(`browser.onboarding.tour.${completedTourId}.completed`, true);
+ await BrowserTestUtils.synthesizeMouseAtCenter(`#${completedTourId}-page .onboarding-tour-action-button`, {}, gBrowser.selectedBrowser);
+ await expectedPrefUpdate;
+
+ for (let i = tabs.length - 1; i >= 0; --i) {
+ let tab = tabs[i];
+ await assertOverlaySemantics(tab.linkedBrowser);
+ for (let id of tourIds) {
+ await assertTourCompleted(id, id == completedTourId, tab.linkedBrowser);
+ }
+ BrowserTestUtils.removeTab(tab);
+ }
+});
+
+add_task(async function test_set_watermark_after_all_tour_completed() {
+ resetOnboardingDefaultState();
+
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.tour-type", "new"],
+ ]});
+
+ let tabs = [];
+ for (let url of URLs) {
+ let tab = await openTab(url);
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+ tabs.push(tab);
+ }
+ let expectedPrefUpdate = promisePrefUpdated("browser.onboarding.state", ICON_STATE_WATERMARK);
+ TOUR_IDs.forEach(id => Preferences.set(`browser.onboarding.tour.${id}.completed`, true));
+ await expectedPrefUpdate;
+
+ for (let tab of tabs) {
+ await assertWatermarkIconDisplayed(tab.linkedBrowser);
+ BrowserTestUtils.removeTab(tab);
+ }
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js b/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
new file mode 100644
index 000000000000..3bbc50b69083
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+async function testTourIDs(browser, tourIDs) {
+ await ContentTask.spawn(browser, tourIDs, async (tourIDsContent) => {
+ let doc = content.document;
+ let doms = doc.querySelectorAll(".onboarding-tour-item");
+ Assert.equal(doms.length, tourIDsContent.length, "has exact tour numbers");
+ doms.forEach((dom, idx) => {
+ Assert.equal(tourIDsContent[idx], dom.id, "contain defined onboarding id");
+ });
+ });
+}
+
+add_task(async function test_onboarding_default_new_tourset() {
+ resetOnboardingDefaultState();
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ let browser = tab.linkedBrowser;
+ await promiseOnboardingOverlayLoaded(browser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, browser);
+ await promiseOnboardingOverlayOpened(browser);
+
+ await testTourIDs(browser, TOUR_IDs);
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_onboarding_custom_new_tourset() {
+ const CUSTOM_NEW_TOURs = [
+ "onboarding-tour-private-browsing",
+ "onboarding-tour-addons",
+ "onboarding-tour-customize",
+ ];
+
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.tour-type", "new"],
+ ["browser.onboarding.tourset-version", 1],
+ ["browser.onboarding.seen-tourset-version", 1],
+ ["browser.onboarding.newtour", "private,addons,customize"],
+ ]});
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ let browser = tab.linkedBrowser;
+ await promiseOnboardingOverlayLoaded(browser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, browser);
+ await promiseOnboardingOverlayOpened(browser);
+
+ await testTourIDs(browser, CUSTOM_NEW_TOURs);
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_onboarding_custom_update_tourset() {
+ const CUSTOM_UPDATE_TOURs = [
+ "onboarding-tour-customize",
+ "onboarding-tour-private-browsing",
+ "onboarding-tour-addons",
+ ];
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.tour-type", "update"],
+ ["browser.onboarding.tourset-version", 1],
+ ["browser.onboarding.seen-tourset-version", 1],
+ ["browser.onboarding.updatetour", "customize,private,addons"],
+ ]});
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ let browser = tab.linkedBrowser;
+ await promiseOnboardingOverlayLoaded(browser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, browser);
+ await promiseOnboardingOverlayOpened(browser);
+
+ await testTourIDs(browser, CUSTOM_UPDATE_TOURs);
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js b/browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js
new file mode 100644
index 000000000000..716dd59651e4
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js
@@ -0,0 +1,167 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(3);
+
+function promisePopupChange(popup, expectedState) {
+ return new Promise(resolve => {
+ let event = expectedState == "open" ? "popupshown" : "popuphidden";
+ popup.addEventListener(event, resolve, { once: true });
+ });
+}
+
+async function promiseOpenOnboardingOverlay(tab) {
+ await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
+ return promiseOnboardingOverlayOpened(tab.linkedBrowser);
+}
+
+async function triggerUITourHighlight(tourName, tab) {
+ await promiseOpenOnboardingOverlay(tab);
+ BrowserTestUtils.synthesizeMouseAtCenter(`#onboarding-tour-${tourName}`, {}, tab.linkedBrowser);
+ BrowserTestUtils.synthesizeMouseAtCenter(`#onboarding-tour-${tourName}-button`, {}, tab.linkedBrowser);
+}
+
+add_task(async function test_clean_up_uitour_after_closing_overlay() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "library"],
+ ]});
+
+ // Trigger UITour showHighlight
+ let highlight = document.getElementById("UITourHighlightContainer");
+ let highlightOpenPromise = promisePopupChange(highlight, "open");
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await triggerUITourHighlight("library", tab);
+ await highlightOpenPromise;
+ is(highlight.state, "open", "Should show UITour highlight");
+ is(highlight.getAttribute("targetName"), "library", "UITour should highlight library");
+
+ // Close the overlay by clicking the overlay
+ let highlightClosePromise = promisePopupChange(highlight, "closed");
+ BrowserTestUtils.synthesizeMouseAtPoint(2, 2, {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayClosed(tab.linkedBrowser);
+ await highlightClosePromise;
+ is(highlight.state, "closed", "Should close UITour highlight after closing the overlay by clicking the overlay");
+
+ // Trigger UITour showHighlight again
+ highlightOpenPromise = promisePopupChange(highlight, "open");
+ await triggerUITourHighlight("library", tab);
+ await highlightOpenPromise;
+ is(highlight.state, "open", "Should show UITour highlight");
+ is(highlight.getAttribute("targetName"), "library", "UITour should highlight library");
+
+ // Close the overlay by clicking the skip-tour button
+ highlightClosePromise = promisePopupChange(highlight, "closed");
+ BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-skip-tour-btn", {}, tab.linkedBrowser);
+ await promiseOnboardingOverlayClosed(tab.linkedBrowser);
+ await highlightClosePromise;
+ is(highlight.state, "closed", "Should close UITour highlight after closing the overlay by clicking the skip-tour button");
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_after_navigating_to_other_tour_by_keyboard() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "singlesearch,customize"],
+ ]});
+
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await promiseOpenOnboardingOverlay(tab);
+
+ // Navigate to the Customize tour to trigger UITour showHighlight
+ let highlight = document.getElementById("UITourHighlightContainer");
+ let highlightOpenPromise = promisePopupChange(highlight, "open");
+ tab.linkedBrowser.focus(); // Make sure the key event will be fired on the focused page
+ await BrowserTestUtils.synthesizeKey("VK_TAB", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("VK_TAB", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("VK_TAB", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, tab.linkedBrowser);
+ await highlightOpenPromise;
+ is(highlight.state, "open", "Should show UITour highlight");
+ is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+ // Navigate to the Single-Search tour
+ let highlightClosePromise = promisePopupChange(highlight, "closed");
+ tab.linkedBrowser.focus(); // Make sure the key event will be fired on the focused page
+ await BrowserTestUtils.synthesizeKey("VK_TAB", { shiftKey: true }, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("VK_TAB", { shiftKey: true }, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, tab.linkedBrowser);
+ await highlightClosePromise;
+ is(highlight.state, "closed", "Should close UITour highlight after navigating to another tour by keyboard");
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_after_navigating_to_other_tour_by_mouse() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "singlesearch,customize"],
+ ]});
+
+ // Navigate to the Customize tour to trigger UITour showHighlight
+ let highlight = document.getElementById("UITourHighlightContainer");
+ let highlightOpenPromise = promisePopupChange(highlight, "open");
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await triggerUITourHighlight("customize", tab);
+ await highlightOpenPromise;
+ is(highlight.state, "open", "Should show UITour highlight");
+ is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+ // Navigate to the Single-Search tour
+ let highlightClosePromise = promisePopupChange(highlight, "closed");
+ BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-tour-singlesearch", {}, tab.linkedBrowser);
+ await highlightClosePromise;
+ is(highlight.state, "closed", "Should close UITour highlight after navigating to another tour by mouse");
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_on_page_unload() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "singlesearch,customize"],
+ ]});
+
+ // Trigger UITour showHighlight
+ let highlight = document.getElementById("UITourHighlightContainer");
+ let highlightOpenPromise = promisePopupChange(highlight, "open");
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await triggerUITourHighlight("customize", tab);
+ await highlightOpenPromise;
+ is(highlight.state, "open", "Should show UITour highlight");
+ is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+ // Load another page to unload the current page
+ let highlightClosePromise = promisePopupChange(highlight, "closed");
+ await BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com");
+ await highlightClosePromise;
+ is(highlight.state, "closed", "Should close UITour highlight after page unloaded");
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_clean_up_uitour_on_window_resize() {
+ resetOnboardingDefaultState();
+ await SpecialPowers.pushPrefEnv({set: [
+ ["browser.onboarding.newtour", "singlesearch,customize"],
+ ]});
+
+ // Trigger UITour showHighlight
+ let highlight = document.getElementById("UITourHighlightContainer");
+ let highlightOpenPromise = promisePopupChange(highlight, "open");
+ let tab = await openTab(ABOUT_NEWTAB_URL);
+ await triggerUITourHighlight("customize", tab);
+ await highlightOpenPromise;
+ is(highlight.state, "open", "Should show UITour highlight");
+ is(highlight.getAttribute("targetName"), "customize", "UITour should highlight customize");
+
+ // Resize window to destroy the onboarding tour
+ const originalWidth = window.innerWidth;
+ let highlightClosePromise = promisePopupChange(highlight, "closed");
+ window.innerWidth = 300;
+ await highlightClosePromise;
+ is(highlight.state, "closed", "Should close UITour highlight after window resized");
+ window.innerWidth = originalWidth;
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/browser/extensions/onboarding/test/browser/head.js b/browser/extensions/onboarding/test/browser/head.js
new file mode 100644
index 000000000000..9a66f60df88a
--- /dev/null
+++ b/browser/extensions/onboarding/test/browser/head.js
@@ -0,0 +1,288 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let { Preferences } = ChromeUtils.import("resource://gre/modules/Preferences.jsm", {});
+
+const ABOUT_HOME_URL = "about:home";
+const ABOUT_NEWTAB_URL = "about:newtab";
+const URLs = [ABOUT_HOME_URL, ABOUT_NEWTAB_URL];
+const TOUR_IDs = [
+ "onboarding-tour-performance",
+ "onboarding-tour-private-browsing",
+ "onboarding-tour-screenshots",
+ "onboarding-tour-addons",
+ "onboarding-tour-customize",
+ "onboarding-tour-default-browser",
+];
+const UPDATE_TOUR_IDs = [
+ "onboarding-tour-performance",
+ "onboarding-tour-library",
+ "onboarding-tour-screenshots",
+ "onboarding-tour-singlesearch",
+ "onboarding-tour-customize",
+ "onboarding-tour-sync",
+];
+const ICON_STATE_WATERMARK = "watermark";
+const ICON_STATE_DEFAULT = "default";
+
+registerCleanupFunction(resetOnboardingDefaultState);
+
+function resetOnboardingDefaultState() {
+ // All the prefs should be reset to the default states
+ // and no need to revert back so we don't use `SpecialPowers.pushPrefEnv` here.
+ Preferences.set("browser.onboarding.enabled", true);
+ Preferences.set("browser.onboarding.state", ICON_STATE_DEFAULT);
+ Preferences.set("browser.onboarding.notification.finished", false);
+ Preferences.set("browser.onboarding.notification.mute-duration-on-first-session-ms", 300000);
+ Preferences.set("browser.onboarding.notification.max-life-time-per-tour-ms", 432000000);
+ Preferences.set("browser.onboarding.notification.max-life-time-all-tours-ms", 1209600000);
+ Preferences.set("browser.onboarding.notification.max-prompt-count-per-tour", 8);
+ Preferences.reset("browser.onboarding.notification.last-time-of-changing-tour-sec");
+ Preferences.reset("browser.onboarding.notification.prompt-count");
+ Preferences.reset("browser.onboarding.notification.tour-ids-queue");
+ Preferences.reset("browser.onboarding.skip-tour-button.hide");
+ TOUR_IDs.forEach(id => Preferences.reset(`browser.onboarding.tour.${id}.completed`));
+ UPDATE_TOUR_IDs.forEach(id => Preferences.reset(`browser.onboarding.tour.${id}.completed`));
+}
+
+function setTourCompletedState(tourId, state) {
+ Preferences.set(`browser.onboarding.tour.${tourId}.completed`, state);
+}
+
+async function openTab(url) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+ let loadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+ await loadedPromise;
+ return tab;
+}
+
+function reloadTab(tab) {
+ let reloadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ tab.linkedBrowser.reload();
+ return reloadPromise;
+}
+
+function promiseOnboardingOverlayLoaded(browser) {
+ function isLoaded() {
+ let doc = content && content.document;
+ if (doc.querySelector("#onboarding-overlay")) {
+ ok(true, "Should load onboarding overlay");
+ return Promise.resolve();
+ }
+ return new Promise(resolve => {
+ let observer = new content.MutationObserver(mutations => {
+ mutations.forEach(mutation => {
+ let overlay = Array.from(mutation.addedNodes)
+ .find(node => node.id == "onboarding-overlay");
+ if (overlay) {
+ observer.disconnect();
+ ok(true, "Should load onboarding overlay");
+ resolve();
+ }
+ });
+ });
+ observer.observe(doc.body, { childList: true });
+ });
+ }
+ return ContentTask.spawn(browser, {}, isLoaded);
+}
+
+function promiseOnboardingOverlayOpened(browser) {
+ return BrowserTestUtils.waitForCondition(() =>
+ ContentTask.spawn(browser, {}, () =>
+ content.document.querySelector("#onboarding-overlay").classList.contains(
+ "onboarding-opened")),
+ "Should open onboarding overlay",
+ 100,
+ 30
+ );
+}
+
+function promiseOnboardingOverlayClosed(browser) {
+ return BrowserTestUtils.waitForCondition(() =>
+ ContentTask.spawn(browser, {}, () =>
+ !content.document.querySelector("#onboarding-overlay").classList.contains(
+ "onboarding-opened")),
+ "Should close onboarding overlay",
+ 100,
+ 30
+ );
+}
+
+function promisePrefUpdated(name, expectedValue) {
+ return new Promise(resolve => {
+ let onUpdate = actualValue => {
+ Preferences.ignore(name, onUpdate);
+ is(expectedValue, actualValue, `Should update the pref of ${name}`);
+ resolve();
+ };
+ Preferences.observe(name, onUpdate);
+ });
+}
+
+function promiseTourNotificationOpened(browser) {
+ function isOpened() {
+ let doc = content && content.document;
+ let notification = doc.querySelector("#onboarding-notification-bar");
+ if (notification && notification.classList.contains("onboarding-opened")) {
+ ok(true, "Should open tour notification");
+ return Promise.resolve();
+ }
+ return new Promise(resolve => {
+ let observer = new content.MutationObserver(mutations => {
+ mutations.forEach(mutation => {
+ let bar = Array.from(mutation.addedNodes)
+ .find(node => node.id == "onboarding-notification-bar");
+ if (bar && bar.classList.contains("onboarding-opened")) {
+ observer.disconnect();
+ ok(true, "Should open tour notification");
+ resolve();
+ }
+ });
+ });
+ observer.observe(doc.body, { childList: true });
+ });
+ }
+ return ContentTask.spawn(browser, {}, isOpened);
+}
+
+function promiseTourNotificationClosed(browser) {
+ let condition = () => {
+ return ContentTask.spawn(browser, {}, function() {
+ return new Promise(resolve => {
+ let bar = content.document.querySelector("#onboarding-notification-bar");
+ if (bar && !bar.classList.contains("onboarding-opened")) {
+ resolve(true);
+ return;
+ }
+ resolve(false);
+ });
+ });
+ };
+ return BrowserTestUtils.waitForCondition(
+ condition,
+ "Should close tour notification",
+ 100,
+ 30
+ );
+}
+
+function getCurrentNotificationTargetTourId(browser) {
+ return ContentTask.spawn(browser, {}, function() {
+ let bar = content.document.querySelector("#onboarding-notification-bar");
+ return bar ? bar.dataset.targetTourId : null;
+ });
+}
+
+function getCurrentActiveTour(browser) {
+ return ContentTask.spawn(browser, {}, function() {
+ let list = content.document.querySelector("#onboarding-tour-list");
+ let items = list.querySelectorAll(".onboarding-tour-item");
+ let activeNavItemId = null;
+ for (let item of items) {
+ if (item.classList.contains("onboarding-active")) {
+ if (!activeNavItemId) {
+ activeNavItemId = item.id;
+ } else {
+ ok(false, "There are more than one item marked as active.");
+ }
+ }
+ }
+ let activePageId = null;
+ let pages = content.document.querySelectorAll(".onboarding-tour-page");
+ for (let page of pages) {
+ if (page.style.display != "none") {
+ if (!activePageId) {
+ activePageId = page.id;
+ } else {
+ ok(false, "Thre are more than one tour page visible.");
+ }
+ }
+ }
+ return { activeNavItemId, activePageId };
+ });
+}
+
+function waitUntilWindowIdle(browser) {
+ return ContentTask.spawn(browser, {}, function() {
+ return new Promise(resolve => content.requestIdleCallback(resolve));
+ });
+}
+
+function skipMuteNotificationOnFirstSession() {
+ Preferences.set("browser.onboarding.notification.mute-duration-on-first-session-ms", 0);
+}
+
+function assertOverlaySemantics(browser) {
+ return ContentTask.spawn(browser, {}, function() {
+ let doc = content.document;
+
+ info("Checking dialog");
+ let dialog = doc.getElementById("onboarding-overlay-dialog");
+ is(dialog.getAttribute("role"), "dialog",
+ "Dialog should have a dialog role attribute set");
+ is(dialog.tabIndex, "-1", "Dialog should be focusable but not in tab order");
+ is(dialog.getAttribute("aria-labelledby"), "onboarding-header",
+ "Dialog should be labaled by its header");
+
+ info("Checking the tablist container");
+ is(doc.getElementById("onboarding-tour-list").getAttribute("role"), "tablist",
+ "Tour list should have a tablist role attribute set");
+
+ info("Checking each tour item that represents the tab");
+ let items = [...doc.querySelectorAll(".onboarding-tour-item")];
+ items.forEach(item => {
+ is(item.parentNode.getAttribute("role"), "presentation",
+ "Parent should have no semantic value");
+ is(item.getAttribute("aria-selected"),
+ item.classList.contains("onboarding-active") ? "true" : "false",
+ "Active item should have aria-selected set to true and inactive to false");
+ is(item.tabIndex, "0", "Item tab index must be set for keyboard accessibility");
+ is(item.getAttribute("role"), "tab", "Item should have a tab role attribute set");
+ let tourPanelId = `${item.id}-page`;
+ is(item.getAttribute("aria-controls"), tourPanelId,
+ "Item should have aria-controls attribute point to its tabpanel");
+ let panel = doc.getElementById(tourPanelId);
+ is(panel.getAttribute("role"), "tabpanel",
+ "Tour panel should have a tabpanel role attribute set");
+ is(panel.getAttribute("aria-labelledby"), item.id,
+ "Tour panel should have aria-labelledby attribute point to its tab");
+ });
+ });
+}
+
+function assertModalDialog(browser, args) {
+ return ContentTask.spawn(browser, args, ({ keyboardFocus, visible, focusedId }) => {
+ let doc = content.document;
+ let overlayButton = doc.getElementById("onboarding-overlay-button");
+ if (visible) {
+ [...doc.body.children].forEach(child =>
+ child.id !== "onboarding-overlay" &&
+ is(child.getAttribute("aria-hidden"), "true",
+ "Content should not be visible to screen reader"));
+ is(focusedId ? doc.getElementById(focusedId) : doc.body,
+ doc.activeElement, `Focus should be on ${focusedId || "body"}`);
+ is(keyboardFocus ? "true" : undefined,
+ overlayButton.dataset.keyboardFocus,
+ "Overlay button focus state is saved correctly");
+ } else {
+ [...doc.body.children].forEach(
+ child => ok(!child.hasAttribute("aria-hidden"),
+ "Content should be visible to screen reader"));
+ if (keyboardFocus) {
+ is(overlayButton, doc.activeElement,
+ "Focus should be set on overlay button");
+ }
+ ok(!overlayButton.dataset.keyboardFocus,
+ "Overlay button focus state should be cleared");
+ }
+ });
+}
+
+function assertWatermarkIconDisplayed(browser) {
+ return ContentTask.spawn(browser, {}, function() {
+ let overlayButton = content.document.getElementById("onboarding-overlay-button");
+ ok(overlayButton.classList.contains("onboarding-watermark"), "Should display the watermark onboarding icon");
+ });
+}
diff --git a/browser/extensions/onboarding/test/unit/.eslintrc.js b/browser/extensions/onboarding/test/unit/.eslintrc.js
new file mode 100644
index 000000000000..58f8bd73ee48
--- /dev/null
+++ b/browser/extensions/onboarding/test/unit/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "plugin:mozilla/xpcshell-test",
+ ],
+};
diff --git a/browser/extensions/onboarding/test/unit/head.js b/browser/extensions/onboarding/test/unit/head.js
new file mode 100644
index 000000000000..715ba8589b4e
--- /dev/null
+++ b/browser/extensions/onboarding/test/unit/head.js
@@ -0,0 +1,54 @@
+/**
+ * Provides infrastructure for automated onboarding components tests.
+ */
+
+"use strict";
+
+/* global Cc, Ci, Cu */
+ChromeUtils.import("resource://gre/modules/Preferences.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "resProto",
+ "@mozilla.org/network/protocol;1?name=resource",
+ "nsISubstitutingProtocolHandler");
+
+// Load our bootstrap extension manifest so we can access our chrome/resource URIs.
+// Cargo culted from formautofill system add-on
+const EXTENSION_ID = "onboarding(a)mozilla.org";
+let extensionDir = Services.dirsvc.get("GreD", Ci.nsIFile);
+extensionDir.append("browser");
+extensionDir.append("features");
+extensionDir.append(EXTENSION_ID);
+let resourceURI;
+// If the unpacked extension doesn't exist, use the packed version.
+if (!extensionDir.exists()) {
+ extensionDir.leafName += ".xpi";
+
+ resourceURI = "jar:" + Services.io.newFileURI(extensionDir).spec + "!/chrome/content/";
+} else {
+ resourceURI = Services.io.newFileURI(extensionDir).spec + "/chrome/content/";
+}
+Components.manager.addBootstrappedManifestLocation(extensionDir);
+
+resProto.setSubstitution("onboarding", Services.io.newURI(resourceURI));
+
+const TOURSET_VERSION = 1;
+const NEXT_TOURSET_VERSION = 2;
+const PREF_TOUR_TYPE = "browser.onboarding.tour-type";
+const PREF_TOURSET_VERSION = "browser.onboarding.tourset-version";
+const PREF_SEEN_TOURSET_VERSION = "browser.onboarding.seen-tourset-version";
+
+function resetOnboardingDefaultState() {
+ // All the prefs should be reset to what prefs should looks like in a new user profile
+ Services.prefs.setIntPref(PREF_TOURSET_VERSION, TOURSET_VERSION);
+ Services.prefs.clearUserPref(PREF_SEEN_TOURSET_VERSION);
+ Services.prefs.clearUserPref(PREF_TOUR_TYPE);
+}
+
+function resetOldProfileDefaultState() {
+ // All the prefs should be reset to what prefs should looks like in a older new user profile
+ Services.prefs.setIntPref(PREF_TOURSET_VERSION, TOURSET_VERSION);
+ Services.prefs.setIntPref(PREF_SEEN_TOURSET_VERSION, 0);
+ Services.prefs.clearUserPref(PREF_TOUR_TYPE);
+}
diff --git a/browser/extensions/onboarding/test/unit/test-onboarding-tour-type.js b/browser/extensions/onboarding/test/unit/test-onboarding-tour-type.js
new file mode 100644
index 000000000000..489ae6eebce1
--- /dev/null
+++ b/browser/extensions/onboarding/test/unit/test-onboarding-tour-type.js
@@ -0,0 +1,89 @@
+/*
+ * Test for onboarding tour type check.
+ */
+
+"use strict";
+
+ChromeUtils.import("resource://onboarding/modules/OnboardingTourType.jsm");
+
+add_task(async function() {
+ info("Starting testcase: When New user open the browser first time");
+ resetOnboardingDefaultState();
+ OnboardingTourType.check();
+
+ Assert.equal(Preferences.get(PREF_TOUR_TYPE), "new", "should show the new user tour");
+ Assert.equal(Preferences.get(PREF_TOURSET_VERSION), TOURSET_VERSION,
+ "tourset version should not change");
+ Assert.equal(Preferences.get(PREF_SEEN_TOURSET_VERSION), TOURSET_VERSION,
+ "seen tourset version should be set as the tourset version");
+});
+
+add_task(async function() {
+ info("Starting testcase: When New user restart the browser");
+ resetOnboardingDefaultState();
+ Preferences.set(PREF_TOUR_TYPE, "new");
+ Preferences.set(PREF_SEEN_TOURSET_VERSION, TOURSET_VERSION);
+ OnboardingTourType.check();
+
+ Assert.equal(Preferences.get(PREF_TOUR_TYPE), "new", "should show the new user tour");
+ Assert.equal(Preferences.get(PREF_TOURSET_VERSION), TOURSET_VERSION,
+ "tourset version should not change");
+ Assert.equal(Preferences.get(PREF_SEEN_TOURSET_VERSION), TOURSET_VERSION,
+ "seen tourset version should be set as the tourset version");
+});
+
+add_task(async function() {
+ info("Starting testcase: When New User choosed to hide the overlay and restart the browser");
+ resetOnboardingDefaultState();
+ Preferences.set(PREF_TOUR_TYPE, "new");
+ Preferences.set(PREF_SEEN_TOURSET_VERSION, TOURSET_VERSION);
+ OnboardingTourType.check();
+
+ Assert.equal(Preferences.get(PREF_TOUR_TYPE), "new", "should show the new user tour");
+ Assert.equal(Preferences.get(PREF_TOURSET_VERSION), TOURSET_VERSION,
+ "tourset version should not change");
+ Assert.equal(Preferences.get(PREF_SEEN_TOURSET_VERSION), TOURSET_VERSION,
+ "seen tourset version should be set as the tourset version");
+});
+
+add_task(async function() {
+ info("Starting testcase: When New User updated to the next major version and restart the browser");
+ resetOnboardingDefaultState();
+ Preferences.set(PREF_TOURSET_VERSION, NEXT_TOURSET_VERSION);
+ Preferences.set(PREF_TOUR_TYPE, "new");
+ Preferences.set(PREF_SEEN_TOURSET_VERSION, TOURSET_VERSION);
+ OnboardingTourType.check();
+
+ Assert.equal(Preferences.get(PREF_TOUR_TYPE), "update", "should show the update user tour");
+ Assert.equal(Preferences.get(PREF_TOURSET_VERSION), NEXT_TOURSET_VERSION,
+ "tourset version should not change");
+ Assert.equal(Preferences.get(PREF_SEEN_TOURSET_VERSION), NEXT_TOURSET_VERSION,
+ "seen tourset version should be set as the tourset version");
+});
+
+add_task(async function() {
+ info("Starting testcase: When New User prefer hide the tour, then updated to the next major version and restart the browser");
+ resetOnboardingDefaultState();
+ Preferences.set(PREF_TOURSET_VERSION, NEXT_TOURSET_VERSION);
+ Preferences.set(PREF_TOUR_TYPE, "new");
+ Preferences.set(PREF_SEEN_TOURSET_VERSION, TOURSET_VERSION);
+ OnboardingTourType.check();
+
+ Assert.equal(Preferences.get(PREF_TOUR_TYPE), "update", "should show the update user tour");
+ Assert.equal(Preferences.get(PREF_TOURSET_VERSION), NEXT_TOURSET_VERSION,
+ "tourset version should not change");
+ Assert.equal(Preferences.get(PREF_SEEN_TOURSET_VERSION), NEXT_TOURSET_VERSION,
+ "seen tourset version should be set as the tourset version");
+});
+
+add_task(async function() {
+ info("Starting testcase: When User update from browser version < 56");
+ resetOldProfileDefaultState();
+ OnboardingTourType.check();
+
+ Assert.equal(Preferences.get(PREF_TOUR_TYPE), "update", "should show the update user tour");
+ Assert.equal(Preferences.get(PREF_TOURSET_VERSION), TOURSET_VERSION,
+ "tourset version should not change");
+ Assert.equal(Preferences.get(PREF_SEEN_TOURSET_VERSION), TOURSET_VERSION,
+ "seen tourset version should be set as the tourset version");
+});
diff --git a/browser/extensions/onboarding/test/unit/xpcshell.ini b/browser/extensions/onboarding/test/unit/xpcshell.ini
new file mode 100644
index 000000000000..ed484d0f200f
--- /dev/null
+++ b/browser/extensions/onboarding/test/unit/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+firefox-appdir = browser
+head = head.js
+
+[test-onboarding-tour-type.js]
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 9e36326dee5b..f583f0fd8f0a 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -268,6 +268,7 @@
@RESPATH@/browser/chrome/icons/default/default64.png
@RESPATH@/browser/chrome/icons/default/default128.png
#endif
+@RESPATH@/browser/features/*
; [DevTools Startup Files]
@RESPATH@/browser/chrome/devtools-startup@JAREXT@
diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in
index 1fdf34d9460f..d2671745854d 100644
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -58,6 +58,7 @@ libs-%:
@$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
+ @$(MAKE) -C ../extensions/onboarding/locales AB_CD=$* XPI_NAME=locale-$*
@$(MAKE) -C ../../devtools/client/locales AB_CD=$* XPI_NAME=locale-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
@$(MAKE) -C ../../devtools/startup/locales AB_CD=$* XPI_NAME=locale-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
@@ -71,6 +72,7 @@ chrome-%:
@$(MAKE) -C ../../toolkit/locales chrome-$*
@$(MAKE) -C ../../services/sync/locales chrome AB_CD=$*
@$(MAKE) -C ../../extensions/spellcheck/locales chrome AB_CD=$*
+ @$(MAKE) -C ../extensions/onboarding/locales chrome AB_CD=$*
@$(MAKE) -C ../../devtools/client/locales chrome AB_CD=$*
@$(MAKE) -C ../../devtools/startup/locales chrome AB_CD=$*
@$(MAKE) chrome AB_CD=$*
diff --git a/browser/locales/filter.py b/browser/locales/filter.py
index 1fc9b14e7c87..b3ca1609a412 100755
--- a/browser/locales/filter.py
+++ b/browser/locales/filter.py
@@ -13,6 +13,7 @@ def test(mod, path, entity=None):
"browser",
"browser/extensions/formautofill",
"browser/extensions/fxmonitor",
+ "browser/extensions/onboarding",
"browser/extensions/report-site-issue",
"extensions/spellcheck",
"other-licenses/branding/firefox",
diff --git a/browser/locales/l10n.ini b/browser/locales/l10n.ini
index f4cb7caf53b0..33642110b600 100644
--- a/browser/locales/l10n.ini
+++ b/browser/locales/l10n.ini
@@ -14,6 +14,7 @@ dirs = browser
devtools/startup
browser/extensions/formautofill
browser/extensions/fxmonitor
+ browser/extensions/onboarding
browser/extensions/report-site-issue
[includes]
diff --git a/browser/locales/l10n.toml b/browser/locales/l10n.toml
index dc5b9025ac12..acdda5e7dd30 100644
--- a/browser/locales/l10n.toml
+++ b/browser/locales/l10n.toml
@@ -128,6 +128,10 @@ locales = [
reference = "browser/extensions/formautofill/locales/en-US/**"
l10n = "{l}browser/extensions/formautofill/**"
+[[paths]]
+ reference = "browser/extensions/onboarding/locales/en-US/**"
+ l10n = "{l}browser/extensions/onboarding/**"
+
[[paths]]
reference = "browser/extensions/fxmonitor/locales/en-US/**"
l10n = "{l}browser/extensions/fxmonitor/**"
diff --git a/extensions/permissions/PermissionManager.cpp b/extensions/permissions/PermissionManager.cpp
index 36665fad7de7..1450bf865a84 100644
--- a/extensions/permissions/PermissionManager.cpp
+++ b/extensions/permissions/PermissionManager.cpp
@@ -125,6 +125,9 @@ static const nsLiteralCString kPreloadPermissions[] = {
// removed. See bug 1428130.
NS_LITERAL_CSTRING("cookie"),
+ // Bug 28822: Make sure uitour permissions are preloaded in content processes.
+ NS_LITERAL_CSTRING("uitour"),
+
USER_INTERACTION_PERM};
// Certain permissions should never be persisted to disk under GeckoView; it's
diff --git a/tools/lint/codespell.yml b/tools/lint/codespell.yml
index 5e4acbabf8a1..6d6cbcc70937 100644
--- a/tools/lint/codespell.yml
+++ b/tools/lint/codespell.yml
@@ -9,6 +9,7 @@ codespell:
- browser/components/touchbar/docs/
- browser/components/urlbar/docs/
- browser/extensions/formautofill/locales/en-US/
+ - browser/extensions/onboarding/locales/en-US/
- browser/extensions/report-site-issue/locales/en-US/
- browser/installer/windows/docs/
- browser/locales/en-US/
1
0