commit
bc32531719
@ -1,17 +1,17 @@
|
|||||||
For more information and how to setup your own NadekoBot, go to: <http://github.com/Kwoth/NadekoBot/wiki>
|
For more information and how to setup your own NadekoBot, go to: <http://github.com/Kwoth/NadekoBot/wiki>
|
||||||
You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: `nadekodiscordbot@gmail.com`
|
You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: `nadekodiscordbot@gmail.com`
|
||||||
##Table Of Contents
|
##Table Of Contents
|
||||||
- [Searches](#searches)
|
|
||||||
- [NSFW](#nsfw)
|
|
||||||
- [Music](#music)
|
|
||||||
- [Help](#help)
|
- [Help](#help)
|
||||||
- [Permissions](#permissions)
|
|
||||||
- [Gambling](#gambling)
|
|
||||||
- [Administration](#administration)
|
- [Administration](#administration)
|
||||||
- [Utility](#utility)
|
|
||||||
- [ClashOfClans](#clashofclans)
|
- [ClashOfClans](#clashofclans)
|
||||||
- [CustomReactions](#customreactions)
|
- [CustomReactions](#customreactions)
|
||||||
|
- [Gambling](#gambling)
|
||||||
- [Games](#games)
|
- [Games](#games)
|
||||||
|
- [Music](#music)
|
||||||
|
- [NSFW](#nsfw)
|
||||||
|
- [Permissions](#permissions)
|
||||||
|
- [Searches](#searches)
|
||||||
|
- [Utility](#utility)
|
||||||
|
|
||||||
|
|
||||||
### Administration
|
### Administration
|
||||||
@ -154,7 +154,7 @@ Command and aliases | Description | Usage
|
|||||||
`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3`
|
`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3`
|
||||||
`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3`
|
`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3`
|
||||||
`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend`
|
`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend`
|
||||||
`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the channel this command is ran in. You can specify "all" parameter to enable it in the whole server. Custom reactions starting with %mention% won't work if cleverbot is enabled.' **Requires ManageMessages server permission.** | `>cleverbot`
|
`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot`
|
||||||
`>pick` | Picks the currency planted in this channel. | `>pick`
|
`>pick` | Picks the currency planted in this channel. | `>pick`
|
||||||
`>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant`
|
`>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant`
|
||||||
`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc`
|
`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc`
|
||||||
|
@ -5,6 +5,7 @@ using NadekoBot.Services;
|
|||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Services.CleverBotApi;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -21,26 +22,27 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class CleverBotCommands
|
public class CleverBotCommands
|
||||||
{
|
{
|
||||||
private Logger _log { get; }
|
private static Logger _log { get; }
|
||||||
|
|
||||||
class CleverAnswer {
|
class CleverAnswer {
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public string Response { get; set; }
|
public string Response { get; set; }
|
||||||
}
|
}
|
||||||
public CleverBotCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
}
|
|
||||||
|
|
||||||
//user#discrim is the key
|
//user#discrim is the key
|
||||||
public static ConcurrentHashSet<string> ChannelsInConversation { get; } = new ConcurrentHashSet<string>();
|
public static ConcurrentHashSet<string> ChannelsInConversation { get; } = new ConcurrentHashSet<string>();
|
||||||
public static ConcurrentHashSet<ulong> CleverbotGuilds { get; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentDictionary<ulong, ChatterBotSession> CleverbotGuilds { get; } = new ConcurrentDictionary<ulong, ChatterBotSession>();
|
||||||
|
|
||||||
static CleverBotCommands()
|
static CleverBotCommands()
|
||||||
{
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
CleverbotGuilds = new ConcurrentHashSet<ulong>(uow.GuildConfigs.GetAll().Where(gc => gc.CleverbotEnabled).Select(gc => gc.GuildId));
|
var bot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT);
|
||||||
|
CleverbotGuilds = new ConcurrentDictionary<ulong, ChatterBotSession>(
|
||||||
|
uow.GuildConfigs.GetAll()
|
||||||
|
.Where(gc => gc.CleverbotEnabled)
|
||||||
|
.ToDictionary(gc => gc.GuildId, gc => bot.CreateSession()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,9 +52,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (channel == null)
|
if (channel == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var nick = msg.Channel.Id + "NadekoBot";
|
ChatterBotSession cleverbot;
|
||||||
|
if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out cleverbot))
|
||||||
if (!ChannelsInConversation.Contains(nick) && !CleverbotGuilds.Contains(channel.Guild.Id))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var nadekoId = NadekoBot.Client.GetCurrentUser().Id;
|
var nadekoId = NadekoBot.Client.GetCurrentUser().Id;
|
||||||
@ -61,11 +62,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
string message;
|
string message;
|
||||||
if (msg.Content.StartsWith(normalMention))
|
if (msg.Content.StartsWith(normalMention))
|
||||||
{
|
{
|
||||||
message = msg.Content.Substring(normalMention.Length);
|
message = msg.Content.Substring(normalMention.Length).Trim();
|
||||||
}
|
}
|
||||||
else if (msg.Content.StartsWith(nickMention))
|
else if (msg.Content.StartsWith(nickMention))
|
||||||
{
|
{
|
||||||
message = msg.Content.Substring(nickMention.Length);
|
message = msg.Content.Substring(nickMention.Length).Trim();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -74,98 +75,51 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
await msg.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
await msg.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
using (var http = new HttpClient())
|
var response = await cleverbot.Think(message).ConfigureAwait(false);
|
||||||
{
|
|
||||||
var content = new FormUrlEncodedContent(new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "user", NadekoBot.Credentials.CleverbotApiUser},
|
|
||||||
{ "key", NadekoBot.Credentials.CleverbotApiKey},
|
|
||||||
{ "nick", nick},
|
|
||||||
{ "text", message},
|
|
||||||
});
|
|
||||||
var res = await http.PostAsync("https://cleverbot.io/1.0/ask", content).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (res.StatusCode == System.Net.HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var answer = JsonConvert.DeserializeObject<CleverAnswer>(await res.Content.ReadAsStringAsync().ConfigureAwait(false));
|
await msg.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
||||||
try
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await msg.Channel.SendMessageAsync(WebUtility.HtmlDecode(answer.Response)).ConfigureAwait(false);
|
_log.Warn(ex, "Eror sending response");
|
||||||
|
await msg.Channel.SendMessageAsync(response).ConfigureAwait(false); // try twice :\
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
await msg.Channel.SendMessageAsync(answer.Response).ConfigureAwait(false); // try twice :\
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequirePermission(ChannelPermission.ManageMessages)]
|
[RequirePermission(ChannelPermission.ManageMessages)]
|
||||||
public async Task Cleverbot(IUserMessage imsg, string all = null)
|
public async Task Cleverbot(IUserMessage imsg)
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)imsg.Channel;
|
var channel = (ITextChannel)imsg.Channel;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CleverbotApiKey) ||
|
ChatterBotSession throwaway;
|
||||||
string.IsNullOrWhiteSpace(NadekoBot.Credentials.CleverbotApiKey))
|
if (CleverbotGuilds.TryRemove(channel.Guild.Id, out throwaway))
|
||||||
{
|
{
|
||||||
await channel.SendMessageAsync(":anger: `Bot owner didn't setup Cleverbot Api keys. Session will not start.`").ConfigureAwait(false);
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
uow.GuildConfigs.SetCleverbotEnabled(channel.Guild.Id, false);
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
await channel.SendMessageAsync($"{imsg.Author.Mention} `Disabled cleverbot on this server.`").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all?.Trim().ToLowerInvariant() == "all")
|
var cleverbot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT);
|
||||||
{
|
var session = cleverbot.CreateSession();
|
||||||
var cleverbotEnabled = CleverbotGuilds.Add(channel.Guild.Id);
|
|
||||||
if (!cleverbotEnabled)
|
CleverbotGuilds.TryAdd(channel.Guild.Id, session);
|
||||||
CleverbotGuilds.TryRemove(channel.Guild.Id);
|
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
uow.GuildConfigs.SetCleverbotEnabled(channel.Guild.Id, cleverbotEnabled);
|
uow.GuildConfigs.SetCleverbotEnabled(channel.Guild.Id, true);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await channel.SendMessageAsync($"{imsg.Author.Mention} `{(cleverbotEnabled ? "Enabled" : "Disabled")} cleverbot for all users.`").ConfigureAwait(false);
|
await channel.SendMessageAsync($"{imsg.Author.Mention} `Enabled cleverbot on this server.`").ConfigureAwait(false);
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var nick = channel.Id + "NadekoBot";
|
|
||||||
|
|
||||||
if (ChannelsInConversation.TryRemove(nick))
|
|
||||||
{
|
|
||||||
await channel.SendMessageAsync($"{imsg.Author.Mention} `I will no longer reply to your messages starting with my mention.`").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var http = new HttpClient())
|
|
||||||
{
|
|
||||||
var content = new FormUrlEncodedContent(new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "user", NadekoBot.Credentials.CleverbotApiUser},
|
|
||||||
{ "key", NadekoBot.Credentials.CleverbotApiKey},
|
|
||||||
{ "nick", nick},
|
|
||||||
});
|
|
||||||
var res = await http.PostAsync("https://cleverbot.io/1.0/create", content).ConfigureAwait(false);
|
|
||||||
if (res.StatusCode != System.Net.HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
await channel.SendMessageAsync($"{imsg.Author.Mention} `Something went wrong in starting your cleverbot session :\\`");
|
|
||||||
_log.Warn(await res.Content.ReadAsStringAsync());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelsInConversation.Add(nick);
|
|
||||||
}
|
|
||||||
await channel.SendMessageAsync($"{imsg.Author.Mention} `I will reply to your messages starting with my mention.`").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Help
|
|||||||
helpstr.AppendLine(@"For more information and how to setup your own NadekoBot, go to: <http://github.com/Kwoth/NadekoBot/wiki>
|
helpstr.AppendLine(@"For more information and how to setup your own NadekoBot, go to: <http://github.com/Kwoth/NadekoBot/wiki>
|
||||||
You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: `nadekodiscordbot@gmail.com`");
|
You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: `nadekodiscordbot@gmail.com`");
|
||||||
helpstr.AppendLine("##Table Of Contents");
|
helpstr.AppendLine("##Table Of Contents");
|
||||||
helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Select(m => $"- [{m.Name}](#{m.Name.ToLowerInvariant()})")));
|
helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Where(m => m.Name.ToLowerInvariant() != "help").OrderBy(m => m.Name).Prepend(NadekoBot.CommandService.Modules.FirstOrDefault(m=>m.Name.ToLowerInvariant()=="help")).Select(m => $"- [{m.Name}](#{m.Name.ToLowerInvariant()})")));
|
||||||
helpstr.AppendLine();
|
helpstr.AppendLine();
|
||||||
string lastModule = null;
|
string lastModule = null;
|
||||||
foreach (var com in _commands.Commands.OrderBy(com=>com.Module.Name).GroupBy(c=>c.Text).Select(g=>g.First()))
|
foreach (var com in _commands.Commands.OrderBy(com=>com.Module.Name).GroupBy(c=>c.Text).Select(g=>g.First()))
|
||||||
|
@ -59,7 +59,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
if (autoDelete)
|
if (autoDelete)
|
||||||
try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
await umsg.Channel.SendMessageAsync($"{umsg.Author.Mention} `said:` "+text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
|
await umsg.Channel.SendMessageAsync($"{umsg.Author.Mention} `:` "+text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
@ -161,6 +161,7 @@ namespace NadekoBot.Modules.Searches
|
|||||||
if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to))
|
if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to))
|
||||||
{
|
{
|
||||||
try { await channel.SendMessageAsync("`Invalid source and/or target Language.`").ConfigureAwait(false); } catch { }
|
try { await channel.SendMessageAsync("`Invalid source and/or target Language.`").ConfigureAwait(false); } catch { }
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
|
UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);
|
||||||
|
@ -2623,7 +2623,7 @@
|
|||||||
<value>cleverbot</value>
|
<value>cleverbot</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="cleverbot_desc" xml:space="preserve">
|
<data name="cleverbot_desc" xml:space="preserve">
|
||||||
<value>Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the channel this command is ran in. You can specify "all" parameter to enable it in the whole server. Custom reactions starting with %mention% won't work if cleverbot is enabled.' </value>
|
<value>Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="cleverbot_usage" xml:space="preserve">
|
<data name="cleverbot_usage" xml:space="preserve">
|
||||||
<value>`{0}cleverbot`</value>
|
<value>`{0}cleverbot`</value>
|
||||||
|
25
src/NadekoBot/Services/CleverBotApi/ChatterBot.cs
Normal file
25
src/NadekoBot/Services/CleverBotApi/ChatterBot.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
public interface ChatterBot
|
||||||
|
{
|
||||||
|
ChatterBotSession CreateSession();
|
||||||
|
}
|
||||||
|
}
|
45
src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs
Normal file
45
src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
public class ChatterBotFactory
|
||||||
|
{
|
||||||
|
public static ChatterBot Create(ChatterBotType type)
|
||||||
|
{
|
||||||
|
return Create(type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatterBot Create(ChatterBotType type, object arg)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ChatterBotType.CLEVERBOT:
|
||||||
|
return new Cleverbot("http://www.cleverbot.com/", "http://www.cleverbot.com/webservicemin?uc=165", 26);
|
||||||
|
case ChatterBotType.JABBERWACKY:
|
||||||
|
return new Cleverbot("http://jabberwacky.com", "http://jabberwacky.com/webservicemin", 20);
|
||||||
|
case ChatterBotType.PANDORABOTS:
|
||||||
|
if (arg == null) throw new ArgumentException("PANDORABOTS needs a botid arg", nameof(arg));
|
||||||
|
return new Pandorabots(arg.ToString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
src/NadekoBot/Services/CleverBotApi/ChatterBotSession.cs
Normal file
28
src/NadekoBot/Services/CleverBotApi/ChatterBotSession.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
public interface ChatterBotSession
|
||||||
|
{
|
||||||
|
Task<ChatterBotThought> Think(ChatterBotThought thought);
|
||||||
|
Task<string> Think(string text);
|
||||||
|
}
|
||||||
|
}
|
26
src/NadekoBot/Services/CleverBotApi/ChatterBotThought.cs
Normal file
26
src/NadekoBot/Services/CleverBotApi/ChatterBotThought.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
public class ChatterBotThought
|
||||||
|
{
|
||||||
|
public string[] Emotions { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
}
|
||||||
|
}
|
27
src/NadekoBot/Services/CleverBotApi/ChatterBotType.cs
Normal file
27
src/NadekoBot/Services/CleverBotApi/ChatterBotType.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
public enum ChatterBotType
|
||||||
|
{
|
||||||
|
CLEVERBOT,
|
||||||
|
JABBERWACKY,
|
||||||
|
PANDORABOTS
|
||||||
|
}
|
||||||
|
}
|
116
src/NadekoBot/Services/CleverBotApi/Cleverbot.cs
Normal file
116
src/NadekoBot/Services/CleverBotApi/Cleverbot.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
internal class Cleverbot : ChatterBot
|
||||||
|
{
|
||||||
|
private readonly int endIndex;
|
||||||
|
private readonly string baseUrl;
|
||||||
|
private readonly string url;
|
||||||
|
|
||||||
|
public Cleverbot(string baseUrl, string url, int endIndex)
|
||||||
|
{
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
this.url = url;
|
||||||
|
this.endIndex = endIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChatterBotSession CreateSession()
|
||||||
|
{
|
||||||
|
return new CleverbotSession(baseUrl, url, endIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CleverbotSession : ChatterBotSession
|
||||||
|
{
|
||||||
|
private readonly int endIndex;
|
||||||
|
private readonly string url;
|
||||||
|
private readonly IDictionary<string, string> vars;
|
||||||
|
private readonly CookieCollection cookies;
|
||||||
|
|
||||||
|
public CleverbotSession(string baseUrl, string url, int endIndex)
|
||||||
|
{
|
||||||
|
this.url = url;
|
||||||
|
this.endIndex = endIndex;
|
||||||
|
vars = new Dictionary<string, string>();
|
||||||
|
//vars["start"] = "y";
|
||||||
|
vars["stimulus"] = "";
|
||||||
|
vars["islearning"] = "1";
|
||||||
|
vars["icognoid"] = "wsf";
|
||||||
|
//vars["fno"] = "0";
|
||||||
|
//vars["sub"] = "Say";
|
||||||
|
//vars["cleanslate"] = "false";
|
||||||
|
cookies = Utils.GetCookies(baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ChatterBotThought> Think(ChatterBotThought thought)
|
||||||
|
{
|
||||||
|
vars["stimulus"] = thought.Text;
|
||||||
|
|
||||||
|
var formData = Utils.ParametersToWWWFormURLEncoded(vars);
|
||||||
|
var formDataToDigest = formData.Substring(9, endIndex);
|
||||||
|
var formDataDigest = Utils.MD5(formDataToDigest);
|
||||||
|
vars["icognocheck"] = formDataDigest;
|
||||||
|
|
||||||
|
var response = await Utils.Post(url, vars, cookies).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var responseValues = response.Split('\r');
|
||||||
|
|
||||||
|
//vars[""] = Utils.StringAtIndex(responseValues, 0); ??
|
||||||
|
vars["sessionid"] = Utils.StringAtIndex(responseValues, 1);
|
||||||
|
vars["logurl"] = Utils.StringAtIndex(responseValues, 2);
|
||||||
|
vars["vText8"] = Utils.StringAtIndex(responseValues, 3);
|
||||||
|
vars["vText7"] = Utils.StringAtIndex(responseValues, 4);
|
||||||
|
vars["vText6"] = Utils.StringAtIndex(responseValues, 5);
|
||||||
|
vars["vText5"] = Utils.StringAtIndex(responseValues, 6);
|
||||||
|
vars["vText4"] = Utils.StringAtIndex(responseValues, 7);
|
||||||
|
vars["vText3"] = Utils.StringAtIndex(responseValues, 8);
|
||||||
|
vars["vText2"] = Utils.StringAtIndex(responseValues, 9);
|
||||||
|
vars["prevref"] = Utils.StringAtIndex(responseValues, 10);
|
||||||
|
//vars[""] = Utils.StringAtIndex(responseValues, 11); ??
|
||||||
|
// vars["emotionalhistory"] = Utils.StringAtIndex(responseValues, 12);
|
||||||
|
// vars["ttsLocMP3"] = Utils.StringAtIndex(responseValues, 13);
|
||||||
|
// vars["ttsLocTXT"] = Utils.StringAtIndex(responseValues, 14);
|
||||||
|
// vars["ttsLocTXT3"] = Utils.StringAtIndex(responseValues, 15);
|
||||||
|
// vars["ttsText"] = Utils.StringAtIndex(responseValues, 16);
|
||||||
|
// vars["lineRef"] = Utils.StringAtIndex(responseValues, 17);
|
||||||
|
// vars["lineURL"] = Utils.StringAtIndex(responseValues, 18);
|
||||||
|
// vars["linePOST"] = Utils.StringAtIndex(responseValues, 19);
|
||||||
|
// vars["lineChoices"] = Utils.StringAtIndex(responseValues, 20);
|
||||||
|
// vars["lineChoicesAbbrev"] = Utils.StringAtIndex(responseValues, 21);
|
||||||
|
// vars["typingData"] = Utils.StringAtIndex(responseValues, 22);
|
||||||
|
// vars["divert"] = Utils.StringAtIndex(responseValues, 23);
|
||||||
|
|
||||||
|
var responseThought = new ChatterBotThought();
|
||||||
|
|
||||||
|
responseThought.Text = Utils.StringAtIndex(responseValues, 0);
|
||||||
|
|
||||||
|
return responseThought;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Think(string text)
|
||||||
|
{
|
||||||
|
return (await Think(new ChatterBotThought {Text = text}).ConfigureAwait(false)).Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
src/NadekoBot/Services/CleverBotApi/Pandorabots.cs
Normal file
68
src/NadekoBot/Services/CleverBotApi/Pandorabots.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
internal class Pandorabots : ChatterBot
|
||||||
|
{
|
||||||
|
private readonly string botid;
|
||||||
|
|
||||||
|
public Pandorabots(string botid)
|
||||||
|
{
|
||||||
|
this.botid = botid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChatterBotSession CreateSession()
|
||||||
|
{
|
||||||
|
return new PandorabotsSession(botid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PandorabotsSession : ChatterBotSession
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, string> vars;
|
||||||
|
|
||||||
|
public PandorabotsSession(string botid)
|
||||||
|
{
|
||||||
|
vars = new Dictionary<string, string>();
|
||||||
|
vars["botid"] = botid;
|
||||||
|
vars["custid"] = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ChatterBotThought> Think(ChatterBotThought thought)
|
||||||
|
{
|
||||||
|
vars["input"] = thought.Text;
|
||||||
|
|
||||||
|
var response = await Utils.Post("http://www.pandorabots.com/pandora/talk-xml", vars, null).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var responseThought = new ChatterBotThought();
|
||||||
|
responseThought.Text = Utils.XPathSearch(response, "//result/that/text()");
|
||||||
|
|
||||||
|
return responseThought;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Think(string text)
|
||||||
|
{
|
||||||
|
return (await Think(new ChatterBotThought {Text = text}).ConfigureAwait(false)).Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
src/NadekoBot/Services/CleverBotApi/Utils.cs
Normal file
148
src/NadekoBot/Services/CleverBotApi/Utils.cs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
using NadekoBot.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.XPath;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ChatterBotAPI
|
||||||
|
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Services.CleverBotApi
|
||||||
|
{
|
||||||
|
internal static class Utils
|
||||||
|
{
|
||||||
|
public static string ParametersToWWWFormURLEncoded(IDictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
string wwwFormUrlEncoded = null;
|
||||||
|
foreach (var parameterKey in parameters.Keys)
|
||||||
|
{
|
||||||
|
var parameterValue = parameters[parameterKey];
|
||||||
|
var parameter = string.Format("{0}={1}", System.Uri.EscapeDataString(parameterKey), System.Uri.EscapeDataString(parameterValue));
|
||||||
|
if (wwwFormUrlEncoded == null)
|
||||||
|
{
|
||||||
|
wwwFormUrlEncoded = parameter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wwwFormUrlEncoded = string.Format("{0}&{1}", wwwFormUrlEncoded, parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wwwFormUrlEncoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string MD5(string input)
|
||||||
|
{
|
||||||
|
// step 1, calculate MD5 hash from input
|
||||||
|
var md5 = System.Security.Cryptography.MD5.Create();
|
||||||
|
var inputBytes = Encoding.ASCII.GetBytes(input);
|
||||||
|
var hash = md5.ComputeHash(inputBytes);
|
||||||
|
|
||||||
|
// step 2, convert byte array to hex string
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
for (var i = 0; i < hash.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(hash[i].ToString("X2"));
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CookieCollection GetCookies(string url)
|
||||||
|
{
|
||||||
|
CookieContainer container = new CookieContainer();
|
||||||
|
|
||||||
|
HttpResponseMessage res;
|
||||||
|
using (var handler = new HttpClientHandler() { CookieContainer = container })
|
||||||
|
using (var http = new HttpClient(handler))
|
||||||
|
{
|
||||||
|
http.AddFakeHeaders();
|
||||||
|
http.DefaultRequestHeaders.Add("ContentType", "text/html");
|
||||||
|
res = http.GetAsync(url).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
var response = res.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
return container.GetCookies(res.RequestMessage.RequestUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string> Post(string url, IDictionary<string, string> parameters, CookieCollection cookies)
|
||||||
|
{
|
||||||
|
var postData = ParametersToWWWFormURLEncoded(parameters);
|
||||||
|
var postDataBytes = Encoding.ASCII.GetBytes(postData);
|
||||||
|
|
||||||
|
var request = (HttpWebRequest)WebRequest.Create(url);
|
||||||
|
|
||||||
|
if (cookies != null)
|
||||||
|
{
|
||||||
|
var container = new CookieContainer();
|
||||||
|
container.Add(new Uri(url), cookies);
|
||||||
|
request.CookieContainer = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
request.Method = "POST";
|
||||||
|
request.ContentType = "application/x-www-form-urlencoded";
|
||||||
|
|
||||||
|
using (var outputStream = await request.GetRequestStreamAsync())
|
||||||
|
{
|
||||||
|
outputStream.Write(postDataBytes, 0, postDataBytes.Length);
|
||||||
|
outputStream.Flush();
|
||||||
|
|
||||||
|
var response = (HttpWebResponse)await request.GetResponseAsync();
|
||||||
|
using (var responseStreamReader = new StreamReader(response.GetResponseStream()))
|
||||||
|
{
|
||||||
|
return responseStreamReader.ReadToEnd().Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//HttpClientHandler handler;
|
||||||
|
//var uri = new Uri(url);
|
||||||
|
//if (cookies == null)
|
||||||
|
// handler = new HttpClientHandler();
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// var cookieContainer = new CookieContainer();
|
||||||
|
// cookieContainer.Add(uri, cookies);
|
||||||
|
// handler = new HttpClientHandler() { CookieContainer = cookieContainer };
|
||||||
|
//}
|
||||||
|
//using (handler)
|
||||||
|
//using (var http = new HttpClient(handler))
|
||||||
|
//{
|
||||||
|
// var res = await http.PostAsync(url, new FormUrlEncodedContent(parameters)).ConfigureAwait(false);
|
||||||
|
// return await res.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static string XPathSearch(string input, string expression)
|
||||||
|
{
|
||||||
|
var document = new XPathDocument(new MemoryStream(Encoding.ASCII.GetBytes(input)));
|
||||||
|
var navigator = document.CreateNavigator();
|
||||||
|
return navigator.SelectSingleNode(expression).Value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string StringAtIndex(string[] strings, int index)
|
||||||
|
{
|
||||||
|
if (index >= strings.Length) return "";
|
||||||
|
return strings[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,8 +26,6 @@ namespace NadekoBot.Services.Impl
|
|||||||
public string LoLApiKey { get; }
|
public string LoLApiKey { get; }
|
||||||
public string OsuApiKey { get; }
|
public string OsuApiKey { get; }
|
||||||
public string SoundCloudClientId { get; }
|
public string SoundCloudClientId { get; }
|
||||||
public string CleverbotApiUser { get; }
|
|
||||||
public string CleverbotApiKey { get; }
|
|
||||||
|
|
||||||
public DB Db { get; }
|
public DB Db { get; }
|
||||||
public int TotalShards { get; }
|
public int TotalShards { get; }
|
||||||
@ -52,8 +50,6 @@ namespace NadekoBot.Services.Impl
|
|||||||
ClientId = cm.ClientId;
|
ClientId = cm.ClientId;
|
||||||
SoundCloudClientId = cm.SoundCloudClientId;
|
SoundCloudClientId = cm.SoundCloudClientId;
|
||||||
CarbonKey = cm.CarbonKey;
|
CarbonKey = cm.CarbonKey;
|
||||||
CleverbotApiKey = cm.CleverbotApiKey;
|
|
||||||
CleverbotApiUser = cm.CleverbotApiUser;
|
|
||||||
if (cm.Db == null)
|
if (cm.Db == null)
|
||||||
Db = new DB("sqlite", "");
|
Db = new DB("sqlite", "");
|
||||||
else
|
else
|
||||||
@ -81,8 +77,6 @@ namespace NadekoBot.Services.Impl
|
|||||||
public string CarbonKey { get; set; } = "";
|
public string CarbonKey { get; set; } = "";
|
||||||
public DB Db { get; set; }
|
public DB Db { get; set; }
|
||||||
public int TotalShards { get; set; } = 1;
|
public int TotalShards { get; set; } = 1;
|
||||||
public string CleverbotApiUser { get; set; }
|
|
||||||
public string CleverbotApiKey { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DbModel
|
private class DbModel
|
||||||
|
@ -12,7 +12,5 @@
|
|||||||
"SoundCloudClientId": "",
|
"SoundCloudClientId": "",
|
||||||
"CarbonKey": "",
|
"CarbonKey": "",
|
||||||
"Db": null,
|
"Db": null,
|
||||||
"TotalShards": 1,
|
"TotalShards": 1
|
||||||
"CleverbotApiUser": null,
|
|
||||||
"CleverbotApiKey": null
|
|
||||||
}
|
}
|
@ -41,7 +41,8 @@
|
|||||||
},
|
},
|
||||||
"Discord.Net": {
|
"Discord.Net": {
|
||||||
"target": "project"
|
"target": "project"
|
||||||
}
|
},
|
||||||
|
"System.Xml.XPath": "4.0.1"
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
|
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
|
||||||
|
Loading…
Reference in New Issue
Block a user