public static void AddDialog(string login, Msg question, Msg[] answers, Flag flag, File[] files, long? broadcast = null)
		{
			Settings.ConnectionString.UsingConnection(conn => conn.UsingTransaction(tran =>
			{
				AddMessage(tran, question, login);
				Array.ForEach(answers, answer => AddMessage(tran, answer, login));
				AddFlag(tran, flag, login);
				AddFiles(tran, files, login);
				SetBroadcast(tran, broadcast, login);
			}));
		}
		public static string GetAnswer(string question, Dictionary<string, Flag> state, out Flag flag, out File[] files, out DateTime timer)
		{
			flag = null;
			files = null;

			timer = HasBombTimer(state) ? Settings.BombTimerEnd : DateTime.MinValue;

			question = question.TrimToNull();
			if(question == null)
				return GetRandomAnswer(DefaultAnswers, string.Empty);

			var possibleFlag = question.SanitizeFlag();

			if(state.ContainsKey(possibleFlag))
				return GetRandomAnswer(OldFlagAnswers, possibleFlag);

			FlagType flagType;
			if(Flags.TryGetValue(possibleFlag, out flagType))
				flag = new Flag {Value = possibleFlag, Type = flagType};

			FlagFiles.TryGetValue(possibleFlag, out files);

			string answer;
			if(FlagAnswers.TryGetValue(possibleFlag, out answer))
				return answer + GetSuffix(flag, state, ref timer);

			if(possibleFlag.StartsWith(Settings.FlagPrefix, StringComparison.InvariantCultureIgnoreCase))
				return GetRandomAnswer(InvalidFlagAnswers, question);

			if(question.IndexOfAny(Settings.MartianChars) >= 0)
				return GetRandomAnswer(MartianAnswers, question);

			if(HintAnswers.TryGetValue(question, out answer))
				return answer;

			return GetRandomAnswer(DefaultAnswers, question);
		}
		private static void AddFlag(DbTransaction tran, Flag flag, string login)
		{
			if(flag == null)
				return;
			tran.Connection.UsingCommand("insert into flags ([login], [flag], [type], [dt]) values (@login, @flag, @type, @dt)",
				cmd =>
				{
					cmd.Transaction = tran;
					cmd.AddParam("login", login, DbType.String);
					cmd.AddParam("flag", flag.Value, DbType.String);
					cmd.AddParam("type", flag.Type.ToString(), DbType.String);
					cmd.AddParam("dt", DateTime.UtcNow, DbType.DateTime2);
					if(cmd.ExecuteNonQuery() > 0)
						Log.DebugFormat("Add {0} flag '{1}'", flag.Type, flag.Value);
				});
		}
		private static string GetSuffix(Flag flag, Dictionary<string, Flag> state, ref DateTime timer)
		{
			if(flag == null)
				return null;
			if(state != null && Flags.Keys.All(f => state.ContainsKey(f) || string.Equals(flag.Value, f, StringComparison.InvariantCultureIgnoreCase)))
			{
				timer = DateTime.MinValue;
				return Settings.EndGameSuffix;
			}
			var bombs = GetBombFlags(state);
			if(IsMainBombFlag(flag.Value))
			{
				timer = Settings.BombTimerEnd;
				if(state == null || bombs == 0)
					return null;
				if(bombs < Settings.BombShutDownFlagsCount)
					return string.Format(Settings.MainBombTaskSuffix, bombs);
				timer = DateTime.MinValue;
				return Settings.BombShuttedDownSuffix;
			}
			if(flag.Type == FlagType.Bomb)
			{
				bombs++;
				var hasBombTimer = HasBombTimer(state);
				if(hasBombTimer && bombs < Settings.BombShutDownFlagsCount)
				{
					timer =  Settings.BombTimerEnd;
					return Settings.BombTasksSuffix;
				}
				if(hasBombTimer && bombs == Settings.BombShutDownFlagsCount)
				{
					timer = DateTime.MinValue;
					return Settings.BombShuttedDownSuffix;
				}
				timer = DateTime.MinValue;
				return null;
			}
			return null;
		}