diff --git a/slic3r-1.3.0-fixtest.patch b/slic3r-1.3.0-fixtest.patch new file mode 100644 index 0000000..6fa81bd --- /dev/null +++ b/slic3r-1.3.0-fixtest.patch @@ -0,0 +1,11 @@ +diff -up Slic3r-1.3.0/t/gcode.t.fixtest Slic3r-1.3.0/t/gcode.t +--- Slic3r-1.3.0/t/gcode.t.fixtest 2018-06-25 11:59:06.226705956 -0400 ++++ Slic3r-1.3.0/t/gcode.t 2018-06-25 11:59:42.289840358 -0400 +@@ -186,6 +186,7 @@ use Slic3r::Test; + { + my $config = Slic3r::Config->new_from_defaults; + $config->set('gcode_flavor', 'sailfish'); ++ $config->set('layer_height', '0.4'); + my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale_xyz => [1,1, 1/(20/$config->layer_height) ]); + $test->($print, 'one layer object'); + } diff --git a/slic3r-boolcast.patch b/slic3r-boolcast.patch deleted file mode 100644 index 8fb6c98..0000000 --- a/slic3r-boolcast.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp -index 49e999b..e3344e7 100644 ---- a/xs/src/libslic3r/Config.hpp -+++ b/xs/src/libslic3r/Config.hpp -@@ -65,7 +65,7 @@ class ConfigOptionFloat : public ConfigOption - - bool deserialize(std::string str) { - std::istringstream iss(str); -- return iss >> this->value; -+ return static_cast(iss >> this->value); - }; - }; - -@@ -124,7 +124,7 @@ class ConfigOptionInt : public ConfigOption - - bool deserialize(std::string str) { - std::istringstream iss(str); -- return iss >> this->value; -+ return static_cast(iss >> this->value); - }; - }; - -@@ -249,7 +249,7 @@ class ConfigOptionPercent : public ConfigOption - bool deserialize(std::string str) { - // don't try to parse the trailing % since it's optional - std::istringstream iss(str); -- return iss >> this->value; -+ return static_cast(iss >> this->value); - }; - }; - -@@ -279,7 +279,7 @@ class ConfigOptionFloatOrPercent : public ConfigOption - bool deserialize(std::string str) { - this->percent = str.find_first_of("%") != std::string::npos; - std::istringstream iss(str); -- return iss >> this->value; -+ return static_cast(iss >> this->value); - }; - }; - diff --git a/slic3r-boost160.patch b/slic3r-boost160.patch deleted file mode 100644 index b71af38..0000000 --- a/slic3r-boost160.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp -index f9850c7..9a52f3f 100644 ---- a/xs/src/libslic3r/Point.hpp -+++ b/xs/src/libslic3r/Point.hpp -@@ -128,16 +128,6 @@ class Pointf3 : public Pointf - namespace boost { namespace polygon { - template <> - struct geometry_concept { typedef coordinate_concept type; }; -- -- template <> -- struct coordinate_traits { -- typedef coord_t coordinate_type; -- typedef long double area_type; -- typedef long long manhattan_area_type; -- typedef unsigned long long unsigned_area_type; -- typedef long long coordinate_difference; -- typedef long double coordinate_distance; -- }; - - template <> - struct geometry_concept { typedef point_concept type; }; diff --git a/slic3r-clipper.patch b/slic3r-clipper.patch index 820ef87..be8e593 100644 --- a/slic3r-clipper.patch +++ b/slic3r-clipper.patch @@ -1,18 +1,18 @@ diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp -index ab144f2..86331ac 100644 +index ddd551c..8149366 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -2,7 +2,7 @@ #define slic3r_ClipperUtils_hpp_ - #include + #include -#include "clipper.hpp" +#include #include "ExPolygon.hpp" #include "Polygon.hpp" #include "Surface.hpp" diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp -index 827029a..e5b54bb 100644 +index 7bcb644..5258485 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -3,7 +3,7 @@ @@ -22,16 +22,29 @@ index 827029a..e5b54bb 100644 -#include "clipper.hpp" +#include #include + #include #include - #include +diff --git a/xs/src/libslic3r/SVG.hpp b/xs/src/libslic3r/SVG.hpp +index fbb5e37..bb9f4cc 100644 +--- a/xs/src/libslic3r/SVG.hpp ++++ b/xs/src/libslic3r/SVG.hpp +@@ -2,7 +2,7 @@ + #define slic3r_SVG_hpp_ + + #include "libslic3r.h" +-#include "clipper.hpp" ++#include + #include "ExPolygon.hpp" + #include "Line.hpp" + #include "TriangleMesh.hpp" diff --git a/xs/xsp/Clipper.xsp b/xs/xsp/Clipper.xsp -index d9530f7..3ba2448 100644 +index 7bbbdb8..8b52133 100644 --- a/xs/xsp/Clipper.xsp +++ b/xs/xsp/Clipper.xsp @@ -2,7 +2,7 @@ %{ - #include + #include -#include "clipper.hpp" +#include #include "libslic3r/ClipperUtils.hpp" diff --git a/slic3r-datadir.patch b/slic3r-datadir.patch index f438564..6dc17ae 100644 --- a/slic3r-datadir.patch +++ b/slic3r-datadir.patch @@ -2,12 +2,12 @@ diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 154af90..ef8274c 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm -@@ -30,7 +30,7 @@ warn "Running Slic3r under Perl 5.16 is not supported nor recommended\n" - if $^V == v5.16; +@@ -42,7 +42,7 @@ warn "Running Slic3r under Perl 5.16 is neither supported nor recommended\n" use FindBin; --our $var = decode_path($FindBin::Bin) . "/var"; -+our $var = "/usr/share/slic3r"; - - use Moo 1.003001; - + # Path to the images. +-my $varpath = decode_path($FindBin::Bin) . "/var"; ++my $varpath = "/usr/share/slic3r"; + if ($^O eq 'darwin' && !-d $varpath) { + $varpath = decode_path($FindBin::Bin) . "/../Resources/var"; + } diff --git a/slic3r-english-locale.patch b/slic3r-english-locale.patch index d01a79a..4c21b2a 100644 --- a/slic3r-english-locale.patch +++ b/slic3r-english-locale.patch @@ -1,12 +1,12 @@ diff --git a/slic3r.pl b/slic3r.pl -index a533250..814d8b7 100755 +index 11dc2fa..80e6dc7 100755 --- a/slic3r.pl +++ b/slic3r.pl -@@ -11,6 +11,7 @@ BEGIN { +@@ -13,6 +13,7 @@ use File::Basename qw(basename); use Getopt::Long qw(:config no_auto_abbrev); use List::Util qw(first); - use POSIX qw(setlocale LC_NUMERIC); + use POSIX qw(setlocale LC_NUMERIC ceil); +$ENV{LC_NUMERIC} = 'en_US.UTF-8'; use Slic3r; + use Slic3r::Geometry qw(epsilon X Y Z deg2rad); use Time::HiRes qw(gettimeofday tv_interval); - $|++; diff --git a/slic3r-linker.patch b/slic3r-linker.patch index 91f9e60..f1304b4 100644 --- a/slic3r-linker.patch +++ b/slic3r-linker.patch @@ -1,15 +1,15 @@ -diff --git a/xs/Build.PL b/xs/Build.PL -index bc18bc5..9e2ce40 100644 ---- a/xs/Build.PL -+++ b/xs/Build.PL -@@ -41,6 +41,10 @@ my $build = Module::Build::WithXSpp->new( - Module::Build::WithXSpp 0.13 - )}, - extra_compiler_flags => \@cflags, -+ extra_linker_flags => [qw( -+ -ladmesh -+ -lpoly2tri -+ )], - - # Provides extra C typemaps that are auto-merged - extra_typemap_modules => { +diff -up Slic3r-1.3.0/xs/Build.PL.linker Slic3r-1.3.0/xs/Build.PL +--- Slic3r-1.3.0/xs/Build.PL.linker 2018-05-08 18:47:09.000000000 -0400 ++++ Slic3r-1.3.0/xs/Build.PL 2018-06-25 10:48:55.421774896 -0400 +@@ -30,6 +30,11 @@ push @cflags, qw(-std=c++11); + + my @ldflags = (); + ++if (defined $ENV{SYSTEM_LIBS}) { ++ my $syslibs = $ENV{SYSTEM_LIBS}; ++ push @ldflags, split(' ', $syslibs); ++} ++ + if ($linux && (defined $ENV{SLIC3R_STATIC} && $ENV{SLIC3R_STATIC})) { + push @ldflags, qw(-static-libgcc -static-libstdc++); + if ($ENV{TRAVIS}) { diff --git a/slic3r-opengl070.patch b/slic3r-opengl070.patch deleted file mode 100644 index b89515b..0000000 --- a/slic3r-opengl070.patch +++ /dev/null @@ -1,117 +0,0 @@ -diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm -index 7628a6c..d37199b 100644 ---- a/lib/Slic3r/GUI/3DScene.pm -+++ b/lib/Slic3r/GUI/3DScene.pm -@@ -1,9 +1,9 @@ - package Slic3r::GUI::3DScene::Base; - use strict; - use warnings; -- - use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS); - # must load OpenGL *before* Wx::GLCanvas -+ - use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants); - use base qw(Wx::GLCanvas Class::Accessor); - use Math::Trig qw(asin); -@@ -48,6 +48,12 @@ use constant DEFAULT_COLOR => [1,1,0]; - use constant SELECTED_COLOR => [0,1,0,1]; - use constant HOVER_COLOR => [0.4,0.9,0,1]; - -+# Constant to determine if Vertex Buffer objects are used to draw -+# bed grid and the cut plane for object separation. -+# Old Perl (5.10.x) should set to 0. -+use constant HAS_VBO => 1; -+ -+ - # make OpenGL::Array thread-safe - { - no warnings 'redefine'; -@@ -114,6 +120,7 @@ sub new { - $self->Refresh; - }); - EVT_MOUSE_EVENTS($self, \&mouse_event); -+ - - return $self; - } -@@ -741,9 +748,19 @@ sub Render { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnableClientState(GL_VERTEX_ARRAY); -+ if (HAS_VBO) { -+ my ($triangle_vertex); -+ ($triangle_vertex) = -+ glGenBuffersARB_p(1); -+ $self->bed_triangles->bind($triangle_vertex); -+ glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $self->bed_triangles, GL_STATIC_DRAW_ARB); -+ glVertexPointer_c(3, GL_FLOAT, 0, 0); -+ } else { -+ # fall back on old behavior -+ glVertexPointer_p(3, $self->bed_triangles); -+ } - glColor4f(0.8, 0.6, 0.5, 0.4); - glNormal3d(0,0,1); -- glVertexPointer_p(3, $self->bed_triangles); - glDrawArrays(GL_TRIANGLES, 0, $self->bed_triangles->elements / 3); - glDisableClientState(GL_VERTEX_ARRAY); - -@@ -753,13 +770,29 @@ sub Render { - - # draw grid - glLineWidth(3); -- glColor4f(0.2, 0.2, 0.2, 0.4); - glEnableClientState(GL_VERTEX_ARRAY); -- glVertexPointer_p(3, $self->bed_grid_lines); -+ if (HAS_VBO) { -+ my ($grid_vertex); -+ ($grid_vertex) = -+ glGenBuffersARB_p(1); -+ $self->bed_grid_lines->bind($grid_vertex); -+ glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $self->bed_grid_lines, GL_STATIC_DRAW_ARB); -+ glVertexPointer_c(3, GL_FLOAT, 0, 0); -+ } else { -+ # fall back on old behavior -+ glVertexPointer_p(3, $self->bed_grid_lines); -+ } -+ glColor4f(0.2, 0.2, 0.2, 0.4); -+ glNormal3d(0,0,1); - glDrawArrays(GL_LINES, 0, $self->bed_grid_lines->elements / 3); - glDisableClientState(GL_VERTEX_ARRAY); - - glDisable(GL_BLEND); -+ if (HAS_VBO) { -+ # Turn off buffer objects to let the rest of the draw code work. -+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); -+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); -+ } - } - - my $volumes_bb = $self->volumes_bounding_box; -@@ -899,10 +932,26 @@ sub draw_volumes { - glDisable(GL_BLEND); - - if (defined $self->cutting_plane_z) { -+ if (HAS_VBO) { -+ # Use Vertex Buffer Object for cutting plane (previous method crashes on modern POGL). -+ my ($cut_vertex) = glGenBuffersARB_p(1); -+ $self->cut_lines_vertices->bind($cut_vertex); -+ glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $self->cut_lines_vertices, GL_STATIC_DRAW_ARB); -+ glVertexPointer_c(3, GL_FLOAT, 0, 0); -+ } else { -+ # Use legacy method. -+ glVertexPointer_p(3, $self->cut_lines_vertices); -+ } - glLineWidth(2); - glColor3f(0, 0, 0); -- glVertexPointer_p(3, $self->cut_lines_vertices); - glDrawArrays(GL_LINES, 0, $self->cut_lines_vertices->elements / 3); -+ -+ if (HAS_VBO) { -+ # Turn off buffer objects to let the rest of the draw code work. -+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); -+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); -+ } -+ - } - glDisableClientState(GL_VERTEX_ARRAY); - } diff --git a/slic3r-wxclose.patch b/slic3r-wxclose.patch deleted file mode 100644 index cffe02e..0000000 --- a/slic3r-wxclose.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/lib/Slic3r/GUI/AboutDialog.pm b/lib/Slic3r/GUI/AboutDialog.pm -index 6fc83b6..78f89ef 100644 ---- a/lib/Slic3r/GUI/AboutDialog.pm -+++ b/lib/Slic3r/GUI/AboutDialog.pm -@@ -66,7 +66,7 @@ sub new { - $vsizer->Add($html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 20); - EVT_HTML_LINK_CLICKED($self, $html, \&link_clicked); - -- my $buttons = $self->CreateStdDialogButtonSizer(wxCLOSE); -+ my $buttons = $self->CreateStdDialogButtonSizer(wxOK); - $self->SetEscapeId(wxID_CLOSE); - EVT_BUTTON($self, wxID_CLOSE, sub { - $self->EndModal(wxID_CLOSE); diff --git a/slic3r.spec b/slic3r.spec index b4b1376..f915b44 100644 --- a/slic3r.spec +++ b/slic3r.spec @@ -1,6 +1,11 @@ +%global use_system_admesh 0 +%global use_system_expat 1 +%global use_system_polyclipping 1 +%global use_system_poly2tri 1 + Name: slic3r -Version: 1.2.9 -Release: 18%{?dist} +Version: 1.3.0 +Release: 2%{?dist} Summary: G-code generator for 3D printers (RepRap, Makerbot, Ultimaker etc.) License: AGPLv3 and CC-BY # Images are CC-BY, code is AGPLv3 @@ -15,22 +20,8 @@ Patch0: %{name}-buildpl.patch Patch1: %{name}-datadir.patch Patch2: %{name}-english-locale.patch Patch3: %{name}-linker.patch -#Patch4: %{name}-clipper.patch - -# https://bugzilla.redhat.com/show_bug.cgi?id=1306668 -# https://github.com/alexrj/Slic3r/issues/3117#issuecomment-187767676 -Patch5: %{name}-boost160.patch - -# Patch to manually cast too bool, fix FTBFS -# Will report upstream -Patch6: %{name}-boolcast.patch - -# https://bugzilla.redhat.com/show_bug.cgi?id=1285807 -# https://github.com/alexrj/Slic3r/commit/1a09ae81db06602050ae83620268efa33ed14da1 -Patch7: %{name}-wxclose.patch - -# https://github.com/alexrj/Slic3r/pull/3575 -Patch8: %{name}-opengl070.patch +Patch4: %{name}-clipper.patch +Patch5: %{name}-1.3.0-fixtest.patch Source1: %{name}.desktop Source2: %{name}.appdata.xml @@ -39,10 +30,13 @@ BuildRequires: gcc-c++ BuildRequires: perl-devel BuildRequires: perl-generators BuildRequires: perl(Class::XSAccessor) +BuildRequires: perl(Devel::CheckLib) +BuildRequires: perl(Devel::Peek) BuildRequires: perl(Encode::Locale) >= 1.05 +BuildRequires: perl(ExtUtils::CppGuess) BuildRequires: perl(ExtUtils::CBuilder) BuildRequires: perl(ExtUtils::MakeMaker) >= 6.80 -BuildRequires: perl(ExtUtils::ParseXS) >= 3.22 +BuildRequires: perl(ExtUtils::ParseXS) >= 3.35 BuildRequires: perl(ExtUtils::Typemaps::Default) >= 1.05 BuildRequires: perl(ExtUtils::Typemaps) >= 1.00 BuildRequires: perl(File::Basename) @@ -51,6 +45,7 @@ BuildRequires: perl(Getopt::Long) BuildRequires: perl(Growl::GNTP) >= 0.15 BuildRequires: perl(IO::Scalar) BuildRequires: perl(List::Util) +BuildRequires: perl(local::lib) BuildRequires: perl(Math::PlanePath) >= 53 BuildRequires: perl(Module::Build::WithXSpp) >= 0.14 BuildRequires: perl(Moo) >= 1.003001 @@ -61,26 +56,55 @@ BuildRequires: perl(Storable) BuildRequires: perl(SVG) BuildRequires: perl(Test::Harness) BuildRequires: perl(Test::More) +BuildRequires: perl(Thread::Queue) BuildRequires: perl(Thread::Semaphore) BuildRequires: perl(threads) >= 1.96 +BuildRequires: perl(threads::shared) BuildRequires: perl(Time::HiRes) BuildRequires: perl(Unicode::Normalize) BuildRequires: perl(Wx) BuildRequires: perl(XML::SAX) BuildRequires: perl(XML::SAX::ExpatXS) +%if %{use_system_admesh} BuildRequires: admesh-devel >= 0.98.1 -BuildRequires: boost-devel -BuildRequires: desktop-file-utils -BuildRequires: poly2tri-devel -#BuildRequires: polyclipping-devel >= 6.2.0 -BuildRequires: ImageMagick +Requires: admesh-libs >= 0.98.1 +%else +Provides: bundled(admesh) = 0.98 +# Bundled admesh FTBFS with: +# error "admesh works correctly on little endian machines only!" +ExcludeArch: ppc ppc64 s390 s390x +%endif +%if %{use_system_expat} +BuildRequires: expat-devel >= 2.2.0 +%else +Provides: bundled(expat) = 2.2.0 +%endif + +%if %{use_system_polyclipping} +BuildRequires: polyclipping-devel >= 6.4.2 +%else +Provides: bundled(polyclipping) = 6.4.2 +%endif + +%if %{use_system_poly2tri} +BuildRequires: poly2tri-devel +%else +Provides: bundled(poly2tri) = 0.0 +%endif + +BuildRequires: boost-devel +BuildRequires: boost-nowide-devel +BuildRequires: desktop-file-utils +BuildRequires: ImageMagick +Requires: perl(Growl::GNTP) >= 0.15 Requires: perl(XML::SAX) Requires: perl(:MODULE_COMPAT_%(eval "`perl -V:version`"; echo $version)) -Requires: admesh-libs >= 0.98.1 -Provides: bundled(polyclipping) = 6.2.9 +# Optional dependency. Not packaged in Fedora yet. +# It's only used for magically finding octoprint servers. +Recommends: perl(Net::Bonjour) %description Slic3r is a G-code generator for 3D printers. It's compatible with RepRaps, @@ -94,21 +118,55 @@ for more information. %patch0 -p1 %patch1 -p1 %patch2 -p1 -%patch3 -p1 -#%%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 +%patch3 -p1 -b .linker +%if %{use_system_polyclipping} +%patch4 -p1 +%endif +%patch5 -p1 -b .fixtest -# Remove bundled admesh, clipper, poly2tri and boost +# Optional removals +%if %{use_system_admesh} rm -rf xs/src/admesh +sed -i '/src\/admesh/d' xs/MANIFEST +%endif + +%if %{use_system_expat} +rm -rf xs/src/expat +sed -i '/src\/expat/d' xs/MANIFEST +# These are the files with hardcoded expat/expat.h includes +sed -i 's|expat/expat.h|expat.h|g' xs/src/libslic3r/IO/AMF.cpp +sed -i 's|expat/expat.h|expat.h|g' xs/src/libslic3r/IO/TMF.hpp +%endif + +%if %{use_system_polyclipping} #rm xs/src/clipper.*pp +export SYSTEM_LIBS="${SYSTEM_LIBS} -lpolyclipping" +%endif + +%if %{use_system_poly2tri} rm -rf xs/src/poly2tri +sed -i '/src\/poly2tri/d' xs/MANIFEST +%endif + +# We always do boost. rm -rf xs/src/boost +sed -i '/src\/boost\/nowide/d' xs/MANIFEST %build +%if %{use_system_admesh} +export SYSTEM_LIBS="${SYSTEM_LIBS} -ladmesh" +%endif + +%if %{use_system_expat} +export SYSTEM_LIBS="${SYSTEM_LIBS} -lexpat" +%endif + +%if %{use_system_poly2tri} +export SYSTEM_LIBS="${SYSTEM_LIBS} -lpoly2tri" +%endif + cd xs +[[ ! -z "${SYSTEM_LIBS}" ]] && echo "SYSTEM_LIBS is ${SYSTEM_LIBS}" perl ./Build.PL installdirs=vendor optimize="$RPM_OPT_FLAGS" ./Build cd - @@ -165,10 +223,6 @@ cd - SLIC3R_NO_AUTO=1 perl Build.PL installdirs=vendor # the --gui runs no tests, it only checks requires -%post -p /sbin/ldconfig - -%postun -p /sbin/ldconfig - %files %doc README.md %{_bindir}/%{name} @@ -184,6 +238,14 @@ SLIC3R_NO_AUTO=1 perl Build.PL installdirs=vendor %{_datadir}/%{name} %changelog +* Mon Jun 25 2018 Tom Callaway - 1.3.0-2 +- conditionalize bundled bits +- fix t/gcode.t (needed to define config->layer_height before trying to use it) +- exclude big endian architectures + +* Thu May 31 2018 Miro HronĨok - 1.3.0-1 +- Update to 1.3.0 + * Tue Mar 06 2018 Petr Pisar - 1.2.9-18 - Adapt to removing GCC from a build root (bug #1547165) diff --git a/sources b/sources index a83feaf..e6da8b9 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -05ac7b137cbb7b12f442776e4c12dcc2 1.2.9.tar.gz +SHA512 (1.3.0.tar.gz) = ff0f7747e166826ff1c53220974ee9d3a217d0e19964dbe4a5fa3e81f262a6810a47632686b7f1b3128384ae05c6f98d8aab980524079bdf9811445fe23a0f0d