public LoaderPlugin()
        {
            try
            {
                Bot = SimlBot.Instance;
                VA.Components.Add(Bot);

                //Perform tick based on Virtual Assistant timer.
                VA.Timer.Tick += (sender, args) =>
                {
                    Bot.Timer.PerformTick();
                };

                SimlBot.Logger.LogReceived += (sender, args) =>
                {
                    VirtualAssistant.Instance.Logger.Log(args.Level, args.Message);
                };

                var vaSettings = VA.SettingsManager["VA"];

                var simlSettingsPath = Path.Combine(vaSettings["Bot-Directory"].Value, "Commands", "Settings");
                SimlFileManager = new SimlFileManager(simlSettingsPath);

                //When the VA is closing, save both MainUser and Bot settings to files.
                VA.Closing += (sender, eventArgs) =>
                {
                    SimlFileManager.SaveDocument(UserSettingsFileId, Bot.MainUser.Settings.GetDocument());
                    SimlFileManager.SaveDocument(BotSettingsFileId, Bot.Settings.GetDocument());
                };

                Bot.Learning += (sender, learningEventArgs) =>
                {
                    SaveLearned(LearnedFilePath, learningEventArgs.Document);
                };

                Bot.Memorizing += (sender, memorizingEventArgs) =>
                {
                    SaveLearned(MemorizedFilePath, memorizingEventArgs.Document);
                };

                VirtualAssistant.Instance.Logger.LogReceived += (sender, args) =>
                {
                    //Trigger the 'Error-Logged' event only if the level is greater than or equal to 'Warn'
                    if (args.Level >= LogLevel.Warn)
                    {
                        Bot.Trigger("Error-Logged");
                    }
                };

                VA.Architecture = "SIML";
                //Whenever the VA receives a message, the Bot generates a response.
                VA.Interaction.MessageReceived += (sender, args) =>
                {
                    if (args.Handled)
                    {
                        return;
                    }

                    //Message type is UserMessage
                    if (args.Message.Type == MessageType.UserMessage)
                    {
                        ChatResult result;
                        if (args.Message.User.IsMain)
                        {
                            result = Bot.Chat(args.Message.Text);
                        }
                        else
                        {
                            result = Bot.Chat(args.Message.Text, Bot.CreateUser(args.Message.User.ID));
                        }
                        var response = new Response
                        {
                            Text = result.BotMessage,
                            Hint = result.Hint,
                            Rank = result.LastResponse.Rank,
                            User = args.Message.User
                        };

                        args.Handled = true;
                        VA.Interaction.Respond(response);
                    }
                    //Message is an Event message
                    else if (args.Message.Type == MessageType.EventMessage)
                    {
                        if (args.Message.User.IsMain)
                        {
                            Bot.Trigger(args.Message.Text);
                        }
                        else
                        {
                            Bot.Trigger(args.Message.Text, Bot.CreateUser(args.Message.User.ID));
                        }
                        args.Handled = true;
                    }
                };

                //Whenever the VA receives a textual response, use speech synthesis.
                VA.Interaction.ResponseReceived += (sender, args) =>
                {
                    if (!args.Response.User.IsMain)
                    {
                        return;
                    }
                    var rank = Enum.Parse(typeof(ResponseRank), VA.SettingsManager["Speech"]["Speech-Rank"].Value);
                    if (args.Response.Rank >= (ResponseRank)rank)
                    {
                        VA.Speech.Synthesizers.Current?.Speak(args.Response.Text);
                    }
                };

                //Whenever the MainUser receives an Event Message, send a response to the VA.
                Bot.MainUser.ResponseReceived += (sender, args) =>
                {
                    var response = new Response
                    {
                        Text = args.Result.BotMessage,
                        Hint = args.Result.Hint,
                        Rank = args.Result.LastResponse.Rank
                    };
                    VA.Interaction.Respond(response);
                };


                Emotion currentEmotion = null;

                //When the Bot emotion changes set the currentEmotion.
                Bot.EmotionChanged += (sender, args) => { currentEmotion = args.Current; };

                //Whenver the current SpeechRecognizer is changed.
                VA.Speech.Recognizers.RecognizerChanged += (sender, args) =>
                {
                    args.Recognizer.SpeechRecognized += (o, eventArgs) =>
                    {
                        var defaultConfidence = 0.5d;
                        if (VA.SettingsManager.Contains("Speech"))
                        {
                            var speechSettings = VA.SettingsManager["Speech"];
                            if (speechSettings.Contains("Speech-Confidence"))
                            {
                                var    confidence = speechSettings["Speech-Confidence"].Value;
                                double outValue;
                                if (double.TryParse(confidence, out outValue))
                                {
                                    defaultConfidence = outValue;
                                }
                            }
                        }
                        if (eventArgs.Confidence >= defaultConfidence)
                        {
                            VA.Interaction.SendMessage(eventArgs.Text);
                        }
                    };
                };

                //Whenever the Current Speech Synthesizer is changed.
                VA.Speech.Synthesizers.SynthesizerChanged += (sender, args) =>
                {
                    args.Synthesizer.VisemeReached += (sender1, visemeArrivedEventArgs) =>
                    {
                        VA.Avatar.Morph(visemeArrivedEventArgs.Viseme.ToString(), visemeArrivedEventArgs.Duration);
                    };

                    //If currentEmotion is not null then at the end of speech switch to expression.
                    VA.Speech.Synthesizers.Current.SpeakCompleted += (sender1, args1) =>
                    {
                        try
                        {
                            if (currentEmotion == null)
                            {
                                return;
                            }
                            var emotionElement    = SynUtility.Xml.RemoveAllNamespaces(currentEmotion.GetElement());
                            var durationAttribute = emotionElement.Attribute("duration");
                            var infoElement       = emotionElement.Element("info");
                            var duration          = 2000;
                            if (durationAttribute != null)
                            {
                                duration = Convert.ToInt32(durationAttribute.Value);
                            }
                            var simlEmotion         = infoElement?.Element("Emotion");
                            var expressionAttribute = simlEmotion?.Attribute("Expression");
                            if (expressionAttribute != null)
                            {
                                VA.Avatar.Morph(expressionAttribute.Value, TimeSpan.FromMilliseconds(duration));
                            }
                            //Reset currentEmotion to null.
                            currentEmotion = null;
                        }
                        catch (Exception exception)
                        {
                            VA.Logger.Error(exception);
                        }
                    };
                };

                Project = new ProjectManager();

                //Path to the functional Commands knowledge-base.
                var commandsSimlProject = Path.Combine(vaSettings["Bot-Directory"].Value, "Commands.simlproj");

                //Path to the General chat knowledge-base.
                var generalSimlProject = Path.Combine(vaSettings["Bot-Directory"].Value, "General.simlproj");

                if (File.Exists(commandsSimlProject))
                {
                    Project.LoadFromFile(commandsSimlProject);
                }
                if (File.Exists(generalSimlProject))
                {
                    Project.LoadFromFile(generalSimlProject);
                }

                var externalBotDirectory     = vaSettings["External-Bot-Directory"].Value;
                var externalPluginsDirectory = vaSettings["External-Plugins-Directory"].Value;

                //if External-Bot-Directory is set then load external Bot Project.
                if (!string.IsNullOrEmpty(externalBotDirectory))
                {
                    LoadProjectFromDirectory(externalBotDirectory);
                }

                // Load Knowledge-Base into Bot.
                //All projects are loaded at this point.
                Project.LoadIntoBot(Bot);

                //Add the 'MainUser' Settings so the VA can work with User variables.
                VA.SettingsManager.Add(Bot.MainUser.Settings);

                //Create textual choices.
                foreach (var item in Bot.Examples)
                {
                    VA.Interaction.Choices.Add(new ChoiceItem("Siml-Bot", item.Value));
                }

                //Load Important Plugins first.
                AddPlugin(typeof(BotPlugin));
                AddPlugin(typeof(UserPlugin));

                //Now load external Plugins.
                LoadPlugins(vaSettings["Plugins-Directory"].Value);

                //If 'External-Plugins-Directory' is set then load plugins from directory
                if (!string.IsNullOrEmpty(externalPluginsDirectory))
                {
                    LoadPlugins(externalPluginsDirectory);
                }

                VA.SettingsManager.SettingsSaved += (sender, args) =>
                {
                    var settingsWindow       = VA.Components.Get <SettingsWindow>();
                    var settingsSavedMessage = !string.IsNullOrEmpty(args.Settings["Settings-Saved-Message"].Value) ? args.Settings["Settings-saved-message"].Value : Settings["Settings-Saved"].Value;
                    settingsWindow.DisplayMessage(args.Settings.Name, settingsSavedMessage);
                };

                VA.Timer.Tick += (sender, args) =>
                {
                    Bot.Timer.PerformTick();
                };

                //Trigger Greet-User event when the VA is ready.
                VA.Loaded += (sender, args) =>
                {
                    Bot.Trigger("Load-Time-Event");
                    Bot.Trigger("Greet-User");
                };

                //Reset all plugin settings if the VA is reset.
                VA.Resetting += (sender, args) =>
                {
                    ResetAllPlugins();
                };

                Bot.Adapters.Add(new CreditAdapter());
                Bot.Adapters.Add(new AgentAdapter());
                Bot.Adapters.Add(new TextWindowAdapter());
                Bot.Adapters.Add(new HelpWindowAdapter());

                AddWelcomeWidget();
            }
            catch (Exception exception)
            {
                VA.Logger.Error(exception);
            }
        }