# Buggy code
def run(self):
    if not self._allow_root:
        self._check_for_root()

    if self._settings is None:
        self._settings = settings()

    if not self._settings.getBoolean(["server", "ignoreIncompleteStartup"]):
        self._settings.setBoolean(["server", "incompleteStartup"], True)
        self._settings.save()

    if self._plugin_manager is None:
        self._plugin_manager = octoprint.plugin.plugin_manager()

    global app
    global babel

    global printer
    global printerProfileManager
    global fileManager
    global slicingManager
    global analysisQueue
    global userManager
    global permissionManager
    global groupManager
    global eventManager
    global loginManager
    global pluginManager
    global pluginLifecycleManager
    global preemptiveCache
    global jsonEncoder
    global jsonDecoder
    global connectivityChecker
    global debug
    global safe_mode

    from tornado.ioloop import IOLoop
    from tornado.web import Application

    debug = self._debug
    safe_mode = self._safe_mode

    if self._v6_only and not octoprint.util.net.HAS_V6:
        raise RuntimeError("IPv6 only mode configured but system doesn't support IPv6")

    if self._host is None:
        host = self._settings.get(["server", "host"])
        if host is None:
            if octoprint.util.net.HAS_V6:
                host = "::"
            else:
                host = "0.0.0.0"

        self._host = host

    if ":" in self._host and not octoprint.util.net.HAS_V6:
        raise RuntimeError(
            "IPv6 host address {!r} configured but system doesn't support IPv6".format(
                self._host
            )
        )

    if self._port is None:
        self._port = self._settings.getInt(["server", "port"])
        if self._port is None:
            self._port = 5000

    self._logger = logging.getLogger(__name__)
    self._setup_heartbeat_logging()
    pluginManager = self._plugin_manager

    # monkey patch/fix some stuff
    util.tornado.fix_json_encode()
    util.tornado.fix_websocket_check_origin()
    util.flask.fix_flask_jsonify()

    self._setup_mimetypes()

    additional_translation_folders = []
    if not safe_mode:
        additional_translation_folders += [self._settings.getBaseFolder("translations")]
    util.flask.enable_additional_translations(
        additional_folders=additional_translation_folders
    )

    # setup app
    self._setup_app(app)

    # setup i18n
    self._setup_i18n(app)

    if self._settings.getBoolean(["serial", "log"]):
        # enable debug logging to serial.log
        logging.getLogger("SERIAL").setLevel(logging.DEBUG)

    # start the intermediary server
    self._start_intermediary_server()

    ### IMPORTANT!
    ###
    ### Best do not start any subprocesses until the intermediary server shuts down again or they MIGHT inherit the
    ### open port and prevent us from firing up Tornado later.
    ###
    ### The intermediary server's socket should have the CLOSE_EXEC flag (or its equivalent) set where possible, but
    ### we can only do that if fcntl is available or we are on Windows, so better safe than sorry.
    ###
    ### See also issues #2035 and #2090

    # then initialize the plugin manager
    pluginManager.reload_plugins(startup=True, initialize_implementations=False)

    printerProfileManager = PrinterProfileManager()
    eventManager = self._event_manager

    analysis_queue_factories = dict(
        gcode=octoprint.filemanager.analysis.GcodeAnalysisQueue
    )
    analysis_queue_hooks = pluginManager.get_hooks(
        "octoprint.filemanager.analysis.factory"
    )
    for name, hook in analysis_queue_hooks.items():
        try:
            additional_factories = hook()
            analysis_queue_factories.update(**additional_factories)
        except Exception:
            self._logger.exception(
                "Error while processing analysis queues from {}".format(name),
                extra=dict(plugin=name),
            )
    analysisQueue = octoprint.filemanager.analysis.AnalysisQueue(
        analysis_queue_factories
    )

    slicingManager = octoprint.slicing.SlicingManager(
        self._settings.getBaseFolder("slicingProfiles"), printerProfileManager
    )

    storage_managers = dict()
    storage_managers[octoprint.filemanager.FileDestinations.LOCAL] = (
        octoprint.filemanager.storage.LocalFileStorage(
            self._settings.getBaseFolder("uploads")
        )
    )

    fileManager = octoprint.filemanager.FileManager(
        analysisQueue,
        slicingManager,
        printerProfileManager,
        initial_storage_managers=storage_managers,
    )
    pluginLifecycleManager = LifecycleManager(pluginManager)
    preemptiveCache = PreemptiveCache(
        os.path.join(
            self._settings.getBaseFolder("data"), "preemptive_cache_config.yaml"
        )
    )

    JsonEncoding.add_encoder(users.User, lambda obj: obj.as_dict())
    JsonEncoding.add_encoder(groups.Group, lambda obj: obj.as_dict())
    JsonEncoding.add_encoder(permissions.OctoPrintPermission, lambda obj: obj.as_dict())

    # start regular check if we are connected to the internet
    def on_connectivity_change(old_value, new_value):
        eventManager.fire(
            events.Events.CONNECTIVITY_CHANGED,
            payload=dict(old=old_value, new=new_value),
        )

    connectivityChecker = self._connectivity_checker

    def on_settings_update(*args, **kwargs):
        # make sure our connectivity checker runs with the latest settings
        connectivityEnabled = self._settings.getBoolean(
            ["server", "onlineCheck", "enabled"]
        )
        connectivityInterval = self._settings.getInt(
            ["server", "onlineCheck", "interval"]
        )
        connectivityHost = self._settings.get(["server", "onlineCheck", "host"])
        connectivityPort = self._settings.getInt(["server", "onlineCheck", "port"])
        connectivityName = self._settings.get(["server", "onlineCheck", "name"])

        if (
            connectivityChecker.enabled != connectivityEnabled
            or connectivityChecker.interval != connectivityInterval
            or connectivityChecker.host != connectivityHost
            or connectivityChecker.port != connectivityPort
            or connectivityChecker.name != connectivityName
        ):
            connectivityChecker.enabled = connectivityEnabled
            connectivityChecker.interval = connectivityInterval
            connectivityChecker.host = connectivityHost
            connectivityChecker.port = connectivityPort
            connectivityChecker.name = connectivityName
            connectivityChecker.check_immediately()

    eventManager.subscribe(events.Events.SETTINGS_UPDATED, on_settings_update)

    components = dict(
        plugin_manager=pluginManager,
        printer_profile_manager=printerProfileManager,
        event_bus=eventManager,
        analysis_queue=analysisQueue,
        slicing_manager=slicingManager,
        file_manager=fileManager,
        plugin_lifecycle_manager=pluginLifecycleManager,
        preemptive_cache=preemptiveCache,
        json_encoder=jsonEncoder,
        json_decoder=jsonDecoder,
        connectivity_checker=connectivityChecker,
        environment_detector=self._environment_detector,
    )

    # ~~ setup access control

    # get additional permissions from plugins
    self._setup_plugin_permissions()

    # create group manager instance
    group_manager_factories = pluginManager.get_hooks("octoprint.access.groups.factory")
    for name, factory in group_manager_factories.items():
        try:
            groupManager = factory(components, self._settings)
            if groupManager is not None:
                self._logger.debug(
                    "Created group manager instance from factory {}".format(name)
                )
                break
        except Exception:
            self._logger.exception(
                "Error while creating group manager instance from factory {}".format(
                    name
                )
            )
    else:
        group_manager_name = self._settings.get(["accessControl", "groupManager"])
        try:
            clazz = octoprint.util.get_class(group_manager_name)
            groupManager = clazz()
        except AttributeError:
            self._logger.exception(
                "Could not instantiate group manager {}, "
                "falling back to FilebasedGroupManager!".format(group_manager_name)
            )
            groupManager = octoprint.access.groups.FilebasedGroupManager()
    components.update(dict(group_manager=groupManager))

    # create user manager instance
    user_manager_factories = pluginManager.get_hooks(
        "octoprint.users.factory"
    )  # legacy, set first so that new wins
    user_manager_factories.update(
        pluginManager.get_hooks("octoprint.access.users.factory")
    )
    for name, factory in user_manager_factories.items():
        try:
            userManager = factory(components, self._settings)
            if userManager is not None:
                self._logger.debug(
                    "Created user manager instance from factory {}".format(name)
                )
                break
        except Exception:
            self._logger.exception(
                "Error while creating user manager instance from factory {}".format(
                    name
                ),
                extra=dict(plugin=name),
            )
    else:
        user_manager_name = self._settings.get(["accessControl", "userManager"])
        try:
            clazz = octoprint.util.get_class(user_manager_name)
            userManager = clazz(groupManager)
        except Exception:
            self._logger.exception(
                "Could not instantiate user manager {}, "
                "falling back to FilebasedUserManager!".format(user_manager_name)
            )
            userManager = octoprint.access.users.FilebasedUserManager(groupManager)
        finally:
            userManager.enabled = self._settings.getBoolean(
                ["accessControl", "enabled"]
            )
    components.update(dict(user_manager=userManager))

    # create printer instance
    printer_factories = pluginManager.get_hooks("octoprint.printer.factory")
    for name, factory in printer_factories.items():
        try:
            printer = factory(components)
            if printer is not None:
                self._logger.debug(
                    "Created printer instance from factory {}".format(name)
                )
                break
        except Exception:
            self._logger.exception(
                "Error while creating printer instance from factory {}".format(name),
                extra=dict(plugin=name),
            )
    else:
        printer = Printer(fileManager, analysisQueue, printerProfileManager)
    components.update(dict(printer=printer))

    def octoprint_plugin_inject_factory(name, implementation):
        """Factory for injections for all OctoPrintPlugins"""
        if not isinstance(implementation, octoprint.plugin.OctoPrintPlugin):
            return None

        components_copy = dict(components)
        if "printer" in components:
            import wrapt
            import functools

            def tagwrap(f):
                @functools.wraps(f)
                def wrapper(*args, **kwargs):
                    tags = kwargs.get("tags", set()) | {
                        "source:plugin",
                        "plugin:{}".format(name),
                    }
                    kwargs["tags"] = tags
                    return f(*args, **kwargs)

                setattr(wrapper, "__tagwrapped__", True)
                return wrapper

            class TaggedFuncsPrinter(wrapt.ObjectProxy):
                def __getattribute__(self, attr):
                    __wrapped__ = super(TaggedFuncsPrinter, self).__getattribute__(
                        "__wrapped__"
                    )
                    if attr == "__wrapped__":
                        return __wrapped__

                    item = getattr(__wrapped__, attr)
                    if (
                        callable(item)
                        and (
                            "tags" in item.__code__.co_varnames
                            or "kwargs" in item.__code__.co_varnames
                        )
                        and not getattr(item, "__tagwrapped__", False)
                    ):
                        return tagwrap(item)
                    else:
                        return item

            components_copy["printer"] = TaggedFuncsPrinter(components["printer"])

        props = dict()
        props.update(components_copy)
        props.update(
            dict(data_folder=os.path.join(self._settings.getBaseFolder("data"), name))
        )
        return props

    def settings_plugin_inject_factory(name, implementation):
        """Factory for additional injections/initializations depending on plugin type"""
        if not isinstance(implementation, octoprint.plugin.SettingsPlugin):
            return

        default_settings_overlay = dict(plugins=dict())
        default_settings_overlay["plugins"][name] = (
            implementation.get_settings_defaults()
        )
        self._settings.add_overlay(default_settings_overlay, at_end=True)

        plugin_settings = octoprint.plugin.plugin_settings_for_settings_plugin(
            name, implementation
        )
        if plugin_settings is None:
            return

        return dict(settings=plugin_settings)

    def settings_plugin_config_migration_and_cleanup(identifier, implementation):
        """Take care of migrating and cleaning up any old settings"""

        if not isinstance(implementation, octoprint.plugin.SettingsPlugin):
            return

        settings_version = implementation.get_settings_version()
        settings_migrator = implementation.on_settings_migrate

        if settings_version is not None and settings_migrator is not None:
            stored_version = implementation._settings.get_int(
                [octoprint.plugin.SettingsPlugin.config_version_key]
            )
            if stored_version is None or stored_version < settings_version:
                settings_migrator(settings_version, stored_version)
                implementation._settings.set_int(
                    [octoprint.plugin.SettingsPlugin.config_version_key],
                    settings_version,
                    force=True,
                )

        implementation.on_settings_cleanup()
        implementation._settings.save()

        implementation.on_settings_initialized()

    custom_events_hooks = pluginManager.get_hooks(
        "octoprint.events.register_custom_events"
    )
    for name, hook in custom_events_hooks.items():
        try:
            result = hook()
            if isinstance(result, (list, tuple)):
                for event in result:
                    constant, value = octoprint.events.Events.register_event(
                        event, prefix="plugin_{}_".format(name)
                    )
                    self._logger.debug(
                        'Registered event {} of plugin {} as Events.{} = "{}"'.format(
                            event, name, constant, value
                        )
                    )
        except Exception:
            self._logger.exception(
                "Error while retrieving custom event list from plugin {}".format(name),
                extra=dict(plugin=name),
            )

    pluginManager.implementation_inject_factories = [
        octoprint_plugin_inject_factory,
        settings_plugin_inject_factory,
    ]
    pluginManager.initialize_implementations()

    settingsPlugins = pluginManager.get_implementations(octoprint.plugin.SettingsPlugin)
    for implementation in settingsPlugins:
        try:
            settings_plugin_config_migration_and_cleanup(
                implementation._identifier, implementation
            )
        except Exception:
            self._logger.exception(
                "Error while trying to migrate settings for "
                "plugin {}, ignoring it".format(implementation._identifier),
                extra=dict(plugin=implementation._identifier),
            )

    pluginManager.implementation_post_inits = [
        settings_plugin_config_migration_and_cleanup
    ]

    pluginManager.log_all_plugins()

    # log environment data now
    self._environment_detector.log_detected_environment()

    # initialize file manager and register it for changes in the registered plugins
    fileManager.initialize()
    pluginLifecycleManager.add_callback(
        ["enabled", "disabled"], lambda name, plugin: fileManager.reload_plugins()
    )

    # initialize slicing manager and register it for changes in the registered plugins
    slicingManager.initialize()
    pluginLifecycleManager.add_callback(
        ["enabled", "disabled"], lambda name, plugin: slicingManager.reload_slicers()
    )

    # setup jinja2
    self._setup_jinja2()

    # setup assets
    self._setup_assets()

    # configure timelapse
    octoprint.timelapse.valid_timelapse("test")
    octoprint.timelapse.configure_timelapse()

    # setup command triggers
    events.CommandTrigger(printer)
    if self._debug:
        events.DebugEventListener()

    # setup login manager
    self._setup_login_manager()

    # register API blueprint
    self._setup_blueprints()

    ## Tornado initialization starts here

    ioloop = IOLoop()
    ioloop.install()

    enable_cors = settings().getBoolean(["api", "allowCrossOrigin"])

    self._router = SockJSRouter(
        self._create_socket_connection,
        "/sockjs",
        session_kls=util.sockjs.ThreadSafeSession,
        user_settings=dict(
            websocket_allow_origin="*" if enable_cors else "",
            jsessionid=False,
            sockjs_url="../../static/js/lib/sockjs.min.js",
        ),
    )

    upload_suffixes = dict(
        name=self._settings.get(["server", "uploads", "nameSuffix"]),
        path=self._settings.get(["server", "uploads", "pathSuffix"]),
    )

    def mime_type_guesser(path):
        from octoprint.filemanager import get_mime_type

        return get_mime_type(path)

    def download_name_generator(path):
        metadata = fileManager.get_metadata("local", path)
        if metadata and "display" in metadata:
            return metadata["display"]

    download_handler_kwargs = dict(as_attachment=True, allow_client_caching=False)

    additional_mime_types = dict(mime_type_guesser=mime_type_guesser)

    ##~~ Permission validators

    access_validators_from_plugins = []
    for plugin, hook in pluginManager.get_hooks(
        "octoprint.server.http.access_validator"
    ).items():
        try:
            access_validators_from_plugins.append(
                util.tornado.access_validation_factory(app, hook)
            )
        except Exception:
            self._logger.exception(
                "Error while adding tornado access validator from plugin {}".format(
                    plugin
                ),
                extra=dict(plugin=plugin),
            )
    access_validator = dict(
        access_validation=util.tornado.validation_chain(*access_validators_from_plugins)
    )

    timelapse_validators = [
        util.tornado.access_validation_factory(
            app, util.flask.permission_validator, permissions.Permissions.TIMELAPSE_LIST
        ),
    ] + access_validators_from_plugins
    download_validators = [
        util.tornado.access_validation_factory(
            app, util.flask.permission_validator, permissions.Permissions.FILES_DOWNLOAD
        ),
    ] + access_validators_from_plugins
    log_validators = [
        util.tornado.access_validation_factory(
            app,
            util.flask.permission_validator,
            permissions.Permissions.PLUGIN_LOGGING_MANAGE,
        ),
    ] + access_validators_from_plugins
    camera_validators = [
        util.tornado.access_validation_factory(
            app, util.flask.permission_validator, permissions.Permissions.WEBCAM
        ),
    ] + access_validators_from_plugins

    timelapse_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*timelapse_validators)
    )
    download_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*download_validators)
    )
    log_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*log_validators)
    )
    camera_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*camera_validators)
    )

    no_hidden_files_validator = dict(
        path_validation=util.tornado.path_validation_factory(
            lambda path: not octoprint.util.is_hidden_path(path), status_code=404
        )
    )
    timelapse_path_validator = dict(
        path_validation=util.tornado.path_validation_factory(
            lambda path: not octoprint.util.is_hidden_path(path)
            and octoprint.timelapse.valid_timelapse(path),
            status_code=404,
        )
    )

    def joined_dict(*dicts):
        if not len(dicts):
            return dict()

        joined = dict()
        for d in dicts:
            joined.update(d)
        return joined

    util.tornado.RequestlessExceptionLoggingMixin.LOG_REQUEST = debug
    util.tornado.CorsSupportMixin.ENABLE_CORS = enable_cors

    server_routes = self._router.urls + [
        # various downloads
        # .mpg and .mp4 timelapses:
        (
            r"/downloads/timelapse/(.*)",
            util.tornado.LargeResponseHandler,
            joined_dict(
                dict(path=self._settings.getBaseFolder("timelapse")),
                timelapse_permission_validator,
                download_handler_kwargs,
                timelapse_path_validator,
            ),
        ),
        (
            r"/downloads/files/local/(.*)",
            util.tornado.LargeResponseHandler,
            joined_dict(
                dict(
                    path=self._settings.getBaseFolder("uploads"),
                    as_attachment=True,
                    name_generator=download_name_generator,
                ),
                download_permission_validator,
                download_handler_kwargs,
                no_hidden_files_validator,
                additional_mime_types,
            ),
        ),
        (
            r"/downloads/logs/([^/]*)",
            util.tornado.LargeResponseHandler,
            joined_dict(
                dict(
                    path=self._settings.getBaseFolder("logs"),
                    mime_type_guesser=lambda *args, **kwargs: "text/plain",
                ),
                download_handler_kwargs,
                log_permission_validator,
            ),
        ),
        # camera snapshot
        (
            r"/downloads/camera/current",
            util.tornado.UrlProxyHandler,
            joined_dict(
                dict(
                    url=self._settings.get(["webcam", "snapshot"]), as_attachment=True
                ),
                camera_permission_validator,
            ),
        ),
        # generated webassets
        (
            r"/static/webassets/(.*)",
            util.tornado.LargeResponseHandler,
            dict(
                path=os.path.join(
                    self._settings.getBaseFolder("generated"), "webassets"
                ),
                is_pre_compressed=True,
            ),
        ),
        # online indicators - text file with "online" as content and a transparent gif
        (r"/online.txt", util.tornado.StaticDataHandler, dict(data="online\n")),
        (
            r"/online.gif",
            util.tornado.StaticDataHandler,
            dict(
                data=bytes(
                    base64.b64decode(
                        "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
                    )
                ),
                content_type="image/gif",
            ),
        ),
        # deprecated endpoints
        (
            r"/api/logs",
            util.tornado.DeprecatedEndpointHandler,
            dict(url="/plugin/logging/logs"),
        ),
        (
            r"/api/logs/(.*)",
            util.tornado.DeprecatedEndpointHandler,
            dict(url="/plugin/logging/logs/{0}"),
        ),
    ]

    # fetch additional routes from plugins
    for name, hook in pluginManager.get_hooks("octoprint.server.http.routes").items():
        try:
            result = hook(list(server_routes))
        except Exception:
            self._logger.exception(
                "There was an error while retrieving additional "
                "server routes from plugin hook {name}".format(**locals()),
                extra=dict(plugin=name),
            )
        else:
            if isinstance(result, (list, tuple)):
                for entry in result:
                    if not isinstance(entry, tuple) or not len(entry) == 3:
                        continue
                    if not isinstance(entry[0], basestring):
                        continue
                    if not isinstance(entry[2], dict):
                        continue

                    route, handler, kwargs = entry
                    route = r"/plugin/{name}/{route}".format(
                        name=name,
                        route=route if not route.startswith("/") else route[1:],
                    )

                    self._logger.debug(
                        "Adding additional route {route} handled by handler {handler} and with additional arguments {kwargs!r}".format(
                            **locals()
                        )
                    )
                    server_routes.append((route, handler, kwargs))

    headers = {
        "X-Robots-Tag": "noindex, nofollow, noimageindex",
        "X-Content-Type-Options": "nosniff",
    }
    if not settings().getBoolean(["server", "allowFraming"]):
        headers["X-Frame-Options"] = "sameorigin"

    removed_headers = ["Server"]

    server_routes.append(
        (
            r".*",
            util.tornado.UploadStorageFallbackHandler,
            dict(
                fallback=util.tornado.WsgiInputContainer(
                    app.wsgi_app, headers=headers, removed_headers=removed_headers
                ),
                file_prefix="octoprint-file-upload-",
                file_suffix=".tmp",
                suffixes=upload_suffixes,
            ),
        )
    )

    transforms = [
        util.tornado.GlobalHeaderTransform.for_headers(
            "OctoPrintGlobalHeaderTransform",
            headers=headers,
            removed_headers=removed_headers,
        )
    ]

    self._tornado_app = Application(handlers=server_routes, transforms=transforms)
    max_body_sizes = [
        (
            "POST",
            r"/api/files/([^/]*)",
            self._settings.getInt(["server", "uploads", "maxSize"]),
        ),
        ("POST", r"/api/languages", 5 * 1024 * 1024),
    ]

    # allow plugins to extend allowed maximum body sizes
    for name, hook in pluginManager.get_hooks("octoprint.server.http.bodysize").items():
        try:
            result = hook(list(max_body_sizes))
        except Exception:
            self._logger.exception(
                "There was an error while retrieving additional "
                "upload sizes from plugin hook {name}".format(**locals()),
                extra=dict(plugin=name),
            )
        else:
            if isinstance(result, (list, tuple)):
                for entry in result:
                    if not isinstance(entry, tuple) or not len(entry) == 3:
                        continue
                    if (
                        not entry[0]
                        in util.tornado.UploadStorageFallbackHandler.BODY_METHODS
                    ):
                        continue
                    if not isinstance(entry[2], int):
                        continue

                    method, route, size = entry
                    route = r"/plugin/{name}/{route}".format(
                        name=name,
                        route=route if not route.startswith("/") else route[1:],
                    )

                    self._logger.debug(
                        "Adding maximum body size of {size}B for {method} requests to {route})".format(
                            **locals()
                        )
                    )
                    max_body_sizes.append((method, route, size))

    self._stop_intermediary_server()

    # initialize and bind the server
    trusted_downstream = self._settings.get(
        ["server", "reverseProxy", "trustedDownstream"]
    )
    if not isinstance(trusted_downstream, list):
        self._logger.warning(
            "server.reverseProxy.trustedDownstream is not a list, skipping"
        )
        trusted_downstreams = []

    server_kwargs = dict(
        max_body_sizes=max_body_sizes,
        default_max_body_size=self._settings.getInt(["server", "maxSize"]),
        xheaders=True,
        trusted_downstream=trusted_downstream,
    )
    if sys.platform == "win32":
        # set 10min idle timeout under windows to hopefully make #2916 less likely
        server_kwargs.update(dict(idle_connection_timeout=600))

    self._server = util.tornado.CustomHTTPServer(self._tornado_app, **server_kwargs)

    listening_address = self._host
    if self._host == "::" and not self._v6_only:
        # special case - tornado only listens on v4 _and_ v6 if we use None as address
        listening_address = None

    self._server.listen(self._port, address=listening_address)

    ### From now on it's ok to launch subprocesses again

    eventManager.fire(events.Events.STARTUP)

    # analysis backlog
    fileManager.process_backlog()

    # auto connect
    if self._settings.getBoolean(["serial", "autoconnect"]):
        self._logger.info(
            "Autoconnect on startup is configured, trying to connect to the printer..."
        )
        try:
            (port, baudrate) = (
                self._settings.get(["serial", "port"]),
                self._settings.getInt(["serial", "baudrate"]),
            )
            printer_profile = printerProfileManager.get_default()
            connectionOptions = printer.__class__.get_connection_options()
            if port in connectionOptions["ports"] or port == "AUTO" or port is None:
                self._logger.info(
                    "Trying to connect to configured serial port {}".format(port)
                )
                printer.connect(
                    port=port,
                    baudrate=baudrate,
                    profile=printer_profile["id"]
                    if "id" in printer_profile
                    else "_default",
                )
            else:
                self._logger.info(
                    "Could not find configured serial port {} in the system, cannot automatically connect to a non existing printer. Is it plugged in and booted up yet?"
                )
        except Exception:
            self._logger.exception(
                "Something went wrong while attempting to automatically connect to the printer"
            )

    # start up watchdogs
    watched = self._settings.getBaseFolder("watched")
    watchdog_handler = util.watchdog.GcodeWatchdogHandler(fileManager, printer)
    watchdog_handler.initial_scan(watched)

    if self._settings.getBoolean(["feature", "pollWatched"]):
        # use less performant polling observer if explicitly configured
        observer = PollingObserver()
    else:
        # use os default
        observer = Observer()
    observer.schedule(watchdog_handler, watched, recursive=True)
    observer.start()

    # run our startup plugins
    octoprint.plugin.call_plugin(
        octoprint.plugin.StartupPlugin,
        "on_startup",
        args=(self._host, self._port),
        sorting_context="StartupPlugin.on_startup",
    )

    def call_on_startup(name, plugin):
        implementation = plugin.get_implementation(octoprint.plugin.StartupPlugin)
        if implementation is None:
            return
        implementation.on_startup(self._host, self._port)

    pluginLifecycleManager.add_callback("enabled", call_on_startup)

    # prepare our after startup function
    def on_after_startup():
        if self._host == "::":
            if self._v6_only:
                # only v6
                self._logger.info(
                    "Listening on http://[::]:{port}".format(port=self._port)
                )
            else:
                # all v4 and v6
                self._logger.info(
                    "Listening on http://0.0.0.0:{port} and http://[::]:{port}".format(
                        port=self._port
                    )
                )
        else:
            self._logger.info(
                "Listening on http://{}:{}".format(
                    self._host if not ":" in self._host else "[" + self._host + "]",
                    self._port,
                )
            )

        if safe_mode and self._settings.getBoolean(["server", "startOnceInSafeMode"]):
            self._logger.info(
                "Server started successfully in safe mode as requested from config, removing flag"
            )
            self._settings.setBoolean(["server", "startOnceInSafeMode"], False)
            self._settings.save()

        # now this is somewhat ugly, but the issue is the following: startup plugins might want to do things for
        # which they need the server to be already alive (e.g. for being able to resolve urls, such as favicons
        # or service xmls or the like). While they are working though the ioloop would block. Therefore we'll
        # create a single use thread in which to perform our after-startup-tasks, start that and hand back
        # control to the ioloop
        def work():
            octoprint.plugin.call_plugin(
                octoprint.plugin.StartupPlugin,
                "on_after_startup",
                sorting_context="StartupPlugin.on_after_startup",
            )

            def call_on_after_startup(name, plugin):
                implementation = plugin.get_implementation(
                    octoprint.plugin.StartupPlugin
                )
                if implementation is None:
                    return
                implementation.on_after_startup()

            pluginLifecycleManager.add_callback("enabled", call_on_after_startup)

            # if there was a rogue plugin we wouldn't even have made it here, so remove startup triggered safe mode
            # flag again...
            self._settings.setBoolean(["server", "incompleteStartup"], False)
            self._settings.save()

            # make a backup of the current config
            self._settings.backup(ext="backup")

            # when we are through with that we also run our preemptive cache
            if settings().getBoolean(["devel", "cache", "preemptive"]):
                self._execute_preemptive_flask_caching(preemptiveCache)

        import threading

        threading.Thread(target=work).start()

    ioloop.add_callback(on_after_startup)

    # prepare our shutdown function
    def on_shutdown():
        # will be called on clean system exit and shutdown the watchdog observer and call the on_shutdown methods
        # on all registered ShutdownPlugins
        self._logger.info("Shutting down...")
        observer.stop()
        observer.join()
        eventManager.fire(events.Events.SHUTDOWN)

        self._logger.info("Calling on_shutdown on plugins")
        octoprint.plugin.call_plugin(
            octoprint.plugin.ShutdownPlugin,
            "on_shutdown",
            sorting_context="ShutdownPlugin.on_shutdown",
        )

        # wait for shutdown event to be processed, but maximally for 15s
        event_timeout = 15.0
        if eventManager.join(timeout=event_timeout):
            self._logger.warning(
                "Event loop was still busy processing after {}s, shutting down anyhow".format(
                    event_timeout
                )
            )

        if self._octoprint_daemon is not None:
            self._logger.info("Cleaning up daemon pidfile")
            self._octoprint_daemon.terminated()

        self._logger.info("Goodbye!")

    atexit.register(on_shutdown)

    def sigterm_handler(*args, **kwargs):
        # will stop tornado on SIGTERM, making the program exit cleanly
        def shutdown_tornado():
            self._logger.debug("Shutting down tornado's IOLoop...")
            ioloop.stop()

        self._logger.debug("SIGTERM received...")
        ioloop.add_callback_from_signal(shutdown_tornado)

    signal.signal(signal.SIGTERM, sigterm_handler)

    try:
        # this is the main loop - as long as tornado is running, OctoPrint is running
        ioloop.start()
        self._logger.debug("Tornado's IOLoop stopped")
    except (KeyboardInterrupt, SystemExit):
        pass
    except Exception:
        self._logger.fatal(
            "Now that is embarrassing... Something really really went wrong here. Please report this including the stacktrace below in OctoPrint's bugtracker. Thanks!"
        )
        self._logger.exception("Stacktrace follows:")


# Traceback (AttributeError)
pi@octoprint:~ $ cat ~/.octoprint/logs/octoprint.log
2020-08-04 00:21:23,030 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 00:21:23,035 - octoprint.server - INFO - --- Log roll over detected ---------------------------------------------------
2020-08-04 00:21:23,036 - octoprint.server - INFO - OctoPrint 1.4.0
2020-08-04 00:21:23,041 - octoprint.plugin.core - INFO - 19 plugin(s) registered with the system:
|  Action Command Prompt Support (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/action_command_prompt
|  Announcement Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/announcements
|  Anonymous Usage Tracking (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/tracking
|  Application Keys Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/appkeys
|  Backup &amp; Restore (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/backup
|  Core Wizard (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/corewizard
|  Discovery (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/discovery
|  EEPROM Editor for MPSM (0.1.1) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_eeprom_MPSelectMini
|  Error Tracking (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/errortracking
|  Logging (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/logging
|  Login UI (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/loginui
|  Malyan/Monoprice Connection Fix (0.1.3) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_malyan_connection_fix
|  Pi Support Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pi_support
|  Plugin Manager (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pluginmanager
|  PortLister (0.1.10) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_portlister
|  Printer Safety Check (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/printer_safety_check
|  Prusa Leveling Guide (1.0.8) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_PrusaLevelingGuide
|  Software Update (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/softwareupdate
|  Virtual Printer (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/virtual_printer
Prefix legend: ! = disabled, # = blacklisted, * = incompatible
2020-08-04 00:21:23,063 - octoprint.environment - INFO - Detected environment is Python 2.7.16 under Linux (linux2). Details:
|  hardware:
|      cores: 4
|      freq: 1200.0
|      ram: 917708800
|  os:
|      id: linux
|      platform: linux2
|  plugins:
|      pi_support:
|          model: Raspberry Pi 3 Model B Rev 1.2
|          octopi_version: 0.17.0
|  python:
|      pip: 19.3.1
|      version: 2.7.16
|      virtualenv: /home/pi/oprint
2020-08-04 00:21:23,063 - octoprint.server - INFO - ------------------------------------------------------------------------------
2020-08-04 00:36:23,032 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 00:51:23,034 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 01:06:23,035 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 01:21:23,039 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 01:24:36,978 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.30
2020-08-04 01:36:23,041 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 01:51:23,043 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 02:06:23,045 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 02:21:23,048 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 02:36:23,051 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 02:51:23,053 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 03:06:23,055 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 03:21:23,058 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 03:36:23,060 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 03:51:23,062 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 04:06:23,064 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 04:21:23,066 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 04:36:23,069 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 04:51:23,073 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 05:06:23,075 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 05:21:23,078 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 05:36:23,080 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 05:51:23,082 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 06:06:23,084 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 06:21:23,087 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 06:36:23,089 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 06:51:23,092 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 07:06:23,095 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 07:21:23,098 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 07:36:23,100 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 07:51:23,103 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 08:06:23,105 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 08:21:23,106 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 08:36:23,110 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 08:51:23,113 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 09:06:23,115 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 09:21:23,116 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 09:36:23,119 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 09:51:23,122 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 09:52:33,780 - octoprint.util.comm - INFO - Finished in 39429.569 s.
2020-08-04 09:52:33,782 - octoprint.util.comm - INFO - Changing monitoring state from "Printing" to "Finishing"
2020-08-04 09:52:33,788 - octoprint.filemanager.analysis - INFO - Starting analysis of local:MK3_PLA_3D_scanner.gcode
2020-08-04 09:52:33,795 - octoprint.filemanager.analysis - INFO - Invoking analysis command: /home/pi/oprint/bin/python2 -m octoprint analysis gcode --speed-x=10200 --speed-y=10200 --max-t=10 --throttle=0.0 --throttle-lines=100 /home/pi/.octoprint/uploads/MK3_PLA_3D_scanner.gcode
2020-08-04 09:52:33,805 - octoprint.printer.standard.job - INFO - Print job done - origin: local, path: MK3_PLA_3D_scanner.gcode, owner: _api
2020-08-04 09:52:33,854 - octoprint.util.comm - INFO - Changing monitoring state from "Finishing" to "Operational"
2020-08-04 09:54:08,637 - octoprint.filemanager.analysis - INFO - Analysis of entry local:MK3_PLA_3D_scanner.gcode finished, needed 94.85s
2020-08-04 10:03:05,705 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.30
2020-08-04 10:03:05,857 - octoprint.server.util.flask - INFO - Passively logging in user nirvdrum from ::ffff:192.168.13.30
2020-08-04 10:03:05,858 - octoprint.access.users - INFO - Cleaning up user session 0FB7BFDA583845BF81D4C4FF47851B14 for user nirvdrum
2020-08-04 10:03:05,859 - octoprint.access.users - INFO - Logged out user: nirvdrum
2020-08-04 10:03:05,859 - octoprint.access.users - INFO - Logged in user: nirvdrum
2020-08-04 10:03:06,035 - octoprint.server.util.sockjs - INFO - User nirvdrum logged in on the socket from client ::ffff:192.168.13.30
2020-08-04 10:06:23,125 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 10:07:15,116 - octoprint.filemanager.analysis - INFO - Starting analysis of local:MK3_PLA_3D_scanner.gcode
2020-08-04 10:07:15,119 - octoprint.filemanager.analysis - INFO - Invoking analysis command: /home/pi/oprint/bin/python2 -m octoprint analysis gcode --speed-x=10200 --speed-y=10200 --max-t=10 --throttle=0.0 --throttle-lines=100 /home/pi/.octoprint/uploads/MK3_PLA_3D_scanner.gcode
2020-08-04 10:07:15,150 - octoprint.printer.standard.job - INFO - Print job selected - origin: local, path: MK3_PLA_3D_scanner.gcode, owner: _api, user: _api
2020-08-04 10:07:15,177 - octoprint.util.comm - INFO - Changing monitoring state from "Operational" to "Starting"
2020-08-04 10:07:15,186 - octoprint.printer.standard.job - INFO - Print job started - origin: local, path: MK3_PLA_3D_scanner.gcode, owner: _api, user: _api
2020-08-04 10:07:15,203 - octoprint.util.comm - INFO - M110 detected, setting current line number to 0
2020-08-04 10:07:15,216 - octoprint.util.comm - INFO - Changing monitoring state from "Starting" to "Printing"
2020-08-04 10:21:23,127 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 10:36:23,129 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 10:51:23,132 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 10:53:52,992 - octoprint.server.util.sockjs - INFO - New connection from client: fe80::d65:fec9:a521:d32c
2020-08-04 10:53:54,040 - tornado.access - WARNING - 403 GET /api/settings (fe80::d65:fec9:a521:d32c) 150.68ms
2020-08-04 11:03:35,162 - octoprint.server.util.sockjs - INFO - Client connection closed: fe80::d65:fec9:a521:d32c
2020-08-04 11:06:23,135 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 11:10:16,030 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.37
2020-08-04 11:10:16,151 - octoprint.server.util.flask - INFO - Passively logging in user nirvdrum from ::ffff:192.168.13.37
2020-08-04 11:10:16,154 - octoprint.access.users - INFO - Cleaning up user session 0FB7BFDA583845BF81D4C4FF47851B14 for user nirvdrum
2020-08-04 11:10:16,156 - octoprint.server.util.sockjs - INFO - User nirvdrum logged out, logging out on socket
2020-08-04 11:10:16,161 - octoprint.access.users - INFO - Logged out user: nirvdrum
2020-08-04 11:10:16,163 - octoprint.access.users - INFO - Logged in user: nirvdrum
2020-08-04 11:10:16,215 - octoprint.server.util.sockjs - INFO - User nirvdrum logged in on the socket from client ::ffff:192.168.13.37
2020-08-04 11:21:23,136 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 11:25:45,458 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.30
2020-08-04 11:36:23,139 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 11:50:29,621 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.37
2020-08-04 11:51:23,141 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 11:51:35,350 - octoprint.server.util.sockjs - INFO - New connection from client: fe80::d65:fec9:a521:d32c
2020-08-04 11:51:36,338 - tornado.access - WARNING - 403 GET /api/settings (fe80::d65:fec9:a521:d32c) 132.14ms
2020-08-04 12:01:38,056 - octoprint.server.util.sockjs - INFO - Client connection closed: fe80::d65:fec9:a521:d32c
2020-08-04 12:06:23,144 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 12:21:23,148 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 12:36:23,150 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 12:51:23,153 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 13:06:23,154 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 13:14:39,925 - octoprint.util.comm - INFO - Got a resend request from the printer: requested line = 90466, current line = 90482
| Last lines in terminal:
| Recv: ok
| Send: N90481 G1 X47.881 Y163.292 E0.08192*91
| Recv: echo:enqueing "G1 E-1.000 F2700"
| Recv: echo:enqueing "G1 Z15.600 F800.000"
| Recv: echo:enqueing "CRASH_DETECTEDY"
| Recv: tmc2130_home_enter(axes_mask=0x01)
| Recv: echo:busy: processing
| Recv:   0 step=30 mscnt= 483
| Recv: tmc2130_goto_step 0 45 2 1000
| Recv: tmc2130_home_exit tmc2130_sg_homing_axes_mask=0x01
| Recv: tmc2130_home_enter(axes_mask=0x02)
| Recv: echo:busy: processing
| Recv: echo:busy: processing
| Recv:   0 step=49 mscnt= 799
| Recv: tmc2130_goto_step 1 33 2 1000
| Recv: tmc2130_home_exit tmc2130_sg_homing_axes_mask=0x02
| Recv: echo:enqueing "CRASH_RECOVER"
| Recv: echo:busy: processing
| Recv: echo:busy: processing
| Recv: Resend: 90466
2020-08-04 13:21:23,157 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 13:36:23,161 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 13:51:23,163 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 14:06:23,166 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 14:21:23,168 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 14:36:23,170 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 14:51:23,173 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 15:06:23,176 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 15:21:23,178 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 15:36:23,180 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 15:51:23,182 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 16:00:11,538 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.19
2020-08-04 16:00:12,609 - tornado.access - WARNING - 403 GET /api/settings (::ffff:192.168.13.19) 128.82ms
2020-08-04 16:06:23,186 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 16:10:38,802 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.19
2020-08-04 16:21:23,190 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 16:36:23,192 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 16:51:23,196 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 17:06:23,200 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 17:21:23,201 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 17:34:10,627 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:34:20,625 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:34:30,637 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:34:34,676 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:34,708 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('169.254.55.4', 61106), not sending a M-SEARCH reply
2020-08-04 17:34:34,815 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:34,852 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:34,880 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:37,692 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:37,720 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('169.254.55.4', 61106), not sending a M-SEARCH reply
2020-08-04 17:34:37,728 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:38,333 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:38,362 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:40,648 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:34:40,700 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:40,728 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('169.254.55.4', 61106), not sending a M-SEARCH reply
2020-08-04 17:34:40,734 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.30', 61110), not sending a M-SEARCH reply
2020-08-04 17:34:41,296 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 18248), not sending a M-SEARCH reply
2020-08-04 17:34:41,302 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 18248), not sending a M-SEARCH reply
2020-08-04 17:34:50,675 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:34:51,594 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 15431), not sending a M-SEARCH reply
2020-08-04 17:34:51,601 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 15431), not sending a M-SEARCH reply
2020-08-04 17:35:00,650 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:35:10,661 - octoprint.plugins.discovery - WARNING - Can't determine address to user for client ('192.168.13.202', 38609), not sending a M-SEARCH reply
2020-08-04 17:36:23,204 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 17:51:23,207 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 18:06:23,209 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 18:21:23,211 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 18:36:23,212 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 18:51:23,214 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 19:06:23,217 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 19:21:23,219 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 19:36:23,222 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 19:51:23,226 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 20:06:23,228 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 20:21:23,231 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 20:36:23,234 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 20:51:23,238 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 21:06:17,671 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.37
2020-08-04 21:06:17,813 - octoprint.server.util.flask - INFO - Passively logging in user nirvdrum from ::ffff:192.168.13.37
2020-08-04 21:06:17,815 - octoprint.access.users - INFO - Cleaning up user session 0FB7BFDA583845BF81D4C4FF47851B14 for user nirvdrum
2020-08-04 21:06:17,817 - octoprint.access.users - INFO - Logged out user: nirvdrum
2020-08-04 21:06:17,818 - octoprint.access.users - INFO - Logged in user: nirvdrum
2020-08-04 21:06:23,239 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 21:06:23,249 - octoprint.server.util.sockjs - INFO - User nirvdrum logged in on the socket from client ::ffff:192.168.13.37
2020-08-04 21:06:24,606 - octoprint.plugins.pluginmanager - INFO - Loaded plugin notices data from https://plugins.octoprint.org/notices.json
2020-08-04 21:21:23,243 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 21:36:23,248 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 21:51:23,249 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 22:04:03,698 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.37
2020-08-04 22:06:23,252 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 22:10:31,689 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.30
2020-08-04 22:10:31,826 - octoprint.server.util.flask - INFO - Passively logging in user nirvdrum from ::ffff:192.168.13.30
2020-08-04 22:10:31,827 - octoprint.access.users - INFO - Cleaning up user session 0FB7BFDA583845BF81D4C4FF47851B14 for user nirvdrum
2020-08-04 22:10:31,828 - octoprint.access.users - INFO - Logged out user: nirvdrum
2020-08-04 22:10:31,830 - octoprint.access.users - INFO - Logged in user: nirvdrum
2020-08-04 22:10:31,908 - octoprint.server.util.sockjs - INFO - User nirvdrum logged in on the socket from client ::ffff:192.168.13.30
2020-08-04 22:21:23,254 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 22:32:04,979 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.30
2020-08-04 22:36:23,256 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 22:51:23,257 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 22:59:36,485 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.30
2020-08-04 22:59:36,619 - octoprint.server.util.flask - INFO - Passively logging in user nirvdrum from ::ffff:192.168.13.30
2020-08-04 22:59:36,621 - octoprint.access.users - INFO - Cleaning up user session 0FB7BFDA583845BF81D4C4FF47851B14 for user nirvdrum
2020-08-04 22:59:36,623 - octoprint.access.users - INFO - Logged out user: nirvdrum
2020-08-04 22:59:36,625 - octoprint.access.users - INFO - Logged in user: nirvdrum
2020-08-04 22:59:36,693 - octoprint.server.util.sockjs - INFO - User nirvdrum logged in on the socket from client ::ffff:192.168.13.30
2020-08-04 23:02:23,034 - octoprint.util.comm - INFO - Finished in 46507.859 s.
2020-08-04 23:02:23,038 - octoprint.util.comm - INFO - Changing monitoring state from "Printing" to "Finishing"
2020-08-04 23:02:23,051 - octoprint.filemanager.analysis - INFO - Starting analysis of local:MK3_PLA_3D_scanner.gcode
2020-08-04 23:02:23,056 - octoprint.filemanager.analysis - INFO - Invoking analysis command: /home/pi/oprint/bin/python2 -m octoprint analysis gcode --speed-x=10200 --speed-y=10200 --max-t=10 --throttle=0.0 --throttle-lines=100 /home/pi/.octoprint/uploads/MK3_PLA_3D_scanner.gcode
2020-08-04 23:02:23,068 - octoprint.printer.standard.job - INFO - Print job done - origin: local, path: MK3_PLA_3D_scanner.gcode, owner: _api
2020-08-04 23:02:23,220 - octoprint.util.comm - INFO - Changing monitoring state from "Finishing" to "Operational"
2020-08-04 23:04:18,840 - octoprint.filemanager.analysis - INFO - Analysis of entry local:MK3_PLA_3D_scanner.gcode finished, needed 115.79s
2020-08-04 23:06:23,259 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 23:21:12,994 - octoprint.server.util.sockjs - INFO - Client connection closed: ::ffff:192.168.13.30
2020-08-04 23:21:23,260 - octoprint.server.heartbeat - INFO - Server heartbeat <3
2020-08-04 23:30:32,565 - octoprint.server.util.sockjs - INFO - New connection from client: ::ffff:192.168.13.30
2020-08-04 23:30:32,745 - octoprint.server.util.flask - INFO - Passively logging in user nirvdrum from ::ffff:192.168.13.30
2020-08-04 23:30:32,746 - octoprint.access.users - INFO - Cleaning up user session 0FB7BFDA583845BF81D4C4FF47851B14 for user nirvdrum
2020-08-04 23:30:32,748 - octoprint.access.users - INFO - Logged out user: nirvdrum
2020-08-04 23:30:32,749 - octoprint.access.users - INFO - Logged in user: nirvdrum
2020-08-04 23:30:33,409 - octoprint.server.util.sockjs - INFO - User nirvdrum logged in on the socket from client ::ffff:192.168.13.30
2020-08-04 23:30:34,426 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2020-08-04 23:30:35,300 - octoprint.plugins.pluginmanager - INFO - Loaded plugin repository data from https://plugins.octoprint.org/plugins.json
2020-08-04 23:30:40,937 - octoprint.plugins.softwareupdate - INFO - Starting update of octoprint to 1.4.1...
2020-08-04 23:32:32,113 - octoprint.plugins.softwareupdate - INFO - Update of octoprint to 1.4.1 successful!
2020-08-04 23:32:32,247 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2020-08-04 23:32:32,252 - octoprint.plugins.softwareupdate - INFO - Restarting...
2020-08-04 23:32:32,922 - octoprint.server - INFO - Shutting down...
2020-08-04 23:32:33,227 - octoprint.events - INFO - Processing shutdown event, this will be our last event
2020-08-04 23:32:33,231 - octoprint.events - INFO - Event loop shut down
2020-08-04 23:32:33,248 - octoprint.server - INFO - Goodbye!
2020-08-04 23:32:35,399 - octoprint.startup - INFO - ******************************************************************************
2020-08-04 23:32:35,401 - octoprint.startup - INFO - Starting OctoPrint 1.4.1
2020-08-04 23:32:35,402 - octoprint.startup - INFO - ******************************************************************************
2020-08-04 23:32:36,071 - octoprint.util.connectivity.connectivity_checker - INFO - Connectivity state is currently: online
2020-08-04 23:32:36,071 - octoprint.util.connectivity.connectivity_checker - INFO - Connecting to 1.1.1.1:53 is working
2020-08-04 23:32:36,073 - octoprint.util.connectivity.connectivity_checker - INFO - Resolving octoprint.org is working
2020-08-04 23:32:36,548 - octoprint.startup - INFO - Blacklist processing done, adding 1 blacklisted plugin versions: roomtemp (any)
2020-08-04 23:32:36,604 - octoprint.plugin.core - INFO - Loading plugins from /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins, /home/pi/.octoprint/plugins and installed plugin packages...
2020-08-04 23:32:37,909 - octoprint.plugin.core - INFO - Found 22 plugin(s) providing 22 mixin implementations, 39 hook handlers
2020-08-04 23:32:38,230 - octoprint.server.heartbeat - INFO - Starting server heartbeat, 900.0s interval
2020-08-04 23:32:38,257 - octoprint.server - INFO - Intermediary server started
2020-08-04 23:32:38,258 - octoprint.plugin.core - INFO - Loading plugins from /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins, /home/pi/.octoprint/plugins and installed plugin packages...
2020-08-04 23:32:38,392 - octoprint.plugin.core - INFO - Found 22 plugin(s) providing 22 mixin implementations, 39 hook handlers
2020-08-04 23:32:38,427 - octoprint.filemanager.storage - INFO - Initializing the file metadata for /home/pi/.octoprint/uploads...
2020-08-04 23:32:39,009 - octoprint.filemanager.storage - INFO - ... file metadata for /home/pi/.octoprint/uploads initialized successfully.
2020-08-04 23:32:39,014 - octoprint.server - INFO - Added new permission from plugin action_command_notification: PLUGIN_ACTION_COMMAND_NOTIFICATION_SHOW (needs: u"Need(method='role', value=u'plugin_action_command_notification_show')")
2020-08-04 23:32:39,015 - octoprint.server - INFO - Added new permission from plugin action_command_notification: PLUGIN_ACTION_COMMAND_NOTIFICATION_CLEAR (needs: u"Need(method='role', value=u'plugin_action_command_notification_clear')")
2020-08-04 23:32:39,017 - octoprint.server - INFO - Added new permission from plugin action_command_prompt: PLUGIN_ACTION_COMMAND_PROMPT_INTERACT (needs: u"Need(method='role', value=u'plugin_action_command_prompt_interact')")
2020-08-04 23:32:39,019 - octoprint.server - INFO - Added new permission from plugin announcements: PLUGIN_ANNOUNCEMENTS_READ (needs: u"Need(method='role', value=u'plugin_announcements_read')")
2020-08-04 23:32:39,020 - octoprint.server - INFO - Added new permission from plugin announcements: PLUGIN_ANNOUNCEMENTS_MANAGE (needs: u"Need(method='role', value=u'plugin_announcements_manage'), Need(method='role', value=u'plugin_announcements_read')")
2020-08-04 23:32:39,022 - octoprint.server - INFO - Added new permission from plugin appkeys: PLUGIN_APPKEYS_ADMIN (needs: u"Need(method='role', value=u'plugin_appkeys_admin')")
2020-08-04 23:32:39,024 - octoprint.server - INFO - Added new permission from plugin backup: PLUGIN_BACKUP_ACCESS (needs: u"Need(method='role', value=u'plugin_backup_access')")
2020-08-04 23:32:39,025 - octoprint.server - INFO - Added new permission from plugin firmware_check: PLUGIN_FIRMWARE_CHECK_DISPLAY (needs: u"Need(method='role', value=u'plugin_firmware_check_display')")
2020-08-04 23:32:39,028 - octoprint.server - INFO - Added new permission from plugin logging: PLUGIN_LOGGING_MANAGE (needs: u"Need(method='role', value=u'plugin_logging_manage')")
2020-08-04 23:32:39,029 - octoprint.server - INFO - Added new permission from plugin pi_support: PLUGIN_PI_SUPPORT_STATUS (needs: u"Need(method='role', value=u'plugin_pi_support_check')")
2020-08-04 23:32:39,031 - octoprint.server - INFO - Added new permission from plugin pluginmanager: PLUGIN_PLUGINMANAGER_MANAGE (needs: u"Need(method='role', value=u'plugin_pluginmanager_manage')")
2020-08-04 23:32:39,033 - octoprint.server - INFO - Added new permission from plugin pluginmanager: PLUGIN_PLUGINMANAGER_INSTALL (needs: u"Need(method='role', value=u'plugin_pluginmanager_install'), Need(method='role', value=u'plugin_pluginmanager_manage')")
2020-08-04 23:32:39,035 - octoprint.server - INFO - Added new permission from plugin softwareupdate: PLUGIN_SOFTWAREUPDATE_CHECK (needs: u"Need(method='role', value=u'plugin_softwareupdate_check')")
2020-08-04 23:32:39,037 - octoprint.server - INFO - Added new permission from plugin softwareupdate: PLUGIN_SOFTWAREUPDATE_UPDATE (needs: u"Need(method='role', value=u'plugin_softwareupdate_update')")
2020-08-04 23:32:39,144 - octoprint.plugins.softwareupdate - INFO - Version cache was created for another version of OctoPrint, not using it
2020-08-04 23:32:40,265 - octoprint.util.pip - INFO - Using "/home/pi/oprint/bin/python2 -m pip" as command to invoke pip
2020-08-04 23:32:41,365 - octoprint.util.pip - INFO - Version of pip is 19.3.1
2020-08-04 23:32:41,367 - octoprint.util.pip - INFO - pip installs to /home/pi/oprint/lib/python2.7/site-packages (writable -> yes), --user flag needed -> no, virtual env -> yes
2020-08-04 23:32:41,368 - octoprint.util.pip - INFO - ==> pip ok -> yes
2020-08-04 23:32:41,372 - octoprint.plugin.core - INFO - Initialized 22 plugin implementation(s)
2020-08-04 23:32:41,779 - octoprint.plugin.core - INFO - 22 plugin(s) registered with the system:
|  Action Command Notification Support (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/action_command_notification
|  Action Command Prompt Support (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/action_command_prompt
|  Announcement Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/announcements
|  Anonymous Usage Tracking (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/tracking
|  Application Keys Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/appkeys
|  Backup &amp; Restore (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/backup
|  Core Wizard (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/corewizard
|  Discovery (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/discovery
|  EEPROM Editor for MPSM (0.1.1) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_eeprom_MPSelectMini
|  Error Tracking (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/errortracking
|  File Check (2020.7.6) (bundled) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_file_check
|  Firmware Check (2020.6.22) (bundled) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_firmware_check
|  GCode Viewer (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/gcodeviewer
|  Logging (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/logging
|  Login UI (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/loginui
|  Malyan/Monoprice Connection Fix (0.1.3) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_malyan_connection_fix
|  Pi Support Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pi_support
|  Plugin Manager (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pluginmanager
|  PortLister (0.1.10) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_portlister
|  Prusa Leveling Guide (1.0.8) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_PrusaLevelingGuide
|  Software Update (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/softwareupdate
|  Virtual Printer (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/virtual_printer
Prefix legend: ! = disabled, # = blacklisted, * = incompatible
2020-08-04 23:32:41,797 - octoprint.environment - INFO - Detected environment is Python 2.7.16 under Linux (linux2). Details:
|  hardware:
|      cores: 4
|      freq: 1200.0
|      ram: 917708800
|  os:
|      id: linux
|      platform: linux2
|  plugins:
|      pi_support:
|          model: Raspberry Pi 3 Model B Rev 1.2
|          octopi_version: 0.17.0
|  python:
|      pip: 19.3.1
|      version: 2.7.16
|      virtualenv: /home/pi/oprint
2020-08-04 23:32:41,809 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/webassets...
2020-08-04 23:32:41,835 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/.webassets-cache...
2020-08-04 23:32:43,030 - octoprint.server - INFO - Shutting down intermediary server...
2020-08-04 23:32:43,298 - octoprint.server - INFO - Intermediary server shut down
2020-08-04 23:32:43,301 - octoprint.events - INFO - Processing startup event, this is our first event
2020-08-04 23:32:43,304 - octoprint.events - INFO - Adding 0 events to queue that were held back before startup event
2020-08-04 23:32:43,306 - octoprint.filemanager - INFO - Adding backlog items from all storage types to analysis queue...
2020-08-04 23:32:43,308 - octoprint.server - INFO - Autoconnect on startup is configured, trying to connect to the printer...
2020-08-04 23:32:43,361 - octoprint.filemanager - INFO - Added 0 items from storage type "local" to analysis queue
2020-08-04 23:32:43,383 - octoprint.server - INFO - Trying to connect to configured serial port None
2020-08-04 23:32:43,436 - octoprint.util.comm - INFO - Changing monitoring state from "Offline" to "Detecting serial connection"
2020-08-04 23:32:43,449 - octoprint.server.util.watchdog - INFO - Running initial scan on watched folder...
2020-08-04 23:32:43,466 - octoprint.util.comm - INFO - Serial detection: Performing autodetection with 7 port/baudrate candidates: /dev/ttyACM0@115200, /dev/ttyACM0@250000, /dev/ttyACM0@230400, /dev/ttyACM0@57600, /dev/ttyACM0@38400, /dev/ttyACM0@19200, /dev/ttyACM0@9600
2020-08-04 23:32:43,467 - octoprint.util.comm - INFO - Serial detection: Trying port /dev/ttyACM0, baudrate 115200
2020-08-04 23:32:43,472 - octoprint.util.comm - INFO - Serial detection: Handshake attempt #1 with timeout 2.0s
2020-08-04 23:32:43,476 - octoprint.util.comm - INFO - M110 detected, setting current line number to 0
2020-08-04 23:32:43,485 - octoprint.cli.server - ERROR - Uncaught exception
Traceback (most recent call last):
File "/home/pi/oprint/bin/octoprint", line 8, in <module>
sys.exit(main())
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/__init__.py", line 629, in main
octo(args=args, prog_name="octoprint", auto_envvar_prefix="OCTOPRINT")
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/cli/server.py", line 207, in serve_command
ignore_blacklist)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/cli/server.py", line 119, in run_server
octoprint_server.run()
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/server/__init__.py", line 832, in run
observer.start()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/observers/api.py", line 260, in start
emitter.start()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/utils/__init__.py", line 110, in start
self.on_thread_start()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/observers/polling.py", line 81, in on_thread_start
self._snapshot = self._take_snapshot()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/observers/polling.py", line 78, in <lambda>
self.watch.path, self.watch.is_recursive, stat=stat, listdir=listdir)
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/utils/dirsnapshot.py", line 257, in __init__
for p, st in self.walk(path):
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/utils/dirsnapshot.py", line 265, in walk
for entry in self.listdir(root)]
AttributeError: 'unicode' object has no attribute 'name'
2020-08-04 23:42:44,141 - octoprint.startup - INFO - ******************************************************************************
2020-08-04 23:42:44,146 - octoprint.startup - INFO - Starting OctoPrint 1.4.1
2020-08-04 23:42:44,148 - octoprint.startup - INFO - Starting in SAFE MODE. Third party plugins will be disabled!
2020-08-04 23:42:44,150 - octoprint.startup - INFO - Reason for safe mode: problem during last startup
2020-08-04 23:42:44,153 - octoprint.startup - INFO - ******************************************************************************
2020-08-04 23:42:45,493 - octoprint.util.connectivity.connectivity_checker - INFO - Connectivity state is currently: online
2020-08-04 23:42:45,495 - octoprint.util.connectivity.connectivity_checker - INFO - Connecting to 1.1.1.1:53 is working
2020-08-04 23:42:45,496 - octoprint.util.connectivity.connectivity_checker - INFO - Resolving octoprint.org is working
2020-08-04 23:42:45,513 - octoprint.startup - INFO - Blacklist processing done, adding 1 blacklisted plugin versions: roomtemp (any)
2020-08-04 23:42:45,624 - octoprint.plugin.core - INFO - Loading plugins from /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins, /home/pi/.octoprint/plugins and installed plugin packages...
2020-08-04 23:42:48,855 - octoprint.plugin.core - INFO - Found 22 plugin(s) providing 18 mixin implementations, 32 hook handlers
2020-08-04 23:42:48,983 - octoprint.server.heartbeat - INFO - Starting server heartbeat, 900.0s interval
2020-08-04 23:42:49,030 - octoprint.server - INFO - Intermediary server started
2020-08-04 23:42:49,030 - octoprint.plugin.core - INFO - Loading plugins from /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins, /home/pi/.octoprint/plugins and installed plugin packages...
2020-08-04 23:42:49,253 - octoprint.plugin.core - INFO - Found 22 plugin(s) providing 18 mixin implementations, 32 hook handlers
2020-08-04 23:42:49,289 - octoprint.filemanager.storage - INFO - Initializing the file metadata for /home/pi/.octoprint/uploads...
2020-08-04 23:42:49,876 - octoprint.filemanager.storage - INFO - ... file metadata for /home/pi/.octoprint/uploads initialized successfully.
2020-08-04 23:42:49,880 - octoprint.server - INFO - Added new permission from plugin action_command_notification: PLUGIN_ACTION_COMMAND_NOTIFICATION_SHOW (needs: u"Need(method='role', value=u'plugin_action_command_notification_show')")
2020-08-04 23:42:49,881 - octoprint.server - INFO - Added new permission from plugin action_command_notification: PLUGIN_ACTION_COMMAND_NOTIFICATION_CLEAR (needs: u"Need(method='role', value=u'plugin_action_command_notification_clear')")
2020-08-04 23:42:49,883 - octoprint.server - INFO - Added new permission from plugin action_command_prompt: PLUGIN_ACTION_COMMAND_PROMPT_INTERACT (needs: u"Need(method='role', value=u'plugin_action_command_prompt_interact')")
2020-08-04 23:42:49,885 - octoprint.server - INFO - Added new permission from plugin announcements: PLUGIN_ANNOUNCEMENTS_READ (needs: u"Need(method='role', value=u'plugin_announcements_read')")
2020-08-04 23:42:49,887 - octoprint.server - INFO - Added new permission from plugin announcements: PLUGIN_ANNOUNCEMENTS_MANAGE (needs: u"Need(method='role', value=u'plugin_announcements_manage'), Need(method='role', value=u'plugin_announcements_read')")
2020-08-04 23:42:49,888 - octoprint.server - INFO - Added new permission from plugin appkeys: PLUGIN_APPKEYS_ADMIN (needs: u"Need(method='role', value=u'plugin_appkeys_admin')")
2020-08-04 23:42:49,890 - octoprint.server - INFO - Added new permission from plugin backup: PLUGIN_BACKUP_ACCESS (needs: u"Need(method='role', value=u'plugin_backup_access')")
2020-08-04 23:42:49,891 - octoprint.server - INFO - Added new permission from plugin firmware_check: PLUGIN_FIRMWARE_CHECK_DISPLAY (needs: u"Need(method='role', value=u'plugin_firmware_check_display')")
2020-08-04 23:42:49,893 - octoprint.server - INFO - Added new permission from plugin logging: PLUGIN_LOGGING_MANAGE (needs: u"Need(method='role', value=u'plugin_logging_manage')")
2020-08-04 23:42:49,895 - octoprint.server - INFO - Added new permission from plugin pi_support: PLUGIN_PI_SUPPORT_STATUS (needs: u"Need(method='role', value=u'plugin_pi_support_check')")
2020-08-04 23:42:49,897 - octoprint.server - INFO - Added new permission from plugin pluginmanager: PLUGIN_PLUGINMANAGER_MANAGE (needs: u"Need(method='role', value=u'plugin_pluginmanager_manage')")
2020-08-04 23:42:49,898 - octoprint.server - INFO - Added new permission from plugin pluginmanager: PLUGIN_PLUGINMANAGER_INSTALL (needs: u"Need(method='role', value=u'plugin_pluginmanager_install'), Need(method='role', value=u'plugin_pluginmanager_manage')")
2020-08-04 23:42:49,899 - octoprint.server - INFO - Added new permission from plugin softwareupdate: PLUGIN_SOFTWAREUPDATE_CHECK (needs: u"Need(method='role', value=u'plugin_softwareupdate_check')")
2020-08-04 23:42:49,901 - octoprint.server - INFO - Added new permission from plugin softwareupdate: PLUGIN_SOFTWAREUPDATE_UPDATE (needs: u"Need(method='role', value=u'plugin_softwareupdate_update')")
2020-08-04 23:42:50,016 - octoprint.plugins.softwareupdate - INFO - Version cache was created for another version of OctoPrint, not using it
2020-08-04 23:42:51,266 - octoprint.util.pip - INFO - Using "/home/pi/oprint/bin/python2 -m pip" as command to invoke pip
2020-08-04 23:42:52,357 - octoprint.util.pip - INFO - Version of pip is 19.3.1
2020-08-04 23:42:52,359 - octoprint.util.pip - INFO - pip installs to /home/pi/oprint/lib/python2.7/site-packages (writable -> yes), --user flag needed -> no, virtual env -> yes
2020-08-04 23:42:52,361 - octoprint.util.pip - INFO - ==> pip ok -> yes
2020-08-04 23:42:52,368 - octoprint.plugin.core - INFO - Initialized 18 plugin implementation(s)
2020-08-04 23:42:52,383 - octoprint.plugin.core - INFO - 22 plugin(s) registered with the system:
|  Action Command Notification Support (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/action_command_notification
|  Action Command Prompt Support (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/action_command_prompt
|  Announcement Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/announcements
|  Anonymous Usage Tracking (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/tracking
|  Application Keys Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/appkeys
|  Backup &amp; Restore (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/backup
|  Core Wizard (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/corewizard
|  Discovery (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/discovery
| !EEPROM Editor for MPSM (0.1.1) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_eeprom_MPSelectMini
|  Error Tracking (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/errortracking
|  File Check (2020.7.6) (bundled) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_file_check
|  Firmware Check (2020.6.22) (bundled) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_firmware_check
|  GCode Viewer (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/gcodeviewer
|  Logging (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/logging
|  Login UI (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/loginui
| !Malyan/Monoprice Connection Fix (0.1.3) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_malyan_connection_fix
|  Pi Support Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pi_support
|  Plugin Manager (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pluginmanager
| !PortLister (0.1.10) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_portlister
| !Prusa Leveling Guide (1.0.8) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_PrusaLevelingGuide
|  Software Update (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/softwareupdate
|  Virtual Printer (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/virtual_printer
Prefix legend: ! = disabled, # = blacklisted, * = incompatible
2020-08-04 23:42:52,402 - octoprint.environment - INFO - Detected environment is Python 2.7.16 under Linux (linux2). Details:
|  hardware:
|      cores: 4
|      freq: 1200.0
|      ram: 917708800
|  os:
|      id: linux
|      platform: linux2
|  plugins:
|      pi_support:
|          model: Raspberry Pi 3 Model B Rev 1.2
|          octopi_version: 0.17.0
|  python:
|      pip: 19.3.1
|      version: 2.7.16
|      virtualenv: /home/pi/oprint
2020-08-04 23:42:52,412 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/webassets...
2020-08-04 23:42:52,415 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/.webassets-cache...
2020-08-04 23:42:53,610 - octoprint.server - INFO - Shutting down intermediary server...
2020-08-04 23:42:54,085 - octoprint.server - INFO - Intermediary server shut down
2020-08-04 23:42:54,091 - octoprint.events - INFO - Processing startup event, this is our first event
2020-08-04 23:42:54,093 - octoprint.events - INFO - Adding 0 events to queue that were held back before startup event
2020-08-04 23:42:54,099 - octoprint.filemanager - INFO - Adding backlog items from all storage types to analysis queue...
2020-08-04 23:42:54,101 - octoprint.server - INFO - Autoconnect on startup is configured, trying to connect to the printer...
2020-08-04 23:42:54,196 - octoprint.filemanager - INFO - Added 0 items from storage type "local" to analysis queue
2020-08-04 23:42:54,218 - octoprint.server - INFO - Trying to connect to configured serial port None
2020-08-04 23:42:54,272 - octoprint.util.comm - INFO - Changing monitoring state from "Offline" to "Detecting serial connection"
2020-08-04 23:42:54,288 - octoprint.server.util.watchdog - INFO - Running initial scan on watched folder...
2020-08-04 23:42:54,301 - octoprint.util.comm - INFO - Serial detection: Performing autodetection with 7 port/baudrate candidates: /dev/ttyACM0@115200, /dev/ttyACM0@250000, /dev/ttyACM0@230400, /dev/ttyACM0@57600, /dev/ttyACM0@38400, /dev/ttyACM0@19200, /dev/ttyACM0@9600
2020-08-04 23:42:54,302 - octoprint.util.comm - INFO - Serial detection: Trying port /dev/ttyACM0, baudrate 115200
2020-08-04 23:42:54,305 - octoprint.util.comm - INFO - Connecting to port /dev/ttyACM0, baudrate 115200
2020-08-04 23:42:54,313 - octoprint.util.comm - INFO - Serial detection: Handshake attempt #1 with timeout 2.0s
2020-08-04 23:42:54,318 - octoprint.util.comm - INFO - M110 detected, setting current line number to 0
2020-08-04 23:42:54,320 - octoprint.cli.server - ERROR - Uncaught exception
Traceback (most recent call last):
File "/home/pi/oprint/bin/octoprint", line 8, in <module>
sys.exit(main())
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/__init__.py", line 629, in main
octo(args=args, prog_name="octoprint", auto_envvar_prefix="OCTOPRINT")
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/cli/server.py", line 207, in serve_command
ignore_blacklist)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/cli/server.py", line 119, in run_server
octoprint_server.run()
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/server/__init__.py", line 832, in run
observer.start()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/observers/api.py", line 260, in start
emitter.start()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/utils/__init__.py", line 110, in start
self.on_thread_start()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/observers/polling.py", line 81, in on_thread_start
self._snapshot = self._take_snapshot()
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/observers/polling.py", line 78, in <lambda>
self.watch.path, self.watch.is_recursive, stat=stat, listdir=listdir)
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/utils/dirsnapshot.py", line 257, in __init__
for p, st in self.walk(path):
File "/home/pi/oprint/local/lib/python2.7/site-packages/watchdog/utils/dirsnapshot.py", line 265, in walk
for entry in self.listdir(root)]
AttributeError: 'unicode' object has no attribute 'name'

# Fixed code
def run(self):
    if not self._allow_root:
        self._check_for_root()

    if self._settings is None:
        self._settings = settings()

    if not self._settings.getBoolean(["server", "ignoreIncompleteStartup"]):
        self._settings.setBoolean(["server", "incompleteStartup"], True)
        self._settings.save()

    if self._plugin_manager is None:
        self._plugin_manager = octoprint.plugin.plugin_manager()

    global app
    global babel

    global printer
    global printerProfileManager
    global fileManager
    global slicingManager
    global analysisQueue
    global userManager
    global permissionManager
    global groupManager
    global eventManager
    global loginManager
    global pluginManager
    global pluginLifecycleManager
    global preemptiveCache
    global jsonEncoder
    global jsonDecoder
    global connectivityChecker
    global debug
    global safe_mode

    from tornado.ioloop import IOLoop
    from tornado.web import Application

    debug = self._debug
    safe_mode = self._safe_mode

    if self._v6_only and not octoprint.util.net.HAS_V6:
        raise RuntimeError("IPv6 only mode configured but system doesn't support IPv6")

    if self._host is None:
        host = self._settings.get(["server", "host"])
        if host is None:
            if octoprint.util.net.HAS_V6:
                host = "::"
            else:
                host = "0.0.0.0"

        self._host = host

    if ":" in self._host and not octoprint.util.net.HAS_V6:
        raise RuntimeError(
            "IPv6 host address {!r} configured but system doesn't support IPv6".format(
                self._host
            )
        )

    if self._port is None:
        self._port = self._settings.getInt(["server", "port"])
        if self._port is None:
            self._port = 5000

    self._logger = logging.getLogger(__name__)
    self._setup_heartbeat_logging()
    pluginManager = self._plugin_manager

    # monkey patch/fix some stuff
    util.tornado.fix_json_encode()
    util.tornado.fix_websocket_check_origin()
    util.flask.fix_flask_jsonify()

    self._setup_mimetypes()

    additional_translation_folders = []
    if not safe_mode:
        additional_translation_folders += [self._settings.getBaseFolder("translations")]
    util.flask.enable_additional_translations(
        additional_folders=additional_translation_folders
    )

    # setup app
    self._setup_app(app)

    # setup i18n
    self._setup_i18n(app)

    if self._settings.getBoolean(["serial", "log"]):
        # enable debug logging to serial.log
        logging.getLogger("SERIAL").setLevel(logging.DEBUG)

    # start the intermediary server
    self._start_intermediary_server()

    ### IMPORTANT!
    ###
    ### Best do not start any subprocesses until the intermediary server shuts down again or they MIGHT inherit the
    ### open port and prevent us from firing up Tornado later.
    ###
    ### The intermediary server's socket should have the CLOSE_EXEC flag (or its equivalent) set where possible, but
    ### we can only do that if fcntl is available or we are on Windows, so better safe than sorry.
    ###
    ### See also issues #2035 and #2090

    # then initialize the plugin manager
    pluginManager.reload_plugins(startup=True, initialize_implementations=False)

    printerProfileManager = PrinterProfileManager()
    eventManager = self._event_manager

    analysis_queue_factories = dict(
        gcode=octoprint.filemanager.analysis.GcodeAnalysisQueue
    )
    analysis_queue_hooks = pluginManager.get_hooks(
        "octoprint.filemanager.analysis.factory"
    )
    for name, hook in analysis_queue_hooks.items():
        try:
            additional_factories = hook()
            analysis_queue_factories.update(**additional_factories)
        except Exception:
            self._logger.exception(
                "Error while processing analysis queues from {}".format(name),
                extra=dict(plugin=name),
            )
    analysisQueue = octoprint.filemanager.analysis.AnalysisQueue(
        analysis_queue_factories
    )

    slicingManager = octoprint.slicing.SlicingManager(
        self._settings.getBaseFolder("slicingProfiles"), printerProfileManager
    )

    storage_managers = dict()
    storage_managers[octoprint.filemanager.FileDestinations.LOCAL] = (
        octoprint.filemanager.storage.LocalFileStorage(
            self._settings.getBaseFolder("uploads")
        )
    )

    fileManager = octoprint.filemanager.FileManager(
        analysisQueue,
        slicingManager,
        printerProfileManager,
        initial_storage_managers=storage_managers,
    )
    pluginLifecycleManager = LifecycleManager(pluginManager)
    preemptiveCache = PreemptiveCache(
        os.path.join(
            self._settings.getBaseFolder("data"), "preemptive_cache_config.yaml"
        )
    )

    JsonEncoding.add_encoder(users.User, lambda obj: obj.as_dict())
    JsonEncoding.add_encoder(groups.Group, lambda obj: obj.as_dict())
    JsonEncoding.add_encoder(permissions.OctoPrintPermission, lambda obj: obj.as_dict())

    # start regular check if we are connected to the internet
    def on_connectivity_change(old_value, new_value):
        eventManager.fire(
            events.Events.CONNECTIVITY_CHANGED,
            payload=dict(old=old_value, new=new_value),
        )

    connectivityChecker = self._connectivity_checker

    def on_settings_update(*args, **kwargs):
        # make sure our connectivity checker runs with the latest settings
        connectivityEnabled = self._settings.getBoolean(
            ["server", "onlineCheck", "enabled"]
        )
        connectivityInterval = self._settings.getInt(
            ["server", "onlineCheck", "interval"]
        )
        connectivityHost = self._settings.get(["server", "onlineCheck", "host"])
        connectivityPort = self._settings.getInt(["server", "onlineCheck", "port"])
        connectivityName = self._settings.get(["server", "onlineCheck", "name"])

        if (
            connectivityChecker.enabled != connectivityEnabled
            or connectivityChecker.interval != connectivityInterval
            or connectivityChecker.host != connectivityHost
            or connectivityChecker.port != connectivityPort
            or connectivityChecker.name != connectivityName
        ):
            connectivityChecker.enabled = connectivityEnabled
            connectivityChecker.interval = connectivityInterval
            connectivityChecker.host = connectivityHost
            connectivityChecker.port = connectivityPort
            connectivityChecker.name = connectivityName
            connectivityChecker.check_immediately()

    eventManager.subscribe(events.Events.SETTINGS_UPDATED, on_settings_update)

    components = dict(
        plugin_manager=pluginManager,
        printer_profile_manager=printerProfileManager,
        event_bus=eventManager,
        analysis_queue=analysisQueue,
        slicing_manager=slicingManager,
        file_manager=fileManager,
        plugin_lifecycle_manager=pluginLifecycleManager,
        preemptive_cache=preemptiveCache,
        json_encoder=jsonEncoder,
        json_decoder=jsonDecoder,
        connectivity_checker=connectivityChecker,
        environment_detector=self._environment_detector,
    )

    # ~~ setup access control

    # get additional permissions from plugins
    self._setup_plugin_permissions()

    # create group manager instance
    group_manager_factories = pluginManager.get_hooks("octoprint.access.groups.factory")
    for name, factory in group_manager_factories.items():
        try:
            groupManager = factory(components, self._settings)
            if groupManager is not None:
                self._logger.debug(
                    "Created group manager instance from factory {}".format(name)
                )
                break
        except Exception:
            self._logger.exception(
                "Error while creating group manager instance from factory {}".format(
                    name
                )
            )
    else:
        group_manager_name = self._settings.get(["accessControl", "groupManager"])
        try:
            clazz = octoprint.util.get_class(group_manager_name)
            groupManager = clazz()
        except AttributeError:
            self._logger.exception(
                "Could not instantiate group manager {}, "
                "falling back to FilebasedGroupManager!".format(group_manager_name)
            )
            groupManager = octoprint.access.groups.FilebasedGroupManager()
    components.update(dict(group_manager=groupManager))

    # create user manager instance
    user_manager_factories = pluginManager.get_hooks(
        "octoprint.users.factory"
    )  # legacy, set first so that new wins
    user_manager_factories.update(
        pluginManager.get_hooks("octoprint.access.users.factory")
    )
    for name, factory in user_manager_factories.items():
        try:
            userManager = factory(components, self._settings)
            if userManager is not None:
                self._logger.debug(
                    "Created user manager instance from factory {}".format(name)
                )
                break
        except Exception:
            self._logger.exception(
                "Error while creating user manager instance from factory {}".format(
                    name
                ),
                extra=dict(plugin=name),
            )
    else:
        user_manager_name = self._settings.get(["accessControl", "userManager"])
        try:
            clazz = octoprint.util.get_class(user_manager_name)
            userManager = clazz(groupManager)
        except Exception:
            self._logger.exception(
                "Could not instantiate user manager {}, "
                "falling back to FilebasedUserManager!".format(user_manager_name)
            )
            userManager = octoprint.access.users.FilebasedUserManager(groupManager)
        finally:
            userManager.enabled = self._settings.getBoolean(
                ["accessControl", "enabled"]
            )
    components.update(dict(user_manager=userManager))

    # create printer instance
    printer_factories = pluginManager.get_hooks("octoprint.printer.factory")
    for name, factory in printer_factories.items():
        try:
            printer = factory(components)
            if printer is not None:
                self._logger.debug(
                    "Created printer instance from factory {}".format(name)
                )
                break
        except Exception:
            self._logger.exception(
                "Error while creating printer instance from factory {}".format(name),
                extra=dict(plugin=name),
            )
    else:
        printer = Printer(fileManager, analysisQueue, printerProfileManager)
    components.update(dict(printer=printer))

    def octoprint_plugin_inject_factory(name, implementation):
        """Factory for injections for all OctoPrintPlugins"""
        if not isinstance(implementation, octoprint.plugin.OctoPrintPlugin):
            return None

        components_copy = dict(components)
        if "printer" in components:
            import wrapt
            import functools

            def tagwrap(f):
                @functools.wraps(f)
                def wrapper(*args, **kwargs):
                    tags = kwargs.get("tags", set()) | {
                        "source:plugin",
                        "plugin:{}".format(name),
                    }
                    kwargs["tags"] = tags
                    return f(*args, **kwargs)

                setattr(wrapper, "__tagwrapped__", True)
                return wrapper

            class TaggedFuncsPrinter(wrapt.ObjectProxy):
                def __getattribute__(self, attr):
                    __wrapped__ = super(TaggedFuncsPrinter, self).__getattribute__(
                        "__wrapped__"
                    )
                    if attr == "__wrapped__":
                        return __wrapped__

                    item = getattr(__wrapped__, attr)
                    if (
                        callable(item)
                        and (
                            "tags" in item.__code__.co_varnames
                            or "kwargs" in item.__code__.co_varnames
                        )
                        and not getattr(item, "__tagwrapped__", False)
                    ):
                        return tagwrap(item)
                    else:
                        return item

            components_copy["printer"] = TaggedFuncsPrinter(components["printer"])

        props = dict()
        props.update(components_copy)
        props.update(
            dict(data_folder=os.path.join(self._settings.getBaseFolder("data"), name))
        )
        return props

    def settings_plugin_inject_factory(name, implementation):
        """Factory for additional injections/initializations depending on plugin type"""
        if not isinstance(implementation, octoprint.plugin.SettingsPlugin):
            return

        default_settings_overlay = dict(plugins=dict())
        default_settings_overlay["plugins"][name] = (
            implementation.get_settings_defaults()
        )
        self._settings.add_overlay(default_settings_overlay, at_end=True)

        plugin_settings = octoprint.plugin.plugin_settings_for_settings_plugin(
            name, implementation
        )
        if plugin_settings is None:
            return

        return dict(settings=plugin_settings)

    def settings_plugin_config_migration_and_cleanup(identifier, implementation):
        """Take care of migrating and cleaning up any old settings"""

        if not isinstance(implementation, octoprint.plugin.SettingsPlugin):
            return

        settings_version = implementation.get_settings_version()
        settings_migrator = implementation.on_settings_migrate

        if settings_version is not None and settings_migrator is not None:
            stored_version = implementation._settings.get_int(
                [octoprint.plugin.SettingsPlugin.config_version_key]
            )
            if stored_version is None or stored_version < settings_version:
                settings_migrator(settings_version, stored_version)
                implementation._settings.set_int(
                    [octoprint.plugin.SettingsPlugin.config_version_key],
                    settings_version,
                    force=True,
                )

        implementation.on_settings_cleanup()
        implementation._settings.save()

        implementation.on_settings_initialized()

    custom_events_hooks = pluginManager.get_hooks(
        "octoprint.events.register_custom_events"
    )
    for name, hook in custom_events_hooks.items():
        try:
            result = hook()
            if isinstance(result, (list, tuple)):
                for event in result:
                    constant, value = octoprint.events.Events.register_event(
                        event, prefix="plugin_{}_".format(name)
                    )
                    self._logger.debug(
                        'Registered event {} of plugin {} as Events.{} = "{}"'.format(
                            event, name, constant, value
                        )
                    )
        except Exception:
            self._logger.exception(
                "Error while retrieving custom event list from plugin {}".format(name),
                extra=dict(plugin=name),
            )

    pluginManager.implementation_inject_factories = [
        octoprint_plugin_inject_factory,
        settings_plugin_inject_factory,
    ]
    pluginManager.initialize_implementations()

    settingsPlugins = pluginManager.get_implementations(octoprint.plugin.SettingsPlugin)
    for implementation in settingsPlugins:
        try:
            settings_plugin_config_migration_and_cleanup(
                implementation._identifier, implementation
            )
        except Exception:
            self._logger.exception(
                "Error while trying to migrate settings for "
                "plugin {}, ignoring it".format(implementation._identifier),
                extra=dict(plugin=implementation._identifier),
            )

    pluginManager.implementation_post_inits = [
        settings_plugin_config_migration_and_cleanup
    ]

    pluginManager.log_all_plugins()

    # log environment data now
    self._environment_detector.log_detected_environment()

    # initialize file manager and register it for changes in the registered plugins
    fileManager.initialize()
    pluginLifecycleManager.add_callback(
        ["enabled", "disabled"], lambda name, plugin: fileManager.reload_plugins()
    )

    # initialize slicing manager and register it for changes in the registered plugins
    slicingManager.initialize()
    pluginLifecycleManager.add_callback(
        ["enabled", "disabled"], lambda name, plugin: slicingManager.reload_slicers()
    )

    # setup jinja2
    self._setup_jinja2()

    # setup assets
    self._setup_assets()

    # configure timelapse
    octoprint.timelapse.valid_timelapse("test")
    octoprint.timelapse.configure_timelapse()

    # setup command triggers
    events.CommandTrigger(printer)
    if self._debug:
        events.DebugEventListener()

    # setup login manager
    self._setup_login_manager()

    # register API blueprint
    self._setup_blueprints()

    ## Tornado initialization starts here

    ioloop = IOLoop()
    ioloop.install()

    enable_cors = settings().getBoolean(["api", "allowCrossOrigin"])

    self._router = SockJSRouter(
        self._create_socket_connection,
        "/sockjs",
        session_kls=util.sockjs.ThreadSafeSession,
        user_settings=dict(
            websocket_allow_origin="*" if enable_cors else "",
            jsessionid=False,
            sockjs_url="../../static/js/lib/sockjs.min.js",
        ),
    )

    upload_suffixes = dict(
        name=self._settings.get(["server", "uploads", "nameSuffix"]),
        path=self._settings.get(["server", "uploads", "pathSuffix"]),
    )

    def mime_type_guesser(path):
        from octoprint.filemanager import get_mime_type

        return get_mime_type(path)

    def download_name_generator(path):
        metadata = fileManager.get_metadata("local", path)
        if metadata and "display" in metadata:
            return metadata["display"]

    download_handler_kwargs = dict(as_attachment=True, allow_client_caching=False)

    additional_mime_types = dict(mime_type_guesser=mime_type_guesser)

    ##~~ Permission validators

    access_validators_from_plugins = []
    for plugin, hook in pluginManager.get_hooks(
        "octoprint.server.http.access_validator"
    ).items():
        try:
            access_validators_from_plugins.append(
                util.tornado.access_validation_factory(app, hook)
            )
        except Exception:
            self._logger.exception(
                "Error while adding tornado access validator from plugin {}".format(
                    plugin
                ),
                extra=dict(plugin=plugin),
            )
    access_validator = dict(
        access_validation=util.tornado.validation_chain(*access_validators_from_plugins)
    )

    timelapse_validators = [
        util.tornado.access_validation_factory(
            app, util.flask.permission_validator, permissions.Permissions.TIMELAPSE_LIST
        ),
    ] + access_validators_from_plugins
    download_validators = [
        util.tornado.access_validation_factory(
            app, util.flask.permission_validator, permissions.Permissions.FILES_DOWNLOAD
        ),
    ] + access_validators_from_plugins
    log_validators = [
        util.tornado.access_validation_factory(
            app,
            util.flask.permission_validator,
            permissions.Permissions.PLUGIN_LOGGING_MANAGE,
        ),
    ] + access_validators_from_plugins
    camera_validators = [
        util.tornado.access_validation_factory(
            app, util.flask.permission_validator, permissions.Permissions.WEBCAM
        ),
    ] + access_validators_from_plugins

    timelapse_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*timelapse_validators)
    )
    download_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*download_validators)
    )
    log_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*log_validators)
    )
    camera_permission_validator = dict(
        access_validation=util.tornado.validation_chain(*camera_validators)
    )

    no_hidden_files_validator = dict(
        path_validation=util.tornado.path_validation_factory(
            lambda path: not octoprint.util.is_hidden_path(path), status_code=404
        )
    )
    timelapse_path_validator = dict(
        path_validation=util.tornado.path_validation_factory(
            lambda path: not octoprint.util.is_hidden_path(path)
            and octoprint.timelapse.valid_timelapse(path),
            status_code=404,
        )
    )

    def joined_dict(*dicts):
        if not len(dicts):
            return dict()

        joined = dict()
        for d in dicts:
            joined.update(d)
        return joined

    util.tornado.RequestlessExceptionLoggingMixin.LOG_REQUEST = debug
    util.tornado.CorsSupportMixin.ENABLE_CORS = enable_cors

    server_routes = self._router.urls + [
        # various downloads
        # .mpg and .mp4 timelapses:
        (
            r"/downloads/timelapse/(.*)",
            util.tornado.LargeResponseHandler,
            joined_dict(
                dict(path=self._settings.getBaseFolder("timelapse")),
                timelapse_permission_validator,
                download_handler_kwargs,
                timelapse_path_validator,
            ),
        ),
        (
            r"/downloads/files/local/(.*)",
            util.tornado.LargeResponseHandler,
            joined_dict(
                dict(
                    path=self._settings.getBaseFolder("uploads"),
                    as_attachment=True,
                    name_generator=download_name_generator,
                ),
                download_permission_validator,
                download_handler_kwargs,
                no_hidden_files_validator,
                additional_mime_types,
            ),
        ),
        (
            r"/downloads/logs/([^/]*)",
            util.tornado.LargeResponseHandler,
            joined_dict(
                dict(
                    path=self._settings.getBaseFolder("logs"),
                    mime_type_guesser=lambda *args, **kwargs: "text/plain",
                ),
                download_handler_kwargs,
                log_permission_validator,
            ),
        ),
        # camera snapshot
        (
            r"/downloads/camera/current",
            util.tornado.UrlProxyHandler,
            joined_dict(
                dict(
                    url=self._settings.get(["webcam", "snapshot"]), as_attachment=True
                ),
                camera_permission_validator,
            ),
        ),
        # generated webassets
        (
            r"/static/webassets/(.*)",
            util.tornado.LargeResponseHandler,
            dict(
                path=os.path.join(
                    self._settings.getBaseFolder("generated"), "webassets"
                ),
                is_pre_compressed=True,
            ),
        ),
        # online indicators - text file with "online" as content and a transparent gif
        (r"/online.txt", util.tornado.StaticDataHandler, dict(data="online\n")),
        (
            r"/online.gif",
            util.tornado.StaticDataHandler,
            dict(
                data=bytes(
                    base64.b64decode(
                        "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
                    )
                ),
                content_type="image/gif",
            ),
        ),
        # deprecated endpoints
        (
            r"/api/logs",
            util.tornado.DeprecatedEndpointHandler,
            dict(url="/plugin/logging/logs"),
        ),
        (
            r"/api/logs/(.*)",
            util.tornado.DeprecatedEndpointHandler,
            dict(url="/plugin/logging/logs/{0}"),
        ),
    ]

    # fetch additional routes from plugins
    for name, hook in pluginManager.get_hooks("octoprint.server.http.routes").items():
        try:
            result = hook(list(server_routes))
        except Exception:
            self._logger.exception(
                "There was an error while retrieving additional "
                "server routes from plugin hook {name}".format(**locals()),
                extra=dict(plugin=name),
            )
        else:
            if isinstance(result, (list, tuple)):
                for entry in result:
                    if not isinstance(entry, tuple) or not len(entry) == 3:
                        continue
                    if not isinstance(entry[0], basestring):
                        continue
                    if not isinstance(entry[2], dict):
                        continue

                    route, handler, kwargs = entry
                    route = r"/plugin/{name}/{route}".format(
                        name=name,
                        route=route if not route.startswith("/") else route[1:],
                    )

                    self._logger.debug(
                        "Adding additional route {route} handled by handler {handler} and with additional arguments {kwargs!r}".format(
                            **locals()
                        )
                    )
                    server_routes.append((route, handler, kwargs))

    headers = {
        "X-Robots-Tag": "noindex, nofollow, noimageindex",
        "X-Content-Type-Options": "nosniff",
    }
    if not settings().getBoolean(["server", "allowFraming"]):
        headers["X-Frame-Options"] = "sameorigin"

    removed_headers = ["Server"]

    server_routes.append(
        (
            r".*",
            util.tornado.UploadStorageFallbackHandler,
            dict(
                fallback=util.tornado.WsgiInputContainer(
                    app.wsgi_app, headers=headers, removed_headers=removed_headers
                ),
                file_prefix="octoprint-file-upload-",
                file_suffix=".tmp",
                suffixes=upload_suffixes,
            ),
        )
    )

    transforms = [
        util.tornado.GlobalHeaderTransform.for_headers(
            "OctoPrintGlobalHeaderTransform",
            headers=headers,
            removed_headers=removed_headers,
        )
    ]

    self._tornado_app = Application(handlers=server_routes, transforms=transforms)
    max_body_sizes = [
        (
            "POST",
            r"/api/files/([^/]*)",
            self._settings.getInt(["server", "uploads", "maxSize"]),
        ),
        ("POST", r"/api/languages", 5 * 1024 * 1024),
    ]

    # allow plugins to extend allowed maximum body sizes
    for name, hook in pluginManager.get_hooks("octoprint.server.http.bodysize").items():
        try:
            result = hook(list(max_body_sizes))
        except Exception:
            self._logger.exception(
                "There was an error while retrieving additional "
                "upload sizes from plugin hook {name}".format(**locals()),
                extra=dict(plugin=name),
            )
        else:
            if isinstance(result, (list, tuple)):
                for entry in result:
                    if not isinstance(entry, tuple) or not len(entry) == 3:
                        continue
                    if (
                        not entry[0]
                        in util.tornado.UploadStorageFallbackHandler.BODY_METHODS
                    ):
                        continue
                    if not isinstance(entry[2], int):
                        continue

                    method, route, size = entry
                    route = r"/plugin/{name}/{route}".format(
                        name=name,
                        route=route if not route.startswith("/") else route[1:],
                    )

                    self._logger.debug(
                        "Adding maximum body size of {size}B for {method} requests to {route})".format(
                            **locals()
                        )
                    )
                    max_body_sizes.append((method, route, size))

    self._stop_intermediary_server()

    # initialize and bind the server
    trusted_downstream = self._settings.get(
        ["server", "reverseProxy", "trustedDownstream"]
    )
    if not isinstance(trusted_downstream, list):
        self._logger.warning(
            "server.reverseProxy.trustedDownstream is not a list, skipping"
        )
        trusted_downstreams = []

    server_kwargs = dict(
        max_body_sizes=max_body_sizes,
        default_max_body_size=self._settings.getInt(["server", "maxSize"]),
        xheaders=True,
        trusted_downstream=trusted_downstream,
    )
    if sys.platform == "win32":
        # set 10min idle timeout under windows to hopefully make #2916 less likely
        server_kwargs.update(dict(idle_connection_timeout=600))

    self._server = util.tornado.CustomHTTPServer(self._tornado_app, **server_kwargs)

    listening_address = self._host
    if self._host == "::" and not self._v6_only:
        # special case - tornado only listens on v4 _and_ v6 if we use None as address
        listening_address = None

    self._server.listen(self._port, address=listening_address)

    ### From now on it's ok to launch subprocesses again

    eventManager.fire(events.Events.STARTUP)

    # analysis backlog
    fileManager.process_backlog()

    # auto connect
    if self._settings.getBoolean(["serial", "autoconnect"]):
        self._logger.info(
            "Autoconnect on startup is configured, trying to connect to the printer..."
        )
        try:
            (port, baudrate) = (
                self._settings.get(["serial", "port"]),
                self._settings.getInt(["serial", "baudrate"]),
            )
            printer_profile = printerProfileManager.get_default()
            connectionOptions = printer.__class__.get_connection_options()
            if port in connectionOptions["ports"] or port == "AUTO" or port is None:
                self._logger.info(
                    "Trying to connect to configured serial port {}".format(port)
                )
                printer.connect(
                    port=port,
                    baudrate=baudrate,
                    profile=printer_profile["id"]
                    if "id" in printer_profile
                    else "_default",
                )
            else:
                self._logger.info(
                    "Could not find configured serial port {} in the system, cannot automatically connect to a non existing printer. Is it plugged in and booted up yet?"
                )
        except Exception:
            self._logger.exception(
                "Something went wrong while attempting to automatically connect to the printer"
            )

    # start up watchdogs
    try:
        watched = self._settings.getBaseFolder("watched")
        watchdog_handler = util.watchdog.GcodeWatchdogHandler(fileManager, printer)
        watchdog_handler.initial_scan(watched)

        if self._settings.getBoolean(["feature", "pollWatched"]):
            # use less performant polling observer if explicitly configured
            observer = PollingObserver()
        else:
            # use os default
            observer = Observer()

        observer.schedule(watchdog_handler, watched, recursive=True)
        observer.start()
    except Exception:
        self._logger.exception("Error starting watched folder observer")

    # run our startup plugins
    octoprint.plugin.call_plugin(
        octoprint.plugin.StartupPlugin,
        "on_startup",
        args=(self._host, self._port),
        sorting_context="StartupPlugin.on_startup",
    )

    def call_on_startup(name, plugin):
        implementation = plugin.get_implementation(octoprint.plugin.StartupPlugin)
        if implementation is None:
            return
        implementation.on_startup(self._host, self._port)

    pluginLifecycleManager.add_callback("enabled", call_on_startup)

    # prepare our after startup function
    def on_after_startup():
        if self._host == "::":
            if self._v6_only:
                # only v6
                self._logger.info(
                    "Listening on http://[::]:{port}".format(port=self._port)
                )
            else:
                # all v4 and v6
                self._logger.info(
                    "Listening on http://0.0.0.0:{port} and http://[::]:{port}".format(
                        port=self._port
                    )
                )
        else:
            self._logger.info(
                "Listening on http://{}:{}".format(
                    self._host if not ":" in self._host else "[" + self._host + "]",
                    self._port,
                )
            )

        if safe_mode and self._settings.getBoolean(["server", "startOnceInSafeMode"]):
            self._logger.info(
                "Server started successfully in safe mode as requested from config, removing flag"
            )
            self._settings.setBoolean(["server", "startOnceInSafeMode"], False)
            self._settings.save()

        # now this is somewhat ugly, but the issue is the following: startup plugins might want to do things for
        # which they need the server to be already alive (e.g. for being able to resolve urls, such as favicons
        # or service xmls or the like). While they are working though the ioloop would block. Therefore we'll
        # create a single use thread in which to perform our after-startup-tasks, start that and hand back
        # control to the ioloop
        def work():
            octoprint.plugin.call_plugin(
                octoprint.plugin.StartupPlugin,
                "on_after_startup",
                sorting_context="StartupPlugin.on_after_startup",
            )

            def call_on_after_startup(name, plugin):
                implementation = plugin.get_implementation(
                    octoprint.plugin.StartupPlugin
                )
                if implementation is None:
                    return
                implementation.on_after_startup()

            pluginLifecycleManager.add_callback("enabled", call_on_after_startup)

            # if there was a rogue plugin we wouldn't even have made it here, so remove startup triggered safe mode
            # flag again...
            self._settings.setBoolean(["server", "incompleteStartup"], False)
            self._settings.save()

            # make a backup of the current config
            self._settings.backup(ext="backup")

            # when we are through with that we also run our preemptive cache
            if settings().getBoolean(["devel", "cache", "preemptive"]):
                self._execute_preemptive_flask_caching(preemptiveCache)

        import threading

        threading.Thread(target=work).start()

    ioloop.add_callback(on_after_startup)

    # prepare our shutdown function
    def on_shutdown():
        # will be called on clean system exit and shutdown the watchdog observer and call the on_shutdown methods
        # on all registered ShutdownPlugins
        self._logger.info("Shutting down...")
        observer.stop()
        observer.join()
        eventManager.fire(events.Events.SHUTDOWN)

        self._logger.info("Calling on_shutdown on plugins")
        octoprint.plugin.call_plugin(
            octoprint.plugin.ShutdownPlugin,
            "on_shutdown",
            sorting_context="ShutdownPlugin.on_shutdown",
        )

        # wait for shutdown event to be processed, but maximally for 15s
        event_timeout = 15.0
        if eventManager.join(timeout=event_timeout):
            self._logger.warning(
                "Event loop was still busy processing after {}s, shutting down anyhow".format(
                    event_timeout
                )
            )

        if self._octoprint_daemon is not None:
            self._logger.info("Cleaning up daemon pidfile")
            self._octoprint_daemon.terminated()

        self._logger.info("Goodbye!")

    atexit.register(on_shutdown)

    def sigterm_handler(*args, **kwargs):
        # will stop tornado on SIGTERM, making the program exit cleanly
        def shutdown_tornado():
            self._logger.debug("Shutting down tornado's IOLoop...")
            ioloop.stop()

        self._logger.debug("SIGTERM received...")
        ioloop.add_callback_from_signal(shutdown_tornado)

    signal.signal(signal.SIGTERM, sigterm_handler)

    try:
        # this is the main loop - as long as tornado is running, OctoPrint is running
        ioloop.start()
        self._logger.debug("Tornado's IOLoop stopped")
    except (KeyboardInterrupt, SystemExit):
        pass
    except Exception:
        self._logger.fatal(
            "Now that is embarrassing... Something really really went wrong here. Please report this including the stacktrace below in OctoPrint's bugtracker. Thanks!"
        )
        self._logger.exception("Stacktrace follows:")