Merge tag 'v23.02.01'

PiSCSI Version 23.02.01
This commit is contained in:
Tony Kuker 2023-02-11 12:36:10 -06:00
commit 3c7e2cd7a3
70 changed files with 5633 additions and 2529 deletions

View File

@ -7,6 +7,7 @@
!/doc !/doc
!/python !/python
!/cpp !/cpp
!/os_integration
!/test !/test
!/easyinstall.sh !/easyinstall.sh
!/LICENCE !/LICENCE

View File

@ -32,3 +32,5 @@ Special thank you to the Silver level sponsors!
- <a href="https://github.com/pendleton115">@pendleton115</a> - <a href="https://github.com/pendleton115">@pendleton115</a>
- <a href="https://github.com/Teufelhunden-0311">@Teufelhunden-0311</a> - <a href="https://github.com/Teufelhunden-0311">@Teufelhunden-0311</a>
- Private sponsor ;] - Private sponsor ;]
Thank you to Lin van der Slikke for the red panda logo design!

View File

@ -69,7 +69,7 @@ MAN_PAGE_DIR = /usr/local/man/man1
DOC_DIR = ../doc DOC_DIR = ../doc
COVERAGE_DIR = coverage COVERAGE_DIR = coverage
COVERAGE_FILE = piscsi.dat COVERAGE_FILE = piscsi.dat
OS_FILES = os_integration OS_FILES = ../os_integration
OBJDIR := obj/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]') OBJDIR := obj/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
BINDIR := bin/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]') BINDIR := bin/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')

View File

@ -36,10 +36,12 @@ DeviceFactory::DeviceFactory()
string network_interfaces; string network_interfaces;
for (const auto& network_interface : GetNetworkInterfaces()) { for (const auto& network_interface : GetNetworkInterfaces()) {
if (!network_interfaces.empty()) { if (network_interface.rfind("dummy", 0) == string::npos) {
network_interfaces += ","; if (!network_interfaces.empty()) {
network_interfaces += ",";
}
network_interfaces += network_interface;
} }
network_interfaces += network_interface;
} }
default_params[SCBR]["interface"] = network_interfaces; default_params[SCBR]["interface"] = network_interfaces;

View File

@ -10,8 +10,6 @@
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
// [ SCSI CD-ROM ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/piscsi_exceptions.h" #include "shared/piscsi_exceptions.h"
@ -79,7 +77,6 @@ void SCSICD::Open()
SetReadOnly(true); SetReadOnly(true);
SetProtectable(false); SetProtectable(false);
// Attention if ready
if (IsReady()) { if (IsReady()) {
SetAttn(true); SetAttn(true);
} }
@ -113,13 +110,12 @@ void SCSICD::OpenIso()
throw io_exception("Illegal raw ISO CD-ROM file header"); throw io_exception("Illegal raw ISO CD-ROM file header");
} }
// Set to RAW file
rawfile = true; rawfile = true;
} }
if (rawfile) { if (rawfile) {
if (size % 2536) { if (size % 2536) {
throw io_exception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes but is " GetLogger().Warn("Raw ISO CD-ROM file size is not a multiple of 2536 bytes but is "
+ to_string(size) + " bytes"); + to_string(size) + " bytes");
} }
@ -134,7 +130,6 @@ void SCSICD::OpenIso()
// TODO This code is only executed if the filename starts with a `\`, but fails to open files starting with `\`. // TODO This code is only executed if the filename starts with a `\`, but fails to open files starting with `\`.
void SCSICD::OpenPhysical() void SCSICD::OpenPhysical()
{ {
// Get size
off_t size = GetFileSize(); off_t size = GetFileSize();
if (size < 2048) { if (size < 2048) {
throw io_exception("CD-ROM file size must be at least 2048 bytes"); throw io_exception("CD-ROM file size must be at least 2048 bytes");
@ -176,12 +171,10 @@ void SCSICD::SetUpModePages(map<int, vector<byte>>& pages, int page, bool change
{ {
Disk::SetUpModePages(pages, page, changeable); Disk::SetUpModePages(pages, page, changeable);
// Page code 13
if (page == 0x0d || page == 0x3f) { if (page == 0x0d || page == 0x3f) {
AddCDROMPage(pages, changeable); AddCDROMPage(pages, changeable);
} }
// Page code 14
if (page == 0x0e || page == 0x3f) { if (page == 0x0e || page == 0x3f) {
AddCDDAPage(pages, changeable); AddCDDAPage(pages, changeable);
} }
@ -226,10 +219,7 @@ int SCSICD::Read(const vector<int>& cdb, vector<uint8_t>& buf, uint64_t block)
{ {
CheckReady(); CheckReady();
// Search for the track
const int index = SearchTrack(static_cast<int>(block)); const int index = SearchTrack(static_cast<int>(block));
// If invalid, out of range
if (index < 0) { if (index < 0) {
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
} }
@ -249,7 +239,6 @@ int SCSICD::Read(const vector<int>& cdb, vector<uint8_t>& buf, uint64_t block)
dataindex = index; dataindex = index;
} }
// Base class
assert(dataindex >= 0); assert(dataindex >= 0);
return Disk::Read(cdb, buf, block); return Disk::Read(cdb, buf, block);
} }
@ -321,7 +310,6 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<uint8_t>& buf)
int offset = 4; int offset = 4;
// Loop....
for (int i = 0; i < loop; i++) { for (int i = 0; i < loop; i++) {
// ADR and Control // ADR and Control
if (tracks[index]->IsAudio()) { if (tracks[index]->IsAudio()) {
@ -351,11 +339,6 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<uint8_t>& buf)
return length; return length;
} }
//---------------------------------------------------------------------------
//
// LBA→MSF Conversion
//
//---------------------------------------------------------------------------
void SCSICD::LBAtoMSF(uint32_t lba, uint8_t *msf) const void SCSICD::LBAtoMSF(uint32_t lba, uint8_t *msf) const
{ {
// 75 and 75*60 get the remainder // 75 and 75*60 get the remainder
@ -390,12 +373,6 @@ void SCSICD::ClearTrack()
audioindex = -1; audioindex = -1;
} }
//---------------------------------------------------------------------------
//
// Track Search
// * Returns -1 if not found
//
//---------------------------------------------------------------------------
int SCSICD::SearchTrack(uint32_t lba) const int SCSICD::SearchTrack(uint32_t lba) const
{ {
// Track loop // Track loop

View File

@ -5,7 +5,7 @@
// //
// Powered by XM6 TypeG Technology. // Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS // Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020-2022 Contributors to the PiSCSI project // Copyright (C) 2020-2023 Contributors to the PiSCSI project
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -146,11 +146,11 @@ PbDeviceType Piscsi::ParseDeviceType(const string& value) const
return type; return type;
} }
void Piscsi::TerminationHandler(int signum) void Piscsi::TerminationHandler(int)
{ {
Cleanup(); Cleanup();
exit(signum); // Process will terminate automatically
} }
Piscsi::optargs_type Piscsi::ParseArguments(const vector<char *>& args, int& port) const Piscsi::optargs_type Piscsi::ParseArguments(const vector<char *>& args, int& port) const

View File

@ -599,7 +599,12 @@ bool PiscsiExecutor::ValidateImageFile(const CommandContext& context, StorageDev
storage_device.SetProtectable(true); storage_device.SetProtectable(true);
} }
storage_device.Open(); try {
storage_device.Open();
}
catch(const io_exception&) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_FILE_OPEN, effective_filename);
}
full_path = effective_filename; full_path = effective_filename;

View File

@ -5,7 +5,7 @@
// //
// Powered by XM6 TypeG Technology. // Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS // Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020-2022 Contributors to the PiSCSI project // Copyright (C) 2020-2023 Contributors to the PiSCSI project
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -239,7 +239,7 @@ int ScsiCtl::run(const vector<char *>& args) const
case 'X': case 'X':
command.set_operation(SHUT_DOWN); command.set_operation(SHUT_DOWN);
SetParam(command, "mode", "piscsi"); SetParam(command, "mode", "rascsi");
break; break;
case 'z': case 'z':

View File

@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI // SCSI Target Emulator PiSCSI
// for Raspberry Pi // for Raspberry Pi
// //
// Copyright (C) 2021-2022 Uwe Seimet // Copyright (C) 2021-2023 Uwe Seimet
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -74,7 +74,7 @@ string piscsi_util::Banner(const string& app)
s << "Version " << piscsi_get_version_string() << " (" << __DATE__ << ' ' << __TIME__ << ")\n"; s << "Version " << piscsi_get_version_string() << " (" << __DATE__ << ' ' << __TIME__ << ")\n";
s << "Powered by XM6 TypeG Technology / "; s << "Powered by XM6 TypeG Technology / ";
s << "Copyright (C) 2016-2020 GIMONS\n"; s << "Copyright (C) 2016-2020 GIMONS\n";
s << "Copyright (C) 2020-2022 Contributors to the PiSCSI project\n"; s << "Copyright (C) 2020-2023 Contributors to the PiSCSI project\n";
return s.str(); return s.str();
} }

View File

@ -13,9 +13,9 @@
#include <iomanip> #include <iomanip>
// The following should be updated for each release // The following should be updated for each release
const int piscsi_major_version = 22; // Last two digits of year const int piscsi_major_version = 23; // Last two digits of year
const int piscsi_minor_version = 12; // Month const int piscsi_minor_version = 2; // Month
const int piscsi_patch_version = 1; // Patch number - increment for each update const int piscsi_patch_version = 1; // Patch number - increment for each update
using namespace std; using namespace std;
@ -23,13 +23,13 @@ string piscsi_get_version_string()
{ {
stringstream s; stringstream s;
s << setw(2) << setfill('0') << piscsi_major_version << '.' << piscsi_minor_version; s << setw(2) << setfill('0') << piscsi_major_version << '.' << setw(2) << piscsi_minor_version;
if (piscsi_patch_version < 0) { if (piscsi_patch_version < 0) {
s << " --DEVELOPMENT BUILD--"; s << " --DEVELOPMENT BUILD--";
} }
else { else {
s << '.' << piscsi_patch_version; s << '.' << setw(2) << piscsi_patch_version;
} }
return s.str(); return s.str();

View File

@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI // SCSI Target Emulator PiSCSI
// for Raspberry Pi // for Raspberry Pi
// //
// Copyright (C) 2022 Uwe Seimet // Copyright (C) 2022-2023 Uwe Seimet
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -106,7 +106,7 @@ TEST(HostServicesTest, ModeSense6)
// Minor version 0 // Minor version 0
EXPECT_EQ(0x00, buffer[7]); EXPECT_EQ(0x00, buffer[7]);
// Year // Year
EXPECT_NE(0x00, buffer[9]); EXPECT_NE(0x00, buffer[8]);
// Day // Day
EXPECT_NE(0x00, buffer[10]); EXPECT_NE(0x00, buffer[10]);
@ -151,7 +151,7 @@ TEST(HostServicesTest, ModeSense10)
// Minor version 0 // Minor version 0
EXPECT_EQ(0x00, buffer[11]); EXPECT_EQ(0x00, buffer[11]);
// Year // Year
EXPECT_NE(0x00, buffer[13]); EXPECT_NE(0x00, buffer[12]);
// Day // Day
EXPECT_NE(0x00, buffer[14]); EXPECT_NE(0x00, buffer[14]);

View File

@ -278,7 +278,7 @@ TEST_F(PiscsiExecutorTest, Attach)
path filename = CreateTempFile(1); path filename = CreateTempFile(1);
SetParam(definition, "file", filename.c_str()); SetParam(definition, "file", filename.c_str());
EXPECT_THROW(executor.Attach(context, definition, false), io_exception) << "Too small image file not rejected"; EXPECT_FALSE(executor.Attach(context, definition, false)) << "Too small image file not rejected";
remove(filename); remove(filename);
filename = CreateTempFile(512); filename = CreateTempFile(512);
@ -359,8 +359,7 @@ TEST_F(PiscsiExecutorTest, Insert)
path filename = CreateTempFile(1); path filename = CreateTempFile(1);
SetParam(definition, "file", filename.c_str()); SetParam(definition, "file", filename.c_str());
EXPECT_THROW(executor.Insert(context, definition, device, false), io_exception) EXPECT_FALSE(executor.Insert(context, definition, device, false)) << "Too small image file not rejected";
<< "Too small image file not rejected";
remove(filename); remove(filename);
filename = CreateTempFile(512); filename = CreateTempFile(512);

View File

@ -95,9 +95,7 @@ TEST(ScsiCdTest, Open)
out.open(filename); out.open(filename);
out.write(header.data(), header.size()); out.write(header.data(), header.size());
out.close(); out.close();
resize_file(filename, 2 * 2535);
cd_raw.SetFilename(string(filename)); cd_raw.SetFilename(string(filename));
EXPECT_THROW(cd_raw.Open(), io_exception) << "Raw ISO CD-ROM image file size must be a multiple of 2536";
resize_file(filename, 2 * 2536); resize_file(filename, 2 * 2536);
cd_raw.Open(); cd_raw.Open();
EXPECT_EQ(2, cd_raw.GetBlockCount()); EXPECT_EQ(2, cd_raw.GetBlockCount());

View File

@ -3,7 +3,7 @@
// SCSI Target Emulator PiSCSI // SCSI Target Emulator PiSCSI
// for Raspberry Pi // for Raspberry Pi
// //
// Copyright (C) 2022 Uwe Seimet // Copyright (C) 2022-2023 Uwe Seimet
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -64,7 +64,7 @@ void TestInquiry(PbDeviceType type, device_type t, scsi_level l, const string& i
string product_data; string product_data;
if (ident.size() == 24) { if (ident.size() == 24) {
ostringstream s; ostringstream s;
s << ident << setw(2) << setfill('0') << piscsi_major_version << piscsi_minor_version; s << ident << setw(2) << setfill('0') << piscsi_major_version << setw(2) << piscsi_minor_version;
product_data = s.str(); product_data = s.str();
} else { } else {
product_data = ident; product_data = ident;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

BIN
doc/logo/redpanda-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
doc/logo/redpanda-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

1986
doc/logo/redpanda-mono.ai Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/logo/redpanda-mono.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

272
doc/logo/redpanda-mono.svg Normal file
View File

@ -0,0 +1,272 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 320 320" style="enable-background:new 0 0 320 320;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;fill:#CC6600;}
.st2{fill:#CC6600;}
.st3{fill:#FFFFFF;}
.st4{fill:none;}
</style>
<g id="BG" class="st0">
<rect x="0" y="0" class="st1" width="320" height="320"/>
<line class="st2" x1="160" y1="-0.5" x2="160" y2="339.5"/>
</g>
<g id="line" class="st0">
</g>
<g id="body">
<g>
<g>
<path class="st3" d="M258.4,177.1c0.3-0.4,0.6-0.8,0.7-0.9c0-0.1,0.1-0.2,0.2-0.2c1.3-1.5,1.9-3.2,1.7-3.5c0,0,0,0,0-0.1
c-0.1-0.1-0.2-0.3-0.4-0.4c-0.1-0.1-0.3-0.1-0.4-0.2c-2.6-0.6-8.7,2.2-16.8,7.7c-0.4,0.3-1,0.3-1.4-0.1c-0.4-0.4-0.5-1-0.3-1.5
c0.5-1.3,1-3,0.1-3.5c-0.2-0.1-0.5-0.2-0.9-0.2c-2.6,0-7.9,3.5-12.2,7.3c-7.1,6.2-11,12.6-10.1,16.2c0.1,0.4,0.2,0.8,0.3,1.2
c0.2,0.8,0.5,1.6,0.6,2.4c0.1,0.5,0.2,0.9,0.3,1.4c1.1,3.9,1.7,7.7,1.6,11.3l0,1.3c-0.1,8.5-0.2,17.3-7.4,26.8
c0.1,0.1,0.2,0.2,0.3,0.3c0.6-0.4,1.4-0.9,2.2-1.5c2.8-2,5.7-3.7,8.6-5.3c7.3-4,14.8-13.6,17.4-20.8c0.5-1.6,1.7-6.2,1.7-7.9
c0-1.6,1.6-2,3.2-2.2c0.3,0,0.5-0.1,0.8-0.1c0.3,0,1.4-0.8,1.7-1l0.1,0c1.9-0.6,2.4-1,2.5-1.3c0,0-0.1-0.2-0.5-0.6v0
c-0.3-0.3-0.4-0.7-0.4-1c0.1-0.9,0.7-1.2,2.8-2.2c0.2-0.1,0.4-0.2,0.5-0.2c0,0,0.1-0.1,0.1-0.1c0.3-0.1,0.3-0.5,0.3-0.5
c0-0.1,0-0.4-0.3-0.5c-0.2-0.1-0.4-0.2-0.5-0.4c-0.2-0.3-0.3-0.7-0.2-1.1c0.1-0.8,0.8-1.4,2.4-2.6c0.2-0.2,0.4-0.3,0.5-0.4
c0,0,0.1-0.1,0.1-0.1c0.2-0.2,0.4-0.4,0.4-0.6c0-0.4-0.6-1.1-1.5-1.6c-0.2-0.1-0.3-0.2-0.4-0.4c-1.1-1.6,0.8-3.1,2.3-4.3
c0.2-0.2,0.6-0.5,0.7-0.6c0-0.1,0.1-0.1,0.2-0.2c0.3-0.3,0.5-0.8,0.4-1.2c0-0.3-0.2-0.4-0.3-0.4l-2.4-1c-0.3-0.1-0.6-0.4-0.7-0.8
c-0.1-0.2-0.1-0.3-0.1-0.5c0-0.7,0.5-1.4,2.3-3.7C258.1,177.3,258.2,177.2,258.4,177.1z"/>
<path class="st3" d="M106.3,242.2c-7.2-9.5-7.3-18.3-7.4-26.8l0-1.3c-0.1-3.6,0.5-7.4,1.6-11.3c0.1-0.5,0.2-0.9,0.3-1.4
c0.2-0.8,0.4-1.7,0.6-2.4c0.1-0.4,0.2-0.8,0.3-1.2c0.9-3.6-3-10-10.1-16.2c-4.9-4.3-11.1-8.2-13.1-7.1c-0.9,0.5-0.5,2.2,0.1,3.5
c0.2,0.5,0.1,1.1-0.3,1.5c-0.4,0.4-1,0.4-1.4,0.1c-8.1-5.5-14.2-8.3-16.8-7.7c-0.2,0-0.3,0.1-0.4,0.2c-0.2,0.1-0.4,0.3-0.4,0.4
c0,0,0,0.1,0,0.1c-0.2,0.3,0.3,2,1.7,3.5c0.1,0.1,0.1,0.2,0.2,0.2c0.1,0.1,0.4,0.5,0.7,0.9c0.1,0.1,0.2,0.3,0.3,0.4
c1.8,2.2,2.3,3,2.3,3.7c0,0.2,0,0.3-0.1,0.5c-0.1,0.3-0.3,0.6-0.7,0.8l-2.4,1c-0.1,0-0.2,0.1-0.3,0.4c-0.1,0.4,0.1,0.9,0.4,1.2
c0.1,0.1,0.1,0.1,0.2,0.2c0.1,0.1,0.4,0.4,0.7,0.6c1.5,1.2,3.4,2.7,2.3,4.3c-0.1,0.2-0.3,0.3-0.4,0.4c-0.9,0.5-1.5,1.2-1.5,1.6
c0,0.2,0.2,0.5,0.4,0.6c0,0,0.1,0.1,0.1,0.1c0.1,0.1,0.3,0.2,0.5,0.4c1.6,1.2,2.3,1.7,2.4,2.6c0.1,0.4,0,0.8-0.2,1.1
c-0.1,0.2-0.3,0.3-0.5,0.4c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.1,0,0.4,0.3,0.5c0,0,0.1,0,0.1,0.1c0.1,0,0.3,0.1,0.5,0.2
c2.1,1,2.7,1.3,2.8,2.2c0,0.4-0.1,0.8-0.4,1l0,0c-0.4,0.4-0.4,0.6-0.4,0.6c0.1,0.2,0.6,0.6,2.5,1.2l0.1,0c0.4,0.1,1.5,0.9,1.7,1
c0.3,0,0.5,0.1,0.8,0.1c1.6,0.2,3.2,0.7,3.2,2.2c0,1.7,1.3,6.3,1.8,7.9c2.5,7.2,10.1,16.7,17.4,20.7c2.9,1.6,5.8,3.4,8.6,5.3
c0.8,0.6,1.6,1.1,2.2,1.5C106.1,242.4,106.2,242.2,106.3,242.2z"/>
</g>
<g>
<path class="st3" d="M243.5,148.9L243.5,148.9l-0.2-0.1c-0.3,0-0.5-0.1-0.8-0.1c-0.2,0-0.3-0.1-0.4-0.2c-0.1-0.2-0.1-0.3-0.1-0.5
c0.2-0.4,0.5-0.8,0.9-1c0.6-0.3,1-0.9,0.9-1.5c-0.1-0.6-0.5-1.1-1.2-1.2c-3-0.7-5.6-0.7-8.2-0.8c-0.2,0-0.3-0.1-0.4-0.2
c-0.1-0.1-0.2-0.3-0.2-0.5c0.1-0.6,0.2-1.2,0.7-1.7c0.5-0.5,0.6-1.1,0.4-1.6c0,0,0-0.1,0-0.1c-0.2-0.4-0.7-0.7-1.2-0.7
c-0.3,0-0.7-0.1-1-0.1c-2.4-0.2-4.7-0.1-6.9,0.2c-0.2,0-0.4-0.1-0.5-0.1c-0.2-0.1-0.2-0.3-0.2-0.5c0.1-0.5,0.4-1,0.9-1.4
c0.5-0.5,0.6-1.1,0.3-1.7c-0.3-0.5-0.8-0.8-1.5-0.8c-2.7,0.1-5.2,0.4-7.7,0.7c-0.8,0.1-1.5,0.2-2.3,0.3c-0.3,0-0.4-0.1-0.5-0.2
c-0.1-0.1-0.2-0.4-0.1-0.7c0.1-0.3,0.3-0.5,0.5-0.9c0.3-0.5,0.3-1.1-0.1-1.6c-0.3-0.4-0.9-0.6-1.4-0.5
c-4.8,0.4-11.2,1.3-15.9,4.1c-1.4,0.8-2.9,1.5-4.4,2.2c-1.2,0.6-2.4,1.3-3.6,2.2c-0.8,0.6-1.5,1.2-2.2,1.7l-0.4,0.4
c-0.9,0.8-1.9,1.8-2.9,2.8c-1.7,1.7-3.3,3.7-5,5.9c-0.5,0.6-1,1.3-1.4,1.9c-0.4,0.6-0.9,1.2-1.3,1.8c-0.6,0.9-1.2,1.8-1.8,2.7
c-2.4,3.8-6.4,10.9-5.9,15.6c0.2,1.7,0.9,3,2.2,3.9c1.1,0.7,2.4,1.1,4,1.1c1,0,2.2-0.2,3.5-0.5c0.4-0.1,0.7-0.2,1.1-0.3
c0.3-0.1,0.6-0.2,0.9-0.3c0.3-0.1,0.6-0.2,0.9-0.3c0.5-0.2,0.9-0.4,1.4-0.6c1.1,3.4,4.3,6.3,8.8,8c0.6,0.2,1.2,0.4,1.9,0.6
c0.4,0.1,0.8,0.2,1.3,0.3c0.5,0.1,0.9,0.2,1.4,0.3c1.2,0.2,2.4,0.3,3.6,0.3c0.3,0,0.7,0,1,0c0.9,0,1.8-0.2,2.6-0.4l0.1,0
c0.1,0,0.2-0.1,0.3-0.1c0.6-0.2,1.2-0.4,1.9-0.7c2.6-1.1,4.7-3.1,6-5.7c1.4-2.8,1.8-6.1,1.1-9.3c-0.1-0.4-0.2-0.9-0.4-1.3
c-0.2-0.6-0.4-1.2-0.7-1.8c1.7-0.7,3.5-1.7,5.1-3c1.3-1,2.4-2.1,3.4-3.2c0.4-0.5,1-0.8,1.8-0.9c0.7-0.1,1.5-0.2,2.2-0.4
c0.9-0.2,1.8-0.4,2.7-0.5c0.4-0.1,0.9-0.2,1.3-0.3c0.7-0.1,1.3-0.3,1.9-0.5c0.8-0.2,1.7-0.4,2.5-0.6c0.8-0.2,1.6-0.5,2.4-0.7
c0.8-0.3,1.6-0.5,2.3-0.8c0.6-0.2,1.1-0.4,1.7-0.6c0.5-0.2,1.1-0.4,1.5-0.7c0.6-0.3,1.2-0.6,1.7-0.9c0.6-0.3,1.1-0.7,1.6-1
c0.6-0.5,1-0.9,1.2-1.3C244.5,150,244.2,149.3,243.5,148.9z M205.8,175.9c-0.8,1.5-2,2.7-3.5,3.4c-0.4,0.2-0.7,0.3-1.1,0.4
c-0.1,0-0.2,0-0.2,0.1c-0.5,0.1-1.1,0.2-1.6,0.2c-1,0.1-2,0-3.1-0.2c-0.3-0.1-0.6-0.1-0.9-0.2c-0.3-0.1-0.6-0.1-0.9-0.2
c-0.4-0.1-0.8-0.3-1.2-0.4c-2.8-1.1-4.8-2.8-5.5-4.8c-0.6-2,0.1-4.4,1.8-6.7c0.1-0.2,0.3-0.3,0.4-0.5c0,0,0.1-0.1,0.1-0.1
c0.5-2.5,2.8-4.5,5.6-4.5c0.8,0,1.6,0.2,2.3,0.5c1.4,0,2.8,0.4,4.1,1.2c2,1.2,3.5,3.1,4.2,5.3c0.1,0.3,0.2,0.6,0.2,0.8
C206.9,172.2,206.7,174.2,205.8,175.9z"/>
<path class="st3" d="M195.7,164.4c-2,0-3.6,1.5-3.6,3.4c0,1.9,1.6,3.4,3.6,3.4c2,0,3.6-1.5,3.6-3.4
C199.2,166,197.6,164.4,195.7,164.4z"/>
<path class="st3" d="M144.1,154.4c-0.4-0.6-0.8-1.2-1.3-1.8c-0.5-0.7-1-1.3-1.4-1.9c-1.7-2.1-3.3-4.1-5-5.9c-1-1-2-2-2.9-2.8
l-0.4-0.4c-0.7-0.6-1.4-1.1-2.2-1.7c-1.2-0.9-2.5-1.6-3.6-2.2c-1.5-0.7-3-1.4-4.4-2.2c-4.6-2.8-11-3.6-15.9-4.1
c-0.6-0.1-1.1,0.2-1.4,0.5c-0.4,0.4-0.4,1.1-0.1,1.6c0.2,0.3,0.3,0.6,0.5,0.9c0.1,0.3,0,0.5-0.1,0.7c-0.1,0.1-0.3,0.2-0.5,0.2
c-0.8-0.1-1.6-0.2-2.3-0.3c-2.4-0.3-5-0.6-7.7-0.7c-0.6,0-1.2,0.3-1.5,0.8c-0.3,0.5-0.2,1.2,0.3,1.7c0.5,0.5,0.8,0.9,0.9,1.4
c0,0.2,0,0.4-0.2,0.5c-0.1,0.1-0.2,0.2-0.5,0.1c-2.2-0.3-4.5-0.4-6.9-0.2c-0.3,0-0.7,0.1-1,0.1c-0.5,0.1-1,0.3-1.2,0.7
c0,0,0,0.1,0,0.1c-0.2,0.5-0.1,1.2,0.4,1.6c0.5,0.5,0.6,1,0.7,1.7c0,0.2,0,0.4-0.2,0.5c-0.1,0.1-0.3,0.2-0.4,0.2
c-2.6,0-5.2,0.1-8.2,0.8c-0.7,0.1-1.1,0.6-1.2,1.2c-0.1,0.6,0.3,1.2,0.9,1.5c0.5,0.2,0.8,0.5,0.9,1c0.1,0.2,0,0.4-0.1,0.5
c-0.1,0.1-0.2,0.2-0.4,0.2c-0.3,0-0.5,0.1-0.8,0.1l-0.1,0l-0.1,0.1c-0.7,0.5-1,1.1-0.7,1.8c0.2,0.4,0.6,0.9,1.2,1.3
c0.4,0.3,0.9,0.7,1.6,1c0.5,0.3,1.1,0.6,1.7,0.9c0.5,0.2,1,0.4,1.5,0.7c0.5,0.2,1.1,0.4,1.7,0.6c0.7,0.3,1.5,0.5,2.3,0.8
c0.8,0.2,1.6,0.5,2.4,0.7c0.8,0.2,1.6,0.4,2.5,0.6c0.6,0.2,1.3,0.3,1.9,0.5c0.4,0.1,0.9,0.2,1.3,0.3c0.9,0.2,1.8,0.4,2.7,0.5
c0.7,0.1,1.5,0.3,2.2,0.4c0.7,0.1,1.3,0.4,1.8,0.9c1,1.1,2.1,2.2,3.4,3.2c1.6,1.3,3.3,2.2,5.1,3c-0.3,0.6-0.5,1.2-0.7,1.8
c-0.1,0.4-0.3,0.9-0.4,1.3c-0.7,3.2-0.3,6.5,1.1,9.3c1.3,2.6,3.4,4.5,6,5.7c0.7,0.3,1.3,0.5,1.9,0.7c0.1,0,0.2,0,0.3,0.1l0.1,0
c0.8,0.2,1.7,0.3,2.6,0.4c0.3,0,0.7,0,1,0c1.2,0,2.4-0.1,3.6-0.3c0.5-0.1,0.9-0.2,1.4-0.3c0.4-0.1,0.8-0.2,1.3-0.3
c0.7-0.2,1.3-0.4,1.9-0.6c4.5-1.7,7.7-4.6,8.8-8c0.5,0.2,0.9,0.4,1.4,0.6c0.3,0.1,0.6,0.2,0.9,0.3c0.3,0.1,0.6,0.2,0.9,0.3
c0.4,0.1,0.7,0.2,1.1,0.3c1.3,0.3,2.4,0.5,3.5,0.5c1.6,0,3-0.4,4-1.1c1.2-0.9,2-2.2,2.2-3.9c0.5-4.6-3.5-11.8-5.9-15.6
C145.3,156.2,144.7,155.3,144.1,154.4z M132.3,174.1c-0.6,2-2.6,3.7-5.5,4.8c-0.4,0.2-0.8,0.3-1.2,0.4c-0.3,0.1-0.6,0.2-0.9,0.2
c-0.3,0.1-0.6,0.1-0.9,0.2c-1.1,0.2-2.1,0.2-3.1,0.2c-0.6,0-1.1-0.1-1.6-0.2c-0.1,0-0.2,0-0.2-0.1c-0.4-0.1-0.8-0.2-1.1-0.4
c-1.5-0.7-2.7-1.8-3.5-3.4c-0.9-1.7-1.1-3.7-0.7-5.7c0.1-0.3,0.1-0.6,0.2-0.8c0.7-2.3,2.2-4.2,4.2-5.3c1.3-0.8,2.7-1.2,4.1-1.2
c0.7-0.3,1.5-0.5,2.3-0.5c2.8,0,5.1,1.9,5.6,4.5c0,0,0.1,0.1,0.1,0.1c0.1,0.2,0.3,0.3,0.4,0.5
C132.2,169.7,132.9,172.1,132.3,174.1z"/>
<path class="st3" d="M124.3,164.4c-2,0-3.6,1.5-3.6,3.4c0,1.9,1.6,3.4,3.6,3.4c2,0,3.6-1.5,3.6-3.4
C127.9,166,126.3,164.4,124.3,164.4z"/>
</g>
<g>
<path class="st3" d="M180.8,200.3c-6.3-7.2-13.5-9.2-20.8-8.8c-7.3-0.5-14.5,1.6-20.8,8.8c-4.4,0.9-21.1,5.3-20.9,24.5
c0.2,10,5.8,17.7,13.1,21.7l0.1-0.7c0-0.2,0.1-0.3,0.2-0.4c0.1-0.1,0.3-0.2,0.5-0.1c1.8,0.2,2.8,0.8,3.2,1.9
c0.1,0.4,0.1,0.7,0.1,1.1c0,0,0.1,0,0.1,0c1.1,5.9,5.4,11.7,11.9,14.7c3.9,1.8,8.2,2.4,12.5,2.1c4.3,0.3,8.7-0.3,12.5-2.1
c6.5-3,10.9-8.7,11.9-14.7c0,0,0.1,0,0.1,0c-0.1-0.4,0-0.8,0.1-1.1c0.3-1,1.4-1.7,3.2-1.9c0.2,0,0.3,0,0.5,0.1
c0.1,0.1,0.2,0.3,0.2,0.4l0.1,0.7c7.3-4,12.9-11.7,13.1-21.7C202,205.6,185.2,201.2,180.8,200.3z M173.5,212.2
c-0.2,1.3-0.6,2.7-1.2,4.1c-0.2,0.4-0.4,0.8-0.6,1.2c-0.2,0.4-0.4,0.7-0.6,1.1c-0.3,0.5-0.7,1.1-1,1.6c-2.6,3.6-6.1,5.8-9.6,6
c-0.1,0-0.3,0-0.5,0c-3.4,0.1-7-1.5-10.2-4.5c-0.2-0.2-0.5-0.5-0.7-0.7c-0.2-0.2-0.4-0.4-0.6-0.6c-0.2-0.2-0.3-0.4-0.5-0.6
c-1-1.2-1.8-2.5-2.4-3.8c-0.2-0.5-0.5-1-0.6-1.5c-0.2-0.5-0.4-1.1-0.5-1.6c-0.1-0.4-0.2-0.8-0.2-1.2c-0.3-2.9,0.9-5.8,3.4-8.1
c2.6-2.4,6.2-3.8,10.1-4.1c0.5,0,1-0.1,1.5-0.1c0.2,0,0.5,0,0.7,0c3.2,0.1,6.2,1,8.6,2.6c2.3,1.5,3.9,3.6,4.6,5.8
c0.2,0.5,0.3,1.1,0.3,1.6c0,0.1,0,0.2,0,0.3C173.6,210.7,173.6,211.4,173.5,212.2z"/>
</g>
</g>
<g>
<path class="st4" d="M253.9,125.3L253.9,125.3c-0.4-0.3-0.7-0.5-1.1-0.7c-0.4-0.2-0.8-0.5-1.1-0.7c-0.4-0.2-0.7-0.4-1.1-0.6
c-0.2-0.4-0.4-0.7-0.6-1.1c-0.7-1.2-1.4-2.5-2.2-3.7c-2.2-3.7-5.3-7-8.9-10c0,0,0.1-0.1,0.1-0.1c0.4-0.5,0.6-1,0.4-1.5
c-0.1-0.2-0.2-0.4-0.3-0.6c-1.4-1.5-3.1-2.7-5.1-3.7c-0.1,0-0.1-0.1-0.2-0.1c-0.8-0.4-1.6-0.8-2.4-1.2c-0.5-0.2-1-0.4-1.4-0.6
c-0.4-0.2-0.8-0.3-1.2-0.5c-0.1,0-0.2-0.1-0.2-0.1c0.1,0,0.3-0.1,0.6-0.1c0.2,0,0.4-0.1,0.6-0.1c0.9-0.3,1.7-0.8,2-1.5
c0.2-0.3,0.2-0.7,0.1-1c-0.1-0.4-0.4-0.8-0.9-1.1c-1-0.5-2-1-3-1.4c-1.5-0.7-3.1-1.3-4.7-1.9c0.1,0,0.2,0,0.3,0
c1.3-0.1,2.4-0.7,2.8-1.6c0,0,0,0,0,0c0.4-0.9,0-1.8-1-2.2c-0.1,0-0.2-0.1-0.3-0.1c-3.8-1.6-6.9-2.1-9.4-2.6
c0.1-0.1,0.3-0.2,0.5-0.3c1.1-0.4,1.9-1.1,2-2c0.1-0.8-0.6-1.5-1.7-1.8c-3.3-0.7-6.2-0.9-9.2-1c0.2-0.4,0.4-0.7,0.7-0.9
c0.9-0.6,1.3-1.3,1.1-2.1c0-0.1-0.1-0.2-0.2-0.4c-0.3-0.5-1-0.9-1.8-1c-0.7-0.1-1.4-0.2-2.1-0.2c-0.3,0-0.6,0-1-0.1
c-2-0.1-3.9-0.1-5.9,0c0,0,0,0,0,0c0.1-0.2,0.4-0.4,0.8-0.6c0.2-0.1,0.4-0.3,0.5-0.4c0.4-0.4,0.6-0.8,0.6-1.3c0-0.1,0-0.3-0.1-0.4
c-0.1-0.1-0.1-0.3-0.2-0.4c-0.2-0.2-0.4-0.4-0.6-0.5c-0.4-0.2-0.9-0.4-1.5-0.4c-0.3,0-0.5,0-0.8,0c-0.6,0-1.1,0-1.7,0
c-0.4-0.3-0.7-0.6-1.1-1c-0.1-0.1-0.2-0.1-0.3-0.2c-0.2-0.2-0.5-0.3-0.7-0.5c-0.1-0.1-0.3-0.2-0.4-0.3c-0.1-0.1-0.3-0.2-0.4-0.3
c-0.2-0.1-0.3-0.2-0.5-0.3c-0.1-0.1-0.3-0.2-0.4-0.3c-0.3-0.2-0.6-0.3-0.9-0.5c-0.2-0.1-0.4-0.2-0.5-0.3c-0.1,0-0.1-0.1-0.2-0.1
c-0.6-0.3-1.2-0.7-1.9-1c-0.9-0.5-1.9-0.9-2.9-1.3c-0.1,0-0.2-0.1-0.4-0.1c-1-0.4-2-0.8-3-1.1c-0.7-0.2-1.5-0.3-2.3-0.3
c-1-0.5-2-1-3.1-1.5c-0.3-0.1-0.6-0.2-0.9-0.3c0,0,0,0,0,0c-0.3-0.1-0.6-0.1-1-0.1c-0.6,0-1.2,0.1-1.7,0.4
c-0.4,0.2-0.6,0.4-0.8,0.6c-2-0.9-4.5-1.8-7.4-2.1c-1.2-0.1-2.4,0.2-3,0.8c-0.1,0.1-0.1,0.1-0.2,0.2c-2.6-0.6-5.2-1.1-7.7-1.2
c-1.3,0-2.3,0.5-2.7,1.2c0,0.1-0.1,0.2-0.1,0.2c-2.2-0.3-4.6-0.5-7.1-0.4c-1.2,0-2.1,0.5-2.4,1.2c-0.1,0.2-0.1,0.4-0.1,0.6
c-1.9-0.1-3.8,0-5.6,0.1c-1.2,0.1-2.2,0.6-2.4,1.3c-0.1,0.2,0,0.5,0,0.7c-2.1,0-4.2,0.2-6.2,0.7c-0.2,0-0.3,0.1-0.4,0.1
c0,0,0,0,0,0c-0.1,0.1-0.2,0.1-0.4,0.2c-0.3,0.2-0.5,0.4-0.6,0.6c0,0,0,0,0,0c-0.1,0.1-0.1,0.2-0.1,0.3c0,0,0,0.1,0,0.1
c0,0.1,0,0.2,0,0.4c0,0.1,0.1,0.3,0.2,0.4c-1.5,0.1-3.1,0.2-4.9,0.7c-0.9,0.2-1.5,0.8-1.6,1.5c0,0.5,0.4,1.1,1,1.5
c-0.1,0.1-0.2,0.1-0.2,0.2c0,0.1-0.1,0.1-0.1,0.2c-0.8,0.2-1.6,0.3-2.3,0.4c-1.3,0.2-2.1,0.9-2,1.8c0.1,0.3,0.2,0.5,0.4,0.8
c-0.1,0-0.2,0-0.3,0c-0.3,0-0.6,0-1,0.1c-0.7,0.1-1.4,0.1-2.1,0.2c-0.8,0.1-1.5,0.5-1.8,1c-0.1,0.1-0.1,0.2-0.2,0.4
c-0.2,0.7,0.2,1.5,1.1,2.1c0.3,0.2,0.5,0.4,0.7,0.9c-3,0.1-5.9,0.3-9.2,1c-1.1,0.2-1.8,0.9-1.7,1.8c0.1,0.8,0.8,1.6,2,2
c0.2,0.1,0.4,0.2,0.5,0.3c-2.5,0.4-5.6,1-9.4,2.6c-0.1,0-0.2,0.1-0.3,0.1c-1,0.4-1.4,1.3-1,2.2c0,0,0,0,0,0
c0.4,0.9,1.6,1.5,2.8,1.6c0.1,0,0.2,0,0.3,0c-1.6,0.5-3.1,1.2-4.7,1.9c-1,0.5-2,0.9-3,1.4c-0.5,0.3-0.8,0.7-0.9,1.1
c-0.1,0.3,0,0.6,0.1,1c0.3,0.7,1.1,1.2,2,1.5c0.2,0.1,0.4,0.1,0.6,0.1c0.3,0,0.4,0.1,0.6,0.1c-0.1,0-0.2,0.1-0.2,0.1
c-0.4,0.2-0.8,0.3-1.2,0.5c-0.5,0.2-1,0.4-1.4,0.6c-0.8,0.4-1.6,0.7-2.4,1.2c-0.1,0-0.1,0.1-0.2,0.1c-1.9,1-3.7,2.3-5.1,3.7
c-0.2,0.2-0.3,0.4-0.3,0.6c-0.1,0.5,0,1,0.4,1.5c0,0,0.1,0.1,0.1,0.1c-3.7,3.1-6.8,6.4-8.9,10c-0.7,1.2-1.4,2.5-2.2,3.7
c-0.2,0.4-0.4,0.7-0.6,1.1c-0.4,0.2-0.7,0.4-1.1,0.6c-0.4,0.2-0.8,0.4-1.1,0.7c-0.4,0.2-0.7,0.5-1.1,0.7
c-6.7,4.7-13.7,14.2-15.5,26.6c-0.1,0.5-0.1,1-0.2,1.5c0,0.2,0,0.4-0.1,0.6c0,0.3-0.1,0.6-0.1,0.9c0,0.3,0,0.6-0.1,0.9
c0,0.2,0,0.5,0,0.7c0,0.4,0,0.7,0,1.1c0,0.1,0,0.3,0,0.5c0,2.1,0.2,4.3,0.6,6.6c0,0,0,0,0,0c0.2,1,0.4,2,0.6,3.1
c-0.9,0.4-1.7,1-2.2,1.8c-1.4,2.1,0.2,5.3,2.2,7.5c0.2,0.4,0.7,0.9,1.4,1.7c0.4,0.5,1,1.1,1.4,1.7l-1.3,0.5c0,0,0,0,0,0
c-1.1,0.5-1.8,1.5-2,2.8c-0.2,1.4,0.3,2.9,1.4,3.9c0.2,0.3,0.6,0.6,1.3,1.1c0.3,0.3,1,0.7,1.5,1.2c-0.9,0.7-2,1.8-2.2,3.3
c0,0.2,0,0.4,0,0.6c0.1,0.4,0.2,0.7,0.3,1.1c0.2,0.5,0.6,1,1.2,1.5c0.2,0.2,0.5,0.4,1.1,0.8c0.3,0.2,0.7,0.5,1.1,0.7
c-0.4,0.6-0.6,1.2-0.7,2c0,1.4,0.7,2.7,2,3.3c0.2,0.1,0.4,0.2,0.8,0.4c0.2,0.1,0.6,0.3,1,0.5c-0.3,0.7-0.4,1.4-0.3,2
c0.4,1.7,2.3,2.7,4,3.2c0.5,1.2,1.9,1.4,3.8,1.6c0.6,0.1,1.5,0.2,2.1,0.3c0.1,0.9,0.3,1.7,0.5,2.5c0.1,0.3,0.1,0.5,0.2,0.8
c0.1,0.6,0.3,1.1,0.4,1.7c0.1,0.3,0.2,0.6,0.2,0.9c0.1,0.5,0.3,1,0.5,1.5c0.1,0.3,0.2,0.6,0.3,0.8c0.2,0.5,0.4,1.1,0.6,1.6
c0.1,0.2,0.1,0.4,0.2,0.6c0.3,0.7,0.6,1.4,0.9,2c0.1,0.3,0.3,0.5,0.4,0.8c0.2,0.4,0.4,0.8,0.6,1.2c0.2,0.3,0.3,0.6,0.5,0.9
c0.2,0.3,0.4,0.7,0.6,1c0.2,0.3,0.3,0.6,0.5,0.9c0.2,0.3,0.4,0.6,0.6,0.9c0.2,0.3,0.4,0.6,0.6,0.9c0.2,0.3,0.4,0.6,0.6,0.9
c0.4,0.5,0.8,1.1,1.2,1.6c0.2,0.2,0.3,0.4,0.5,0.6c0.2,0.3,0.5,0.6,0.7,0.9c0.2,0.2,0.3,0.4,0.5,0.6c0.3,0.3,0.5,0.6,0.8,0.9
c0.1,0.2,0.3,0.3,0.4,0.5c0.3,0.3,0.6,0.6,0.8,0.9c0.1,0.1,0.1,0.1,0.2,0.2c0.7,0.7,1.3,1.3,2,1.9c0.1,0,0.1,0.1,0.2,0.1
c0.3,0.3,0.6,0.5,0.9,0.8c0.1,0.1,0.3,0.2,0.4,0.3c0.3,0.2,0.5,0.4,0.8,0.7c0.2,0.1,0.3,0.2,0.5,0.4c4.7,3.7,8.9,5.6,10.4,6
c0.3,0.1,0.7,0.2,1,0.3c0.3,0.2,0.5,0.4,0.8,0.6c2.8,2.1,5.5,4.1,8.3,6c0.8,0.5,1.6,1.1,2.4,1.6c0,0,0,0,0,0
c0.7,0.5,1.5,0.9,2.2,1.4c0.1,0.1,0.2,0.1,0.3,0.2c1.5,0.9,3.1,1.8,4.7,2.6c0.2,0.1,0.3,0.2,0.5,0.2c0.7,0.3,1.4,0.7,2.1,1
c0.1,0.1,0.3,0.1,0.4,0.2c0.8,0.4,1.6,0.7,2.5,1.1c0.2,0.1,0.3,0.1,0.5,0.2c0.7,0.3,1.4,0.6,2.1,0.8c0.2,0.1,0.5,0.2,0.7,0.3
c0.9,0.3,1.7,0.7,2.6,1c0.4,0.1,0.7,0.3,1.1,0.4c0.3,0.3,0.5,0.5,0.8,0.8c8.5,8.6,18.5,14.2,29.8,14.1
c11.3,0.1,21.3-5.5,29.8-14.1c0.3-0.3,0.5-0.5,0.8-0.8c0.4-0.1,0.7-0.3,1.1-0.4c0.9-0.3,1.8-0.6,2.6-1c0.2-0.1,0.5-0.2,0.7-0.3
c0.7-0.3,1.4-0.6,2.1-0.8c0.2-0.1,0.3-0.1,0.5-0.2c0.8-0.4,1.7-0.7,2.5-1.1c0.1-0.1,0.3-0.1,0.4-0.2c0.7-0.3,1.4-0.7,2.1-1
c0.2-0.1,0.3-0.2,0.5-0.2c1.6-0.8,3.2-1.7,4.7-2.6c0.1-0.1,0.2-0.1,0.3-0.2c0.8-0.4,1.5-0.9,2.2-1.4c0,0,0,0,0.1,0
c0.8-0.5,1.6-1,2.4-1.6c0,0,0,0,0,0c2.8-1.8,5.5-3.8,8.3-6c0.3-0.2,0.5-0.4,0.8-0.6c0.3-0.1,0.7-0.2,1-0.3
c1.5-0.4,5.5-2.2,10.2-5.8c0.1-0.1,0.2-0.2,0.4-0.3c0.6-0.5,1.2-1,1.8-1.5c0,0,0.1,0,0.1-0.1c0.3-0.2,0.6-0.5,0.9-0.8
c0.1-0.1,0.3-0.2,0.4-0.3c0.3-0.3,0.6-0.5,0.8-0.8c0.1-0.1,0.3-0.3,0.4-0.4c0.3-0.3,0.6-0.6,0.8-0.9c0.1-0.1,0.1-0.2,0.2-0.2
c0.5-0.6,1.1-1.2,1.6-1.8c0.2-0.2,0.3-0.4,0.5-0.5c0.2-0.3,0.5-0.6,0.7-0.9c0.2-0.2,0.4-0.4,0.5-0.7c0.2-0.3,0.4-0.6,0.6-0.9
c0.2-0.3,0.4-0.5,0.6-0.8c0.2-0.3,0.4-0.5,0.6-0.8c0.3-0.5,0.7-1.1,1-1.6c0.1-0.2,0.3-0.5,0.4-0.7c0.2-0.4,0.4-0.7,0.6-1.1
c0.1-0.3,0.3-0.5,0.4-0.8c0.2-0.4,0.4-0.8,0.6-1.2c0.1-0.3,0.3-0.5,0.4-0.8c0.2-0.5,0.5-1.1,0.7-1.6c0.1-0.1,0.1-0.3,0.2-0.4
c0.3-0.7,0.5-1.4,0.8-2.2c0.1-0.2,0.1-0.4,0.2-0.7c0.2-0.5,0.3-1.1,0.5-1.7c0.1-0.3,0.1-0.5,0.2-0.8c0.2-0.6,0.3-1.2,0.4-1.8
c0.1-0.2,0.1-0.4,0.2-0.7c0.2-0.8,0.3-1.7,0.5-2.6c0.6-0.1,1.5-0.3,2.1-0.3c1.9-0.2,3.3-0.4,3.8-1.6c1.6-0.6,3.5-1.5,4-3.2
c0.2-0.7,0.1-1.4-0.3-2c0.4-0.2,0.8-0.4,1-0.5c0.3-0.2,0.6-0.3,0.8-0.4c1.2-0.6,2-1.9,2-3.3c0-0.7-0.3-1.4-0.7-2
c0.4-0.3,0.8-0.6,1.1-0.7c0.6-0.4,0.9-0.6,1.1-0.8c1.3-1.1,1.5-2.4,1.4-3.2c-0.2-1.5-1.2-2.6-2.2-3.3c0.5-0.4,1.1-0.9,1.5-1.2
c0.7-0.5,1-0.8,1.3-1.1c1-1,1.6-2.5,1.4-3.9c-0.2-1.3-0.9-2.3-2-2.8c0,0,0,0,0,0l-1.3-0.5c0.5-0.6,1-1.3,1.4-1.7
c0.7-0.9,1.1-1.4,1.4-1.7c2.1-2.2,3.6-5.5,2.2-7.5c-0.5-0.8-1.3-1.4-2.2-1.8c0.1-0.5,0.2-1,0.3-1.4c0,0,0,0,0,0
c0.6-2.7,0.8-5.4,0.9-7.8c0,0,0-0.1,0-0.1c0-0.6,0-1.1,0-1.6c0-0.1,0-0.2,0-0.4c0-0.5,0-0.9-0.1-1.3c0-0.2,0-0.5-0.1-0.7
c0-0.3-0.1-0.6-0.1-0.9c-0.1-0.5-0.1-1.1-0.2-1.6C267.6,139.5,260.7,130.1,253.9,125.3z"/>
<path class="st3" d="M282.3,81.6c1.8-3.9,1.9-7.5,0.3-10.8c0.1-1.7-0.2-3.3-0.9-4.9c0.1-1.1,0.1-2.2,0.1-3.2
c0.5-3.4-0.7-6.9-3.2-9.5c0-2.8-0.8-5.2-2.5-7.1c-0.6-0.9-1.3-1.7-2.1-2.4c-0.6-0.6-1.4-1.1-2.1-1.6c-0.7-4.1-3.1-7.4-6.7-9.1
c-3.9-1.8-8.7-1.4-13.6,1.1c-5-1.7-10.8-0.9-17.3,2.5c-3-0.9-6.6-0.8-12,2.2c-6.7-1-11.5,2.1-14.9,5.1c-2.4-0.2-4.6,0.1-6.6,1l0,0
c-2.9,1.2-4.7,3.2-6.3,5c-0.4,0.4-0.8,0.9-1.1,1.2c-6.6,1.3-8.8,4.3-10.3,6.5c0,0,0,0.1-0.1,0.1c-4.2-0.1-7.7-1.2-11.1-2.9
c-0.3,0.2-0.6,0.4-0.9,0.6c-1.7-0.5-3.6-1-5.7-1.2c-0.5-0.1-1-0.1-1.5-0.1c-1.3,0-2.6,0.2-3.8,0.6c-1.9-0.4-4.1-0.7-6.3-0.7
l-0.1,0c-1.9,0-3.6,0.4-5.1,1.1c-0.7-0.6-1.5-1.1-2.3-1.5c-0.4,0.2-0.7,0.5-1.1,0.7c-1.1,0.6-2.2,1.1-3.3,1.5
c-1.4,1.1-2.8,2-4.4,2.6c-0.2-0.2-0.3-0.5-0.5-0.7c-1.6-2.3-3.7-5.3-10.3-6.5c-0.4-0.4-0.8-0.8-1.1-1.2c-1.6-1.8-3.4-3.8-6.3-5
l0,0c-2-0.8-4.1-1.2-6.6-1c-3.4-3.1-8.2-6.2-14.9-5.1c-5.4-3-9-3-12-2.2c-6.5-3.4-12.3-4.3-17.3-2.5c-4.9-2.5-9.6-2.9-13.6-1.1
c-3.6,1.6-6,4.9-6.7,9.1c-0.8,0.5-1.5,1-2.1,1.6c-0.8,0.7-1.5,1.5-2.1,2.4c-1.7,1.9-2.5,4.2-2.5,7.1c-2.5,2.6-3.6,6-3.2,9.5
c-0.1,1-0.1,2.1,0.1,3.2c-0.7,1.6-0.9,3.2-0.9,4.9c-1.6,3.3-1.5,6.9,0.3,10.8C34.6,87.7,38,94,39.9,97c-1,4.1-0.8,8.8,5.3,14.3
c-0.8,5.9,3.2,9.7,6.6,12.5c-0.1,0.2-0.3,0.4-0.4,0.6c-0.3,3.3-1.6,6.6-4.1,8.8c-6.1,9.6-9.7,22.4-7,35.4c-0.4,3.2,0.7,6.8,3.2,10
c-0.5,1-0.8,2.1-1,3.2c-0.4,3,0.4,6.1,2.3,8.5c-0.1,0.5-0.2,1-0.3,1.6c-0.3,3,0.7,6,2.9,8.2c0.1,3,1.5,5.7,3.8,7.5
c0.9,3.8,3.7,5.8,6.2,7c0.5,0.5,1,0.9,1.6,1.2c4.9,24.3,25.3,36,31.4,37.8c0.2,0.1,0.4,0.2,0.6,0.3c8.7,6.7,18.1,13,30.7,17.4
c12,12.4,25,17.1,38.1,17.1h0.7c13.1,0,26.1-4.7,38.1-17.1c12.6-4.4,21.9-10.7,30.7-17.4c0.2-0.1,0.4-0.2,0.6-0.3
c6.2-1.8,26.6-13.5,31.4-37.8c0.6-0.3,1.1-0.7,1.6-1.2c2.5-1.2,5.2-3.2,6.2-7c2.3-1.8,3.7-4.6,3.8-7.5c2.2-2.3,3.3-5.2,2.9-8.2
c-0.1-0.5-0.2-1-0.3-1.6c1.8-2.4,2.7-5.5,2.3-8.5c-0.2-1.1-0.5-2.2-1-3.2c2.5-3.3,3.6-6.9,3.2-10.1c2.8-14-1.4-27.6-8.3-37.4
l0.9-0.4c-2.4-1.4-4.3-3.5-5.4-6.2l0.4-0.1c3.6-2.9,8.4-6.8,7.6-13.3c6-5.5,6.3-10.3,5.3-14.3C282,94,285.4,87.7,282.3,81.6z
M213.6,75.6c0.6-1.1,1.6-1.7,2.8-1.5c0.1,0,0.2,0,0.4,0.1c0.6-1.2,1.2-2.4,2-3.7c0.7-1.1,1.8-1.5,3-1.2c0.2,0.1,0.4,0.2,0.6,0.3
c0.5-0.7,1-1.4,1.6-2c0.9-1,2.4-1.2,3.5-0.3c0,0,0,0,0.1,0.1c0.7-0.8,1.5-1.5,2.5-2.3c1.1-0.8,2.5-0.7,3.5,0.4
c0,0,0.1,0.1,0.1,0.1c0.8-0.5,1.7-1,2.8-1.5c1.1-0.5,2.4-0.2,3.3,0.9c0.1,0.1,0.6-0.6,0.7-0.4c0.5-0.3,0.7,0.3,1.2,0.1
c1.2-0.5,2.5,0.1,3.3,1.3c0,0.1,0.1,0.2,0.1,0.2c1.4-0.5,2.9-0.7,4.5-0.4c1,0.2,1.8,0.9,2.3,1.9c0,0,0.2,0,0.5,0.1
c-0.1,0-0.3,0.1-0.4,0.1c0,0,3.5,0.4,4.6,0.5c0.1,0.1,0.2,0.2,0.3,0.4c0.5,0.7,0.7,1.5,0.7,2.3c0,0.4-0.1,0.8-0.2,1.1
c-0.1,0.4-0.3,0.7-0.4,1.1c-0.2,0.5-0.4,0.9-0.7,1.2l-0.7,0.7c0.6,0.8,0.9,1.9,0.7,3c-0.2,1.4-0.5,2.7-1,3.7
c0.8,0.7,1.3,1.8,1.3,3c0,0.2,0,0.4-0.1,0.6c-0.3,1.8-0.9,3.3-1.6,4.7c0.1,0.1,0.3,0.3,0.4,0.5c0.8,1.1,0.9,2.7,0.4,3.9
c-0.6,1.2-1.3,2.5-2,3.7c0.1,0.1,0.2,0.2,0.2,0.4c0.7,1.1,0.7,2.6,0.1,3.7c-0.9,1.7-2,3.2-3.2,4.5c0.2,0.3,0.3,0.7,0.3,1
c-0.1,0-0.1-0.1-0.2-0.1c-0.2-1.4-1-2.7-2.1-3.5c-0.8-0.6-1.2-1-1.7-1.5c-0.6-0.6-1.2-1.3-2.3-1.9c0-0.3,0-0.7,0-1
c0-0.3-0.1-0.6-0.2-0.9c-0.4-1.4-1.3-2.5-2.4-3.1c-0.5-0.3-1.1-0.5-1.6-0.8c-0.2-0.1-0.5-0.2-0.7-0.3c-0.4-0.2-0.9-0.3-1.3-0.5
c0-0.2,0.1-0.4,0.1-0.7c0-0.4,0-0.7,0-1.1c0-0.3-0.1-0.6-0.2-1c-0.2-0.6-0.5-1.1-0.8-1.5c-0.6-0.7-1.3-1.2-2.1-1.5l-0.6-0.2
c-0.6-0.2-1.3-0.4-1.9-0.6c-0.1-0.7-0.5-1.4-1-1.8c-0.6-0.4-1.2-0.8-1.8-1.2c-0.4-0.3-0.8-0.5-1.3-0.8c-0.6-1-1.6-1.8-2.7-2
c-0.4-0.1-0.9-0.2-1.3-0.3l-0.2-0.1c-3.5-1.9-7.3-3.7-11.2-5.3C213.5,75.9,213.6,75.7,213.6,75.6z M63.2,68.2
c0.1-0.1,0.2-0.3,0.3-0.4c1.1-0.1,4.6-0.5,4.6-0.5c-0.1,0-0.3-0.1-0.4-0.1c0.3,0,0.5-0.1,0.5-0.1c0.4-1,1.3-1.8,2.3-1.9
c1.6-0.3,3.2,0,4.5,0.4c0-0.1,0.1-0.2,0.1-0.2c0.8-1.2,2.1-1.7,3.3-1.3c0.6,0.2,0.7-0.3,1.2-0.1c0.1-0.1,0.6,0.6,0.7,0.4
c0.8-1.1,2.1-1.5,3.3-0.9c1.1,0.5,2,1,2.8,1.5c0,0,0.1-0.1,0.1-0.1c1-1,2.4-1.2,3.5-0.4c1,0.7,1.8,1.5,2.5,2.3c0,0,0,0,0.1-0.1
c1.1-0.8,2.6-0.7,3.5,0.3c0.6,0.6,1.1,1.3,1.6,2c0.2-0.1,0.4-0.2,0.6-0.3c1.1-0.4,2.3,0.1,3,1.2c0.8,1.3,1.4,2.5,2,3.7
c0.1,0,0.2-0.1,0.4-0.1c1.1-0.2,2.2,0.4,2.8,1.5c0.1,0.1,0.1,0.3,0.2,0.4c-3.9,1.6-7.7,3.4-11.2,5.3L95.1,81
c-0.4,0.1-0.9,0.2-1.3,0.3c-1.1,0.3-2,1-2.7,2c-0.4,0.3-0.8,0.5-1.3,0.8c-0.6,0.4-1.2,0.8-1.8,1.2c-0.6,0.4-0.9,1-1,1.8
c-0.6,0.2-1.2,0.4-1.9,0.6l-0.6,0.2c-0.8,0.3-1.5,0.8-2.1,1.5c-0.3,0.4-0.6,0.9-0.8,1.5c-0.1,0.3-0.2,0.7-0.2,1
c-0.1,0.3-0.1,0.7,0,1.1c0,0.2,0,0.4,0.1,0.7c-0.4,0.2-0.9,0.3-1.3,0.5c-0.2,0.1-0.5,0.2-0.7,0.3c-0.5,0.2-1.1,0.5-1.6,0.8
c-1.2,0.6-2.1,1.7-2.4,3.1c-0.1,0.3-0.1,0.6-0.2,0.9c0,0.3,0,0.7,0,1c-1.1,0.6-1.7,1.3-2.3,1.9c-0.4,0.5-0.9,1-1.7,1.5
c-1.2,0.8-1.9,2.1-2.1,3.5c-0.1,0-0.1,0.1-0.2,0.1c0.1-0.3,0.2-0.7,0.3-1c-1.2-1.3-2.3-2.7-3.2-4.5c-0.6-1.1-0.5-2.6,0.1-3.7
c0.1-0.1,0.2-0.2,0.2-0.4c-0.7-1.2-1.4-2.4-2-3.7c-0.6-1.2-0.4-2.8,0.4-3.9c0.1-0.2,0.3-0.3,0.4-0.5c-0.7-1.4-1.3-3-1.6-4.7
c0-0.2-0.1-0.4-0.1-0.6c0-1.1,0.4-2.3,1.3-3c-0.4-1-0.7-2.3-1-3.7c-0.2-1.1,0.1-2.2,0.7-3L63.8,74c-0.3-0.3-0.6-0.8-0.7-1.2
c-0.1-0.4-0.2-0.8-0.4-1.1c-0.1-0.4-0.2-0.7-0.2-1.1C62.5,69.7,62.8,68.9,63.2,68.2z M269.5,151.9c0.1,0.5,0.1,1,0.2,1.6
c0,0.3,0.1,0.6,0.1,0.9c0,0.2,0,0.5,0.1,0.7c0,0.4,0,0.9,0.1,1.3c0,0.1,0,0.2,0,0.4c0,0.5,0,1.1,0,1.6c0,0,0,0.1,0,0.1
c0,2.4-0.3,5-0.9,7.8c0,0,0,0,0,0c-0.1,0.5-0.2,1-0.3,1.4c0.9,0.4,1.7,1,2.2,1.8c1.4,2.1-0.2,5.3-2.2,7.5
c-0.2,0.4-0.7,0.9-1.4,1.7c-0.4,0.5-1,1.1-1.4,1.7l1.3,0.5c0,0,0,0,0,0c1.1,0.5,1.9,1.5,2,2.8c0.2,1.4-0.3,2.9-1.4,3.9
c-0.2,0.3-0.6,0.6-1.3,1.1c-0.3,0.3-1,0.7-1.5,1.2c0.9,0.7,2,1.8,2.2,3.3c0.1,0.8-0.1,2.1-1.4,3.2c-0.2,0.2-0.5,0.4-1.1,0.8
c-0.3,0.2-0.7,0.5-1.1,0.7c0.4,0.6,0.6,1.2,0.7,2c0,1.4-0.7,2.7-2,3.3c-0.2,0.1-0.4,0.2-0.8,0.4c-0.2,0.1-0.6,0.3-1,0.5
c0.3,0.7,0.4,1.4,0.3,2c-0.4,1.7-2.3,2.7-4,3.2c-0.5,1.2-1.9,1.4-3.8,1.6c-0.6,0.1-1.5,0.2-2.1,0.3c-0.1,0.9-0.3,1.7-0.5,2.6
c0,0.2-0.1,0.5-0.2,0.7c-0.1,0.6-0.3,1.2-0.4,1.8c-0.1,0.3-0.1,0.5-0.2,0.8c-0.2,0.6-0.3,1.1-0.5,1.7c-0.1,0.2-0.1,0.4-0.2,0.7
c-0.3,0.7-0.5,1.5-0.8,2.2c-0.1,0.1-0.1,0.3-0.2,0.4c-0.2,0.6-0.5,1.1-0.7,1.6c-0.1,0.3-0.2,0.5-0.4,0.8c-0.2,0.4-0.4,0.8-0.6,1.2
c-0.1,0.3-0.3,0.5-0.4,0.8c-0.2,0.4-0.4,0.8-0.6,1.1c-0.1,0.2-0.3,0.5-0.4,0.7c-0.3,0.5-0.7,1.1-1,1.6c-0.2,0.3-0.4,0.6-0.6,0.8
c-0.2,0.3-0.4,0.5-0.6,0.8c-0.2,0.3-0.4,0.6-0.6,0.9c-0.2,0.2-0.4,0.5-0.5,0.7c-0.2,0.3-0.5,0.6-0.7,0.9c-0.2,0.2-0.3,0.4-0.5,0.5
c-0.5,0.6-1.1,1.2-1.6,1.8c-0.1,0.1-0.1,0.2-0.2,0.2c-0.3,0.3-0.6,0.6-0.8,0.9c-0.1,0.1-0.3,0.3-0.4,0.4c-0.3,0.3-0.6,0.5-0.8,0.8
c-0.1,0.1-0.3,0.2-0.4,0.3c-0.3,0.3-0.6,0.5-0.9,0.8c0,0-0.1,0-0.1,0.1c-0.6,0.5-1.2,1-1.8,1.5c-0.1,0.1-0.2,0.2-0.4,0.3
c-4.6,3.6-8.7,5.4-10.2,5.8c-0.3,0.1-0.7,0.2-1,0.3c-0.3,0.2-0.5,0.4-0.8,0.6c-2.8,2.1-5.5,4.1-8.3,6c0,0,0,0,0,0
c-0.8,0.5-1.6,1.1-2.4,1.6c0,0,0,0-0.1,0c-0.7,0.5-1.5,0.9-2.2,1.4c-0.1,0.1-0.2,0.1-0.3,0.2c-1.5,0.9-3.1,1.8-4.7,2.6
c-0.2,0.1-0.3,0.2-0.5,0.2c-0.7,0.3-1.4,0.7-2.1,1c-0.1,0.1-0.3,0.1-0.4,0.2c-0.8,0.4-1.6,0.7-2.5,1.1c-0.2,0.1-0.3,0.1-0.5,0.2
c-0.7,0.3-1.4,0.6-2.1,0.8c-0.2,0.1-0.5,0.2-0.7,0.3c-0.9,0.3-1.7,0.7-2.6,1c-0.4,0.1-0.7,0.3-1.1,0.4c-0.3,0.3-0.5,0.5-0.8,0.8
c-8.5,8.6-18.5,14.2-29.8,14.1c-11.3,0.1-21.3-5.5-29.8-14.1c-0.3-0.3-0.5-0.5-0.8-0.8c-0.4-0.1-0.7-0.3-1.1-0.4
c-0.9-0.3-1.8-0.6-2.6-1c-0.2-0.1-0.5-0.2-0.7-0.3c-0.7-0.3-1.4-0.6-2.1-0.8c-0.2-0.1-0.3-0.1-0.5-0.2c-0.8-0.4-1.7-0.7-2.5-1.1
c-0.1-0.1-0.3-0.1-0.4-0.2c-0.7-0.3-1.4-0.7-2.1-1c-0.2-0.1-0.3-0.2-0.5-0.2c-1.6-0.8-3.2-1.7-4.7-2.6c-0.1-0.1-0.2-0.1-0.3-0.2
c-0.8-0.5-1.5-0.9-2.2-1.4c0,0,0,0,0,0c-0.8-0.5-1.6-1-2.4-1.6c-2.8-1.8-5.5-3.8-8.3-6c-0.3-0.2-0.5-0.4-0.8-0.6
c-0.3-0.1-0.7-0.2-1-0.3c-1.5-0.4-5.7-2.3-10.4-6c-0.2-0.1-0.3-0.2-0.5-0.4c-0.3-0.2-0.5-0.4-0.8-0.7c-0.1-0.1-0.3-0.2-0.4-0.3
c-0.3-0.2-0.6-0.5-0.9-0.8c-0.1,0-0.1-0.1-0.2-0.1c-0.7-0.6-1.3-1.2-2-1.9c-0.1-0.1-0.1-0.1-0.2-0.2c-0.3-0.3-0.6-0.6-0.8-0.9
c-0.1-0.2-0.3-0.3-0.4-0.5c-0.3-0.3-0.5-0.6-0.8-0.9c-0.2-0.2-0.3-0.4-0.5-0.6c-0.2-0.3-0.5-0.6-0.7-0.9c-0.2-0.2-0.3-0.4-0.5-0.6
c-0.4-0.5-0.8-1-1.2-1.6c-0.2-0.3-0.4-0.6-0.6-0.9c-0.2-0.3-0.4-0.6-0.6-0.9c-0.2-0.3-0.4-0.6-0.6-0.9c-0.2-0.3-0.4-0.6-0.5-0.9
c-0.2-0.3-0.4-0.7-0.6-1c-0.2-0.3-0.3-0.6-0.5-0.9c-0.2-0.4-0.4-0.8-0.6-1.2c-0.1-0.3-0.3-0.5-0.4-0.8c-0.3-0.7-0.6-1.3-0.9-2
c-0.1-0.2-0.1-0.4-0.2-0.6c-0.2-0.5-0.4-1.1-0.6-1.6c-0.1-0.3-0.2-0.6-0.3-0.8c-0.2-0.5-0.3-1-0.5-1.5c-0.1-0.3-0.2-0.6-0.2-0.9
c-0.1-0.5-0.3-1.1-0.4-1.7c-0.1-0.3-0.1-0.5-0.2-0.8c-0.2-0.8-0.3-1.7-0.5-2.5c-0.6-0.1-1.5-0.3-2.1-0.3c-1.9-0.2-3.3-0.4-3.8-1.6
c-1.6-0.6-3.5-1.5-4-3.2c-0.2-0.7-0.1-1.4,0.3-2c-0.4-0.2-0.8-0.4-1-0.5c-0.3-0.2-0.6-0.3-0.8-0.4c-1.2-0.6-2-1.9-2-3.3
c0-0.7,0.3-1.4,0.7-2c-0.4-0.3-0.8-0.6-1.1-0.7c-0.6-0.4-0.9-0.6-1.1-0.8c-0.6-0.5-1-1-1.2-1.5c-0.1-0.4-0.2-0.7-0.3-1.1
c0-0.2,0-0.4,0-0.6c0.2-1.5,1.2-2.6,2.2-3.3c-0.5-0.4-1.1-0.9-1.5-1.2c-0.7-0.5-1-0.8-1.3-1.1c-1-1-1.6-2.5-1.4-3.9
c0.2-1.3,0.9-2.3,2-2.8c0,0,0,0,0,0l1.3-0.5c-0.5-0.6-1-1.3-1.4-1.7c-0.7-0.9-1.1-1.4-1.4-1.7c-2.1-2.2-3.6-5.5-2.2-7.5
c0.5-0.8,1.3-1.4,2.2-1.8c-0.3-1-0.5-2.1-0.6-3.1c0,0,0,0,0,0c-0.4-2.3-0.6-4.5-0.6-6.6c0-0.2,0-0.3,0-0.5c0-0.4,0-0.7,0-1.1
c0-0.2,0-0.5,0-0.7c0-0.3,0-0.6,0.1-0.9c0-0.3,0.1-0.6,0.1-0.9c0-0.2,0-0.4,0.1-0.6c0.1-0.5,0.1-1,0.2-1.5
c1.9-12.4,8.8-21.8,15.5-26.6c0.4-0.3,0.7-0.5,1.1-0.7c0.4-0.2,0.8-0.5,1.1-0.7c0.4-0.2,0.7-0.4,1.1-0.6c0.2-0.4,0.4-0.7,0.6-1.1
c0.7-1.2,1.4-2.5,2.2-3.7c2.2-3.7,5.3-7,8.9-10c0,0-0.1-0.1-0.1-0.1c-0.4-0.5-0.6-1-0.4-1.5c0.1-0.2,0.2-0.4,0.3-0.6
c1.4-1.5,3.1-2.7,5.1-3.7c0.1,0,0.1-0.1,0.2-0.1c0.8-0.4,1.6-0.8,2.4-1.2c0.5-0.2,1-0.4,1.4-0.6c0.4-0.2,0.8-0.3,1.2-0.5
c0.1,0,0.2-0.1,0.2-0.1c-0.1,0-0.3-0.1-0.6-0.1c-0.2,0-0.4-0.1-0.6-0.1c-0.9-0.3-1.7-0.8-2-1.5c-0.2-0.3-0.2-0.7-0.1-1
c0.1-0.4,0.4-0.8,0.9-1.1c1-0.5,2-1,3-1.4c1.5-0.7,3.1-1.3,4.7-1.9c-0.1,0-0.2,0-0.3,0c-1.3-0.1-2.4-0.7-2.8-1.6c0,0,0,0,0,0
c-0.4-0.9,0-1.8,1-2.2c0.1,0,0.2-0.1,0.3-0.1c3.8-1.6,6.9-2.1,9.4-2.6c-0.1-0.1-0.3-0.2-0.5-0.3c-1.1-0.4-1.9-1.1-2-2
c-0.1-0.8,0.6-1.5,1.7-1.8c3.3-0.7,6.2-0.9,9.2-1c-0.2-0.4-0.4-0.7-0.7-0.9c-0.9-0.6-1.3-1.3-1.1-2.1c0-0.1,0.1-0.2,0.2-0.4
c0.3-0.5,1-0.9,1.8-1c0.7-0.1,1.4-0.2,2.1-0.2c0.3,0,0.6,0,1-0.1c0.1,0,0.2,0,0.3,0c-0.2-0.2-0.4-0.5-0.4-0.8
c-0.2-0.9,0.7-1.6,2-1.8c0.7-0.1,1.5-0.2,2.3-0.4c0-0.1,0.1-0.1,0.1-0.2c0.1-0.1,0.1-0.2,0.2-0.2c-0.6-0.4-1-0.9-1-1.5
c0-0.7,0.6-1.2,1.6-1.5c1.8-0.4,3.4-0.6,4.9-0.7c-0.1-0.1-0.1-0.3-0.2-0.4c0-0.1,0-0.2,0-0.4c0,0,0-0.1,0-0.1
c0-0.1,0.1-0.2,0.1-0.3c0,0,0,0,0,0c0.1-0.2,0.3-0.4,0.6-0.6c0.1-0.1,0.2-0.1,0.4-0.2c0,0,0,0,0,0c0.1-0.1,0.3-0.1,0.4-0.1
c2-0.5,4.1-0.6,6.2-0.7c-0.1-0.2-0.1-0.5,0-0.7c0.2-0.7,1.1-1.3,2.4-1.3c1.8-0.1,3.7-0.1,5.6-0.1c0-0.2,0-0.4,0.1-0.6
c0.3-0.7,1.2-1.2,2.4-1.2c2.5-0.1,4.8,0.1,7.1,0.4c0-0.1,0-0.2,0.1-0.2c0.3-0.7,1.4-1.2,2.7-1.2c2.5,0,5.1,0.5,7.7,1.2
c0-0.1,0.1-0.1,0.2-0.2c0.6-0.6,1.8-1,3-0.8c2.9,0.3,5.4,1.3,7.4,2.1c0.2-0.2,0.4-0.5,0.8-0.6c0.5-0.2,1.1-0.4,1.7-0.4
c0.3,0,0.7,0,1,0.1c0,0,0,0,0,0c0.3,0.1,0.6,0.2,0.9,0.3c1.1,0.5,2.1,1,3.1,1.5c0.8,0,1.6,0,2.3,0.3c1,0.4,2,0.7,3,1.1
c0.1,0,0.2,0.1,0.4,0.1c1,0.4,1.9,0.8,2.9,1.3c0.6,0.3,1.3,0.6,1.9,1c0.1,0,0.1,0.1,0.2,0.1c0.2,0.1,0.4,0.2,0.5,0.3
c0.3,0.2,0.6,0.3,0.9,0.5c0.1,0.1,0.3,0.2,0.4,0.3c0.2,0.1,0.3,0.2,0.5,0.3c0.1,0.1,0.3,0.2,0.4,0.3c0.2,0.1,0.3,0.2,0.4,0.3
c0.2,0.2,0.5,0.3,0.7,0.5c0.1,0.1,0.2,0.1,0.3,0.2c0.4,0.3,0.8,0.6,1.1,1c0.6,0,1.1,0,1.7,0c0.3,0,0.5,0,0.8,0
c0.6,0,1.1,0.1,1.5,0.4c0.3,0.1,0.5,0.3,0.6,0.5c0.1,0.1,0.2,0.2,0.2,0.4c0.1,0.1,0.1,0.3,0.1,0.4c0,0.4-0.2,0.9-0.6,1.3
c-0.1,0.1-0.3,0.3-0.5,0.4c-0.4,0.2-0.6,0.4-0.8,0.6c0,0,0,0,0,0c1.9-0.1,3.9-0.1,5.9,0c0.3,0,0.6,0,1,0.1
c0.7,0.1,1.4,0.1,2.1,0.2c0.8,0.1,1.5,0.5,1.8,1c0.1,0.1,0.1,0.2,0.2,0.4c0.2,0.7-0.2,1.5-1.1,2.1c-0.3,0.2-0.5,0.4-0.7,0.9
c3,0.1,5.9,0.3,9.2,1c1.1,0.2,1.8,0.9,1.7,1.8c-0.1,0.8-0.8,1.6-2,2c-0.2,0.1-0.4,0.2-0.5,0.3c2.5,0.4,5.6,1,9.4,2.6
c0.1,0,0.2,0.1,0.3,0.1c1,0.4,1.4,1.3,1,2.2c0,0,0,0,0,0c-0.4,0.9-1.6,1.5-2.8,1.6c-0.1,0-0.2,0-0.3,0c1.6,0.5,3.1,1.2,4.7,1.9
c1,0.5,2,0.9,3,1.4c0.5,0.3,0.8,0.7,0.9,1.1c0.1,0.3,0,0.6-0.1,1c-0.3,0.7-1.1,1.2-2,1.5c-0.2,0.1-0.4,0.1-0.6,0.1
c-0.3,0-0.4,0.1-0.6,0.1c0.1,0,0.2,0.1,0.2,0.1c0.4,0.2,0.8,0.3,1.2,0.5c0.5,0.2,1,0.4,1.4,0.6c0.8,0.4,1.6,0.7,2.4,1.2
c0.1,0,0.1,0.1,0.2,0.1c1.9,1,3.7,2.3,5.1,3.7c0.2,0.2,0.3,0.4,0.3,0.6c0.1,0.5,0,1-0.4,1.5c0,0-0.1,0.1-0.1,0.1
c3.7,3.1,6.8,6.4,8.9,10c0.7,1.2,1.4,2.5,2.2,3.7c0.2,0.4,0.4,0.7,0.6,1.1c0.4,0.2,0.7,0.4,1.1,0.6c0.4,0.2,0.8,0.4,1.1,0.7
c0.4,0.2,0.7,0.5,1.1,0.7h0C260.7,130.1,267.6,139.5,269.5,151.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

BIN
doc/logo/redpanda-rgb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

193
doc/logo/redpanda-rgb.svg Normal file
View File

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 320 320" style="enable-background:new 0 0 320 320;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;fill:#BCBEC0;}
.st2{fill:none;stroke:#231F20;stroke-miterlimit:10;}
.st3{fill:#231F20;}
.st4{fill:#080505;}
.st5{fill:#FFFFFF;}
.st6{fill:#CC6600;}
</style>
<g id="BG" class="st0">
<rect x="0" y="0" class="st1" width="320" height="320"/>
<line class="st2" x1="160" y1="-0.5" x2="160" y2="339.5"/>
</g>
<g id="line" class="st0">
</g>
<g id="Layer_5" class="st0">
</g>
<g id="body">
<path class="st3" d="M259.9,120l-2.2-3.9c0.1-28-12.7-39.4-27.6-48H203c-0.4-0.5-0.8-1-1.3-1.4c-0.7-0.7-1.8-0.8-2.7-0.4
c-0.2,0.1-0.4,0.2-0.6,0.4c-1.1-0.9-2.2-1.8-3.3-2.5c-0.9-0.6-2.1-0.5-2.9,0.1c-0.2,0.1-0.3,0.3-0.5,0.4c-0.9-0.6-1.9-1.1-2.9-1.6
c-0.1-0.1-0.2-0.1-0.3-0.1l-0.6,5.2H160H89.8c-14.9,8.7-27.6,20.1-27.6,48l-2.2,3.9C43,130.4,27.7,163.8,51.7,191
c1.6,8.5,4.2,14.6,6.5,21.4c3.5,27.2,26.4,40,32.4,41.5c8.8,6.7,18.2,13.1,31,17.6c12,12.4,25,17.1,38.1,17.1c0.1,0,0.2,0,0.3,0
s0.2,0,0.3,0c13.1,0,26.1-4.7,38.1-17.1c12.7-4.5,22.1-10.9,31-17.6c6-1.5,28.9-14.3,32.4-41.5c2.3-6.8,5-12.9,6.5-21.4
C292.3,163.8,277,130.4,259.9,120z"/>
<path class="st4" d="M290.8,81.5c1.5-5,0.9-9.2-0.3-12.4c-0.1-1.5-0.3-2.9-0.8-4.3c0-0.7,0-1.3,0-1.9c0.4-4.5-0.8-9-3.4-12.7
c-0.5-3.3-1.8-6.3-3.9-8.8c-0.9-1.3-2-2.5-3.1-3.6c-0.1-0.1-0.3-0.3-0.5-0.4c-1.8-5.2-5.5-9.3-10.5-11.6c-2.6-1.2-5.5-1.8-8.5-1.8
c-3,0-6,0.6-9,1.8c-1.5-0.3-3-0.4-4.6-0.4c-4.2,0-8.6,1-13.1,3c-0.7-0.1-1.5-0.1-2.3-0.1c-3.3,0-6.6,0.8-10.2,2.5c-0.3,0-0.7,0-1,0
c-5.4,0-10.5,1.8-15.2,5.3c-2.4,0.2-4.7,0.7-6.8,1.6l0,0h0c-4.1,1.7-6.7,4.4-8.5,6.4c-6.7,1.9-9.9,5.4-11.8,8
c-2.4,0.9-4.5,2.1-6.3,3.6c-1.7-0.5-3.6-1-5.7-1.2c-0.5-0.1-1-0.1-1.5-0.1c-1.3,0-2.6,0.2-3.8,0.6c-1.9-0.4-4.1-0.7-6.3-0.7l-0.1,0
c-1.9,0-3.6,0.4-5.1,1.1c-1.7-1.3-3.7-2.4-5.9-3.3c-1.9-2.6-5.1-6.1-11.8-8c-1.8-2-4.5-4.7-8.5-6.4h0l0,0c-2.1-0.9-4.4-1.5-6.8-1.6
c-4.7-3.5-9.8-5.3-15.2-5.3c-0.3,0-0.7,0-1,0c-3.5-1.7-6.9-2.5-10.2-2.5c-0.8,0-1.5,0-2.3,0.1c-4.5-2-8.9-3-13.1-3
c-1.6,0-3.1,0.1-4.6,0.4c-3-1.2-6.1-1.8-9-1.8c-3,0-5.8,0.6-8.5,1.8c-5,2.2-8.7,6.4-10.5,11.6c-0.2,0.1-0.3,0.3-0.5,0.4
c-1.2,1.1-2.2,2.3-3.1,3.6c-2.1,2.5-3.4,5.5-3.9,8.8c-2.6,3.8-3.8,8.2-3.4,12.7c0,0.6,0,1.3,0,1.9c-0.4,1.4-0.7,2.9-0.8,4.3
c-1.1,3.1-1.8,7.4-0.3,12.4c-1.5,5.2-0.7,10.9,2.4,16.9c-0.6,5.8,1.3,11.2,5.6,16.1c0.7,8.3,7,13.4,10.5,16.3l2,0.9
c-3.3,5.3-5.9,11.7-7,19.1c-0.6,4.3-0.7,8.6-0.2,12.8c-0.3,0.3-0.5,0.7-0.7,1c-2.6,4-1.9,9.4,1.7,14.1c-0.5,1-0.8,2.1-1,3.2
c-0.4,3,0.4,6.1,2.3,8.5c-0.1,0.5-0.2,1-0.3,1.6c-0.3,3,0.7,6,2.9,8.2c0.1,3,1.5,5.7,3.8,7.5c0.9,3.8,3.7,5.8,6.2,7
c1.4,1.3,3.1,2,4.7,2.4c0.4,1.8,1,3.6,1.6,5.3c0.1,0.4,0.2,0.7,0.2,0.7l0.1,0.4c0.5,1.4,1.2,2.9,1.9,4.4c2.9,6,6.9,11.4,11.8,16.1
c4,4,10,9.1,17,11.5c2.4,1.9,4.7,3.6,6.4,4.7c2.7,1.7,4.2,2.6,5.5,3.1c0,0,0,0,0.1,0c6.1,3.8,12.1,6.7,18.6,9
c10.6,10.6,22.2,16,34.5,16c0.1,0,0.3,0,0.4,0c0.1,0,0.3,0,0.4,0c12.3,0,23.9-5.4,34.5-16c6.5-2.3,12.4-5.2,18.6-9c0,0,0,0,0.1,0
c1.2-0.5,2.8-1.3,5.5-3.1c1.7-1.1,4.1-2.7,6.4-4.7c6.9-2.4,13-7.4,17-11.5c4.9-4.7,8.9-10.1,11.8-16.1c0.8-1.5,1.4-3,1.9-4.4l0,0
c0.1-0.2,0.2-0.4,0.2-0.6l0.1-0.4c0.6-1.7,1.1-3.5,1.6-5.3c1.5-0.4,3.3-1,4.7-2.4c2.5-1.2,5.2-3.2,6.2-7c2.3-1.8,3.7-4.6,3.8-7.5
c2.2-2.3,3.3-5.2,2.9-8.2c-0.1-0.5-0.2-1-0.3-1.6c1.8-2.4,2.7-5.5,2.3-8.5c-0.2-1.1-0.5-2.2-1-3.2c3.6-4.8,4.3-10.1,1.7-14.1
c-0.2-0.4-0.5-0.7-0.7-1c0.5-4.2,0.4-8.5-0.2-12.8c-1.1-7.4-3.7-13.8-7-19.1l2-0.9c3.6-2.9,9.8-8,10.5-16.3
c4.3-4.9,6.1-10.3,5.6-16.1C291.6,92.4,292.4,86.7,290.8,81.5z"/>
<g>
<g>
<g>
<path class="st5" d="M278.6,53.2c0-2.8-0.8-5.2-2.5-7.1c-0.6-0.9-1.3-1.7-2.1-2.4c-0.6-0.6-1.4-1.1-2.1-1.6
c-0.7-4.1-3.1-7.4-6.7-9.1c-3.9-1.8-8.7-1.4-13.6,1.1c-5-1.7-10.8-0.9-17.3,2.5c-3-0.9-6.6-0.8-12,2.2c-6.7-1-11.5,2.1-14.9,5.1
c-2.4-0.2-4.6,0.1-6.6,1l0,0c-2.9,1.2-4.7,3.2-6.3,5c-0.4,0.4-0.8,0.9-1.1,1.2c-6.6,1.3-8.8,4.3-10.3,6.5
c-0.2,0.4-0.5,0.7-0.7,1c-8.5,2.4-10.1,7.4-11.5,11.7c-0.2,0.5-0.3,0.9-0.5,1.4l1.4,3.7c83,63,89.3,48.5,91.4,49.5l4-0.5
c3.6-2.9,8.4-6.8,7.6-13.3c6-5.5,6.3-10.3,5.3-14.3c1.9-3,5.3-9.3,2.2-15.4c1.8-3.9,1.9-7.5,0.3-10.8c0.1-1.7-0.2-3.3-0.9-4.9
c0.1-1.1,0.1-2.2,0.1-3.2C282.2,59.2,281.1,55.8,278.6,53.2z"/>
<path class="st3" d="M224.9,81.4c0.4,0.1,0.9,0.2,1.3,0.3c1.1,0.3,2,1,2.7,2c0.4,0.3,0.8,0.5,1.3,0.8c0.6,0.4,1.2,0.8,1.8,1.2
c0.6,0.4,0.9,1,1,1.8c0.6,0.2,1.2,0.4,1.9,0.6l0.6,0.2c0.8,0.3,1.5,0.8,2.1,1.5c0.3,0.4,0.6,0.9,0.8,1.5c0.1,0.3,0.2,0.7,0.2,1
c0.1,0.3,0.1,0.7,0,1.1c0,0.2,0,0.4-0.1,0.7c0.4,0.2,0.9,0.3,1.3,0.5c0.2,0.1,0.5,0.2,0.7,0.3c0.5,0.2,1.1,0.5,1.6,0.8
c1.2,0.6,2.1,1.7,2.4,3.1c0.1,0.3,0.1,0.6,0.2,0.9c0,0.3,0,0.7,0,1c1.1,0.6,1.7,1.3,2.3,1.9c0.4,0.5,0.9,1,1.7,1.5
c1.2,0.8,1.9,2.1,2.1,3.5c0.1,0,0.1,0.1,0.2,0.1c-0.1-0.3-0.2-0.7-0.3-1c1.2-1.3,2.3-2.7,3.2-4.5c0.6-1.1,0.5-2.6-0.1-3.7
c-0.1-0.1-0.2-0.2-0.2-0.4c0.7-1.2,1.4-2.4,2-3.7c0.6-1.2,0.4-2.8-0.4-3.9c-0.1-0.2-0.3-0.3-0.4-0.5c0.7-1.4,1.3-3,1.6-4.7
c0-0.2,0.1-0.4,0.1-0.6c0-1.1-0.4-2.3-1.3-3c0,0,0,0,0,0c0,0,0,0,0,0c0.4-1,0.7-2.3,1-3.7c0.2-1.1-0.1-2.2-0.7-3l0.7-0.7
c0.3-0.3,0.6-0.8,0.7-1.2c0.1-0.4,0.2-0.8,0.4-1.1c0.1-0.4,0.2-0.7,0.2-1.1c0-0.8-0.2-1.6-0.7-2.3c-0.1-0.1-0.2-0.3-0.3-0.4
c-1.1-0.1-4.6-0.5-4.6-0.5c0.1,0,0.3-0.1,0.4-0.1c-0.3,0-0.5-0.1-0.5-0.1c-0.4-1-1.3-1.8-2.3-1.9c-1.6-0.3-3.2,0-4.5,0.4
c0-0.1-0.1-0.2-0.1-0.2c-0.8-1.2-2.1-1.7-3.3-1.3c-0.6,0.2-0.7-0.3-1.2-0.1c-0.1-0.1-0.6,0.6-0.7,0.4c-0.8-1.1-2.1-1.5-3.3-0.9
c-1.1,0.5-2,1-2.8,1.5c0,0-0.1-0.1-0.1-0.1c-1-1-2.4-1.2-3.5-0.4c-1,0.7-1.8,1.5-2.5,2.3c0,0,0,0-0.1-0.1
c-1.1-0.8-2.6-0.7-3.5,0.3c-0.6,0.6-1.1,1.3-1.6,2c-0.2-0.1-0.4-0.2-0.6-0.3c-1.1-0.4-2.3,0.1-3,1.2c-0.8,1.3-1.4,2.5-2,3.7
c-0.1,0-0.2-0.1-0.4-0.1c-1.1-0.2-2.2,0.4-2.8,1.5c-0.1,0.1-0.1,0.3-0.2,0.4c3.9,1.6,7.7,3.4,11.2,5.3L224.9,81.4z"/>
</g>
<g>
<path class="st5" d="M41.4,53.2c0-2.8,0.8-5.2,2.5-7.1c0.6-0.9,1.3-1.7,2.1-2.4c0.6-0.6,1.4-1.1,2.1-1.6
c0.7-4.1,3.1-7.4,6.7-9.1c3.9-1.8,8.7-1.4,13.6,1.1c5-1.7,10.8-0.9,17.3,2.5c3-0.9,6.6-0.8,12,2.2c6.7-1,11.5,2.1,14.9,5.1
c2.4-0.2,4.6,0.1,6.6,1l0,0c2.9,1.2,4.7,3.2,6.3,5c0.4,0.4,0.8,0.9,1.1,1.2c6.6,1.3,8.8,4.3,10.3,6.5c0.2,0.4,0.5,0.7,0.7,1
c8.5,2.4,10.1,7.4,11.5,11.7c0.2,0.5,0.3,0.9,0.5,1.4l-1.4,3.7c-83,63-89.3,48.5-91.4,49.5l-4-0.5c-3.6-2.9-8.4-6.8-7.6-13.3
c-6-5.5-6.3-10.3-5.3-14.3c-1.9-3-5.3-9.3-2.2-15.4c-1.8-3.9-1.9-7.5-0.3-10.8c-0.1-1.7,0.2-3.3,0.9-4.9
c-0.1-1.1-0.1-2.2-0.1-3.2C37.8,59.2,38.9,55.8,41.4,53.2z"/>
<path class="st3" d="M95.1,81c-0.4,0.1-0.9,0.2-1.3,0.3c-1.1,0.3-2,1-2.7,2c-0.4,0.3-0.8,0.5-1.3,0.8c-0.6,0.4-1.2,0.8-1.8,1.2
c-0.6,0.4-0.9,1-1,1.8c-0.6,0.2-1.2,0.4-1.9,0.6l-0.6,0.2c-0.8,0.3-1.5,0.8-2.1,1.5c-0.3,0.4-0.6,0.9-0.8,1.5
c-0.1,0.3-0.2,0.7-0.2,1c-0.1,0.3-0.1,0.7,0,1.1c0,0.2,0,0.4,0.1,0.7c-0.4,0.2-0.9,0.3-1.3,0.5c-0.2,0.1-0.5,0.2-0.7,0.3
c-0.5,0.2-1.1,0.5-1.6,0.8c-1.2,0.6-2.1,1.7-2.4,3.1c-0.1,0.3-0.1,0.6-0.2,0.9c0,0.3,0,0.7,0,1c-1.1,0.6-1.7,1.3-2.3,1.9
c-0.4,0.5-0.9,1-1.7,1.5c-1.2,0.8-1.9,2.1-2.1,3.5c-0.1,0-0.1,0.1-0.2,0.1c0.1-0.3,0.2-0.7,0.3-1c-1.2-1.3-2.3-2.7-3.2-4.5
c-0.6-1.1-0.5-2.6,0.1-3.7c0.1-0.1,0.2-0.2,0.2-0.4c-0.7-1.2-1.4-2.4-2-3.7c-0.6-1.2-0.4-2.8,0.4-3.9c0.1-0.2,0.3-0.3,0.4-0.5
c-0.7-1.4-1.3-3-1.6-4.7c0-0.2-0.1-0.4-0.1-0.6c0-1.1,0.4-2.3,1.3-3c0,0,0,0,0,0c0,0,0,0,0,0c-0.4-1-0.7-2.3-1-3.7
c-0.2-1.1,0.1-2.2,0.7-3L63.8,74c-0.3-0.3-0.6-0.8-0.7-1.2c-0.1-0.4-0.2-0.8-0.4-1.1c-0.1-0.4-0.2-0.7-0.2-1.1
c0-0.8,0.2-1.6,0.7-2.3c0.1-0.1,0.2-0.3,0.3-0.4c1.1-0.1,4.6-0.5,4.6-0.5c-0.1,0-0.3-0.1-0.4-0.1c0.3,0,0.5-0.1,0.5-0.1
c0.4-1,1.3-1.8,2.3-1.9c1.6-0.3,3.2,0,4.5,0.4c0-0.1,0.1-0.2,0.1-0.2c0.8-1.2,2.1-1.7,3.3-1.3c0.6,0.2,0.7-0.3,1.2-0.1
c0.1-0.1,0.6,0.6,0.7,0.4c0.8-1.1,2.1-1.5,3.3-0.9c1.1,0.5,2,1,2.8,1.5c0,0,0.1-0.1,0.1-0.1c1-1,2.4-1.2,3.5-0.4
c1,0.7,1.8,1.5,2.5,2.3c0,0,0,0,0.1-0.1c1.1-0.8,2.6-0.7,3.5,0.3c0.6,0.6,1.1,1.3,1.6,2c0.2-0.1,0.4-0.2,0.6-0.3
c1.1-0.4,2.3,0.1,3,1.2c0.8,1.3,1.4,2.5,2,3.7c0.1,0,0.2-0.1,0.4-0.1c1.1-0.2,2.2,0.4,2.8,1.5c0.1,0.1,0.1,0.3,0.2,0.4
c-3.9,1.6-7.7,3.4-11.2,5.3L95.1,81z"/>
</g>
</g>
<path class="st6" d="M269.5,151.9c-2.1-13.7-10.4-23.9-17.8-28c-0.4-0.2-0.7-0.4-1.1-0.6c-0.2-0.4-0.4-0.7-0.6-1.1
c-0.7-1.2-1.4-2.5-2.2-3.7c-2.2-3.7-5.3-7-8.9-10c0,0,0.1-0.1,0.1-0.1c0.4-0.5,0.6-1,0.4-1.5c-0.1-0.2-0.2-0.4-0.3-0.6
c-1.4-1.5-3.1-2.7-5.1-3.7c-0.1,0-0.1-0.1-0.2-0.1c-0.8-0.4-1.6-0.8-2.4-1.2c-0.5-0.2-1-0.4-1.4-0.6c-0.4-0.2-0.8-0.3-1.2-0.5
c-0.1,0-0.2-0.1-0.2-0.1c0.1,0,0.3-0.1,0.6-0.1c0.2,0,0.4-0.1,0.6-0.1c0.9-0.3,1.7-0.8,2-1.5c0.2-0.3,0.2-0.7,0.1-1
c-0.1-0.4-0.4-0.8-0.9-1.1c-1-0.5-2-1-3-1.4c-1.5-0.7-3.1-1.3-4.7-1.9c0.1,0,0.2,0,0.3,0c1.3-0.1,2.4-0.7,2.8-1.6c0,0,0,0,0,0
c0.4-0.9,0-1.8-1-2.2c-0.1,0-0.2-0.1-0.3-0.1c-3.8-1.6-6.9-2.1-9.4-2.6c0.1-0.1,0.3-0.2,0.5-0.3c1.1-0.4,1.9-1.1,2-2
c0.1-0.8-0.6-1.5-1.7-1.8c-3.3-0.7-6.2-0.9-9.2-1c0.2-0.4,0.4-0.7,0.7-0.9c0.9-0.6,1.3-1.4,1.1-2.1c0-0.1-0.1-0.2-0.2-0.4
c-0.3-0.5-1-0.9-1.8-1c-0.7-0.1-1.4-0.2-2.1-0.2c-0.3,0-0.6,0-1-0.1c-2-0.1-3.9-0.1-5.9,0c0,0,0,0,0,0c0.1-0.2,0.4-0.4,0.8-0.6
c0.2-0.1,0.4-0.3,0.5-0.4c0.4-0.4,0.6-0.8,0.6-1.3c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.1-0.3-0.2-0.4c-0.2-0.2-0.4-0.4-0.6-0.5
c-0.4-0.2-0.9-0.4-1.5-0.4c-0.3,0-0.5,0-0.8,0c-0.6,0-1.1,0-1.7,0c-3.2-2.9-8.1-5.4-13.5-7.3c-0.7-0.2-1.5-0.3-2.3-0.3
c-1-0.5-2-1-3.1-1.5c-1.1-0.5-2.6-0.5-3.6,0c-0.4,0.2-0.6,0.4-0.8,0.6c-2-0.9-4.5-1.8-7.4-2.1c-1.2-0.1-2.4,0.2-3,0.8
c-0.1,0.1-0.1,0.1-0.2,0.2c-2.6-0.6-5.2-1.1-7.7-1.2c-1.3,0-2.3,0.5-2.7,1.2c0,0.1-0.1,0.2-0.1,0.2c-2.2-0.3-4.6-0.5-7.1-0.4
c-1.2,0-2.1,0.5-2.4,1.2c-0.1,0.2-0.1,0.4-0.1,0.6c-1.9-0.1-3.8,0-5.6,0.1c-1.2,0.1-2.2,0.6-2.4,1.3c-0.1,0.2,0,0.5,0,0.7
c-2.1,0-4.2,0.2-6.2,0.7c-1.1,0.3-1.7,0.9-1.6,1.7c0,0.1,0.1,0.3,0.2,0.4c-1.5,0.1-3.1,0.2-4.9,0.7c-0.9,0.2-1.5,0.8-1.6,1.5
c0,0.5,0.4,1.1,1,1.5c-0.1,0.1-0.2,0.1-0.2,0.2c0,0.1-0.1,0.1-0.1,0.2c-0.8,0.2-1.6,0.3-2.3,0.4c-1.3,0.2-2.1,0.9-2,1.8
c0.1,0.3,0.2,0.5,0.4,0.8c-0.1,0-0.2,0-0.3,0c-0.3,0-0.6,0-1,0.1c-0.7,0.1-1.4,0.1-2.1,0.2c-0.8,0.1-1.5,0.5-1.8,1
c-0.1,0.1-0.1,0.2-0.2,0.4c-0.2,0.7,0.2,1.5,1.1,2.1c0.3,0.2,0.5,0.4,0.7,0.9c-3,0.1-5.9,0.3-9.2,1c-1.1,0.2-1.8,0.9-1.7,1.8
c0.1,0.8,0.8,1.6,2,2c0.2,0.1,0.4,0.2,0.5,0.3c-2.5,0.4-5.6,1-9.4,2.6c-0.1,0-0.2,0.1-0.3,0.1c-1,0.4-1.4,1.3-1,2.2c0,0,0,0,0,0
c0.4,0.9,1.6,1.5,2.8,1.6c0.1,0,0.2,0,0.3,0c-1.6,0.5-3.1,1.2-4.7,1.9c-1,0.5-2,0.9-3,1.4c-0.5,0.3-0.8,0.7-0.9,1.1
c-0.1,0.3,0,0.6,0.1,1c0.3,0.7,1.1,1.2,2,1.5c0.2,0.1,0.4,0.1,0.6,0.1c0.3,0,0.4,0.1,0.6,0.1c-0.1,0-0.2,0.1-0.2,0.1
c-0.4,0.2-0.8,0.3-1.2,0.5c-0.5,0.2-1,0.4-1.4,0.6c-0.8,0.4-1.6,0.7-2.4,1.2c-0.1,0-0.1,0.1-0.2,0.1c-1.9,1-3.7,2.3-5.1,3.7
c-0.2,0.2-0.3,0.4-0.3,0.6c-0.1,0.5,0,1,0.4,1.5c0,0,0.1,0.1,0.1,0.1c-3.7,3.1-6.8,6.4-8.9,10c-0.7,1.2-1.4,2.5-2.2,3.7
c-0.2,0.4-0.4,0.7-0.6,1.1c-0.4,0.2-0.7,0.4-1.1,0.6c-7.3,4.1-15.7,14.2-17.8,28c-1.3,8.5-0.5,21.5,10.6,34.4
c0.3,0.4,0.6,0.7,0.9,1.1c0.1,0.5,0.2,0.9,0.2,1.4c1.1,6.3,2.9,11.1,4.8,16.3c0.5,1.4,1,2.9,1.5,4.3c0.1,0.2,0.1,0.3,0.2,0.5
c0,0.2,0,0.3,0.1,0.5c3.2,25.2,24.6,36.2,28.4,37.1c0.3,0.1,0.7,0.2,1,0.3c0.3,0.2,0.5,0.4,0.8,0.6c9.4,7.1,17.9,12.6,29.4,16.6
c0.4,0.1,0.7,0.3,1.1,0.4c0.3,0.3,0.5,0.5,0.8,0.8c8.5,8.6,18.5,14.2,29.8,14.1c11.3,0.1,21.3-5.5,29.8-14.1
c0.3-0.3,0.5-0.5,0.8-0.8c0.4-0.1,0.7-0.3,1.1-0.4c11.4-4,20-9.5,29.4-16.6c0.3-0.2,0.5-0.4,0.8-0.6c0.3-0.1,0.7-0.2,1-0.3
c3.8-0.9,25.2-11.9,28.4-37.1c0-0.2,0-0.3,0.1-0.5c0.1-0.2,0.1-0.3,0.2-0.5c0.5-1.5,1-2.9,1.5-4.3c1.9-5.1,3.6-10,4.8-16.3
c0.1-0.5,0.2-0.9,0.2-1.4c0.3-0.4,0.6-0.7,0.9-1.1C270,173.4,270.8,160.4,269.5,151.9z"/>
<g>
<path class="st5" d="M268.5,181.4l-3-1.2c0-0.8,3.4-4.5,3.9-5.2c1.7-1.8,3.2-4.6,2.2-6.1c-2.6-4.5-14.2,1.6-23.9,8
c0.8-1.8,1.7-4.8-0.6-6.1c-4.5-2.6-16.5,7.4-17.9,8.6c-7.6,6.5-14.5,15-12.9,20.9c0.4,1.4,0.9,2.8,1.2,4.2
c0.1,0.6,0.3,1.2,0.4,1.7c1.3,4.2,2,8.6,1.9,13c-0.2,11,0.2,21.5-9.3,33.2c-2.9,3.4-3.2,4.9,0.3,3.3c0.5,0,6.3-3.5,10.8-7.4
c10.6-2.8,23.2-16.9,27.1-27.6c0,0,2.2-7.2,2.2-9.9c0-1.7,7.8-0.9,6-2.5c1.9-0.6,6.2-1.9,3.2-4.8c-0.3-0.2,3.3-1.8,3.3-1.8
c1.6-0.8,1.6-3.3-0.1-4c-0.4-0.5,3.1-2.6,3.3-2.9c2.3-1.9,0.3-4.1-1.7-5.2c-0.7-0.9,3.3-3.3,3.7-3.9
C270.1,184.6,270.1,182.1,268.5,181.4z"/>
<path class="st5" d="M51.5,181.4l3-1.2c0-0.8-3.4-4.5-3.9-5.2c-1.7-1.8-3.2-4.6-2.2-6.1c2.6-4.5,14.2,1.6,23.9,8
c-0.8-1.8-1.7-4.8,0.6-6.1c4.5-2.6,16.5,7.4,17.9,8.6c7.6,6.5,14.5,15,12.9,20.9c-0.4,1.4-0.9,2.8-1.2,4.2
c-0.1,0.6-0.3,1.2-0.4,1.7c-1.3,4.2-2,8.6-1.9,13c0.2,11-0.2,21.5,9.3,33.2c2.9,3.4,3.2,4.9-0.3,3.3c-0.5,0-6.3-3.5-10.8-7.4
c-10.6-2.8-23.2-16.9-27.1-27.6c0,0-2.2-7.2-2.2-9.9c0-1.7-7.8-0.9-6-2.5c-1.9-0.6-6.2-1.9-3.2-4.8c0.3-0.2-3.3-1.8-3.3-1.8
c-1.6-0.8-1.6-3.3,0.1-4c0.4-0.5-3.1-2.6-3.3-2.9c-2.3-1.9-0.3-4.1,1.7-5.2c0.7-0.9-3.3-3.3-3.7-3.9
C49.9,184.6,49.9,182.1,51.5,181.4z"/>
</g>
<g>
<path class="st5" d="M243.5,148.9L243.5,148.9l-0.2-0.1c-0.3,0-0.5-0.1-0.8-0.1c-0.2,0-0.3-0.1-0.4-0.2c-0.1-0.2-0.1-0.3-0.1-0.5
c0.2-0.4,0.5-0.8,0.9-1c0.6-0.3,1-0.9,0.9-1.5c-0.1-0.6-0.5-1.1-1.2-1.2c-3-0.7-5.6-0.7-8.2-0.8c-0.2,0-0.3-0.1-0.4-0.2
c-0.1-0.1-0.2-0.3-0.2-0.5c0.1-0.6,0.2-1.2,0.7-1.7c0.5-0.5,0.6-1.1,0.4-1.6c0,0,0-0.1,0-0.1c-0.2-0.4-0.7-0.7-1.2-0.7
c-0.3,0-0.7-0.1-1-0.1c-2.4-0.2-4.7-0.1-6.9,0.2c-0.2,0-0.4-0.1-0.5-0.1c-0.2-0.1-0.2-0.3-0.2-0.5c0.1-0.5,0.4-1,0.9-1.4
c0.5-0.5,0.6-1.1,0.3-1.7c-0.3-0.5-0.8-0.8-1.5-0.8c-2.7,0.1-5.2,0.4-7.7,0.7c-0.8,0.1-1.5,0.2-2.3,0.3c-0.3,0-0.4-0.1-0.5-0.2
c-0.1-0.1-0.2-0.4-0.1-0.7c0.1-0.3,0.3-0.5,0.5-0.9c0.3-0.5,0.3-1.1-0.1-1.6c-0.3-0.4-0.9-0.6-1.4-0.5
c-4.8,0.4-11.2,1.3-15.9,4.1c-1.4,0.8-2.9,1.5-4.4,2.2c-1.2,0.6-2.4,1.3-3.6,2.2c-0.8,0.6-1.5,1.2-2.2,1.7l-0.4,0.4
c-0.9,0.8-1.9,1.8-2.9,2.8c-1.7,1.7-3.3,3.7-5,5.9c-0.5,0.6-1,1.3-1.4,1.9c-0.4,0.6-0.9,1.2-1.3,1.8c-0.6,0.9-1.2,1.8-1.8,2.7
c-2.4,3.8-6.4,10.9-5.9,15.6c0.2,1.7,0.9,3,2.2,3.9c1.1,0.7,2.4,1.1,4,1.1c1,0,2.2-0.2,3.5-0.5c0.4-0.1,0.7-0.2,1.1-0.3
c0.3-0.1,0.6-0.2,0.9-0.3c0.3-0.1,0.6-0.2,0.9-0.3c0.5-0.2,0.9-0.4,1.4-0.6c1.1,3.4,4.3,6.3,8.8,8c0.6,0.2,1.2,0.4,1.9,0.6
c0.4,0.1,0.8,0.2,1.3,0.3c0.5,0.1,0.9,0.2,1.4,0.3c1.2,0.2,2.4,0.3,3.6,0.3c0.3,0,0.7,0,1,0c0.9,0,1.8-0.2,2.6-0.4l0.1,0
c0.1,0,0.2-0.1,0.3-0.1c0.6-0.2,1.2-0.4,1.9-0.7c2.6-1.1,4.7-3.1,6-5.7c1.4-2.8,1.8-6.1,1.1-9.3c-0.1-0.4-0.2-0.9-0.4-1.3
c-0.2-0.6-0.4-1.2-0.7-1.8c1.7-0.7,3.5-1.7,5.1-3c1.3-1,2.4-2.1,3.4-3.2c0.4-0.5,1-0.8,1.8-0.9c0.7-0.1,1.5-0.2,2.2-0.4
c0.9-0.2,1.8-0.4,2.7-0.5c0.4-0.1,0.9-0.2,1.3-0.3c0.7-0.1,1.3-0.3,1.9-0.5c0.8-0.2,1.7-0.4,2.5-0.6c0.8-0.2,1.6-0.5,2.4-0.7
c0.8-0.3,1.6-0.5,2.3-0.8c0.6-0.2,1.1-0.4,1.7-0.6c0.5-0.2,1.1-0.4,1.5-0.7c0.6-0.3,1.2-0.6,1.7-0.9c0.6-0.3,1.1-0.7,1.6-1
c0.6-0.5,1-0.9,1.2-1.3C244.5,150,244.2,149.3,243.5,148.9z"/>
<path d="M206.5,170.2c-0.1-0.3-0.1-0.6-0.2-0.8c-0.7-2.3-2.2-4.2-4.2-5.3c-1.3-0.8-2.7-1.2-4.1-1.2c-0.7-0.3-1.5-0.5-2.3-0.5
c-2.8,0-5.1,1.9-5.6,4.5c0,0-0.1,0.1-0.1,0.1c-0.1,0.2-0.3,0.3-0.4,0.5c-1.8,2.3-2.5,4.7-1.8,6.7c0.6,2,2.6,3.7,5.5,4.8
c0.4,0.2,0.8,0.3,1.2,0.4c0.3,0.1,0.6,0.2,0.9,0.2c0.3,0.1,0.6,0.1,0.9,0.2c1.1,0.2,2.1,0.2,3.1,0.2c0.6,0,1.1-0.1,1.6-0.2
c0.1,0,0.2,0,0.2-0.1c0.4-0.1,0.8-0.2,1.1-0.4c1.5-0.7,2.7-1.8,3.5-3.4C206.7,174.2,206.9,172.2,206.5,170.2z"/>
<ellipse class="st5" cx="195.7" cy="167.9" rx="3.6" ry="3.4"/>
<path class="st5" d="M75.8,150.6c0.2,0.4,0.6,0.9,1.2,1.3c0.4,0.3,0.9,0.7,1.6,1c0.5,0.3,1.1,0.6,1.7,0.9c0.5,0.2,1,0.4,1.5,0.7
c0.5,0.2,1.1,0.4,1.7,0.6c0.7,0.3,1.5,0.5,2.3,0.8c0.8,0.2,1.6,0.5,2.4,0.7c0.8,0.2,1.6,0.4,2.5,0.6c0.6,0.2,1.3,0.3,1.9,0.5
c0.4,0.1,0.9,0.2,1.3,0.3c0.9,0.2,1.8,0.4,2.7,0.5c0.7,0.1,1.5,0.3,2.2,0.4c0.7,0.1,1.3,0.4,1.8,0.9c1,1.1,2.1,2.2,3.4,3.2
c1.6,1.3,3.3,2.2,5.1,3c-0.3,0.6-0.5,1.2-0.7,1.8c-0.1,0.4-0.3,0.9-0.4,1.3c-0.7,3.2-0.3,6.5,1.1,9.3c1.3,2.6,3.4,4.5,6,5.7
c0.7,0.3,1.3,0.5,1.9,0.7c0.1,0,0.2,0,0.3,0.1l0.1,0c0.8,0.2,1.7,0.3,2.6,0.4c0.3,0,0.7,0,1,0c1.2,0,2.4-0.1,3.6-0.3
c0.5-0.1,0.9-0.2,1.4-0.3c0.4-0.1,0.8-0.2,1.3-0.3c0.7-0.2,1.3-0.4,1.9-0.6c4.5-1.7,7.7-4.6,8.8-8c0.5,0.2,0.9,0.4,1.4,0.6
c0.3,0.1,0.6,0.2,0.9,0.3c0.3,0.1,0.6,0.2,0.9,0.3c0.4,0.1,0.7,0.2,1.1,0.3c1.3,0.3,2.4,0.5,3.5,0.5c1.6,0,3-0.4,4-1.1
c1.2-0.9,2-2.2,2.2-3.9c0.5-4.6-3.5-11.8-5.9-15.6c-0.6-0.9-1.2-1.8-1.8-2.7c-0.4-0.6-0.8-1.2-1.3-1.8c-0.5-0.7-1-1.3-1.4-1.9
c-1.7-2.1-3.3-4.1-5-5.9c-1-1-2-2-2.9-2.8l-0.4-0.4c-0.7-0.6-1.4-1.1-2.2-1.7c-1.2-0.9-2.5-1.6-3.6-2.2c-1.5-0.7-3-1.4-4.4-2.2
c-4.6-2.8-11-3.6-15.9-4.1c-0.6-0.1-1.1,0.2-1.4,0.5c-0.4,0.4-0.4,1.1-0.1,1.6c0.2,0.3,0.3,0.6,0.5,0.9c0.1,0.3,0,0.5-0.1,0.7
c-0.1,0.1-0.3,0.2-0.5,0.2c-0.8-0.1-1.6-0.2-2.3-0.3c-2.4-0.3-5-0.6-7.7-0.7c-0.6,0-1.2,0.3-1.5,0.8c-0.3,0.5-0.2,1.2,0.3,1.7
c0.5,0.5,0.8,0.9,0.9,1.4c0,0.2,0,0.4-0.2,0.5c-0.1,0.1-0.2,0.2-0.5,0.1c-2.2-0.3-4.5-0.4-6.9-0.2c-0.3,0-0.7,0.1-1,0.1
c-0.5,0.1-1,0.3-1.2,0.7c0,0,0,0.1,0,0.1c-0.2,0.5-0.1,1.2,0.4,1.6c0.5,0.5,0.6,1,0.7,1.7c0,0.2,0,0.4-0.2,0.5
c-0.1,0.1-0.3,0.2-0.4,0.2c-2.6,0-5.2,0.1-8.2,0.8c-0.7,0.1-1.1,0.6-1.2,1.2c-0.1,0.6,0.3,1.2,0.9,1.5c0.5,0.2,0.8,0.5,0.9,1
c0.1,0.2,0,0.4-0.1,0.5c-0.1,0.1-0.2,0.2-0.4,0.2c-0.3,0-0.5,0.1-0.8,0.1l-0.1,0l-0.1,0.1C75.8,149.3,75.5,150,75.8,150.6z"/>
<path d="M113.5,170.2c0.1-0.3,0.1-0.6,0.2-0.8c0.7-2.3,2.2-4.2,4.2-5.3c1.3-0.8,2.7-1.2,4.1-1.2c0.7-0.3,1.5-0.5,2.3-0.5
c2.8,0,5.1,1.9,5.6,4.5c0,0,0.1,0.1,0.1,0.1c0.1,0.2,0.3,0.3,0.4,0.5c1.8,2.3,2.5,4.7,1.8,6.7c-0.6,2-2.6,3.7-5.5,4.8
c-0.4,0.2-0.8,0.3-1.2,0.4c-0.3,0.1-0.6,0.2-0.9,0.2c-0.3,0.1-0.6,0.1-0.9,0.2c-1.1,0.2-2.1,0.2-3.1,0.2c-0.6,0-1.1-0.1-1.6-0.2
c-0.1,0-0.2,0-0.2-0.1c-0.4-0.1-0.8-0.2-1.1-0.4c-1.5-0.7-2.7-1.8-3.5-3.4C113.3,174.2,113.1,172.2,113.5,170.2z"/>
<ellipse class="st5" cx="124.3" cy="167.9" rx="3.6" ry="3.4"/>
</g>
<path class="st5" d="M180.8,200.3c-6.3-7.2-13.5-9.2-20.8-8.8c-7.3-0.5-14.5,1.6-20.8,8.8c-4.4,0.9-21.1,5.3-20.9,24.5
c0.2,10,5.8,17.7,13.1,21.7l0.1-0.7c0-0.2,0.1-0.3,0.2-0.4c0.1-0.1,0.3-0.2,0.5-0.1c1.8,0.2,2.8,0.8,3.2,1.9
c0.1,0.4,0.1,0.7,0.1,1.1c0,0,0.1,0,0.1,0c1.1,5.9,5.4,11.7,11.9,14.7c3.9,1.8,8.2,2.4,12.5,2.1c4.3,0.3,8.7-0.3,12.5-2.1
c6.5-3,10.9-8.7,11.9-14.7c0,0,0.1,0,0.1,0c-0.1-0.4,0-0.8,0.1-1.1c0.3-1,1.4-1.7,3.2-1.9c0.2,0,0.3,0,0.5,0.1
c0.1,0.1,0.2,0.3,0.2,0.4l0.1,0.7c7.3-4,12.9-11.7,13.1-21.7C202,205.6,185.2,201.2,180.8,200.3z"/>
<path class="st4" d="M173.6,209.9c0-0.1,0-0.2,0-0.3c-0.1-0.6-0.2-1.1-0.3-1.6c-0.7-2.3-2.3-4.3-4.6-5.8c-2.4-1.6-5.5-2.5-8.6-2.6
c-0.2,0-0.5,0-0.7,0c-0.5,0-1,0-1.5,0.1c-4,0.3-7.6,1.8-10.1,4.1c-2.5,2.3-3.7,5.2-3.4,8.1c0,0.4,0.1,0.8,0.2,1.2
c0.1,0.5,0.3,1,0.5,1.6c0.2,0.5,0.4,1,0.6,1.5c0.6,1.3,1.5,2.6,2.4,3.8c0.2,0.2,0.3,0.4,0.5,0.6c0.2,0.2,0.4,0.4,0.6,0.6
c0.2,0.2,0.5,0.5,0.7,0.7c3.1,3,6.8,4.6,10.2,4.5c0.2,0,0.3,0,0.5,0c3.5-0.3,7-2.5,9.6-6c0.4-0.5,0.7-1,1-1.6
c0.2-0.4,0.4-0.7,0.6-1.1c0.2-0.4,0.4-0.8,0.6-1.2c0.6-1.4,1-2.8,1.2-4.1C173.6,211.4,173.6,210.7,173.6,209.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -24,9 +24,8 @@ RUN mkdir -p /home/pi/shared_files \
USER pi USER pi
WORKDIR /home/pi/piscsi WORKDIR /home/pi/piscsi
RUN mkdir /home/pi/piscsi/{python,cpp}
COPY --chown=pi:pi easyinstall.sh . COPY --chown=pi:pi easyinstall.sh .
COPY --chown=pi:pi cpp/os_integration cpp/os_integration COPY --chown=pi:pi os_integration os_integration
COPY --chown=pi:pi cpp/piscsi_interface.proto cpp/piscsi_interface.proto COPY --chown=pi:pi cpp/piscsi_interface.proto cpp/piscsi_interface.proto
COPY --chown=pi:pi python/web python/web COPY --chown=pi:pi python/web python/web
COPY --chown=pi:pi python/common python/common COPY --chown=pi:pi python/common python/common

View File

@ -214,8 +214,6 @@ function installPiscsiWebInterface() {
sudo cp -f "$WEB_INSTALL_PATH/service-infra/nginx-default.conf" /etc/nginx/sites-available/default sudo cp -f "$WEB_INSTALL_PATH/service-infra/nginx-default.conf" /etc/nginx/sites-available/default
sudo cp -f "$WEB_INSTALL_PATH/service-infra/502.html" /var/www/html/502.html sudo cp -f "$WEB_INSTALL_PATH/service-infra/502.html" /var/www/html/502.html
sudo usermod -a -G $USER www-data
deleteFile "$SSL_CERTS_PATH" "rascsi-web.crt" deleteFile "$SSL_CERTS_PATH" "rascsi-web.crt"
deleteFile "$SSL_KEYS_PATH" "rascsi-web.key" deleteFile "$SSL_KEYS_PATH" "rascsi-web.key"
@ -415,12 +413,12 @@ function migrateLegacyData() {
fi fi
if [[ -f "/etc/rsyslog.d/rascsi.conf" ]]; then if [[ -f "/etc/rsyslog.d/rascsi.conf" ]]; then
sudo rm "/etc/rsyslog.d/rascsi.conf" sudo rm "/etc/rsyslog.d/rascsi.conf"
sudo cp "$CPP_PATH/os_integration/piscsi.conf" "/etc/rsyslog.d" sudo cp "$BASE/os_integration/piscsi.conf" "/etc/rsyslog.d"
echo "Replaced rascsi.conf with piscsi.conf" echo "Replaced rascsi.conf with piscsi.conf"
fi fi
if [[ -f "/etc/network/interfaces.d/rascsi_bridge" ]]; then if [[ -f "/etc/network/interfaces.d/rascsi_bridge" ]]; then
sudo rm "/etc/network/interfaces.d/rascsi_bridge" sudo rm "/etc/network/interfaces.d/rascsi_bridge"
sudo cp "$CPP_PATH/os_integration/piscsi_bridge" "/etc/network/interfaces.d" sudo cp "$BASE/os_integration/piscsi_bridge" "/etc/network/interfaces.d"
echo "Replaced rascsi_bridge with piscsi_bridge" echo "Replaced rascsi_bridge with piscsi_bridge"
fi fi
if [[ $(getent group rascsi) && $(getent group "$AUTH_GROUP") ]]; then if [[ $(getent group rascsi) && $(getent group "$AUTH_GROUP") ]]; then
@ -601,7 +599,7 @@ function setupWiredNetworking() {
echo "Modified /etc/dhcpcd.conf" echo "Modified /etc/dhcpcd.conf"
# default config file is made for eth0, this will set the right net interface # default config file is made for eth0, this will set the right net interface
sudo bash -c 'sed s/eth0/'"$LAN_INTERFACE"'/g '"$CPP_PATH"'/os_integration/piscsi_bridge > /etc/network/interfaces.d/piscsi_bridge' sudo bash -c 'sed s/eth0/'"$LAN_INTERFACE"'/g '"$BASE"'/os_integration/piscsi_bridge > /etc/network/interfaces.d/piscsi_bridge'
echo "Modified /etc/network/interfaces.d/piscsi_bridge" echo "Modified /etc/network/interfaces.d/piscsi_bridge"
echo "Configuration completed!" echo "Configuration completed!"
@ -709,7 +707,7 @@ function setupWirelessNetworking() {
# Downloads, compiles, and installs Netatalk (AppleShare server) # Downloads, compiles, and installs Netatalk (AppleShare server)
function installNetatalk() { function installNetatalk() {
NETATALK_VERSION="2-221101" NETATALK_VERSION="2-230201"
NETATALK_CONFIG_PATH="/etc/netatalk" NETATALK_CONFIG_PATH="/etc/netatalk"
if [ -d "$NETATALK_CONFIG_PATH" ]; then if [ -d "$NETATALK_CONFIG_PATH" ]; then

View File

@ -4,7 +4,7 @@ Module for methods reading from and writing to the file system
import logging import logging
import asyncio import asyncio
from os import path, walk from os import walk
from functools import lru_cache from functools import lru_cache
from pathlib import PurePath, Path from pathlib import PurePath, Path
from zipfile import ZipFile, is_zipfile from zipfile import ZipFile, is_zipfile
@ -54,24 +54,6 @@ class FileCmds:
return self.sock_cmd.send_pb_command(command.SerializeToString()) return self.sock_cmd.send_pb_command(command.SerializeToString())
# noinspection PyMethodMayBeStatic
# pylint: disable=no-self-use
def list_files(self, file_types, dir_path):
"""
Takes a (list) or (tuple) of (str) file_types - e.g. ('hda', 'hds')
Returns (list) of (list)s files_list:
index 0 is (str) file name and index 1 is (int) size in bytes
"""
files_list = []
for file_path, _dirs, files in walk(dir_path):
# Only list selected file types
# TODO: Refactor for readability?
files = [f for f in files if f.lower().endswith(file_types)]
files_list.extend(
[(file, path.getsize(path.join(file_path, file))) for file in files],
)
return files_list
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def list_config_files(self): def list_config_files(self):
""" """
@ -100,18 +82,13 @@ class FileCmds:
result = proto.PbResult() result = proto.PbResult()
result.ParseFromString(data) result.ParseFromString(data)
# Get a list of all *.properties files in CFG_DIR
prop_data = self.list_files(PROPERTIES_SUFFIX, CFG_DIR)
prop_files = [PurePath(x[0]).stem for x in prop_data]
server_info = self.piscsi.get_server_info() server_info = self.piscsi.get_server_info()
files = [] files = []
for file in result.image_files_info.image_files: for file in result.image_files_info.image_files:
# Add properties meta data for the image, if applicable prop_file_path = Path(CFG_DIR) / f"{file.name}.{PROPERTIES_SUFFIX}"
if file.name in prop_files: # Add properties meta data for the image, if matching prop file is found
process = self.read_drive_properties( if prop_file_path.exists():
Path(CFG_DIR) / f"{file.name}.{PROPERTIES_SUFFIX}" process = self.read_drive_properties(prop_file_path)
)
prop = process["conf"] prop = process["conf"]
else: else:
prop = False prop = False
@ -160,87 +137,11 @@ class FileCmds:
return {"status": result.status, "msg": result.msg, "files": files} return {"status": result.status, "msg": result.msg, "files": files}
def create_new_image(self, file_name, file_type, size):
"""
Takes (str) file_name, (str) file_type, and (int) size
Sends a CREATE_IMAGE command to the server
Returns (dict) with (bool) status and (str) msg
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.CREATE_IMAGE
command.params["token"] = self.token
command.params["locale"] = self.locale
command.params["file"] = f"{file_name}.{file_type}"
command.params["size"] = str(size)
command.params["read_only"] = "false"
data = self.send_pb_command(command)
result = proto.PbResult()
result.ParseFromString(data)
return {"status": result.status, "msg": result.msg}
def delete_image(self, file_name):
"""
Takes (str) file_name
Sends a DELETE_IMAGE command to the server
Returns (dict) with (bool) status and (str) msg
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.DELETE_IMAGE
command.params["token"] = self.piscsi.token
command.params["locale"] = self.piscsi.locale
command.params["file"] = file_name
data = self.send_pb_command(command)
result = proto.PbResult()
result.ParseFromString(data)
return {"status": result.status, "msg": result.msg}
def rename_image(self, file_name, new_file_name):
"""
Takes (str) file_name, (str) new_file_name
Sends a RENAME_IMAGE command to the server
Returns (dict) with (bool) status and (str) msg
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.RENAME_IMAGE
command.params["token"] = self.piscsi.token
command.params["locale"] = self.piscsi.locale
command.params["from"] = file_name
command.params["to"] = new_file_name
data = self.send_pb_command(command)
result = proto.PbResult()
result.ParseFromString(data)
return {"status": result.status, "msg": result.msg}
def copy_image(self, file_name, new_file_name):
"""
Takes (str) file_name, (str) new_file_name
Sends a COPY_IMAGE command to the server
Returns (dict) with (bool) status and (str) msg
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.COPY_IMAGE
command.params["token"] = self.piscsi.token
command.params["locale"] = self.piscsi.locale
command.params["from"] = file_name
command.params["to"] = new_file_name
data = self.send_pb_command(command)
result = proto.PbResult()
result.ParseFromString(data)
return {"status": result.status, "msg": result.msg}
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def delete_file(self, file_path): def delete_file(self, file_path):
""" """
Takes (Path) file_path for the file to delete Takes (Path) file_path for the file to delete
Returns (dict) with (bool) status and (str) msg Returns (dict) with (bool) status, (str) msg, (dict) parameters
""" """
parameters = {"file_path": file_path} parameters = {"file_path": file_path}
@ -263,10 +164,12 @@ class FileCmds:
Takes: Takes:
- (Path) file_path for the file to rename - (Path) file_path for the file to rename
- (Path) target_path for the name to rename - (Path) target_path for the name to rename
Returns (dict) with (bool) status and (str) msg Returns (dict) with (bool) status, (str) msg, (dict) parameters
""" """
parameters = {"target_path": target_path} parameters = {"target_path": target_path}
if target_path.parent.exists: if not target_path.parent.exists():
target_path.parent.mkdir(parents=True)
if target_path.parent.exists() and not target_path.exists():
file_path.rename(target_path) file_path.rename(target_path)
return { return {
"status": True, "status": True,
@ -285,10 +188,12 @@ class FileCmds:
Takes: Takes:
- (Path) file_path for the file to copy from - (Path) file_path for the file to copy from
- (Path) target_path for the name to copy to - (Path) target_path for the name to copy to
Returns (dict) with (bool) status and (str) msg Returns (dict) with (bool) status, (str) msg, (dict) parameters
""" """
parameters = {"target_path": target_path} parameters = {"target_path": target_path}
if target_path.parent.exists: if not target_path.parent.exists():
target_path.parent.mkdir(parents=True)
if target_path.parent.exists() and not target_path.exists():
copyfile(str(file_path), str(target_path)) copyfile(str(file_path), str(target_path))
return { return {
"status": True, "status": True,
@ -297,7 +202,32 @@ class FileCmds:
} }
return { return {
"status": False, "status": False,
"return_code": ReturnCodes.WRITEFILE_UNABLE_TO_WRITE, "return_code": ReturnCodes.WRITEFILE_COULD_NOT_WRITE,
"parameters": parameters,
}
def create_empty_image(self, target_path, size):
"""
Takes (Path) target_path and (int) size in bytes
Creates a new empty binary file to use as image
Returns (dict) with (bool) status, (str) msg, (dict) parameters
"""
parameters = {"target_path": target_path}
if not target_path.parent.exists():
target_path.parent.mkdir(parents=True)
if target_path.parent.exists() and not target_path.exists():
try:
with open(f"{target_path}", "wb") as out:
out.seek(size - 1)
out.write(b"\0")
except OSError as error:
return {"status": False, "msg": str(error)}
return {"status": True, "msg": ""}
return {
"status": False,
"return_code": ReturnCodes.WRITEFILE_COULD_NOT_WRITE,
"parameters": parameters, "parameters": parameters,
} }
@ -635,30 +565,48 @@ class FileCmds:
) )
tmp_full_path.unlink(True) tmp_full_path.unlink(True)
try: process = self.generate_iso(iso_filename, Path(tmp_dir), *iso_args)
run(
[ if not process["status"]:
"genisoimage", return {"status": False, "msg": process["msg"]}
*iso_args,
"-o",
str(iso_filename),
tmp_dir,
],
capture_output=True,
check=True,
)
except CalledProcessError as error:
logging.warning(SHELL_ERROR, " ".join(error.cmd), error.stderr.decode("utf-8"))
return {"status": False, "msg": error.stderr.decode("utf-8")}
parameters = {"value": " ".join(iso_args)}
return { return {
"status": True, "status": True,
"return_code": ReturnCodes.DOWNLOADFILETOISO_SUCCESS, "return_code": process["return_code"],
"parameters": parameters, "parameters": process["parameters"],
"file_name": iso_filename.name, "file_name": process["file_name"],
} }
def generate_iso(self, iso_file, target_path, *iso_args):
"""
Takes
- (Path) iso_file - the path to the file to create
- (Path) target_path - the path to the file or dir to generate the iso from
- (*str) iso_args - the tuple of arguments to pass to genisoimage
"""
try:
run(
[
"genisoimage",
*iso_args,
"-o",
str(iso_file),
str(target_path),
],
capture_output=True,
check=True,
)
except CalledProcessError as error:
logging.warning(SHELL_ERROR, " ".join(error.cmd), error.stderr.decode("utf-8"))
return {"status": False, "msg": error.stderr.decode("utf-8")}
return {
"status": True,
"return_code": ReturnCodes.DOWNLOADFILETOISO_SUCCESS,
"parameters": {"value": " ".join(iso_args)},
"file_name": iso_file.name,
}
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def download_to_dir(self, url, save_dir, file_name): def download_to_dir(self, url, save_dir, file_name):
""" """
@ -829,6 +777,8 @@ class FileCmds:
Returns (dict) with (bool) status and (str) msg Returns (dict) with (bool) status and (str) msg
""" """
file_path = Path(CFG_DIR) / file_name file_path = Path(CFG_DIR) / file_name
if not file_path.parent.exists():
file_path.parent.mkdir(parents=True)
try: try:
with open(file_path, "w") as json_file: with open(file_path, "w") as json_file:
dump(conf, json_file, indent=4) dump(conf, json_file, indent=4)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 B

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

View File

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 320 320" style="enable-background:new 0 0 320 320;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;fill:#BCBEC0;}
.st2{fill:none;stroke:#231F20;stroke-miterlimit:10;}
.st3{fill:#231F20;}
.st4{fill:#080505;}
.st5{fill:#FFFFFF;}
.st6{fill:#CC6600;}
</style>
<g id="BG" class="st0">
<rect x="0" y="0" class="st1" width="320" height="320"/>
<line class="st2" x1="160" y1="-0.5" x2="160" y2="339.5"/>
</g>
<g id="line" class="st0">
</g>
<g id="Layer_5" class="st0">
</g>
<g id="body">
<path class="st3" d="M259.9,120l-2.2-3.9c0.1-28-12.7-39.4-27.6-48H203c-0.4-0.5-0.8-1-1.3-1.4c-0.7-0.7-1.8-0.8-2.7-0.4
c-0.2,0.1-0.4,0.2-0.6,0.4c-1.1-0.9-2.2-1.8-3.3-2.5c-0.9-0.6-2.1-0.5-2.9,0.1c-0.2,0.1-0.3,0.3-0.5,0.4c-0.9-0.6-1.9-1.1-2.9-1.6
c-0.1-0.1-0.2-0.1-0.3-0.1l-0.6,5.2H160H89.8c-14.9,8.7-27.6,20.1-27.6,48l-2.2,3.9C43,130.4,27.7,163.8,51.7,191
c1.6,8.5,4.2,14.6,6.5,21.4c3.5,27.2,26.4,40,32.4,41.5c8.8,6.7,18.2,13.1,31,17.6c12,12.4,25,17.1,38.1,17.1c0.1,0,0.2,0,0.3,0
s0.2,0,0.3,0c13.1,0,26.1-4.7,38.1-17.1c12.7-4.5,22.1-10.9,31-17.6c6-1.5,28.9-14.3,32.4-41.5c2.3-6.8,5-12.9,6.5-21.4
C292.3,163.8,277,130.4,259.9,120z"/>
<path class="st4" d="M290.8,81.5c1.5-5,0.9-9.2-0.3-12.4c-0.1-1.5-0.3-2.9-0.8-4.3c0-0.7,0-1.3,0-1.9c0.4-4.5-0.8-9-3.4-12.7
c-0.5-3.3-1.8-6.3-3.9-8.8c-0.9-1.3-2-2.5-3.1-3.6c-0.1-0.1-0.3-0.3-0.5-0.4c-1.8-5.2-5.5-9.3-10.5-11.6c-2.6-1.2-5.5-1.8-8.5-1.8
c-3,0-6,0.6-9,1.8c-1.5-0.3-3-0.4-4.6-0.4c-4.2,0-8.6,1-13.1,3c-0.7-0.1-1.5-0.1-2.3-0.1c-3.3,0-6.6,0.8-10.2,2.5c-0.3,0-0.7,0-1,0
c-5.4,0-10.5,1.8-15.2,5.3c-2.4,0.2-4.7,0.7-6.8,1.6l0,0h0c-4.1,1.7-6.7,4.4-8.5,6.4c-6.7,1.9-9.9,5.4-11.8,8
c-2.4,0.9-4.5,2.1-6.3,3.6c-1.7-0.5-3.6-1-5.7-1.2c-0.5-0.1-1-0.1-1.5-0.1c-1.3,0-2.6,0.2-3.8,0.6c-1.9-0.4-4.1-0.7-6.3-0.7l-0.1,0
c-1.9,0-3.6,0.4-5.1,1.1c-1.7-1.3-3.7-2.4-5.9-3.3c-1.9-2.6-5.1-6.1-11.8-8c-1.8-2-4.5-4.7-8.5-6.4h0l0,0c-2.1-0.9-4.4-1.5-6.8-1.6
c-4.7-3.5-9.8-5.3-15.2-5.3c-0.3,0-0.7,0-1,0c-3.5-1.7-6.9-2.5-10.2-2.5c-0.8,0-1.5,0-2.3,0.1c-4.5-2-8.9-3-13.1-3
c-1.6,0-3.1,0.1-4.6,0.4c-3-1.2-6.1-1.8-9-1.8c-3,0-5.8,0.6-8.5,1.8c-5,2.2-8.7,6.4-10.5,11.6c-0.2,0.1-0.3,0.3-0.5,0.4
c-1.2,1.1-2.2,2.3-3.1,3.6c-2.1,2.5-3.4,5.5-3.9,8.8c-2.6,3.8-3.8,8.2-3.4,12.7c0,0.6,0,1.3,0,1.9c-0.4,1.4-0.7,2.9-0.8,4.3
c-1.1,3.1-1.8,7.4-0.3,12.4c-1.5,5.2-0.7,10.9,2.4,16.9c-0.6,5.8,1.3,11.2,5.6,16.1c0.7,8.3,7,13.4,10.5,16.3l2,0.9
c-3.3,5.3-5.9,11.7-7,19.1c-0.6,4.3-0.7,8.6-0.2,12.8c-0.3,0.3-0.5,0.7-0.7,1c-2.6,4-1.9,9.4,1.7,14.1c-0.5,1-0.8,2.1-1,3.2
c-0.4,3,0.4,6.1,2.3,8.5c-0.1,0.5-0.2,1-0.3,1.6c-0.3,3,0.7,6,2.9,8.2c0.1,3,1.5,5.7,3.8,7.5c0.9,3.8,3.7,5.8,6.2,7
c1.4,1.3,3.1,2,4.7,2.4c0.4,1.8,1,3.6,1.6,5.3c0.1,0.4,0.2,0.7,0.2,0.7l0.1,0.4c0.5,1.4,1.2,2.9,1.9,4.4c2.9,6,6.9,11.4,11.8,16.1
c4,4,10,9.1,17,11.5c2.4,1.9,4.7,3.6,6.4,4.7c2.7,1.7,4.2,2.6,5.5,3.1c0,0,0,0,0.1,0c6.1,3.8,12.1,6.7,18.6,9
c10.6,10.6,22.2,16,34.5,16c0.1,0,0.3,0,0.4,0c0.1,0,0.3,0,0.4,0c12.3,0,23.9-5.4,34.5-16c6.5-2.3,12.4-5.2,18.6-9c0,0,0,0,0.1,0
c1.2-0.5,2.8-1.3,5.5-3.1c1.7-1.1,4.1-2.7,6.4-4.7c6.9-2.4,13-7.4,17-11.5c4.9-4.7,8.9-10.1,11.8-16.1c0.8-1.5,1.4-3,1.9-4.4l0,0
c0.1-0.2,0.2-0.4,0.2-0.6l0.1-0.4c0.6-1.7,1.1-3.5,1.6-5.3c1.5-0.4,3.3-1,4.7-2.4c2.5-1.2,5.2-3.2,6.2-7c2.3-1.8,3.7-4.6,3.8-7.5
c2.2-2.3,3.3-5.2,2.9-8.2c-0.1-0.5-0.2-1-0.3-1.6c1.8-2.4,2.7-5.5,2.3-8.5c-0.2-1.1-0.5-2.2-1-3.2c3.6-4.8,4.3-10.1,1.7-14.1
c-0.2-0.4-0.5-0.7-0.7-1c0.5-4.2,0.4-8.5-0.2-12.8c-1.1-7.4-3.7-13.8-7-19.1l2-0.9c3.6-2.9,9.8-8,10.5-16.3
c4.3-4.9,6.1-10.3,5.6-16.1C291.6,92.4,292.4,86.7,290.8,81.5z"/>
<g>
<g>
<g>
<path class="st5" d="M278.6,53.2c0-2.8-0.8-5.2-2.5-7.1c-0.6-0.9-1.3-1.7-2.1-2.4c-0.6-0.6-1.4-1.1-2.1-1.6
c-0.7-4.1-3.1-7.4-6.7-9.1c-3.9-1.8-8.7-1.4-13.6,1.1c-5-1.7-10.8-0.9-17.3,2.5c-3-0.9-6.6-0.8-12,2.2c-6.7-1-11.5,2.1-14.9,5.1
c-2.4-0.2-4.6,0.1-6.6,1l0,0c-2.9,1.2-4.7,3.2-6.3,5c-0.4,0.4-0.8,0.9-1.1,1.2c-6.6,1.3-8.8,4.3-10.3,6.5
c-0.2,0.4-0.5,0.7-0.7,1c-8.5,2.4-10.1,7.4-11.5,11.7c-0.2,0.5-0.3,0.9-0.5,1.4l1.4,3.7c83,63,89.3,48.5,91.4,49.5l4-0.5
c3.6-2.9,8.4-6.8,7.6-13.3c6-5.5,6.3-10.3,5.3-14.3c1.9-3,5.3-9.3,2.2-15.4c1.8-3.9,1.9-7.5,0.3-10.8c0.1-1.7-0.2-3.3-0.9-4.9
c0.1-1.1,0.1-2.2,0.1-3.2C282.2,59.2,281.1,55.8,278.6,53.2z"/>
<path class="st3" d="M224.9,81.4c0.4,0.1,0.9,0.2,1.3,0.3c1.1,0.3,2,1,2.7,2c0.4,0.3,0.8,0.5,1.3,0.8c0.6,0.4,1.2,0.8,1.8,1.2
c0.6,0.4,0.9,1,1,1.8c0.6,0.2,1.2,0.4,1.9,0.6l0.6,0.2c0.8,0.3,1.5,0.8,2.1,1.5c0.3,0.4,0.6,0.9,0.8,1.5c0.1,0.3,0.2,0.7,0.2,1
c0.1,0.3,0.1,0.7,0,1.1c0,0.2,0,0.4-0.1,0.7c0.4,0.2,0.9,0.3,1.3,0.5c0.2,0.1,0.5,0.2,0.7,0.3c0.5,0.2,1.1,0.5,1.6,0.8
c1.2,0.6,2.1,1.7,2.4,3.1c0.1,0.3,0.1,0.6,0.2,0.9c0,0.3,0,0.7,0,1c1.1,0.6,1.7,1.3,2.3,1.9c0.4,0.5,0.9,1,1.7,1.5
c1.2,0.8,1.9,2.1,2.1,3.5c0.1,0,0.1,0.1,0.2,0.1c-0.1-0.3-0.2-0.7-0.3-1c1.2-1.3,2.3-2.7,3.2-4.5c0.6-1.1,0.5-2.6-0.1-3.7
c-0.1-0.1-0.2-0.2-0.2-0.4c0.7-1.2,1.4-2.4,2-3.7c0.6-1.2,0.4-2.8-0.4-3.9c-0.1-0.2-0.3-0.3-0.4-0.5c0.7-1.4,1.3-3,1.6-4.7
c0-0.2,0.1-0.4,0.1-0.6c0-1.1-0.4-2.3-1.3-3c0,0,0,0,0,0c0,0,0,0,0,0c0.4-1,0.7-2.3,1-3.7c0.2-1.1-0.1-2.2-0.7-3l0.7-0.7
c0.3-0.3,0.6-0.8,0.7-1.2c0.1-0.4,0.2-0.8,0.4-1.1c0.1-0.4,0.2-0.7,0.2-1.1c0-0.8-0.2-1.6-0.7-2.3c-0.1-0.1-0.2-0.3-0.3-0.4
c-1.1-0.1-4.6-0.5-4.6-0.5c0.1,0,0.3-0.1,0.4-0.1c-0.3,0-0.5-0.1-0.5-0.1c-0.4-1-1.3-1.8-2.3-1.9c-1.6-0.3-3.2,0-4.5,0.4
c0-0.1-0.1-0.2-0.1-0.2c-0.8-1.2-2.1-1.7-3.3-1.3c-0.6,0.2-0.7-0.3-1.2-0.1c-0.1-0.1-0.6,0.6-0.7,0.4c-0.8-1.1-2.1-1.5-3.3-0.9
c-1.1,0.5-2,1-2.8,1.5c0,0-0.1-0.1-0.1-0.1c-1-1-2.4-1.2-3.5-0.4c-1,0.7-1.8,1.5-2.5,2.3c0,0,0,0-0.1-0.1
c-1.1-0.8-2.6-0.7-3.5,0.3c-0.6,0.6-1.1,1.3-1.6,2c-0.2-0.1-0.4-0.2-0.6-0.3c-1.1-0.4-2.3,0.1-3,1.2c-0.8,1.3-1.4,2.5-2,3.7
c-0.1,0-0.2-0.1-0.4-0.1c-1.1-0.2-2.2,0.4-2.8,1.5c-0.1,0.1-0.1,0.3-0.2,0.4c3.9,1.6,7.7,3.4,11.2,5.3L224.9,81.4z"/>
</g>
<g>
<path class="st5" d="M41.4,53.2c0-2.8,0.8-5.2,2.5-7.1c0.6-0.9,1.3-1.7,2.1-2.4c0.6-0.6,1.4-1.1,2.1-1.6
c0.7-4.1,3.1-7.4,6.7-9.1c3.9-1.8,8.7-1.4,13.6,1.1c5-1.7,10.8-0.9,17.3,2.5c3-0.9,6.6-0.8,12,2.2c6.7-1,11.5,2.1,14.9,5.1
c2.4-0.2,4.6,0.1,6.6,1l0,0c2.9,1.2,4.7,3.2,6.3,5c0.4,0.4,0.8,0.9,1.1,1.2c6.6,1.3,8.8,4.3,10.3,6.5c0.2,0.4,0.5,0.7,0.7,1
c8.5,2.4,10.1,7.4,11.5,11.7c0.2,0.5,0.3,0.9,0.5,1.4l-1.4,3.7c-83,63-89.3,48.5-91.4,49.5l-4-0.5c-3.6-2.9-8.4-6.8-7.6-13.3
c-6-5.5-6.3-10.3-5.3-14.3c-1.9-3-5.3-9.3-2.2-15.4c-1.8-3.9-1.9-7.5-0.3-10.8c-0.1-1.7,0.2-3.3,0.9-4.9
c-0.1-1.1-0.1-2.2-0.1-3.2C37.8,59.2,38.9,55.8,41.4,53.2z"/>
<path class="st3" d="M95.1,81c-0.4,0.1-0.9,0.2-1.3,0.3c-1.1,0.3-2,1-2.7,2c-0.4,0.3-0.8,0.5-1.3,0.8c-0.6,0.4-1.2,0.8-1.8,1.2
c-0.6,0.4-0.9,1-1,1.8c-0.6,0.2-1.2,0.4-1.9,0.6l-0.6,0.2c-0.8,0.3-1.5,0.8-2.1,1.5c-0.3,0.4-0.6,0.9-0.8,1.5
c-0.1,0.3-0.2,0.7-0.2,1c-0.1,0.3-0.1,0.7,0,1.1c0,0.2,0,0.4,0.1,0.7c-0.4,0.2-0.9,0.3-1.3,0.5c-0.2,0.1-0.5,0.2-0.7,0.3
c-0.5,0.2-1.1,0.5-1.6,0.8c-1.2,0.6-2.1,1.7-2.4,3.1c-0.1,0.3-0.1,0.6-0.2,0.9c0,0.3,0,0.7,0,1c-1.1,0.6-1.7,1.3-2.3,1.9
c-0.4,0.5-0.9,1-1.7,1.5c-1.2,0.8-1.9,2.1-2.1,3.5c-0.1,0-0.1,0.1-0.2,0.1c0.1-0.3,0.2-0.7,0.3-1c-1.2-1.3-2.3-2.7-3.2-4.5
c-0.6-1.1-0.5-2.6,0.1-3.7c0.1-0.1,0.2-0.2,0.2-0.4c-0.7-1.2-1.4-2.4-2-3.7c-0.6-1.2-0.4-2.8,0.4-3.9c0.1-0.2,0.3-0.3,0.4-0.5
c-0.7-1.4-1.3-3-1.6-4.7c0-0.2-0.1-0.4-0.1-0.6c0-1.1,0.4-2.3,1.3-3c0,0,0,0,0,0c0,0,0,0,0,0c-0.4-1-0.7-2.3-1-3.7
c-0.2-1.1,0.1-2.2,0.7-3L63.8,74c-0.3-0.3-0.6-0.8-0.7-1.2c-0.1-0.4-0.2-0.8-0.4-1.1c-0.1-0.4-0.2-0.7-0.2-1.1
c0-0.8,0.2-1.6,0.7-2.3c0.1-0.1,0.2-0.3,0.3-0.4c1.1-0.1,4.6-0.5,4.6-0.5c-0.1,0-0.3-0.1-0.4-0.1c0.3,0,0.5-0.1,0.5-0.1
c0.4-1,1.3-1.8,2.3-1.9c1.6-0.3,3.2,0,4.5,0.4c0-0.1,0.1-0.2,0.1-0.2c0.8-1.2,2.1-1.7,3.3-1.3c0.6,0.2,0.7-0.3,1.2-0.1
c0.1-0.1,0.6,0.6,0.7,0.4c0.8-1.1,2.1-1.5,3.3-0.9c1.1,0.5,2,1,2.8,1.5c0,0,0.1-0.1,0.1-0.1c1-1,2.4-1.2,3.5-0.4
c1,0.7,1.8,1.5,2.5,2.3c0,0,0,0,0.1-0.1c1.1-0.8,2.6-0.7,3.5,0.3c0.6,0.6,1.1,1.3,1.6,2c0.2-0.1,0.4-0.2,0.6-0.3
c1.1-0.4,2.3,0.1,3,1.2c0.8,1.3,1.4,2.5,2,3.7c0.1,0,0.2-0.1,0.4-0.1c1.1-0.2,2.2,0.4,2.8,1.5c0.1,0.1,0.1,0.3,0.2,0.4
c-3.9,1.6-7.7,3.4-11.2,5.3L95.1,81z"/>
</g>
</g>
<path class="st6" d="M269.5,151.9c-2.1-13.7-10.4-23.9-17.8-28c-0.4-0.2-0.7-0.4-1.1-0.6c-0.2-0.4-0.4-0.7-0.6-1.1
c-0.7-1.2-1.4-2.5-2.2-3.7c-2.2-3.7-5.3-7-8.9-10c0,0,0.1-0.1,0.1-0.1c0.4-0.5,0.6-1,0.4-1.5c-0.1-0.2-0.2-0.4-0.3-0.6
c-1.4-1.5-3.1-2.7-5.1-3.7c-0.1,0-0.1-0.1-0.2-0.1c-0.8-0.4-1.6-0.8-2.4-1.2c-0.5-0.2-1-0.4-1.4-0.6c-0.4-0.2-0.8-0.3-1.2-0.5
c-0.1,0-0.2-0.1-0.2-0.1c0.1,0,0.3-0.1,0.6-0.1c0.2,0,0.4-0.1,0.6-0.1c0.9-0.3,1.7-0.8,2-1.5c0.2-0.3,0.2-0.7,0.1-1
c-0.1-0.4-0.4-0.8-0.9-1.1c-1-0.5-2-1-3-1.4c-1.5-0.7-3.1-1.3-4.7-1.9c0.1,0,0.2,0,0.3,0c1.3-0.1,2.4-0.7,2.8-1.6c0,0,0,0,0,0
c0.4-0.9,0-1.8-1-2.2c-0.1,0-0.2-0.1-0.3-0.1c-3.8-1.6-6.9-2.1-9.4-2.6c0.1-0.1,0.3-0.2,0.5-0.3c1.1-0.4,1.9-1.1,2-2
c0.1-0.8-0.6-1.5-1.7-1.8c-3.3-0.7-6.2-0.9-9.2-1c0.2-0.4,0.4-0.7,0.7-0.9c0.9-0.6,1.3-1.4,1.1-2.1c0-0.1-0.1-0.2-0.2-0.4
c-0.3-0.5-1-0.9-1.8-1c-0.7-0.1-1.4-0.2-2.1-0.2c-0.3,0-0.6,0-1-0.1c-2-0.1-3.9-0.1-5.9,0c0,0,0,0,0,0c0.1-0.2,0.4-0.4,0.8-0.6
c0.2-0.1,0.4-0.3,0.5-0.4c0.4-0.4,0.6-0.8,0.6-1.3c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.1-0.3-0.2-0.4c-0.2-0.2-0.4-0.4-0.6-0.5
c-0.4-0.2-0.9-0.4-1.5-0.4c-0.3,0-0.5,0-0.8,0c-0.6,0-1.1,0-1.7,0c-3.2-2.9-8.1-5.4-13.5-7.3c-0.7-0.2-1.5-0.3-2.3-0.3
c-1-0.5-2-1-3.1-1.5c-1.1-0.5-2.6-0.5-3.6,0c-0.4,0.2-0.6,0.4-0.8,0.6c-2-0.9-4.5-1.8-7.4-2.1c-1.2-0.1-2.4,0.2-3,0.8
c-0.1,0.1-0.1,0.1-0.2,0.2c-2.6-0.6-5.2-1.1-7.7-1.2c-1.3,0-2.3,0.5-2.7,1.2c0,0.1-0.1,0.2-0.1,0.2c-2.2-0.3-4.6-0.5-7.1-0.4
c-1.2,0-2.1,0.5-2.4,1.2c-0.1,0.2-0.1,0.4-0.1,0.6c-1.9-0.1-3.8,0-5.6,0.1c-1.2,0.1-2.2,0.6-2.4,1.3c-0.1,0.2,0,0.5,0,0.7
c-2.1,0-4.2,0.2-6.2,0.7c-1.1,0.3-1.7,0.9-1.6,1.7c0,0.1,0.1,0.3,0.2,0.4c-1.5,0.1-3.1,0.2-4.9,0.7c-0.9,0.2-1.5,0.8-1.6,1.5
c0,0.5,0.4,1.1,1,1.5c-0.1,0.1-0.2,0.1-0.2,0.2c0,0.1-0.1,0.1-0.1,0.2c-0.8,0.2-1.6,0.3-2.3,0.4c-1.3,0.2-2.1,0.9-2,1.8
c0.1,0.3,0.2,0.5,0.4,0.8c-0.1,0-0.2,0-0.3,0c-0.3,0-0.6,0-1,0.1c-0.7,0.1-1.4,0.1-2.1,0.2c-0.8,0.1-1.5,0.5-1.8,1
c-0.1,0.1-0.1,0.2-0.2,0.4c-0.2,0.7,0.2,1.5,1.1,2.1c0.3,0.2,0.5,0.4,0.7,0.9c-3,0.1-5.9,0.3-9.2,1c-1.1,0.2-1.8,0.9-1.7,1.8
c0.1,0.8,0.8,1.6,2,2c0.2,0.1,0.4,0.2,0.5,0.3c-2.5,0.4-5.6,1-9.4,2.6c-0.1,0-0.2,0.1-0.3,0.1c-1,0.4-1.4,1.3-1,2.2c0,0,0,0,0,0
c0.4,0.9,1.6,1.5,2.8,1.6c0.1,0,0.2,0,0.3,0c-1.6,0.5-3.1,1.2-4.7,1.9c-1,0.5-2,0.9-3,1.4c-0.5,0.3-0.8,0.7-0.9,1.1
c-0.1,0.3,0,0.6,0.1,1c0.3,0.7,1.1,1.2,2,1.5c0.2,0.1,0.4,0.1,0.6,0.1c0.3,0,0.4,0.1,0.6,0.1c-0.1,0-0.2,0.1-0.2,0.1
c-0.4,0.2-0.8,0.3-1.2,0.5c-0.5,0.2-1,0.4-1.4,0.6c-0.8,0.4-1.6,0.7-2.4,1.2c-0.1,0-0.1,0.1-0.2,0.1c-1.9,1-3.7,2.3-5.1,3.7
c-0.2,0.2-0.3,0.4-0.3,0.6c-0.1,0.5,0,1,0.4,1.5c0,0,0.1,0.1,0.1,0.1c-3.7,3.1-6.8,6.4-8.9,10c-0.7,1.2-1.4,2.5-2.2,3.7
c-0.2,0.4-0.4,0.7-0.6,1.1c-0.4,0.2-0.7,0.4-1.1,0.6c-7.3,4.1-15.7,14.2-17.8,28c-1.3,8.5-0.5,21.5,10.6,34.4
c0.3,0.4,0.6,0.7,0.9,1.1c0.1,0.5,0.2,0.9,0.2,1.4c1.1,6.3,2.9,11.1,4.8,16.3c0.5,1.4,1,2.9,1.5,4.3c0.1,0.2,0.1,0.3,0.2,0.5
c0,0.2,0,0.3,0.1,0.5c3.2,25.2,24.6,36.2,28.4,37.1c0.3,0.1,0.7,0.2,1,0.3c0.3,0.2,0.5,0.4,0.8,0.6c9.4,7.1,17.9,12.6,29.4,16.6
c0.4,0.1,0.7,0.3,1.1,0.4c0.3,0.3,0.5,0.5,0.8,0.8c8.5,8.6,18.5,14.2,29.8,14.1c11.3,0.1,21.3-5.5,29.8-14.1
c0.3-0.3,0.5-0.5,0.8-0.8c0.4-0.1,0.7-0.3,1.1-0.4c11.4-4,20-9.5,29.4-16.6c0.3-0.2,0.5-0.4,0.8-0.6c0.3-0.1,0.7-0.2,1-0.3
c3.8-0.9,25.2-11.9,28.4-37.1c0-0.2,0-0.3,0.1-0.5c0.1-0.2,0.1-0.3,0.2-0.5c0.5-1.5,1-2.9,1.5-4.3c1.9-5.1,3.6-10,4.8-16.3
c0.1-0.5,0.2-0.9,0.2-1.4c0.3-0.4,0.6-0.7,0.9-1.1C270,173.4,270.8,160.4,269.5,151.9z"/>
<g>
<path class="st5" d="M268.5,181.4l-3-1.2c0-0.8,3.4-4.5,3.9-5.2c1.7-1.8,3.2-4.6,2.2-6.1c-2.6-4.5-14.2,1.6-23.9,8
c0.8-1.8,1.7-4.8-0.6-6.1c-4.5-2.6-16.5,7.4-17.9,8.6c-7.6,6.5-14.5,15-12.9,20.9c0.4,1.4,0.9,2.8,1.2,4.2
c0.1,0.6,0.3,1.2,0.4,1.7c1.3,4.2,2,8.6,1.9,13c-0.2,11,0.2,21.5-9.3,33.2c-2.9,3.4-3.2,4.9,0.3,3.3c0.5,0,6.3-3.5,10.8-7.4
c10.6-2.8,23.2-16.9,27.1-27.6c0,0,2.2-7.2,2.2-9.9c0-1.7,7.8-0.9,6-2.5c1.9-0.6,6.2-1.9,3.2-4.8c-0.3-0.2,3.3-1.8,3.3-1.8
c1.6-0.8,1.6-3.3-0.1-4c-0.4-0.5,3.1-2.6,3.3-2.9c2.3-1.9,0.3-4.1-1.7-5.2c-0.7-0.9,3.3-3.3,3.7-3.9
C270.1,184.6,270.1,182.1,268.5,181.4z"/>
<path class="st5" d="M51.5,181.4l3-1.2c0-0.8-3.4-4.5-3.9-5.2c-1.7-1.8-3.2-4.6-2.2-6.1c2.6-4.5,14.2,1.6,23.9,8
c-0.8-1.8-1.7-4.8,0.6-6.1c4.5-2.6,16.5,7.4,17.9,8.6c7.6,6.5,14.5,15,12.9,20.9c-0.4,1.4-0.9,2.8-1.2,4.2
c-0.1,0.6-0.3,1.2-0.4,1.7c-1.3,4.2-2,8.6-1.9,13c0.2,11-0.2,21.5,9.3,33.2c2.9,3.4,3.2,4.9-0.3,3.3c-0.5,0-6.3-3.5-10.8-7.4
c-10.6-2.8-23.2-16.9-27.1-27.6c0,0-2.2-7.2-2.2-9.9c0-1.7-7.8-0.9-6-2.5c-1.9-0.6-6.2-1.9-3.2-4.8c0.3-0.2-3.3-1.8-3.3-1.8
c-1.6-0.8-1.6-3.3,0.1-4c0.4-0.5-3.1-2.6-3.3-2.9c-2.3-1.9-0.3-4.1,1.7-5.2c0.7-0.9-3.3-3.3-3.7-3.9
C49.9,184.6,49.9,182.1,51.5,181.4z"/>
</g>
<g>
<path class="st5" d="M243.5,148.9L243.5,148.9l-0.2-0.1c-0.3,0-0.5-0.1-0.8-0.1c-0.2,0-0.3-0.1-0.4-0.2c-0.1-0.2-0.1-0.3-0.1-0.5
c0.2-0.4,0.5-0.8,0.9-1c0.6-0.3,1-0.9,0.9-1.5c-0.1-0.6-0.5-1.1-1.2-1.2c-3-0.7-5.6-0.7-8.2-0.8c-0.2,0-0.3-0.1-0.4-0.2
c-0.1-0.1-0.2-0.3-0.2-0.5c0.1-0.6,0.2-1.2,0.7-1.7c0.5-0.5,0.6-1.1,0.4-1.6c0,0,0-0.1,0-0.1c-0.2-0.4-0.7-0.7-1.2-0.7
c-0.3,0-0.7-0.1-1-0.1c-2.4-0.2-4.7-0.1-6.9,0.2c-0.2,0-0.4-0.1-0.5-0.1c-0.2-0.1-0.2-0.3-0.2-0.5c0.1-0.5,0.4-1,0.9-1.4
c0.5-0.5,0.6-1.1,0.3-1.7c-0.3-0.5-0.8-0.8-1.5-0.8c-2.7,0.1-5.2,0.4-7.7,0.7c-0.8,0.1-1.5,0.2-2.3,0.3c-0.3,0-0.4-0.1-0.5-0.2
c-0.1-0.1-0.2-0.4-0.1-0.7c0.1-0.3,0.3-0.5,0.5-0.9c0.3-0.5,0.3-1.1-0.1-1.6c-0.3-0.4-0.9-0.6-1.4-0.5
c-4.8,0.4-11.2,1.3-15.9,4.1c-1.4,0.8-2.9,1.5-4.4,2.2c-1.2,0.6-2.4,1.3-3.6,2.2c-0.8,0.6-1.5,1.2-2.2,1.7l-0.4,0.4
c-0.9,0.8-1.9,1.8-2.9,2.8c-1.7,1.7-3.3,3.7-5,5.9c-0.5,0.6-1,1.3-1.4,1.9c-0.4,0.6-0.9,1.2-1.3,1.8c-0.6,0.9-1.2,1.8-1.8,2.7
c-2.4,3.8-6.4,10.9-5.9,15.6c0.2,1.7,0.9,3,2.2,3.9c1.1,0.7,2.4,1.1,4,1.1c1,0,2.2-0.2,3.5-0.5c0.4-0.1,0.7-0.2,1.1-0.3
c0.3-0.1,0.6-0.2,0.9-0.3c0.3-0.1,0.6-0.2,0.9-0.3c0.5-0.2,0.9-0.4,1.4-0.6c1.1,3.4,4.3,6.3,8.8,8c0.6,0.2,1.2,0.4,1.9,0.6
c0.4,0.1,0.8,0.2,1.3,0.3c0.5,0.1,0.9,0.2,1.4,0.3c1.2,0.2,2.4,0.3,3.6,0.3c0.3,0,0.7,0,1,0c0.9,0,1.8-0.2,2.6-0.4l0.1,0
c0.1,0,0.2-0.1,0.3-0.1c0.6-0.2,1.2-0.4,1.9-0.7c2.6-1.1,4.7-3.1,6-5.7c1.4-2.8,1.8-6.1,1.1-9.3c-0.1-0.4-0.2-0.9-0.4-1.3
c-0.2-0.6-0.4-1.2-0.7-1.8c1.7-0.7,3.5-1.7,5.1-3c1.3-1,2.4-2.1,3.4-3.2c0.4-0.5,1-0.8,1.8-0.9c0.7-0.1,1.5-0.2,2.2-0.4
c0.9-0.2,1.8-0.4,2.7-0.5c0.4-0.1,0.9-0.2,1.3-0.3c0.7-0.1,1.3-0.3,1.9-0.5c0.8-0.2,1.7-0.4,2.5-0.6c0.8-0.2,1.6-0.5,2.4-0.7
c0.8-0.3,1.6-0.5,2.3-0.8c0.6-0.2,1.1-0.4,1.7-0.6c0.5-0.2,1.1-0.4,1.5-0.7c0.6-0.3,1.2-0.6,1.7-0.9c0.6-0.3,1.1-0.7,1.6-1
c0.6-0.5,1-0.9,1.2-1.3C244.5,150,244.2,149.3,243.5,148.9z"/>
<path d="M206.5,170.2c-0.1-0.3-0.1-0.6-0.2-0.8c-0.7-2.3-2.2-4.2-4.2-5.3c-1.3-0.8-2.7-1.2-4.1-1.2c-0.7-0.3-1.5-0.5-2.3-0.5
c-2.8,0-5.1,1.9-5.6,4.5c0,0-0.1,0.1-0.1,0.1c-0.1,0.2-0.3,0.3-0.4,0.5c-1.8,2.3-2.5,4.7-1.8,6.7c0.6,2,2.6,3.7,5.5,4.8
c0.4,0.2,0.8,0.3,1.2,0.4c0.3,0.1,0.6,0.2,0.9,0.2c0.3,0.1,0.6,0.1,0.9,0.2c1.1,0.2,2.1,0.2,3.1,0.2c0.6,0,1.1-0.1,1.6-0.2
c0.1,0,0.2,0,0.2-0.1c0.4-0.1,0.8-0.2,1.1-0.4c1.5-0.7,2.7-1.8,3.5-3.4C206.7,174.2,206.9,172.2,206.5,170.2z"/>
<ellipse class="st5" cx="195.7" cy="167.9" rx="3.6" ry="3.4"/>
<path class="st5" d="M75.8,150.6c0.2,0.4,0.6,0.9,1.2,1.3c0.4,0.3,0.9,0.7,1.6,1c0.5,0.3,1.1,0.6,1.7,0.9c0.5,0.2,1,0.4,1.5,0.7
c0.5,0.2,1.1,0.4,1.7,0.6c0.7,0.3,1.5,0.5,2.3,0.8c0.8,0.2,1.6,0.5,2.4,0.7c0.8,0.2,1.6,0.4,2.5,0.6c0.6,0.2,1.3,0.3,1.9,0.5
c0.4,0.1,0.9,0.2,1.3,0.3c0.9,0.2,1.8,0.4,2.7,0.5c0.7,0.1,1.5,0.3,2.2,0.4c0.7,0.1,1.3,0.4,1.8,0.9c1,1.1,2.1,2.2,3.4,3.2
c1.6,1.3,3.3,2.2,5.1,3c-0.3,0.6-0.5,1.2-0.7,1.8c-0.1,0.4-0.3,0.9-0.4,1.3c-0.7,3.2-0.3,6.5,1.1,9.3c1.3,2.6,3.4,4.5,6,5.7
c0.7,0.3,1.3,0.5,1.9,0.7c0.1,0,0.2,0,0.3,0.1l0.1,0c0.8,0.2,1.7,0.3,2.6,0.4c0.3,0,0.7,0,1,0c1.2,0,2.4-0.1,3.6-0.3
c0.5-0.1,0.9-0.2,1.4-0.3c0.4-0.1,0.8-0.2,1.3-0.3c0.7-0.2,1.3-0.4,1.9-0.6c4.5-1.7,7.7-4.6,8.8-8c0.5,0.2,0.9,0.4,1.4,0.6
c0.3,0.1,0.6,0.2,0.9,0.3c0.3,0.1,0.6,0.2,0.9,0.3c0.4,0.1,0.7,0.2,1.1,0.3c1.3,0.3,2.4,0.5,3.5,0.5c1.6,0,3-0.4,4-1.1
c1.2-0.9,2-2.2,2.2-3.9c0.5-4.6-3.5-11.8-5.9-15.6c-0.6-0.9-1.2-1.8-1.8-2.7c-0.4-0.6-0.8-1.2-1.3-1.8c-0.5-0.7-1-1.3-1.4-1.9
c-1.7-2.1-3.3-4.1-5-5.9c-1-1-2-2-2.9-2.8l-0.4-0.4c-0.7-0.6-1.4-1.1-2.2-1.7c-1.2-0.9-2.5-1.6-3.6-2.2c-1.5-0.7-3-1.4-4.4-2.2
c-4.6-2.8-11-3.6-15.9-4.1c-0.6-0.1-1.1,0.2-1.4,0.5c-0.4,0.4-0.4,1.1-0.1,1.6c0.2,0.3,0.3,0.6,0.5,0.9c0.1,0.3,0,0.5-0.1,0.7
c-0.1,0.1-0.3,0.2-0.5,0.2c-0.8-0.1-1.6-0.2-2.3-0.3c-2.4-0.3-5-0.6-7.7-0.7c-0.6,0-1.2,0.3-1.5,0.8c-0.3,0.5-0.2,1.2,0.3,1.7
c0.5,0.5,0.8,0.9,0.9,1.4c0,0.2,0,0.4-0.2,0.5c-0.1,0.1-0.2,0.2-0.5,0.1c-2.2-0.3-4.5-0.4-6.9-0.2c-0.3,0-0.7,0.1-1,0.1
c-0.5,0.1-1,0.3-1.2,0.7c0,0,0,0.1,0,0.1c-0.2,0.5-0.1,1.2,0.4,1.6c0.5,0.5,0.6,1,0.7,1.7c0,0.2,0,0.4-0.2,0.5
c-0.1,0.1-0.3,0.2-0.4,0.2c-2.6,0-5.2,0.1-8.2,0.8c-0.7,0.1-1.1,0.6-1.2,1.2c-0.1,0.6,0.3,1.2,0.9,1.5c0.5,0.2,0.8,0.5,0.9,1
c0.1,0.2,0,0.4-0.1,0.5c-0.1,0.1-0.2,0.2-0.4,0.2c-0.3,0-0.5,0.1-0.8,0.1l-0.1,0l-0.1,0.1C75.8,149.3,75.5,150,75.8,150.6z"/>
<path d="M113.5,170.2c0.1-0.3,0.1-0.6,0.2-0.8c0.7-2.3,2.2-4.2,4.2-5.3c1.3-0.8,2.7-1.2,4.1-1.2c0.7-0.3,1.5-0.5,2.3-0.5
c2.8,0,5.1,1.9,5.6,4.5c0,0,0.1,0.1,0.1,0.1c0.1,0.2,0.3,0.3,0.4,0.5c1.8,2.3,2.5,4.7,1.8,6.7c-0.6,2-2.6,3.7-5.5,4.8
c-0.4,0.2-0.8,0.3-1.2,0.4c-0.3,0.1-0.6,0.2-0.9,0.2c-0.3,0.1-0.6,0.1-0.9,0.2c-1.1,0.2-2.1,0.2-3.1,0.2c-0.6,0-1.1-0.1-1.6-0.2
c-0.1,0-0.2,0-0.2-0.1c-0.4-0.1-0.8-0.2-1.1-0.4c-1.5-0.7-2.7-1.8-3.5-3.4C113.3,174.2,113.1,172.2,113.5,170.2z"/>
<ellipse class="st5" cx="124.3" cy="167.9" rx="3.6" ry="3.4"/>
</g>
<path class="st5" d="M180.8,200.3c-6.3-7.2-13.5-9.2-20.8-8.8c-7.3-0.5-14.5,1.6-20.8,8.8c-4.4,0.9-21.1,5.3-20.9,24.5
c0.2,10,5.8,17.7,13.1,21.7l0.1-0.7c0-0.2,0.1-0.3,0.2-0.4c0.1-0.1,0.3-0.2,0.5-0.1c1.8,0.2,2.8,0.8,3.2,1.9
c0.1,0.4,0.1,0.7,0.1,1.1c0,0,0.1,0,0.1,0c1.1,5.9,5.4,11.7,11.9,14.7c3.9,1.8,8.2,2.4,12.5,2.1c4.3,0.3,8.7-0.3,12.5-2.1
c6.5-3,10.9-8.7,11.9-14.7c0,0,0.1,0,0.1,0c-0.1-0.4,0-0.8,0.1-1.1c0.3-1,1.4-1.7,3.2-1.9c0.2,0,0.3,0,0.5,0.1
c0.1,0.1,0.2,0.3,0.2,0.4l0.1,0.7c7.3-4,12.9-11.7,13.1-21.7C202,205.6,185.2,201.2,180.8,200.3z"/>
<path class="st4" d="M173.6,209.9c0-0.1,0-0.2,0-0.3c-0.1-0.6-0.2-1.1-0.3-1.6c-0.7-2.3-2.3-4.3-4.6-5.8c-2.4-1.6-5.5-2.5-8.6-2.6
c-0.2,0-0.5,0-0.7,0c-0.5,0-1,0-1.5,0.1c-4,0.3-7.6,1.8-10.1,4.1c-2.5,2.3-3.7,5.2-3.4,8.1c0,0.4,0.1,0.8,0.2,1.2
c0.1,0.5,0.3,1,0.5,1.6c0.2,0.5,0.4,1,0.6,1.5c0.6,1.3,1.5,2.6,2.4,3.8c0.2,0.2,0.3,0.4,0.5,0.6c0.2,0.2,0.4,0.4,0.6,0.6
c0.2,0.2,0.5,0.5,0.7,0.7c3.1,3,6.8,4.6,10.2,4.5c0.2,0,0.3,0,0.5,0c3.5-0.3,7-2.5,9.6-6c0.4-0.5,0.7-1,1-1.6
c0.2-0.4,0.4-0.7,0.6-1.1c0.2-0.4,0.4-0.8,0.6-1.2c0.6-1.4,1-2.8,1.2-4.1C173.6,211.4,173.6,210.7,173.6,209.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -10,6 +10,8 @@
--primary: var(--bs-primary); --primary: var(--bs-primary);
--secondary: var(--bs-secondary); --secondary: var(--bs-secondary);
--text-color: var(--bs-body-color); --text-color: var(--bs-body-color);
--highlight: #d76f14;
--disabled: #ededed;
--border-radius: 0.2rem; --border-radius: 0.2rem;
--input-padding: 0.25rem 0.5rem; --input-padding: 0.25rem 0.5rem;
--font-size: 0.85rem; --font-size: 0.85rem;
@ -47,6 +49,10 @@ a:hover {
text-decoration: none; text-decoration: none;
} }
input[type="radio"] {
margin: 0 0.1rem 0 0.75rem;
}
/* /*
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Tables Tables
@ -143,10 +149,6 @@ select {
align-items: center; align-items: center;
} }
.dropzone label {
padding: 0 0.5rem;
}
.dropzone p, .dropzone p,
.dropzone .dz-default { .dropzone .dz-default {
flex: 0 0 100%; flex: 0 0 100%;
@ -296,7 +298,7 @@ div.header div.authentication-disabled a {
div.header div.title a { div.header div.title a {
display: block; display: block;
background: url("/static/logo.png") no-repeat; background: url("/static/logo.svg") no-repeat;
background-size: auto 2rem; background-size: auto 2rem;
background-position: 1rem center; background-position: 1rem center;
padding: 1rem 1rem 1rem 3.5rem; padding: 1rem 1rem 1rem 3.5rem;
@ -367,7 +369,7 @@ div.header div.authentication-disabled a {
div.header div.title a { div.header div.title a {
display: inline-block; display: inline-block;
background: url("/static/logo.png") no-repeat; background: url("/static/logo.svg") no-repeat;
background-size: auto 40px; background-size: auto 40px;
background-position: left center; background-position: left center;
padding-left: 3rem; padding-left: 3rem;
@ -380,15 +382,7 @@ div.header div.authentication-disabled a {
@supports (-webkit-background-clip: text) { @supports (-webkit-background-clip: text) {
div.header div.title a:hover h1 { div.header div.title a:hover h1 {
background: linear-gradient( background: var(--highlight);
to right,
rgb(101 204 51 / 100%) 0%,
rgb(255 204 51 / 100%) 10%,
rgb(255 153 51 / 100%) 20%,
rgb(205 51 50 / 100%) 55%,
rgb(152 50 153 / 100%) 100%
);
-webkit-background-clip: text; /* stylelint-disable-line */ -webkit-background-clip: text; /* stylelint-disable-line */
-webkit-text-fill-color: transparent; /* stylelint-disable-line */ -webkit-text-fill-color: transparent; /* stylelint-disable-line */
} }
@ -619,7 +613,7 @@ table#attached-devices span.filename {
} }
table#attached-devices tr.reserved td { table#attached-devices tr.reserved td {
background-color: #ffe9e9; background-color: var(--disabled);
} }
@media (max-width: 900px) { @media (max-width: 900px) {

View File

@ -1,7 +1,7 @@
<!doctype html> <!doctype html>
<html lang="{{ env["locale"] }}"> <html lang="{{ env["locale"] }}">
<head> <head>
<title>{{ _("PiSCSI Control Page") }} [{{ env["host"] }}]</title> <title>{{ page_title }} [{{ env["host"] }}]</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="apple-touch-icon" sizes="57x57" href="/pwa/apple-icon-57x57.png"> <link rel="apple-touch-icon" sizes="57x57" href="/pwa/apple-icon-57x57.png">

View File

@ -13,7 +13,7 @@
</details> </details>
<p> <p>
<form action="/config/load" method="post" id="config-actions"> <form action="/config/action" method="post" id="config-actions">
<label for="config_load_name">{{ _("File Name:") }}</label> <label for="config_load_name">{{ _("File Name:") }}</label>
<select name="name" id="config_load_name" required="" width="14"> <select name="name" id="config_load_name" required="" width="14">
{% if config_files %} {% if config_files %}
@ -30,6 +30,7 @@
</select> </select>
<input name="load" type="submit" value="{{ _("Load") }}" onclick="return confirm('{{ _("Detach all current device and Load configuration?") }}')"> <input name="load" type="submit" value="{{ _("Load") }}" onclick="return confirm('{{ _("Detach all current device and Load configuration?") }}')">
<input name="delete" type="submit" value="{{ _("Delete") }}" onclick="return confirm('{{ _("Delete configuration file?") }}')"> <input name="delete" type="submit" value="{{ _("Delete") }}" onclick="return confirm('{{ _("Delete configuration file?") }}')">
<input name="send" type="submit" value="{{ _("Download") }}">
</form> </form>
</p> </p>
@ -222,8 +223,8 @@
{% for key in file["prop"] %} {% for key in file["prop"] %}
<li>{{ key }}: {{ file['prop'][key] }}</li> <li>{{ key }}: {{ file['prop'][key] }}</li>
{% endfor %} {% endfor %}
<form action="/files/download" method="post"> <form action="/files/download_config" method="post">
<input name="file" type="hidden" value="{{ CFG_DIR }}/{{ file['name'].replace(env['image_dir'], '') }}.{{ PROPERTIES_SUFFIX }}"> <input name="file" type="hidden" value="{{ file['name'] }}.{{ PROPERTIES_SUFFIX }}">
<input type="submit" value="{{ _("Properties File") }} &#8595;"> <input type="submit" value="{{ _("Properties File") }} &#8595;">
</form> </form>
</ul> </ul>
@ -271,7 +272,7 @@
<td>{{ file["name"] }}</td> <td>{{ file["name"] }}</td>
{% endif %} {% endif %}
<td align="center"> <td align="center">
<form action="/files/download" method="post"> <form action="/files/download_image" method="post">
<input name="file" type="hidden" value="{{ file['name'] }}"> <input name="file" type="hidden" value="{{ file['name'] }}">
<input type="submit" value="{{ file['size_mb'] }} {{ _("MiB") }} &#8595;"> <input type="submit" value="{{ file['size_mb'] }} {{ _("MiB") }} &#8595;">
</form> </form>
@ -368,10 +369,10 @@
<form action="/files/download_url" method="post"> <form action="/files/download_url" method="post">
<label for="download_url">{{ _("Download file from URL:") }}</label> <label for="download_url">{{ _("Download file from URL:") }}</label>
<input name="url" id="download_url" required="" type="url"> <input name="url" id="download_url" required="" type="url">
<label for="disk_images">{{ _("Disk Images") }}</label>
<input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked"> <input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked">
<label for="shared_files">{{ _("Shared Files") }}</label> <label for="disk_images">{{ _("Disk Images") }}</label>
<input type="radio" name="destination" id="shared_files" value="shared_files"> <input type="radio" name="destination" id="shared_files" value="shared_files">
<label for="shared_files">{{ _("Shared Files") }}</label>
<input type="submit" value="{{ _("Download") }}" onclick="processNotify('{{ _("Downloading File...") }}')"> <input type="submit" value="{{ _("Download") }}" onclick="processNotify('{{ _("Downloading File...") }}')">
</form> </form>
</section> </section>
@ -382,6 +383,145 @@
<hr/> <hr/>
<section id="create-iso">
<details>
<summary class="heading">
{{ _("Create CD-ROM Image") }}
</summary>
<ul>
<li>{{ _("HFS is for Mac OS, Joliet for Windows, and Rock Ridge for POSIX.") }}</li>
<li>{{ _("If the downloaded file is a zip archive, we will attempt to unzip it and store the resulting files.") }}</li>
</ul>
</details>
<div>
<form action="/files/create_iso" method="post">
<label for="iso_url">{{ _("Download file from URL:") }}</label>
<input name="url" id="iso_url" required="" type="url">
<label for="iso_url_type">{{ _("Type:") }}</label>
<select name="type" id="iso_url_type">
<option value="HFS">
HFS
</option>
<option value="ISO-9660 Level 1">
ISO-9660 Level 1
</option>
<option value="ISO-9660 Level 2">
ISO-9660 Level 2
</option>
<option value="ISO-9660 Level 3">
ISO-9660 Level 3
</option>
<option value="Joliet">
Joliet
</option>
<option value="Rock Ridge">
Rock Ridge
</option>
</select>
<input type="submit" value="{{ _("Create") }}" onclick="processNotify('{{ _("Downloading file and generating CD-ROM image...") }}')">
</form>
</div>
<div>
<form action="/files/create_iso" method="post">
<label for="iso_file">{{ _("Use local file:") }}</label>
<select name="file" id="iso_file">
{% for f in files|sort(attribute='name') %}
<option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
{% endfor %}
</select>
<label for="iso_file_type">{{ _("Type:") }}</label>
<select name="type" id="iso_file_type">
<option value="HFS">
HFS
</option>
<option value="ISO-9660 Level 1">
ISO-9660 Level 1
</option>
<option value="ISO-9660 Level 2">
ISO-9660 Level 2
</option>
<option value="ISO-9660 Level 3">
ISO-9660 Level 3
</option>
<option value="Joliet">
Joliet
</option>
<option value="Rock Ridge">
Rock Ridge
</option>
</select>
<input type="submit" value="{{ _("Create") }}" onclick="processNotify('{{ _("Generating CD-ROM image...") }}')">
</form>
</div>
</section>
<hr/>
<section id="create-image">
<details>
<summary class="heading">
{{ _("Create Empty Disk Image") }}
</summary>
<ul>
<li>{{ _("Please refer to <a href=\"%(url)s\" target=\"_blank\">wiki documentation</a> to learn more about the supported image file types.", url="https://github.com/PiSCSI/piscsi/wiki/Supported-Device-Types#image-types") }}</li>
<li>{{ _("It is not recommended to use the Lido hard disk driver with the Macintosh Plus.") }}</li>
</ul>
</details>
<form action="/files/create" method="post">
<label for="image_create_file_name">{{ _("File Name:") }}</label>
<input name="file_name" id="image_create_file_name" required="" type="text">
<label for="image_create_type">{{ _("Type:") }}</label>
<select name="type" id="image_create_type">
{% for key, value in image_suffixes_to_create.items() %}
<option value="{{ key }}">
{{ value }} [.{{ key }}]
</option>
{% endfor %}
</select>
<label for="image_create_size">{{ _("Size:") }}</label>
<input name="size" id="image_create_size" type="number" placeholder="{{ _("MiB") }}" min="1" max="262144" required>
<label for="image_create_drive_name">{{ _("Masquerade as:") }}</label>
<select name="drive_name" id="image_create_drive_name">
<option value="">
{{ _("None") }}
</option>
{% for drive in drive_properties["hd_conf"] | sort(attribute='name') %}
<option value="{{ drive.name }}">
{{ drive.name }}
</option>
{% endfor %}
</select>
<label for="drive_format">{{ _("Format as:") }}</label>
<select name="drive_format" id="drive_format">
<option value="">
{{ _("None") }}
</option>
<option value="Lido 7.56">
HFS + Lido
</option>
<option value="SpeedTools 3.6">
HFS + SpeedTools
</option>
<option value="FAT16">
FAT16
</option>
<option value="FAT32">
FAT32
</option>
</select>
<input type="submit" value="{{ _("Create") }}">
</form>
</section>
<section id="create-drive">
<a href="/drive/list"><p>{{ _("Create Disk Image With Properties") }}</p></a>
</section>
<hr/>
<section id="logging">
<section id="attach-devices"> <section id="attach-devices">
<details> <details>
<summary class="heading"> <summary class="heading">
@ -482,120 +622,6 @@
<hr/> <hr/>
<section id="download-to-iso">
<details>
<summary class="heading">
{{ _("Download File and Create CD-ROM Image") }}
</summary>
<ul>
<li>{{ _("Create an ISO file system CD-ROM image with the downloaded file, and mount it on the given SCSI ID.") }}</li>
<li>{{ _("HFS is for Mac OS, Joliet for Windows, and Rock Ridge for POSIX.") }}</li>
<li>{{ _("If the downloaded file is a zip archive, we will attempt to unzip it and store the resulting files.") }}</li>
</ul>
</details>
<form action="/files/download_to_iso" method="post">
<label for="iso_url">{{ _("Download file from URL:") }}</label>
<input name="url" id="iso_url" required="" type="url">
<label for="iso_type">{{ _("Type:") }}</label>
<select name="type" id="iso_type">
<option value="HFS">
HFS
</option>
<option value="ISO-9660 Level 1">
ISO-9660 Level 1
</option>
<option value="ISO-9660 Level 2">
ISO-9660 Level 2
</option>
<option value="ISO-9660 Level 3">
ISO-9660 Level 3
</option>
<option value="Joliet">
Joliet
</option>
<option value="Rock Ridge">
Rock Ridge
</option>
</select>
<label for="iso_scsi_id">{{ _("ID") }}</label>
<select name="scsi_id" id="iso_scsi_id">
{% for id in scsi_ids["valid_ids"] %}
<option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}>
{{ id }}
</option>
{% endfor %}
</select>
<input type="submit" value="{{ _("Download and Mount CD-ROM image") }}" onclick="processNotify('{{ _("Downloading File and generating CD-ROM image...") }}')">
</form>
</section>
<hr/>
<section id="create-image">
<details>
<summary class="heading">
{{ _("Create Empty Disk Image File") }}
</summary>
<ul>
<li>{{ _("Please refer to <a href=\"%(url)s\" target=\"_blank\">wiki documentation</a> to learn more about the supported image file types.", url="https://github.com/PiSCSI/piscsi/wiki/Supported-Device-Types#image-types") }}</li>
<li>{{ _("It is not recommended to use the Lido hard disk driver with the Macintosh Plus.") }}</li>
</ul>
</details>
<form action="/files/create" method="post">
<label for="image_create_file_name">{{ _("File Name:") }}</label>
<input name="file_name" id="image_create_file_name" required="" type="text">
<label for="image_create_type">{{ _("Type:") }}</label>
<select name="type" id="image_create_type">
{% for key, value in image_suffixes_to_create.items() %}
<option value="{{ key }}">
{{ value }} [.{{ key }}]
</option>
{% endfor %}
</select>
<label for="image_create_size">{{ _("Size:") }}</label>
<input name="size" id="image_create_size" type="number" placeholder="{{ _("MiB") }}" min="1" max="262144" required>
<label for="image_create_drive_name">{{ _("Masquerade as:") }}</label>
<select name="drive_name" id="image_create_drive_name">
<option value="">
{{ _("None") }}
</option>
{% for drive in drive_properties["hd_conf"] | sort(attribute='name') %}
<option value="{{ drive.name }}">
{{ drive.name }}
</option>
{% endfor %}
</select>
<label for="drive_format">{{ _("Format as:") }}</label>
<select name="drive_format" id="drive_format">
<option value="">
{{ _("None") }}
</option>
<option value="Lido 7.56">
HFS + Lido
</option>
<option value="SpeedTools 3.6">
HFS + SpeedTools
</option>
<option value="FAT16">
FAT16
</option>
<option value="FAT32">
FAT32
</option>
</select>
<input type="submit" value="{{ _("Create") }}">
</form>
</section>
<section id="create-drive">
<a href="/drive/list"><p>{{ _("Create Disk Image With Properties") }}</p></a>
</section>
<hr/>
<section id="logging">
<details> <details>
<summary class="heading"> <summary class="heading">
{{ _("Logging") }} {{ _("Logging") }}

View File

@ -7,14 +7,17 @@
<li>{{ _("You have to manually clean up partially uploaded files, as a result of cancelling the upload or closing this page.") }}</li> <li>{{ _("You have to manually clean up partially uploaded files, as a result of cancelling the upload or closing this page.") }}</li>
<li>{{ _("Disk Images") }} = {{ env["image_dir"] }}</li> <li>{{ _("Disk Images") }} = {{ env["image_dir"] }}</li>
<li>{{ _("Shared Files") }} = {{ FILE_SERVER_DIR }}</li> <li>{{ _("Shared Files") }} = {{ FILE_SERVER_DIR }}</li>
<li>{{ _("PiSCSI Config") }} = {{ CFG_DIR }}</li>
</ul> </ul>
<h3>{{ _("Destination") }}</h3> <h3>{{ _("Destination") }}</h3>
<form name="dropper" action="/files/upload" method="post" class="dropzone dz-clickable" enctype="multipart/form-data" id="dropper"> <form name="dropper" action="/files/upload" method="post" class="dropzone dz-clickable" enctype="multipart/form-data" id="dropper">
<label for="disk_images">{{ _("Disk Images") }}</label>
<input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked"> <input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked">
<label for="shared_files">{{ _("Shared Files") }}</label> <label for="disk_images">{{ _("Disk Images") }}</label>
<input type="radio" name="destination" id="shared_files" value="shared_files"> <input type="radio" name="destination" id="shared_files" value="shared_files">
<label for="shared_files">{{ _("Shared Files") }}</label>
<input type="radio" name="destination" id="piscsi_config" value="piscsi_config">
<label for="piscsi_config">{{ _("PiSCSI Config") }}</label>
</form> </form>
<script type="application/javascript"> <script type="application/javascript">

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -260,6 +260,7 @@ def index():
return response( return response(
template="index.html", template="index.html",
page_title=_("PiSCSI Control Page"),
locales=get_supported_locales(), locales=get_supported_locales(),
netinfo=piscsi_cmd.get_network_info(), netinfo=piscsi_cmd.get_network_info(),
bridge_configured=sys_cmd.is_bridge_setup(), bridge_configured=sys_cmd.is_bridge_setup(),
@ -305,6 +306,7 @@ def drive_list():
return response( return response(
template="drives.html", template="drives.html",
page_title=_("PiSCSI Create Drive"),
files=file_cmd.list_images()["files"], files=file_cmd.list_images()["files"],
drive_properties=format_drive_properties(APP.config["PISCSI_DRIVE_PROPERTIES"]), drive_properties=format_drive_properties(APP.config["PISCSI_DRIVE_PROPERTIES"]),
) )
@ -318,7 +320,9 @@ def upload_page():
return response( return response(
template="upload.html", template="upload.html",
page_title=_("PiSCSI File Upload"),
max_file_size=int(int(MAX_FILE_SIZE) / 1024 / 1024), max_file_size=int(int(MAX_FILE_SIZE) / 1024 / 1024),
CFG_DIR=CFG_DIR,
FILE_SERVER_DIR=FILE_SERVER_DIR, FILE_SERVER_DIR=FILE_SERVER_DIR,
) )
@ -385,7 +389,7 @@ def drive_create():
Creates the image and properties file pair Creates the image and properties file pair
""" """
drive_name = request.form.get("drive_name") drive_name = request.form.get("drive_name")
file_name = Path(request.form.get("file_name")).name file_name = Path(request.form.get("file_name"))
properties = get_properties_by_drive_name(APP.config["PISCSI_DRIVE_PROPERTIES"], drive_name) properties = get_properties_by_drive_name(APP.config["PISCSI_DRIVE_PROPERTIES"], drive_name)
@ -396,11 +400,12 @@ def drive_create():
) )
# Creating the image file # Creating the image file
process = file_cmd.create_new_image( server_info = piscsi_cmd.get_server_info()
file_name, process = file_cmd.create_empty_image(
properties["file_type"], Path(server_info["image_dir"]) / f"{file_name}.{properties['file_type']}",
properties["size"], properties["size"],
) )
process = ReturnCodeMapper.add_msg(process)
if not process["status"]: if not process["status"]:
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
@ -427,7 +432,7 @@ def drive_cdrom():
Creates a properties file for a CD-ROM image Creates a properties file for a CD-ROM image
""" """
drive_name = request.form.get("drive_name") drive_name = request.form.get("drive_name")
file_name = Path(request.form.get("file_name")).name file_name = Path(request.form.get("file_name"))
# Creating the drive properties file # Creating the drive properties file
file_name = f"{file_name}.{PROPERTIES_SUFFIX}" file_name = f"{file_name}.{PROPERTIES_SUFFIX}"
@ -463,13 +468,16 @@ def config_save():
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
@APP.route("/config/load", methods=["POST"]) @APP.route("/config/action", methods=["POST"])
@login_required @login_required
def config_load(): def config_action():
""" """
Loads a config file from disk Carries out on an operation on the config file
""" """
file_name = Path(request.form.get("name")).name file_name = Path(request.form.get("name"))
safe_path = is_safe_path(file_name)
if not safe_path["status"]:
return response(error=True, message=safe_path["msg"])
if "load" in request.form: if "load" in request.form:
process = file_cmd.read_config(file_name) process = file_cmd.read_config(file_name)
@ -480,15 +488,20 @@ def config_load():
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
if "delete" in request.form: if "delete" in request.form:
file_path = Path(CFG_DIR) / file_name process = file_cmd.delete_file(Path(CFG_DIR) / file_name)
process = file_cmd.delete_file(file_path)
process = ReturnCodeMapper.add_msg(process) process = ReturnCodeMapper.add_msg(process)
if process["status"]: if process["status"]:
return response(message=process["msg"]) return response(message=process["msg"])
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
return response(error=True, message="Action field (load, delete) missing") if "send" in request.form:
return send_from_directory(CFG_DIR, str(file_name), as_attachment=True)
return response(
error=True,
message="No known operation in request header. Expected one of: load, delete, send",
)
@APP.route("/files/diskinfo", methods=["POST"]) @APP.route("/files/diskinfo", methods=["POST"])
@ -505,6 +518,7 @@ def show_diskinfo():
if returncode == 0: if returncode == 0:
return response( return response(
template="diskinfo.html", template="diskinfo.html",
page_title=_("PiSCSI Image Info"),
file_name=str(file_name), file_name=str(file_name),
diskinfo=diskinfo, diskinfo=diskinfo,
) )
@ -552,13 +566,14 @@ def show_manpage():
return response( return response(
template="manpage.html", template="manpage.html",
page_title=_("PiSCSI Manual"),
app=app, app=app,
manpage=formatted_manpage, manpage=formatted_manpage,
) )
return response( return response(
error=True, error=True,
message=_("An error occurred when accessing man page: %(error)s", error=manpage), message=_("An error occurred when accessing manual page: %(error)s", error=manpage),
) )
@ -574,6 +589,7 @@ def show_logs():
if returncode == 0: if returncode == 0:
return response( return response(
template="logs.html", template="logs.html",
page_title=_("PiSCSI System Logs"),
scope=scope, scope=scope,
lines=lines, lines=lines,
logs=logs, logs=logs,
@ -791,6 +807,7 @@ def device_info():
if process["status"]: if process["status"]:
return response( return response(
template="deviceinfo.html", template="deviceinfo.html",
page_title=_("PiSCSI Device Info"),
devices=process["device_list"], devices=process["device_list"],
) )
@ -879,15 +896,15 @@ def shutdown():
return response(error=True, message=message) return response(error=True, message=message)
@APP.route("/files/download_to_iso", methods=["POST"]) @APP.route("/files/create_iso", methods=["POST"])
@login_required @login_required
def download_to_iso(): def download_to_iso():
""" """
Downloads a file and creates a CD-ROM image with the specified file system and the file Downloads a file and creates a CD-ROM image with the specified file system and the file
""" """
scsi_id = request.form.get("scsi_id")
url = request.form.get("url") url = request.form.get("url")
iso_type = request.form.get("type") iso_type = request.form.get("type")
local_file = request.form.get("file")
if iso_type == "HFS": if iso_type == "HFS":
iso_args = ["-hfs"] iso_args = ["-hfs"]
@ -907,7 +924,14 @@ def download_to_iso():
message=_("%(iso_type)s is not a valid CD-ROM format.", iso_type=iso_type), message=_("%(iso_type)s is not a valid CD-ROM format.", iso_type=iso_type),
) )
process = file_cmd.download_file_to_iso(url, *iso_args) if url:
process = file_cmd.download_file_to_iso(url, *iso_args)
elif local_file:
server_info = piscsi_cmd.get_server_info()
file_path = Path(server_info["image_dir"]) / local_file
iso_path = Path(str(file_path) + ".iso")
process = file_cmd.generate_iso(iso_path, file_path, *iso_args)
process = ReturnCodeMapper.add_msg(process) process = ReturnCodeMapper.add_msg(process)
if not process["status"]: if not process["status"]:
return response( return response(
@ -918,31 +942,11 @@ def download_to_iso():
), ),
) )
process_attach = piscsi_cmd.attach_device(
scsi_id,
device_type="SCCD",
params={"file": process["file_name"]},
)
process_attach = ReturnCodeMapper.add_msg(process_attach)
if process_attach["status"]:
return response(
message=_(
"CD-ROM image %(file_name)s with type %(iso_type)s was created "
"and attached to SCSI ID %(id_number)s",
file_name=process["file_name"],
iso_type=iso_type,
id_number=scsi_id,
),
)
return response( return response(
error=True,
message=_( message=_(
"CD-ROM image %(file_name)s with type %(iso_type)s was created " "CD-ROM image %(file_name)s with type %(iso_type)s was created.",
"but could not be attached: %(error)s",
file_name=process["file_name"], file_name=process["file_name"],
iso_type=iso_type, iso_type=iso_type,
error=process_attach["msg"],
), ),
) )
@ -986,11 +990,16 @@ def upload_file():
return make_response(auth["msg"], 403) return make_response(auth["msg"], 403)
destination = request.form.get("destination") destination = request.form.get("destination")
if destination == "file_server": if destination == "disk_images":
destination_dir = FILE_SERVER_DIR
else:
server_info = piscsi_cmd.get_server_info() server_info = piscsi_cmd.get_server_info()
destination_dir = server_info["image_dir"] destination_dir = server_info["image_dir"]
elif destination == "shared_files":
destination_dir = FILE_SERVER_DIR
elif destination == "piscsi_config":
destination_dir = CFG_DIR
else:
return make_response("Invalid destination", 403)
return upload_with_dropzonejs(destination_dir) return upload_with_dropzonejs(destination_dir)
@ -1010,7 +1019,10 @@ def create_file():
if not safe_path["status"]: if not safe_path["status"]:
return response(error=True, message=safe_path["msg"]) return response(error=True, message=safe_path["msg"])
full_file_name = f"{file_name}.{file_type}" full_file_name = f"{file_name}.{file_type}"
process = file_cmd.create_new_image(str(file_name), file_type, size)
server_info = piscsi_cmd.get_server_info()
process = file_cmd.create_empty_image(Path(server_info["image_dir"]) / full_file_name, size)
process = ReturnCodeMapper.add_msg(process)
if not process["status"]: if not process["status"]:
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
@ -1107,11 +1119,11 @@ def create_file():
) )
@APP.route("/files/download", methods=["POST"]) @APP.route("/files/download_image", methods=["POST"])
@login_required @login_required
def download(): def download_image():
""" """
Downloads a file from the system to the local computer Downloads a file from the image dir to the local computer
""" """
file_name = Path(request.form.get("file")) file_name = Path(request.form.get("file"))
safe_path = is_safe_path(file_name) safe_path = is_safe_path(file_name)
@ -1121,6 +1133,19 @@ def download():
return send_from_directory(server_info["image_dir"], str(file_name), as_attachment=True) return send_from_directory(server_info["image_dir"], str(file_name), as_attachment=True)
@APP.route("/files/download_config", methods=["POST"])
@login_required
def download_config():
"""
Downloads a file from the config dir to the local computer
"""
file_name = Path(request.form.get("file"))
safe_path = is_safe_path(file_name)
if not safe_path["status"]:
return response(error=True, message=safe_path["msg"])
return send_from_directory(CFG_DIR, str(file_name), as_attachment=True)
@APP.route("/files/delete", methods=["POST"]) @APP.route("/files/delete", methods=["POST"])
@login_required @login_required
def delete(): def delete():
@ -1131,7 +1156,9 @@ def delete():
safe_path = is_safe_path(file_name) safe_path = is_safe_path(file_name)
if not safe_path["status"]: if not safe_path["status"]:
return response(error=True, message=safe_path["msg"]) return response(error=True, message=safe_path["msg"])
process = file_cmd.delete_image(str(file_name)) server_info = piscsi_cmd.get_server_info()
process = file_cmd.delete_file(Path(server_info["image_dir"]) / file_name)
process = ReturnCodeMapper.add_msg(process)
if not process["status"]: if not process["status"]:
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
@ -1172,7 +1199,12 @@ def rename():
safe_path = is_safe_path(new_file_name) safe_path = is_safe_path(new_file_name)
if not safe_path["status"]: if not safe_path["status"]:
return response(error=True, message=safe_path["msg"]) return response(error=True, message=safe_path["msg"])
process = file_cmd.rename_image(str(file_name), str(new_file_name)) server_info = piscsi_cmd.get_server_info()
process = file_cmd.rename_file(
Path(server_info["image_dir"]) / str(file_name),
Path(server_info["image_dir"]) / str(new_file_name),
)
process = ReturnCodeMapper.add_msg(process)
if not process["status"]: if not process["status"]:
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])
@ -1214,7 +1246,12 @@ def copy():
safe_path = is_safe_path(new_file_name) safe_path = is_safe_path(new_file_name)
if not safe_path["status"]: if not safe_path["status"]:
return response(error=True, message=safe_path["msg"]) return response(error=True, message=safe_path["msg"])
process = file_cmd.copy_image(str(file_name), str(new_file_name)) server_info = piscsi_cmd.get_server_info()
process = file_cmd.copy_file(
Path(server_info["image_dir"]) / str(file_name),
Path(server_info["image_dir"]) / str(new_file_name),
)
process = ReturnCodeMapper.add_msg(process)
if not process["status"]: if not process["status"]:
return response(error=True, message=process["msg"]) return response(error=True, message=process["msg"])

View File

@ -3,7 +3,6 @@ import uuid
import os import os
from conftest import ( from conftest import (
SCSI_ID,
FILE_SIZE_1_MIB, FILE_SIZE_1_MIB,
STATUS_SUCCESS, STATUS_SUCCESS,
) )
@ -254,6 +253,7 @@ def test_upload_file(http_client, delete_file):
chunk_byte_offset = chunk_number * chunk_size chunk_byte_offset = chunk_number * chunk_size
form_data = { form_data = {
"destination": "disk_images",
"dzuuid": str(uuid.uuid4()), "dzuuid": str(uuid.uuid4()),
"dzchunkindex": chunk_number, "dzchunkindex": chunk_number,
"dzchunksize": chunk_size, "dzchunksize": chunk_size,
@ -281,11 +281,11 @@ def test_upload_file(http_client, delete_file):
delete_file(file_name) delete_file(file_name)
# route("/files/download", methods=["POST"]) # route("/files/download_image", methods=["POST"])
def test_download_file(http_client, create_test_image): def test_download_image(http_client, create_test_image):
file_name = create_test_image() file_name = create_test_image()
response = http_client.post("/files/download", data={"file": file_name}) response = http_client.post("/files/download_image", data={"file": file_name})
assert response.status_code == 200 assert response.status_code == 200
assert response.headers["content-type"] == "application/octet-stream" assert response.headers["content-type"] == "application/octet-stream"
@ -293,6 +293,42 @@ def test_download_file(http_client, create_test_image):
assert response.headers["content-length"] == str(FILE_SIZE_1_MIB) assert response.headers["content-length"] == str(FILE_SIZE_1_MIB)
# route("/files/download_config", methods=["POST"])
def test_download_properties(http_client, list_files, delete_file):
file_prefix = str(uuid.uuid4())
file_name = f"{file_prefix}.hds"
response = http_client.post(
"/files/create",
data={
"file_name": file_prefix,
"type": "hds",
"size": 1,
"drive_name": "Miniscribe M8425",
},
)
response_data = response.json()
assert response.status_code == 201
assert response_data["status"] == STATUS_SUCCESS
assert response_data["data"]["image"] == file_name
assert (
response_data["messages"][0]["message"]
== f"Image file with properties created: {file_name}"
)
assert file_name in list_files()
response = http_client.post("/files/download_config", data={"file": f"{file_name}.properties"})
assert response.status_code == 200
assert response.headers["content-type"] == "application/octet-stream"
assert response.headers["content-disposition"] == f"attachment; filename={file_name}.properties"
# Cleanup
delete_file(file_name)
# route("/files/download_url", methods=["POST"]) # route("/files/download_url", methods=["POST"])
def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_file): def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_file):
file_name = str(uuid.uuid4()) file_name = str(uuid.uuid4())
@ -328,14 +364,11 @@ def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_fi
delete_file(file_name) delete_file(file_name)
# route("/files/download_to_iso", methods=["POST"]) # route("/files/create_iso", methods=["POST"])
def test_download_url_to_iso( def test_create_iso_from_url(
env,
httpserver, httpserver,
http_client, http_client,
list_files, list_files,
list_attached_images,
detach_devices,
delete_file, delete_file,
): ):
test_file_name = str(uuid.uuid4()) test_file_name = str(uuid.uuid4())
@ -354,9 +387,8 @@ def test_download_url_to_iso(
) )
response = http_client.post( response = http_client.post(
"/files/download_to_iso", "/files/create_iso",
data={ data={
"scsi_id": SCSI_ID,
"type": ISO_TYPE, "type": ISO_TYPE,
"url": url, "url": url,
}, },
@ -367,16 +399,48 @@ def test_download_url_to_iso(
assert response.status_code == 200 assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS assert response_data["status"] == STATUS_SUCCESS
assert iso_file_name in list_files() assert iso_file_name in list_files()
assert iso_file_name in list_attached_images()
assert ( assert (
response_data["messages"][0]["message"] response_data["messages"][0]["message"]
== f"CD-ROM image {iso_file_name} with type {ISO_TYPE} was created " == f"CD-ROM image {iso_file_name} with type {ISO_TYPE} was created."
f"and attached to SCSI ID {SCSI_ID}" )
# Cleanup
delete_file(iso_file_name)
# route("/files/create_iso", methods=["POST"])
def test_create_iso_from_local_file(
http_client,
create_test_image,
list_files,
delete_file,
):
test_file_name = create_test_image()
iso_file_name = f"{test_file_name}.iso"
ISO_TYPE = "HFS"
response = http_client.post(
"/files/create_iso",
data={
"type": ISO_TYPE,
"file": test_file_name,
},
)
response_data = response.json()
assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS
assert iso_file_name in list_files()
assert (
response_data["messages"][0]["message"]
== f"CD-ROM image {iso_file_name} with type {ISO_TYPE} was created."
) )
# Cleanup # Cleanup
detach_devices()
delete_file(iso_file_name) delete_file(iso_file_name)

View File

@ -10,7 +10,7 @@ from conftest import STATUS_SUCCESS
[ [
("de", "Webinterface-Sprache auf Deutsch geändert"), ("de", "Webinterface-Sprache auf Deutsch geändert"),
("es", "Se ha cambiado el lenguaje de la Interfaz Web a español"), ("es", "Se ha cambiado el lenguaje de la Interfaz Web a español"),
("fr", "Langue de linterface web changée pour français"), ("fr", "Langue de linterface web changée en français"),
("sv", "Bytte webbgränssnittets språk till svenska"), ("sv", "Bytte webbgränssnittets språk till svenska"),
("en", "Changed Web Interface language to English"), ("en", "Changed Web Interface language to English"),
("zh", "Web 界面语言已更改为 中文"), ("zh", "Web 界面语言已更改为 中文"),
@ -74,7 +74,7 @@ def test_show_logs(http_client):
# route("/config/save", methods=["POST"]) # route("/config/save", methods=["POST"])
# route("/config/load", methods=["POST"]) # route("/config/action", methods=["POST"])
def test_save_load_and_delete_configs(env, http_client): def test_save_load_and_delete_configs(env, http_client):
config_name = str(uuid.uuid4()) config_name = str(uuid.uuid4())
config_json_file = f"{config_name}.json" config_json_file = f"{config_name}.json"
@ -115,7 +115,7 @@ def test_save_load_and_delete_configs(env, http_client):
# Load the saved config # Load the saved config
response = http_client.post( response = http_client.post(
"/config/load", "/config/action",
data={ data={
"name": config_json_file, "name": config_json_file,
"load": True, "load": True,
@ -135,7 +135,7 @@ def test_save_load_and_delete_configs(env, http_client):
# Delete the saved config # Delete the saved config
response = http_client.post( response = http_client.post(
"/config/load", "/config/action",
data={ data={
"name": config_json_file, "name": config_json_file,
"delete": True, "delete": True,
@ -153,6 +153,49 @@ def test_save_load_and_delete_configs(env, http_client):
assert config_json_file not in http_client.get("/").json()["data"]["config_files"] assert config_json_file not in http_client.get("/").json()["data"]["config_files"]
# route("/config/save", methods=["POST"])
# route("/config/action", methods=["POST"])
def test_download_configs(env, http_client, delete_file):
config_name = str(uuid.uuid4())
config_json_file = f"{config_name}.json"
# Save the initial state to a config
response = http_client.post(
"/config/save",
data={
"name": config_name,
},
)
assert response.status_code == 200
assert config_json_file in http_client.get("/").json()["data"]["config_files"]
# Download the saved config
response = http_client.post(
"/config/action",
data={
"name": config_json_file,
"send": True,
},
)
assert response.status_code == 200
assert response.headers["content-type"] == "application/json"
assert response.headers["content-disposition"] == f"attachment; filename={config_json_file}"
# Delete the saved config
response = http_client.post(
"/config/action",
data={
"name": config_json_file,
"delete": True,
},
)
assert response.status_code == 200
assert config_json_file not in http_client.get("/").json()["data"]["config_files"]
# route("/theme", methods=["POST"]) # route("/theme", methods=["POST"])
@pytest.mark.parametrize( @pytest.mark.parametrize(
"theme", "theme",

View File

@ -2,10 +2,16 @@
set -e set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"
# Check for the existence of a python venv in the current dir
# Create the venv if it doesn't exist
if ! test -e venv; then if ! test -e venv; then
echo "No python venv detected. Please run start.sh first." echo "Creating python venv for PiSCSI-Web"
exit 1 python3 -m venv venv
echo "Activating venv"
source venv/bin/activate
echo "Installing requirements.txt"
pip3 install wheel
pip3 install -r requirements.txt
fi fi
source venv/bin/activate source venv/bin/activate