diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65a124055..24fae45c6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -241,6 +241,7 @@ add_subdirectory(resources/localization)
 
 # libslic3r, Slic3r GUI and the slic3r executable.
 add_subdirectory(src)
+set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT slic3r)
 
 # Perl bindings, currently only used for the unit / integration tests of libslic3r.
 # Also runs the unit / integration tests.
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index e7442d773..bf8be7feb 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -566,6 +566,103 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
     return opt;
 }
 
+void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra)
+{
+    std::vector<char*> args;    
+    // push a bogus executable name (argv[0])
+    args.emplace_back(const_cast<char*>(""));
+    for (size_t i = 0; i < tokens.size(); ++ i)
+        args.emplace_back(const_cast<char *>(tokens[i].c_str()));
+    this->read_cli(args.size(), &args[0], extra);
+}
+
+bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra)
+{
+    // cache the CLI option => opt_key mapping
+    std::map<std::string,std::string> opts;
+    for (const auto &oit : this->def()->options) {
+        std::string cli = oit.second.cli;
+        cli = cli.substr(0, cli.find("="));
+        boost::trim_right_if(cli, boost::is_any_of("!"));
+        std::vector<std::string> tokens;
+        boost::split(tokens, cli, boost::is_any_of("|"));
+        for (const std::string &t : tokens)
+            opts[t] = oit.first;
+    }
+    
+    bool parse_options = true;
+    for (int i = 1; i < argc; ++ i) {
+        std::string token = argv[i];
+        // Store non-option arguments in the provided vector.
+        if (! parse_options || ! boost::starts_with(token, "-")) {
+            extra->push_back(token);
+            continue;
+        }
+        // Stop parsing tokens as options when -- is supplied.
+        if (token == "--") {
+            parse_options = false;
+            continue;
+        }
+        // Remove leading dashes
+        boost::trim_left_if(token, boost::is_any_of("-"));
+        // Remove the "no-" prefix used to negate boolean options.
+        bool no = false;
+        if (boost::starts_with(token, "no-")) {
+            no = true;
+            boost::replace_first(token, "no-", "");
+        }
+        // Read value when supplied in the --key=value form.
+        std::string value;
+        {
+            size_t equals_pos = token.find("=");
+            if (equals_pos != std::string::npos) {
+                value = token.substr(equals_pos+1);
+                token.erase(equals_pos);
+            }
+        }
+        // Look for the cli -> option mapping.
+        const auto it = opts.find(token);
+        if (it == opts.end()) {
+            printf("Warning: unknown option --%s\n", token.c_str());
+            // instead of continuing, return false to caller
+            // to stop execution and print usage
+            return false;
+            //continue;
+        }
+        const t_config_option_key opt_key = it->second;
+        const ConfigOptionDef &optdef = this->def()->options.at(opt_key);
+        // If the option type expects a value and it was not already provided,
+        // look for it in the next token.
+        if (optdef.type != coBool && optdef.type != coBools && value.empty()) {
+            if (i == (argc-1)) {
+                printf("No value supplied for --%s\n", token.c_str());
+                continue;
+            }
+            value = argv[++ i];
+        }
+        // Store the option value.
+        const bool existing = this->has(opt_key);
+        if (ConfigOptionBool* opt = this->opt<ConfigOptionBool>(opt_key, true)) {
+            opt->value = !no;
+        } else if (ConfigOptionBools* opt = this->opt<ConfigOptionBools>(opt_key, true)) {
+            if (!existing) opt->values.clear(); // remove the default values
+            opt->values.push_back(!no);
+        } else if (ConfigOptionStrings* opt = this->opt<ConfigOptionStrings>(opt_key, true)) {
+            if (!existing) opt->values.clear(); // remove the default values
+            opt->deserialize(value, true);
+        } else if (ConfigOptionFloats* opt = this->opt<ConfigOptionFloats>(opt_key, true)) {
+            if (!existing) opt->values.clear(); // remove the default values
+            opt->deserialize(value, true);
+        } else if (ConfigOptionPoints* opt = this->opt<ConfigOptionPoints>(opt_key, true)) {
+            if (!existing) opt->values.clear(); // remove the default values
+            opt->deserialize(value, true);
+        } else {
+            this->set_deserialize(opt_key, value, true);
+        }
+    }
+    return true;
+}
+
 t_config_option_keys DynamicConfig::keys() const
 {
     t_config_option_keys keys;
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index e3cd14335..2704bbcf3 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -976,7 +976,7 @@ public:
 // Map from a config option name to its definition.
 // The definition does not carry an actual value of the config option, only its constant default value.
 // t_config_option_key is std::string
-typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map;
+typedef std::map<t_config_option_key, ConfigOptionDef> t_optiondef_map;
 
 // Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
 // The configuration definition is static: It does not carry the actual configuration values,
@@ -984,18 +984,27 @@ typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map;
 class ConfigDef
 {
 public:
-    t_optiondef_map options;
-    ~ConfigDef() { for (auto &opt : this->options) delete opt.second.default_value; }
-    ConfigOptionDef*        add(const t_config_option_key &opt_key, ConfigOptionType type) {
-        ConfigOptionDef* opt = &this->options[opt_key];
-        opt->type = type;
-        return opt;
-    }
+    t_optiondef_map         options;
+
     bool                    has(const t_config_option_key &opt_key) const { return this->options.count(opt_key) > 0; }
     const ConfigOptionDef*  get(const t_config_option_key &opt_key) const {
         t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key);
         return (it == this->options.end()) ? nullptr : &it->second;
     }
+    std::vector<std::string> keys() const {
+        std::vector<std::string> out;
+        out.reserve(options.size());
+        for(auto const& kvp : options)
+            out.push_back(kvp.first);
+        return out;
+    }
+
+protected:
+    ConfigOptionDef*        add(const t_config_option_key &opt_key, ConfigOptionType type) {
+        ConfigOptionDef* opt = &this->options[opt_key];
+        opt->type = type;
+        return opt;
+    }
 };
 
 // An abstract configuration store.
@@ -1219,6 +1228,10 @@ public:
     bool                opt_bool(const t_config_option_key &opt_key) const                      { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
     bool                opt_bool(const t_config_option_key &opt_key, unsigned int idx) const    { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }
 
+    // Command line processing
+    void                read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra);
+    bool                read_cli(int argc, char** argv, t_config_option_keys* extra);
+
 private:
     typedef std::map<t_config_option_key,ConfigOption*> t_options_map;
     t_options_map options;
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index ec7447352..ed705e007 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -113,6 +113,12 @@ Model Model::read_from_archive(const std::string &input_file, PresetBundle* bund
     return model;
 }
 
+void Model::repair()
+{
+    for (ModelObject *o : this->objects)
+        o->repair();
+}
+
 ModelObject* Model::add_object()
 {
     this->objects.emplace_back(new ModelObject(this));
@@ -886,6 +892,12 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
     return;
 }
 
+void ModelObject::repair()
+{
+    for (ModelVolume *v : this->volumes)
+        v->mesh.repair();
+}
+
 // Called by Print::validate() from the UI thread.
 void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
 {
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 4c2356429..3acf9b8d2 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -120,6 +120,7 @@ public:
     void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); }
     void translate(coordf_t x, coordf_t y, coordf_t z);
     void scale(const Vec3d &versor);
+    void scale(const double s) { this->scale(Vec3d(s, s, s)); }
     void rotate(float angle, const Axis &axis);
     void rotate(float angle, const Vec3d& axis);
     void mirror(const Axis &axis);
@@ -128,6 +129,7 @@ public:
     bool needed_repair() const;
     void cut(coordf_t z, Model* model) const;
     void split(ModelObjectPtrs* new_objects);
+    void repair();
 
     // Called by Print::validate() from the UI thread.
     void check_instances_print_volume_state(const BoundingBoxf3& print_volume);
@@ -190,11 +192,11 @@ public:
     // Split this volume, append the result to the object owning this volume.
     // Return the number of volumes created from this one.
     // This is useful to assign different materials to different volumes of an object.
-    size_t split(unsigned int max_extruders);
+    size_t              split(unsigned int max_extruders);
 
-    ModelMaterial* assign_unique_material();
+    ModelMaterial*      assign_unique_material();
     
-    void calculate_convex_hull();
+    void                calculate_convex_hull();
     const TriangleMesh& get_convex_hull() const;
 
     // Helpers for loading / storing into AMF / 3MF files.
@@ -325,6 +327,10 @@ public:
     static Model read_from_file(const std::string &input_file, bool add_default_instances = true);
     static Model read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances = true);
 
+    /// Repair the ModelObjects of the current Model.
+    /// This function calls repair function on each TriangleMesh of each model object volume
+    void repair();
+
     ModelObject* add_object();
     ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh);
     ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh);
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index ed02f6d43..061233069 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -2345,7 +2345,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
     }
 }
 
-PrintConfigDef print_config_def;
+const PrintConfigDef print_config_def;
 
 DynamicPrintConfig* DynamicPrintConfig::new_from_defaults()
 {
@@ -2601,4 +2601,135 @@ StaticPrintConfig::StaticCache<class Slic3r::SLAMaterialConfig>  SLAMaterialConf
 StaticPrintConfig::StaticCache<class Slic3r::SLAPrinterConfig>   SLAPrinterConfig::s_cache_SLAPrinterConfig;
 StaticPrintConfig::StaticCache<class Slic3r::SLAFullPrintConfig> SLAFullPrintConfig::s_cache_SLAFullPrintConfig;
 
+
+CLIConfigDef::CLIConfigDef()
+{
+    ConfigOptionDef *def;
+    
+    def = this->add("cut", coFloat);
+    def->label = L("Cut");
+    def->tooltip = L("Cut model at the given Z.");
+    def->cli = "cut";
+    def->default_value = new ConfigOptionFloat(0);
+
+    def = this->add("export_3mf", coBool);
+    def->label = L("Export 3MF");
+    def->tooltip = L("Slice the model and export slices as 3MF.");
+    def->cli = "export-3mf";
+    def->default_value = new ConfigOptionBool(false);
+
+    def = this->add("slice", coBool);
+    def->label = L("Slice");
+    def->tooltip = L("Slice the model and export gcode.");
+    def->cli = "slice";
+    def->default_value = new ConfigOptionBool(false);
+
+    def = this->add("help", coBool);
+    def->label = L("Help");
+    def->tooltip = L("Show this help.");
+    def->cli = "help";
+    def->default_value = new ConfigOptionBool(false);
+
+    def = this->add("gui", coBool);
+    def->label = L("Use GUI");
+    def->tooltip = L("Start the Slic3r GUI.");
+    def->cli = "gui";
+    def->default_value = new ConfigOptionBool(false);
+    
+    def = this->add("info", coBool);
+    def->label = L("Output Model Info");
+    def->tooltip = L("Write information about the model to the console.");
+    def->cli = "info";
+    def->default_value = new ConfigOptionBool(false);
+    
+    def = this->add("load", coStrings);
+    def->label = L("Load config file");
+    def->tooltip = L("Load configuration from the specified file. It can be used more than once to load options from multiple files.");
+    def->cli = "load";
+    def->default_value = new ConfigOptionStrings();
+    
+    def = this->add("output", coString);
+    def->label = L("Output File");
+    def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file).");
+    def->cli = "output";
+    def->default_value = new ConfigOptionString("");
+    
+    def = this->add("rotate", coFloat);
+    def->label = L("Rotate");
+    def->tooltip = L("Rotation angle around the Z axis in degrees (0-360, default: 0).");
+    def->cli = "rotate";
+    def->default_value = new ConfigOptionFloat(0);
+    
+    def = this->add("rotate_x", coFloat);
+    def->label = L("Rotate around X");
+    def->tooltip = L("Rotation angle around the X axis in degrees (0-360, default: 0).");
+    def->cli = "rotate-x";
+    def->default_value = new ConfigOptionFloat(0);
+    
+    def = this->add("rotate_y", coFloat);
+    def->label = L("Rotate around Y");
+    def->tooltip = L("Rotation angle around the Y axis in degrees (0-360, default: 0).");
+    def->cli = "rotate-y";
+    def->default_value = new ConfigOptionFloat(0);
+    
+    def = this->add("save", coString);
+    def->label = L("Save config file");
+    def->tooltip = L("Save configuration to the specified file.");
+    def->cli = "save";
+    def->default_value = new ConfigOptionString();
+    
+    def = this->add("scale", coFloat);
+    def->label = L("Scale");
+    def->tooltip = L("Scaling factor (default: 1).");
+    def->cli = "scale";
+    def->default_value = new ConfigOptionFloat(1);
+
+/*    
+    def = this->add("scale_to_fit", coPoint3);
+    def->label = L("Scale to Fit");
+    def->tooltip = L("Scale to fit the given volume.");
+    def->cli = "scale-to-fit";
+    def->default_value = new ConfigOptionPoint3(Pointf3(0,0,0));
+*/
+
+    def = this->add("center", coPoint);
+    def->label = L("Center");
+    def->tooltip = L("Center the print around the given center (default: 100, 100).");
+    def->cli = "center";
+    def->default_value = new ConfigOptionPoint(Vec2d(100,100));
+}
+
+const CLIConfigDef cli_config_def;
+DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def;
+
+std::ostream& print_cli_options(std::ostream& out)
+{
+    for (const auto& opt : cli_config_def.options) {
+        if (opt.second.cli.size() != 0) {
+            out << "\t" << std::left << std::setw(40) << std::string("--") + opt.second.cli;
+            out << "\t" << opt.second.tooltip << "\n";
+            if (opt.second.default_value != nullptr)
+                out << "\t" << std::setw(40) << " " << "\t" << " (default: " << opt.second.default_value->serialize() << ")";
+            out << "\n";
+        }
+    }
+    std::cerr << std::endl;
+    return out;
+}
+
+std::ostream& print_print_options(std::ostream& out)
+{
+    for (const auto& opt : print_config_def.options) {
+        if (opt.second.cli.size() != 0) {
+            out << "\t" << std::left << std::setw(40) << std::string("--") + opt.second.cli; 
+            out << "\t" << opt.second.tooltip << "\n";
+            if (opt.second.default_value != nullptr) 
+                out << "\t" << std::setw(40) << " " << "\t" << " (default: " << opt.second.default_value->serialize() << ")";
+            out << "\n";
+        }
+    }
+    std::cerr << std::endl;
+    return out;
+}
+
 }
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index bc3b0ef49..0475f4ecb 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -165,7 +165,7 @@ private:
 
 // The one and only global definition of SLic3r configuration options.
 // This definition is constant.
-extern PrintConfigDef print_config_def;
+extern const PrintConfigDef print_config_def;
 
 // Slic3r dynamic configuration, used to override the configuration 
 // per object, per modification volume or per printing material.
@@ -968,6 +968,88 @@ protected:
 #undef STATIC_PRINT_CONFIG_CACHE_DERIVED
 #undef OPT_PTR
 
-}
+class CLIConfigDef : public ConfigDef
+{
+public:
+    CLIConfigDef();
+};
+
+extern const CLIConfigDef cli_config_def;
+
+#define OPT_PTR(KEY) if (opt_key == #KEY) return &this->KEY
+
+class CLIConfig : public virtual ConfigBase, public StaticConfig
+{
+public:
+    ConfigOptionFloat               cut;
+    ConfigOptionBool                export_3mf;
+    ConfigOptionBool                gui;
+    ConfigOptionBool                info;
+    ConfigOptionBool                help;
+    ConfigOptionStrings             load;
+    ConfigOptionString              output;
+    ConfigOptionFloat               rotate;
+    ConfigOptionFloat               rotate_x;
+    ConfigOptionFloat               rotate_y;
+    ConfigOptionString              save;
+    ConfigOptionFloat               scale;
+//    ConfigOptionPoint3              scale_to_fit;
+    ConfigOptionPoint               center;
+    ConfigOptionBool                slice;
+    
+    CLIConfig() : ConfigBase(), StaticConfig()
+    {
+        this->set_defaults();
+    };
+
+    // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
+    const ConfigDef*    def() const override { return &cli_config_def; }
+
+    ConfigOption*       optptr(const t_config_option_key &opt_key, bool create = false) override
+    {
+        OPT_PTR(cut);
+        OPT_PTR(export_3mf);
+        OPT_PTR(gui);
+        OPT_PTR(help);
+        OPT_PTR(info);
+        OPT_PTR(load);
+        OPT_PTR(output);
+        OPT_PTR(rotate);
+        OPT_PTR(rotate_x);
+        OPT_PTR(rotate_y);
+        OPT_PTR(save);
+        OPT_PTR(scale);
+//        OPT_PTR(scale_to_fit);
+        OPT_PTR(slice);
+        return NULL;
+    }
+};
+
+#undef OPT_PTR
+
+class DynamicPrintAndCLIConfig : public DynamicPrintConfig
+{
+public:
+    DynamicPrintAndCLIConfig() { this->apply(FullPrintConfig::defaults()); this->apply(CLIConfig()); }
+    DynamicPrintAndCLIConfig(const DynamicPrintAndCLIConfig &other) : DynamicPrintConfig(other) {}
+
+    // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
+    const ConfigDef*    def() const override { return &s_def; }
+
+private:
+    class PrintAndCLIConfigDef : public PrintConfigDef
+    {
+    public:
+        PrintAndCLIConfigDef() { this->options.insert(cli_config_def.options.begin(), cli_config_def.options.end()); }
+    };
+    static PrintAndCLIConfigDef s_def;
+};
+
+/// Iterate through all of the print options and write them to a stream.
+std::ostream& print_print_options(std::ostream& out);
+/// Iterate through all of the CLI options and write them to a stream.
+std::ostream& print_cli_options(std::ostream& out);
+
+} // namespace Slic3r
 
 #endif
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index ef2364dc4..280b30e53 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1591,7 +1591,7 @@ std::vector<ExPolygons> PrintObject::slice_support_enforcers() const
     std::vector<float> zs;
     zs.reserve(this->layers().size());
     for (const Layer *l : this->layers())
-        zs.emplace_back(l->slice_z);
+        zs.emplace_back((float)l->slice_z);
     return this->_slice_volumes(zs, volumes);
 }
 
@@ -1604,7 +1604,7 @@ std::vector<ExPolygons> PrintObject::slice_support_blockers() const
     std::vector<float> zs;
     zs.reserve(this->layers().size());
     for (const Layer *l : this->layers())
-        zs.emplace_back(l->slice_z);
+        zs.emplace_back((float)l->slice_z);
     return this->_slice_volumes(zs, volumes);
 }
 
diff --git a/src/slic3r.cpp b/src/slic3r.cpp
index 8174ba0a2..5840ac0c1 100644
--- a/src/slic3r.cpp
+++ b/src/slic3r.cpp
@@ -1,7 +1,12 @@
+//#include "ConfigBase.hpp"
 #include "Config.hpp"
 #include "Geometry.hpp"
+//#include "IO.hpp"
 #include "Model.hpp"
+//#include "SLAPrint.hpp"
+#include "Print.hpp"
 #include "TriangleMesh.hpp"
+#include "Format/3mf.hpp"
 #include "libslic3r.h"
 #include <cstdio>
 #include <string>
@@ -12,6 +17,9 @@
 #include <boost/nowide/args.hpp>
 #include <boost/nowide/iostream.hpp>
 
+#ifdef USE_WX
+//    #include "GUI/GUI.hpp"
+#endif
 #include "slic3r/GUI/GUI.hpp"
 
 using namespace Slic3r;
@@ -87,37 +95,55 @@ void MyFrame::OnHello(wxCommandEvent& event)
     wxLogMessage("Hello world from wxWidgets!");
 }
 
+/// utility function for displaying CLI usage
+void printUsage();
 
-#if 1
-int
-main(int argc, char **argv)
+using namespace Slic3r;
+
+int main(int argc, char **argv)
 {
-    // Convert arguments to UTF-8 (needed on Windows).
-    // argv then points to memory owned by a.
+    // Convert arguments to UTF-8 (needed on Windows). argv then points to memory owned by a.
     boost::nowide::args a(argc, argv);
-    
-#if 0
+
     // parse all command line options into a DynamicConfig
-    ConfigDef config_def;
-    config_def.merge(cli_config_def);
-    config_def.merge(print_config_def);
-    DynamicConfig config(&config_def);
+    DynamicPrintAndCLIConfig config;
     t_config_option_keys input_files;
-    config.read_cli(argc, argv, &input_files);
-    
+    // if any option is unsupported, print usage and abort immediately
+    if (! config.read_cli(argc, argv, &input_files)) {
+        printUsage();
+        return 0;
+    }
+
     // apply command line options to a more handy CLIConfig
     CLIConfig cli_config;
     cli_config.apply(config, true);
     
     DynamicPrintConfig print_config;
-    
+
+#if 1
+    MyApp *gui = new MyApp();
+
+    MyApp::SetInstance(gui);
+    wxEntry(argc, argv);
+#endif
+
+#ifdef USE_WX
+    if (cli_config.gui) {
+        GUI::App *gui = new GUI::App();
+        GUI::App::SetInstance(gui);
+        wxEntry(argc, argv);
+    }
+#else
+    if (cli_config.gui) {
+        std::cout << "GUI support has not been built." << "\n";
+    }
+#endif
     // load config files supplied via --load
     for (const std::string &file : cli_config.load.values) {
         if (!boost::filesystem::exists(file)) {
             boost::nowide::cout << "No such file: " << file << std::endl;
             exit(1);
         }
-        
         DynamicPrintConfig c;
         try {
             c.load(file);
@@ -135,12 +161,13 @@ main(int argc, char **argv)
     print_config.normalize();
     
     // write config if requested
-    if (!cli_config.save.value.empty()) print_config.save(cli_config.save.value);
-    
+    if (! cli_config.save.value.empty())
+        print_config.save(cli_config.save.value);
+
     // read input file(s) if any
     std::vector<Model> models;
     for (const t_config_option_key &file : input_files) {
-        if (!boost::filesystem::exists(file)) {
+        if (! boost::filesystem::exists(file)) {
             boost::nowide::cerr << "No such file: " << file << std::endl;
             exit(1);
         }
@@ -162,9 +189,10 @@ main(int argc, char **argv)
         
         // apply command line transform options
         for (ModelObject* o : model.objects) {
+/*
             if (cli_config.scale_to_fit.is_positive_volume())
                 o->scale_to_fit(cli_config.scale_to_fit.value);
-            
+*/
             // TODO: honor option order?
             o->scale(cli_config.scale.value);
             o->rotate(Geometry::deg2rad(cli_config.rotate_x.value), X);
@@ -175,87 +203,79 @@ main(int argc, char **argv)
         // TODO: handle --merge
         models.push_back(model);
     }
+    if (cli_config.help) {
+        printUsage();
+        return 0;
+    }
     
     for (Model &model : models) {
         if (cli_config.info) {
             // --info works on unrepaired model
             model.print_info();
-        } else if (cli_config.export_obj) {
+        } else if (cli_config.export_3mf) {
             std::string outfile = cli_config.output.value;
-            if (outfile.empty()) outfile = model.objects.front()->input_file + ".obj";
-    
-            TriangleMesh mesh = model.mesh();
-            mesh.repair();
-            IO::OBJ::write(mesh, outfile);
-            boost::nowide::cout << "File exported to " << outfile << std::endl;
-        } else if (cli_config.export_pov) {
-            std::string outfile = cli_config.output.value;
-            if (outfile.empty()) outfile = model.objects.front()->input_file + ".pov";
-    
-            TriangleMesh mesh = model.mesh();
-            mesh.repair();
-            IO::POV::write(mesh, outfile);
-            boost::nowide::cout << "File exported to " << outfile << std::endl;
-        } else if (cli_config.export_svg) {
-            std::string outfile = cli_config.output.value;
-            if (outfile.empty()) outfile = model.objects.front()->input_file + ".svg";
-            
-            SLAPrint print(&model);
-            print.config.apply(print_config, true);
-            print.slice();
-            print.write_svg(outfile);
-            boost::nowide::cout << "SVG file exported to " << outfile << std::endl;
-        } else if (cli_config.cut_x > 0 || cli_config.cut_y > 0 || cli_config.cut > 0) {
+            if (outfile.empty()) outfile = model.objects.front()->input_file;
+            // Check if the file is already a 3mf.
+            if(outfile.substr(outfile.find_last_of('.'), outfile.length()) == ".3mf")
+                outfile = outfile.substr(0, outfile.find_last_of('.')) + "_2" + ".3mf";
+            else
+                // Remove the previous extension and add .3mf extention.
+                outfile = outfile.substr(0, outfile.find_last_of('.')) + ".3mf";
+            store_3mf(outfile.c_str(), &model, nullptr, false);
+            boost::nowide::cout << "File file exported to " << outfile << std::endl;
+        } else if (cli_config.cut > 0) {
             model.repair();
-            model.translate(0, 0, -model.bounding_box().min.z);
-            
-            if (!model.objects.empty()) {
-                // FIXME: cut all objects
+            model.translate(0, 0, - model.bounding_box().min(2));
+            if (! model.objects.empty()) {
                 Model out;
-                if (cli_config.cut_x > 0) {
-                    model.objects.front()->cut(X, cli_config.cut_x, &out);
-                } else if (cli_config.cut_y > 0) {
-                    model.objects.front()->cut(Y, cli_config.cut_y, &out);
-                } else {
-                    model.objects.front()->cut(Z, cli_config.cut, &out);
-                }
-                
+                model.objects.front()->cut(cli_config.cut, &out);
                 ModelObject &upper = *out.objects[0];
                 ModelObject &lower = *out.objects[1];
-            
-                if (upper.facets_count() > 0) {
-                    TriangleMesh m = upper.mesh();
-                    IO::STL::write(m, upper.input_file + "_upper.stl");
-                }
-                if (lower.facets_count() > 0) {
-                    TriangleMesh m = lower.mesh();
-                    IO::STL::write(m, lower.input_file + "_lower.stl");
-                }
+                // Use the input name and trim off the extension.
+                std::string outfile = cli_config.output.value;
+                if (outfile.empty()) 
+                    outfile = model.objects.front()->input_file;
+                outfile = outfile.substr(0, outfile.find_last_of('.'));
+                std::cerr << outfile << "\n";
+                if (upper.facets_count() > 0)
+                    upper.mesh().write_binary((outfile + "_upper.stl").c_str());
+                if (lower.facets_count() > 0)
+                    lower.mesh().write_binary((outfile + "_lower.stl").c_str());
             }
-        } else if (cli_config.cut_grid.value.x > 0 && cli_config.cut_grid.value.y > 0) {
-            TriangleMesh mesh = model.mesh();
-            mesh.repair();
-            
-            TriangleMeshPtrs meshes = mesh.cut_by_grid(cli_config.cut_grid.value);
-            size_t i = 0;
-            for (TriangleMesh* m : meshes) {
-                std::ostringstream ss;
-                ss << model.objects.front()->input_file << "_" << i++ << ".stl";
-                IO::STL::write(*m, ss.str());
-                delete m;
+        } else if (cli_config.slice) {
+            std::string outfile = cli_config.output.value;
+            Print print;
+            model.arrange_objects(print.config().min_object_distance());
+            model.center_instances_around_point(cli_config.center);
+            if (outfile.empty()) outfile = model.objects.front()->input_file + ".gcode";
+            print.apply_config(print_config);
+            for (auto* mo : model.objects) {
+                print.auto_assign_extruders(mo);
+                print.add_model_object(mo);
             }
+            print.validate();
+            print.export_gcode(outfile, nullptr);
         } else {
             boost::nowide::cerr << "error: command not supported" << std::endl;
             return 1;
         }
     }
-#endif
     
-
-    MyApp *gui = new MyApp();
-
-    MyApp::SetInstance(gui);
-    wxEntry(argc, argv);
     return 0;
 }
-#endif
+
+void printUsage()
+{
+    std::cout << "Slic3r " << SLIC3R_VERSION << " is a STL-to-GCODE translator for RepRap 3D printers" << "\n"
+              << "written by Alessandro Ranellucci <aar@cpan.org> - http://slic3r.org/ - https://github.com/slic3r/Slic3r" << "\n"
+//              << "Git Version " << BUILD_COMMIT << "\n\n"
+              << "Usage: ./slic3r [ OPTIONS ] [ file.stl ] [ file2.stl ] ..." << "\n";
+    // CLI Options
+    std::cout << "** CLI OPTIONS **\n";
+    print_cli_options(boost::nowide::cout);
+    std::cout << "****\n";
+        // Print options
+        std::cout << "** PRINT OPTIONS **\n";
+    print_print_options(boost::nowide::cout);
+    std::cout << "****\n";
+}
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index e784d8525..e7b1868d0 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -380,7 +380,7 @@ void PageVendors::on_variant_checked()
 
 PageFirmware::PageFirmware(ConfigWizard *parent) :
 	ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))),
-	gcode_opt(print_config_def.options["gcode_flavor"]),
+	gcode_opt(*print_config_def.get("gcode_flavor")),
 	gcode_picker(nullptr)
 {
 	append_text(_(L("Choose the type of firmware used by your printer.")));
@@ -440,13 +440,13 @@ PageDiameters::PageDiameters(ConfigWizard *parent) :
 {
 	spin_nozzle->SetDigits(2);
 	spin_nozzle->SetIncrement(0.1);
-	const auto &def_nozzle = print_config_def.options["nozzle_diameter"];
+	const auto &def_nozzle = *print_config_def.get("nozzle_diameter");
 	auto *default_nozzle = dynamic_cast<const ConfigOptionFloats*>(def_nozzle.default_value);
 	spin_nozzle->SetValue(default_nozzle != nullptr && default_nozzle->size() > 0 ? default_nozzle->get_at(0) : 0.5);
 
 	spin_filam->SetDigits(2);
 	spin_filam->SetIncrement(0.25);
-	const auto &def_filam = print_config_def.options["filament_diameter"];
+	const auto &def_filam = *print_config_def.get("filament_diameter");
 	auto *default_filam = dynamic_cast<const ConfigOptionFloats*>(def_filam.default_value);
 	spin_filam->SetValue(default_filam != nullptr && default_filam->size() > 0 ? default_filam->get_at(0) : 3.0);
 
@@ -490,13 +490,13 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent) :
 	spin_bed(new wxSpinCtrlDouble(this, wxID_ANY))
 {
 	spin_extr->SetIncrement(5.0);
-	const auto &def_extr = print_config_def.options["temperature"];
+	const auto &def_extr = *print_config_def.get("temperature");
 	spin_extr->SetRange(def_extr.min, def_extr.max);
 	auto *default_extr = dynamic_cast<const ConfigOptionInts*>(def_extr.default_value);
 	spin_extr->SetValue(default_extr != nullptr && default_extr->size() > 0 ? default_extr->get_at(0) : 200);
 
 	spin_bed->SetIncrement(5.0);
-	const auto &def_bed = print_config_def.options["bed_temperature"];
+	const auto &def_bed = *print_config_def.get("bed_temperature");
 	spin_bed->SetRange(def_bed.min, def_bed.max);
 	auto *default_bed = dynamic_cast<const ConfigOptionInts*>(def_bed.default_value);
 	spin_bed->SetValue(default_bed != nullptr && default_bed->size() > 0 ? default_bed->get_at(0) : 0);
diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp
index b8ad84ba4..d5d295839 100644
--- a/xs/xsp/Config.xsp
+++ b/xs/xsp/Config.xsp
@@ -137,7 +137,7 @@ PROTOTYPES: DISABLE
 SV*
 print_config_def()
     CODE:
-        t_optiondef_map &def = Slic3r::print_config_def.options;
+        t_optiondef_map &def = *const_cast<t_optiondef_map*>(&Slic3r::print_config_def.options);
         
         HV* options_hv = newHV();
         for (t_optiondef_map::iterator oit = def.begin(); oit != def.end(); ++oit) {