/// <summary>
        /// Process system configuration initialisation
        /// This will parse the configuration text, It can run multiple times, once the config has loaded the system won't
        /// re-load the config until you call ProcessConfig.unload() followed by ProcessConfig.initialise(...), so it's safe
        /// to not surround it with ifs.
        ///
        /// NOTE: If a cluster is specified in config text and its 'node-name' matches nodeName, then those settings
        /// will be used to connect to the cluster.  This allows for different staging environments to be setup.
        /// </summary>
        /// <param name="nodeName">If a cluster is specified in the cluster.conf and its 'node-name' matches nodeName, then
        /// those settings will be used to connect to the cluster.  This allows for different staging environments to be
        /// setup.</param>
        /// <param name="setup">A setup function to call on successful loading of the configuration files - this will
        /// happen once only.</param>
        /// <param name="strategyFuncs">Plugin extra strategy behaviours by passing in a list of FuncSpecs.</param>
        public static Unit initialise(string configText, Option <string> nodeName, Action setup = null, IEnumerable <FuncSpec> strategyFuncs = null)
        {
            lock (sync)
            {
                var parser  = new ProcessSystemConfigParser(nodeName.IfNone(""), new Types(), strategyFuncs);
                var configs = String.IsNullOrWhiteSpace(configText)
                    ? Map.create(Tuple(new SystemName(""), ProcessSystemConfig.Empty))
                    : parser.ParseConfigText(configText);

                nodeName.Map(_ => configs.Filter(c => c.NodeName == nodeName).Iter(StartFromConfig))
                .IfNone(() => configs.Filter(c => c.NodeName == "root").Iter(StartFromConfig));

                if (setup != null)
                {
                    setup();
                }
                return(unit);
            }
        }