public DemoderationPlugin(IConnectionManager connMgr, JObject config)
        {
            ConnectionManager = connMgr;
            Config            = new DemoderationConfig(config);

            ChannelsMessages = new Dictionary <string, RingBuffer <ChannelMessage> >();
            RegexCache       = new RegexCache();

            ConnectionManager.ChannelMessage += HandleChannelMessage;
            CleanupTimer = new Timer(
                CleanupTimerElapsed, null, TimeSpan.Zero, TimeSpan.FromMinutes(Config.CleanupPeriodMinutes)
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmabuse"),
                    CommandUtil.MakeOptions(
                        CommandUtil.MakeOption("-b", CommandUtil.NonzeroStringMatcherRequiredWordTaker),
                        CommandUtil.MakeOption("--ban-time", CommandUtil.NonzeroStringMatcherRequiredWordTaker),
                        CommandUtil.MakeOption("-c", CommandUtil.NonzeroStringMatcherRequiredWordTaker),
                        CommandUtil.MakeOption("--cooldown-time", CommandUtil.NonzeroStringMatcherRequiredWordTaker)
                        ),
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker, // nickname
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker  // criterion name
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleAbuseCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmnew"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker, // criterion name
                        RestTaker.Instance                                 // criterion detection regex
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleNewCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmdel"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker // criterion name
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleDeleteCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmrestore"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker // criterion name
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleRestoreCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmimmunity"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker,                // nickname
                        new RegexMatcher("(?:[#+&][^ ,:]+|GLOBAL)").ToRequiredWordTaker() // channel or "GLOBAL"
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleImmunityCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmdelimmunity"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker,                // nickname
                        new RegexMatcher("(?:[#+&][^ ,:]+|GLOBAL)").ToRequiredWordTaker() // channel or "GLOBAL"
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleDeleteImmunityCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmpermaban"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker,                // nickname
                        new RegexMatcher("(?:[#+&][^ ,:]+|GLOBAL)").ToRequiredWordTaker() // channel or "GLOBAL"
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandlePermabanCommand
                );

            ConnectionManager.CommandManager.RegisterChannelMessageCommandHandler(
                new Command(
                    CommandUtil.MakeNames("dmunpermaban"),
                    CommandUtil.NoOptions,
                    CommandUtil.MakeArguments(
                        CommandUtil.NonzeroStringMatcherRequiredWordTaker,                // nickname
                        new RegexMatcher("(?:[#+&][^ ,:]+|GLOBAL)").ToRequiredWordTaker() // channel or "GLOBAL"
                        ),
                    forbiddenFlags: MessageFlags.UserBanned
                    ),
                HandleUnPermabanCommand
                );

            UpdateCommandCache();
        }