From c69f7951a743216fc547b96d8aebbac97ff57914 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 14:34:09 +1300 Subject: [PATCH 01/62] Updated EllieBot.Coordinator --- EllieBot.sln | 16 +- TODO.md | 3 +- src/EllieBot.Coordinator/CoordStartup.cs | 47 ++ .../EllieBot.Coordinator.csproj | 19 + src/EllieBot.Coordinator/LogSetup.cs | 43 ++ src/EllieBot.Coordinator/Program.cs | 20 + .../Properties/launchSettings.json | 13 + .../Protos/coordinator.proto | 127 +++++ src/EllieBot.Coordinator/README.md | 11 + .../Services/CoordinatorRunner.cs | 457 ++++++++++++++++++ .../Services/CoordinatorService.cs | 144 ++++++ src/EllieBot.Coordinator/Shared/Config.cs | 21 + src/EllieBot.Coordinator/Shared/CoordState.cs | 9 + .../Shared/JsonStatusObject.cs | 9 + .../Shared/ShardStatus.cs | 15 + .../appsettings.Development.json | 9 + src/EllieBot.Coordinator/appsettings.json | 20 + src/EllieBot.Coordinator/coord.yml | 12 + 18 files changed, 993 insertions(+), 2 deletions(-) create mode 100644 src/EllieBot.Coordinator/CoordStartup.cs create mode 100644 src/EllieBot.Coordinator/EllieBot.Coordinator.csproj create mode 100644 src/EllieBot.Coordinator/LogSetup.cs create mode 100644 src/EllieBot.Coordinator/Program.cs create mode 100644 src/EllieBot.Coordinator/Properties/launchSettings.json create mode 100644 src/EllieBot.Coordinator/Protos/coordinator.proto create mode 100644 src/EllieBot.Coordinator/README.md create mode 100644 src/EllieBot.Coordinator/Services/CoordinatorRunner.cs create mode 100644 src/EllieBot.Coordinator/Services/CoordinatorService.cs create mode 100644 src/EllieBot.Coordinator/Shared/Config.cs create mode 100644 src/EllieBot.Coordinator/Shared/CoordState.cs create mode 100644 src/EllieBot.Coordinator/Shared/JsonStatusObject.cs create mode 100644 src/EllieBot.Coordinator/Shared/ShardStatus.cs create mode 100644 src/EllieBot.Coordinator/appsettings.Development.json create mode 100644 src/EllieBot.Coordinator/appsettings.json create mode 100644 src/EllieBot.Coordinator/coord.yml diff --git a/EllieBot.sln b/EllieBot.sln index c2985a3..4b578fa 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -17,7 +17,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot", "src\EllieBot\El EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ayu", "ayu", "{872A4C63-833C-4AE0-91AB-3CE348D3E6F8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ayu.Discord.Voice", "src\ayu\Ayu.Discord.Voice\Ayu.Discord.Voice.csproj", "{5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ayu.Discord.Voice", "src\ayu\Ayu.Discord.Voice\Ayu.Discord.Voice.csproj", "{5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Tests", "src\EllieBot.Tests\EllieBot.Tests.csproj", "{179DF3B3-AD32-4335-8231-9818338DF3A2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Coordinator", "src\EllieBot.Coordinator\EllieBot.Coordinator.csproj", "{A631DDF0-3AD1-4CB9-8458-314B1320868A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +37,14 @@ Global {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Debug|Any CPU.Build.0 = Debug|Any CPU {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Release|Any CPU.ActiveCfg = Release|Any CPU {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Release|Any CPU.Build.0 = Release|Any CPU + {179DF3B3-AD32-4335-8231-9818338DF3A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {179DF3B3-AD32-4335-8231-9818338DF3A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {179DF3B3-AD32-4335-8231-9818338DF3A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {179DF3B3-AD32-4335-8231-9818338DF3A2}.Release|Any CPU.Build.0 = Release|Any CPU + {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -41,6 +53,8 @@ Global {BCB21472-84D2-4B63-B5DD-31E6A3EC9791} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {872A4C63-833C-4AE0-91AB-3CE348D3E6F8} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067} = {872A4C63-833C-4AE0-91AB-3CE348D3E6F8} + {179DF3B3-AD32-4335-8231-9818338DF3A2} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {A631DDF0-3AD1-4CB9-8458-314B1320868A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79F61C2C-CDBB-4361-A234-91A0B334CFE4} diff --git a/TODO.md b/TODO.md index 6227514..fb3ff2e 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,4 @@ # List of things to do - - Finish the full system rewrite \ No newline at end of file + - Finish the full system rewrite + - Finish the EllieBot.Tests project \ No newline at end of file diff --git a/src/EllieBot.Coordinator/CoordStartup.cs b/src/EllieBot.Coordinator/CoordStartup.cs new file mode 100644 index 0000000..4bc262c --- /dev/null +++ b/src/EllieBot.Coordinator/CoordStartup.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace EllieBot.Coordinator +{ + public class CoordStartup + { + public IConfiguration Configuration { get; } + + public CoordStartup(IConfiguration config) + => Configuration = config; + + public void ConfigureServices(IServiceCollection services) + { + services.AddGrpc(); + services.AddSingleton(); + services.AddSingleton( + serviceProvider => serviceProvider.GetRequiredService()); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + + endpoints.MapGet("/", + async context => + { + await context.Response.WriteAsync( + "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); + }); + }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj b/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj new file mode 100644 index 0000000..91942cc --- /dev/null +++ b/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + + + + + + + + + + + + + + + diff --git a/src/EllieBot.Coordinator/LogSetup.cs b/src/EllieBot.Coordinator/LogSetup.cs new file mode 100644 index 0000000..0850b39 --- /dev/null +++ b/src/EllieBot.Coordinator/LogSetup.cs @@ -0,0 +1,43 @@ +using System; +using System.Text; +using Serilog; +using Serilog.Events; +using Serilog.Sinks.SystemConsole.Themes; + +namespace EllieBot.Services +{ + public static class LogSetup + { + public static void SetupLogger(object source) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .MinimumLevel.Override("System", LogEventLevel.Information) + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.File("coord.log", LogEventLevel.Information, + rollOnFileSizeLimit: true, + fileSizeLimitBytes: 10_000_000) + .WriteTo.Console(LogEventLevel.Information, + theme: GetTheme(), + outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}") + .Enrich.WithProperty("LogSource", source) + .CreateLogger(); + + Console.OutputEncoding = Encoding.UTF8; + } + + private static ConsoleTheme GetTheme() + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + return AnsiConsoleTheme.Code; + + +#if DEBUG + return AnsiConsoleTheme.Code; +#else + return ConsoleTheme.None; +#endif + } + } +} diff --git a/src/EllieBot.Coordinator/Program.cs b/src/EllieBot.Coordinator/Program.cs new file mode 100644 index 0000000..6923013 --- /dev/null +++ b/src/EllieBot.Coordinator/Program.cs @@ -0,0 +1,20 @@ +using System; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using EllieBot.Coordinator; +using EllieBot.Services; +using Serilog; + +// Additional configuration is required to successfully run gRPC on macOS. +// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 +static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + +LogSetup.SetupLogger("coord"); +Log.Information("Starting coordinator... Pid: {ProcessId}", Environment.ProcessId); + +CreateHostBuilder(args).Build().Run(); \ No newline at end of file diff --git a/src/EllieBot.Coordinator/Properties/launchSettings.json b/src/EllieBot.Coordinator/Properties/launchSettings.json new file mode 100644 index 0000000..1f39bc8 --- /dev/null +++ b/src/EllieBot.Coordinator/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "EllieBot.Coordinator": { + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": false, + "applicationUrl": "http://localhost:3442;https://localhost:3443", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/EllieBot.Coordinator/Protos/coordinator.proto b/src/EllieBot.Coordinator/Protos/coordinator.proto new file mode 100644 index 0000000..2df14c3 --- /dev/null +++ b/src/EllieBot.Coordinator/Protos/coordinator.proto @@ -0,0 +1,127 @@ +syntax = "proto3"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "EllieBot.Coordinator"; + +package elliebot; + +service Coordinator { + // sends update to coordinator to let it know that the shard is alive + rpc Heartbeat(HeartbeatRequest) returns (HeartbeatReply); + // restarts a shard given the id + rpc RestartShard(RestartShardRequest) returns (RestartShardReply); + // reshards given the new number of shards + rpc Reshard(ReshardRequest) returns (ReshardReply); + // Reload config + rpc Reload(ReloadRequest) returns (ReloadReply); + // Gets status of a single shard + rpc GetStatus(GetStatusRequest) returns (GetStatusReply); + // Get status of all shards + rpc GetAllStatuses(GetAllStatusesRequest) returns (GetAllStatusesReply); + // Restarts all shards. Queues them to be restarted at a normal rate. Setting Nuke to true will kill all shards right + // away + rpc RestartAllShards(RestartAllRequest) returns (RestartAllReply); + + // kill coordinator (and all shards as a consequence) + rpc Die(DieRequest) returns (DieReply); + + rpc SetConfigText(SetConfigTextRequest) returns (SetConfigTextReply); + + rpc GetConfigText(GetConfigTextRequest) returns (GetConfigTextReply); +} + +enum ConnState { + Disconnected = 0; + Connecting = 1; + Connected = 2; +} + +message HeartbeatRequest { + int32 shardId = 1; + int32 guildCount = 2; + ConnState state = 3; +} + +message HeartbeatReply { + bool gracefulImminent = 1; +} + +message RestartShardRequest { + int32 shardId = 1; + // should it be queued for restart, set false to kill it and restart immediately with priority + bool queue = 2; +} + +message RestartShardReply { + +} + +message ReshardRequest { + int32 shards = 1; +} + +message ReshardReply { + +} + +message ReloadRequest { + +} + +message ReloadReply { + +} + +message GetStatusRequest { + int32 shardId = 1; +} + +message GetStatusReply { + int32 shardId = 1; + ConnState state = 2; + int32 guildCount = 3; + google.protobuf.Timestamp lastUpdate = 4; + bool scheduledForRestart = 5; + google.protobuf.Timestamp startedAt = 6; +} + +message GetAllStatusesRequest { + +} + +message GetAllStatusesReply { + repeated GetStatusReply Statuses = 1; +} + +message RestartAllRequest { + bool nuke = 1; +} + +message RestartAllReply { + +} + +message DieRequest { + bool graceful = 1; +} + +message DieReply { + +} + +message GetConfigTextRequest { + +} + +message GetConfigTextReply { + string configYml = 1; +} + +message SetConfigTextRequest { + string configYml = 1; +} + +message SetConfigTextReply { + bool success = 1; + string error = 2; +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/README.md b/src/EllieBot.Coordinator/README.md new file mode 100644 index 0000000..9a2a993 --- /dev/null +++ b/src/EllieBot.Coordinator/README.md @@ -0,0 +1,11 @@ +# Coordinator project + +Grpc-based coordinator useful for sharded EllieBot. Its purpose is controlling the lifetime and checking status of the shards it creates. + +### Supports + +- Checking status +- Individual shard restarts +- Full shard restarts +- Graceful coordinator restarts (restart/update coordinator without killing shards) +- Kill/Stop diff --git a/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs b/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs new file mode 100644 index 0000000..de870ca --- /dev/null +++ b/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs @@ -0,0 +1,457 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Serilog; +using YamlDotNet.Serialization; + +namespace EllieBot.Coordinator +{ + public sealed class CoordinatorRunner : BackgroundService + { + private const string CONFIG_PATH = "coord.yml"; + + private const string GRACEFUL_STATE_PATH = "graceful.json"; + private const string GRACEFUL_STATE_BACKUP_PATH = "graceful_old.json"; + + private readonly Serializer _serializer; + private readonly Deserializer _deserializer; + + private Config _config; + private ShardStatus[] _shardStatuses; + + private readonly object locker = new object(); + private readonly Random _rng; + private bool _gracefulImminent; + + public CoordinatorRunner() + { + _serializer = new(); + _deserializer = new(); + _config = LoadConfig(); + _rng = new Random(); + + if (!TryRestoreOldState()) + InitAll(); + } + + private Config LoadConfig() + { + lock (locker) + { + return _deserializer.Deserialize(File.ReadAllText(CONFIG_PATH)); + } + } + + private void SaveConfig(in Config config) + { + lock (locker) + { + var output = _serializer.Serialize(config); + File.WriteAllText(CONFIG_PATH, output); + } + } + + public void ReloadConfig() + { + lock (locker) + { + var oldConfig = _config; + var newConfig = LoadConfig(); + if (oldConfig.TotalShards != newConfig.TotalShards) + { + KillAll(); + } + _config = newConfig; + if (oldConfig.TotalShards != newConfig.TotalShards) + { + InitAll(); + } + } + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + // Log.Information("Executing"); + + bool first = true; + while (!stoppingToken.IsCancellationRequested) + { + try + { + bool hadAction = false; + lock (locker) + { + var shardIds = Enumerable.Range(0, 1) // shard 0 is always first + .Append((int)((1173494918812024863 >> 22) % _config.TotalShards)) // then ellie server shard + .Concat(Enumerable.Range(1, _config.TotalShards - 1) + .OrderBy(_ => _rng.Next())) // then all other shards in a random order + .Distinct() + .ToList(); + + if (first) + { + // Log.Information("Startup order: {StartupOrder}",string.Join(' ', shardIds)); + first = false; + } + + foreach (var shardId in shardIds) + { + if (stoppingToken.IsCancellationRequested) + break; + + var status = _shardStatuses[shardId]; + + if (status.ShouldRestart) + { + Log.Warning("Shard {ShardId} is restarting (scheduled)...", shardId); + hadAction = true; + StartShard(shardId); + break; + } + + if (DateTime.UtcNow - status.LastUpdate > + TimeSpan.FromSeconds(_config.UnresponsiveSec)) + { + Log.Warning("Shard {ShardId} is restarting (unresponsive)...", shardId); + hadAction = true; + StartShard(shardId); + break; + } + + if (status.StateCounter > 8 && status.State != ConnState.Connected) + { + Log.Warning("Shard {ShardId} is restarting (stuck)...", shardId); + hadAction = true; + StartShard(shardId); + break; + } + + try + { + if (status.Process is null or { HasExited: true }) + { + Log.Warning("Shard {ShardId} is starting (process)...", shardId); + hadAction = true; + StartShard(shardId); + break; + } + } + catch (InvalidOperationException) + { + Log.Warning("Process for shard {ShardId} is bugged... ", shardId); + hadAction = true; + StartShard(shardId); + break; + } + } + } + + if (hadAction) + { + await Task.Delay(_config.RecheckIntervalMs, stoppingToken).ConfigureAwait(false); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error in coordinator: {Message}", ex.Message); + } + + await Task.Delay(5000, stoppingToken).ConfigureAwait(false); + } + } + + private void StartShard(int shardId) + { + var status = _shardStatuses[shardId]; + try + { + status.Process?.Kill(true); + } + catch + { + } + try + { + status.Process?.Dispose(); + } + catch + { + } + + var proc = StartShardProcess(shardId); + _shardStatuses[shardId] = status with + { + Process = proc, + LastUpdate = DateTime.UtcNow, + State = ConnState.Disconnected, + ShouldRestart = false, + StateCounter = 0, + }; + } + + private Process StartShardProcess(int shardId) + => Process.Start(new ProcessStartInfo() + { + FileName = _config.ShardStartCommand, + Arguments = string.Format(_config.ShardStartArgs, + shardId, + _config.TotalShards), + EnvironmentVariables = + { + {"ELLIEBOT_IS_COORDINATED", "1"} + } + // CreateNoWindow = true, + // UseShellExecute = false, + }); + + public bool Heartbeat(int shardId, int guildCount, ConnState state) + { + lock (locker) + { + if (shardId >= _shardStatuses.Length) + throw new ArgumentOutOfRangeException(nameof(shardId)); + + var status = _shardStatuses[shardId]; + status = _shardStatuses[shardId] = status with + { + GuildCount = guildCount, + State = state, + LastUpdate = DateTime.UtcNow, + StateCounter = status.State == state + ? status.StateCounter + 1 + : 1 + }; + if (status.StateCounter > 1 && status.State == ConnState.Disconnected) + { + Log.Warning("Shard {ShardId} is in DISCONNECTED state! ({StateCounter})", + status.ShardId, + status.StateCounter); + } + + return _gracefulImminent; + } + } + + public void SetShardCount(int totalShards) + { + lock (locker) + { + SaveConfig(new Config( + totalShards, + _config.RecheckIntervalMs, + _config.ShardStartCommand, + _config.ShardStartArgs, + _config.UnresponsiveSec)); + } + } + + public void RestartShard(int shardId, bool queue) + { + lock (locker) + { + if (shardId >= _shardStatuses.Length) + throw new ArgumentOutOfRangeException(nameof(shardId)); + + _shardStatuses[shardId] = _shardStatuses[shardId] with + { + ShouldRestart = true, + StateCounter = 0, + }; + } + } + + public void RestartAll(bool nuke) + { + lock (locker) + { + if (nuke) + { + KillAll(); + } + + QueueAll(); + } + } + + private void KillAll() + { + lock (locker) + { + for (var shardId = 0; shardId < _shardStatuses.Length; shardId++) + { + var status = _shardStatuses[shardId]; + if (status.Process is Process p) + { + try { p.Kill(); } catch { } + try { p.Dispose(); } catch { } + _shardStatuses[shardId] = status with + { + Process = null, + ShouldRestart = true, + LastUpdate = DateTime.UtcNow, + State = ConnState.Disconnected, + StateCounter = 0, + }; + } + } + } + } + + public void SaveState() + { + var coordState = new CoordState() + { + StatusObjects = _shardStatuses + .Select(x => new JsonStatusObject() + { + Pid = x.Process?.Id, + ConnectionState = x.State, + GuildCount = x.GuildCount, + }) + .ToList() + }; + var jsonState = JsonSerializer.Serialize(coordState, new JsonSerializerOptions() + { + WriteIndented = true, + }); + File.WriteAllText(GRACEFUL_STATE_PATH, jsonState); + } + private bool TryRestoreOldState() + { + lock (locker) + { + if (!File.Exists(GRACEFUL_STATE_PATH)) + return false; + + Log.Information("Restoring old coordinator state..."); + + CoordState savedState; + try + { + savedState = JsonSerializer.Deserialize(File.ReadAllText(GRACEFUL_STATE_PATH)); + + if (savedState is null) + throw new Exception("Old state is null?!"); + } + catch (Exception ex) + { + Log.Error(ex, "Error deserializing old state: {Message}", ex.Message); + File.Move(GRACEFUL_STATE_PATH, GRACEFUL_STATE_BACKUP_PATH, overwrite: true); + return false; + } + + if (savedState.StatusObjects.Count != _config.TotalShards) + { + Log.Error("Unable to restore old state because shard count doesn't match"); + File.Move(GRACEFUL_STATE_PATH, GRACEFUL_STATE_BACKUP_PATH, overwrite: true); + return false; + } + + _shardStatuses = new ShardStatus[_config.TotalShards]; + + for (int shardId = 0; shardId < _shardStatuses.Length; shardId++) + { + var statusObj = savedState.StatusObjects[shardId]; + Process p = null; + if (statusObj.Pid is { } pid) + { + try + { + p = Process.GetProcessById(pid); + } + catch (Exception ex) + { + Log.Warning(ex, "Process for shard {ShardId} is not runnning", shardId); + } + } + + _shardStatuses[shardId] = new( + shardId, + DateTime.UtcNow, + statusObj.GuildCount, + statusObj.ConnectionState, + p is null, + p); + } + + File.Move(GRACEFUL_STATE_PATH, GRACEFUL_STATE_BACKUP_PATH, overwrite: true); + Log.Information("Old state restored!"); + return true; + } + } + + private void InitAll() + { + lock (locker) + { + _shardStatuses = new ShardStatus[_config.TotalShards]; + for (var shardId = 0; shardId < _shardStatuses.Length; shardId++) + { + _shardStatuses[shardId] = new ShardStatus(shardId, DateTime.UtcNow); + } + } + } + + private void QueueAll() + { + lock (locker) + { + for (var shardId = 0; shardId < _shardStatuses.Length; shardId++) + { + _shardStatuses[shardId] = _shardStatuses[shardId] with + { + ShouldRestart = true + }; + } + } + } + + + public ShardStatus GetShardStatus(int shardId) + { + lock (locker) + { + if (shardId >= _shardStatuses.Length) + throw new ArgumentOutOfRangeException(nameof(shardId)); + + return _shardStatuses[shardId]; + } + } + + public List GetAllStatuses() + { + lock (locker) + { + var toReturn = new List(_shardStatuses.Length); + toReturn.AddRange(_shardStatuses); + return toReturn; + } + } + + public void PrepareGracefulShutdown() + { + lock (locker) + { + _gracefulImminent = true; + } + } + + public string GetConfigText() + => File.ReadAllText(CONFIG_PATH); + + public void SetConfigText(string text) + { + if (string.IsNullOrWhiteSpace(text)) + throw new ArgumentNullException(nameof(text), "coord.yml can't be empty"); + var config = _deserializer.Deserialize(text); + SaveConfig(in config); + ReloadConfig(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/Services/CoordinatorService.cs b/src/EllieBot.Coordinator/Services/CoordinatorService.cs new file mode 100644 index 0000000..8666736 --- /dev/null +++ b/src/EllieBot.Coordinator/Services/CoordinatorService.cs @@ -0,0 +1,144 @@ +using System; +using System.Threading.Tasks; +using Google.Protobuf.WellKnownTypes; +using Grpc.Core; + +namespace EllieBot.Coordinator +{ + public sealed class CoordinatorService : Coordinator.CoordinatorBase + { + private readonly CoordinatorRunner _runner; + + public CoordinatorService(CoordinatorRunner runner) + => _runner = runner; + + public override Task Heartbeat(HeartbeatRequest request, ServerCallContext context) + { + var gracefulImminent = _runner.Heartbeat(request.ShardId, request.GuildCount, request.State); + return Task.FromResult(new HeartbeatReply() + { + GracefulImminent = gracefulImminent + }); + } + + public override Task Reshard(ReshardRequest request, ServerCallContext context) + { + _runner.SetShardCount(request.Shards); + return Task.FromResult(new ReshardReply()); + } + + public override Task RestartShard(RestartShardRequest request, ServerCallContext context) + { + _runner.RestartShard(request.ShardId, request.Queue); + return Task.FromResult(new RestartShardReply()); + } + + public override Task Reload(ReloadRequest request, ServerCallContext context) + { + _runner.ReloadConfig(); + return Task.FromResult(new ReloadReply()); + } + + public override Task GetStatus(GetStatusRequest request, ServerCallContext context) + { + var status = _runner.GetShardStatus(request.ShardId); + + + return Task.FromResult(StatusToStatusReply(status)); + } + + public override Task GetAllStatuses(GetAllStatusesRequest request, + ServerCallContext context) + { + var statuses = _runner + .GetAllStatuses(); + + var reply = new GetAllStatusesReply(); + foreach (var status in statuses) + reply.Statuses.Add(StatusToStatusReply(status)); + + return Task.FromResult(reply); + } + + private static GetStatusReply StatusToStatusReply(ShardStatus status) + { + DateTime startTime; + try + { + startTime = status.Process is null or { HasExited: true } + ? DateTime.MinValue.ToUniversalTime() + : status.Process.StartTime.ToUniversalTime(); + } + catch + { + startTime = DateTime.MinValue.ToUniversalTime(); + } + + var reply = new GetStatusReply() + { + State = status.State, + GuildCount = status.GuildCount, + ShardId = status.ShardId, + LastUpdate = Timestamp.FromDateTime(status.LastUpdate), + ScheduledForRestart = status.ShouldRestart, + StartedAt = Timestamp.FromDateTime(startTime) + }; + + return reply; + } + + public override Task RestartAllShards(RestartAllRequest request, ServerCallContext context) + { + _runner.RestartAll(request.Nuke); + return Task.FromResult(new RestartAllReply()); + } + + public override async Task Die(DieRequest request, ServerCallContext context) + { + if (request.Graceful) + { + _runner.PrepareGracefulShutdown(); + await Task.Delay(10_000); + } + + _runner.SaveState(); + _ = Task.Run(async () => + { + await Task.Delay(250); + Environment.Exit(0); + }); + + return new DieReply(); + } + + public override Task SetConfigText(SetConfigTextRequest request, ServerCallContext context) + { + var error = string.Empty; + var success = true; + try + { + _runner.SetConfigText(request.ConfigYml); + } + catch (Exception ex) + { + error = ex.Message; + success = false; + } + + return Task.FromResult(new(new() + { + Success = success, + Error = error + })); + } + + public override Task GetConfigText(GetConfigTextRequest request, ServerCallContext context) + { + var text = _runner.GetConfigText(); + return Task.FromResult(new GetConfigTextReply() + { + ConfigYml = text, + }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/Shared/Config.cs b/src/EllieBot.Coordinator/Shared/Config.cs new file mode 100644 index 0000000..af22c33 --- /dev/null +++ b/src/EllieBot.Coordinator/Shared/Config.cs @@ -0,0 +1,21 @@ +namespace EllieBot.Coordinator +{ + public readonly struct Config + { + public int TotalShards { get; init; } + public int RecheckIntervalMs { get; init; } + public string ShardStartCommand { get; init; } + public string ShardStartArgs { get; init; } + public double UnresponsiveSec { get; init; } + + public Config(int totalShards, int recheckIntervalMs, string shardStartCommand, string shardStartArgs, double unresponsiveSec) + { + TotalShards = totalShards; + RecheckIntervalMs = recheckIntervalMs; + ShardStartCommand = shardStartCommand; + ShardStartArgs = shardStartArgs; + UnresponsiveSec = unresponsiveSec; + } + + } +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/Shared/CoordState.cs b/src/EllieBot.Coordinator/Shared/CoordState.cs new file mode 100644 index 0000000..c9dfef8 --- /dev/null +++ b/src/EllieBot.Coordinator/Shared/CoordState.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace EllieBot.Coordinator +{ + public class CoordState + { + public List StatusObjects { get; init; } + } +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/Shared/JsonStatusObject.cs b/src/EllieBot.Coordinator/Shared/JsonStatusObject.cs new file mode 100644 index 0000000..5de659f --- /dev/null +++ b/src/EllieBot.Coordinator/Shared/JsonStatusObject.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Coordinator +{ + public class JsonStatusObject + { + public int? Pid { get; init; } + public int GuildCount { get; init; } + public ConnState ConnectionState { get; init; } + } +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/Shared/ShardStatus.cs b/src/EllieBot.Coordinator/Shared/ShardStatus.cs new file mode 100644 index 0000000..d2deb0b --- /dev/null +++ b/src/EllieBot.Coordinator/Shared/ShardStatus.cs @@ -0,0 +1,15 @@ +using System; +using System.Diagnostics; + +namespace EllieBot.Coordinator +{ + public sealed record ShardStatus( + int ShardId, + DateTime LastUpdate, + int GuildCount = 0, + ConnState State = ConnState.Disconnected, + bool ShouldRestart = false, + Process Process = null, + int StateCounter = 0 + ); +} \ No newline at end of file diff --git a/src/EllieBot.Coordinator/appsettings.Development.json b/src/EllieBot.Coordinator/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/src/EllieBot.Coordinator/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/EllieBot.Coordinator/appsettings.json b/src/EllieBot.Coordinator/appsettings.json new file mode 100644 index 0000000..7e5ece7 --- /dev/null +++ b/src/EllieBot.Coordinator/appsettings.json @@ -0,0 +1,20 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + }, + "Endpoints": { + "Http": { + "Url": "http://localhost:3442" + } + } + } +} diff --git a/src/EllieBot.Coordinator/coord.yml b/src/EllieBot.Coordinator/coord.yml new file mode 100644 index 0000000..02587a2 --- /dev/null +++ b/src/EllieBot.Coordinator/coord.yml @@ -0,0 +1,12 @@ +# total number of shards +TotalShards: 3 +# How often do shards ping their state back to the coordinator +RecheckIntervalMs: 5000 +# Command to run the shard +ShardStartCommand: dotnet +# Arguments to run the shard +# {0} = shard id +# {1} = total number of shards +ShardStartArgs: run -p "..\EllieBot\EllieBot.csproj" --no-build -- {0} {1} +# How long does it take for the shard to be forcefully restarted once it stops reporting its state +UnresponsiveSec: 30 From 3252829969b93bb77999adb4564a7c3b060d1e3b Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 14:54:27 +1300 Subject: [PATCH 02/62] Updated EllieBot.Generators --- EllieBot.sln | 7 + .../Cloneable/CloneableGenerator.cs | 254 +++++++++++++ .../Cloneable/SymbolExtensions.cs | 24 ++ .../Cloneable/SyntaxReceiver.cs | 27 ++ .../Command/CommandAttributesGenerator.cs | 336 ++++++++++++++++++ .../EllieBot.Generators.csproj | 25 ++ .../LocalizedStringsGenerator.cs | 144 ++++++++ src/EllieBot.Generators/README.md | 24 ++ 8 files changed, 841 insertions(+) create mode 100644 src/EllieBot.Generators/Cloneable/CloneableGenerator.cs create mode 100644 src/EllieBot.Generators/Cloneable/SymbolExtensions.cs create mode 100644 src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs create mode 100644 src/EllieBot.Generators/Command/CommandAttributesGenerator.cs create mode 100644 src/EllieBot.Generators/EllieBot.Generators.csproj create mode 100644 src/EllieBot.Generators/LocalizedStringsGenerator.cs create mode 100644 src/EllieBot.Generators/README.md diff --git a/EllieBot.sln b/EllieBot.sln index 4b578fa..c015691 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Tests", "src\Ellie EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Coordinator", "src\EllieBot.Coordinator\EllieBot.Coordinator.csproj", "{A631DDF0-3AD1-4CB9-8458-314B1320868A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Generators", "src\EllieBot.Generators\EllieBot.Generators.csproj", "{CB1A5307-DD85-4795-8A8A-A25D36DADC51}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Debug|Any CPU.Build.0 = Debug|Any CPU {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Release|Any CPU.ActiveCfg = Release|Any CPU {A631DDF0-3AD1-4CB9-8458-314B1320868A}.Release|Any CPU.Build.0 = Release|Any CPU + {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -55,6 +61,7 @@ Global {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067} = {872A4C63-833C-4AE0-91AB-3CE348D3E6F8} {179DF3B3-AD32-4335-8231-9818338DF3A2} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {A631DDF0-3AD1-4CB9-8458-314B1320868A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79F61C2C-CDBB-4361-A234-91A0B334CFE4} diff --git a/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs b/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs new file mode 100644 index 0000000..6bd7da4 --- /dev/null +++ b/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs @@ -0,0 +1,254 @@ +// Code temporarily yeeted from +// https://github.com/mostmand/Cloneable/blob/master/Cloneable/CloneableGenerator.cs +// because of NRT issue +#nullable enable +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Cloneable +{ + [Generator] + public class CloneableGenerator : ISourceGenerator + { + private const string PREVENT_DEEP_COPY_KEY_STRING = "PreventDeepCopy"; + private const string EXPLICIT_DECLARATION_KEY_STRING = "ExplicitDeclaration"; + + private const string CLONEABLE_NAMESPACE = "Cloneable"; + private const string CLONEABLE_ATTRIBUTE_STRING = "CloneableAttribute"; + private const string CLONE_ATTRIBUTE_STRING = "CloneAttribute"; + private const string IGNORE_CLONE_ATTRIBUTE_STRING = "IgnoreCloneAttribute"; + + private const string CLONEABLE_ATTRIBUTE_TEXT = @"// +using System; + +namespace " + CLONEABLE_NAMESPACE + @" +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)] + public sealed class " + CLONEABLE_ATTRIBUTE_STRING + @" : Attribute + { + public " + CLONEABLE_ATTRIBUTE_STRING + @"() + { + } + + public bool " + EXPLICIT_DECLARATION_KEY_STRING + @" { get; set; } + } +} +"; + + private const string CLONE_PROPERTY_ATTRIBUTE_TEXT = @"// +using System; + +namespace " + CLONEABLE_NAMESPACE + @" +{ + [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] + public sealed class " + CLONE_ATTRIBUTE_STRING + @" : Attribute + { + public " + CLONE_ATTRIBUTE_STRING + @"() + { + } + + public bool " + PREVENT_DEEP_COPY_KEY_STRING + @" { get; set; } + } +} +"; + + private const string IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT = @"// +using System; + +namespace " + CLONEABLE_NAMESPACE + @" +{ + [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] + public sealed class " + IGNORE_CLONE_ATTRIBUTE_STRING + @" : Attribute + { + public " + IGNORE_CLONE_ATTRIBUTE_STRING + @"() + { + } + } +} +"; + + private INamedTypeSymbol? _cloneableAttribute; + private INamedTypeSymbol? _ignoreCloneAttribute; + private INamedTypeSymbol? _cloneAttribute; + + public void Initialize(GeneratorInitializationContext context) + => context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); + + public void Execute(GeneratorExecutionContext context) + { + InjectCloneableAttributes(context); + GenerateCloneMethods(context); + } + + private void GenerateCloneMethods(GeneratorExecutionContext context) + { + if (context.SyntaxReceiver is not SyntaxReceiver receiver) + return; + + Compilation compilation = GetCompilation(context); + + InitAttributes(compilation); + + var classSymbols = GetClassSymbols(compilation, receiver); + foreach (var classSymbol in classSymbols) + { + if (!classSymbol.TryGetAttribute(_cloneableAttribute!, out var attributes)) + continue; + + var attribute = attributes.Single(); + var isExplicit = (bool?)attribute.NamedArguments.FirstOrDefault(e => e.Key.Equals(EXPLICIT_DECLARATION_KEY_STRING)).Value.Value ?? false; + context.AddSource($"{classSymbol.Name}_cloneable.g.cs", SourceText.From(CreateCloneableCode(classSymbol, isExplicit), Encoding.UTF8)); + } + } + + private void InitAttributes(Compilation compilation) + { + _cloneableAttribute = compilation.GetTypeByMetadataName($"{CLONEABLE_NAMESPACE}.{CLONEABLE_ATTRIBUTE_STRING}")!; + _cloneAttribute = compilation.GetTypeByMetadataName($"{CLONEABLE_NAMESPACE}.{CLONE_ATTRIBUTE_STRING}")!; + _ignoreCloneAttribute = compilation.GetTypeByMetadataName($"{CLONEABLE_NAMESPACE}.{IGNORE_CLONE_ATTRIBUTE_STRING}")!; + } + + private static Compilation GetCompilation(GeneratorExecutionContext context) + { + var options = context.Compilation.SyntaxTrees.First().Options as CSharpParseOptions; + + var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(CLONEABLE_ATTRIBUTE_TEXT, Encoding.UTF8), options)). + AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8), options)). + AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8), options)); + return compilation; + } + + private string CreateCloneableCode(INamedTypeSymbol classSymbol, bool isExplicit) + { + string namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); + var fieldAssignmentsCode = GenerateFieldAssignmentsCode(classSymbol, isExplicit).ToList(); + var fieldAssignmentsCodeSafe = fieldAssignmentsCode.Select(x => + { + if (x.isCloneable) + return x.line + "Safe(referenceChain)"; + return x.line; + }); + var fieldAssignmentsCodeFast = fieldAssignmentsCode.Select(x => + { + if (x.isCloneable) + return x.line + "()"; + return x.line; + }); + + return $@"using System.Collections.Generic; + +namespace {namespaceName} +{{ + {GetAccessModifier(classSymbol)} partial class {classSymbol.Name} + {{ + /// + /// Creates a copy of {classSymbol.Name} with NO circular reference checking. This method should be used if performance matters. + /// + /// Will occur on any object that has circular references in the hierarchy. + /// + public {classSymbol.Name} Clone() + {{ + return new {classSymbol.Name} + {{ +{string.Join(",\n", fieldAssignmentsCodeFast)} + }}; + }} + + /// + /// Creates a copy of {classSymbol.Name} with circular reference checking. If a circular reference was detected, only a reference of the leaf object is passed instead of cloning it. + /// + /// Should only be provided if specific objects should not be cloned but passed by reference instead. + public {classSymbol.Name} CloneSafe(Stack referenceChain = null) + {{ + if(referenceChain?.Contains(this) == true) + return this; + referenceChain ??= new Stack(); + referenceChain.Push(this); + var result = new {classSymbol.Name} + {{ +{string.Join($",\n", fieldAssignmentsCodeSafe)} + }}; + referenceChain.Pop(); + return result; + }} + }} +}}"; + } + + private IEnumerable<(string line, bool isCloneable)> GenerateFieldAssignmentsCode(INamedTypeSymbol classSymbol, bool isExplicit) + { + var fieldNames = GetCloneableProperties(classSymbol, isExplicit); + + var fieldAssignments = fieldNames.Select(field => IsFieldCloneable(field, classSymbol)) + .OrderBy(x => x.isCloneable) + .Select(x => (GenerateAssignmentCode(x.item.Name, x.isCloneable), x.isCloneable)); + return fieldAssignments; + } + + private string GenerateAssignmentCode(string name, bool isCloneable) + { + if (isCloneable) + { + return $@" {name} = this.{name}?.Clone"; + } + + return $@" {name} = this.{name}"; + } + + private (IPropertySymbol item, bool isCloneable) IsFieldCloneable(IPropertySymbol x, INamedTypeSymbol classSymbol) + { + if (SymbolEqualityComparer.Default.Equals(x.Type, classSymbol)) + { + return (x, false); + } + + if (!x.Type.TryGetAttribute(_cloneableAttribute!, out var attributes)) + { + return (x, false); + } + + var preventDeepCopy = (bool?)attributes.Single().NamedArguments.FirstOrDefault(e => e.Key.Equals(PREVENT_DEEP_COPY_KEY_STRING)).Value.Value ?? false; + return (item: x, !preventDeepCopy); + } + + private string GetAccessModifier(INamedTypeSymbol classSymbol) + => classSymbol.DeclaredAccessibility.ToString().ToLowerInvariant(); + + private IEnumerable GetCloneableProperties(ITypeSymbol classSymbol, bool isExplicit) + { + var targetSymbolMembers = classSymbol.GetMembers().OfType() + .Where(x => x.SetMethod is not null && + x.CanBeReferencedByName); + if (isExplicit) + { + return targetSymbolMembers.Where(x => x.HasAttribute(_cloneAttribute!)); + } + else + { + return targetSymbolMembers.Where(x => !x.HasAttribute(_ignoreCloneAttribute!)); + } + } + + private static IEnumerable GetClassSymbols(Compilation compilation, SyntaxReceiver receiver) + => receiver.CandidateClasses.Select(clazz => GetClassSymbol(compilation, clazz)); + + private static INamedTypeSymbol GetClassSymbol(Compilation compilation, ClassDeclarationSyntax clazz) + { + var model = compilation.GetSemanticModel(clazz.SyntaxTree); + var classSymbol = model.GetDeclaredSymbol(clazz)!; + return classSymbol; + } + + private static void InjectCloneableAttributes(GeneratorExecutionContext context) + { + context.AddSource(CLONEABLE_ATTRIBUTE_STRING, SourceText.From(CLONEABLE_ATTRIBUTE_TEXT, Encoding.UTF8)); + context.AddSource(CLONE_ATTRIBUTE_STRING, SourceText.From(CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8)); + context.AddSource(IGNORE_CLONE_ATTRIBUTE_STRING, SourceText.From(IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8)); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs b/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs new file mode 100644 index 0000000..6c0c605 --- /dev/null +++ b/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs @@ -0,0 +1,24 @@ +// Code temporarily yeeted from +// https://github.com/mostmand/Cloneable/blob/master/Cloneable/CloneableGenerator.cs +// because of NRT issue +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace Cloneable +{ + internal static class SymbolExtensions + { + public static bool TryGetAttribute(this ISymbol symbol, INamedTypeSymbol attributeType, + out IEnumerable attributes) + { + attributes = symbol.GetAttributes() + .Where(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType)); + return attributes.Any(); + } + + public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType) + => symbol.GetAttributes() + .Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType)); + } +} \ No newline at end of file diff --git a/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs b/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs new file mode 100644 index 0000000..962c395 --- /dev/null +++ b/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs @@ -0,0 +1,27 @@ +// Code temporarily yeeted from +// https://github.com/mostmand/Cloneable/blob/master/Cloneable/CloneableGenerator.cs +// because of NRT issue +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Cloneable +{ + internal class SyntaxReceiver : ISyntaxReceiver + { + public IList CandidateClasses { get; } = new List(); + + /// + /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation + /// + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + // any field with at least one attribute is a candidate for being cloneable + if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax && + classDeclarationSyntax.AttributeLists.Count > 0) + { + CandidateClasses.Add(classDeclarationSyntax); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Generators/Command/CommandAttributesGenerator.cs b/src/EllieBot.Generators/Command/CommandAttributesGenerator.cs new file mode 100644 index 0000000..81a758c --- /dev/null +++ b/src/EllieBot.Generators/Command/CommandAttributesGenerator.cs @@ -0,0 +1,336 @@ +// #nullable enable +// using System; +// using System.CodeDom.Compiler; +// using System.Collections.Generic; +// using System.Collections.Immutable; +// using System.Collections.ObjectModel; +// using System.Diagnostics; +// using System.IO; +// using System.Linq; +// using System.Text; +// using System.Threading; +// using Microsoft.CodeAnalysis; +// using Microsoft.CodeAnalysis.CSharp; +// using Microsoft.CodeAnalysis.CSharp.Syntax; +// using Microsoft.CodeAnalysis.Text; +// +// namespace EllieBot.Generators.Command; +// +// [Generator] +// public class CommandAttributesGenerator : IIncrementalGenerator +// { +// public const string ATTRIBUTE = @"// +// +// namespace EllieBot.Common; +// +// [System.AttributeUsage(System.AttributeTargets.Method)] +// public class CmdAttribute : System.Attribute +// { +// +// }"; +// +// public class MethodModel +// { +// public string? Namespace { get; } +// public IReadOnlyCollection Classes { get; } +// public string ReturnType { get; } +// public string MethodName { get; } +// public IEnumerable Params { get; } +// +// public MethodModel(string? ns, IReadOnlyCollection classes, string returnType, string methodName, IEnumerable @params) +// { +// Namespace = ns; +// Classes = classes; +// ReturnType = returnType; +// MethodName = methodName; +// Params = @params; +// } +// } +// +// public class FileModel +// { +// public string? Namespace { get; } +// public IReadOnlyCollection ClassHierarchy { get; } +// public IReadOnlyCollection Methods { get; } +// +// public FileModel(string? ns, IReadOnlyCollection classHierarchy, IReadOnlyCollection methods) +// { +// Namespace = ns; +// ClassHierarchy = classHierarchy; +// Methods = methods; +// } +// } +// +// public void Initialize(IncrementalGeneratorInitializationContext context) +// { +// // #if DEBUG +// // if (!Debugger.IsAttached) +// // Debugger.Launch(); +// // // SpinWait.SpinUntil(() => Debugger.IsAttached); +// // #endif +// context.RegisterPostInitializationOutput(static ctx => ctx.AddSource( +// "CmdAttribute.g.cs", +// SourceText.From(ATTRIBUTE, Encoding.UTF8))); +// +// var methods = context.SyntaxProvider +// .CreateSyntaxProvider( +// static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 }, +// static (ctx, cancel) => Transform(ctx, cancel)) +// .Where(static m => m is not null) +// .Where(static m => m?.ChildTokens().Any(static x => x.IsKind(SyntaxKind.PublicKeyword)) ?? false); +// +// var compilationMethods = context.CompilationProvider.Combine(methods.Collect()); +// +// context.RegisterSourceOutput(compilationMethods, +// static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right)); +// } +// +// private static void RegisterAction(in SourceProductionContext ctx, +// Compilation comp, +// in ImmutableArray methods) +// { +// if (methods is { IsDefaultOrEmpty: true }) +// return; +// +// var models = GetModels(comp, methods, ctx.CancellationToken); +// +// foreach (var model in models) +// { +// var name = $"{model.Namespace}.{string.Join(".", model.ClassHierarchy)}.g.cs"; +// try +// { +// var source = GetSourceText(model); +// ctx.AddSource(name, SourceText.From(source, Encoding.UTF8)); +// } +// catch (Exception ex) +// { +// Console.WriteLine($"Error writing source file {name}\n" + ex); +// } +// } +// } +// +// private static string GetSourceText(FileModel model) +// { +// using var sw = new StringWriter(); +// using var tw = new IndentedTextWriter(sw); +// +// tw.WriteLine("// "); +// tw.WriteLine("#pragma warning disable CS1066"); +// +// if (model.Namespace is not null) +// { +// tw.WriteLine($"namespace {model.Namespace};"); +// tw.WriteLine(); +// } +// +// foreach (var className in model.ClassHierarchy) +// { +// tw.WriteLine($"public partial class {className}"); +// tw.WriteLine("{"); +// tw.Indent ++; +// } +// +// foreach (var method in model.Methods) +// { +// tw.WriteLine("[EllieCommand]"); +// tw.WriteLine("[EllieDescription]"); +// tw.WriteLine("[Aliases]"); +// tw.WriteLine($"public partial {method.ReturnType} {method.MethodName}({string.Join(", ", method.Params)});"); +// } +// +// foreach (var _ in model.ClassHierarchy) +// { +// tw.Indent --; +// tw.WriteLine("}"); +// } +// +// tw.Flush(); +// return sw.ToString(); +// } +// +// private static IReadOnlyCollection GetModels(Compilation compilation, +// in ImmutableArray inputMethods, +// CancellationToken cancel) +// { +// var models = new List(); +// +// var methods = inputMethods +// .Where(static x => x is not null) +// .Distinct(); +// +// var methodModels = methods +// .Select(x => MethodDeclarationToMethodModel(compilation, x!)) +// .Where(static x => x is not null) +// .Cast(); +// +// var groups = methodModels +// .GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}"); +// +// foreach (var group in groups) +// { +// if (cancel.IsCancellationRequested) +// return new Collection(); +// +// if (group is null) +// continue; +// +// var elems = group.ToList(); +// if (elems.Count is 0) +// continue; +// +// var model = new FileModel( +// methods: elems, +// ns: elems[0].Namespace, +// classHierarchy: elems![0].Classes +// ); +// +// models.Add(model); +// } +// +// +// return models; +// } +// +// private static MethodModel? MethodDeclarationToMethodModel(Compilation comp, MethodDeclarationSyntax decl) +// { +// // SpinWait.SpinUntil(static () => Debugger.IsAttached); +// +// SemanticModel semanticModel; +// try +// { +// semanticModel = comp.GetSemanticModel(decl.SyntaxTree); +// } +// catch +// { +// // for some reason this method can throw "Not part of this compilation" argument exception +// return null; +// } +// +// var methodModel = new MethodModel( +// @params: decl.ParameterList.Parameters +// .Where(p => p.Type is not null) +// .Select(p => +// { +// var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword)) +// ? "params " +// : string.Empty; +// +// var type = semanticModel +// .GetTypeInfo(p.Type!) +// .Type +// ?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); +// +// +// var name = p.Identifier.Text; +// +// var suffix = string.Empty; +// if (p.Default is not null) +// { +// if (p.Default.Value is LiteralExpressionSyntax) +// { +// suffix = " = " + p.Default.Value; +// } +// else if (p.Default.Value is MemberAccessExpressionSyntax maes) +// { +// var maesSemModel = comp.GetSemanticModel(maes.SyntaxTree); +// var sym = maesSemModel.GetSymbolInfo(maes.Name); +// if (sym.Symbol is null) +// { +// suffix = " = " + p.Default.Value; +// } +// else +// { +// suffix = " = " + sym.Symbol.ToDisplayString(); +// } +// } +// } +// +// return $"{prefix}{type} {name}{suffix}"; +// }) +// .ToList(), +// methodName: decl.Identifier.Text, +// returnType: decl.ReturnType.ToString(), +// ns: GetNamespace(decl), +// classes: GetClasses(decl) +// ); +// +// return methodModel; +// } +// +// //https://github.com/andrewlock/NetEscapades.EnumGenerators/blob/main/src/NetEscapades.EnumGenerators/EnumGenerator.cs +// static string? GetNamespace(MethodDeclarationSyntax declarationSyntax) +// { +// // determine the namespace the class is declared in, if any +// string? nameSpace = null; +// var parentOfInterest = declarationSyntax.Parent; +// while (parentOfInterest is not null) +// { +// parentOfInterest = parentOfInterest.Parent; +// +// if (parentOfInterest is BaseNamespaceDeclarationSyntax ns) +// { +// nameSpace = ns.Name.ToString(); +// while (true) +// { +// if (ns.Parent is not NamespaceDeclarationSyntax parent) +// { +// break; +// } +// +// ns = parent; +// nameSpace = $"{ns.Name}.{nameSpace}"; +// } +// +// return nameSpace; +// } +// +// } +// +// return nameSpace; +// } +// +// static IReadOnlyCollection GetClasses(MethodDeclarationSyntax declarationSyntax) +// { +// // determine the namespace the class is declared in, if any +// var classes = new LinkedList(); +// var parentOfInterest = declarationSyntax.Parent; +// while (parentOfInterest is not null) +// { +// if (parentOfInterest is ClassDeclarationSyntax cds) +// { +// classes.AddFirst(cds.Identifier.ToString()); +// } +// +// parentOfInterest = parentOfInterest.Parent; +// } +// +// Debug.WriteLine($"Method {declarationSyntax.Identifier.Text} has {classes.Count} classes"); +// +// return classes; +// } +// +// private static MethodDeclarationSyntax? Transform(GeneratorSyntaxContext ctx, CancellationToken cancel) +// { +// var methodDecl = ctx.Node as MethodDeclarationSyntax; +// if (methodDecl is null) +// return default; +// +// foreach (var attListSyntax in methodDecl.AttributeLists) +// { +// foreach (var attSyntax in attListSyntax.Attributes) +// { +// if (cancel.IsCancellationRequested) +// return default; +// +// var symbol = ctx.SemanticModel.GetSymbolInfo(attSyntax).Symbol; +// if (symbol is not IMethodSymbol attSymbol) +// continue; +// +// if (attSymbol.ContainingType.ToDisplayString() == "EllieBot.Common.CmdAttribute") +// return methodDecl; +// } +// } +// +// return default; +// } +// } \ No newline at end of file diff --git a/src/EllieBot.Generators/EllieBot.Generators.csproj b/src/EllieBot.Generators/EllieBot.Generators.csproj new file mode 100644 index 0000000..742b2ea --- /dev/null +++ b/src/EllieBot.Generators/EllieBot.Generators.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + latest + false + true + + + + + + + + + + $(GetTargetPathDependsOn);GetDependencyTargetPaths + + + + + + + + diff --git a/src/EllieBot.Generators/LocalizedStringsGenerator.cs b/src/EllieBot.Generators/LocalizedStringsGenerator.cs new file mode 100644 index 0000000..95abda9 --- /dev/null +++ b/src/EllieBot.Generators/LocalizedStringsGenerator.cs @@ -0,0 +1,144 @@ +#nullable enable +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.CodeAnalysis; +using Newtonsoft.Json; + +namespace EllieBot.Generators +{ + internal readonly struct TranslationPair + { + public string Name { get; } + public string Value { get; } + + public TranslationPair(string name, string value) + { + Name = name; + Value = value; + } + } + + [Generator] + public class LocalizedStringsGenerator : ISourceGenerator + { + private const string LOC_STR_SOURCE = @"namespace EllieBot +{ + public readonly struct LocStr + { + public readonly string Key; + public readonly object[] Params; + + public LocStr(string key, params object[] data) + { + Key = key; + Params = data; + } + } +}"; + + public void Initialize(GeneratorInitializationContext context) + { + + } + + public void Execute(GeneratorExecutionContext context) + { + var file = context.AdditionalFiles.First(x => x.Path.EndsWith("responses.en-US.json")); + + var fields = GetFields(file.GetText()?.ToString()); + + using (var stringWriter = new StringWriter()) + using (var sw = new IndentedTextWriter(stringWriter)) + { + sw.WriteLine("namespace EllieBot;"); + sw.WriteLine(); + + sw.WriteLine("public static class strs"); + sw.WriteLine("{"); + sw.Indent++; + + var typedParamStrings = new List(10); + foreach (var field in fields) + { + var matches = Regex.Matches(field.Value, @"{(?\d)[}:]"); + var max = 0; + foreach (Match match in matches) + { + max = Math.Max(max, int.Parse(match.Groups["num"].Value) + 1); + } + + typedParamStrings.Clear(); + var typeParams = new string[max]; + var passedParamString = string.Empty; + for (var i = 0; i < max; i++) + { + typedParamStrings.Add($"in T{i} p{i}"); + passedParamString += $", p{i}"; + typeParams[i] = $"T{i}"; + } + + var sig = string.Empty; + var typeParamStr = string.Empty; + if (max > 0) + { + sig = $"({string.Join(", ", typedParamStrings)})"; + typeParamStr = $"<{string.Join(", ", typeParams)}>"; + } + + sw.WriteLine("public static LocStr {0}{1}{2} => new LocStr(\"{3}\"{4});", + field.Name, + typeParamStr, + sig, + field.Name, + passedParamString); + } + + sw.Indent--; + sw.WriteLine("}"); + + + sw.Flush(); + context.AddSource("strs.g.cs", stringWriter.ToString()); + } + + context.AddSource("LocStr.g.cs", LOC_STR_SOURCE); + } + + private List GetFields(string? dataText) + { + if (string.IsNullOrWhiteSpace(dataText)) + return new(); + + Dictionary data; + try + { + var output = JsonConvert.DeserializeObject>(dataText!); + if (output is null) + return new(); + + data = output; + } + catch + { + Debug.WriteLine("Failed parsing responses file."); + return new(); + } + + var list = new List(); + foreach (var entry in data) + { + list.Add(new( + entry.Key, + entry.Value + )); + } + + return list; + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Generators/README.md b/src/EllieBot.Generators/README.md new file mode 100644 index 0000000..cfe1ea4 --- /dev/null +++ b/src/EllieBot.Generators/README.md @@ -0,0 +1,24 @@ +## Generators + +Project which contains source generators required for EllieBot project + +--- +### 1) Localized Strings Generator + + -- Why -- + Type safe response strings access, and enforces correct usage of response strings. + + -- How it works -- + Creates a file "strs.cs" containing a class called "strs" in "EllieBot" namespace. + + Loads "data/strings/responses.en-US.json" and creates a property or a function for each key in the responses json file based on whether the value has string format placeholders or not. + + - If a value has no placeholders, it creates a property in the strs class which returns an instance of a LocStr struct containing only the key and no replacement parameters + + - If a value has placeholders, it creates a function with the same number of arguments as the number of placeholders, and passes those arguments to the LocStr instance + + -- How to use -- + 1. Add a new key to responses.en-US.json "greet_me": "Hello, {0}" + 2. You now have access to a function strs.greet_me(obj p1) + 3. Using "GetText(strs.greet_me("Me"))" will return "Hello, Me" + From fb808dfc1d064291b4ead70d7b03ba03e69269e1 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 16:42:10 +1300 Subject: [PATCH 03/62] Updated EllieBot.VotesApi --- EllieBot.sln | 7 ++ src/EllieBot.VotesApi/.dockerignore | 25 +++++ src/EllieBot.VotesApi/.gitignore | 1 + src/EllieBot.VotesApi/Common/AuthHandler.cs | 41 +++++++ src/EllieBot.VotesApi/Common/ConfKeys.cs | 8 ++ .../Common/DiscordsVoteWebhookModel.cs | 26 +++++ src/EllieBot.VotesApi/Common/Policies.cs | 8 ++ .../Common/TopggVoteWebhookModel.cs | 30 ++++++ .../Controllers/DiscordsController.cs | 33 ++++++ .../Controllers/TopGgController.cs | 34 ++++++ .../Controllers/WebhookController.cs | 48 +++++++++ src/EllieBot.VotesApi/Dockerfile | 20 ++++ .../EllieBot.VotesApi.csproj | 13 +++ src/EllieBot.VotesApi/Program.cs | 9 ++ .../Properties/launchSettings.json | 31 ++++++ src/EllieBot.VotesApi/README.md | 46 ++++++++ .../Services/FileVotesCache.cs | 100 ++++++++++++++++++ src/EllieBot.VotesApi/Services/IVotesCache.cs | 13 +++ src/EllieBot.VotesApi/Startup.cs | 68 ++++++++++++ src/EllieBot.VotesApi/WeatherForecast.cs | 7 ++ .../appsettings.Development.json | 9 ++ src/EllieBot.VotesApi/appsettings.json | 12 +++ 22 files changed, 589 insertions(+) create mode 100644 src/EllieBot.VotesApi/.dockerignore create mode 100644 src/EllieBot.VotesApi/.gitignore create mode 100644 src/EllieBot.VotesApi/Common/AuthHandler.cs create mode 100644 src/EllieBot.VotesApi/Common/ConfKeys.cs create mode 100644 src/EllieBot.VotesApi/Common/DiscordsVoteWebhookModel.cs create mode 100644 src/EllieBot.VotesApi/Common/Policies.cs create mode 100644 src/EllieBot.VotesApi/Common/TopggVoteWebhookModel.cs create mode 100644 src/EllieBot.VotesApi/Controllers/DiscordsController.cs create mode 100644 src/EllieBot.VotesApi/Controllers/TopGgController.cs create mode 100644 src/EllieBot.VotesApi/Controllers/WebhookController.cs create mode 100644 src/EllieBot.VotesApi/Dockerfile create mode 100644 src/EllieBot.VotesApi/EllieBot.VotesApi.csproj create mode 100644 src/EllieBot.VotesApi/Program.cs create mode 100644 src/EllieBot.VotesApi/Properties/launchSettings.json create mode 100644 src/EllieBot.VotesApi/README.md create mode 100644 src/EllieBot.VotesApi/Services/FileVotesCache.cs create mode 100644 src/EllieBot.VotesApi/Services/IVotesCache.cs create mode 100644 src/EllieBot.VotesApi/Startup.cs create mode 100644 src/EllieBot.VotesApi/WeatherForecast.cs create mode 100644 src/EllieBot.VotesApi/appsettings.Development.json create mode 100644 src/EllieBot.VotesApi/appsettings.json diff --git a/EllieBot.sln b/EllieBot.sln index c015691..b112a25 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Coordinator", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Generators", "src\EllieBot.Generators\EllieBot.Generators.csproj", "{CB1A5307-DD85-4795-8A8A-A25D36DADC51}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.VotesApi", "src\EllieBot.VotesApi\EllieBot.VotesApi.csproj", "{F1A77F56-71B0-430E-AE46-94CDD7D43874}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB1A5307-DD85-4795-8A8A-A25D36DADC51}.Release|Any CPU.Build.0 = Release|Any CPU + {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -62,6 +68,7 @@ Global {179DF3B3-AD32-4335-8231-9818338DF3A2} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {A631DDF0-3AD1-4CB9-8458-314B1320868A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {F1A77F56-71B0-430E-AE46-94CDD7D43874} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79F61C2C-CDBB-4361-A234-91A0B334CFE4} diff --git a/src/EllieBot.VotesApi/.dockerignore b/src/EllieBot.VotesApi/.dockerignore new file mode 100644 index 0000000..4c2af91 --- /dev/null +++ b/src/EllieBot.VotesApi/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/src/EllieBot.VotesApi/.gitignore b/src/EllieBot.VotesApi/.gitignore new file mode 100644 index 0000000..9ae80d3 --- /dev/null +++ b/src/EllieBot.VotesApi/.gitignore @@ -0,0 +1 @@ +store/ \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Common/AuthHandler.cs b/src/EllieBot.VotesApi/Common/AuthHandler.cs new file mode 100644 index 0000000..9294153 --- /dev/null +++ b/src/EllieBot.VotesApi/Common/AuthHandler.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace EllieBot.VotesApi +{ + public class AuthHandler : AuthenticationHandler + { + public const string SchemeName = "AUTHORIZATION_SCHEME"; + public const string DiscordsClaim = "DISCORDS_CLAIM"; + public const string TopggClaim = "TOPGG_CLAIM"; + + private readonly IConfiguration _conf; + + public AuthHandler(IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock, + IConfiguration conf) + : base(options, logger, encoder, clock) + => _conf = conf; + + protected override Task HandleAuthenticateAsync() + { + var claims = new List(); + + if (_conf[ConfKeys.DISCORDS_KEY].Trim() == Request.Headers["Authorization"].ToString().Trim()) + claims.Add(new(DiscordsClaim, "true")); + + if (_conf[ConfKeys.TOPGG_KEY] == Request.Headers["Authorization"].ToString().Trim()) + claims.Add(new Claim(TopggClaim, "true")); + + return Task.FromResult(AuthenticateResult.Success(new(new(new ClaimsIdentity(claims)), SchemeName))); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Common/ConfKeys.cs b/src/EllieBot.VotesApi/Common/ConfKeys.cs new file mode 100644 index 0000000..dd7de64 --- /dev/null +++ b/src/EllieBot.VotesApi/Common/ConfKeys.cs @@ -0,0 +1,8 @@ +namespace EllieBot.VotesApi +{ + public static class ConfKeys + { + public const string DISCORDS_KEY = "DiscordsKey"; + public const string TOPGG_KEY = "TopGGKey"; + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Common/DiscordsVoteWebhookModel.cs b/src/EllieBot.VotesApi/Common/DiscordsVoteWebhookModel.cs new file mode 100644 index 0000000..09522b7 --- /dev/null +++ b/src/EllieBot.VotesApi/Common/DiscordsVoteWebhookModel.cs @@ -0,0 +1,26 @@ +namespace EllieBot.VotesApi +{ + public class DiscordsVoteWebhookModel + { + /// + /// The ID of the user who voted + /// + public string User { get; set; } + + /// + /// The ID of the bot which recieved the vote + /// + public string Bot { get; set; } + + /// + /// Contains totalVotes, votesMonth, votes24, hasVoted - a list of IDs of users who have voted this month, and + /// Voted24 - a list of IDs of users who have voted today + /// + public string Votes { get; set; } + + /// + /// The type of event, whether it is a vote event or test event + /// + public string Type { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Common/Policies.cs b/src/EllieBot.VotesApi/Common/Policies.cs new file mode 100644 index 0000000..d4c59d0 --- /dev/null +++ b/src/EllieBot.VotesApi/Common/Policies.cs @@ -0,0 +1,8 @@ +namespace EllieBot.VotesApi +{ + public static class Policies + { + public const string DiscordsAuth = "DiscordsAuth"; + public const string TopggAuth = "TopggAuth"; + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Common/TopggVoteWebhookModel.cs b/src/EllieBot.VotesApi/Common/TopggVoteWebhookModel.cs new file mode 100644 index 0000000..bdfd8a9 --- /dev/null +++ b/src/EllieBot.VotesApi/Common/TopggVoteWebhookModel.cs @@ -0,0 +1,30 @@ +namespace EllieBot.VotesApi +{ + public class TopggVoteWebhookModel + { + /// + /// Discord ID of the bot that received a vote. + /// + public string Bot { get; set; } + + /// + /// Discord ID of the user who voted. + /// + public string User { get; set; } + + /// + /// The type of the vote (should always be "upvote" except when using the test button it's "test"). + /// + public string Type { get; set; } + + /// + /// Whether the weekend multiplier is in effect, meaning users votes count as two. + /// + public bool Weekend { get; set; } + + /// + /// Query string params found on the /bot/:ID/vote page. Example: ?a=1&b=2. + /// + public string Query { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Controllers/DiscordsController.cs b/src/EllieBot.VotesApi/Controllers/DiscordsController.cs new file mode 100644 index 0000000..183db84 --- /dev/null +++ b/src/EllieBot.VotesApi/Controllers/DiscordsController.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using EllieBot.VotesApi.Services; + +namespace EllieBot.VotesApi.Controllers +{ + [ApiController] + [Route("[controller]")] + public class DiscordsController : ControllerBase + { + private readonly ILogger _logger; + private readonly IVotesCache _cache; + + public DiscordsController(ILogger logger, IVotesCache cache) + { + _logger = logger; + _cache = cache; + } + + [HttpGet("new")] + [Authorize(Policy = Policies.DiscordsAuth)] + public async Task> New() + { + var votes = await _cache.GetNewDiscordsVotesAsync(); + if (votes.Count > 0) + _logger.LogInformation("Sending {NewDiscordsVotes} new discords votes", votes.Count); + return votes; + } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Controllers/TopGgController.cs b/src/EllieBot.VotesApi/Controllers/TopGgController.cs new file mode 100644 index 0000000..28fb5a7 --- /dev/null +++ b/src/EllieBot.VotesApi/Controllers/TopGgController.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using EllieBot.VotesApi.Services; + +namespace EllieBot.VotesApi.Controllers +{ + [ApiController] + [Route("[controller]")] + public class TopGgController : ControllerBase + { + private readonly ILogger _logger; + private readonly IVotesCache _cache; + + public TopGgController(ILogger logger, IVotesCache cache) + { + _logger = logger; + _cache = cache; + } + + [HttpGet("new")] + [Authorize(Policy = Policies.TopggAuth)] + public async Task> New() + { + var votes = await _cache.GetNewTopGgVotesAsync(); + if (votes.Count > 0) + _logger.LogInformation("Sending {NewTopggVotes} new topgg votes", votes.Count); + + return votes; + } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Controllers/WebhookController.cs b/src/EllieBot.VotesApi/Controllers/WebhookController.cs new file mode 100644 index 0000000..51dcfd6 --- /dev/null +++ b/src/EllieBot.VotesApi/Controllers/WebhookController.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using EllieBot.VotesApi.Services; + +namespace EllieBot.VotesApi.Controllers +{ + [ApiController] + public class WebhookController : ControllerBase + { + private readonly ILogger _logger; + private readonly IVotesCache _votesCache; + + public WebhookController(ILogger logger, IVotesCache votesCache) + { + _logger = logger; + _votesCache = votesCache; + } + + [HttpPost("/discordswebhook")] + [Authorize(Policy = Policies.DiscordsAuth)] + public async Task DiscordsWebhook([FromBody] DiscordsVoteWebhookModel data) + { + + _logger.LogInformation("User {UserId} has voted for Bot {BotId} on {Platform}", + data.User, + data.Bot, + "discords.com"); + + await _votesCache.AddNewDiscordsVote(data.User); + return Ok(); + } + + [HttpPost("/topggwebhook")] + [Authorize(Policy = Policies.TopggAuth)] + public async Task TopggWebhook([FromBody] TopggVoteWebhookModel data) + { + _logger.LogInformation("User {UserId} has voted for Bot {BotId} on {Platform}", + data.User, + data.Bot, + "top.gg"); + + await _votesCache.AddNewTopggVote(data.User); + return Ok(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Dockerfile b/src/EllieBot.VotesApi/Dockerfile new file mode 100644 index 0000000..4597cb2 --- /dev/null +++ b/src/EllieBot.VotesApi/Dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build +WORKDIR /src +COPY ["src/EllieBot.VotesApi/EllieBot.VotesApi.csproj", "EllieBot.VotesApi/"] +RUN dotnet restore "src/EllieBot.VotesApi/EllieBot.VotesApi.csproj" +COPY . . +WORKDIR "/src/EllieBot.VotesApi" +RUN dotnet build "EllieBot.VotesApi.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "EllieBot.VotesApi.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "EllieBot.VotesApi.dll"] diff --git a/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj b/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj new file mode 100644 index 0000000..f42db3d --- /dev/null +++ b/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + Linux + + + + + + + + diff --git a/src/EllieBot.VotesApi/Program.cs b/src/EllieBot.VotesApi/Program.cs new file mode 100644 index 0000000..20b7d0a --- /dev/null +++ b/src/EllieBot.VotesApi/Program.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using EllieBot.VotesApi; + +CreateHostBuilder(args).Build().Run(); + +static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Properties/launchSettings.json b/src/EllieBot.VotesApi/Properties/launchSettings.json new file mode 100644 index 0000000..5112c07 --- /dev/null +++ b/src/EllieBot.VotesApi/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:16451", + "sslPort": 44323 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "EllieBot.VotesApi": { + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/EllieBot.VotesApi/README.md b/src/EllieBot.VotesApi/README.md new file mode 100644 index 0000000..4c22299 --- /dev/null +++ b/src/EllieBot.VotesApi/README.md @@ -0,0 +1,46 @@ +## Votes Api + +This api is used if you want your bot to be able to reward users who vote for it on discords.com or top.gg + +#### [GET] `/discords/new` + Get the discords votes received after previous call to this endpoint. + Input full url of this endpoint in your creds.yml file under Discords url field. + For example "https://api.my.cool.bot/discords/new" +#### [GET] `/topgg/new` + Get the topgg votes received after previous call to this endpoint. + Input full url of this endpoint in your creds.yml file under Topgg url field. + For example "https://api.my.cool.bot/topgg/new" + +#### [POST] `/discordswebhook` + Input this endpoint as the webhook on discords.com bot edit page + model: https://docs.botsfordiscord.com/methods/receiving-votes + For example "https://api.my.cool.bot/topggwebhook" +#### [POST] `/topggwebhook` + Input this endpoint as the webhook https://top.gg/bot/:your-bot-id/webhooks (replace :your-bot-id with your bot's id) + model: https://docs.top.gg/resources/webhooks/#schema + For example "https://api.my.cool.bot/discordswebhook" + +Input your super-secret header value in appsettings.json's DiscordsKey and TopGGKey fields +They must match your DiscordsKey and TopGG key respectively, as well as your secrets in the discords.com and top.gg webhook setup pages + +Full Example: + +⚠ Change TopggKey and DiscordsKey to a secure long string +⚠ You can use https://www.random.org/strings/?num=1&len=20&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new to generate it + +`creds.yml` +```yml +votes: + TopggServiceUrl: "https://api.my.cool.bot/topgg" + TopggKey: "my_topgg_key" + DiscordsServiceUrl: "https://api.my.cool.bot/discords" + DiscordsKey: "my_discords_key" +``` + +`appsettings.json` +```json +... + "DiscordsKey": "my_discords_key", + "TopGGKey": "my_topgg_key", +... +``` \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Services/FileVotesCache.cs b/src/EllieBot.VotesApi/Services/FileVotesCache.cs new file mode 100644 index 0000000..77b963a --- /dev/null +++ b/src/EllieBot.VotesApi/Services/FileVotesCache.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using MorseCode.ITask; + +namespace EllieBot.VotesApi.Services +{ + public class FileVotesCache : IVotesCache + { + // private const string STATS_FILE = "store/stats.json"; + private const string TOPGG_FILE = "store/topgg.json"; + private const string DISCORDS_FILE = "store/discords.json"; + + private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1); + + public FileVotesCache() + { + if (!Directory.Exists("store")) + Directory.CreateDirectory("store"); + + if (!File.Exists(TOPGG_FILE)) + File.WriteAllText(TOPGG_FILE, "[]"); + + if (!File.Exists(DISCORDS_FILE)) + File.WriteAllText(DISCORDS_FILE, "[]"); + } + + public ITask AddNewTopggVote(string userId) + => AddNewVote(TOPGG_FILE, userId); + + public ITask AddNewDiscordsVote(string userId) + => AddNewVote(DISCORDS_FILE, userId); + + private async ITask AddNewVote(string file, string userId) + { + await _locker.WaitAsync(); + try + { + var votes = await GetVotesAsync(file); + votes.Add(userId); + await File.WriteAllTextAsync(file, JsonSerializer.Serialize(votes)); + } + finally + { + _locker.Release(); + } + } + + public async ITask> GetNewTopGgVotesAsync() + { + var votes = await EvictTopggVotes(); + return votes; + } + + public async ITask> GetNewDiscordsVotesAsync() + { + var votes = await EvictDiscordsVotes(); + return votes; + } + + private ITask> EvictTopggVotes() + => EvictVotes(TOPGG_FILE); + + private ITask> EvictDiscordsVotes() + => EvictVotes(DISCORDS_FILE); + + private async ITask> EvictVotes(string file) + { + await _locker.WaitAsync(); + try + { + + var ids = await GetVotesAsync(file); + await File.WriteAllTextAsync(file, "[]"); + + return ids? + .Select(x => (Ok: ulong.TryParse(x, out var r), Id: r)) + .Where(x => x.Ok) + .Select(x => new Vote + { + UserId = x.Id + }) + .ToList(); + } + finally + { + _locker.Release(); + } + } + + private async ITask> GetVotesAsync(string file) + { + await using var fs = File.Open(file, FileMode.Open); + var votes = await JsonSerializer.DeserializeAsync>(fs); + return votes; + } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Services/IVotesCache.cs b/src/EllieBot.VotesApi/Services/IVotesCache.cs new file mode 100644 index 0000000..0bc25de --- /dev/null +++ b/src/EllieBot.VotesApi/Services/IVotesCache.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using MorseCode.ITask; + +namespace EllieBot.VotesApi.Services +{ + public interface IVotesCache + { + ITask> GetNewTopGgVotesAsync(); + ITask> GetNewDiscordsVotesAsync(); + ITask AddNewTopggVote(string userId); + ITask AddNewDiscordsVote(string userId); + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/Startup.cs b/src/EllieBot.VotesApi/Startup.cs new file mode 100644 index 0000000..c1d850f --- /dev/null +++ b/src/EllieBot.VotesApi/Startup.cs @@ -0,0 +1,68 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi.Models; +using EllieBot.VotesApi.Services; + +namespace EllieBot.VotesApi +{ + public class Startup + { + public IConfiguration Configuration { get; } + + public Startup(IConfiguration configuration) + => Configuration = configuration; + + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + services.AddSingleton(); + services.AddSwaggerGen(static c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "EllieBot.VotesApi", Version = "v1" }); + }); + + services + .AddAuthentication(opts => + { + opts.DefaultScheme = AuthHandler.SchemeName; + opts.AddScheme(AuthHandler.SchemeName, AuthHandler.SchemeName); + }); + + services + .AddAuthorization(static opts => + { + opts.DefaultPolicy = new AuthorizationPolicyBuilder(AuthHandler.SchemeName) + .RequireAssertion(static _ => false) + .Build(); + opts.AddPolicy(Policies.DiscordsAuth, static policy => policy.RequireClaim(AuthHandler.DiscordsClaim)); + opts.AddPolicy(Policies.TopggAuth, static policy => policy.RequireClaim(AuthHandler.TopggClaim)); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(static c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "EllieBot.VotesApi v1")); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseEndpoints(static endpoints => { endpoints.MapControllers(); }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/WeatherForecast.cs b/src/EllieBot.VotesApi/WeatherForecast.cs new file mode 100644 index 0000000..a1e8f62 --- /dev/null +++ b/src/EllieBot.VotesApi/WeatherForecast.cs @@ -0,0 +1,7 @@ +namespace EllieBot.VotesApi +{ + public class Vote + { + public ulong UserId { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.VotesApi/appsettings.Development.json b/src/EllieBot.VotesApi/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/src/EllieBot.VotesApi/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/EllieBot.VotesApi/appsettings.json b/src/EllieBot.VotesApi/appsettings.json new file mode 100644 index 0000000..7b5f330 --- /dev/null +++ b/src/EllieBot.VotesApi/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "DiscordsKey": "my_discords_key", + "TopGGKey": "my_topgg_key", + "AllowedHosts": "*" +} From a645caf495ad3dcb0961742c1ce1785aad304ee9 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 18:42:46 +1300 Subject: [PATCH 04/62] Updated Ellie.Marmalade --- EllieBot.sln | 13 +- .../Attributes/FilterAttribute.cs | 10 ++ .../Attributes/MarmaladePermAttribute.cs | 10 ++ .../Attributes/bot_owner_onlyAttribute.cs | 7 + .../Attributes/bot_permAttribute.cs | 22 +++ .../Attributes/cmdAttribute.cs | 37 +++++ .../Attributes/injectAttribute.cs | 10 ++ .../Attributes/leftoverAttribute.cs | 10 ++ .../Attributes/prioAttribute.cs | 20 +++ .../Attributes/svcAttribute.cs | 23 +++ .../Attributes/user_permAttribute.cs | 22 +++ src/Ellie.Marmalade/Canary.cs | 143 ++++++++++++++++++ src/Ellie.Marmalade/Context/AnyContext.cs | 52 +++++++ src/Ellie.Marmalade/Context/DmContext.cs | 11 ++ src/Ellie.Marmalade/Context/GuildContext.cs | 12 ++ src/Ellie.Marmalade/Ellie.Marmalade.csproj | 24 +++ src/Ellie.Marmalade/EmbedColor.cs | 8 + .../Extensions/EmbedBuilderExtensions.cs | 14 ++ .../Extensions/MarmaladeExtensions.cs | 66 ++++++++ src/Ellie.Marmalade/IEmbedBuilder.cs | 18 +++ .../ParamParser/ParamParser.cs | 16 ++ .../ParamParser/ParseResult.cs | 48 ++++++ src/Ellie.Marmalade/README.md | 1 + src/Ellie.Marmalade/Strings/CommandStrings.cs | 24 +++ .../Strings/IMarmaladeStrings.cs | 15 ++ .../Strings/IMarmaladeStringsProvider.cs | 28 ++++ .../Strings/LocalMarmaladeStringsProvider.cs | 40 +++++ .../Strings/MarmaladeStrings.cs | 79 ++++++++++ src/Ellie.Marmalade/Strings/StringsLoader.cs | 137 +++++++++++++++++ 29 files changed, 917 insertions(+), 3 deletions(-) create mode 100644 src/Ellie.Marmalade/Attributes/FilterAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/bot_permAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/cmdAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/injectAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/leftoverAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/prioAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/svcAttribute.cs create mode 100644 src/Ellie.Marmalade/Attributes/user_permAttribute.cs create mode 100644 src/Ellie.Marmalade/Canary.cs create mode 100644 src/Ellie.Marmalade/Context/AnyContext.cs create mode 100644 src/Ellie.Marmalade/Context/DmContext.cs create mode 100644 src/Ellie.Marmalade/Context/GuildContext.cs create mode 100644 src/Ellie.Marmalade/Ellie.Marmalade.csproj create mode 100644 src/Ellie.Marmalade/EmbedColor.cs create mode 100644 src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs create mode 100644 src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs create mode 100644 src/Ellie.Marmalade/IEmbedBuilder.cs create mode 100644 src/Ellie.Marmalade/ParamParser/ParamParser.cs create mode 100644 src/Ellie.Marmalade/ParamParser/ParseResult.cs create mode 100644 src/Ellie.Marmalade/README.md create mode 100644 src/Ellie.Marmalade/Strings/CommandStrings.cs create mode 100644 src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs create mode 100644 src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs create mode 100644 src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs create mode 100644 src/Ellie.Marmalade/Strings/MarmaladeStrings.cs create mode 100644 src/Ellie.Marmalade/Strings/StringsLoader.cs diff --git a/EllieBot.sln b/EllieBot.sln index b112a25..bd0e604 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -21,11 +21,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ayu.Discord.Voice", "src\ay EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Tests", "src\EllieBot.Tests\EllieBot.Tests.csproj", "{179DF3B3-AD32-4335-8231-9818338DF3A2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Coordinator", "src\EllieBot.Coordinator\EllieBot.Coordinator.csproj", "{A631DDF0-3AD1-4CB9-8458-314B1320868A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Coordinator", "src\EllieBot.Coordinator\EllieBot.Coordinator.csproj", "{A631DDF0-3AD1-4CB9-8458-314B1320868A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Generators", "src\EllieBot.Generators\EllieBot.Generators.csproj", "{CB1A5307-DD85-4795-8A8A-A25D36DADC51}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Generators", "src\EllieBot.Generators\EllieBot.Generators.csproj", "{CB1A5307-DD85-4795-8A8A-A25D36DADC51}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.VotesApi", "src\EllieBot.VotesApi\EllieBot.VotesApi.csproj", "{F1A77F56-71B0-430E-AE46-94CDD7D43874}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.VotesApi", "src\EllieBot.VotesApi\EllieBot.VotesApi.csproj", "{F1A77F56-71B0-430E-AE46-94CDD7D43874}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Marmalade", "src\Ellie.Marmalade\Ellie.Marmalade.csproj", "{76AC715D-12FF-4CBE-9585-A861139A2D0C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -57,6 +59,10 @@ Global {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Debug|Any CPU.Build.0 = Debug|Any CPU {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1A77F56-71B0-430E-AE46-94CDD7D43874}.Release|Any CPU.Build.0 = Release|Any CPU + {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -69,6 +75,7 @@ Global {A631DDF0-3AD1-4CB9-8458-314B1320868A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {F1A77F56-71B0-430E-AE46-94CDD7D43874} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {76AC715D-12FF-4CBE-9585-A861139A2D0C} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79F61C2C-CDBB-4361-A234-91A0B334CFE4} diff --git a/src/Ellie.Marmalade/Attributes/FilterAttribute.cs b/src/Ellie.Marmalade/Attributes/FilterAttribute.cs new file mode 100644 index 0000000..1f2858e --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/FilterAttribute.cs @@ -0,0 +1,10 @@ +namespace Ellie.Canary; + +/// +/// Overridden to implement custom checks which commands have to pass in order to be executed. +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)] +public abstract class FilterAttribute : Attribute +{ + public abstract ValueTask CheckAsync(AnyContext ctx); +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs b/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs new file mode 100644 index 0000000..0e7003c --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs @@ -0,0 +1,10 @@ +namespace Ellie.Canary; + +/// +/// Used as a marker class for bot_perm and user_perm Attributes +/// Has no functionality. +/// +public abstract class MarmaladePermAttribute : Attribute +{ + +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs b/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs new file mode 100644 index 0000000..cbffa6c --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs @@ -0,0 +1,7 @@ +namespace Ellie.Canary; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class bot_owner_onlyAttribute : MarmaladePermAttribute +{ + +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs b/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs new file mode 100644 index 0000000..faaede2 --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs @@ -0,0 +1,22 @@ +using Discord; + +namespace Ellie.Canary; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class bot_permAttribute : MarmaladePermAttribute +{ + public GuildPermission? GuildPerm { get; } + public ChannelPermission? ChannelPerm { get; } + + public bot_permAttribute(GuildPermission perm) + { + GuildPerm = perm; + ChannelPerm = null; + } + + public bot_permAttribute(ChannelPermission perm) + { + ChannelPerm = perm; + GuildPerm = null; + } +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Attributes/cmdAttribute.cs b/src/Ellie.Marmalade/Attributes/cmdAttribute.cs new file mode 100644 index 0000000..f40ca2e --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/cmdAttribute.cs @@ -0,0 +1,37 @@ +namespace Ellie.Canary; + +/// +/// Marks a method as a snek command +/// +[AttributeUsage(AttributeTargets.Method)] +public class cmdAttribute : Attribute +{ + /// + /// Command description. Avoid using, as cmds.yml is preferred + /// + public string? desc { get; set; } + + /// + /// Command args examples. Avoid using, as cmds.yml is preferred + /// + public string[]? args { get; set; } + + /// + /// Command aliases + /// + public string[] Aliases { get; } + + public cmdAttribute() + { + desc = null; + args = null; + Aliases = Array.Empty(); + } + + public cmdAttribute(params string[] aliases) + { + Aliases = aliases; + desc = null; + args = null; + } +} diff --git a/src/Ellie.Marmalade/Attributes/injectAttribute.cs b/src/Ellie.Marmalade/Attributes/injectAttribute.cs new file mode 100644 index 0000000..3380b9d --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/injectAttribute.cs @@ -0,0 +1,10 @@ +namespace Ellie.Canary; + +/// +/// Marks services in command arguments for injection. +/// The injected services must come after the context and before any input parameters. +/// +public class injectAttribute : Attribute +{ + +} diff --git a/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs b/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs new file mode 100644 index 0000000..d632715 --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs @@ -0,0 +1,10 @@ +namespace Ellie.Canary; + +/// +/// Marks the parameter to take +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class leftoverAttribute : Attribute +{ + +} diff --git a/src/Ellie.Marmalade/Attributes/prioAttribute.cs b/src/Ellie.Marmalade/Attributes/prioAttribute.cs new file mode 100644 index 0000000..cf6d0d4 --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/prioAttribute.cs @@ -0,0 +1,20 @@ +namespace Ellie.Canary; + +/// +/// Sets the priority of a command in case there are multiple commands with the same name but different parameters. +/// Higher value means higher priority. +/// +[AttributeUsage(AttributeTargets.Method)] +public class prioAttribute : Attribute +{ + public int Priority { get; } + + /// + /// Snek command priority + /// + /// Priority value. The higher the value, the higher the priority + public prioAttribute(int priority) + { + Priority = priority; + } +} diff --git a/src/Ellie.Marmalade/Attributes/svcAttribute.cs b/src/Ellie.Marmalade/Attributes/svcAttribute.cs new file mode 100644 index 0000000..eb225b0 --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/svcAttribute.cs @@ -0,0 +1,23 @@ +namespace Ellie.Canary; + +/// +/// Marks the class as a service which can be used within the same Medusa +/// +[AttributeUsage(AttributeTargets.Class)] +public class svcAttribute : Attribute +{ + public Lifetime Lifetime { get; } + public svcAttribute(Lifetime lifetime) + { + Lifetime = lifetime; + } +} + +/// +/// Lifetime for +/// +public enum Lifetime +{ + Singleton, + Transient +} diff --git a/src/Ellie.Marmalade/Attributes/user_permAttribute.cs b/src/Ellie.Marmalade/Attributes/user_permAttribute.cs new file mode 100644 index 0000000..a4826db --- /dev/null +++ b/src/Ellie.Marmalade/Attributes/user_permAttribute.cs @@ -0,0 +1,22 @@ +using Discord; + +namespace Ellie.Canary; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class user_permAttribute : MarmaladePermAttribute +{ + public GuildPermission? GuildPerm { get; } + public ChannelPermission? ChannelPerm { get; } + + public user_permAttribute(GuildPermission perm) + { + GuildPerm = perm; + ChannelPerm = null; + } + + public user_permAttribute(ChannelPermission perm) + { + ChannelPerm = perm; + GuildPerm = null; + } +} diff --git a/src/Ellie.Marmalade/Canary.cs b/src/Ellie.Marmalade/Canary.cs new file mode 100644 index 0000000..5c50aa8 --- /dev/null +++ b/src/Ellie.Marmalade/Canary.cs @@ -0,0 +1,143 @@ +using Discord; + +namespace Ellie.Canary; + +/// +/// The base class which will be loaded as a module into NadekoBot +/// Any user-defined snek has to inherit from this class. +/// Sneks get instantiated ONLY ONCE during the loading, +/// and any snek commands will be executed on the same instance. +/// +public abstract class Snek : IAsyncDisposable +{ + /// + /// Name of the snek. Defaults to the lowercase class name + /// + public virtual string Name + => GetType().Name.ToLowerInvariant(); + + /// + /// The prefix required before the command name. For example + /// if you set this to 'test' then a command called 'cmd' will have to be invoked by using + /// '.test cmd' instead of `.cmd` + /// + public virtual string Prefix + => string.Empty; + + /// + /// Executed once this snek has been instantiated and before any command is executed. + /// + /// A representing completion + public virtual ValueTask InitializeAsync() + => default; + + /// + /// Override to cleanup any resources or references which might hold this snek in memory + /// + /// + public virtual ValueTask DisposeAsync() + => default; + + /// + /// This method is called right after the message was received by the bot. + /// You can use this method to make the bot conditionally ignore some messages and prevent further processing. + /// Execution order: + /// + /// ** → + /// → + /// → + /// OR + /// + /// + /// Guild in which the message was sent + /// Message received by the bot + /// A representing whether the message should be ignored and not processed further + public virtual ValueTask ExecOnMessageAsync(IGuild? guild, IUserMessage msg) + => default; + + /// + /// Override this method to modify input before the bot searches for any commands matching the input + /// Executed after + /// This is useful if you want to reinterpret the message under some conditions + /// Execution order: + /// + /// → + /// ** → + /// → + /// OR + /// + /// + /// Guild in which the message was sent + /// Channel in which the message was sent + /// User who sent the message + /// Content of the message + /// A representing new, potentially modified content + public virtual ValueTask ExecInputTransformAsync( + IGuild? guild, + IMessageChannel channel, + IUser user, + string input + ) + => default; + + /// + /// This method is called after the command was found but not executed, + /// and can be used to prevent the command's execution. + /// The command information doesn't have to be from this snek as this method + /// will be called when *any* command from any module or snek was found. + /// You can choose to prevent the execution of the command by returning "true" value. + /// Execution order: + /// + /// → + /// → + /// ** → + /// OR + /// + /// + /// Command context + /// Name of the snek or module from which the command originates + /// Name of the command which is about to be executed + /// A representing whether the execution should be blocked + public virtual ValueTask ExecPreCommandAsync( + AnyContext context, + string moduleName, + string commandName + ) + => default; + + /// + /// This method is called after the command was succesfully executed. + /// If this method was called, then will not be executed + /// Execution order: + /// + /// → + /// → + /// → + /// ** OR + /// + /// + /// A representing completion + public virtual ValueTask ExecPostCommandAsync(AnyContext ctx, string moduleName, string commandName) + => default; + + /// + /// This method is called if no command was found for the input. + /// Useful if you want to have games or features which take arbitrary input + /// but ignore any messages which were blocked or caused a command execution + /// If this method was called, then will not be executed + /// Execution order: + /// + /// → + /// → + /// → + /// OR ** + /// + /// + /// A representing completion + public virtual ValueTask ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) + => default; +} + +public readonly struct ExecResponse +{ +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Context/AnyContext.cs b/src/Ellie.Marmalade/Context/AnyContext.cs new file mode 100644 index 0000000..f333f1e --- /dev/null +++ b/src/Ellie.Marmalade/Context/AnyContext.cs @@ -0,0 +1,52 @@ +using Discord; +using EllieBot; + +namespace Ellie.Canary; + +/// +/// Commands which take this class as a first parameter can be executed in both DMs and Servers +/// +public abstract class AnyContext +{ + /// + /// Channel from the which the command is invoked + /// + public abstract IMessageChannel Channel { get; } + + /// + /// Message which triggered the command + /// + public abstract IUserMessage Message { get; } + + /// + /// The user who invoked the command + /// + public abstract IUser User { get; } + + /// + /// Bot user + /// + public abstract ISelfUser Bot { get; } + + /// + /// Provides access to strings used by this medusa + /// + public abstract IMarmaladeStrings Strings { get; } + + /// + /// Gets a formatted localized string using a key and arguments which should be formatted in + /// + /// The key of the string as specified in localization files + /// Arguments (if any) to format in + /// A formatted localized string + public abstract string GetText(string key, object[]? args = null); + + /// + /// Creates a context-aware instance + /// (future feature for guild-based embed colors) + /// Any code dealing with embeds should use it for future-proofness + /// instead of manually creating embedbuilder instances + /// + /// A context-aware instance + public abstract IEmbedBuilder Embed(); +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Context/DmContext.cs b/src/Ellie.Marmalade/Context/DmContext.cs new file mode 100644 index 0000000..3810984 --- /dev/null +++ b/src/Ellie.Marmalade/Context/DmContext.cs @@ -0,0 +1,11 @@ +using Discord; + +namespace Ellie.Canary; + +/// +/// Commands which take this type as the first parameter can only be executed in DMs +/// +public abstract class DmContext : AnyContext +{ + public abstract override IDMChannel Channel { get; } +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Context/GuildContext.cs b/src/Ellie.Marmalade/Context/GuildContext.cs new file mode 100644 index 0000000..916f945 --- /dev/null +++ b/src/Ellie.Marmalade/Context/GuildContext.cs @@ -0,0 +1,12 @@ +using Discord; + +namespace Ellie.Canary; + +/// +/// Commands which take this type as a first parameter can only be executed in a server +/// +public abstract class GuildContext : AnyContext +{ + public abstract override ITextChannel Channel { get; } + public abstract IGuild Guild { get; } +} diff --git a/src/Ellie.Marmalade/Ellie.Marmalade.csproj b/src/Ellie.Marmalade/Ellie.Marmalade.csproj new file mode 100644 index 0000000..d296490 --- /dev/null +++ b/src/Ellie.Marmalade/Ellie.Marmalade.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + enable + enable + preview + true + Ellie.Canary + + The EllieBot Devs + + + + + + + + + + 5.0.0 + + + diff --git a/src/Ellie.Marmalade/EmbedColor.cs b/src/Ellie.Marmalade/EmbedColor.cs new file mode 100644 index 0000000..cd492b5 --- /dev/null +++ b/src/Ellie.Marmalade/EmbedColor.cs @@ -0,0 +1,8 @@ +namespace EllieBot; + +public enum EmbedColor +{ + Ok, + Pending, + Error +} diff --git a/src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs b/src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs new file mode 100644 index 0000000..6b6d50d --- /dev/null +++ b/src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs @@ -0,0 +1,14 @@ +namespace EllieBot; + +public static class EmbedBuilderExtensions +{ + public static IEmbedBuilder WithOkColor(this IEmbedBuilder eb) + => eb.WithColor(EmbedColor.Ok); + + public static IEmbedBuilder WithPendingColor(this IEmbedBuilder eb) + => eb.WithColor(EmbedColor.Pending); + + public static IEmbedBuilder WithErrorColor(this IEmbedBuilder eb) + => eb.WithColor(EmbedColor.Error); + +} diff --git a/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs b/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs new file mode 100644 index 0000000..c72859f --- /dev/null +++ b/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs @@ -0,0 +1,66 @@ +using Discord; +using Ellie.Canary; + +namespace EllieBot; + +public static class MarmaladeExtensions +{ + public static Task EmbedAsync(this IMessageChannel ch, IEmbedBuilder embed, string msg = "") + => ch.SendMessageAsync(msg, + embed: embed.Build(), + options: new() + { + RetryMode = RetryMode.Retry502 + }); + + // unlocalized + public static Task SendConfirmAsync(this IMessageChannel ch, AnyContext ctx, string msg) + => ch.EmbedAsync(ctx.Embed().WithOkColor().WithDescription(msg)); + + public static Task SendPendingAsync(this IMessageChannel ch, AnyContext ctx, string msg) + => ch.EmbedAsync(ctx.Embed().WithPendingColor().WithDescription(msg)); + + public static Task SendErrorAsync(this IMessageChannel ch, AnyContext ctx, string msg) + => ch.EmbedAsync(ctx.Embed().WithErrorColor().WithDescription(msg)); + + // unlocalized + public static Task SendConfirmAsync(this AnyContext ctx, string msg) + => ctx.Channel.SendConfirmAsync(ctx, msg); + + public static Task SendPendingAsync(this AnyContext ctx, string msg) + => ctx.Channel.SendPendingAsync(ctx, msg); + + public static Task SendErrorAsync(this AnyContext ctx, string msg) + => ctx.Channel.SendErrorAsync(ctx, msg); + + // localized + public static Task ConfirmAsync(this AnyContext ctx) + => ctx.Message.AddReactionAsync(new Emoji("✅")); + + public static Task ErrorAsync(this AnyContext ctx) + => ctx.Message.AddReactionAsync(new Emoji("❌")); + + public static Task WarningAsync(this AnyContext ctx) + => ctx.Message.AddReactionAsync(new Emoji("⚠️")); + + public static Task WaitAsync(this AnyContext ctx) + => ctx.Message.AddReactionAsync(new Emoji("🤔")); + + public static Task ErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args) + => ctx.SendErrorAsync(ctx.GetText(key, args)); + + public static Task PendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args) + => ctx.SendPendingAsync(ctx.GetText(key, args)); + + public static Task ConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args) + => ctx.SendConfirmAsync(ctx.GetText(key, args)); + + public static Task ReplyErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args) + => ctx.SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}"); + + public static Task ReplyPendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args) + => ctx.SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}"); + + public static Task ReplyConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args) + => ctx.SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}"); +} diff --git a/src/Ellie.Marmalade/IEmbedBuilder.cs b/src/Ellie.Marmalade/IEmbedBuilder.cs new file mode 100644 index 0000000..0d77367 --- /dev/null +++ b/src/Ellie.Marmalade/IEmbedBuilder.cs @@ -0,0 +1,18 @@ +using Discord; + +namespace EllieBot; + +public interface IEmbedBuilder +{ + IEmbedBuilder WithDescription(string? desc); + IEmbedBuilder WithTitle(string? title); + IEmbedBuilder AddField(string title, object value, bool isInline = false); + IEmbedBuilder WithFooter(string text, string? iconUrl = null); + IEmbedBuilder WithAuthor(string name, string? iconUrl = null, string? url = null); + IEmbedBuilder WithColor(EmbedColor color); + IEmbedBuilder WithDiscordColor(Color color); + Embed Build(); + IEmbedBuilder WithUrl(string url); + IEmbedBuilder WithImageUrl(string url); + IEmbedBuilder WithThumbnailUrl(string url); +} diff --git a/src/Ellie.Marmalade/ParamParser/ParamParser.cs b/src/Ellie.Marmalade/ParamParser/ParamParser.cs new file mode 100644 index 0000000..feec7d1 --- /dev/null +++ b/src/Ellie.Marmalade/ParamParser/ParamParser.cs @@ -0,0 +1,16 @@ +namespace Ellie.Canary; + +/// +/// Overridden to implement parsers for custom types +/// +/// Type into which to parse the input +public abstract class ParamParser +{ + /// + /// Overridden to implement parsing logic + /// + /// Context + /// Input to parse + /// A with successful or failed status + public abstract ValueTask> TryParseAsync(AnyContext ctx, string input); +} diff --git a/src/Ellie.Marmalade/ParamParser/ParseResult.cs b/src/Ellie.Marmalade/ParamParser/ParseResult.cs new file mode 100644 index 0000000..81a8607 --- /dev/null +++ b/src/Ellie.Marmalade/ParamParser/ParseResult.cs @@ -0,0 +1,48 @@ +namespace Ellie.Canary; + +public readonly struct ParseResult +{ + /// + /// Whether the parsing was successful + /// + public bool IsSuccess { get; private init; } + + /// + /// Parsed value. It should only have value if is set to true + /// + public T? Data { get; private init; } + + /// + /// Instantiate a **successful** parse result + /// + /// Parsed value + public ParseResult(T data) + { + Data = data; + IsSuccess = true; + } + + + /// + /// Create a new with IsSuccess = false + /// + /// A new + public static ParseResult Fail() + => new ParseResult + { + IsSuccess = false, + Data = default, + }; + + /// + /// Create a new with IsSuccess = true + /// + /// Value of the parsed object + /// A new + public static ParseResult Success(T obj) + => new ParseResult + { + IsSuccess = true, + Data = obj, + }; +} diff --git a/src/Ellie.Marmalade/README.md b/src/Ellie.Marmalade/README.md new file mode 100644 index 0000000..98e851d --- /dev/null +++ b/src/Ellie.Marmalade/README.md @@ -0,0 +1 @@ +This is the library which is the base of any marmalade. \ No newline at end of file diff --git a/src/Ellie.Marmalade/Strings/CommandStrings.cs b/src/Ellie.Marmalade/Strings/CommandStrings.cs new file mode 100644 index 0000000..8328fae --- /dev/null +++ b/src/Ellie.Marmalade/Strings/CommandStrings.cs @@ -0,0 +1,24 @@ +using YamlDotNet.Serialization; + +namespace Ellie.Canary; + +public readonly struct CommandStrings +{ + public CommandStrings(string? desc, string[]? args) + { + Desc = desc; + Args = args; + } + + [YamlMember(Alias = "desc")] + public string? Desc { get; init; } + + [YamlMember(Alias = "args")] + public string[]? Args { get; init; } + + public void Deconstruct(out string? desc, out string[]? args) + { + desc = Desc; + args = Args; + } +} diff --git a/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs b/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs new file mode 100644 index 0000000..1527bfe --- /dev/null +++ b/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs @@ -0,0 +1,15 @@ +using System.Globalization; + +namespace Ellie.Canary; + +/// +/// Defines methods to retrieve and reload marmalade strings +/// +public interface IMarmaladeStrings +{ + // string GetText(string key, ulong? guildId = null, params object[] data); + string? GetText(string key, CultureInfo locale, params object[] data); + void Reload(); + CommandStrings GetCommandStrings(string commandName, CultureInfo cultureInfo); + string? GetDescription(CultureInfo? locale); +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs b/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs new file mode 100644 index 0000000..d2fb1a7 --- /dev/null +++ b/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs @@ -0,0 +1,28 @@ +namespace Ellie.Canary; + +/// +/// Implemented by classes which provide localized strings in their own ways +/// +public interface IMarmaladeStringsProvider +{ + /// + /// Gets localized string + /// + /// Language name + /// String key + /// Localized string + string? GetText(string localeName, string key); + + /// + /// Reloads string cache + /// + void Reload(); + + // /// + // /// Gets command arg examples and description + // /// + // /// Language name + // /// Command name + // CommandStrings GetCommandStrings(string localeName, string commandName); + CommandStrings? GetCommandStrings(string localeName, string commandName); +} diff --git a/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs b/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs new file mode 100644 index 0000000..2bb6ca6 --- /dev/null +++ b/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs @@ -0,0 +1,40 @@ +namespace Ellie.Canary; + +public class LocalMarmaladeStringsProvider : IMarmaladeStringsProvider +{ + private readonly StringsLoader _source; + private IReadOnlyDictionary> _responseStrings; + private IReadOnlyDictionary> _commandStrings; + + public LocalMarmaladeStringsProvider(StringsLoader source) + { + _source = source; + _responseStrings = _source.GetResponseStrings(); + _commandStrings = _source.GetCommandStrings(); + } + + public void Reload() + { + _responseStrings = _source.GetResponseStrings(); + _commandStrings = _source.GetCommandStrings(); + } + + + public string? GetText(string localeName, string key) + { + if (_responseStrings.TryGetValue(localeName.ToLowerInvariant(), out var langStrings) + && langStrings.TryGetValue(key.ToLowerInvariant(), out var text)) + return text; + + return null; + } + + public CommandStrings? GetCommandStrings(string localeName, string commandName) + { + if (_commandStrings.TryGetValue(localeName.ToLowerInvariant(), out var langStrings) + && langStrings.TryGetValue(commandName.ToLowerInvariant(), out var strings)) + return strings; + + return null; + } +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs b/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs new file mode 100644 index 0000000..2880764 --- /dev/null +++ b/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs @@ -0,0 +1,79 @@ +using System.Globalization; +using Serilog; + +namespace Ellie.Canary; + +public class MarmaladeStrings : IMarmaladeStrings +{ + /// + /// Used as failsafe in case response key doesn't exist in the selected or default language. + /// + private readonly CultureInfo _usCultureInfo = new("en-US"); + + private readonly IMarmaladeStringsProvider _stringsProvider; + + public MarmaladeStrings(IMarmaladeStringsProvider stringsProvider) + { + _stringsProvider = stringsProvider; + } + + private string? GetString(string key, CultureInfo cultureInfo) + => _stringsProvider.GetText(cultureInfo.Name, key); + + public string? GetText(string key, CultureInfo cultureInfo) + => GetString(key, cultureInfo) + ?? GetString(key, _usCultureInfo); + + public string? GetText(string key, CultureInfo cultureInfo, params object[] data) + { + var text = GetText(key, cultureInfo); + + if (string.IsNullOrWhiteSpace(text)) + return null; + + try + { + return string.Format(text, data); + } + catch (FormatException) + { + Log.Warning(" Key '{Key}' is not properly formatted in '{LanguageName}' response strings", + key, + cultureInfo.Name); + + return $"⚠️ Response string key '{key}' is not properly formatted. Please report this.\n\n{text}"; + } + } + + public CommandStrings GetCommandStrings(string commandName, CultureInfo cultureInfo) + { + var cmdStrings = _stringsProvider.GetCommandStrings(cultureInfo.Name, commandName); + if (cmdStrings is null) + { + if (cultureInfo.Name == _usCultureInfo.Name) + { + Log.Warning("'{CommandName}' doesn't exist in 'en-US' command strings for one of the marmalades", + commandName); + + return new(null, null); + } + + Log.Information("Missing '{CommandName}' command strings for the '{LocaleName}' locale", + commandName, + cultureInfo.Name); + + return GetCommandStrings(commandName, _usCultureInfo); + } + + return cmdStrings.Value; + } + + public string? GetDescription(CultureInfo? locale = null) + => GetText("marmalades.description", locale ?? _usCultureInfo); + + public static MarmaladeStrings CreateDefault(string basePath) + => new MarmaladeStrings(new LocalMarmaladeStringsProvider(new(basePath))); + + public void Reload() + => _stringsProvider.Reload(); +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/Strings/StringsLoader.cs b/src/Ellie.Marmalade/Strings/StringsLoader.cs new file mode 100644 index 0000000..bec5c17 --- /dev/null +++ b/src/Ellie.Marmalade/Strings/StringsLoader.cs @@ -0,0 +1,137 @@ +using System.Diagnostics.CodeAnalysis; +using Serilog; +using YamlDotNet.Serialization; + +namespace Ellie.Canary; + +/// +/// Loads strings from the shortcut or localizable path +/// +public class StringsLoader +{ + private readonly string _localizableResponsesPath; + private readonly string _shortcutResponsesFile; + + private readonly string _localizableCommandsPath; + private readonly string _shortcutCommandsFile; + + public StringsLoader(string basePath) + { + _localizableResponsesPath = Path.Join(basePath, "strings/res"); + _shortcutResponsesFile = Path.Join(basePath, "res.yml"); + + _localizableCommandsPath = Path.Join(basePath, "strings/cmds"); + _shortcutCommandsFile = Path.Join(basePath, "cmds.yml"); + } + + public IReadOnlyDictionary> GetCommandStrings() + { + var outputDict = new Dictionary>(); + + if (File.Exists(_shortcutCommandsFile)) + { + if (TryLoadCommandsFromFile(_shortcutCommandsFile, out var dict, out _)) + { + outputDict["en-us"] = dict; + } + + return outputDict; + } + + if (Directory.Exists(_localizableCommandsPath)) + { + foreach (var cmdsFile in Directory.EnumerateFiles(_localizableCommandsPath)) + { + if (TryLoadCommandsFromFile(cmdsFile, out var dict, out var locale) && locale is not null) + { + outputDict[locale.ToLowerInvariant()] = dict; + } + } + } + + return outputDict; + } + + + private static readonly IDeserializer _deserializer = new DeserializerBuilder().Build(); + private static bool TryLoadCommandsFromFile(string file, + [NotNullWhen(true)] out IReadOnlyDictionary? strings, + out string? localeName) + { + try + { + var text = File.ReadAllText(file); + strings = _deserializer.Deserialize?>(text) + ?? new(); + localeName = GetLocaleName(file); + return true; + } + catch (Exception ex) + { + Log.Error(ex, "Error loading {FileName} command strings: {ErrorMessage}", file, ex.Message); + } + + strings = null; + localeName = null; + return false; + } + + + public IReadOnlyDictionary> GetResponseStrings() + { + var outputDict = new Dictionary>(); + + // try to load a shortcut file + if (File.Exists(_shortcutResponsesFile)) + { + if (TryLoadResponsesFromFile(_shortcutResponsesFile, out var dict, out _)) + { + outputDict["en-us"] = dict; + } + + return outputDict; + } + + if (!Directory.Exists(_localizableResponsesPath)) + return outputDict; + + // if shortcut file doesn't exist, try to load localizable files + foreach (var file in Directory.GetFiles(_localizableResponsesPath)) + { + if (TryLoadResponsesFromFile(file, out var strings, out var localeName) && localeName is not null) + { + outputDict[localeName.ToLowerInvariant()] = strings; + } + } + + return outputDict; + } + + private static bool TryLoadResponsesFromFile(string file, + [NotNullWhen(true)] out IReadOnlyDictionary? strings, + out string? localeName) + { + try + { + strings = _deserializer.Deserialize?>(File.ReadAllText(file)); + if (strings is null) + { + localeName = null; + return false; + } + + localeName = GetLocaleName(file).ToLowerInvariant(); + return true; + } + catch (Exception ex) + { + Log.Error(ex, "Error loading {FileName} response strings: {ErrorMessage}", file, ex.Message); + strings = null; + localeName = null; + return false; + } + } + + private static string GetLocaleName(string fileName) + => Path.GetFileNameWithoutExtension(fileName); +} \ No newline at end of file From 30606ad92a7ab37b9efe7e72f4eb54ef5db387c4 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 18:51:29 +1300 Subject: [PATCH 05/62] Updated EllieBot.sln --- EllieBot.sln | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/EllieBot.sln b/EllieBot.sln index bd0e604..c83e592 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -29,6 +29,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.VotesApi", "src\El EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Marmalade", "src\Ellie.Marmalade\Ellie.Marmalade.csproj", "{76AC715D-12FF-4CBE-9585-A861139A2D0C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Common", "src\Ellie.Common\Ellie.Common.csproj", "{5C1B88B0-B881-4E20-8382-4DDE275F8642}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Econ", "src\Ellie.Econ\Ellie.Econ.csproj", "{A73A6399-50E1-4362-BE29-86C2C88CF05A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -63,6 +67,14 @@ Global {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Release|Any CPU.Build.0 = Release|Any CPU + {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Release|Any CPU.Build.0 = Release|Any CPU + {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -76,6 +88,8 @@ Global {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {F1A77F56-71B0-430E-AE46-94CDD7D43874} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {76AC715D-12FF-4CBE-9585-A861139A2D0C} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {5C1B88B0-B881-4E20-8382-4DDE275F8642} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {A73A6399-50E1-4362-BE29-86C2C88CF05A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79F61C2C-CDBB-4361-A234-91A0B334CFE4} From 88bf80ce96a6d1e5892d47ce577de037f4d1a67f Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 18:52:36 +1300 Subject: [PATCH 06/62] Updated TODO.md --- TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index fb3ff2e..476e447 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,5 @@ # List of things to do - Finish the full system rewrite - - Finish the EllieBot.Tests project \ No newline at end of file + - Finish the EllieBot.Tests project + - Finish the EllieBot project \ No newline at end of file From 320626cf2ab407581a05468ce7ed994e173b392c Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 19:18:18 +1300 Subject: [PATCH 07/62] Updated Ellie.Common --- src/Ellie.Common/AsyncLazy.cs | 19 +++ .../Collections/ConcurrentHashSet.cs | 88 +++++++++++ .../Collections/IndexedCollection.cs | 148 ++++++++++++++++++ src/Ellie.Common/Ellie.Common.csproj | 15 ++ src/Ellie.Common/EllieRandom.cs | 69 ++++++++ .../Extensions/ArrayExtensions.cs | 51 ++++++ .../Extensions/EnumerableExtensions.cs | 107 +++++++++++++ .../Extensions/HttpClientExtensions.cs | 35 +++++ src/Ellie.Common/Extensions/PipExtensions.cs | 22 +++ src/Ellie.Common/GlobalUsings.cs | 1 + src/Ellie.Common/Helpers/LogSetup.cs | 36 +++++ .../Helpers/StandardConversions.cs | 7 + src/Ellie.Common/Kwum.cs | 100 ++++++++++++ src/Ellie.Common/QueueRunner.cs | 63 ++++++++ src/Ellie.Common/ShmartBankAmount.cs | 19 +++ src/Ellie.Common/ShmartNumber.cs | 38 +++++ 16 files changed, 818 insertions(+) create mode 100644 src/Ellie.Common/AsyncLazy.cs create mode 100644 src/Ellie.Common/Collections/ConcurrentHashSet.cs create mode 100644 src/Ellie.Common/Collections/IndexedCollection.cs create mode 100644 src/Ellie.Common/Ellie.Common.csproj create mode 100644 src/Ellie.Common/EllieRandom.cs create mode 100644 src/Ellie.Common/Extensions/ArrayExtensions.cs create mode 100644 src/Ellie.Common/Extensions/EnumerableExtensions.cs create mode 100644 src/Ellie.Common/Extensions/HttpClientExtensions.cs create mode 100644 src/Ellie.Common/Extensions/PipExtensions.cs create mode 100644 src/Ellie.Common/GlobalUsings.cs create mode 100644 src/Ellie.Common/Helpers/LogSetup.cs create mode 100644 src/Ellie.Common/Helpers/StandardConversions.cs create mode 100644 src/Ellie.Common/Kwum.cs create mode 100644 src/Ellie.Common/QueueRunner.cs create mode 100644 src/Ellie.Common/ShmartBankAmount.cs create mode 100644 src/Ellie.Common/ShmartNumber.cs diff --git a/src/Ellie.Common/AsyncLazy.cs b/src/Ellie.Common/AsyncLazy.cs new file mode 100644 index 0000000..5c69a0d --- /dev/null +++ b/src/Ellie.Common/AsyncLazy.cs @@ -0,0 +1,19 @@ +using System.Runtime.CompilerServices; + +namespace Ellie.Common; + +public class AsyncLazy : Lazy> +{ + public AsyncLazy(Func valueFactory) + : base(() => Task.Run(valueFactory)) + { + } + + public AsyncLazy(Func> taskFactory) + : base(() => Task.Run(taskFactory)) + { + } + + public TaskAwaiter GetAwaiter() + => Value.GetAwaiter(); +} diff --git a/src/Ellie.Common/Collections/ConcurrentHashSet.cs b/src/Ellie.Common/Collections/ConcurrentHashSet.cs new file mode 100644 index 0000000..19986be --- /dev/null +++ b/src/Ellie.Common/Collections/ConcurrentHashSet.cs @@ -0,0 +1,88 @@ +using System.Diagnostics; + +namespace System.Collections.Generic; + +[DebuggerDisplay("{_backingStore.Count}")] +public sealed class ConcurrentHashSet : IReadOnlyCollection, ICollection where T : notnull +{ + private readonly ConcurrentDictionary _backingStore; + + public ConcurrentHashSet() + => _backingStore = new(); + + public ConcurrentHashSet(IEnumerable values, IEqualityComparer? comparer = null) + => _backingStore = new(values.Select(x => new KeyValuePair(x, true)), comparer); + + public IEnumerator GetEnumerator() + => _backingStore.Keys.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + /// Adds the specified item to the . + /// + /// The item to add. + /// + /// true if the items was added to the + /// successfully; false if it already exists. + /// + /// + /// The + /// contains too many items. + /// + public bool Add(T item) + => _backingStore.TryAdd(item, true); + + void ICollection.Add(T item) + => Add(item); + + public void Clear() + => _backingStore.Clear(); + + public bool Contains(T item) + => _backingStore.ContainsKey(item); + + public void CopyTo(T[] array, int arrayIndex) + { + ArgumentNullException.ThrowIfNull(array); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + + if (arrayIndex >= array.Length) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + + CopyToInternal(array, arrayIndex); + } + + private void CopyToInternal(T[] array, int arrayIndex) + { + var len = array.Length; + foreach (var (k, _) in _backingStore) + { + if (arrayIndex >= len) + throw new IndexOutOfRangeException(nameof(arrayIndex)); + + array[arrayIndex++] = k; + } + } + + bool ICollection.Remove(T item) + => TryRemove(item); + + public bool TryRemove(T item) + => _backingStore.TryRemove(item, out _); + + public void RemoveWhere(Func predicate) + { + foreach (var elem in this.Where(predicate)) + TryRemove(elem); + } + + public int Count + => _backingStore.Count; + + public bool IsReadOnly + => false; +} \ No newline at end of file diff --git a/src/Ellie.Common/Collections/IndexedCollection.cs b/src/Ellie.Common/Collections/IndexedCollection.cs new file mode 100644 index 0000000..15fdc7f --- /dev/null +++ b/src/Ellie.Common/Collections/IndexedCollection.cs @@ -0,0 +1,148 @@ +using System.Collections; + +namespace Ellie.Common; + +public interface IIndexed +{ + int Index { get; set; } +} + +public class IndexedCollection : IList + where T : class, IIndexed +{ + public List Source { get; } + + public int Count + => Source.Count; + + public bool IsReadOnly + => false; + + public virtual T this[int index] + { + get => Source[index]; + set + { + lock (_locker) + { + value.Index = index; + Source[index] = value; + } + } + } + + private readonly object _locker = new(); + + public IndexedCollection() + => Source = new(); + + public IndexedCollection(IEnumerable source) + { + lock (_locker) + { + Source = source.OrderBy(x => x.Index).ToList(); + UpdateIndexes(); + } + } + + public int IndexOf(T item) + => item?.Index ?? -1; + + public IEnumerator GetEnumerator() + => Source.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => Source.GetEnumerator(); + + public void Add(T item) + { + ArgumentNullException.ThrowIfNull(item); + + lock (_locker) + { + item.Index = Source.Count; + Source.Add(item); + } + } + + public virtual void Clear() + { + lock (_locker) + { + Source.Clear(); + } + } + + public bool Contains(T item) + { + lock (_locker) + { + return Source.Contains(item); + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + lock (_locker) + { + Source.CopyTo(array, arrayIndex); + } + } + + public virtual bool Remove(T item) + { + lock (_locker) + { + if (Source.Remove(item)) + { + for (var i = 0; i < Source.Count; i++) + { + if (Source[i].Index != i) + Source[i].Index = i; + } + + return true; + } + } + + return false; + } + + public virtual void Insert(int index, T item) + { + lock (_locker) + { + Source.Insert(index, item); + for (var i = index; i < Source.Count; i++) + Source[i].Index = i; + } + } + + public virtual void RemoveAt(int index) + { + lock (_locker) + { + Source.RemoveAt(index); + for (var i = index; i < Source.Count; i++) + Source[i].Index = i; + } + } + + public void UpdateIndexes() + { + lock (_locker) + { + for (var i = 0; i < Source.Count; i++) + { + if (Source[i].Index != i) + Source[i].Index = i; + } + } + } + + public static implicit operator List(IndexedCollection x) + => x.Source; + + public List ToList() + => Source.ToList(); +} diff --git a/src/Ellie.Common/Ellie.Common.csproj b/src/Ellie.Common/Ellie.Common.csproj new file mode 100644 index 0000000..754532f --- /dev/null +++ b/src/Ellie.Common/Ellie.Common.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/src/Ellie.Common/EllieRandom.cs b/src/Ellie.Common/EllieRandom.cs new file mode 100644 index 0000000..efb4b8f --- /dev/null +++ b/src/Ellie.Common/EllieRandom.cs @@ -0,0 +1,69 @@ +#nullable disable +using System.Security.Cryptography; + +namespace Ellie.Common; + +public class EllieRandom : Random +{ + private readonly RandomNumberGenerator _rng; + + public EllieRandom() + => _rng = RandomNumberGenerator.Create(); + + public override int Next() + { + var bytes = new byte[sizeof(int)]; + _rng.GetBytes(bytes); + return Math.Abs(BitConverter.ToInt32(bytes, 0)); + } + + public override int Next(int maxValue) + { + if (maxValue <= 0) + throw new ArgumentOutOfRangeException(nameof(maxValue)); + var bytes = new byte[sizeof(int)]; + _rng.GetBytes(bytes); + return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue; + } + + public override int Next(int minValue, int maxValue) + { + if (minValue > maxValue) + throw new ArgumentOutOfRangeException(nameof(maxValue)); + if (minValue == maxValue) + return minValue; + var bytes = new byte[sizeof(int)]; + _rng.GetBytes(bytes); + var sign = Math.Sign(BitConverter.ToInt32(bytes, 0)); + return (sign * BitConverter.ToInt32(bytes, 0) % (maxValue - minValue)) + minValue; + } + + public long NextLong(long minValue, long maxValue) + { + if (minValue > maxValue) + throw new ArgumentOutOfRangeException(nameof(maxValue)); + if (minValue == maxValue) + return minValue; + var bytes = new byte[sizeof(long)]; + _rng.GetBytes(bytes); + var sign = Math.Sign(BitConverter.ToInt64(bytes, 0)); + return (sign * BitConverter.ToInt64(bytes, 0) % (maxValue - minValue)) + minValue; + } + + public override void NextBytes(byte[] buffer) + => _rng.GetBytes(buffer); + + protected override double Sample() + { + var bytes = new byte[sizeof(double)]; + _rng.GetBytes(bytes); + return Math.Abs((BitConverter.ToDouble(bytes, 0) / double.MaxValue) + 1); + } + + public override double NextDouble() + { + var bytes = new byte[sizeof(double)]; + _rng.GetBytes(bytes); + return BitConverter.ToDouble(bytes, 0); + } +} diff --git a/src/Ellie.Common/Extensions/ArrayExtensions.cs b/src/Ellie.Common/Extensions/ArrayExtensions.cs new file mode 100644 index 0000000..a861220 --- /dev/null +++ b/src/Ellie.Common/Extensions/ArrayExtensions.cs @@ -0,0 +1,51 @@ +namespace Ellie.Common; + +// made for expressions because they almost never get added +// and they get looped through constantly +public static class ArrayExtensions +{ + /// + /// Create a new array from the old array + new element at the end + /// + /// Input array + /// Item to add to the end of the output array + /// Type of the array + /// A new array with the new element at the end + public static T[] With(this T[] input, T added) + { + var newExprs = new T[input.Length + 1]; + Array.Copy(input, 0, newExprs, 0, input.Length); + newExprs[input.Length] = added; + return newExprs; + } + + /// + /// Creates a new array by applying the specified function to every element in the input array + /// + /// Array to modify + /// Function to apply + /// Orignal type of the elements in the array + /// Output type of the elements of the array + /// New array with updated elements + public static TOut[] Map(this TIn[] arr, Func f) + => Array.ConvertAll(arr, x => f(x)); + + /// + /// Creates a new array by applying the specified function to every element in the input array + /// + /// Array to modify + /// Function to apply + /// Orignal type of the elements in the array + /// Output type of the elements of the array + /// New array with updated elements + public static TOut[] Map(this IReadOnlyCollection col, Func f) + { + var toReturn = new TOut[col.Count]; + + var i = 0; + foreach (var item in col) + toReturn[i++] = f(item); + + return toReturn; + } +} diff --git a/src/Ellie.Common/Extensions/EnumerableExtensions.cs b/src/Ellie.Common/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000..1583b9f --- /dev/null +++ b/src/Ellie.Common/Extensions/EnumerableExtensions.cs @@ -0,0 +1,107 @@ +using System.Security.Cryptography; + +namespace Ellie.Common; + +public static class EnumerableExtensions +{ + /// + /// Concatenates the members of a collection, using the specified separator between each member. + /// + /// Collection to join + /// + /// The character to use as a separator. separator is included in the returned string only if + /// values has more than one element. + /// + /// Optional transformation to apply to each element before concatenation. + /// The type of the members of values. + /// + /// A string that consists of the members of values delimited by the separator character. -or- Empty if values has + /// no elements. + /// + public static string Join(this IEnumerable data, char separator, Func? func = null) + => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); + + /// + /// Concatenates the members of a collection, using the specified separator between each member. + /// + /// Collection to join + /// + /// The string to use as a separator.separator is included in the returned string only if values + /// has more than one element. + /// + /// Optional transformation to apply to each element before concatenation. + /// The type of the members of values. + /// + /// A string that consists of the members of values delimited by the separator character. -or- Empty if values has + /// no elements. + /// + public static string Join(this IEnumerable data, string separator, Func? func = null) + => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); + + /// + /// Randomize element order by performing the Fisher-Yates shuffle + /// + /// Item type + /// Items to shuffle + public static IReadOnlyList Shuffle(this IEnumerable items) + { + using var provider = RandomNumberGenerator.Create(); + var list = items.ToList(); + var n = list.Count; + while (n > 1) + { + var box = new byte[(n / byte.MaxValue) + 1]; + int boxSum; + do + { + provider.GetBytes(box); + boxSum = box.Sum(b => b); + } while (!(boxSum < n * (byte.MaxValue * box.Length / n))); + + var k = boxSum % n; + n--; + (list[k], list[n]) = (list[n], list[k]); + } + + return list; + } + + /// + /// Initializes a new instance of the class + /// that contains elements copied from the specified + /// has the default concurrency level, has the default initial capacity, + /// and uses the default comparer for the key type. + /// + /// + /// The whose elements are copied to the new + /// . + /// + /// A new instance of the class + public static ConcurrentDictionary ToConcurrent( + this IEnumerable> dict) + where TKey : notnull + => new(dict); + + public static IndexedCollection ToIndexed(this IEnumerable enumerable) + where T : class, IIndexed + => new(enumerable); + + /// + /// Creates a task that will complete when all of the objects in an enumerable + /// collection have completed + /// + /// The tasks to wait on for completion. + /// The type of the completed task. + /// A task that represents the completion of all of the supplied tasks. + public static Task WhenAll(this IEnumerable> tasks) + => Task.WhenAll(tasks); + + /// + /// Creates a task that will complete when all of the objects in an enumerable + /// collection have completed + /// + /// The tasks to wait on for completion. + /// A task that represents the completion of all of the supplied tasks. + public static Task WhenAll(this IEnumerable tasks) + => Task.WhenAll(tasks); +} diff --git a/src/Ellie.Common/Extensions/HttpClientExtensions.cs b/src/Ellie.Common/Extensions/HttpClientExtensions.cs new file mode 100644 index 0000000..1b4b492 --- /dev/null +++ b/src/Ellie.Common/Extensions/HttpClientExtensions.cs @@ -0,0 +1,35 @@ +using System.Net.Http.Headers; + +namespace Ellie.Common; + +public static class HttpClientExtensions +{ + public static HttpClient AddFakeHeaders(this HttpClient http) + { + AddFakeHeaders(http.DefaultRequestHeaders); + return http; + } + + public static void AddFakeHeaders(this HttpHeaders dict) + { + dict.Clear(); + dict.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + dict.Add("User-Agent", + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"); + } + + public static bool IsImage(this HttpResponseMessage msg) + => IsImage(msg, out _); + + public static bool IsImage(this HttpResponseMessage msg, out string? mimeType) + { + mimeType = msg.Content.Headers.ContentType?.MediaType; + if (mimeType is "image/png" or "image/jpeg" or "image/gif") + return true; + + return false; + } + + public static long GetContentLength(this HttpResponseMessage msg) + => msg.Content.Headers.ContentLength ?? long.MaxValue; +} diff --git a/src/Ellie.Common/Extensions/PipExtensions.cs b/src/Ellie.Common/Extensions/PipExtensions.cs new file mode 100644 index 0000000..eb2b5a2 --- /dev/null +++ b/src/Ellie.Common/Extensions/PipExtensions.cs @@ -0,0 +1,22 @@ +namespace Ellie.Common; + +public delegate TOut PipeFunc(in TIn a); +public delegate TOut PipeFunc(in TIn1 a, in TIn2 b); + +public static class PipeExtensions +{ + public static TOut Pipe(this TIn a, Func fn) + => fn(a); + + public static TOut Pipe(this TIn a, PipeFunc fn) + => fn(a); + + public static TOut Pipe(this (TIn1, TIn2) a, PipeFunc fn) + => fn(a.Item1, a.Item2); + + public static (TIn, TExtra) With(this TIn a, TExtra b) + => (a, b); + + public static async Task Pipe(this Task a, Func fn) + => fn(await a); +} diff --git a/src/Ellie.Common/GlobalUsings.cs b/src/Ellie.Common/GlobalUsings.cs new file mode 100644 index 0000000..55fdcac --- /dev/null +++ b/src/Ellie.Common/GlobalUsings.cs @@ -0,0 +1 @@ +global using NonBlocking; \ No newline at end of file diff --git a/src/Ellie.Common/Helpers/LogSetup.cs b/src/Ellie.Common/Helpers/LogSetup.cs new file mode 100644 index 0000000..16e1f05 --- /dev/null +++ b/src/Ellie.Common/Helpers/LogSetup.cs @@ -0,0 +1,36 @@ +using Serilog.Events; +using Serilog.Sinks.SystemConsole.Themes; +using System.Text; +using Serilog; + +namespace Ellie.Common; + +public static class LogSetup +{ + public static void SetupLogger(object source) + { + Log.Logger = new LoggerConfiguration().MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .MinimumLevel.Override("System", LogEventLevel.Information) + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.Console(LogEventLevel.Information, + theme: GetTheme(), + outputTemplate: + "[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}") + .Enrich.WithProperty("LogSource", source) + .CreateLogger(); + + Console.OutputEncoding = Encoding.UTF8; + } + + private static ConsoleTheme GetTheme() + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + return AnsiConsoleTheme.Code; +#if DEBUG + return AnsiConsoleTheme.Code; +#else + return ConsoleTheme.None; +#endif + } +} diff --git a/src/Ellie.Common/Helpers/StandardConversions.cs b/src/Ellie.Common/Helpers/StandardConversions.cs new file mode 100644 index 0000000..6b68353 --- /dev/null +++ b/src/Ellie.Common/Helpers/StandardConversions.cs @@ -0,0 +1,7 @@ +namespace Ellie.Common; + +public static class StandardConversions +{ + public static double CelsiusToFahrenheit(double cel) + => (cel * 1.8f) + 32; +} diff --git a/src/Ellie.Common/Kwum.cs b/src/Ellie.Common/Kwum.cs new file mode 100644 index 0000000..87e081d --- /dev/null +++ b/src/Ellie.Common/Kwum.cs @@ -0,0 +1,100 @@ +using System.Runtime.CompilerServices; + +namespace Ellie.Common; + +// needs proper invalid input check (character array input out of range) +// needs negative number support +// ReSharper disable once InconsistentNaming +#pragma warning disable IDE1006 +public readonly struct kwum : IEquatable +#pragma warning restore IDE1006 +{ + private const string VALID_CHARACTERS = "23456789abcdefghijkmnpqrstuvwxyz"; + private readonly int _value; + + public kwum(int num) + => _value = num; + + public kwum(in char c) + { + if (!IsValidChar(c)) + throw new ArgumentException("Character needs to be a valid kwum character.", nameof(c)); + + _value = InternalCharToValue(c); + } + + public kwum(in ReadOnlySpan input) + { + _value = 0; + for (var index = 0; index < input.Length; index++) + { + var c = input[index]; + if (!IsValidChar(c)) + throw new ArgumentException("All characters need to be a valid kwum characters.", nameof(input)); + + _value += VALID_CHARACTERS.IndexOf(c) * (int)Math.Pow(VALID_CHARACTERS.Length, input.Length - index - 1); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int InternalCharToValue(in char c) + => VALID_CHARACTERS.IndexOf(c); + + public static bool TryParse(in ReadOnlySpan input, out kwum value) + { + value = default; + foreach (var c in input) + { + if (!IsValidChar(c)) + return false; + } + + value = new(input); + return true; + } + + public static kwum operator +(kwum left, kwum right) + => new(left._value + right._value); + + public static bool operator ==(kwum left, kwum right) + => left._value == right._value; + + public static bool operator !=(kwum left, kwum right) + => !(left == right); + + public static implicit operator long(kwum kwum) + => kwum._value; + + public static implicit operator int(kwum kwum) + => kwum._value; + + public static implicit operator kwum(int num) + => new(num); + + public static bool IsValidChar(char c) + => VALID_CHARACTERS.Contains(c); + + public override string ToString() + { + var count = VALID_CHARACTERS.Length; + var localValue = _value; + var arrSize = (int)Math.Log(localValue, count) + 1; + Span chars = new char[arrSize]; + while (localValue > 0) + { + localValue = Math.DivRem(localValue, count, out var rem); + chars[--arrSize] = VALID_CHARACTERS[rem]; + } + + return new(chars); + } + + public override bool Equals(object? obj) + => obj is kwum kw && kw == this; + + public bool Equals(kwum other) + => other == this; + + public override int GetHashCode() + => _value.GetHashCode(); +} diff --git a/src/Ellie.Common/QueueRunner.cs b/src/Ellie.Common/QueueRunner.cs new file mode 100644 index 0000000..80fc691 --- /dev/null +++ b/src/Ellie.Common/QueueRunner.cs @@ -0,0 +1,63 @@ +using System.Threading.Channels; +using Serilog; + +namespace Ellie.Common; + +public sealed class QueueRunner +{ + private readonly Channel> _channel; + private readonly int _delayMs; + + public QueueRunner(int delayMs = 0, int maxCapacity = -1) + { + if (delayMs < 0) + throw new ArgumentOutOfRangeException(nameof(delayMs)); + + _delayMs = delayMs; + _channel = maxCapacity switch + { + 0 or < -1 => throw new ArgumentOutOfRangeException(nameof(maxCapacity)), + -1 => Channel.CreateUnbounded>(new UnboundedChannelOptions() + { + SingleReader = true, + SingleWriter = false, + AllowSynchronousContinuations = true, + }), + _ => Channel.CreateBounded>(new BoundedChannelOptions(maxCapacity) + { + Capacity = maxCapacity, + FullMode = BoundedChannelFullMode.DropOldest, + SingleReader = true, + SingleWriter = false, + AllowSynchronousContinuations = true + }) + }; + } + + public async Task RunAsync(CancellationToken cancel = default) + { + while (true) + { + var func = await _channel.Reader.ReadAsync(cancel); + + try + { + await func(); + } + catch (Exception ex) + { + Log.Warning(ex, "Exception executing a staggered func: {ErrorMessage}", ex.Message); + } + finally + { + if (_delayMs != 0) + { + await Task.Delay(_delayMs, cancel); + } + } + } + } + + public ValueTask EnqueueAsync(Func action) + => _channel.Writer.WriteAsync(action); +} diff --git a/src/Ellie.Common/ShmartBankAmount.cs b/src/Ellie.Common/ShmartBankAmount.cs new file mode 100644 index 0000000..0a6a7d9 --- /dev/null +++ b/src/Ellie.Common/ShmartBankAmount.cs @@ -0,0 +1,19 @@ +namespace Ellie.Common; + +public readonly struct ShmartBankAmount +{ + public long Amount { get; } + public ShmartBankAmount(long amount) + { + Amount = amount; + } + + public static implicit operator ShmartBankAmount(long num) + => new(num); + + public static implicit operator long(ShmartBankAmount num) + => num.Amount; + + public static implicit operator ShmartBankAmount(int num) + => new(num); +} diff --git a/src/Ellie.Common/ShmartNumber.cs b/src/Ellie.Common/ShmartNumber.cs new file mode 100644 index 0000000..be722a0 --- /dev/null +++ b/src/Ellie.Common/ShmartNumber.cs @@ -0,0 +1,38 @@ +namespace Ellie.Common; + +public readonly struct ShmartNumber : IEquatable +{ + public long Value { get; } + + public ShmartNumber(long val) + { + Value = val; + } + + public static implicit operator ShmartNumber(long num) + => new(num); + + public static implicit operator long(ShmartNumber num) + => num.Value; + + public static implicit operator ShmartNumber(int num) + => new(num); + + public override string ToString() + => Value.ToString(); + + public override bool Equals(object? obj) + => obj is ShmartNumber sn && Equals(sn); + + public bool Equals(ShmartNumber other) + => other.Value == Value; + + public override int GetHashCode() + => Value.GetHashCode(); + + public static bool operator ==(ShmartNumber left, ShmartNumber right) + => left.Equals(right); + + public static bool operator !=(ShmartNumber left, ShmartNumber right) + => !(left == right); +} From b7f1a0a3dbe1b6af871fe591aae0e5bdc7142b0f Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 20:50:52 +1300 Subject: [PATCH 08/62] Fixed something in Canary.cs --- src/Ellie.Marmalade/Canary.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ellie.Marmalade/Canary.cs b/src/Ellie.Marmalade/Canary.cs index 5c50aa8..19f1d47 100644 --- a/src/Ellie.Marmalade/Canary.cs +++ b/src/Ellie.Marmalade/Canary.cs @@ -3,7 +3,7 @@ namespace Ellie.Canary; /// -/// The base class which will be loaded as a module into NadekoBot +/// The base class which will be loaded as a module into EllieBot /// Any user-defined snek has to inherit from this class. /// Sneks get instantiated ONLY ONCE during the loading, /// and any snek commands will be executed on the same instance. From 2a4730a1fdce4394958094830df0c5a67881e436 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 20:51:27 +1300 Subject: [PATCH 09/62] Updated Ellie.Econ --- src/Ellie.Econ/Deck/Deck.cs | 309 ++++++++++++++++++ src/Ellie.Econ/Deck/NewCard.cs | 5 + src/Ellie.Econ/Deck/NewDeck.cs | 54 +++ .../MultipleRegularDeck.cs | 28 ++ src/Ellie.Econ/Deck/Regular/RegularCard.cs | 4 + src/Ellie.Econ/Deck/Regular/RegularDeck.cs | 15 + .../Deck/Regular/RegularDeckExtensions.cs | 56 ++++ src/Ellie.Econ/Deck/Regular/RegularSuit.cs | 9 + src/Ellie.Econ/Deck/Regular/RegularValue.cs | 18 + src/Ellie.Econ/Ellie.Econ.csproj | 13 + .../Gambling/Betdraw/BetdrawColorGuess.cs | 7 + .../Gambling/Betdraw/BetdrawGame.cs | 86 +++++ .../Gambling/Betdraw/BetdrawResult.cs | 9 + .../Gambling/Betdraw/BetdrawResultType.cs | 7 + .../Gambling/Betdraw/BetdrawValueGuess.cs | 7 + .../Gambling/Betflip/BetflipGame.cs | 33 ++ .../Gambling/Betflip/BetflipResult.cs | 8 + .../Gambling/Betroll/BetrollGame.cs | 42 +++ .../Gambling/Betroll/BetrollResult.cs | 9 + src/Ellie.Econ/Gambling/Rps/RpsGame.cs | 75 +++++ src/Ellie.Econ/Gambling/Slot/SlotGame.cs | 116 +++++++ src/Ellie.Econ/Gambling/Slot/SlotResult.cs | 9 + src/Ellie.Econ/Gambling/Wof/LuLaResult.cs | 9 + src/Ellie.Econ/Gambling/Wof/WofGame.cs | 34 ++ src/Ellie.Econ/GlobalUsings.cs | 1 + 25 files changed, 963 insertions(+) create mode 100644 src/Ellie.Econ/Deck/Deck.cs create mode 100644 src/Ellie.Econ/Deck/NewCard.cs create mode 100644 src/Ellie.Econ/Deck/NewDeck.cs create mode 100644 src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs create mode 100644 src/Ellie.Econ/Deck/Regular/RegularCard.cs create mode 100644 src/Ellie.Econ/Deck/Regular/RegularDeck.cs create mode 100644 src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs create mode 100644 src/Ellie.Econ/Deck/Regular/RegularSuit.cs create mode 100644 src/Ellie.Econ/Deck/Regular/RegularValue.cs create mode 100644 src/Ellie.Econ/Ellie.Econ.csproj create mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs create mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs create mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs create mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs create mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs create mode 100644 src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs create mode 100644 src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs create mode 100644 src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs create mode 100644 src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs create mode 100644 src/Ellie.Econ/Gambling/Rps/RpsGame.cs create mode 100644 src/Ellie.Econ/Gambling/Slot/SlotGame.cs create mode 100644 src/Ellie.Econ/Gambling/Slot/SlotResult.cs create mode 100644 src/Ellie.Econ/Gambling/Wof/LuLaResult.cs create mode 100644 src/Ellie.Econ/Gambling/Wof/WofGame.cs create mode 100644 src/Ellie.Econ/GlobalUsings.cs diff --git a/src/Ellie.Econ/Deck/Deck.cs b/src/Ellie.Econ/Deck/Deck.cs new file mode 100644 index 0000000..78f5dd0 --- /dev/null +++ b/src/Ellie.Econ/Deck/Deck.cs @@ -0,0 +1,309 @@ +#nullable disable +namespace Ellie.Econ; + +public class Deck +{ + public enum CardSuit + { + Spades = 1, + Hearts = 2, + Diamonds = 3, + Clubs = 4 + } + + private static readonly Dictionary _cardNames = new() + { + { 1, "Ace" }, + { 2, "Two" }, + { 3, "Three" }, + { 4, "Four" }, + { 5, "Five" }, + { 6, "Six" }, + { 7, "Seven" }, + { 8, "Eight" }, + { 9, "Nine" }, + { 10, "Ten" }, + { 11, "Jack" }, + { 12, "Queen" }, + { 13, "King" } + }; + + private static Dictionary, bool>> handValues; + + public List CardPool { get; set; } + private readonly Random _r = new EllieRandom(); + + static Deck() + => InitHandValues(); + + /// + /// Creates a new instance of the BlackJackGame, this allows you to create multiple games running at one time. + /// + public Deck() + => RefillPool(); + + /// + /// Restart the game of blackjack. It will only refill the pool for now. Probably wont be used, unless you want to have + /// only 1 bjg running at one time, + /// then you will restart the same game every time. + /// + public void Restart() + => RefillPool(); + + /// + /// Removes all cards from the pool and refills the pool with all of the possible cards. NOTE: I think this is too + /// expensive. + /// We should probably make it so it copies another premade list with all the cards, or something. + /// + protected virtual void RefillPool() + { + CardPool = new(52); + //foreach suit + for (var j = 1; j < 14; j++) + // and number + for (var i = 1; i < 5; i++) + //generate a card of that suit and number and add it to the pool + + // the pool will go from ace of spades,hears,diamonds,clubs all the way to the king of spades. hearts, ... + CardPool.Add(new((CardSuit)i, j)); + } + + /// + /// Take a card from the pool, you either take it from the top if the deck is shuffled, or from a random place if the + /// deck is in the default order. + /// + /// A card from the pool + public Card Draw() + { + if (CardPool.Count == 0) + Restart(); + //you can either do this if your deck is not shuffled + + var num = _r.Next(0, CardPool.Count); + var c = CardPool[num]; + CardPool.RemoveAt(num); + return c; + + // if you want to shuffle when you fill, then take the first one + /* + Card c = cardPool[0]; + cardPool.RemoveAt(0); + return c; + */ + } + + /// + /// Shuffles the deck. Use this if you want to take cards from the top of the deck, instead of randomly. See DrawACard + /// method. + /// + private void Shuffle() + { + if (CardPool.Count <= 1) + return; + var orderedPool = CardPool.Shuffle(); + CardPool ??= orderedPool.ToList(); + } + + public override string ToString() + => string.Concat(CardPool.Select(c => c.ToString())) + Environment.NewLine; + + private static void InitHandValues() + { + bool HasPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 1; + } + + bool IsPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 3) == 0 && HasPair(cards); + } + + bool IsTwoPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 2; + } + + bool IsStraight(List cards) + { + if (cards.GroupBy(card => card.Number).Count() != cards.Count()) + return false; + var toReturn = cards.Max(card => card.Number) - cards.Min(card => card.Number) == 4; + if (toReturn || cards.All(c => c.Number != 1)) + return toReturn; + + var newCards = cards.Select(c => c.Number == 1 ? new(c.Suit, 14) : c).ToArray(); + return newCards.Max(card => card.Number) - newCards.Min(card => card.Number) == 4; + } + + bool HasThreeOfKind(List cards) + { + return cards.GroupBy(card => card.Number).Any(group => group.Count() == 3); + } + + bool IsThreeOfKind(List cards) + { + return HasThreeOfKind(cards) && !HasPair(cards); + } + + bool IsFlush(List cards) + { + return cards.GroupBy(card => card.Suit).Count() == 1; + } + + bool IsFourOfKind(List cards) + { + return cards.GroupBy(card => card.Number).Any(group => group.Count() == 4); + } + + bool IsFullHouse(List cards) + { + return HasPair(cards) && HasThreeOfKind(cards); + } + + bool HasStraightFlush(List cards) + { + return IsFlush(cards) && IsStraight(cards); + } + + bool IsRoyalFlush(List cards) + { + return cards.Min(card => card.Number) == 1 + && cards.Max(card => card.Number) == 13 + && HasStraightFlush(cards); + } + + bool IsStraightFlush(List cards) + { + return HasStraightFlush(cards) && !IsRoyalFlush(cards); + } + + handValues = new() + { + { "Royal Flush", IsRoyalFlush }, + { "Straight Flush", IsStraightFlush }, + { "Four Of A Kind", IsFourOfKind }, + { "Full House", IsFullHouse }, + { "Flush", IsFlush }, + { "Straight", IsStraight }, + { "Three Of A Kind", IsThreeOfKind }, + { "Two Pairs", IsTwoPair }, + { "A Pair", IsPair } + }; + } + + public static string GetHandValue(List cards) + { + if (handValues is null) + InitHandValues(); + + foreach (var kvp in handValues.Where(x => x.Value(cards))) + return kvp.Key; + return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetValueText() ?? cards.Max().GetValueText()); + } + + public class Card : IComparable + { + private static readonly IReadOnlyDictionary _suitToSuitChar = new Dictionary + { + { CardSuit.Diamonds, "♦" }, + { CardSuit.Clubs, "♣" }, + { CardSuit.Spades, "♠" }, + { CardSuit.Hearts, "♥" } + }; + + private static readonly IReadOnlyDictionary _suitCharToSuit = new Dictionary + { + { "♦", CardSuit.Diamonds }, + { "d", CardSuit.Diamonds }, + { "♣", CardSuit.Clubs }, + { "c", CardSuit.Clubs }, + { "♠", CardSuit.Spades }, + { "s", CardSuit.Spades }, + { "♥", CardSuit.Hearts }, + { "h", CardSuit.Hearts } + }; + + private static readonly IReadOnlyDictionary _numberCharToNumber = new Dictionary + { + { 'a', 1 }, + { '2', 2 }, + { '3', 3 }, + { '4', 4 }, + { '5', 5 }, + { '6', 6 }, + { '7', 7 }, + { '8', 8 }, + { '9', 9 }, + { 't', 10 }, + { 'j', 11 }, + { 'q', 12 }, + { 'k', 13 } + }; + + public CardSuit Suit { get; } + public int Number { get; } + + public string FullName + { + get + { + var str = string.Empty; + + if (Number is <= 10 and > 1) + str += "_" + Number; + else + str += GetValueText().ToLowerInvariant(); + return str + "_of_" + Suit.ToString().ToLowerInvariant(); + } + } + + private readonly string[] _regIndicators = + { + "🇦", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":keycap_ten:", + "🇯", "🇶", "🇰" + }; + + public Card(CardSuit s, int cardNum) + { + Suit = s; + Number = cardNum; + } + + public string GetValueText() + => _cardNames[Number]; + + public override string ToString() + => _cardNames[Number] + " Of " + Suit; + + public int CompareTo(object obj) + { + if (obj is not Card card) + return 0; + return Number - card.Number; + } + + public static Card Parse(string input) + { + if (string.IsNullOrWhiteSpace(input)) + throw new ArgumentNullException(nameof(input)); + + if (input.Length != 2 + || !_numberCharToNumber.TryGetValue(input[0], out var n) + || !_suitCharToSuit.TryGetValue(input[1].ToString(), out var s)) + throw new ArgumentException("Invalid input", nameof(input)); + + return new(s, n); + } + + public string GetEmojiString() + { + var str = string.Empty; + + str += _regIndicators[Number - 1]; + str += _suitToSuitChar[Suit]; + + return str; + } + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/NewCard.cs b/src/Ellie.Econ/Deck/NewCard.cs new file mode 100644 index 0000000..4a091a4 --- /dev/null +++ b/src/Ellie.Econ/Deck/NewCard.cs @@ -0,0 +1,5 @@ +namespace Ellie.Econ; + +public abstract record class NewCard(TSuit Suit, TValue Value) + where TSuit : struct, Enum + where TValue : struct, Enum; \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/NewDeck.cs b/src/Ellie.Econ/Deck/NewDeck.cs new file mode 100644 index 0000000..a71406c --- /dev/null +++ b/src/Ellie.Econ/Deck/NewDeck.cs @@ -0,0 +1,54 @@ +namespace Ellie.Econ; + +public abstract class NewDeck + where TCard: NewCard + where TSuit : struct, Enum + where TValue : struct, Enum +{ + protected static readonly TSuit[] _suits = Enum.GetValues(); + protected static readonly TValue[] _values = Enum.GetValues(); + + public virtual int CurrentCount + => _cards.Count; + + public virtual int TotalCount { get; } + + protected readonly LinkedList _cards = new(); + public NewDeck() + { + TotalCount = _suits.Length * _values.Length; + } + + public virtual TCard? Draw() + { + var first = _cards.First; + if (first is not null) + { + _cards.RemoveFirst(); + return first.Value; + } + + return null; + } + + public virtual TCard? Peek(int x = 0) + { + var card = _cards.First; + for (var i = 0; i < x; i++) + { + card = card?.Next; + } + + return card?.Value; + } + + public virtual void Shuffle() + { + var cards = _cards.ToList(); + var newCards = cards.Shuffle(); + + _cards.Clear(); + foreach (var card in newCards) + _cards.AddFirst(card); + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs b/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs new file mode 100644 index 0000000..2a7e7df --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs @@ -0,0 +1,28 @@ +namespace Ellie.Econ; + +public class MultipleRegularDeck : NewDeck +{ + private int Decks { get; } + + public override int TotalCount { get; } + + public MultipleRegularDeck(int decks = 1) + { + if (decks < 1) + throw new ArgumentOutOfRangeException(nameof(decks), "Has to be more than 0"); + + Decks = decks; + TotalCount = base.TotalCount * decks; + + for (var i = 0; i < Decks; i++) + { + foreach (var suit in _suits) + { + foreach (var val in _values) + { + _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); + } + } + } + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularCard.cs b/src/Ellie.Econ/Deck/Regular/RegularCard.cs new file mode 100644 index 0000000..337a1ff --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularCard.cs @@ -0,0 +1,4 @@ +namespace Ellie.Econ; + +public sealed record class RegularCard(RegularSuit Suit, RegularValue Value) + : NewCard(Suit, Value); \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularDeck.cs b/src/Ellie.Econ/Deck/Regular/RegularDeck.cs new file mode 100644 index 0000000..6997623 --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularDeck.cs @@ -0,0 +1,15 @@ +namespace Ellie.Econ; + +public sealed class RegularDeck : NewDeck +{ + public RegularDeck() + { + foreach (var suit in _suits) + { + foreach (var val in _values) + { + _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); + } + } + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs b/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs new file mode 100644 index 0000000..98c880c --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs @@ -0,0 +1,56 @@ +namespace Ellie.Econ; + +public static class RegularDeckExtensions +{ + public static string GetEmoji(this RegularSuit suit) + => suit switch + { + RegularSuit.Hearts => "♥️", + RegularSuit.Spades => "♠️", + RegularSuit.Diamonds => "♦️", + _ => "♣️", + }; + + public static string GetEmoji(this RegularValue value) + => value switch + { + RegularValue.Ace => "🇦", + RegularValue.Two => "2️⃣", + RegularValue.Three => "3️⃣", + RegularValue.Four => "4️⃣", + RegularValue.Five => "5️⃣", + RegularValue.Six => "6️⃣", + RegularValue.Seven => "7️⃣", + RegularValue.Eight => "8️⃣", + RegularValue.Nine => "9️⃣", + RegularValue.Ten => "🔟", + RegularValue.Jack => "🇯", + RegularValue.Queen => "🇶", + _ => "🇰", + }; + + public static string GetEmoji(this RegularCard card) + => $"{card.Value.GetEmoji()} {card.Suit.GetEmoji()}"; + + public static string GetName(this RegularValue value) + => value.ToString(); + + public static string GetName(this RegularSuit suit) + => suit.ToString(); + + public static string GetName(this RegularCard card) + => $"{card.Value.ToString()} of {card.Suit.GetName()}"; +} + + + + + + + + + + + + + diff --git a/src/Ellie.Econ/Deck/Regular/RegularSuit.cs b/src/Ellie.Econ/Deck/Regular/RegularSuit.cs new file mode 100644 index 0000000..dc4167b --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularSuit.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ; + +public enum RegularSuit +{ + Hearts, + Diamonds, + Clubs, + Spades +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularValue.cs b/src/Ellie.Econ/Deck/Regular/RegularValue.cs new file mode 100644 index 0000000..8aa9171 --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularValue.cs @@ -0,0 +1,18 @@ +namespace Ellie.Econ; + +public enum RegularValue +{ + Ace = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, + Eight = 8, + Nine = 9, + Ten = 10, + Jack = 12, + Queen = 13, + King = 14, +} \ No newline at end of file diff --git a/src/Ellie.Econ/Ellie.Econ.csproj b/src/Ellie.Econ/Ellie.Econ.csproj new file mode 100644 index 0000000..038763e --- /dev/null +++ b/src/Ellie.Econ/Ellie.Econ.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs new file mode 100644 index 0000000..7ecd3bd --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs @@ -0,0 +1,7 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public enum BetdrawColorGuess +{ + Red, + Black +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs new file mode 100644 index 0000000..d52ae43 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs @@ -0,0 +1,86 @@ +using Serilog; + +namespace Ellie.Econ.Gambling.Betdraw; + +public sealed class BetdrawGame +{ + private static readonly EllieRandom _rng = new(); + private readonly RegularDeck _deck; + + private const decimal SINGLE_GUESS_MULTI = 2.075M; + private const decimal DOUBLE_GUESS_MULTI = 4.15M; + + public BetdrawGame() + { + _deck = new RegularDeck(); + } + + public BetdrawResult Draw(BetdrawValueGuess? val, BetdrawColorGuess? col, decimal amount) + { + if (val is null && col is null) + throw new ArgumentNullException(nameof(val)); + + var card = _deck.Peek(_rng.Next(0, 52))!; + + var realVal = (int)card.Value < 7 + ? BetdrawValueGuess.Low + : BetdrawValueGuess.High; + + var realCol = card.Suit is RegularSuit.Diamonds or RegularSuit.Hearts + ? BetdrawColorGuess.Red + : BetdrawColorGuess.Black; + + // if card is 7, autoloss + if (card.Value == RegularValue.Seven) + { + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card, + }; + } + + byte win = 0; + if (val is BetdrawValueGuess valGuess) + { + if (realVal != valGuess) + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card + }; + + ++win; + } + + if (col is BetdrawColorGuess colGuess) + { + if (realCol != colGuess) + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card + }; + + ++win; + } + + var multi = win == 1 + ? SINGLE_GUESS_MULTI + : DOUBLE_GUESS_MULTI; + + return new() + { + Won = amount * multi, + Multiplier = multi, + ResultType = BetdrawResultType.Win, + Card = card + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs new file mode 100644 index 0000000..82661ac --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public readonly struct BetdrawResult +{ + public decimal Won { get; init; } + public decimal Multiplier { get; init; } + public BetdrawResultType ResultType { get; init; } + public RegularCard Card { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs new file mode 100644 index 0000000..371b8fa --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs @@ -0,0 +1,7 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public enum BetdrawResultType +{ + Win, + Lose +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs new file mode 100644 index 0000000..caf2a14 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs @@ -0,0 +1,7 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public enum BetdrawValueGuess +{ + High, + Low, +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs b/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs new file mode 100644 index 0000000..d6d26aa --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs @@ -0,0 +1,33 @@ +namespace Ellie.Econ.Gambling; + +public sealed class BetflipGame +{ + private readonly decimal _winMulti; + private static readonly EllieRandom _rng = new EllieRandom(); + + public BetflipGame(decimal winMulti) + { + _winMulti = winMulti; + } + + public BetflipResult Flip(byte guess, decimal amount) + { + var side = (byte)_rng.Next(0, 2); + if (side == guess) + { + return new BetflipResult() + { + Side = side, + Won = amount * _winMulti, + Multiplier = _winMulti + }; + } + + return new BetflipResult() + { + Side = side, + Won = 0, + Multiplier = 0, + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs b/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs new file mode 100644 index 0000000..8763f50 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs @@ -0,0 +1,8 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct BetflipResult +{ + public decimal Won { get; init; } + public byte Side { get; init; } + public decimal Multiplier { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs b/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs new file mode 100644 index 0000000..5938957 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs @@ -0,0 +1,42 @@ +namespace Ellie.Econ.Gambling; + +public sealed class BetrollGame +{ + private readonly (int WhenAbove, decimal MultiplyBy)[] _thresholdPairs; + private readonly EllieRandom _rng; + + public BetrollGame(IReadOnlyList<(int WhenAbove, decimal MultiplyBy)> pairs) + { + _thresholdPairs = pairs.OrderByDescending(x => x.WhenAbove).ToArray(); + _rng = new(); + } + + public BetrollResult Roll(decimal amount = 0) + { + var roll = _rng.Next(1, 101); + + for (var i = 0; i < _thresholdPairs.Length; i++) + { + ref var pair = ref _thresholdPairs[i]; + + if (pair.WhenAbove < roll) + { + return new() + { + Multiplier = pair.MultiplyBy, + Roll = roll, + Threshold = pair.WhenAbove, + Won = amount * pair.MultiplyBy + }; + } + } + + return new() + { + Multiplier = 0, + Roll = roll, + Threshold = -1, + Won = 0, + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs b/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs new file mode 100644 index 0000000..ddafa5c --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct BetrollResult +{ + public int Roll { get; init; } + public decimal Multiplier { get; init; } + public decimal Threshold { get; init; } + public decimal Won { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Rps/RpsGame.cs b/src/Ellie.Econ/Gambling/Rps/RpsGame.cs new file mode 100644 index 0000000..8d3c623 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Rps/RpsGame.cs @@ -0,0 +1,75 @@ +namespace Ellie.Econ.Gambling.Rps; + +public sealed class RpsGame +{ + private static readonly EllieRandom _rng = new EllieRandom(); + + const decimal WIN_MULTI = 1.95m; + const decimal DRAW_MULTI = 1m; + const decimal LOSE_MULTI = 0m; + + public RpsGame() + { + + } + + public RpsResult Play(RpsPick pick, decimal amount) + { + var compPick = (RpsPick)_rng.Next(0, 3); + if (compPick == pick) + { + return new() + { + Won = amount * DRAW_MULTI, + Multiplier = DRAW_MULTI, + ComputerPick = compPick, + Result = RpsResultType.Draw, + }; + } + + if ((compPick == RpsPick.Paper && pick == RpsPick.Rock) + || (compPick == RpsPick.Rock && pick == RpsPick.Scissors) + || (compPick == RpsPick.Scissors && pick == RpsPick.Paper)) + { + return new() + { + Won = amount * LOSE_MULTI, + Multiplier = LOSE_MULTI, + Result = RpsResultType.Lose, + ComputerPick = compPick, + }; + } + + return new() + { + Won = amount * WIN_MULTI, + Multiplier = WIN_MULTI, + Result = RpsResultType.Win, + ComputerPick = compPick, + }; + } +} + +public enum RpsPick : byte +{ + Rock = 0, + Paper = 1, + Scissors = 2, +} + +public enum RpsResultType : byte +{ + Win, + Draw, + Lose +} + + + +public readonly struct RpsResult +{ + public decimal Won { get; init; } + public decimal Multiplier { get; init; } + public RpsResultType Result { get; init; } + public RpsPick ComputerPick { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Slot/SlotGame.cs b/src/Ellie.Econ/Gambling/Slot/SlotGame.cs new file mode 100644 index 0000000..f6cddb9 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Slot/SlotGame.cs @@ -0,0 +1,116 @@ +namespace Ellie.Econ.Gambling; + +//here is a payout chart +//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg +//thanks to judge for helping me with this +public class SlotGame +{ + private static readonly EllieRandom _rng = new EllieRandom(); + + public SlotResult Spin(decimal bet) + { + var rolls = new[] + { + (byte)_rng.Next(0, 6), + (byte)_rng.Next(0, 6), + (byte)_rng.Next(0, 6) + }; + + ref var a = ref rolls[0]; + ref var b = ref rolls[1]; + ref var c = ref rolls[2]; + + var multi = 0; + var winType = SlotWinType.None; + if (a == b && b == c) + { + if (a == 5) + { + winType = SlotWinType.TrippleJoker; + multi = 30; + } + else + { + winType = SlotWinType.TrippleNormal; + multi = 10; + } + } + else if (a == 5 && (b == 5 || c == 5) + || (b == 5 && c == 5)) + { + winType = SlotWinType.DoubleJoker; + multi = 4; + } + else if (a == 5 || b == 5 || c == 5) + { + winType = SlotWinType.SingleJoker; + multi = 1; + } + + return new() + { + Won = bet * multi, + WinType = winType, + Multiplier = multi, + Rolls = rolls, + }; + } +} + +public enum SlotWinType : byte +{ + None, + SingleJoker, + DoubleJoker, + TrippleNormal, + TrippleJoker, +} + +/* +var rolls = new[] + { + _rng.Next(default(byte), 6), + _rng.Next(default(byte), 6), + _rng.Next(default(byte), 6) + }; + + var multi = 0; + var winType = SlotWinType.None; + + ref var a = ref rolls[0]; + ref var b = ref rolls[1]; + ref var c = ref rolls[2]; + if (a == b && b == c) + { + if (a == 5) + { + winType = SlotWinType.TrippleJoker; + multi = 30; + } + else + { + winType = SlotWinType.TrippleNormal; + multi = 10; + } + } + else if (a == 5 && (b == 5 || c == 5) + || (b == 5 && c == 5)) + { + winType = SlotWinType.DoubleJoker; + multi = 4; + } + else if (rolls.Any(x => x == 5)) + { + winType = SlotWinType.SingleJoker; + multi = 1; + } + + return new() + { + Won = bet * multi, + WinType = winType, + Multiplier = multi, + Rolls = rolls, + }; + } +*/ \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Slot/SlotResult.cs b/src/Ellie.Econ/Gambling/Slot/SlotResult.cs new file mode 100644 index 0000000..42d3630 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Slot/SlotResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct SlotResult +{ + public decimal Multiplier { get; init; } + public byte[] Rolls { get; init; } + public decimal Won { get; init; } + public SlotWinType WinType { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs b/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs new file mode 100644 index 0000000..0f98e1a --- /dev/null +++ b/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct LuLaResult +{ + public int Index { get; init; } + public decimal Multiplier { get; init; } + public decimal Won { get; init; } + public IReadOnlyList Multipliers { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Wof/WofGame.cs b/src/Ellie.Econ/Gambling/Wof/WofGame.cs new file mode 100644 index 0000000..d76a215 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Wof/WofGame.cs @@ -0,0 +1,34 @@ +namespace Ellie.Econ.Gambling; + +public sealed class LulaGame +{ + private static readonly IReadOnlyList DEFAULT_MULTIPLIERS = new[] { 1.7M, 1.5M, 0.2M, 0.1M, 0.3M, 0.5M, 1.2M, 2.4M }; + + private readonly IReadOnlyList _multipliers; + private static readonly EllieRandom _rng = new(); + + public LulaGame(IReadOnlyList multipliers) + { + _multipliers = multipliers; + } + + public LulaGame() : this(DEFAULT_MULTIPLIERS) + { + } + + public LuLaResult Spin(long bet) + { + var result = _rng.Next(0, _multipliers.Count); + + var multi = _multipliers[result]; + var amount = bet * multi; + + return new() + { + Index = result, + Multiplier = multi, + Won = amount, + Multipliers = _multipliers.ToArray(), + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/GlobalUsings.cs b/src/Ellie.Econ/GlobalUsings.cs new file mode 100644 index 0000000..a197f0b --- /dev/null +++ b/src/Ellie.Econ/GlobalUsings.cs @@ -0,0 +1 @@ +global using Ellie.Common; \ No newline at end of file From 487d1ce448cd4bfc8feaaaffd8878056df3ec229 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 23 Mar 2024 21:20:01 +1300 Subject: [PATCH 10/62] Added base files for EllieBot project --- src/EllieBot/.editorconfig | 359 +++++++++++++++++++++++++++++ src/EllieBot/Directory.Build.props | 7 + src/EllieBot/EllieBot.csproj | 139 ++++++++++- src/EllieBot/ellie_icon.ico | Bin 0 -> 4286 bytes src/EllieBot/libopus.so | Bin 0 -> 1722328 bytes src/EllieBot/libsodium.dll | Bin 0 -> 399872 bytes src/EllieBot/libsodium.so | Bin 0 -> 1999216 bytes src/EllieBot/opus.dll | Bin 0 -> 261632 bytes 8 files changed, 502 insertions(+), 3 deletions(-) create mode 100644 src/EllieBot/.editorconfig create mode 100644 src/EllieBot/Directory.Build.props create mode 100644 src/EllieBot/ellie_icon.ico create mode 100644 src/EllieBot/libopus.so create mode 100644 src/EllieBot/libsodium.dll create mode 100644 src/EllieBot/libsodium.so create mode 100644 src/EllieBot/opus.dll diff --git a/src/EllieBot/.editorconfig b/src/EllieBot/.editorconfig new file mode 100644 index 0000000..041e023 --- /dev/null +++ b/src/EllieBot/.editorconfig @@ -0,0 +1,359 @@ +root = true +# Remove the line below if you want to inherit .editorconfig settings from higher directories + +[obj/**] +generated_code = true + +# C# files +[*.cs] + + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = always:error + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion +dotnet_style_prefer_conditional_expression_over_return = false:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true:suggestion + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:warning + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = true +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:suggestion +csharp_style_expression_bodied_constructors = when_on_single_line:suggestion +csharp_style_expression_bodied_indexers = true:suggestion +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = true:suggestion +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +csharp_style_expression_bodied_operators = when_on_single_line:suggestion +csharp_style_expression_bodied_properties = true:suggestion + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:error +csharp_style_pattern_matching_over_is_with_cast_check = true:error +csharp_style_prefer_not_pattern = true:error +csharp_style_prefer_pattern_matching = true:suggestion +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:error + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async + +# Code-block preferences +csharp_prefer_braces = when_multiline:warning +csharp_prefer_simple_using_statement = true + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true:error +csharp_style_inlined_variable_declaration = true:warning +csharp_style_pattern_local_over_anonymous_function = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_range_operator = true +csharp_style_throw_expression = true:error +csharp_style_unused_value_assignment_preference = discard_variable:warning +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:error + +# Enforce file-scoped namespaces +csharp_style_namespace_declarations = file_scoped:error + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +csharp_style_allow_embedded_statements_on_same_line_experimental = false + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.private_readonly_field.symbols = private_readonly_field +dotnet_naming_rule.private_readonly_field.style = begins_with_underscore +dotnet_naming_rule.private_readonly_field.severity = warning + +dotnet_naming_rule.private_field.symbols = private_field +dotnet_naming_rule.private_field.style = camel_case +dotnet_naming_rule.private_field.severity = warning + +dotnet_naming_rule.const_fields.symbols = const_fields +dotnet_naming_rule.const_fields.style = all_upper +dotnet_naming_rule.const_fields.severity = warning + +# dotnet_naming_rule.class_should_be_pascal_case.severity = error +# dotnet_naming_rule.class_should_be_pascal_case.symbols = class +# dotnet_naming_rule.class_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.struct_should_be_pascal_case.severity = error +dotnet_naming_rule.struct_should_be_pascal_case.symbols = struct +dotnet_naming_rule.struct_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = error +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +# dotnet_naming_rule.types_should_be_pascal_case.severity = error +# dotnet_naming_rule.types_should_be_pascal_case.symbols = types +# dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +# dotnet_naming_rule.enum_should_be_pascal_case.severity = error +# dotnet_naming_rule.enum_should_be_pascal_case.symbols = enum +# dotnet_naming_rule.enum_should_be_pascal_case.style = pascal_case + +# dotnet_naming_rule.property_should_be_pascal_case.severity = error +# dotnet_naming_rule.property_should_be_pascal_case.symbols = property +# dotnet_naming_rule.property_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.method_should_be_pascal_case.severity = error +dotnet_naming_rule.method_should_be_pascal_case.symbols = method +dotnet_naming_rule.method_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.async_method_should_be_ends_with_async.severity = error +dotnet_naming_rule.async_method_should_be_ends_with_async.symbols = async_method +dotnet_naming_rule.async_method_should_be_ends_with_async.style = ends_with_async + +# dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = error +# dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +# dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.local_variable_should_be_camel_case.severity = error +dotnet_naming_rule.local_variable_should_be_camel_case.symbols = local_variable +dotnet_naming_rule.local_variable_should_be_camel_case.style = camel_case + +# Symbol specifications + +dotnet_naming_symbols.const_fields.required_modifiers = const +dotnet_naming_symbols.const_fields.applicable_kinds = field + +dotnet_naming_symbols.class.applicable_kinds = class +dotnet_naming_symbols.class.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.class.required_modifiers = + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.struct.applicable_kinds = struct +dotnet_naming_symbols.struct.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.struct.required_modifiers = + +dotnet_naming_symbols.enum.applicable_kinds = enum +dotnet_naming_symbols.enum.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enum.required_modifiers = + +dotnet_naming_symbols.method.applicable_kinds = method +dotnet_naming_symbols.method.applicable_accessibilities = public +dotnet_naming_symbols.method.required_modifiers = + +dotnet_naming_symbols.property.applicable_kinds = property +dotnet_naming_symbols.property.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.property.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.private_readonly_field.applicable_kinds = field +dotnet_naming_symbols.private_readonly_field.applicable_accessibilities = private, protected +dotnet_naming_symbols.private_readonly_field.required_modifiers = readonly + +dotnet_naming_symbols.private_field.applicable_kinds = field +dotnet_naming_symbols.private_field.applicable_accessibilities = private, protected +dotnet_naming_symbols.private_field.required_modifiers = + +dotnet_naming_symbols.async_method.applicable_kinds = method, local_function +dotnet_naming_symbols.async_method.applicable_accessibilities = * +dotnet_naming_symbols.async_method.required_modifiers = async + +dotnet_naming_symbols.local_variable.applicable_kinds = parameter, local +dotnet_naming_symbols.local_variable.applicable_accessibilities = local +dotnet_naming_symbols.local_variable.required_modifiers = + +# Naming styles + + +dotnet_naming_style.all_upper.capitalization = all_upper + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.begins_with_underscore.required_prefix = _ +dotnet_naming_style.begins_with_underscore.required_suffix = +dotnet_naming_style.begins_with_underscore.word_separator = +dotnet_naming_style.begins_with_underscore.capitalization = camel_case + +dotnet_naming_style.ends_with_async.required_prefix = +# dotnet_naming_style.ends_with_async.required_suffix = Async +dotnet_naming_style.ends_with_async.word_separator = +dotnet_naming_style.ends_with_async.capitalization = pascal_case + +dotnet_naming_style.camel_case.required_prefix = +dotnet_naming_style.camel_case.required_suffix = +dotnet_naming_style.camel_case.word_separator = +dotnet_naming_style.camel_case.capitalization = camel_case + +# CA1822: Mark members as static +dotnet_diagnostic.ca1822.severity = suggestion + +# IDE0004: Cast is redundant +dotnet_diagnostic.ide0004.severity = warning + +# IDE0058: Expression value is never used +dotnet_diagnostic.ide0058.severity = none + +# # IDE0011: Add braces to 'if'/'else' statement +# dotnet_diagnostic.ide0011.severity = none + +resharper_wrap_after_invocation_lpar = false +resharper_wrap_before_invocation_rpar = false + +# ReSharper properties +resharper_align_multiline_calls_chain = true +resharper_csharp_wrap_after_declaration_lpar = true +resharper_csharp_wrap_after_invocation_lpar = false +resharper_csharp_wrap_before_binary_opsign = true +resharper_csharp_wrap_before_invocation_rpar = false +resharper_csharp_wrap_parameters_style = chop_if_long +resharper_force_chop_compound_if_expression = false +resharper_keep_existing_linebreaks = true +resharper_keep_user_linebreaks = true +resharper_max_formal_parameters_on_line = 3 +resharper_place_simple_embedded_statement_on_same_line = false +resharper_wrap_chained_binary_expressions = chop_if_long +resharper_wrap_chained_binary_patterns = chop_if_long +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_object_and_collection_initializer_style = chop_always + +resharper_csharp_wrap_before_first_type_parameter_constraint = true +resharper_csharp_place_type_constraints_on_same_line = false +resharper_csharp_wrap_before_extends_colon = true +resharper_csharp_place_constructor_initializer_on_same_line = false +resharper_force_attribute_style = separate +resharper_csharp_braces_for_ifelse = required_for_multiline_statement +resharper_csharp_braces_for_foreach = required_for_multiline +resharper_csharp_braces_for_while = required_for_multiline +resharper_csharp_braces_for_for = required_for_multiline +resharper_arrange_redundant_parentheses_highlighting = hint + +# IDE0011: Add braces +dotnet_diagnostic.IDE0011.severity = warning diff --git a/src/EllieBot/Directory.Build.props b/src/EllieBot/Directory.Build.props new file mode 100644 index 0000000..1623cb0 --- /dev/null +++ b/src/EllieBot/Directory.Build.props @@ -0,0 +1,7 @@ + + + + all + + + \ No newline at end of file diff --git a/src/EllieBot/EllieBot.csproj b/src/EllieBot/EllieBot.csproj index 74abf5c..42d6327 100644 --- a/src/EllieBot/EllieBot.csproj +++ b/src/EllieBot/EllieBot.csproj @@ -1,10 +1,143 @@ - + - Exe net6.0 - enable + preview enable + true + true + + + $(MSBuildProjectDirectory) + exe + ellie_icon.ico + + + + + CS1066 + + + + + all + True + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + True + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Protos\coordinator.proto + + + PreserveNewest + + + PreserveNewest + + + Always + + + + + 4.0.0 + $(VersionPrefix).$(VersionSuffix) + $(VersionPrefix) + + + + + false + GLOBAL_ELLIE + $(NoWarn);CS1573;CS1591 + true + portable + false diff --git a/src/EllieBot/ellie_icon.ico b/src/EllieBot/ellie_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f35e7f2ae596f168a65a5f1c9446f9d6f4981ee2 GIT binary patch literal 4286 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 NyhYg0X5a#o{tr2i2aW&$ literal 0 HcmV?d00001 diff --git a/src/EllieBot/libopus.so b/src/EllieBot/libopus.so new file mode 100644 index 0000000000000000000000000000000000000000..2fb07c3134149e054aec9ed879ea4481f5206350 GIT binary patch literal 1722328 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 Mr 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�uNFh$F1P)23-O7(E-TC+X-S~OF(mkP8>!)q~uU*tt(&5H@U8x1R z?v!&%6g9$!JvfoZo+rl7abGJRC`H40$?kRJF+o8M$`4~_=7V~HI?{xC>4K`aLAuKT zJ}!BA&(e9Hdo4pjVwm@AXy?^Vo^RoGq1JoLOZvj?SIbKw%YNCARc{@WhwGnC*R zL~3t3#}Lt_suXKF=69}Obb#Xhlo%$jJ}?fo+OLd+r@@P+V|AL(;ark7h;J|HyfW{n*3T4tuB0=wZ$$|0Lr&GKtfg5C=R4(vkT7R@FyhR~ zjkvMg-fa80Q$CI``go;8?CFJ^;){q2b`LU%Dj-^wLGQtmm& z?S7M=%OZV8VIA%HJ!T$FkE3iN%t)Z7c+j3DyNvqwlZTLJW_)v>%%X`Az$#8$4aR&el z#rDhHhyKp1W>$yacgl-P2#?iKGCjzVKA+a;YI#wr*=%%WStZAbouz_%OaWq#=|y~# z56&Peq`kZQuvCTry6x`K;gZfU8W#phu|20K8RiXp?@edIQ~kBOhyc$d+AZBl^owU3 zzRT{!`|s2Cvs&WT?>fVwuDg3_k5-vi>XsKJ<(H%eZyTW>cjgq(Rv>izp0BbWgKyLG z#LTze^Vzs_HcdfH!zH`z>3McnIhg_j;qIQMw%q7BtxYEj8}?vaZg=2%owVl^_!btz zNf?DCb&|fwMZnq6!zYWFqgn2E6`t@TYwHeSa9h*KTnP78ZB_PBfM2qMk>Tppebk-i z>t{O9X-qA4rUv`_?cGq&XdC?#{SIO~+`%Ou%lZycoZ$TR=CRlRvQZOTY z&h|*?ox5k;gzywXuskkL-;}S!Vmj6;|Lm@k9Tz=kzgKcN)A~Qq`fwv2 zoR8oGBlM*0^aeSM4dU-abS(@O#rBNX=GZ!rOLSFM-Z&tg_XPbr9rkrauAH8Gcf~o= zCxSuYWi5J(z+jiK8maW8D*0NeqLnz7{@K&VMOON=OZS{JXJXU$ihcDjFFT}nSd1Q> zbF2siF5+upy2q{b=Ytr(WF=Ddshv!ylCN7S`>6A zO~2Cp+00V?-@r#7iHwwQndxW?cOOoCh&uqG5gP7{yYa7_rr%NPaUcD~#I}V#hPi`c zdvy{i5$t{B{cX;4Ltk8fe$znFy=7~h^1O(1 z%eb(?aF8cA?AsO%ZM)|)aYs@2!s=UI`N}**3VWJTxe?Gk+?vX5I&pU6b{gqEWS1BC z<`jm{f$~fbY+D1;V~$!xPdNa$LRn}5o15ImPupGYY+tIDj%yxf8A?Om#*!TZxabT> zLX9xVVUqIuuu}$IV8QJD-G^?POK8x@MQ^6A1SveSBiqqVxMZFJcL_b{{$i#M2^O%4=ChYqgYCx>J$R^rCw&WJl8)%RFbb z_jh(5`p4{Z`c}#wrnP5m*o}>~+xquhJSRwF$HDp$`m+*X8ah06pA7vW3Qj^G8Twnu99^ z?3OM3rPAVHVS6MvPp@OzQ&FC)ked5ouxoqI&ETs|YN=;tj?If$e~gU%blAOzRO7$f z9U(}TotH1mu-jzfR{x4S^J@s^76f4-_xa##YJ&mJGW-<8t!Ea`д@nAq=ffPb3 z9OesdYZ@4(EH84Nm$>tp+8KGgRBbh%%`&rA1^vuEsTZu~b%?XM%CQoAkz2;<#W4M94{MM>__z0ds-@r#;)YWdmRs%72{2S&MOASm2V|4?BTO%qth zg*5xVUU^|5!HAdila`(zgz1ZkT0jrtB^>3^)G0y%8Ezs{(Jcs0p5_K8DjqNz=p7<0 zdK}A~zf=u_GUDDIs4RJ}!rnd2^_wwH#vR67l;MA3E@IQ%aYZJdskQ1C2(b))Gq9^U zF16)iQb-h=WJOa;E@j^wAOoc?umWq^sf$`4kdPHr=zMcXkG{g2 z$HG=I=_9HS($p=d$o)#hm>Qzd)C?*<5|zH`M}N+{rZY8fsg?LL<#?_ANY~?*rC+{T zFZWVjvoGdT7iv;g@dvd2wyyuIy7Pld7gBSOim!4}{VEpYrvJPwp?w~F-}OHxpOcI8cQ(uS6j^hfk@oTD|}TSq?b8<*S`Q3>*We@~b*jy^lJ4LI4iLM4jdx zv5F6<15^_nX~65<&rO5*rcxQN1DuzOT%_b_l* z!fiu|Bf(r!xPyoH3Jzy0BSZ3c)S>ef8 zu2cMn+}6G!m{Tu)F7;H%^q7fNdhBA&Q&Nv>bMYrTMv2rnT7IvxtkhuO27O9>iVg6% zOG|KvRV>m}+eN_(d_%}e5J!-T9-7oZJzCe`V16}k*K&rDS3>@^TK%;u`LiwuT_Z)h+C){w9C&`NP9VfUyv0vetx@69lgzMM|!DHuKzp zcxbPcaKH(9gvLjW4@N=@K%GRD(CdAc_8I79(1yM8V_`ygJ{s_&)>lOs7;~*mzSi3>hj?>+jiz5KyM{s648(o1j_)zVKTx4P zN%K)orP_Y85mvLPnRRB22>-ZoDa={THc|rcL+11sJ+MQGb2sxwZSjc zfh9=;yrnG?-w##)PgVC2p$33^>-bu^Ajvs|aL`^{;v3X=0-ska{u(YV{LxjQN}mwn z(H?F_s9YKO*HfW7#vfC`xWVWyziI%vuFp!y!w7X^B_0l;H;6N@dAkxGKIV9gCbsQ< zg-?*`97uI~-STZ@t}R90x??HPm$!kzK@HpB z+g^&wl2$QZ8Crg^4;XaydwN_(Uu#b=3(OE(5zip2DV~7E)Jb~K0Yt5o4?W4x=YQDWh)nk7RGUl#*67&R z?Wt>Xov|p)X2h`>8}`pryJZ-k;jX51nK66HvyHvdsku}2q0#XVvyn~D?9TA_lxeGsj4qp+G`Y?O4;e<^t_Ve=xP9_v2ozn{_QpVnX_ zC4VV7YW;4o^_WEf4Yp#d`QNDE=6!=c=b^>8@2A{`rEkvaEgX`E@;u`DOUbZ%cM10Q zO{wfK(O#_IJ=dDD-0!QM`q%BYXY^Ld@vg(}q}gE~DZ>8=9l`i;|Lbn=6&6Mxp&W+i2asQgumU}j`TL&n_moHK5T7mf8s(uW@Ir& z)lu5gb)x%F<~-yUT+@9Z^vd0SUth^9T}M&GeE$gIzaf9WFb@xutl- zL0EoX6?Mc{L?0As$8tBi3Cx@4cg}7&Uk+AT%p_c6-2ig*m^r?7n+=CC$p92)%Aa@0HPHb zb$gb`loaWuj9G4CO&HJ7QC7C{b;D)TJ;}%##!=6l=Cx3-;zH3`8M?L=akFjDOl>0 z!}|!KnU8vK;oz!`c{U#ljDu>M{MyRjR+HBT-%=C#8c%AqYZ!O{H$i2afl55oQvZ8; zvI+6RM1F~QGO1~pUaG~W7%^PKyc5V<&aqVN0M~qyzcX7Qn>9%i7O<<-92Z3R?KYmz z#@F;HUxf#&VIRSz&&t1q|5y7Pf2Ghka=iT%c0x|{5$(Ufiv|?Jgq(9uG~njRmIeK0 z>s!Prc%BF_-ua(z#<%Op94Ochiz$wf>v7BJsK1GC987m1sc!Hez|?a3r4Nkx)~pI2 z>_UEa%y*nFHvTsQ?ikwD>#zKTw_2tBEGCFY+2<#UJ)B;mI?ONbfi#vcIQjRirM*Ial<$Pc&SjHWP*UKqVC0Ts5R!^ zu{NvzUC0cqU%2&DcGmzJ{}*y$`xSy4S{`@iOq6MV!SaYr7$aF2voblKRJgT?tcFFt zT@`iP@u>uEahG7C0$zpvY(@XR47~wNpPOnuR?lx@?lEF+{I$}iTzv$P)WuO|!^Y-@-338k*C1Ya zi4PS|hGaO8GF(hxkVCVi9%h$a@P2N*M5Y%JvroDWEuXUeD;5MvmK{D{9bhduxG z8W^4odJK(c9&P1MC2!LERzh}5*#B2R7xDi9;t4EEh|kd;?qV56#$?68Aa}a3p~B^S z*HAMw4n$Ks7)sJ0>D*I_{X~cKU2_mZekF{Zt={xhgh0od!~6$N)u9o%N`?F~fBmCy z3xy+i%;CL3bf$FIveQarzTh8FZZ@6p*Z0K|dlsD4o=tC|AkwE8JhS_{d#-9h23Y?J z6=H7AsI3=gE$C^75@%(N*l!Yh!tE-;V7yF{YDAWw=SOM@U^wREBiUJ;sjyX@=Ehg~ zhvW|;0=wd&4rZXWz88V$s)M|X5yL(<3=?wfs;7AsIR4Zs)^U#mhhceh_FaV)K=JY3 zS`U6vCznGT%NoC^Eb4V2QH$C!&M+Q7K_~DGhZ!zl#nn2<)~x5P*{uyX>a7*lglF$rrdMYxn+w6Rl3Jk`qz& zEo;I%)(S#UvPqWt%}Pn77I8b&ANHWYm_xk=EU8iEN!bYbz6e3r$yqbPHV#lYTOXM` zV%J7&TH2y`o~xEH55Ra3GX>fk{Y%=baIg0n_!<_tIX4lj63-cWiV&7bCGQmU%>v$lj#p7v#_4U zZ<3DKf6>=A9oCsJFy^s$^=l6OI5f2jmzcr)>8!-|`a`OjeKcDp+M0JidOzftI&$h3 zdZVA2NJBZc>+FPh#S`vPr9)S{Rax_04UlReM9YPmQ5<7U-c~X5E|3K6UgW=|tVj6& zw#>51K+Tt-LKK0ols?OUjsG8zGOM2=iJVU*(5mj>8M9KeGkvXHkN>88J6Lvrdp2jC zf%C6nY<=~=6sd%b8#+}!OwU;ElhcZL__i2YkC;2df2|vLxVUD-xrDC6QIJJ@OYPFFprz`$qtZ;tnTzFOD;h{Y)7e=4<~4K8NRVWUe@*;xjO0*Wvp zKB79{{pO!FaoRECb#|Ag5X z2c;LjMx^=)hhA=&W-P822Xo`jVldbB8)LIDyBO&@<8JWm3SaxRZlu&lq_`Eg(ceQx zu5s zBDAUp?a8f!+2O9i5ky5t0lO16dQ*F}Meu>oZ;x)*6~Tv~z-z^^r=39Yqa7--al$ka zM2TsZDI_37y0Da#y0G&NI%-7>jQwm^`F<0_C)C-9%?oa9V;E{6@{$+5=_lZ)FZ6O_ zZ|e!dQsE+fAZ&Nol}};H1g}iI(d5%0l*2W#DdX;}7N?RRp4gUm+HluzChtN*fR~)L zY9k$XqF92k6};DVf;vpym^%+;Lo@w6+0IEXT7tQ4RzF`!qQIt;%^ERh=J(s>ijfs= z{piAo{aWeqNXcttzH2x?>=sN6+uf$T^fj-vu{5C+uPqID@g5^Gg`vOxpRfY_Ys_G@ zAc*H<#EK>f=h=w*M6+0igrs=BeznOB*NN|27g-&T($(bu8PFhG1i*$Hg*X_Og!-0D z_d-F9*^?BlFL;03MSB4d^zVk&)(Rhy(2yR8W+rTndZy_7XwyPYC36t-a` zr&K&kHu+jgI_KE6fh*(Ad;IiC=wj zJ0Z^xFd({A4zl)=HNKs8CzoA=zD|2HF;GsE3NgAe>@WuyydI@lj#wSk0AIsOle#n9 zb%LW)b|i#hhr5_JSVL!9tIAk_QF~&64@PrFLGQx6UTxW z{Zxfp&JNcht50{qYNA+Gl8G&i_e6b@Cyp^|gn$MLexw_ZudGGt$+EabLbWPr@6P(? z#Ziy{6;;?L0!tp^!J}2C7x^Y?F9?D@jmO3xP#N>`AD%~R_Es^hz80Qbb}Oyf(PkS0pTEA=6nk!=z7E^O8Ku1b ze*SEp&%@rEGvmssHQ&)5?}ef(N%*k(8Xi!Ept)@l1vuBBsrQk+F8Y9} zrIi64Dfn4G5y{M~YW_KyRz8B?hB+bHZ1wqfuIty&tOwJPFO&a3G!`^!bad8(v`}5J zg3CMC@kcWrs08}em5(qN;{3#Uvp?sX(wvJAm^s*MP1tAs=xzFE@4Yl3oCNah?txpE zqVB-%654U^B_%0SaL2^Y5Wc8U*KN)-p zftAz^%GY}n5-}f0CxRqG>R%o*@RJj~TI`_-Vkqi9d6<&`s1z z2l;u6p^iBYI$9GBEc~3hucLscq}ykTJFK5!obR~miRVL369zBwud9F1^~Z3&6QKzW zSn+n7RLmpJ>q_sE_$6Kc1ceh^yyYD80w+Y=e?gjcg$PRO*G9#9Y+q{rDM2m&QF)#5 zI}0qyuY53h-MI$vrr0RV19}pud@$9^W@R9k{E}B^?t_qsR2A(w(Fc5cLx#Fo?mwA& z0pldkgVYt=Ctu7>^Gh>laUw!U{nrXk1oHAQOcP92;EN{r)BIpwvYpCMqIW6e)|zl< z)(_4i#0euceu_ymTTvWGeyE+|s&)H?BRlkZ;POWBSa=8aXR$Zg$Gc9-tNG^b)*P@d zzuez&O~!>J{uA8HPkMCC8|t~Vz%jv)w^u!iR*jfIe7)fntNC93wfBxwHngxY+o1;hdx+P4l@vsxzls$mcI39yH(7+8k%ha zCBX5IhVT4K%)WJ_1Sx04NI=b|fV-l^(Gw+yK_!Sl2_^829DHkGU40V zpkb~nHT1bl?O6|q#a90++{Nb;vbBB#PC5WI=FHjvC$Z72f82;R(H`j%9`k;TomG4E zDcu=%d;M1-3k;$B2(lZHxSEjI%$PbC2_7*|`c(RuSJG!nV7#lNTf7o!w*ut@DtXE) zffXOL5(`8Sq7NYcTqz2L$abka#pBFFr@`9mrdC-ltGDh|cBZA^9R*;OY9! zXV9Gbi#|zgig)+!K;W_Zi%{fLJ%5r({~7#yUu-yJo8}x?Xf)e3l+qmw%3Yx zsQ{Ug*u`xx=ev9TdGPw*0Gmff2K!siy+TRGZ-qfJ+&d^{u=s5Fh$s>&1n{{4V7eP$ z>B(!#!5^I)j|qRT#(-rv_&dscl68E+wfnMhK*+2=N`&tzzcq)whv>#)g9+K$c!=#G zbR0KbPrk${$uRrven-erf2)8i+|>~O_+H?|JzGe#&AzYAF*_(f1pqFlv8;>2uuGY#-6nl z1YRS&iXzOY6kU%#hD;8^28ycq19LW{SV$O%4p=2~H>lQA$>%TxXULVCkjPrab2o%B zIP}Gx%5^&0gVfWGAX)_!EXp4fcG}kSY+lXgVa?e*GsrFp6qT>(v*y4$ke-r<7R{Pk zQlD2>Zs8A%z1Qdm04K3TxcjsRHWuL zpGf6HQU4Ar z3tK|7xX$$!7t20B?+^9A5mmg3INACzu^5C4lC6@ClIb+LCP>`3GGoW!(N%8)G4vO@ zdgdBE{}XGJR9n|;6Q1tV!i*sO`MdhHsJ)Yo`TdGIf`T7c{B*)8vtEl)hvMe;H=D{e znN20JYr#LuP7!Cg9vzX#dVC)l6f~zxGc@`Lu6^OCTS*X}!D0Fj`M7#y=NcABy%e!`b9A~8y&d=lYCiyL5cl=O z`d`b?O@D?nPzVB#W@6VvD>)+1m2SnOUG;^Zm=k@4&-QLj zK5=?*c)uT(CvgPTb|c%10sUe(RRz8@2k++&ancJw3@nCX$b8rK%>)(j^Yz|7oKv=uxU>_G$dPp_+2csVeby)Y;!vHAG zOeMduy5?Y^8g$3}wpc8DVA6eD|K42ZF9=3V30++fyd7!JBIHJQz`m|}LZ{5fFb9-$ zsX3?s2w^PSWyix5eb|mHN}t3M!ku)lwKfuLR3xphqUtwo<=KxJYiEX09CN*KXiPEP zJjjbNyE(X&Uo&4aLcC*(ywdc6yVP6*Cg{F0>lZu9{_&1rBR2(MYuXN9i};`gqkP0u zEn9gKryzl0~?7{ZxL=a^c2d5sker3GsJ(HC`GsotJk2SO+pIECi@ zK+b_L3C?N}NpB&Jz21nem2U`$*4F7o^s=n!y$i#mrWZD)ib`G}_<7{gc(B+$fxG6| z#>098hBte=Aos226{t)&Dbju`vC(ju3lg+mX$T_ zep3*!z2Bx2pSD(CN)MV&Aj1DwE*$TH`2=7r+@h8-$%8+b<~99<&hOZI#5(Pl(_i!L zQPOHeZexz&5t%&qIT1mOsnd?8(l0LNj3{Ue{je&4hAKK`l|JAJdqdDyNs}^ZVten07!4 z9G(jfR2&Gxqm0jb`bS-MG2+T>P!_X=N!FQ%E3+q#wNxg?saJPx`@>( znWVL~1%n!EW}A!9$ePt`r<-YmIf^`J%ef4WEiuA&hKV@_>%GU-&oL z<@v3THC(2}g`;(JG9Ae|4yHh<5S17)UfVX5h@IA~?bd7wilUD>OXej`FBnY|m+z-4 zW%Y#V9fgttM>G_CMkb2OOohBB4rJR#BH&ET^W<;N)PS9+rRT)o@r0Gm)Nue5r%*CR zoAP49qneBHwux+rlZ=;a%ba0blh^_G5KM8qcZ6MPu1u1zWZj8D7F2W#2PPPfT*T%H zg^Q$5lW8zk7oFH{4ETgJOf!sh&W0i)Lfa-3BI*^65F3(n+nC}+q26#tA$>H-r@YX) zQ*-SE2OB!iaO9tDhNEz6W;hB-!>rjR;-tpKoXMS>IU{JgxnPtE_~uM4wi60==1gUj z3QlE4sinzbn>bK*qL}8fKpU`{w}XFn3q?ihlOi5EYt5x&0tLlB0TL6CE;)zJz&OTu zg&2j#m1~qI`z45k7wgNOn&+6gu%`w*j+0;!j=?f}Y9S|28^UU2Tj7~APS>-tDpxuzGSaH>3K$c83~__a|7Gb2WV*yw zo8WRf>{f}XOMXn4C}&m`Qjap!_~%_|rp#Jhz)V`rt!7D+E6vS`YU-R@H_)zsCDRT` zHqsbSvN{UU%-7lWM+@6X)LA8eoB_xt+s((K&1GjnIooH=vm%=sg# z&EbBn|1(QJ+2@Z)CK#QiMqx#gU*{9!P!ICgiBANe2e?;?-iFMx)UYS#G+Up`SW6XI z58Wsu1)XHAk>?H6#89yPG);Fmi?-x?qSg_ctx~NV_B!o= zmwBA^?Z5zp{rF#?HRu0Y0PRCqh|N`i7pyga_D*{AOnE(zEI9`cQseo?hXKAE4OO>d ztpM&AV9S{69bf?Wx{;uCwF##W13AX@cWt*U>dZl$%V4ov$)@FZ!d;B)$q4f@|KOcJ z9igPAVSKiVapne=ZIv!D*X?~xn&pr{DiZo`%sQtPhog|8ig_)sj%F^?f(O4X<~_b5 zeBb)#bp%?&tF$~VZ$CQ-NFL&0XiXHFr_EYFF$bL2f;Bj=1#56#3)bMg7OcT}IUE(v zo8@ZIUdz>>y_Ty%do5Rk_FAq6?agwXHa^os_5U4Kf8#CS8wRQ2kX&c#Ub{BCgH|(t zdG{#(Ww=k)%@Ar672bJEq|UpQGuWhXhYkQCc>eRm^OqoI1=$jg_|nsU@VI22wL-3_ zn}mbr&QRXC#8q%m+UM(K0?OC0sK-qvv0I4)wJqu(i8`kn24F1eRs4)&#;)OZ8u>BZ zeA+i2z|g`ryh7l4|9l@oOG+Hln9N@K4=ZALP=hb{uM7fn6-?R`_%- z%aBH*y_ShgzPWUf5QJt<=6A#sc*yfvBV+$SUZ{}g?F^~VT7Ev$k7m0xlfqY(o@b^1 z4#YwFoTh1v8u%m0IEfxVuL#NnD!q7{6%bbJJEb&6GYnuv$rTEsaV z;qa!0d&+!%BG>si!Vd-z^7V@%lON4BEAtvVwK#87&9lsTu^kSUCZCMCD2otJ(_u~{ z&ie`3$iSqSaa!x1VJ0vSeJ#e98mSJOQn}N%K3DuR!vo^^WSfn*6FFrV#jdEvsL?Fm zy71wX^u2Q{%xu!6Bdc3YJG zJCZpXX|1@PITBRHWGzxTdIjiBr6>>`^#x};)@T=BW9j=+OJI-%T$hl9Fb`ll?q(DqbwU?rA!1biY)JsTE-ry zx483G!s(AXeMCPT;@^>K7jN>9u^ityu)Z8XrEE9uY{qb6#h)DP!d0kI?Izx&x>ADq z6eNQ);dGpaewBHD9j(hE7)80MENd}mwmwE>&TLX4#}my>c#X?>g+qT3D2&fsv&mn# zPHU<=fO{BLAj@_9gbwBr9DuHnanf{#Xsx@hFcSD6R{1u1f%h@`Z?f*LOz148I}@3q zXhlLWfWs-g!?prjqT;*2WpwNBHpo{!L;9D+cjdxYmkWp^mOqxCmt1Ky$JvE)9djS? zJ2ucG^(QN5L^-}2iV+FlTspDBc@MYrRWnV$%d-!FHll0lddXmGoVb)R&U$b>28Atq zMrE$*@SFFCYZ^ygU`Rfr;%N8`=&zJPLvo(w3=Lt=3te~~s6lUUHUs9oo*gCfzVmIw zJj3Zb%CX*gwLX0x6Yc;PK?flm!nU~cH%>F0e?-nF9OE+S`~LXodS(nDkjvFVtw#zB z(p8A|b0V4QcG*6&pt;^ym1h=o*Q=tLvv{Xj8FA6Jp>?>zcn!R2#JMJK-Y7ah>gH9D z94VDTZi@W-2*x^G5%d3%UP3M)lC>I_Hzm*glbP=Xckwxr=~GKXB?m}mxW`(4fC~Sf zP`=0;2xTolP=^XV&@oyn#ez26^n)f`85=dX663&-VK#)@lO$D%@{E|h`rrd4*-NOFjy=OrdU)gFgoMR(hqvnsDq%DD4eIQVdXi2rY^#n3w)JvZ9!%uo9Y=M9H zou$^wxVn6uzu}5CapzUbdz$)4Hr$FeQSX1?C8Bq8>nWA9^^tQI&%!6;W9liV954sR zKJL}CY&gJ(w-85-C=#_ZM8iUJcy+Hvz&d47&&P6nh*9^#s3;Q%C-0u-1aGan*xEA6 z+HysHgv+eTr^;Hr;N@N2aGi{=r5|B+V4xlwJ}{SAAc6H}R5*y1mA&n8g8tZ4zI)1*rA8(mX*DHcBn;g`BvKI7?T)*+mg9p;{m3ie}sp#QO~FoNGBs5)yfFBOt=EdxQF=%X5GJ zkc4qQoK_+j1^Tc6Scq=pQy331T|~L;$?aF1&@=@&fh37Gu+Y>s|zB5R}p5RZ6e5VYLMzJ<@Ik+zY$ciT25(N419=L|7n?*4v z`17iH06WD0xPIX?&;S$B}#gkzc#P8+lYQaYsSkbw)x5h61hMLf_J4{VJGI4SGq zP7|NfRFs?UeP2}2zx#b-6jh2`03txpP3+ALL6Pb&xMq(2*Xb-J`V!^kt5(+ z3v10Th@5`Jo*X&#$jwjM;YjF+F$DyxNCw(^b|Cc#_kz)w*;Z6+Ox@7P0ia@Ivfhod z4)4Y&>_d>?a>)A~!y*QSS!8}(iwQdk-=_J)gSueDa8b}etICIw?$hIa#L{>?9@tSK zm6SLEML07Qat}YA@;!t1lZ@+2lcVbwU!)sD#vcxz&I&l)3F52f&7d7<$NxkXBMhFx z0Ncy}gQwb)gQ1%rGb8KC#pOiIGT~TH3mswY(hVUyZo)&Rk46MYjB~tCeY4PAye7t_ z5az8d_)fY$6#Qv^5n8&vq4Tj&XK7scOE${b~MLahj5EuqgypXwjW}m3d zeB^%3o-p3zsaLR;g{dBx{R4JcpTc((N1V*L(KVcP=AOi9XmteFlKDV78t4mewM^u) zY3;%J8cKF2D@pu?|G^wnZ!nzjfx;0~U>EX}`NN;(x|VPfdKy|=S_@WPlE1p)bt={- z9751m)LQ9fG|!Bd@Jif*ED=WFMq6VWI=vbxg^0DSrI zFgUp5GpGMmpRQ=^`H>$(Bd{1*;J{a{y7N`BGP;)CX+HT7NBl)E=V}yEs~syhNPS37 zXv+>{9%E35J=I6G8wvC}0d;cu*U51=tB-txQA{G`k3z)NO@csi+=gQ%ITg$8!U(() zcN7vbZkb$mkYE^n`_NdD!^)?i@WlS|o}eFu;>rnGarX4I-SSkJH|qOF;6S_~Dbg$v|;^BK%6Sn-THqDNJTWlX|$}K>fwqvV;F4v$ZJ7 zwquJtv&{|!8_U`f#18xibEeNQnDP9G(t-W5brook^2W5-FZGJY$k?*LgxKNIf}K3O zhZ)N4vykh+b1*8CY%jR{5%N))c@lJwwc_q^UrPqJ!v(f`Dssqf+@>BZu)|MQp9s#c zCNN)rOMd|_;~p+lb2D31vf#@K3gj9kRPLhhlxTLU6P#wd1%@yZbE_;Lv02?)tY4aG zwB3*B?$=c4>Nic5;r@%}2s;NUwVjVRsL~&Td?O*cv$d=ZH?6kQH`OVgCifS6K5o#00$ZC-7F;#>`?peC9-)1sQP_0P#3s!>^+1SYH znf91FyZk%P_wecB`~nll0OyC!bDhTmFAvEdys>|y26hJLjn-_i7p?)h?3UMq(ePW= z^10d{d1nWdSD-wsxbUZcsKB4T?396ZkM5FtMfrCQe&~Z3hG7F53A{o7lRwFQ&URju z{U^CSX@B2SpQ)=pf2hM#LI2N#7hp)by(qjE1&ZO#V6O|QUtYIIe&tYOc!6}Uqcq>*%%eLcrBtH>& z8b=|C0>jwDqXg6sw|H6CA)w$CFU>`cK?B?^UMfEazifqdSt7NVIL61%Fti~(5!RcP z)}8u?)I~(`a%9C2YmvSj5#231lc~JVP)1P~tL|+C?Qka|HwgFHyK_}l(hi^OJmp=+ zD!%lKW%T5WWo?*(3xuMjUl z!Td1CnGnSmpF4CM%1*>fgovf6B(NP$rn7VCXIVSk)UiUm_1xLaYSNKNtE zG(nZj2TiQW9ZRzRkmHHy8Zl@$a$%IY31NJWZXka-zn+lNWzVvjugF$kj>)<#m^4pb zWEl#-sA@s?C|8Vb?kkvHaxzC9J~T#$OwuTBU)jt5NWA9l;eT2ATvLdeAjev48j_FU zim|c{cbqhLr21-H3hTh+-;Ee!?J`1+9yBV0;DPaD@`~R)7O@D?LIWSshxv#;KJ=lG zl#BJDU~=2LTi@NvZGbnz8d)HJfUtBr;mbJMd0!F;c?W*WT%%04)&=VkH$27h-+9Ik zNYV5hI{XdV3XRx3LNW)17r*kP8Gjv+MWCEg^e(6M%=Z$`ceclN!@5iGr%1B2DDglc^Fq#b|3uE`qLF1tn~>JeOz@c)jU z|1f+Px`k!|P!h2OcVd!=jnqm`?@nH3YdZ_PNu1rP3*wddw5;$Z*8R`pdN||fZ>>v0Y==3Bjl)Cy3v?$};TKfsSq)LD)6kh;UdWPMJ@q^DKPvIl z96k=$Phf6lJI@&_*m=&}#t26NBoM)z1i}wh+{O~+g0nbx<{uV4u$!=fanzT~aMy7W zLF};2E99~+T?tjgQVV-d<~wwfyFNd!XWU@_h+Bn_xAr1_Z&!cYgOc^L?PHnNRecs{ z5(?gi)W7+rXMl6A^cJ#D3EtN8xbs5ip)gtm4ZE3BnSM$!wpI;LVqOsQBsEjB-}>B$ zC)RNXwd`KR;Mjwg25G5O-!-rXjudPcUWnlcQf04Z_oP2liKD6{YqSniGp?WTj%bB} z%53y}L>D}#L~k1$k2+k$wS06fgN_fy-| zKE*58YIP%R>Z)Lff^;LghR?C17u{}`;rtNnmvN|3`ls5wgEZ!wzwxj?+-0q}3Hs#C zhUa+3YIvS8MFamap}D6>_$jI$-da6Q{Y242y{%Jw5kSn-DMfWZe9`V3i>jl_)$Bq> z!!>!M^l)Cv)cg{my1uP-#|FfE@fe0Uj{x;lznQHM7uB z^PVgatyQfRfmXtJwgg5$7p_>Hd={Mocd<4YU({u#ucYM{zj+r?-bRPr+sD1h%n5M*OwE=Dc2J~OS3&P$RV`02VPayC>t)|_dH+ieD z=Ha?5G`5k%ODyxZfQ|@L4^7F-<71R;eQX5qdYiYs)|_rsP$JgccdZ$U=pL}#KWEajE$|H>{&J3G^tFFxzI&%S zo{KRrNw`Mwtv{i%4yt|w$^MlUj|wk*lt0I~1Tjk1L4$H8P8VtmUnEgIicX{9@IC28 zS`CtV<9b5})|c(R_a{iR3I1Lj4(oRS-%gx3VDS2W4&7jX47%B)aZ>-cCEG{c$MLWYVqx8?^DEmei-SG7 zn4U<^J{E7G`x)qYf6mX#)R3tSYd^}OiYvf)9BgooBI+;7oa$?_o&R}yr7J)_m65H# z^RmKva4lJw!P|j4`e}CKt?d5aOB?L1?A1JLVM;lmFmn#mz*~~C{<_q> z)6!xC%$)4MBblA57iZ<^4m~ss!`XfT(QhUk0P#L9)!f2C6=|n888_Rn_FaPk)^9L{ ze)`kEA-Lp?yu8A^C9jgsuWC;>8{W67DSb>zUU^j;mb}7Gh)Yd^Vz&i*?#WalaG;&k z!2&CEs@3owuOr@NM_3nJo=z`{qg;S}Mbzm8!Gk#SIC-pr9|T)8JOm$)s&2Oxy6!cG zX|;9dS)ql!R@?Tu2~L4mzHZIKZRj&r+dIFs+MbOYZ+{(DTgM;dknu|Fqp7m}m^JS$ z>&ks9H}9q7J$TJr1)AoCTWUrV5X3s=WB3D4RBp%nlTW?4b17P3we6szu>cRjk&*BY z@RB>!>Zf!glNc351ga9@79JxbgXZn7>h=EHLcKCC3jJz5w`;uYP3{1F1|D-~TMdGi zcfFv&a_^6$^zZC!c{|_1xzP(O2mGu4GZ+gTUeIXVCJG!|`M(wUYUmQS>Cn{P7|tHA zd=mRNjd)&1@>wroy|YMt7u%V74vF?woi)eG}{O7-Qi zwq-3j1rHrf1MSAwdFyd@0vNMiY4+54+D=Xp>SAL+-Yr^O*q4dQOAXsL(6mMpliU8grTS-cc;N~on2vo5WF{%;9cp?EK+ z0L``R^_WhK?=|4T_;`xc_afi+EsTC8jb;`3 zU~e-M_WRuTF+XT)M%c7dQ!5PwA#~eL`gPUm{ngibGEQnOY{?)P2Lw`%4D^crqo(|M zyc)9+D7n#N12^CU5Uz9xV76wdA?V~_ag2xeRdcj5xX3j zykZWmRaM|pKQPcGzdOyS)`(qDvh~z+zqK;`Up4u``y|vP( z!zrQhQ9acrj(pr(p~`XZff?`cJAfZs!q%20Q`o&gk^HiLCj9#57cb(&E&ZWD{{qK8 z8Vm1B?uxn(6*B;&g*dF`I$%PxHrO4=ndYQJ;m4~-D5`|+IdyqdldY({eJsUo!Xa09 zzj}*H8cqwfh)A_N8ebAuuSN_-l#aReGF7^Sz_$s`6uEO~=7OiuJF7tA=2sAh>0XU| zb{#HNcP5;dy3Mv)=Rzf z4DHhwViz7ec2=I%;HW|Oc6Eu|mO~+K${1=(_lUAqw%vxmAblln(!*nzBj;J;QxG9A zndqv#ihX(@${w(%rnBE(vS;Z;vRmvWZF#i<;r_(+2c#<1b%^j>32R+%yya-f4m@kO z>zy8BO*mz*W7->LlQ7jX^IKjxEwlxS$q^ds@`e*E8gi`T}zhlEwOV;YOd z@khn#%$^>}3oBN~-DO35qr$sgKT-ErS_GIq#l4Cto3sQkcKp4Ag2j~3qokfZj?F#t zqeorw>#cys<9WHq68~{x?s1&|I3@Qu-hYhb9w+gLE4=7h*xuEIWtV@8MrHhljCv)w zX6CYk#BUMR2vwE7m$YR0O5-UlEqSKWe zzq}b%%bs9`cXK+=F8Go(F|nJswtN{k#Hgqqz|u^p+R{IYmD<^Vp*}%WIidtH8P?2q zBY~s#7Nz~1nzAKFRfJ1j{@(oY3-zi=e`-!Nbt8zqDtf2mBXU8+`LfQ&EWLb=GUP+^KVha%*!<5AMkE?RU-6`mb%rECmDqRm}==kIE_+)ThabJc;ZhI*v# z(#$Bv)uAD2I+f3-)SV|)O>^jfb_%4#>;p26 z_qJ#i$>}&+%$0=S=G3Nxu`hwK(jkG{J5EQuFb85_;RTy_JFXWfU%h7R}HHP0Y{Gtqac?rMc_#MaZcp_g; zB0WCtOq~>S4Y@XEMv&&A?PgtWyIGBY8LooxhnZ$^mC>KIlfZ$u?+{Om&~d z;WOb?hwu-BbGePuDu@xN6Agyo$a;3*o)a3yyeGnktIo9^EU0U)>b07B&E*xIgB;uk zy`lFl{TA1fnP0C0ox+E?fI!PHHkp$jF7uNO(r_FzxGIvL<4AVAmQ^jE<%~2?hyKXb ze)@9IvZpoEv+X$fhxBn-+5dmxbJ#o~@a!Tg~|tdBWkC@1ZN!zHFnAn16)CM^K`$$z@raXNW6GGVm{2_aH92sBIW(?B++_;(2-CNoa$a$P z_292wmogC)BIjexM%v)}WQh6fEQL3!QRr{XyAkv8*2_(S)Slj0*?Tdo>7hMp!MO+O zf>PVxQ2{J1h;dA($IWEn%u4%op7TP-q1r8PP_}?dd~YJRB&R*!hq&UG>0eL~{Q-2Y zZnT#5d+>CobHe#~aB86T5ga6as*te?(SNG+#X4>odbHbY$ zgdfcHfLnPp5XUomozAX^>*`z(8xf?uuX!gr6mwI`kZB_1Nn?%?TTN*pDruI0Px45Q zQCf^0=@O+&{PZ}bMe@iWue3-W=}Ah9*={y{(Y&5(ps_VXZVMMIp zPNAQJ_o@Iwh?g=yY0-{sz8kfgUTh+I`7z@=JmQvP#nOy&kI(d(^jQ)kPH3^qTB=a} z*}S7k#wA!lOOo&uCAzwC!?2Mi&T^i<16HC>OkW54b|?8Q-R#_lLPR0KZyX4#i|>8P z!IQi5nBDb(j%gD#BmP)WKnUcylWbH6>ZF?zSYi{` zBEoedDt0K{8J?~+l?_?-6CnMmgJ)SQ&LW}1%zgl^8Nj^D$LClj>R)h^C`B0_1r9QN zP<|rJdX9kU{t1rbZPlkzn>B9%>z6HdEl$Z+HP^LNos`;g6*LEB)DS2KCr4@~Bh5i1 z;;t9RV9v9J5Fr%33`WC`uO&d(wfDxonNvvI@LR)Qb1rD)##Sc=xY&PpV$jK85xvk` zoeUP{(tjp>T`tWDVBo|cuHWZSEB%AO(0Ski-iU!zOFBP@aa3Ao2A^5n64g0D45RWn z6qs9UrJGP*$s->H(wJWR>bco8bMC`+$zhWH)^d4BLq-Oo1$J5W2xIf?G>I(PhMr)b zjxKF0@b|k{i6TPrLyw5{*L(~fAk10dBy$$P=e`aT9c(!t(cB?((@8+uj!`1@HT+tn zyYdwHUY!Ow>+3WSt0YWGrQOQ|x>|hAbi4BV;^=+ryd0Mr=qLd6m6v5=Er&S;aNM@m z8MRk5%PQ^n#IbY6d2E2G#fYc!%I@j7l;rJel+8`Tx;y6s7k2c|+qeWLdV)sd6^~S_ zUhrd7dXd7$iJP(lTT_eIgsSW%u&&2Oc{f>6m#YTF8v=5hdI=;rLVqmhNwUC2t6t7> zv`}gu(VwiYUPMpn1wHz{7I1EI*BSK&eLlt+kF$k_px0);$qsZd+$YH~27|ei&Nh`O zq-hP*^uO}5?J5&8c{C;}us_fd*qW7EKHY>24AEd7eLH|xP^&7Q`S zk00_K>aVesp{LwU6`4INmNJwL`J7oOaSl;riL#y$b79E86mu8C$K&nRT?jvT6MXza z`1qUP;}^oh+*HCZeEd!D@e3(_Q;wI1nCJ9Hz2Gd+Rmkg_FNc?DW3d|k3xJ}S_d9LQ z*{{LU8vKkp+lHWQkABf|P zQw0GG!TJ_vLeBzGDQTJgeRH#34RkQ5QRl^+C1ziDJ%3XVZZ_MuV>8Ra&0_Xqj?GL5 zO*B)|%yw{diJ#Am2REDT+p(GT;AXRZJ2o>P+^p@J^348mN7&o{^$0tG;Mv)Ka4ze6 z-pqJcKjP{Y6DhcnHfnk7far9+$|jP1P;$)N7U6@3u~t;R?XK{_V}!8Ic69YoXHRAF zjm#c_s1KaY1~}f78JPorH^9>V4pptK=R?q@OuXd-#B8r)J#ggM&0o#!B)+y9A3@Vp z4X~4lNpx%VNpIl?C=i#mN6Pl(@TIcVD>?(&I%39PIoH2F(dsASwe19*L?brqkl2qCqy~oSxwbO&r?%?{1$g$cG5kL(pFgo6f67NP ztVM;+_6a+1=PCX%QTgRqr93mW1}m&}hb1l=5NseD9F?D_{Ly>7IH*jtmMPmy8Dt3k zxknLfv&EwU7m4{)L7}v=tB(n{K-^Gk#b6)bNg9AyfaqjfTOD|nd9d>Jl z!%lQf_Iv%uj!AG4VD-Gt8-d+gzFTDsHxIxCB$kG^=mU5cLe4Z|{{aVuvx?eSC4*eo zsvd?9IwO;>XMas$h+QW{AP2GuJDT#q;+U_oy13mT4x3M8-aPnX1%lkQ)Y&Qt)iFi|AM~e>~OrX7l-$jd_f(&RY>&_OHsOuDVdG~3{ zM+Olx(Nm3Us6GT3nXfNIEKs>r4MyE2;Z)pf6297HxE6e1x{?)@2vmwM${b^3idX(j zWiRm_tu|QA83wvBf;Y5Dv>W4ew=WZU10cvp=&RB{+OwGU+@&J8oG}pc)|pMpc9!M< zVTR?De8?%3l{Q{Vju$x%;Q6xoYVFZwwfqFw;;gi8!6j(6xT&HWoRdm~>P{c`0%J+( zTn4Su5v^=n=5pwzZ8bIMNX75Z%;C)06Lk$NklN&6mbrs70K`x&_=Ce0R;CJ|3Ysw@ z+sMt9QL|dN&j&F9HU{$!|F>y=shYRjm+DqP|48bLYLd=UagxZJ)ZOg&z=@&rse8MI znf)|xGV34UE&_Q0F4Il;koRQ${z1%pXgh5a;e$x4ivEK>CRK)E2NszMBfy#R_Cnso zv8D}Kx3yprmGN-f3cYWpfta_ULqB+={_KTN{8d^eF&+6|&ioL1mD+3$)mGgpX2Wbs z>wIa~66tHjNOJu0x_=Olrzkoe=F}62Gm^;59~uwm&f88JN6S)>J}ECE-qP6W)zvL)r3iM&|jtAa~*d{%sZ*->u0m*(@&BU@rr73v*Q+b zg61J_(Fm{Tr)&&~K&RCNx7@3XQSJcos}ydBx1Liq-#A<4qOB$QH#Mu+#W8Qh$~TZ7 zYzbn$84IW`9mz9S>N+39>$A_8rgl6J~D^!&G!0ihe zKBvjLFNl5dE||tgjIc?Prelj)w9Wb4Tgk>6^_Tqml$LA#N=>p=_ng_yN7TPa@d|cTd7NX+i(Jp)~v~^Pidj3;otHy&pf3z2^#{{lM>#AA=*iJ_wS&P?-3#= z^+K0sZ{`P7u`y${>qp`p5*zBfRI%p8n7dM|$9nL7pMdN|l8ci+YfFB4$I)`D=>WHA z3XxoJW61B=IqH~S$pEiDrDbO|ZP&{4P(nnup%xdU7Uk#Fd@*|~SU9wP(A%&2I z%%5`iwY*Lbe|5^@jlKC}_UDya1TpviS^9DI zb{=9UHYFA~DJ_)DHcBlhFlma-8`hg#34XpyZsr#h@VrjGiQ z)|H#me6zZu3GdTiou}2cNvliK?N0nV6-;&CwxKj0^BV=sZcG>=Q@K zn0j%cJ^12&Q(N<8^!ZbpG((t1+-Vl^1*O9$eHmpD28ozg^V)jIfGP(^MvAM1KGX1r zU^$a|z_J_9tX&+e6 z)GUOtJz=_2`h@{xh+EM<(Xz}h2kTytSM_(?YnVQ?(Y0U#ClMvdrHX12)2hXf61`72 zhw%fA_7fpXxAyRe(&ali6DY|P{D@6e^8fHZt0vhd>}5@N+-N!Tq8+_9^<72v&}$w@ zup186OKvwGiji%&B(yzBVzS6rHYdCU&U)O^dUOk_uTxfG!aM(C_^?lS3%dvK2exA5 zgxy2*lFL~iV1^;w%W)y|d(@LTMA+dMldrJfiJa#ra5z#(JZ)O#h{=cSme)o^Mwj9% zjm}^S#9t)~OTrK^YlVzt6O_Y!UIezw*-Lr~E+-|r6ezGKos<{?>*+drY@ zFq?ewqXwP+&iX?XGK)44Khpsg--^G0>hPX~_Kf55q6pL`MwnJI~s4V667c zoz35MA~#$Nqib;3dEYS?m(py>Onyj2)2fqxvwi)08MEPTY9wz0D*XF1pM=qJTHTc4 zFP!^Bya+#L)qR=bsSk*7JxvL-T|)lv<^eV%-A%V0SM*h7|G{MH(@qvm?9>NEPD%#~ z>$c|9D~D4DY2!}6+S1u)=e4KA`DmhPKpWnK9jOlp3UNL~>fq)i<)}k{|5j6FQ-X7d zZhVH_?WBSl@Bio8ulrd{3# zhl)-aNYbt@m(+@1!TF;Poj>Xf^mV5L&-2C-Vo<&lzFly$%q@%4i%rvHQ?#l}AWUzD z(&a!{wHWYy1<(9B@M&ZJwP0t?XMoR#9Va61f-^2Zn<)tS5Cc-wx!*7y=`I?C7`^ll zwUg3rnC&2I2>fQ$fQ~gt{^go$?RPwH&ecmal-i1(xUS!C$MoC9jubX+9ZSo0(#wGhjy-H=l_2ERH+LgnIat01KrWl28=1|TDuDEm z0g@*m!33ns`3@7Zv%=f3kSwRuYAB_+!p=JP^^2Er?i8>Ly>q9(7oG5S!g&`~>=QW) zzc=J%HuID3Qxa8mXWEfy_`lz)d3ES5{MZk8Ydh16kh-X?_>wlkz>Q&ndeC{i=6C5G z$i&RYT>oPYQuClowRFi$*nO(k^BEt`cDoL}nszx9%C!~=A5!P%Gg-u}Ia1;Mxfb)g zcsqm9R82P&hzq41ynPK_m#T-kmVM+>7Iy}x{%^1uxD$OgHWO5L-5r)z4~Rzm+iThH&6$Ha;63Gj!Cht^R>gR-((i(M?kcS{%^UQc zX>6DYKscx+ygO9|1Q#^x)4i(brN^onZaaB`6{>LFs*p=jGZ$G|UghY8jl)a>@Ewt| zUZ%LrM;ee!3>DXD)u&KIl)^TIk|WJX+c-^@R~iBsBK|N#b3IKLl5jJp1Q7thvod$S z1p=C-Yk$rDx;u^8lPz*PEK*&mKFm~Z6Jij7tNI6V_aa^3)k!_NcC!WoW&auv9P`b1 z;FD07;)H*}T}O}gtk*n9ycHWUpY>v=rqrR%w8QS}v{SF-XTMIx#(!N|TD#dOZ5w_z zH90>y+AONQU{UTnjJS>wGZ=x-85wgr+~TjY&XjAdW64=tj935wi_|6D&7y|a@6aB9 zN8dq*+sw0J0)e8j!ryH0!eE7aNpNvRMdbz|1?{VvV<5)?6RhAeSoZ>WmmN@R&?)r{ zMoUb)s$dSt14xnQ}&+Tbsl&bEAKe|VpD zX=k{#=C`?JjbRbi56PJVLo$v$PsEvvXe)gJ%Tw}No?Y0kYMfxF)l-GR@e++_C$L{y z4*`JY-~wkB`pPXybja%%nkIR3?iyI~#P(^$${Zwggr!70qjds#6w)H((~5Hq3Vz7$ z>?ZZ&L$b~Rd=dE_M(eYu9m?U$K*we3*dVnrY0%SO+j^*Y2Hb72(Vxep;+Iz;&2daxt%ei95NMAE$5vt}k&jnKF)Hno2E!;o ziu|#g+2YBNOyXJKT#j(4@1UQe>I5rcCK%sz_qIQpodGwzH{hNJARJ;i&!`WI^>Co- zbmGJvOFg<$r62>%b{`()yYmgzlBTsUS$z_MgkZqPvzlB9x1duIHH^l@eKbn03Xy*2r-}_0c?okr#`PpT;c>+Z=vs(Kh zzQQJFx1|kdZq*%A2iwxyKMJ3o-7jdO_mdOI`@0VIyGDz1h^3@Gaop|c@wBFWv^_nM z6u3re5-IQpqFaar*}qmG3yE@CJU-rQv)?zL0e|RcUUn|M^zlctm5%ipR21J5sKO@F zAZ5Vmu+pF7P2622x&F3w!zUd6IBgB?n!6Y_yMyU1>Kz6;Thh1Cgp)4i$=xjK1pc1P@I|3u&#nk? zbqxxbiTyK>&^-Bj56GFh1G7rdQRp_^U4C!5!5Zjj(C?)dj*9(;!(i6nwHJk_ z!HoKpWEhLg=ZpyWb+q(Y@_)tU^2Q6a+;>Cez)!K_cIwfzz7&Ajz&A;Dr6$NnUA;1k z%t{k<7V-~a^cSe(AH!keT!)$ znz@}0?mKwt&pZ-#e28&MD1ppDg;_c}mY5gPlD62yM zghOSAyj!>NOfmo1Nwp_WGsU*?qkq&ml1mQMP-A}afkg&ts+nsjPjW1?tA8X51xb=D z^6Xcbugu(^>taNtRO|mi;GX>q`3oA`M~$05{5&VwK3l0|`_FK+d&ImwAjT^*fi|#K z)iuU%SBvg$%KV4Mu*Y^D%iKneyYjVDShlGUE$Zup3TaOj=N??QUoWHPO?xz`0?yn* zcja4TJ9CTNmAxhra#y}*62g_#qpA>7@={hA3@g30B<#uGs$)?O)&z+S^!C#J{rtg#NL;U4^mKNo4<{Jwdqpqh8XV0cqyP0F5%FzDH9Q!L1$#BH| zqZTksqrTB@!V>87UaywpuTSmB4ZU?+a;j=rPEZ}K@GcaCvjhrS_f+8jb>!X^+?Q z5tgSrLeOWT4h$ZMP-@396ave~#B(bohP!zljm9gV;k3hksfqd@w#@g=8F^_ar{1-aD*qiKgdI<;A_ofWy zMwa!u$&k47E*PRa`ZfuhQwLA5wrscRo+s-&J3jAjDw@v}6<<`=Nk{>_bDr<66g}af zb2dG^my0uN^Gzjg&6w1Iv%IRWbf0^FAr){l)JwEzOanit{|GC&VI|E)!r7Y8l7q^y zH|sA>5VLlwCJ5*I6W+V2zk}0GN+60=8gRIE)AZz+HyYI?FH_l_8Ps{jh?b52u6#ep z1wp>oGDo zo}qtyG0#{zj2B^bjX_p;Lltx2%L}RsSkD{;iQG_iCTzOd?6{-P zAfa8xD#fQ1_es&U)t8G+*x#sjmkD;r%iZW&T(zzCg%ls9A;U0LS$1kmDc}oybVnbC zwYb)rdoQfPe7>(Xj>2&Jq+9X^H5HJu!NBU4FhbA5DgCqEiXid`Q5*@jBAjVgrIDl!r< ztu5LDF(nAzi?T-6cE@6v8O(W)>)TZyZO)wkUrdyHMNpE`P9sLUtyB%+;N^hwE;M;{ z%SFu5U`Gfxx-I;8&0F{}vwl@qdKcLoy*>-gtojsk@o!83>P0!yJqw;WujMYSYo>SJgLwa3YlMZFgnNT*+egMmRE<&fXyXjG?g8~1;8!iQ53~nzXU2W3cg~FI z-BoAA@x}!^Tc={f&Wuo~d(F8~T19VU`Z<6g`ffy>W7TJ9oZk(f<~PcXlSq(;%gtg* zriLAeg0;C*V{Vv;N(^JBqoX!;O02cLOW6^lt4pOsfZnYJH!@sr5NE|09`K>dpts_T z3c{6A|EfPJx|>sNYcDslO=;X6C7$$pC8MxPp4E2NHqdleLDa|9{`YhaNEG zg-?G1+<;4U4fm0~jB|CP-R4utyzDVvE@*74^U*82044-HN^RC&2^S1k{~&XRSwIcm z9SUeKV#S)Zv5Fx!PPq}eQ6l?C{vcGTGv5t7KE&%dW+2&m=6vwIzc0|a6?gId>eAtOockVP&ZP^S;u#2M!QaPf_WD>ENKQw^Y${u? zVIqCcvMj>&;w3p@$6SQyTaO5gK;TMkp8{0Jc>f{O$U z=ZAOgaXh(h9pB>K{jP2svJq(GTO`W1!~Nm4yW0$``cuaZDZ<1)gvem{fZp-!Ve7F( z-x*ksd6ds=dWf$Cdil8do@@HxL(^Z3+3yRW1M}nFU+mL8QR&Rl`T>3f1<_49m-Fq^ zJCLA_dF4VUQAho2Pwg5^y*QZaCgr2uYlC^2TpsP{fCFm^LDCU5`(4DC?EmOP%_qlN z^;q_YGM+4Pk-TRMBW8QMK zb;5B4bozxWXrDd?85~SkIglf-l$=tH$T3GOt6>zrGHL9?M=TBNUyoR3u!E*-s&0;7NFuN0qQ-1bY5 z#4C>ZXCz+eW!%QAT!r?O9`uiLYlf0{4<-LJlwg&W@Ieca-f^pvh?V%LwR=jJ4_Aw-@f+u5nsRd-vn+-qt2t)Np%;okjzOlh*yGc z^uO1PDikw{_ok*sag0_|tr$pe;w&zrw{ObN!xG46koO91k2P>-h8y6997rMe^Z4bG?t*TftFIl4VuFnINQ=AY+ixtFD1MS zeuHbl1g=kg;S@aVmrQv)CeW(k%DGt2jHOizrssU-<61ik=X6$#_{HF}< zH>SAwe8x{5_=!1_N8{LJU@SPdCAJm8pfb1cS~`4#ecEyv5flzp-$0$J$)nN0owGQP z9*irmJz7w67Jomu`PcZn8E7eE(?HMW0s7(WH7}aPM`u3cf0}0a+WQMAbHHF!*M_UMe?^mgylOlC z&6;lin*iRl>?s4bU#;f{e1T+IE7~P5_fGSMbujZCTK2If{W!0g=!dcXw3>2wqnq9R znduZVfp{Bp2zG}0zU9XsvzcJYqdMW0kVE1~o%S~ZZl?`deW; zzKkaBx6YHg?+=3PURnhuAnO+g%KMm#5`kO%T;{*2JBY1+2fjtemhH;9cZvHVhch)P0|CXD?=n@uj|jj`|B_ z5k<3K;eF=hTRyCxI2Qv^9D2l#w`$_PU{TERboz8!oak~~3=(Y)Ir;E#L*eaCvff!` zL>Ydx+gN*aEr<XbTglQ3B=5AbIme)8uPprBDctv$FxP%!+of-g%Cz^%GCSTOP8@KI|; z3-6q&lh#V|9ZMZ7N&Yk9&b=G|=Mu9AI&Hb6@=pcHd-11k6S-jdUt!BA_dujz z?s_MAH|Hs9`7O$G=H5&GqvUTinK$^Ee+uj)NXLW&cHlib{KU=4VXeJuEx&?7v=Z27 z3h@3vr#T4^@s1sMvg(`DQo$9Na&>YJ=?t50qH6JecDzQM;=;Idm!sV#@Y);sQ-jy; z&chXzyJvbuyAuT`eI6nJ%LeVipGQ)8)PqmzHcv~G8-;Iu>MLS&pivwZRP zaP~|swGoesV5e%ITRqi&yuY0}E=<$DLbi8lkbN?!R(4lv6v-vq%^4{&X=i1D+hW`3z^u6e|kFc8ImR`uBi zuX0r8g@H=ag3El5;?eLM$yak-87MToCzlNLWW^8ph~6 zc3Vxm%`H#n`kUp>KDVAECum56O=2wL=!eR73&N~Gc^I|4uklFknR;ssTIoeSRICL; zk~vN+g{PTjt@tRl;Y+NhW}IPGv|(+IkH`M+k3BPQV~xecV9~pz{T%q3B{(vGJk9L4 z>%U~zPb|&Myq$0pPGkdWTSf~nP!WFLs>{;+RQKi$keGKffBG4>QRkmih#;gHLC6y{ zV{C%!N7<8trRcd5Tct@I;?6PF)^ri6DHoAuBV~eQ9(1X zxYabJGRSlf#52UVXF7ZVxXUv;MeAIxpyLIPS4p-N!fhnt4#+kj+nW{+p&!5x4_?;SU2l`&|8 zHh#b?!`%1VPABmz%`HXT*ScCf;Pr9s>KEH}X>Nnvq31f`p=O)tQLFgJYv*y%m+s zI03-*pnUZ8Mx5X$bmF!m#gVD0?<7#zNs}z%z z9^UNY&43AgB(RGUVK93qUGw<@b&%d&twvc|^sSQJr0NDRd8m)?4eO)R8$CBT_PDS8 zYagFNEs$YjrPJenmrgj{)6Wg=KCY7KqU~g+pBvd79M;7^Mm_X`rx?K~5ke}Q4gia6 zR3fGe^#|E#%z2fWEp%oSew!eM&t)p$c;2HlT(U~Dy=Y;CzQ|2XVhB;)oU;S&LuL#&GP@wvvWRx^9s8T12|VkGE{5iY_% zf}YLw^@bj=*~79cD%B}>e$06j?OP0)G7GNe8b0@k#AK>GfOUa4 zr>dmFE1DSZ>pcT3GPEwvcS{=Rt1h%8do|8=2Lhoq8+A z&aiFVKq9-(E+yNn_lUI_F9K*>yn9xp?0GA#eVhOy#79B-ool_1?(966>aJPxsyx>& zY0axO{++Jh{tV@Oe?r@1`0j+A#Z-AbUdYTTviJ*u4&z(MEYX@m6lm}Y7~2V~zo4G^ z{8&Dx_y3??@x+!_xhY2vaD`mGV-oY%uI&i>ogeVj_dF4_nzP!Y4ZU-dlXR`U4ILB_ zmPLbvC3!ODUP6YP7ExwjRn9&-&ZRbJqu|>LP%{Q6wy<93MoO;(M_+UwFvjNzXnVK9 z-*PvVC|xMI1#Q7n;^{KBI^jLKOdizSWrew_M#mzhP{L~|CxfwmX~14aAr|;mrHkUY zzV}v0Z8YYsyO~|dT^6Elf|7*Sn1iVsfwI?9_62!FBF&ZQ3$e=EO7Au8T~)fC@RZ8m z$TxKC>O9QDHXc;KJV2(d`pFTM*)G@h^LdT!R_vD!pXudL0X1 zqF#};Wld=#c?7?8#+K5ppta>$K%#QwEqTWjCD0CG4hWgs_X6+M>fIJ(K3&ATqe=*` z(5&=ToI0yYS5rV8^uGE*=bH(ys;9|rRZ>%=Uv|{Kg49sDa{{Y91$C+#43|V zVwF+cmPBzMHMf^QS8_nIpMu4uF^An$p2*}!R^E`vttt%`%qf+_)i(1qQe@ngi>0|Z z?pucoe2NtE+E1OJijhDo?aMFiQ|5J1oXqLoSS;h`%EPSR(#i5gJHsnJF;RJS_h3`T zMb!+i2okXFB{gPRI2FfJr^MN$rV&1l@-OPGp6x&vVg$_^4rjHdC_bmOn4#@rXn&_0 z@+-U3SUlISF^3=<;M&>7^Qg{tG=i#J(xf_`HT`==9GRy zxsgB{-`K`}1lR;JI>h+}>CcP#?UB-Edc;-1O`rj;5RGcHkEx*ke2CmBe6>T+i2&qX zj6^eKeq zF(Qlb<~oTTE0^D{#i{lwlwc+CHLoauOMLCXd6Ba1W!okGZ>V6zwtG`QzLaHj8?U^g zpBi&YGjbVVt*a{SRr`V+E-WoATIZSr`fAy8Ld2W%`StF^Qrr8f ztc8et_$F6a?_gHi$}hZqSx2PoS!>Gyb_YBgG)DsO;NLL}@TyAdG5UaLVlUm&Kic%K zex&=5y61HC?Mfdoex0pY2UFN=;~NeXh*xekP~0d`{X3s;#z!?Cpc8<$Q9f01`Ipas zOar_TTi54_K$;gVdxF{097UX8Y0_*mn9gqDFUnk^1Dxd67?Mdz(M&~{qey+q)C;6c zX25Df{_qra0tG%Dz?wfgZMXbT?i6wFMvk6F3Uv)Zs=VCLz`-|#dL!xwYWY)S zNOiyQe-(IUnpbr`lB&|?>|TKF^ApK0YIPMk&%)gjNeo-`AP0hoL(o7Ud9&X_+Pt8# zv)^D|_LbbZH+A$_m87}D@O#!U{3aG$-#?^6U~PHZ?%Tx=*WAMQL0r#Tw5x9y>&y6V z;<|w^J8jrt<-Yv3`Bt4)_J`xE<6D=5^w9y8VE5`0t7+<|h{c8aFRscRyh`bqzZgt0 z9$1MCG|u)>4PCP!c*+GaxMQ4H@p635*`sr(gkofXD_7U@3!)gOg0P%pa}Euz-VRsq zbaC*z{1euL)6VQ*j+)>%i>JczKKW~e@;Gzx9Y)sv_$+A8&k7Ni$15A8GQ<6Bvq!{v zIE^Ad)|&h##Z#~J%Dru(>`AmhjkJl->Xl1_)F4B*)9BA?A@ZYDHYnxv?K|MmaO^h& zq02^U8PPIlr=J;0^I)^F(U`Cs*J;r}bA|W2T5#3ZBi#s@%&Sm9(dM}G4}@T=eT`Aj zEINx=Z!sqc55s8FW9UNM^C`EljOybL8lX9Kmd^eY(_9=JQ!EhFT1;=&B0bUtG4X@% z#ms69J=Z^{rL(`~U_RbZM{jr1H&XzK%)JO+&#X_&CU6SqZ=7tZo>e!4arm;c_Nca6 z<}T_7p_H&qGR3o?&9*hO_YQ0GQ@-2Nu04piDh~{Iz)JYU-hXw#%0?{rtB;`4l~?vS zXHf!TbRE_nvW(B#gwLSU8+9Kqv8}O|boTpRSbNLx!uoSSIOv6y06JswB;K{hcqlZb z&`U1ss2V*~#A!D@?s|hD=amF3#nM`;tSCt8NB7DS$>cV4eh(o7DQS75pzNr>cd^CF z$0Y1u+2c;9amzY_o_6({16~U6tTTxi@RIF5BJ7#4qvhx*$ZqG+G;Jd^7`PX!EOrf5 zp#xa6HAqh>{B%vmtymv*mTAoBPFGc=-%fr+=WSeT8VnH2Llj-~x`l--@W{Eo6w`|x zC7Q@IUCUSQ&{35bG~SKe(XSHng6tQQ6k-zv_*UYNz(f?sp?F;aKOMj!1S&*CEZK9R zU~Sdqb1;qi9K5`bwAkm~s%3;Uy_z!@?2O{8;4kj>Smnrg1ss!+e6e=3kSRa; zHKOmKpga5D^m^gZ@c!yAn_eFnkR7V$b55u2qQB7oPjcs99H9E_PKSEzT!vrUr;^B{ zZ`Zzv8hoBMfPp?ZCfA%}{-s_#{G|Nhny~lO6H{i!^KaYNx*)#FdM@{@riEwP?k!R? znZ@rUfT7=s`t`+~SD>^%%Z2GWxNhe^9;(NRsuty#yCjmMI!k0saU zAmB#~uBgxaZoed|3SF4oXnS*!jzw3W;ETzkjU{Y%3*(iy7#bD8Bdj+z#j>C76QNr~ zgt*gKv741l}qVSON3k8lnn#XQCHQx7|nz7Sa&r%)aa74R5K64$w|-i>4U2 zc|ND1I0{ctig9iqJQrH&&w?@^QpC3(p2E8J{e@PtokY_2&0@$twLgxgpj=2#ZP#E~ z)Q4}>z13*-U=^WBaGow}2jUuVq^v!)H(zS_Wd{TOa+Hjx$B8q5x6qwSg+-Zf-=f`r z?)n_vqiT)|Zf)05BSj|bWeR2|GG;)3J+Bg$X< zE?rtX-h4J`LPdt$rDo5>fx9xC&4mbtFl!yhkM1gs?@P*!aZGSySi$oE5@FppQk>mb zMuwE~_tuIM_R40IUdb8fw?9tW4m=vWJQ!V?!oLu<(T*o;GH&k3nIxAjsC3|)lPrav zax2)L)3S#&Y8ZsWb-a3>*sKS<4^`kQlQNo>Oy-)S$8>hT=o8vP(q;^-L&ks&wFc(a zYhEJmQmtvEHJ5(Mvzb}<(WQpMAOsp=mN|ZZaRRN+lI7kwK4#olB-~TUzK-mK`?bP^ z`(L4i`)zm(b=##tm+`?>Q- zjuT?JH_j(1QcMzVbVJBbE_A%xR226Se#Romt-3-^p2_(Z$QOM=we4@(YY3DbFVq7*EpoHG3o6(FVDgns5Mr(sR`saFdUPAK8bD|8y`^rEqzzp)XG`s=RRPUVENwidihIQQ0@pY@IAXX9#qVou{) z{b2X0o;Z#7`cDRAPUCw2X|4ZmqyMzpf08Q>>KWKMjobYv13ss*!+$ambQ*X0PX>HW zW4HfgK<6}O^yI{#gE{y4v5h1%<`c1Ik_K*04C#z#;O4|SNE)~~v0Wq$+?-f9Nx_ZA zGU0boJtpn?Gv}s-f!2cy&xD(t^$Dl=rA#V^e79E^U)aTgb&pByW!=#3~iHy1LtT*YB$> z?5;{gFf##?fPx88#CyQojPVjh$puKh|MQ-iBvAMA{eEA5Fy}q*dGD9!ectEl&b_;M zBTWK}nhO~6=uiP3Iba-Rs`?^IHR>jRPL}fhdAx|K)?Z-GP-@#PU!#dEf4i}y-A$X? z3wDjbY_K`K$L;&GNyz3-IaR2sp5e8h5TIOQY-#g6qa7$ji%3_l+#37zSQs_F;V?T1@WCr zCtO`t+(}6id$%;5nJ?mj`$u(3P-SU$8dWy=s3D=MpF=se_i>4kN?N-H+H2Ejb9_jn z%p3vjH041GKu%%x=gk^1=@&+ng=1B~pJgiA z1XP3eQypK{k-(natcM<1(WPz1?ty6k49M7Ou)D`pG3B}wfbaqZ81F_xv(xx0w$Quc z$DpY|ap=j?V*yDE;;5jjt<4(09>5KCyjyf(8`obX?X8zyni{>f>?T1w5t=mW1eN6u znnIvE1<#&C`Y|LLcL%D^>^|<|*#k2yr4?dSYw<_ER>8Ip;{pl!1wnT@a0Xg&t*HT4gT;sAgOfm0?HbvqU4x*;qGFmspR2BR@1B;uMP8Y?Rg666 zP#+JC4|?wcos3JHU?lt+IT_@z4_Ci!r>?AeZWsu9uHjKS)2>RPAUkug8qw|tReh6w)j-yseLI}fC})R^ zmwHro0rwR_#Q4N)3*>Pz))7KNYZM(D0cIkK<=d+|Y)8%-+EK#8*C7)Ieq48(i$>Mw z6Dvy+GdKEsYT0R4OD)(*{Z^?XiX< z>O5jsjM{og#U;2M_#>ytL+)#g;A%;1w6qaiMbN!}*6fzC&TQ9uz|t@Dp8%-{y2wbk zYeymy4Iui2*jJ8V zM)q!51S0wKRk`3YDZDcJGO;4RVzht@?$&q`mg%7g?;g;_wXA2LcK4;i6A33$Vdi&t zPbxf_@X=H_hj3>qJe6=qDh#Q=r3B16<>$clqsYxdK0_tqffqB<=wnxwYD6ys*5oD` zSN)x?YK$Qjx!uhx)1S(?)s5+s7*vvZV=u`>+TLcR9T27Yyld(T1%(yvmVLjh6V2Tc z30RHUx=uoDT`#2GJ}4*J$bTsE<9FxTbBjV^te?06sSsBwM|lcM%bk+A2rvr!ixhfH z`GP|i2!<{xc-s~|q7WdQoLq_$@~?KHB-x!jPbjh|L6pWkVTxpuOMIwk3|kzLkflem z#H4nPa2%0nnz55JZM1}WFH4GMokA7^=1T~}-r_#Xh4zngq{WfHMhs%!v-GNyMZ7$Z zEH6qxcwEB9TAq&^F{wfNHqV(ZEfbe0!n#^694^oTas1M*!Z)=Cgqqkc}FmixK zy?||dAuW}1rFUjctGr*NuI=3oG;N-$`-b$Hp3r-JL@`BM`2w=euPz2&Q3`Z`HLwQO zr#?{FIzGvow;z=oxOl=?6saqc%bAQ7i8Y{cS3tH4ce6A^fzX0j!bNCT#Rsx91Hjjg z;NC!s=7_xjf*6da7-H=$;}~M?03d2oao?ail;((Co2^-4_WjFf3L5d-oyH70WwZ?A zxB^aC9PR+PI6S-)M$1bu!eYj@mrPI0MEzE7mY!1}ZjSsBouakVa zSuVtMQNY?ZIb%`obsw$z5seqY+Ek&_s*Mu*EZ_U8p8`MjJx?(M;j129N9Td(3L{3x4%v0b&U2<53oxF?Ps@X5Uj8T?=^1X5d zxuh!hBe-8fsxef`x^BAa*OIv6{8|A+lWI$3It7&tx}!pxBFM!rM0K|y^XiV!1AF~+ zqw%k#d^+J`5F&b39Mk<6lSi|Wal`raA$nm4^ZkPxC#Yw_8aLEMcUQkEqSZfQ{#3kNvak(ZPrpsd=Yu^J$N4 z)!Q~O`RaC=^urJNG!XurNz7@NB>-~?7610W3R#!rCS;QP`TcXbH5 zf;VAVI~uQO9*avV}k@;%FWNq2*%vl6$D+H&Cgd6 z>~v#S6LhIHKVL_%N5@{b9=edG)4-*v{}#gvPL}QVdX+nPD|mxwtuO5OzS1~yFjDK% zuQjET%R4y3Zk-;#c9Ko_Sg8vri2 zyIC&S>~Ev-2V?t=ZRRwI2Pl2hw(Lx}OB*Lz2>C`j1YLF)j(?!?4VsYN*xVAO#IQ3f z9)|D6(P!69(xfz(Xw$Ipl3?U6mx^=$I-2EDdt5+due|HDXCQuRqCfzB0otOMsQqZO zbQF0#x62@RvY|raFKJgsjYvMoZOfTH4PbI(u{g8j>LvR^4U4DKNN3pdPO0PlwW$RW zOuMNB+Hrj7JXRPMEE@8z3PqY?LQYO`d*VZr^rzY(*9jf2f~dt*M*>FpHL*_1p%g>0=!&8ENYO zdz%o&q%hj0$=;MX$F7?u_<;!bNA7aD44RtF80dB3Ic!_Cuv%PtzH3W{i}QlSFYq-& zA|ddla!MJs?J~wNUfjF7FkY^cgl98e{z2gI*%pveNAr*JIh&`uXS3>4hfH-I=d2e< zqv9OU>gE9!slL;os?`62uTQnPC$${Xp1%L&m`*Mun~R54UTW|5GN$S&Zm28-KwmDe zz5z7|xFeL@4nV~IGky)~P75s5mqp#ZFEP`GPns(GGoua&k7av2K@h z1VW!PyOG#>!HOC7N~H#OTnh!*i_IRPdj*IW9d#o}GnOj;s`u@G=KOELb|iix!zV&s$^ zOP@&L0*^{-MBz~bq;QtD%IQHm#As}he!-fBa40Y>oV6ue9xgrrMGJ!H>zUE_!S;2H z>Ok}@j{mkGK3hSY>`emp!jXR!=#~b3XvVNlG*=-QDG{3NUUS!&Gurb(b-D&z;c??? zjRt6x1N&z^DI@@KuzLjHff(R01!Ugx^_f|L*`(Lvp&sX@)T`dL=>_78;rB)4=5fgG~w+lKeb*#x6h5d0j8&?VBD# z{6kh$`=*CSL*k8{B}?2RgcwbT9Fx?hRlFcnSSJ}W&bE&^A}o8?Gmp#8Ra<&!DtvHn zN@z`7GayaF(zKUBYaYd*LvaB$_iyt~Bm7`_a2?xe%5QX6ZZQLsOZQ>xRSruF6Cbg+_Q1 zH8d_mLGJ_FKj$0Ridjmb=3C|}FxHToZ0soExMmZv#7#9Xdp`Wjcu%&fl?l}z78%w8 zCJ^~6ZGKz*{-`v?z9&ee2WcxLAT=D$+X65IhY&9E@xGw%SscE>Pe5W*wh8Qn)zl&G z*s;-O>kXsX1BX@pvlOTTcb~m{jQVddAS^*yd$@~dXa9Z`CBP0f9~WT5(5&Mf3fbrI z1H0IV?Fm#M-5G_VNZha0gdd=}q^LT`JymTNx5r>>IN{E;!~k$p+9e zfdPB7xN?lfYLH)t5Q3$Fo7SR#C6l;G5FF_dLnn)!w_M&Zv%G05ujQ_RAH8M}L*FFj zV2V+j=EpqZj_LEtmG;aHaxDZE=b}?T(2@%CT#->Atn69DC}jul{LvYy;k88LUo%jt zUF`%Oe7r!WU3_#Q!BgKSbLkpNW1F8ahgmARV(1y*t}7_7^1JCq7b5>$Z<965 z3XXEL*2)l zNy5>4;9fC}klQa@4Dev_D$()h60Tk9LqUzjFkSbMfUeb0)mSVtFxH_sCKY>cOyka`A7}I4yDMKOuk0S-br+D; zXuOy+0%Pg2TuaqkDQf`j+Cx44;o&8qqww_+J|m#7bD(ubDgjd4i8I(HMuhK47o z!IOI)s-vzDlI2Ti`%d-yL(bgWjmA?H&-q+LJ~(ZElsTu(O|sN^Z~nf_Bn-V&bh-N~ z(=4e3s`9LnGm2EweAcI)pAIxXwd89GJ_gpjBrKtDWKuA4>uKTo=rZLx!nGqD={9Tk zh#C|;w?3Su1>laLmtw|~pIsWsxq}hZ+UYzo1t67g)71#~1naHzL1dXiE~w# zEDw4EBJkhlIpjIwY2!M2)%~&>=d0PjHtN?%LAG`y0)#vjPPZ;k07q--z*k)!?YWED-n&XFs>ZM4c=(&sP$;7_hzSP9Y zhF~wa$2wa9k|ZVi-33u!%G9A1U#dO^ks==LY5_;n>q1E9LvcV#T^>P|#c__KIyD~? zL*gq=&CiuUK7o7*6c8woz)S)&B~V15NCJ>X=HoGMlbkuS6mzM^Xsne^APMxKy<3)f z*qL7fnjzQ{+qQrhb0@P6e)LBfGI1xRA1+(d1(j+bZMRzr`e&AeJ7+C{-=&s^#QzIn z>9T|$B0MJ*{y&6^QsIXQ&rF5?Bxf~gG1U7MmNX>z@7h)XBtdJD6pWmB|OdGQDP5jhFv_W=VNl!)f}rVDmew9EJTBs>5k#=3?$?wS&y%fN{ri!cds7z1(3mtmUQt zkkKGsP}Ae(c&9?iM3@5~Kw6`fhH0^vPb1Cj6yyQt^`JY`gbOI1afC@=`M0d6dZS*v zdjiP|c(H7EA=&OivfYIg(X$BEBpS4HL+T#A*zGdVDO50nb{TQ#TN22Z00hah0tpll zm?;5nePxjSO6JH*Q3zerImQmXfdfh(Pc%&*;J`jXWi2(+QmeiE&*ndj4UK}CQGKp@ zlE**ROUDAL_C4MQX<&l<80syua$+>R$tY?GP&*r;V~21cWV*O& zE6hN_H&eK3=ZR4qW@ko;fQ}c+FB4gs%%H!c^5gQ_p@TWi2SL`2QdE>%?veWfJjT{| zg2TRqZY8G<&?4z~@&m4HVA*mLkw1bz9Sc^C1#eFUlUqNL#d=XzWIXPZ9O3e*KGc2h ze?erot8)Y&t0CBGggd*BCx1$n;;>@$Mzk|yw!Rk4%TCG_K5-EQ2`xW_TC;i%m8Xxz z5kmCcT>BnD#l~ImfRfMyuzWZ~751hkzG5S5W_wgZ@+T^o+2f?;UuX3r!k;T@)O+Cf zY$)_%B9YTs9Zx*@Q_6@wNKQMaQ0x~SqyS^{CbD1;UZP2j5s!ajacB>G*al2hgU3}b zWFHS^)6XDBQvV*Je)I%Bcut{KZrRr5g$VOP$|*&)piIxW&5m6YD}Rf@eq83)>* zkvzeAYjV5ci%Unkhn4PB^2@rE8WJIDc*tzdC!qRJC<3vRnajY4RdI#9U|NSBLk$@ZK`qA!_`@`NjD#TV_I0?u5Rpo$KKXr;n4(huv%6SuaK>Z3 zzf2td+At%li%YJSGTil~&C>L{`tt6YT7A}PS|KJB!i7bteQw&z7JALByoCy)sgOmZ z0|k}u1S6ccG-Y-;Qc*Z391+_Dk+p@Q0BX^qTwJ8j;q%;pGb;zp@af2#e2e%z;=%z; zXQGUl?}*)#4LH+vD$dU!Q2{nJui!%tM&jlLo%8=zt|}4Cfgj=KV3A-J&<<#}tgsN{ z4i~t#kg_iN((y|&5(_4<4{6g((e0ll+J%M4`&Iebo1deYQYq$8%6igkZZYA)!g-W) zA(o=@rHHKYMUZ=c)mO;<3b&fl$bQu}F0;-znS8Nh~qrkC2d72ZGNiQWu(>Vu${BBPBn^=igZY^A zbtYWy7U^1PB%O4zi2C2`Az?wP%)C_n8E)eIbLxLw(te!fb_;`hx?9hFf3$vV0;cPK zRg&%}shGvSl=}ZjGOpCAmcEs0!Ax3kmn8j1o%9Xe)Z0jks&+xTc4=w>3BM@`D^t}^ zPc?P9n|NkAajO4QC2c5`wt%!>WLSOari%5#bW8Ij`WYS2dV16)_9ZQqzTC;tznjqTra z$}`SRyeBdJ3iNZD#?p`3C)GZJxS;r4V{b;GdVMzi=O$OZshm|-XZz^m3)jIhSJEI zL-T$x6&D8N!CL2U$dhi|d~$w^*8Qtw`Z1Z#nw&4uI2rMY>ExumNm2&g;!UU|smbZ3 z>~oW5l9b{8B=K3Dyq%_qpq=!=Qop#6k#;*V`OiDi{xY>3Kb7jlNpj{%C#D&Vvveme zKT>{HCn~;%A=anDF%;y2o$}Cq3`08;u8={$;z;=(S#UQc$$yef9g~gCVhR+3pnPN6EcNZwyloEZ4=3G<$SAh(bXEUUKh4-Iv`G3vD>0@oD?Fcu{Dsjdw*eNf2bnIUQ*EeMjD@JFIg)zE%MD2L(zDAYA=~3 zA)ZC4=WKbpb`-R|w&ItTUvGbBZSASI0X5a1QLr(gxW)&)_re$IA4GXO>@1lZcFM!1 z#=3XY7|8c)3aqTJn)Z1{LnAd>D1bEA5RfZ|lP8!hA|=mNe;zM9sBw5H`ND7{2Ii?{ zS)r#vh51XmZnWszr zPaE}>e1PzyzOy!Ex5!=3E@f4>r}sDG;QiVBozwU~>j&hoPP-y$4{VoqkHgr6!2>jF zSG$;x74i{!jC=$cO-$mW>6DIu87y+VYmFW2hRab*XQQqg7R_{v)u?UB&Np_H@oA{s zmkY`*&S5LD*R_KqIPCnei7Nx9Fv@*dA{i7DUmNw3eRglY!KrUrRq)b$ZiK3z`Z}e()J=sv)A-J zD@OerCvryoZ?2Ni8cqOcVYfJoJS;(u26VsG-2B8-4CdvsngJbR;4fy*R`p-Xb!S3GjaVyy+7evT_8ikQ zO2O%LP$Mx~2C)6uv5k00+tK!##If(nrbWuOJ#mDfQz!j~9VVb$hjm+iV(-s}_Rvs6kcc+|3tQWC@jnhiKZk)Ut&tb?901>0nM*=iU9v`7e z5PhzeC-xnshNsB`ENypbLOlhLu@KPR2UXMmylGf$_Ps$SFdRvkwzm*5|0|&gK^5BT z^})9X3~xIlonZpF=$uXz&8HW;N;2Ms!aCwjc<7YWGM9dYqQkkBJH?{iM$v3{%{CkL z+SBRTtjhRMb}}1iF7w^)&6lffaz5|O#c9|4n>yxRJm*0mOwR(ctjFAGP=lir(Ggk` zPfdiDmGQtt5Fr^Z-0$QjpJi2=-TS#z?&yCZppKc{@!mh8HS?CCs{uaxp9d6<7=bp7 z%*9N&6qYaE4TOxVHsH@_-Gk$&pO1aqfJGjEO)OP;nUC6`qtr>qdHKYIukBVy>jvF6l%y&nU&( zly+^S{eR)lMs;B!wPO$R#yg~Z{|;%cu|z+5yMZ$svESo1VPkYKyM3XMEaXU+GdaW9 z5~ns+24)cVJ2{RV(Be(qqT>s>QvK|Asn5N?NoTR_8|F$WWD-reI;;wh;JP!_bsSQ- zCBbvcNJjXUrq|dvPRGQ?cDrh}eM3I(GNn?-+hRHMCUDLUpf*r7J9&l9P{Su}hBZZe zsC^gW#Q3AEPMaY^UV+`p7qKZ<7G&qF5Q98_gM1UtHUAN1s}VzfGv)Z8p`4Zu&f!QAJvK=`%#ru4l7q5WOH7H} z*MdRkYj+>yV&|M+Di3=$XDrs|h`wpuJ7nA0lz9HnmI7V*o^KgX&dx>-Nq2^Fa7&3f zWutL~y19bhc}U8tC|n(O9xi-PYQ+}PDlt*G0z*T#w@(^S(CeO$92LNo$(ZcAMH}M4 zj@C@04r9I<=-jY2eIto$ub~Kxc}5dghVajLLs?iIqt-BoP1y*CHUD9Ggr!enSB;w2 zN$<)=I>ES$G=(?IH6UmNk1|9uFwXib6F>VF<$DIMuI5ZN8pUSgxQ{FO7;tt?s^Nr5 z{`J^A*CL%gQr*mouQsfsSFJ2uXWY?Afrx4K@xTKVB6SlkEfd0NhJVk7i-J)G8WAHI z?&v@kYDeS^Qd14d8PyX{alPSHPbhSx6{yS0RK$how4M(#${|k&=Tb5IqxdkU$Cz&q ziZ{lS-ib)klq*=4`j{A+P8+42VYZ^%x3<4ba{+(7Y+LvoOgA*m$f`NZXyj5o(YyVLjm z<<}c63`M&bIc6bmz;GRuuK`xXyR>zM+`B(w8DZ$##eHPK_4J>_!>8u(e} zle8SSNjv_^YwWmoB2VN-j3+NxU_3UfKoXS@np;qgB#-Ga5%59aVMF1&441E6M~XNl zO!7&lZ;yV@0_MLYpIh}Sf|f0Z8hxr)a6fz5 z%EB@u_-g$1$(9Fm@aw~#-cV$9P{2M3-wAPG2IFT?9$SmM4~*y%C-0tDC~{7^C|p_c zI-6H?r%u5Nm6D2JnVypTrZfF!-V0o{EU{vQF{M+vx}xclfRnjb3N<|+P`Qg`qP3j=YS0q{5qT!Ji3x0b7)$^KWAhA_ z%(zu3`o}db&v7zjR!mCWlf?`wWZgBJzeq?Qc2C8+g>8zR3>!Ljwp$3wFIT zEa$-tI1!0^h~{8^hbero|3!qo!GbNYcQJEwz+RkPj$v3NWkDF}4zXzWgNDe9<>^65 zzu^#TEIM%I&MSEujeF#`Mf+82nJZy13V3^KV*kMPQF3`Yps*yqNUbfm@LlbTznPu5 zkXP_o|33Q%*;O-j#>B8c6<4*;jd;(EAiInM=c6tlaU`9t`bu)UNn6u#8}{1svwNR* z?_Kg)>P-AL{dwatH{w@rMDK6)ISEP{9XPo2pg^?J&gA79vT=Sc4=Hqg-%M{)u}2qB zhmgWs&u$cpejyCLApIv4ckCM>JJ>|%ocmf(X-!RJ@qVY1Z4tSsL>IRtL@*_cgLLrD z3o)NJFB8Tj!kJn^3O}@I0V(^sY%W*GNhQAQ1@1-KQaK@CA+f0~%n4yD-s=@9F9bNf zLEp=8c@TxFk;=T^W-5Fyr|Yxt7g9mc5kos-VF%W>yo-~gQ3Yv{+1`qb6jTpNS;u#y z@kP*m{4XNzBc+C&-xo1ZVMqIK3p;dJq?SZM16mmE>CMf2A#lml5LmNPN0ckGeO{Ay_8O;Wh#E2Z6hxt zU1QPWX*1GMHOKie4b;L$pxa{4q|F1|#ZL320CG(WV&_|kZ;`vAE6y}}Sut-W`q=r3rwHPGhb{b_m(*>J5icX7OD0z53r^e)jyBUa8{ zPnoj8-~w5~EPRw6bjTfpA|^jI27GZR`6C33B@KdsZl?G3@RZt%iZDAS%e_n@ChA{r zS>nF4%8*G187Z*0$ebxW474DxqE`xHB3bjWB5l-PAUo|bAQ(?yI};*l6Ww0}khE$# z4%!P+5IVO}y%=CxY0c-{t+ZAWQ=}|5kG2<)S~0<^+-2pOZNe2J_Y8YW6Upe?dU-gH zzRN?qKcP}tWr-(mWEVxYNPKz=xEq*FYvLPi< zn=(_GL_5S@L>?$Pc$MC2JZ5=3^BSxL9%&%59UQqG)wiA4qXGR+&=!314gdHIBLZ|^p?QXB3sj27X4t_7x+t6haP)X3{3(`p@a|LL}r${R>(USt@{dVC`#k2Sc-xDTa2BiLt)U^nP3|57r@9Ry~c?o z1_?7fXK0j_-A|ZP2OO7%7KlygTwZdXl*zzE?lm|fmwxl3}1BMq}Xpp zDhyoZJWL!p>n58Gr~;iVx3cbgL?)y>>yAfcLh$?xQGfa`STlE6($1>Cmpe&a72kdk zyUba)b^@+epx(UC=;sD}uQFZyM{V8M_6g6IdF})KGd(BN`@Tb*BRd67(?K=~-=6j$ z-eCIC<-J48%U2a4Ch-f?&fA%C&O{5&7|z?&5gj;f)cur+_(AMB>W#+C-UhiRL`O2i zT;XOKn>{kfuq9Uqon3`7UP2Ls1~FLT8In}SW4pXEqs~%K!yTD&B3E80aXk`uqo?6+ zuK?132NKbUx8f?}u{(5fDI`_ixWdvUqmZ2v`!#K^kntCgrko#qf&7|+l z#fOVe+PaXq<&STifG#060_>cqe-K6YXF?p`(kaP!6r~=+sg+@gv_UCsue)2?Cx3Rh zZXGMJy{_&--WbzrkS}k@-Y_vc`k_~a?_Ou$@rVqly5nwn7(4E$sNos1XHP6wcPx{z z%u`6so)%IYre*8PczF|eOjIqCE_&;d-=N$SoR?d3fec5U7xQ8n81Ht4J8~=E)l{@J zJksO+q>Q!rM@vp-zKRd)egnm29ojj+l3pve8t1JLVTZCSlTaAeB7kv)y|QpEbUWGL ztDB8}+qui$i z-lyC)h15au+JxlQb3lDfcQ9HW5Ss8f*p7z^(8x6}{oUKAK$lPD*6vvZwJq8rO1J2+ z{gG)w{XsO+@RcAu5e#(q>-!3l>_tT51AD6^!Xuxz8}_f5f<@Txe))}(9)yPXayjOc|6vlDO3(PizBvP?HO7VqP4O##!mMlgIQiKV&&U^a?%1~}_h zEPL( z>k3xoRw+^iVnJsq$k)bQiGL)C3hbqz=A9z7NCUG1yRMd?u>?**Wf8+qfrpz{(B+-m zfniDpMh6CzDI6%(Qk!bsLv-?qIiZwOZbhHm5GIeunQEv3;Jame<_dzp*A|s~k$0cCH06 zO++*c;>WX0Ul-DHM7Z_~J+bHqpHYKG!&{)DX7_+lQNc|ymbf$q|LVbjf1iaJy~gK> z7EWI+lp~LD+&;lVj~EkIGu3*pXM{J(JOP$FFoV%Fiw8vv-Sowc`Z~s8oUv#1QTN-f zZAiCIpVk@Ex8GEK_j1~D%;bu5q<*-P&og~8bJ7)|aeYJ;1@X7Cd>B*^y$mfB?rGJw zAK#`s=yDIvsJ^0m2s0KXVkw@V>MzwF)_pWWt-W}mVtvEyeGubvmM^9jARkL2VpvKz zE@-)7I(`qh+_x;>3SnjRjt?8DTrHT+06o;k{MHZZ^%rP@S^o(G#g-}g0^|l%w0U5LN3&=NiPp~*!13=T{&~BllK@Z=gvB^rFtoK*kxX>_nRX$4$UbKk_;5g z3k<1~a)IJbvZT*aUr(CS{M3Dkj{i|Q9vJQTH>K21>G(oV^^gB&oj!UkbxK!bREqI# z-D6;+BjY{RbJUFQ;=6nQ4j8);0{C!->4ZR}9HzLD`3 z?Y8)vllw=2q;0^Yy(q*B%+>m6+UEy~EaLBMz%apnIk*K9S{z;hSjat-1NiGH-VanH ze+(S06Kpa*WB}j0hLEXV{-DwL@3aJ3p-4I*gutDrM%so~xeVO7f@_efrSapzE9~{c{;FMt7VMNwplaPwOP~b>VdR!M3gJU%*5RQv>s_H5WU9MLxDAs z{#X4Qi;TwmX?HmCJO&+P(_rGf)N@#bh*+g3!=CPN*761nyCd7cImLARfRivw-xfI; zJ&ADS13EKnEk|Pf_!OES?>Ubi90_iP-I1i_F=@HDda*okN<@7}E3%xez>?BNMFk?< z%@KFqFv1>Mp~62{X&XCks$p?7m8*PXht?!3SNK8Ralb4kf?wdH5Td+VsobddvjNYc zLZ$cPsEG;FA2T-p3q2Qrh@L8(b+r3qCYB&PfT48ymaF)zt>~7Zo12kQ;%f3I7opE1 z`1t>9$6mTb_7`BUB{*Gml)F2XWu`QkO1>-NFYfx0R4uvxi=C#{7bM@|gS&qbQ%cJG zVRLeNQmnY8(vS8BZ^T!iNO?S&L+i)xqdNU|qBM$=!aG2AzFU)wK{ZNs9%xr8dLNzi zD&e09Mwsrud*9Ih>r9~K^6Qal62xjEc$EUniyJLpweuDjEjMFL5Ldq5`Jh%ay(tHRutA9idzGWWyx#bZ8~%PhFGf_Jp4iN>;g=ES|473m^&j<3{6EtTPj8 zWoaZqr7H^u;4IRm#ZLJ03{F(U-X_2r$eU{Jmfi=|D`C$IVO&v^s%O*VOY^_U{~vob z;n5?g=Fc(%7(N0TKxl}+bsjsY6;U`d{@v>w*M zx{itqNc{vG`yZst`bkWZePiCAms%IsDJeIV@)Z^sK4fbLrT!AE$=4318cJGk^S5reFj`$W<+HK=&S=lCQ+!vQ`ox|l-TZO#0nJ>BN5;L^4mW&; zPRfrF?rY|h&Y&;+8cW*zoASAQR+QQI2=i9yH>fEUi=#t16*u5rcH|qGY0`qzv>NcD znGxIob_xQf@lDg7or@EYIa<1*)r)LU<-6h#IK3YzWsp*On^W+O_x>Zf7o9?6C)WZ3-{CY43b!ung ztHeO#c{e+;#xp#k{vgJ9T7>DG@F7igc?K82_UH=ov3xj8egUqS4Om}{?3^F5IW!Ro{Wpr__D z8r$g5wtec9+AXM(pXjwb)eA;xJ3vhvsBo{>A*ZhJcZJ+uk|3tP7Z#dpv_ROTM#JsW zhe%xQ4~r#1XSx;ibwKagbXsl!HGD+C?*nAgrv#(DnWb>+%1)R@?xe(%7;4zOM5SN!M z2@(ynWQ(>uSIQX0a7SRm1<^GhmYVe%MIr-53z&6!*b@_J2gX(;H~c~=UHI1aqf)VF zPgorwZK9ZB?JY7No}~A~;!q2L@lu((GU}RG=h4BrPYUe4^|QezM*(m5`_Z=`44?G$ zzZ!k(-sm9e7r$drv36s$bhSqxq@@A{jK^Y}VoDn!stmCGAlGqVm@}1$gAnM_9d7K`i7ie3Jh@7A}DAp=`rZg9{nAy(s@xgbwkjq-X8D` z*2W*^6B*3tnd}q6Kaf@;QfVI<3+@^V?i~%z=im}Bc^?DhhJH61O82roDzZJd=yYjt z%8=4biEGn6oZKG0do+>TRu7*UB{d0c#G`HLX4`x-=Ue&;Vit$F!9mh2}UD=?*t~{U!L;T9C)5zXYQ}sqauUN zCrY#kT?u`xJt{5}q+jZZTte+pvDil4tn~q9uhLPPfKSxplCC`(BvSs`qe8eZAk^fy zWq8zo%;eWtqF?alTcGR`BIY?c3)O!V5VGuOM!sZ}U-?sZ9?{GSTOE&l5%fE6X5Bw7 zNKi#C2*KmqzYYaZV{L&0(c#awe3o20LD#5e*f%7W*3siwv)?t|fysCO(^a1rJilHv z?%Jb>j%PsaOI0b`uRSW@Lqcg_0KZ;!?EGGNd3n3ul+yeDcQ`EuX2geZiz1s;-6h)> ziF#<2NRDxb`P2;rBp(W?8t+CerXm`4`@QKb^TeAK>ZEd-|I(uz_J!K@tK%wP$uXC3#F?2%) zbT1IpSu=hA18x)4&DArdoN43>wLcM zlx*pCZKnBdyCfa$=fircOunqU%sL(u6#N9#xV!5V*z0OqJq~ZJD_lWDaZE%nWD+p{ zg**B}t^2_xe-#WAr0_NrmS7lRV#vc8tfeR(DeRynT=8eYOc0em54CS7TurJ;ScG^f ztRB&#)?ws426UTu6*lm6lcEkf1tLh3U3D6izn97+#9rQhelGl?1i!q>rWmhA8zp#T|AI$QE*IwlHAg=z7SA^%1 z(NloqH<;H{SqQp2Kk>lO)U2DZQ#P>FfyXx^!+)yk%a-ba1Ls2tu{Er4T)XnuACKN& zu$AJ2<&{9D=xF6fwwVo~%oFp0UBtbh!!a#GPgxg-)u1jrg&$MyC4W}#Js&syH|2FO zuWLAIr1x4Opa4k}`x?+4bPKjJnhLtD zSw{kPDGS5W?Umwn*3Fq!Zqoq32Qok#dZ2@h_VUKVHI;fR2uoFC$l4i2f z?vu|r;MmTSXhXs=i4zF`iV3S%Lr%DHAdJCz7HE%rB1tn(l24QHLvHxuQYY^#^8TRv z{sqf+wG+aEs}m>Rj_PMJ>=`Uo{iVW-zC(*IIg35ovox{qNAj{ll-_G|XpukcFu zLvY$JHoXE_7#lD)i(HlE42iEV`7Pm@_yW1g`Zzx0>YC~Z#?7?2%2BZmi zDNDV~2}WdgiO!wx%>9xYioOjk-SfNxV7ooMz$?>Gf!vfPfeV9+9CcK6(vTYo9Es66s#H=Q&OBu05kQ`j)<Nz8hQSsxwvg0cBLnn%^^nVMOe>x}tWKWn9WY;3LE}OKDphaOdJX0`O;5zUZ5tjV|*KuQjiKp=9aqw5H zHGO0+NWpV0nTyAhN=9I9;W}N5dsI->gOq!2J;-tB_PXcC_<9gYaX#hz_)qF<(L)SG zuz~4G=1OKjfQBe2r?|l50lQ`kj|c4Oh*7|vju-{(>4;Ilo{ks=?CFS6z@Cn90s9%6 zL#qVTreR_!Xl)9NW6>ZD$pt1S1$!IAXW35o#s??JHcCDM44361ibR%LTeu<2$}Ivq zuo82^jQbq?fkaM*o`roNc2z1?$^o`$Mw4Cu=@a*=bX8Ea2mlT8Npew7b%@FEVSqVcV z5pbZ7Rlq=ks#HgMm>ETPDYyeSj~T&$Bw$_r9cxTaidgYLE;p^Fceg&^?QF_O=dE*h zli){Ez}@<|uIx#63JuSl*OwR_*)75i=fF!9Ci6NTw;G+-G_o~1ujz=-n?_Yn3>PY?*%dmcA z{cK!KjbV?;-6Tjd$3+{Y_bR$2$tr1ITYE82H6+>i5@cxuoNw) zFdwoqCRLLG-wVKt(lz@FzYMMixR~#Frz~_fq7b%0*xT>I;_o zj@R8>XgPc(eH%jl7I{*a;%nKL*z>$*|I7V|R=g$Rs`1mb;H{Bs7>U|9<$+R=pMs)dZ&StvO#syQIwweZ zA0$hIeYffQu1VJyUYI#rpV6YB z>$u{}l{t)ggK;rZ;r`0!q(aBKb=YXhrn0m&3-EAUjZHA*u15ezRzDKqMxDMdITMx_ zVhrsGAuWg^O$%h5ob#ON`z_Bio|o7!Ro_P2`6N6XPh0O_YCH$^lz=)=o$Wu0T^duh zS}O0Cj0)NpubTdjs>_TgC&Iw?KegeA|EQ^6tbUCQ@Y&A;dS4t{{*+t4A0?lvFC*+D;^HM4 z^Vr`@*x%lzXij+GEyYzAl7S+V3G4RQi9N!s9Jhb!!Lq5M;v2^9=e7Qvwlh*$6n(o| zqu;&(ImfpG8lc%id_w%Cy?F*f!Qm%)2H1^yyw-cWpXoi&|AHFmjy+z(cZ^UVKe!Di zj6x-KGvjwMJ}$G^U%)>`gFv|2kt*oSA`DqwHANRHST3jIpuRDvVe$CPzv+~m6kOw~R>;A)+wZX!*(Mfa)gdGfdP`Odru=6sWwIaLmGa4n$_i0*fXB zUaydROoe>LqT_6t*)GD95fqsw-%d&dnqjQ7iB(sHokd8`{^X-2&h*RN`GJ(|FI8BfHg8BWM`Cyt-K~5I!2w5j z`7FwvEDh{0d3vDFhh2H4yoH{w`0`ZDH zYZb0Qm#|7+pNL>sMn(xb@*E5y^`g=EAv23ukcFpaW>-WXV0qO1;|C)dSI>QI#B=L! z+#Kl>2>R3{F#%A5I2w$6=xHgqS>S6!5^rFJYA^2hwHtL;QZ9B}`kSvN_3i>GHhOY~ zvwn|BODx|fs;|2T{aM)o$lxBhm$Lw8>O&k)TDDYVw+aNn`npgKKaQ6s_z!GB5vA3D z*V8GkW<-EBI#K{XhX9`C@n$&y+(gzFXa=(Xs)<0l7T^uVk560#A*1+YsplOrp&vh0 zVB&|Sw@~kAdhvX)dq^b0gI(`1*#9odwn3QWCJrY37+*(HefEElOayu{t0w7&Oy7~{ z8GOHKH}8s=X8@w7R~JiukqJ zFbc^}BySUb&Znr(-gl9M3b*#YiM~*{z4ukq&UBh&j%$Zxl8sIO4z9(_LN3TCVeoLq zB^R0)aHYW4$^l8g1s_1DA~Pvoi4uEXlO3c z_4oihzjAtJMpXnL4uU&j#pe(hnUdbOkIg*~nGmfsj9_{>>jHG3<5DVaW zDcjbHuDuPkzas3cEi9o2CAtTH-pGyK{-gBAlKEI12|o>;?7wN~HRm?;QEZ~uFi)U~ z|809e8f&kWZtsPu_SU3ElLkBUM}UpFTxm+ej!VF$kvXa@rRTMw-W$Nh4!4(67I576 zl!ey|1cQCuzAj6(qT^UA100ULitx7SZ$-E9J|QQm!Rl6vVaW+Qzti+3MkX6#IU?34 zOP%!|cOB{5r;dED_$2!ZXEG1ZxAPtbLKV0ATKykYO$ey>)e$j%Q|doc`C5F~%ZBe7 zPMh(%o6NPt!_}D?&GKV9H+YPteb_*7ZufveK);ChOuaWgoY_CT^T`pK^(r*AMlLm| zBW7co?H6p%QqOzEhkL<3N^llJCIDyOh?cC}FiEvTf>c~*fy+ejFXVr&B8W`p zGPIt@PNAwjPxb)swXk0AGtzVM7E>WA*6hD=smqmhk?6D_p7K%UTNZ|Y7^8>v7%gRy zqbL1FlQ>8DAW@Fo=+!^`ttX>8Y^h_K0-%?DcaNxze?U+6V#ysll`mC&F|{vkYdQA` zw^^eVg{kOGGrAYW;nTU5zm+?h?DkPwL1h3sfsmobokZ;ZP5GG_$q}JWu)5O=n`=z{ zVZDsC=}nf8ESKa3fU(34FP%xjJvmQ-NA7`&I2bC!On=Z53*u*6!ugzH6P zCS_Wl7knL-KOw%8v2UAX{h;2R2@UI6@Qhi7{A3DZ#9mFPB>Ozz{{VAv#vMb{4b@o4 z8!r%)i&_2q(jH5FLmTrGKN}%+1~D0RM0F=FgaMD@jz~f+$Ceo28>SZsNB{+wqYSC@ zi(%1{=E%}|Na0FSTa}q;pwrsQOsuVkMFWW_eUkZyD_`JCPN5Kj3N%T`*I~3wA>Gn= zJ!F=w^#Qs2Lm)v5n0x*NU{`Ap-{L+BgW$#AJUrmdCu zLNw8rDD@{RKV0Ojodl*jfb%!X$z};uBARqC;Q5egs3@F_SRR1pOkImYtv^hOpzsh zy5mTRa*dLPrEBXD+Y4VEc30WB>mB1eYK(T%O!kQUh16hBOwwZ28ZkhwjVXJywRm8M zM3T&^Ka3!iQFj|}u6S_8mut0faK$CASg^6BwRYGQVvg0dR^$*17H!n`0Wr+l0ayCD zl~78em^A0}re$gBpCS>*nW&@Wq$3}Qfiu(&NRg_~cpx4h$mt#`-j7gXs=^22kQ#g) zsahY1W9HI1|KIYE)pCz)hU#8zA?<#=yYz2!RbPKnqu^ri?|Bdm73)v( zW2(o6Z_LT(8Ul=CPtR1UfH+Ug^0!fjunr7I$eE7!>n55Obxv_%l`1>}z zXR13Tw=3`K&VU~AvC)(fN0b|XD5PWHWW+1JLO@F|{bhPsx19}vOu2(71Q3kE3iPWb2ul@dt-MJ%@TkkAbvUW7 zyG))(jJjp=JY>|#707d#nEFkGAe@v@IdhWFcm8EOE`lk%3uma1AcW75s+DD*Trmbe z-0J!4rYBMIn|!6XFS4Fe#YyYN7l+8n_~OnZLkf<|eQmt_d1{S}wnxf;5qL)V$1WT# zfAsUGH}`+L8OHTbueovkJEuYG-3%Z6=QZS?-Gha0hQ|Lq!#N{3jST7gO-P*-FpLu= zZ3_*{_TlL0a`dU4199sr$@`9hJR=ArPZZ zP$X^sW19|mD!z}WY{?71Q=Dbvt!_Cv@S-hy6gKl^`YW8QS%3xPaTZ9DD|C{(q-IO} zlW>f767K_a;InLYIB|g_K=!>jHtsmKZMUK!xV|ub61y1W(Tb9n>95fKXYozD^S+Po zy<5lj@45N!W9j@?`Q?U{T+W(Ft)FxA?*eoGukzo=_mo$b8b)jMzR3(Mzg`phMd7{n z-J=l6&boDW5Fzvt3~_2#NH=2N4ECjb+$uB_oVM7=(y2J`>WE)Em14oP^pn4KWwnF1LooO_lq@iqp8cB-?$ZWn!s$7Wc zD_}vkluhJk-DG}nP>rRPqOtJ}0v#jO*#OPM?wwnd2(|OJVP`gk_=Ok<9Ko1j-nY^ElhxAUu@Y+VF$&)oKotLnqKU^O*HxT zSw1N2uV8AU_BXUZn{%A!%=!#kRQX^dD{srRJO?oz%rOYaG0WCetlhBwF zuA|28Y1Jue;U4JXFM**syPQyxp?(G~%Hx0j5ku zxZ5aS+YNk^<%m^+hQx0U0d=5p+P{&L$ga_df%6M5eze3Mg#s<ErP;Q577J|aj8^l zZ`_V&V%etlW?lEjU6@9AXt7hVJHy{@EJ5^R<92XX(RBTL{70`Ds04S+df~%CO5;WR-a> zdqvpFT9FHV6q2Bza+VzoLIL_nY!GAx^TKRJwykV3_>73$PP5CFWt9O7v@Wq7EXxXF z>w>M1uCy~-YP)_iRajP5Nj~Kqpk$eLR28KmIrh2|jT)1b0q_o~h~Zv!7yb?yCUU;t z7Fujcg_?m0&e(}W1xaW`dP6DR(n@Qh*zyvZOyD@2fRFgn*0%KC+Ip*2Ti>t>Bq1aL z-x5$>#FwB5Ge!ymNDmudY0kR8>6OtBMY20*N6o*UV4Y*RE=X4ri)D)dli= zh3{c%ET*F$@a?KW=7X;-R#iNfw4+LMd#t{Up-Kgayh^Uw5rZ3KM#2YdW)&;O}fua%a1?k^$}sYOGIO;Y)V3N%!H>qk-{NP=Uzz5>^(!^)^;*s($0- zfW48xDv`w0e70TfiCk+!Zpp^RE~}kYvCG}7p^?OuMC)Wj6_;uI3BxA7)Gk@2^GKpZ zo7!V?14Gvz3>S4HkKsJND=GO!iTw^btsDgoXxtAV~aCvk#ci&53R?)xa9znt+$ynJSbgY}WT7ERwUeJ3#OyD8zbe`R5Jyx!^IF&v4UuY^p9I`^!hZ9q?&COfcCrt{3CWjMO<|1JmKWIwg z3)dxXM8#B$s&w5K@g8s{+)-iDu$!AI?nKnV%fC&;}q60`aFGT@v z8fg2h+W_$vac+>Srqf*Tf6h#Q8tp4VN=(}a!i9(;)%Hi*2ezF_+x|=cZrjpW(71H< zZT@J{D^`3zGhu(hzR|OQlH;?mePdSGo|+94joX(ibJKPhCjRRH{vSiLv5V2M$hHEB z;liPZutw3oaEt@lql1y&>_rTg3AqH#R%lCiGUt&zcy2d@C1Nl9hkotwF$!VLuf5id{bN)PZYqZG5jBipa$3SP_^F*NEsDEur*oE5&jG-JW_@tyO&SCS}! z?e4~>#)8XrcY>8I!sA#)(MWCm{~sG%q^ddOCa3EDTo`d@aff?D;e< z=H~X{ee*UlSP-PFv+UTF{<>p*L~U>(ro$B|7`~D_@Le?z9ir`yp7)IW2fGcY z!k9Im%WSbsF=LU-;oTAE-$VpAq9zadnk9R;H{E_o>V%myWkgZ4t^}msplsN8HDQ$0 zpL5=qOYGN6oXX&!aM8|1U86SgW7YqX!l5HA{B5cpiYwzm7~+1zKAXd%ywjU`popKA z^if3`?;~^A`R2)}Zh2*oFDZOI)b&350lP+Ikb8s988N;m;Ng*^@3Ep6t1m*RFZXq! zL8m&mMMg2Vzo9H%+vKd-is56GX)FFsAy?H-R?akrvjvZTEvZt{5c(;s-A>~WH1w>5 zcd2sHP4lS>cw!N_`=#`ECLWd zAl9?FJ!&@-s`6K4^)8Qg9V=|nJzzG>!e;JR+Dz~lBGO<)r{oz}5VRJg@m3uSB2i`9R%f_x2Fk|x?nrtqn4gh49wRR#K{5g+N2>*iC+6kGy zw&V}+(iL+q`8N`+wO;}XrdSN|WV!ir;g#mgE%>8Ie|kGPj!)LwTLzOYot!Lm(->DP zf&Sk9M*0IN8oD8M7GDR%pQ9U}r`}@B4NZHg9_KXwmB!x8KIqCI67eoT`*fU6?<&Zws3^;`o`p5e+9#PQcjq zNlz#0j-C%c#KV@}aT&#IA&oUTa7h&odBQuL-nuhLl5 zegSU%1Dq2w2qYS#x9kZQZpEx;BWgvC7r;8mNIuY_;n6)pZbjFanBqs@YBgrk4Mhd> zx?w_tS#ddM22ax6kV3NLGdmf}A{k}BqbPAvH!7H1LDn+pEgwg#o~J8ViMmkRjxtM3 z4-oD!6Ro36iLcA3AC2Iklo)X5qf;HVQIjk?Gdj{7B0O0L7e1l7Ci%o9%(t0DJof#B zJsI7Ye1#umX!LJ@X&aVyI<}~7ezDEx(YS>S6@Gvyh;1kRxh{1!wvGX7DSBC=4>6~U zKFfTHsj&weS<0d_<4yXQVMRObPs6N8fI7esumb3OLKzSL|IAoQ7*tH%$T^6kfeC#& zsxNh%*A=1Fr@jY4OSkkTNK)IGK`-fE_b3H zOvU-^@;yg(7&|pZtzY4g z!w4=$Px|+hQ6HsbyVn0sf3~bo%^1-BmZp>rd>*|VmjR2kPJc?P)?1|*3${xzF0($* zXP*wWE_UF=#@w#h7#h{3qpTc#VzZgr0%1w6UoBFNK7y_2wm)-k&Y3twj336HlQ|Tg zfN*0u%MLq~UrfNNgU8t>g(Qn`S;z)bJ#~=%e8_Gtu`!B27%s%jZgb?O&F*f3^xX-5 z3cD!g2WAVa-_DMX=%YsZ4>@Y0EJQ%&4d=t1(H8D4rW`hb6;D*O4G&0>n8b;qol zpD3QvdI%7E(BSVhUEg$UsCbcC&B?67&ZQIkP$FYE7hXF3gk5?(QdEtZZ(NF+Z{VA% zaHt{X#^bO%k74Vn&)GYA9>NvQMh7?aRv`2CULUSg^myLy@APHhAgAMyHNDv?;HQHB zl{=JqVXpGt*{BQ^>v*XUA z=S=OTM5IX7@mkqw6|~eW8z@6Z0^QHhN1QoJj$gNMtj>1!t5N%K%wAvWRM&EVw@;B&SUgPrsk*X6qT(KL0^$8oR@fDRjBK#?E z@9JjTIJ2u zzMa}X7a^!;QE$yA@iAy~(5Hn7!-|r#YF`ZZs|5ZS+#BN#4M&MbSidZa+n_M}B84Xu zh+zyDs!N@*r~cPEFVCMGv*ys7yV&o5M$VZrUrVH@t>!u0W?{k7=8Fx+$9H7#oM2w4ZXYIp zV^}>9+(>$k;pkQ*mdH^VT+l5yUck@OpXCkG@Nr%D(7xQ3x@YD7J$q46qOKRmENyji z*`C4DCZL3Ek``UvUU!&J`iGuW{(9Q#2d`2#bI-y{Yd4vd=~Q;NHlLT>r|iY(oj9Oq2WOKGky;YugSp?& z)mic2il;a^+Ps^S8OY+4`Rcj{FI}=(xtt}x4)ViNw(m7=Y3`LzDq%zM)z0YrSr00K;>4;ZQm#Y`sQ7OI111ED(WVrW@8sK*D)iz@_ocn!FMFh7jstEGL+x0 z7A6mAP#tloxY77-7&P;JFlux2$-!X%u%}>8*{5|^9>TLnS9QP>yHkbhx(9{0`OXcc z!WK|QHC5mRtQ?}3OI4zjy}a7q<%51F%T+1w&4W4duyW6`8_`Iw6*E;s2Jd65>It z6C)jbXZ(xn*I(NGg~OF|W)O{&SYk4fDqZyk0aeb-m5}`QC|Y&ugRA^rjY`$F$c&UH z3rC=myGxFQ(7n`4X5pf3snz&<^{DDuVP(X5T-TcAbfow~I1KThLWcq@8pgNRKl^K1 z6o_%~(RV2F0L>ZSL=h+P7++$}3}l@wapUHJ5w`ED3hfQYuR`kl& zQ^vj3Ggr{hrFE}RgL(@Ysk5H?aTWj=WZWECYn$qNufS|_sY%3eYkn{nOSkrBG>;h3(tkS0J@@_9x>^rR?UiN2GGIX1K177pH)p{cd& zgS9}AELrVPV;O%7IrEj;oxR}7a7iAVE4k6w(VpfMTcnZ*GvCo{u@ z6V2oM9F2a)m(@FbDa7n#iTz;|)8P7@;IcbJ! zhFl@Gz1aQfh!plZONT3o`!^lU$-#CrQ$VDf;H^syXe`W8t7q8;HsJbP+kl2Se+9T1 z{4zauZCVUDh}uoWZ}8mHB%g&8CGJWumE2LBQH|h-kh#G0#?1XD1x!rsU-C8QnPChbV-L*dZ*Z!vJ-k6+Z&J zv7|xUzmF%@Oy&bie8Qp8noU+qeQ+ju(^CjBb`wx&Tue>caJZ>5^e0E2RY#oF8Ck59 zA9wWiaoQM!DL#L+?(;E%TWELc7FSkDUzJWAD`cAw{0( zu%03?E@SbCh*@$G=PvmXV0>YH22~AP}-kSy++mexP1H zlm*iz_B~OS#lR|a$NS>F2T+&p5ElCe>8uhs()Csak*w=`42c|>2Z$b ze1Ui=Eni@OabdiXORGoWbV%Noo)H@ntshnt1<{zR~e zXQg$zX=dGTcc1f>-t9h{b)R&f&ALCpbF$!JHd3d4z&;}yWCSv1DBSC34XAf{9*qz< zp%J%*<8y+;t$Kwbr*CC2og;zS7{(uo@gW-ISSvo624eOBuCd@tGiqc_ zT}~?Tkhm00NimXr_7^RU!7jt%JW*#DGLKPNO?>n?%Wx7NfnCgZJ?m1JYk-`nuSZOp zVH;PGkYKI)rN;dui@k)!J_V9S_%;?hYket57-;e-i;l=!6|P$ZU{g^uuh zM%xla5%QnLb|=YC2teO@Hhb~6LHo7jjgT0E5sf4>L^C@`RP3_|j#O>{TRk>ZyUx@@ zoNs1Nqf;gQ;%F=WppqB2sw<~)pJ9<>6N1WL^C!puk6th%5fy?g6*RkQhN@1`b%Yk? zDnZv7y%O1j-OdggvHihh%UIJZgs@(`B%QbAd&u4|rm>qcR5&@9n=Jp5iZ794Q-*Qb zc}ec=Jp&2Scf(N5Z7$wvW1f7(Ga`ocCHJ@b?y zxq{D}mVpV~hUwCgVX~6*pN%%*lvBc=lSIL-$>t_KCcBC>BRpq(vW)7BH=*Ra(`u{+zHA$~I9M6XSAK`k;#@^4wO^L53yMVecL*xSsV7VZ z&R(*z%y7yu_k+kq9M7*2FXd7DWW@O)nglr&<3p3_6Z+>TRj#z6>ra^!DD^RqFKa&xBs;i&uDvdx!+zE?`V2`hy%yMBPF_g{uPQ;Y zcf96hnzqE8A)MYakNikV9@v=urf$yiobSs^=v8^i3~iaef7h3h-1RS7B;cztUEIG` z?IbHN_7WvQn0VYhK$$Ke@5xQRVakA-V8F0B)Ix2sVEE7kq$|Iry|rBGg2~@7Q_>6n zD!y{0Eayl$U81Mt$s1HV_(buN7h;GO#<&@y?AWo(!FwzI0(cVP#1SDUv*OKjjORS7 zzLx5>`-`W`7e87)YBP16)3qDUCN2NSzL%uo_t5wb{%0FzL?WtTAYW9%cq`^{N6`u z>sXYs3XU?C3$LYU#Bp8wSp`V_rXL&ik!HyMxK;21SzD>5U@PezRzW+2$N#idpuumq z3SOiF|ECXGEge2^T%AQ@P6J_&;q% zrCjf5L_!2cRjVbay{MnS)&wE0TA%}nt2>jLGAq7}neEw_yy@Rr*aP*Yt~};&dWmOo zQVl1TYyUoNM-bV@#7GJOmzseaMr!rO!H;B$)C34jg^=aZEl`nOMe zMn$xSo8lG(w;!6{Ma1`Baw!ASQq^5x$n@BPKMkT9HV8J`hl8tlPCk$lt5HlV3FD+0 zeI2VMCM@C#QSzVJg@L=fvn1|PK3<1i$2z8yOh$(~&sLewqzucOC(P8U;#^>=zy2Fg z&Vr8ql5R4M9I|d4mby)~u!&A@24!@VfEFh2DyA=wdo5)?vdiR2-oSAiE>Owh7C0S4 zmJSL~kNaWopEdHk>N68}nLT%N^$eUj5b1U|W7I!AzwbVBP_5fUHEne-@E5V&?k~6> zgf^PWezdXT*(@zkM-x8)bzJ;TOTwM2nPP$^5w`(Ag z1tP`BVT1@qE&~v9{ELlPrhQSjJHcGxc~LV`Wn7g@PA2>O!ZtaixStP$?-KtOabQ1r zGwnzSE^-QUVpyKN+7bMZCQGN9dJMmJ*BDAAo)y>UYbkX`H*iN2gM)**qF&Tn>I9#d zzuw7R7jf3CVA{C*>#^$#I=tu+7ySV&oNZ&Gg>LR-1LW}!SAgBh(I&$H(W)9VxWkiuZWyyjI01C)ejQ3+z zZnhnl+vn8jviS%mdB`iDrsbkZ9k5(5D?-N#P_r|DZ5*5FhuTKx88=Q-(XcL zuFg-tZP!~c{q~C9AVO|A`crZBi1ZsQLB-W0({CMm8=Zb@)!Uf#Ta(_#dT)%N(kP#z zC`>!8cpvD4rN*d_xR7GD#?*^H6=b1Hbw`IR++CL%3e2$eoW!;_`Hno~_(0?TExb zMgGP*`{bCvqA@>@$mi624miJJ?KNPlh8&_*L}0D6#Rm{!>9OXOirT_SN+l`b{EHEL zD_1~#FJL@_<+rOY_Xp8G8-L`6%FA;QV!5$#C?K>gyv8VjbJr@?Z}%V;q+g+*{W@rc z2cZUrkADx@{=%6YO7ViycePVF4q?%IIG5l=6ZNH}N7dotOl(YbmkSo*465O9Lv&(u zXs9U0kQwR)wcuOL+YpgW7-sNQz7IqxbE5b@*iy4PG8o-9=RCwp?VKFia*ObwZY`G~ zhS?JOw>7RIobFg78M^00--`I=npk3qLS_tJlFz2#@ogeo4enN7kvV!UoXw?~XYg~| zBrG9r_XPcP`u{;^j5>4sf#dZlJ=`J1LnLwxSB-Tu38eH z7g8V2rs3uH>qV{x3Y!y4mhm!p$x`z@7M$yKY}ll&reoRA|BB2D=IEs&bBOuPX((s+ zHoRSB=EWvoMdnaGSyMBIn;g@clJBe(`%|9zCBDNKU7~!6$7j+EQ;R6=ql4D;q`D4| zv_b6Q5-~+qeJgSzk1ZtQB`dyTy792_rcA1_M z3U$%to}CdG4r9++3-7BzEO^x&%y-Rid8YF{^A6gXBMve*tMQ+?rcM3(OgMPvXC}gt zs(0Z!rGTfIeWcBSKiN0R6NN}jRiHzD@=s>q6`3uss9NM!3U{UaNE>+C%y^T$jR^LX zG2iJ1@a&Xa^_P`>*Q>0?t&Ch^DUC@`rKScsr8RljR5OBd9QwJjndF1Xw}%niEzR$p z@9XTs(`0hdO2BeX*>_E^GIQNu`a~r`O>zsfH~ruAl|fv1mpglESF`tBezkr;pFl9E zsnfKv2LFxtJN`*_xpq=2@?+{PBj&(sud<0jwF!zhAA$)sLG^Ou)!*Lj~oyV z88}r6>??!1uSRx0i5>b04HK-@& zUF^1&qN>VZxl&#vCFVSKSR6A9Y+1x{W#iJp)KW_CtN1mIujE11l5w6j^^#q))gGN% zs&vo3+cVqX{5RLg5n_plgSC7o<4hr34q`iJL^0M2fZH4w_FIL+gN4bE-5P3s|NM}z zHPnRz)?LZ}wL>xDS|e4jnx!wxC1-x7#0Eo?U;bYw`o=rq3z2E;GQtFGL39S=o5_@% zLSYzYvB?P&TgfUI9*kq#6rla6qoW;|j(Uj=#%kQ4vtnYjGT-I)>(4sD&VyuFh1mGe z?d)LkoBwE_m>skVOqwd7nzT?t#gQPBa?Z9cVPAD{9@E1_o*KD^%H*Z030w{zAVGodYsyJk?arm{@aol{^no<(;VoEnskMjHX?v>i=uI6m)-_(`;J z5#eu)6m}70weh&=p=QYCGt?v3(y6=*NnB@*q$exgDJ*EU3J#l=KtB37{Q%$ip5qQv zh{ym-o!_A2L<`HXv>;G-8z3b^m*_k4{Jj_?sB^{uA+Z8ei^uh9dSXshNaJ(K>?TuX zaw3!@{kE4nQ5SrPBueB4y$+f6LW@>GYdG<&>SMX3XM#SsU9QNSU>2-dI}hfv@OPr}#$8})@w+3#cFILC}!1-$tiR6Ac=G$ZTcPnr$+clo*aUcp9 zWQ91M2f-yr4}t5myks47Ofq(iMaODb#P1`}WI~3N!~s*~!$B<^GHYD};uB$3I?(M^ zo(30|?zcl>YkJc{<1bF%{1VZ&^OVDr-dFM$`k{oCFdAr(w=LQlsX}wf?H9@DXOudz zd${xSaVeAFjCfLmi(qK&%z28z`7bTClcnOBI9u~N0zZ@X`+AFj9QAY(1sqpOh^K_b zF+;p;(@b#yX}NK(+lzax$y=<+kgOX!txLDwI>ahCh&{dfQ?z9fa?-##J6{sRvDL!e zDJP+iebtwnmCi*XO(|~L4J*_pxC$oYLDC%k2_T&}DHD}45sS(9YF=WWRA;7dvkH!B z&kR92Pw^K9E}w)G@@*tm0@J--x3+613pta6KIG9dGi05Dzhfk<90>u%mb5Z6NViEQ z&IfQyGI^l{ zAmE^=LPSc1V!o>hkrH$;e4`ry(=>Et%);@f`2PO}9>xe9EG8u|M4+p{Cf7qcv-A8F z#Ot5uzrZ^qcz5wG4bW}u*>xw*wBpZmW|1Od20=(Fu{>@oW-OHv-pc$%W_!1m?>#Dd z5m;s-9MPX)e|*6}T03(f^PA=c3Dl|tq{0|VF!$6$IHHccJHD(v7w;PL!Ov4^X_jN96_g0*-AT^KQZrudPU}97L)pD z)i0+_Z-|#X3zIFZm~Bj{FG@&$$}Kez3gyNNOSfQG%Fp|mn+B=SD9lJY ztoUILRg^GNXRpQbCXfGer@!5>Um{1;qEWa^SE@nMHG?2-c65SDF}q8u93)GaP0`)N zDW)ABJzy;rnf;t3wtsEHQYv(vXJFy(;!0=#O zgYwJFpk}M$&vfr2;GMGSSAiwidN$r;0LQB1&Lm~;8jBeXzlmag&FWiuXMvgSKwVf# znL+pM!daj_DC=Ta5DzmN%fta4!vf$tli`K*OHp$!j&o zw932NRKh(g_8*U}_YF%^ z(8o0TU-lp1?I;nTanBeG_Eu%)Zs5Vf{D3~o8xQM8#XyS)!)W1df@tvj5YI! zLAT1cd56lBXI}SvgE0OeT;+P}(xx9?LA9fKt2mGi~N&ovUo(;Tr+|e5aE?w{(+MF(IGadGVbgtDuuzzd{>)#a65F zp8&Vqng(PWSB^9w#zuqL9-)<7%R=}u#{0_{9S+rfjO$L++axS6BLR6>!2h2No=vEH zx!?&JEHS@y1FX+ku5xNB7Cf$Qyl|+*Dt~_Aw`0!o$$Y_C_pB8p1wMnw3uj3!xabC# zLRKZz4P-^rA3DtUoT&a*T%}&;g!H$3ql!gUsgbu=j6WVN`oL`hwLc%rpRaj9MbAET zCC!iR^*S3?QPY6TD;|{QEL_xMEkD=|aEq=!& zz!jyxO=J`g2sO;<1Axan%_-&Qf^?ePwIa>9aO1|Wdg?aq? zandV0K;~vXfWUx*+US-ZK?dego?v^d_|-a$A?L-85A#7Wky*f@wOB>W=m~4C)urK^ zVf%JOe6J~URs_TBF;@I($eCQ~Rf=2|B{n4XjvPQD!;*UU6M}nPrlAR}8um~#Gyt34xGONM$egYO;3^jSbLP2X*d68< zR(gsWWp9dB-7Q+n{STNu!)l0dAO0NU{dg@`> zkLa+o>)1GT$zgBQc`i6#v<}%0cfXP|=yb?>DlThXygN8|>j9_5QD@C#^qVZ0LWh>t z2bWQ(BoWuhk~;^uWLMbf-xd3Wa~u!KpyzcgPGb3eSe=nTnc`7h8>kr3`zIn7-Y}u~u@&vX+_R^Isg% zT58@)ZDpmp2cgPfHW-NwR5G;i1Oh~Z8I&^V0n$@fP;t^vzeI;Im%qTd$|s$Jxm!j~ zMSTMJ^e)GW_+Ew$)nNwFM9z@)#4ne|3L|l8G^Sh^c5Wiz!2W$PO5aB;t*~>uVWb)e zg!L}$clkeC1>EvJ93|2KH`frx9!93elA99*w<<3DU=5rmE@P~MSFOf;W|OH3WH<0B z+YOft6fwz5@fX{(HpRcNpVysj)@x;p%;!E>Sfg>^{v(VRjVi9TH5Gn{Agdl`QsT{lOI}#e)7x&e*ldc%DI3UTuy%6&sNOfhNde zbf2~Ynmw(Hf;qWCQ(QEZtjS6JrBud50~D{4MNzyO93@+S@f|9TE12p_WdNhj_Y)2) z{zp)ZtxX_EQwHv$8u^ZB47)2AaHDcd=?;|vVE_jWTY(0$IGKFI8&=kUVI}{_EmS7t z6GPfPpijHhCk%tkn6wHtrXTee)0nhY29!vt#2lhLNHd(Ad;5t#oP(P6)#k1*R3<|_`>@jT2`YplmwCsm20j1lvT}^teJtLwlqC_K(6I0k z2luOFDaWf2H?KGd2)yObFqpnkJLTdDPbLQ5#+V6iMo18LzKLb@o2Zx>{j}UKEX2)3 zgspHDbwldTqqpucVN?_RGpo`__x)O5%>dOuR1ani7d0`0ri0kg*KC_*UHZ1Q#7_rl zqc7$=MBL}mW=9FNhY_}C)LvmK2lb9&e3moz&RIwWp~A;V*(RPdcZF4dCgr2fc%QMX zrgHjku1@ALt}*z*#Ytp>(;n904czt~?f9v<)c5fzc`W`psrUKnFY0duaB5TxBrRWN zJbsBy{O0(~b!vA63TIk~e;mXKT-+@@sTQ&D- zWchOGl7|W?;uDbhLm-e1sr#TDFn?oJU(D_u#a45XDru!MRRquiSuX7njn9$+e|`~m z|22DHILG<`+(>Kr7tL0;f3qMFF({xpdY#ccqe08Cd6N)5oON7e*kGj&HaUK)8lu0+ z2+;ijvQ)UH#F#yUw;eUfnD2n>0D79)bYLe7RExQ(1*^gkJ!?ZwhKstzZgMlL$7e15 zHI34hks%&8i!`XAN|lt_|NZ9)t%>eeeo&%cDDdu>WDeb)`dV|Rx)3vXM(B@H;05DPeooE%l+Q8HhuO=oP zI2-e0hE;4>J#ZByJA2{xfF*Qb0^W>TNa)sgC;%=Bo>A);$to!D_-E+wWO3k&-ZJ4C6#`Fr)a3~mI2^lxq*I{3nE5pVcKW%Gv}2Wma@V> zJXv}RBpWA#a&{3b>Z$3*l?m3+Qh8jvKr$;TJk_IIc-8U&Xh7vXFC}lMj(++8Q-v}K z4+-)J#x0+{r*%%gp6<8{uQizGj5T&W5&Ipp(uO_y1mxO@Wq9}Z;le*H0>BA?|Auf9 zz=+wz2f!x$zR|H$tai;AX(oDovgZd#u};x5b5J`@e?Fu?Wf6PNY5f6M$s?$;eoNQc)G5;$z%}d~de%R_ztyjzmSVFek)tDQ7tW30xf;U#dK9kWLS z4Ia2ESnQ}Ll-T&<+lTK;SoC5%KF+)hSrP^vRlCI^)<19<6l4Z6&wU)T?(@EXqAy(Z zkP-Hcx9exhrNN@-U1L?nk_{L2F8a0fVKmb?fi@!!8v2Oygd61<3S7%t5LBQ4qbwKJ zNC*zmC9DxFH3qbE6v&&KJ&<(WF5>PEtd21iLy{Ws2cv8-telD~k05{)+B2WbNZy$KB;kVCoQf;Q;-38v$%%XzZ-<{m+dNS^ zFrTaWTC_}8y9yNgyjTmzqR)ULuESgMQ7@Aa1MNQJ(YeA5;Q9 z(Okj;XLTRl=wme)09;Z3fG9_@^=1|ke(h#?u#~D(mxdgFEf;CfbeAxrb99LdiMOug z(MTr+1*r%C(7PrhV*7)Mgm9UNgQYBf`$NJsUDl7k8pdQgrOA>zA%;^zRKpE}lH=6_ z!c*Y~>RFXv^oo>$^dUc16b#n<&b_#-aR3e^tMo&`;%4A!t8tRS5#$(AhRdLkJ|z!+ z?*#t&{J+sMH$(AYx-F7mx38Ud9*6g1jG)~gXQwT8tj2c*CWZM}ykWN*GLARk zf-n+4=Z(AzILz(Bo6A&E%BJG^>8;T9eJFYPKZgHU)T|7a(UWU=nHx*EI?x#OLN*!F z1kXsTs6se|(K;3-*Fx;4n^xR(VR5UL?LhJ=Kp>eY`zJ&XcN5J`q6g+LbpYPQz}Ag| zZkCW)5l(%uR?YH~r5P9M=p`?81Bc?j9Avc_kSQaQr3 z8qMlpe$s!X=BqV7!Q`>)e9_$m8}3QlYj9>xgP-MmF_3e8Rzhu-v; z;!ss@fa8vF`Eb}0_4xm=yRzAxn=G5?_PM7%8UGH~uK&CBWO?0Z+?s4*8yCI%UY&f`%Xmr4(!Vj@GXzJpzmz7qrJ20 z6Tv+4kNQZW1ny8Jr)G(%HLh;}YFkVzUO_xnSC5L77M>Xd_DVZY;id4hYR1+Hm&_I`CICRsVpA? z#m?d(XCeleJqxx-{*KEL?p#wPXDehTcAp`9a0};%LqZq}Ju z+a%@!@PNkAO-x5=)FmZ_yn!|nlzS*Ymb zKXQQb*O(p7;ZD>(B*6qq650ZSe(5HseVxY&PHUB(SbkdU$4DV^{OhT-0^waCynz{% zR3e8bYR3w%eZgwTdCd0`QdR8t2_U23%SOWp7!GpPFE%AZKf|xb_W~0v_;FDVKA(_2 z)H#U%D__W9Ms#|pYssqXMQUz(T>nBXb3wN`QYN*9%?HW|S9g{RA25OxVUJ4h_waS-iXw$FWMdm6%MvXBYr8;4zBByeqV zkG~b$kQHGiRPZAI5u->ZqidoCMzn(T>3~%?hXK%~00L@0baxTd4x3~~yNJd$(?M)74Sf$ zE-ZTXT49@^|G<-qs3cHt1`9lSM&#X+MWr-wTIJJvi*#^zv(})}YWG3&0#L;kznrNI zx0bz#W`S0Q3)T^^@0|B8HzwvToW=VwV_g4YB}2n$%OB!T<%D!|#Q!woqG=4_ry^j; zF@Ofm%6nvh`+^WF2`~YyF7DTx&7q(9qgb;QH}q_AtG1c+euPAqs@s^AR({{5g6@OX zHLoxelEAfEcYMYGb^mTsUcVJ`G4-5v4?w1vA5F}+T#)Yxt>(dv7&s8MJgj0UpFpTo z3O3E1g49A`xxFh~1f(D^rJ>U z1s}m?59P$(jMJH6Br`QLm^ErALm18uMmx##=sbOt{|PS96wr}80MScMl4`c{i4y!3 zp+*{$`UyQwW>s$vw4GYm z6bq=B7|G&g|1$*DmB&47-;-L;=TGo2@^Ak&+}oo9 zQ+O?B^1U3Z!-kJU7A1o{nIg-S2pcK`B4m3JC;T)PNEKP6X04~FeAm1Dr~Sd=UB~;_ zYwCYb`?y;btZ}s}(KR;1&2J+ToBR*C{q&p9yJ-iR7qr{eSj>2z2lR8($`1g;-8_^X z=0Vc)2okMMo)NK%HkQB6e?(=5RyEf=j{S|61;IeSNB{s#(+jtvm0C`VqqJu3g&wGC zcU;q?j1pl{Ma?yP6yagNZWA?~0ulaB?56Pydj0WF-4rKagX1@#^t}-2@hpp z`*&(Q5F3q23JC2b5UbE!4;yKB4F!lmf*bE9em5euR&7_Tih!O;=dz=KlPa~=td67ay8)1Mf)}_ zyMf;NTtFBSSo4Mlh^C$=v|s#}@;a;WE?@z58W#HsT!1r8afRi0xi9Qo>qCmTu)^+) z*t=r=nuRoeP(})c99JICC~CNDD#$MkxMzm4cv$W-*&6<2*Zzo(lO_Hf9M%4HBVoR1WRniwf==@ zjL<%Iozf$7kAHtx;~~^qLPE@vT>D-|BVMAxeKoi zIk)sh9S~MawEAiPDGa6aW}SNV$}~3W=h6&SV6rDe%bc5NFdzfSN>;L2#ceemp^ut< z)t@Eu60&C4r(cqV)oh#+qc+IF^=-3{f#l?AYl_nGFdoI?pJRpxdMjpqOpaCUnSzVY z>oDsG)ph%H0W87}x%hqY;;f4yFdk7~H`4OcM1M>9iZt`}=_mR$IJ-%5nNI;pdUDxE zqnR3{d6VG~wk~b4mWb$3;*vLh zAubjbPXYf$&v!h z|Cz68XNqO>*OG_D;<9W!ulG)H*^9N9irN-!g#1*0n~_W|8rbLCJ|%TW)b4P5+wg6j zC#hJQu;9_Z3D?ZvXe{^{8LI}A&42`%*S}=AfpPQA0O1)6-X+;*O*M)w0MmZkBjg`8 zlkdEB-1bZQ$7m~)WZl4XtN4N*CwWVy)oENcI25adfNy|LR&N4HMFhL+B#x0lhVNpfKo`Mq4Ewu6c7^l&gheRa>7 zpMcJgA*W##d3em?^5UoaKW1C?*C8|xEpAh&5(#RQP3M=#xLac_)utm(X?8j(T1EVZ zk77=60&0YYSm6OABoj{dd^SygkQnA7lzpH0mit(P?^ch~axKY79-4Nd&v?6cecf;K zl3!P{!kYd`f96XZS2M@q3u~Q@X;jF(Ge#G>Z4g$G9C$}UFUl*ur znlz92yPbABfdr3i!73(dR^c_U^+OPToN*;kf(tR4yE99jUk~Z_a?eF< zh$6JqK4PTDwE{uZdAb|!1NS^3dq-$>h@@u<_#@3t@=8KI!STSeC@CKDs4OlzA#v8= ztMvcmESqqYMO&qxM8Ghr?@s~MQ`dZfw-3*%D}rAc?^}3wtmgHxrmBbl`-=u*h6 zm=*3Oys_1IE=Bk}!+-*DOFoUdYc-5ddJ$4@4ed?d!o346g)R4T2E(Uge4kl4_-uQE zGO;SKGKO>=71jx?4fbJPULDWqiKN#cVV9C4O%<#z))*@-4_y6-yic;U%3-3BOXCgl z@;SP5Z59L;TRBhMFDg^5Xr?z{k-hg%?wa1C5WTuFTZl@pFZmm4rZ%@r92GIwYA`j^ z?7)iK>rHhUWz8d;l=FSj#jUG&0|@y=?zUvbvsh{J)`0qOx78TM;LQUZyT^^XagAuy zKG4#$SZLv+Nurm=!!;H z#%CAZZ`yRO#|6aL0@91gC$Gc6@Q1C0jJ(Gmvk&nuG6HaqmCAq5J`aVoCzqAldzb{= z$50qK)+u8Rp^`Fsa)whF7lUQiPSPq(;_qt^0X;+3q}DXLBT6?gsQy zRUg=CH9q66hN&y08y^?r2kgv)j_G%XewA@#q-uj9^)Z-`{Lho9nw(|9+B{KP_r9_+ zMr28!g+4uO|JsP|`F1~*l-kFsPn4Yc5UrHjZy3`8sp^fyIE-IP8a7;uzm^Wh*#k}6 z<&&(n^Q%!RsCN6$S6XX_SBHV9;akvwLENx-SF+zq+9N)mg>&nb!hXT1~?xTc#{W*}N>u2~Ou<)Itohz#}`6kzj<(e(nZevL7F z5%Uk89t#(C{{8vKSdsaM@)mtu(=KPN5qJLEz4;$``ux8L-3c=-b47a7hyb=;)(uxC zM9@@;H4q)fT4nkHtA43icjvN(WxkAOHQS+e`s>jU!JWZ@WY(iDlF2x8He|(626l`k z$>TlPkrA75W0C7Tg!ae}k3R0I<)ZE7z1FfXh>LLv4P8TCj6FNcOO!zr!lepWeNqdf zrH1o0N_%IKy(L1ENKC?XZn6ou16^n3;SkPwVzV>NAZ z0>*5$pcQSwY4gjRW}^{FUyPWR?TcipGC~iL+Es&K^3qnTVU(#tL3+xYP!n|sY@9IU zySCyb?M8HqdumA6xwx|a)_-IjeeVu9@3sCRzGSGVb^aMh=0ooRI--!{-QY?gX1Gfj8y>#BJ(8xkCy1>h2H~mdK8VqFzzKLWv0|>`DWS7 z|FOU4{7_L-iQPOutEkN?Z6i!q*p@!RUrGS^qHWcefO12^zGS$lZT_nSJF`ES|0X2} zde-FSGDSGl6m6^7GAn%X9PLl_!CJrxH_qC3g%wM)h>i9ziQ1U|bp4bmQ+yk7V1M-d zBkvV%Vvih|`Z<@S5jv#)Y!K1yHu{u>Q_@3#G8V5BSvP~xDw(@>gCbg-zF<-Mi9={EnYTmG(7D@1~U)LoAv+N<(Q}9^n{uVDC zDFfIif)Z*VX>pa~+-dRC;Nn)vJ_e{d>{nA49y&!o!BM1g?C>+K_z5nldOI|V(aei% z<~S~tK3jO+_~J`t~4OpKVwiH zcgEW22K~xNeWVGo-$T%9ExiE7)ok)o2Aj>fs>Q~bu(E{3IJO~D*hws~l9N5>dU7-y z@54PvPmp63y}3 zd7+ge?ZxbyT`U>di;N-B#X%of8 zaT0s4{KPyd@f{M8a6O$yi~kSvW9B6J-f8pj&il-RbP-2nJw9L_HftWT)AJzqIXw@k z;ZhG%Yycql)MEj-&V}G*pNR{4!w03lg$ITKnYzdXphpe>^zTVZ0~)Zt#jC(tkh&c4 zkx+oW?x$1-7%toNPp9p9AgjA6rcSZ~(@;oFK^r-0U+Rqg==DYdqJjFM|73=xABu3r zBjQXVsBvo0Dc#VJT*(t?2{FE>AY$X-tdS$VP{4R7HE##>h7QR6#)IqO)O?fPr{>uK zx}Gopg|4R!b&qTuT>g^M=6aV(yH~s6bh zrr%z_5_tI>-0u?&h9W!A}NwqW}Me zE+M|zTAC}mTh$V^-%eYK2ozycuYU-0niIyElEkXx4OfSK{JWHE)IAHDzVJMw6AD~b zgQ1=?jjL?$bAy@>+$@3{0bcB9QjHKM(&pINf|3L?i^^$P*3>tNSkF-qE_zBUJGMCq zPTwy5)bR5cUdMerXS_dL_)@78KA7E;Jz##aP{ANDqCZ)*N$i8`t4a+h2W!DVhCXqedXu0nrD%}Pa&{}mJSe-=I7-KVtIoMl~F znsMt?BFKMNuWV>`cgWtZ9-rGYEv?@f*x!;wHnHRXc7IJjPYWS`m&-R0#Jw|hk(f3D z$iM2*VGMNNP5T^;+8+shbvGrFxFO$KJN|-*eRuL0vuCf#!zoC_cCz@1+3{|Z`12?htH&tI$3ril#%FheZKpI6=6`#<1LC&|YSQvcr0`ln_@F*o(HoY%=4P5; zz&i_D3SToV^wl&+5#lA-^Tck>DMw*WWn%^FLBGtS1_sw_7Jm&+XuJoH4(7g zOa}@(tIz1q!0FU+1JPI1eY{LO1Fhs@*F@xbnnO`DO^)j#m9F z>w8b?x9;fRS=QXGh#`MYJ%C%}D3Z8a$fAu@{L9Tlj5wqXJ&mra&Fv_fWsQ+?{gzH% z#}r`Ba?1xief8|-7m$b@@LFzll0eo3gb8n4Z7{;ZJ$gW*iGwVABa8%K~D#N_S>l-rIBD{Ufx;cY$t~kcO3+rNFZQ66LK2fx3erwS|JOnI2)Cm7W#pvy#4)#7( zi&Z^+-=Mx19kk7R%^U7Io6RXHTGfz2x1-KI8OZ#jPGhZpyaFNHeDwCWNYx;n!_yx* zjO)HzilR*cQ&bfRUjKDI4>E~b-Oy58fcPYx(h_DnOx&w`J$1(dR(v9=5SMSL&=Z zQ|BQU_m>ln!5ZjZ<>D;fg!>8qGoeJI;1af9W{abIb1%L-H`?)l+m?o=7VtaF-%5E% z9+Pq5ALdK4IVR)02YFx}e%cIc*zdgL%wH*)t~Uts1Y^JX1Ct@sHW}QGOK5d-L#LMk zn-Io*llwiXfw2WlV;cjzKZ+&H9uZ48-E=x)KUq%a_;3(1#9Nu(st#fX?7l~MSJaWJ zgU(bqmqsiF^Q>f7;dvxG%l35sy8(FOd~m~`XPk<(KTvK-ZiX89aBYf9~Ay* zz;_g4?o6JN(R^$WOQGvn=%z+-RhQL2eiqFI{bXeVr(L znnN~=bFFZ(@Pm;3LP;UP*4K)VmDs;tt7XlstA9wo~8`FGuzAy8f_EPht~!k}oIOaBl9LWqp_bC$Zw3+j+K|xUh+HRP7qA z+Cey6N<2A+r_!qL954=}7|wME!1~V*fttSdkD#+GmFITgy=RQfzi!6t>t^j`I|o71 zK2$0;R<~?txF`8Mcl+6q=92(JFAH13&YUl5Y&SRY=aydc*b%LIs+;u%Dufdch*k+| zEZmzmP&Lf%Q@geLs54swr}l*{lwR1NLLTI9ChJaTh6|#1#g>rYRNva35wq6)=u__C zPhc`C;8P3G*-Vd*=phZB4#3ml^%v9jxg7$L8fRS!J?{%=Y-)JqFcSYh`>00cq%FIQ;bE1t6}@1UX%pvx4cfdT32yr} zx=#^3W|_oDfX9IQn8#zD`-p8@}hv_8P4}D}FW^V~IxupRiSEHmp#>(J1guCQgY%=G}r(Ny1S?DEsA$O?l1Gz*IUSmLcyk;(VWB5-0i$%4W95qFx{%fJ(TGr1@+9QHPI=zIomMJ6ckrw4re^8 z%L)Hu?vX4t`=Czjf8q?bXv?vpPEOm40-JmsAzrIifs>Vc_;M*`8=kbgJ;}E zGxABE{OXfM_~p7;>K5_k_)A^0itdOv5Bp@$k7a-M5|>Z@ulUQZnpA2Or5T2Rmbgbi zq7oOwo^;3H0unAqRVS7UaMs#e&%5T@GMC@qF`nMzYVQ&J zA)lr$G_~xyKC=U1C!KH)+a5pV9;%YZpFPR4Z=Kr@z-c4p27b{OAU{h#}2DE;ecetfZ!`X(uxI)r@g zRfWFp2)yxhSewN#&HQYf%Mbn*R!Opu7SR&P>PP|9NNc3CK_&G7Kd7X-%#SzIB(9t2 zXPf9GXPJuD(Z0&zpto+4|HyIFbrbzZX`-YuB7-zh(&~I%6IFA!4#G33E%*rVgSe}+ zA{P`&YvDzTb7QR-X`JMERU?Cm!!beQ`jzhZ68A^HAPAa4=)sKAT6O&y8hz4?)iqB33Yt4WgF8>hwc#9UXpCzISn za;1A^ex>`}!bIx~w{N#R_rw;!c{tO$)l>PaQrkox(|#&5x6!!hYM9Q(PCu2I+qjv>>4#uUPXganbE^IxgarMIIQ8{B zI-6Ti`>}h)59C%lcz0FjJ533FXlmqdEU!s_-8F(wrSm{N7+dK))M$P-G?|~xYx#*e zOmh;jWh{*${---r@cy2H9;ho3W832wcK0phOHLO}IMz#r<) zslWYL3v&Qq|o2Mehb0@TMBYt@HbP;3;A0hCk8Uec-6C>~SEg=E&7lUzo+ z(LJV;-9uTNB$0*&oep2Qn{tv<$d9@Q8p0<%uSbgg%@>X741M$OM*fYHeIV2XEZ|fGBQtQ-p=6xnV z4xSz_NcE|18`US8SeuX2l*dU|lq)YM{Eaa>*{vG?^ODz8d%H5h%+Fzl_;gt_(7$l<<_ctG>m ziie1^dwN^RZY%NIQ`u~r_r?#N;axoF-8Nxgw_%A;+&I0heP=jr(+`%kNmm+V$?8f= zo|3B6Il>LBcIz?Jq{k3uIxA{gVV2vZ)FQx4MNJFx5I3~-O>FJXwM&Q-JoFh~SEDSg zp|AV;)J>L^QI>WqvbGPwEW;h>FDq*>V|c<9DNFS`tSl{IPGB+~FyLP!{Fbt`Ue*5p z*OxYLHq~y_bh$Tc zK}2n2<+9S<=tFsz{#5Jp6C7R&;1qG2jA}+F+jfHsws#?;YL>ftMa>6dbt=8PwS7Vw zV0XGXO?c0kLL6_6{D)l8q>Zw|+bpva?X?TF(Ev#g9`L)_RHJv@FTLwrFfT%tzP@$D z_e#7*`Ci|mae14|=!MbCqQ}R*(OUnkmbAkm-v{RSxz98|SvN)1Bl5m14%-H3nC_Fh^D}Fv+o^bCUin z%C9>KK6B=oWrgM^Ha_00E`b2A!yuyh(Xh;UgzHfRBylb7bJuMq&H6?14ccHPVMVp4 z#MXk%AC=N}+O)0tA?1V8RI-vsIM^HvZP)N9dV+#_Sy$DtrBmc|oa z$rWDYLgEu7bMyf!TF74IBp=|-O=?E4ZgXCR{{<}4BL76Tvt}({ym=q(d6Q!xKON=G zV@B2qPh}DF3VtG7HAsrNh@1x0ULv;$T&41Sl2GHO&`fD->tGnXvehS>l-b(O!K7p( zkKkJXCM<{4t^u(vU}$sKX}(fPu~$k>zOZ}_T__{b^_0~u@5{|KPW5X+PSb`~11ErD zHRXNC6w0bE0;0ZzIuQ~|S{=i&Mcj27yN+h8T2FH*Nd((qF`5`*o*)cDFH*X5l+mJK zNOtp9;c&UUVMKz&v?*#B0tP1tbowbd`tegb{FFj|+;Ah(6AxOqOXFgTrE|`cra9i+ z!iPe~q)In`)d$S|3#aKZif8N%=$@9f813XUXrcBB+io~O+CHPR!kzU74u(q+x~zqi zoAwz67C{+qKrLk5z{AW*?WD^zXS7>Je@a-50j|3(!zWP&gYP{pY-+^b$r$B+mCzNW^WG>sKuSR7WC{pz%gP;^^>KtXMTiR18 zB8N4SEx87hV>NCW;9(`ZKZ)?*n3c%F*F40WC)v@Tk{0rU+=7W(zK+R`IwNZY?Uf^q zwceLr(A4G{5i8!Tl{d;-wHnldZ4zeVh2T7UvA6YeG1?(bOR>_kN69rO0z%$Gl)09$ zYdII;_LR!Eo!xc`er)V-Rp?B$BO(xe5fQ- z`rJp2)YdAKgwtH8h1c9mc`MfXCmBCx`xX#huzk$-4Ir&fYsnGk$<~1r;{#ZZZ-m~p zzJ6lFT_gV6t37Xnw=z!I@m3+Ay4ZZMb z_{-r?ukHMx$Vu6bogXQA2{!=S`C)-w(n-O>T%Wd>yqqjEQfk8v{cx(n{KQ+Qg*vGJ zn1iRZ-5V)+k;`SBAABGa(GUA7&wX&Mpp!g{9ojWC0#Z{=l233Tw()N6m_!&^NFtN8 zh#x!t${E~J=PnCdi6)sl<1I5_ZE-M*Ijviyc(a}71HQv8jS%i(Dwa8MoYJ#z;8dZd!7iO$6=nRd5 z=R^AP(x0kG?brrU;xP?n54`pkeBiF@k=fUuDb?Ul^SST ztDfUvLVdG#PMobD=Y^){3eJt<2Yrq-;(E&rl-KDCod&ICR`tc!xOg#ZRX^w%bi1-< zjb?>n+08(uy;uR?4T+$Ns+v{;P&LIoqs~~;{PBmxh3%A$gZUM!Sr$ zz%T$acE@VGNvfZv6ce?2d6dsTLM^gtn}3Qqo7KmddmAj$X45nGHum1l;!jCMp|n}b z93Cg~*yKN=Q1X>J?rkWPHb3B}qEOoGYjtib<8gzZ8spK|=iD}z#}+@ennz!gbK4>w zJN?vac=UBRw=Ltb+oXQuRy0CJdxNBzJkNl}GZW#i^Q9vr+H(-X?AsG#uHjj6h6t<* zUE&+O32|5nUyfVXXHvrDtg>D`I!UDndOL(!r44>4RrAqW{Sh9)%*J@KxHFO>V!WvX zK3g0g3|Xt59bShzHQY3T^aBpkZ`U-CTz^zXK-k=G6dTg{;9o9_A1+L zDnsYo+JAy?WN$1wx1y%0MQUhk{XWSUt^H%nr-pvzUojR#I;{{rF=|zQuq5itxGmyt zG+mR$+Wi+T@JPua!i2dSw6EEv19ZrC9{v|2>#e@dOt!DkHbl{Mj#1ZZTq21z#&ZNf zHu*|r9PM2&8MA+kpE)>Y#K7h`h5UlbbH?)v9?tl=(1aZn?Oqvh+BRu0?8-Mp6{+}Qdj@? zeR9jxANp24(@lKRuno@9z?U%a(_!$wy02NZ2kVv_x%(Iviom*s@1JkOnsH%z+Gns` z`R_p;fxYWE3)hLtb-ab^e9`0MEnHdqYj)TE!Faaq3Bk7Q^g2)4&I#1={1@L#I z@`{?O?uweazrfSBorDN*1^n(nC#Lq!fU&jK?^g23ECK{=?C30n(C$!Y<^&8>6*cd> zM*f)W8NA001oYLiWJl+U<%hp2TJPSag@ql=-$3^CHHN`pLzIxwI6He+u*%xaLKMrG z)nWNY$Hfy4$Q)-9Kn?xj!z`Uw_N&DCvu>bsmmuow;WJq);c_ za@tE+gNK}=KW6UMv^76OA`lmxf%t&iETt(do+R;J5;LcAj%AKd$+TewlGhxspap-_ zR{YXBSe|jl;j&_pyt+6r3YUU~FP!ulkG}kyDjy14$#nt(x~e>D)96OQNh}rIP#M)% znDs41fH(h?@v#sJ`4eLf>-%EXIcwehMq$jETbOx(35>ZX#XL5&_#1sO4#>Hcqxr2I z)fX%2=ghlK0k@`eVaVQ(J=k+U%``G1z`d3qq@Cnkeo->b`5;!qwQbh+G8_OTGx_3= zBq6ztFx|*GGbedvrkL@e2_zrQk1qx-Z}TFfMul3?3X7C!he0Fb>mo7-dbKQkKE?1t zu!)uK8qr_4tAEU3`aD_Y_rRSJWX=4FN7u-`S;hw?U1psDg#n^_`-F^5CPu01VJO{u z8^sP*IBl7&;OX{RY#YAS`m#4iKx5{aIT#QH5n#|#%Cm->Ii$l>KARSCACgL2K`fFl z>TFLo*=Wcj&VIBplZ|p69-Ygw#q>W$K5d0;KA2UgP|-qV3mk)434u!)LMjIut$52)%bj;THN{k87;6x3mo-bf>-VKxSUXbfuTdnc)rmB#lAA zoe+17Mxu6+uWLt{KSIZzxi3951fKy7RDBs8cXCg1P6V5dflS9T1lJka6K>3<8&0R} zxQ}I4tND1dnn!Uopgq~>@FU)$kh6o`Vj8H8$=_@mzJ65}Tww_wgvMC!{#5*n?6=}3 zi51KyJK5NRqV7s*;-c;<*|Z}i;L4~_8!om;m^zDf5dkH*p}<`u`jxJosybJyPK06g z$WA3SWlTR-z6ZNWF@{ysI65CbF^MffvT5B|DM%C?u}U;%mc604Ne1jpXjNM#k3NEl zGa2`=X(zK2oJ+qlPTPv%UZ_I&=l;>?6E};OQkcRiF|Sb^laVNtKfbFSsk@<~*vnxv0*RZVGI?dXOODdIqe^QQxuZKIZ%mX{%_mAT19 zj3o4;v_{(*hO}TTJ<;XL+%<*z@p&cqM)bF@jKZTQAZ$cudL7oNT_gxs758qD?#i0~ z5QWZ?Z@V!J*)fKhSWTIb_%VB{arrTndn~x0b@#Ch<@VXJh*i}cFi1|Pd!L9lOq0&i zw{p_G*UoJa!(^8}8Cz>R_Zr_`YqgZN_Eyd1^cOO}qUSU$sv4O{ zdjfH^AB7UV=zi9_{Uf{dNW{AIDJ{54!V&Z!iYQO!50sp~D>L7CTKKgZ>pD#s#P!x1 zQ@XL7L)Dtpx?`BLOz#1(YUnhQ^kXCa7l^yg6%vODL3j+-!$z4mFWdq9zN0iV=*v|2J z50@*<(2_mjQZFiOJ8g zA5~(!FW0)H!*(O*5tCuBy{`|dj}B#&?SyAx3yU#s+bip1Ps4)*U%j2k!Gz~~EtgYS zW4LdFw^+^m*&8?&$yJEqlexU<)cnd2D+dY4E1DPZJF=^=Jr#0_P)?t@ORNvk5Nb=i zp`-2q-oQ(&@9&C~;zBuaoXcVBo#(ip?T&<=%=+zU=~|D3%a@>sk|HS7 z3JFhhJ#47<%XV(Ttj)~e3MIy#U9OrZs)UxL;?#tVz z{I*kh-poCC28U-^F*G;fSt#+s@$c7%tYkAti_{~`P@FdJss{*8h3j&9ZubE8@Ji=< zjWOq{dfWK`Hn*|doqyiK3*7KbXGh6CQGyRyMgIv+L+f*Z$JXwA@8Zz?hmSypn3xNk zSu@jPCJhdrlf$gQ7j$Y&cIdGN#8eCYLy9snFRz#=Ykb{%aZPw8OakNs6ISg9sbf2ZEXEe`&l{C~Tvk8vAv896@>q*DYH=e3b zPXekD=Ur^m>C<`i5*jT_eEJ~}%UQXWg=o9s0()}gq=llR1OjU93sY&RJ>DO#dqwuH z#~CL3NuNlOyG?7?E2OuY8T=3L;;`U*iXfZ5J)iH^fi3;U^snAj75pd65Xl5wo|uN5drGtte1@jpx6{26J=Wa^E00|IK%X&!ZWoc zX6BJ#H6Jx|Kt#Lv;WJ8()Lr284S^pm-^)Jyog+gt&{46pHJAZ&f+f^Jd`y4(-z?0$ z24%GO?Mm+Y;UkBi+qZ*idw!1z=XJ}pf)T!SzZGqdaCFG#a8abBbsr|_Rt5EM8EW>( z$SIc{J>I=SI`O3~LA%C?=y4DlqyWZG!488@eNSP>ceIJqi+1O5=0Wu< zn9Dsp4NqrgCi&BoPL%H%Si-;TS;x!gDb7JGHCn4tkt5TJ@zSlEF?uNsU z?&AD=wf3LqfU0iN;T`#!+l8%1rdQO=jln&iX^*3WGBtdz zB4n+>b))GQt-tY;Sm7QJTikj-mCDzWC(NPDt^PPP#B)-;Z38Ge#2vxC#SYl5ubya!-m0j%W@aRJ zad8J((~;0CvDS~67bVZ2)*eMf5TWp<6w&fDGMU3_92wB|mG$M`$G3^t?Vsm&0;&D{ z7VF>>&zRl^Av8xTYG#UKMm1egQ#PIt1JoaU{D=)wA30`TO*QY}qbv%=%yd_%KlC6H z+7}7+oIC!`lb!MUkd8D?(=W$9XL4#GPl0J7TvAtUtv(wR84*}x(kt>#SL|xy zA587AR^G_I=wHvO%}N)R)qa-Tx{mfH3f%lWv0n9ov%F=93~hA>VDJ@H=Jd)J!QsP1 zeBma(nm=Ycu-()>&+h1Yqn(Wep zcV3HdWKHVPVY3>Jf)|E=M0}ZB=37&{Z@Dzoh4920_QH4d5MV&Kp+nFY&_v)ic@j zi*D%pPaw+e0^J1vJ#gb`*8FyxP=Ys)=40A!XHxsCf0L zWo_#hJGuEzfpob}{B353Di`YIYW=zLRp`tlUGYE|T`qFy#$t8lt2c+E))g<~i}Mu@ zlmnm^PHfVX z%J}_h7(7a^mQQ5o>^Rm)#GaOtlx|SXfr~F|Tpr>QoO<4J${NoznsWbE*%3r!la<(Y z>r$s9-o0qnqS{FrgRhao1!$b@AaXNV}h#7a;l(MiQB>utKQc1 z83{bwzt0QQE%9AwlGz>6y%KO?Tm7RsIhS+&B+A$)DlmxQ^&Ed|JmF>14{;TB)Y?=~ zT;*}ATGabC+}JKNs*si7R=XVQE^X%ZM@C@^2$BJyBzt_ba&K3LL@GKO#|5(DV0ZGdhi*YY;|C|%}8QgT<+bS`lsmlFb& zs|GL&Dg+I8x^-5TbUVn{OPXTI7ix)0S+s-gbAD9RHbnKrlUnhb%2b;&Z1Ghk2O^>U z&de%-qLB%XHl76Eg6sSEk()ykVE~YGf^PYDMM!CsxCWG=GYl0vfARow+NrpX=t>R- zeR6&OQEO$XUJx6s#C3l1jUlh-58H%HOPq0b3HZ1D&1h-Q9SbXK2C72+5rQb?6Ccb< zJVJgHylH(rAK`*3K0$jn=EN9=7O%E$R1ZO!4IO`E+!9AFQv?j^t$Q!?3V1KMRZ9<`zu@uX4m7ixZ?h@L+xd@cj3@~uYhWjDP@D9F0C31_+aIRiak3f318GNBbRPy78KF2fc<&YuiQPn7a>>)GsOpX9CB-7KMRT=Ua)TE2*X)YcA$gumhg(a<_REE37hUh_RfVLWr z=r6uHl;mh9GhNd#g3r@#9U#7DOzJiIibBY0U$$M~@v~ka$X*_hWvZkE_ zileH~&~;XozEoS5+*NyKfZ8|jjvootp32(@jHaHRN0&7Du(zFDANX-9Gf6v=D9Gpp zk+4W&$}$`2D!)!g=D&H$_D7eZU7KTHR^_x-I2|!(&-A_NnX;&Y!O+T_%QuToL8kWJ zf0&zw6uxZ*o-9#sE{QrBTnEIT0`7(|98s9y!d(%9C_X8DlZ1D}vy^^V_q%UhHDZ28>Wfeo z9p%W2jNTkuK?WamFD>AlNjQjjB3+TI8?=pMq4TV>W+r(IIY*b3&vPodn7DWu^od{>qof?SFvXxTDlWIL1k>7z+Y?iVq!qF_UD%Dj(El2 zh!V=py0jY|rnTx0JR78YBNs*tD{-?t9d4iLny#R>inzCzInA^5*=t^=AE&vRpY$J7 zglR9I1^iEIFyG%4kDGX(MLOGm?4qh@=^OH}r+~o%YxVOo&DEGe0MOx*sK%tpwG#6c z=)p^>sZ_ELeAik}CBwW64&+nwR3Ug!MYQyA)T%m6`dkuVeQwGp=03Qd164FJMjCFP zr4Ch~z#z;BHClfsI>lj#EC-O8hg~{4Oe|TRzPx zFR~I*#+53cP=B7(FA@SKK_!4;=DQmSGPU z$(B)rzS-`j`NXBM(M6TM506^q6<1oTv_ft7qABQqHD*locp|F`ccTU$W$U`PwTk

AnTTjg{x}grx6>Ie!6!Tq#iJ%{G&FE}JOWnanmHf75Gk}cIojl+5!*UZ zAniS);r5vsVCO{&-`j%PKgWvhcbjKYDaxLrk4VVT2}p~QKA@G^O7s}V1cPXXIHfOd zS7Z!zNb2CYR5TN{6L%8Qe@ba;eIp!s) z1?ZON6Rd}S!D5JUOR8){;-^Q3!-y$ur~wkMWyQu5m@8mCw*h zx_=8z7z))esAX&=>X|S+W5~&M%P7tvV}d%QY+Pxoc5K9*#{}-R5^=DyzF8p2*`~o_ zh?+#9m=!eyJD`zlSV6nj5>L?+;Yzpv=A*&-W&=il)!Wtfg4(D%C!c9YowfX*C?e=W zdR3(#u)O+7dbfSX6%xgezfc?L;)UvP6LJ%-B5d-ddvtH98Dz{`bB#*2Y&%1vEMk;Y zrlk7j9RAYVvKVtHf?*{)fouRRz|2@8prkg>OEDm+2Ng9^(CeB7pO4Yq>u9hNwe+%p@G1rU8)2Z4UBBjB;wTW3(S0QmyjT-n?$qfMXMAVg+Ce?9Z;%+LT-Pb|9g}wb1t(E@t7^T zVI@2uKl>6rCV$BXcGvEyD7Dx5nX<&iT3K&kVH|1=*%_iOhtsD#VrUDVM25JC!8?>5 z*z^$u>|;beAbkPR8>VmVhNTF#8zKnB)a;`87s1uQ0+RGGitQsUI6FO9@3oVB*ktMb z%S;J`oJ%sHG|W^=)0BP&KUstEdp116j|lMhzZ~I-|8RsGsLUru zeKaH*6Ddg#(-sC}cJx_9jZB*t0+A@PK>}*ygp1Q<1WXWwZURDV1?|z6!S-k?qNv#t zii0}k5-Zg)3T4LsvGoTp>vKqB+4=qH)%wi*C!uFk<@3$+H^eeHZ!Di2Eqy)e9KPes zi0f0+U$nuFTR&?_wAB_2v$b`(WadQAG{$4f#|SRW3M@N=dQSsSVU&ni?sG=grj25d ztTl#1ayDvdl{K2v+nKjDEd{!4BEhl{~ED_hU`x|%SL&?54#0dam_R@3soK2ABj}0OHMS@Sl#XE*u z6^}f`6K6gIfay=YdklJ#6`>eFW-s$<_L0ly5p@$i-w3f3?acHRwCLy%Zl0)Xi}Kma z3XII^bk)uFbxB#hB~lI-;f2$`zEFZkT_-Yrn5#)!#>Bh(P&$NhWdVTmi^JZ+!s?#? zN#FC%vB4!x!~2U=kLVb=?#=l~7Vf{(m4*R{{Iy?d7-+eQ-!Jlx=w+>GYZ%ZjVXYBD zk82nZ!fpmmusiKQ%H|>`^UC##*4+=20&kMOgZ9}bu|4y01}}d1UyG{yR`Pdb(-2b8 zaJ4D%eOQn0Pm4I;E8zcl@76KA7UH6Z3M?E?RXcaGJy6HO+3fIlR;Pbw>Zw}_zaoP< zyRi$N0+=hHNfTkzlynWYOg2&@=yP5eb#5vuPc|g z_o-n`p09Z}8wPQ7XS{uk2`$TM7&O3|)G%m(HIa7%tk#CXEU;Q@Piz!^ zf1Z+_l9pxtN=^oxdjUXoCdPf4ElX*@!VqYdx; zCp4ZWt7W9by|}V?rY`g=(*?FM_l9t+=KSLjcszh3M#r*L*xb@0!!DumBgGSAp_k$V z#dBIe~)OvP?iQ?vmu%fW6pTpaKFl67~2Z%$h*cYZN9%&UkuR7z8RihL#aLd;BG)wjG)_1k3Z-(mY`2*)Ug7*Jm{;4Ma ze3SpKB~6AZ#!}_egg^Yw41UXk-_UDH$s3y7qD-EOBuNl{Jr!qm>PiB$MT=_ zzse~@3A;lI}|-jaU$wpO1T3ghq$Fs>rMA%dBCJf%;{_*7yTKAC?*lRSbRTbsrt zT5kQc(-uFlsJ?$u?U!28I5xNBiBAWkb9miiWc}{kJTdG(*B)u(8%Tis)Ll3WZ=bx& zg8bAM?+z=84QdDW<16fM`tiLZ9Aj;G>mkaFSh@*w&C+xnN{(=2*L$&v0`$ zzQH4VMLr)UV1Ou|j4FrCoNqy94>{#CXwkVHy89B&gLAyf2U+1|h%?}m26XF*&UM(O0=(R6rVx@i%diZD zn$g5HJf@i*VOq;;O8YuQ z%y!aZ*h;zsAsBA$G4bA&$(;1kv^x32Co+pzB<`$Y-VJ?JeTGyM}uNX)dMhdv3=!31EKDc~0YEauIrj5q_8FhXB={TLic zU*eHE_Fj9)sV(`dX<=mbJd37XNyF8W|v8o@u{8#u+<^eJO2 zCm2)hiS_-t#UExVuRz%Ud! zRv=h0PuGSdJ0AgB18kE1^227cyoN#-<^#~%roYfL*@y4@)>V01i$mQ1djOE*C|aym zIN>LRBmd6QE+P@s=mLej4+s>4{%e6QH^}=s8{#df3k&nk;i+f4nF#FRZk1F~KKour z)RW`l{w=}2o$h&od2lcR%l$aIHNA_L=~Pj~jcz5*{$`Bl=%-pTV_7~1!ae_$-bo%G zAEvi749F*D1uK*F5jtd}hVzq_AM`b@wP!aNC3NitcyR6Pr5Z(@-M#39wm2>W_qN#B zvARb^PJr)hy1<)Zazwlf{%E&$=h-Lp`k8_p4R31K*$nh^tco^rjAxVM8>E)nN)b=$Wz+U7ox0@V7wHUYeU!~NzX_Ge@MB#5D` zpHRIv?BAG(`)yPqV#zJac)LD;nl^l6xgqRv!BRyfAFzXU;{!f{@!m&R_zX}BpwLnI2r@DJdlloy4QdJ>M zBnu9mR0SS;uY+Z`{=i!Q1h63Nk*Nnh0KkNH;f=pK*te(^e=~~ts(qumUKwbvUx|M- z!2RE}``t}q+6716q~10SaZJ=#aleUlL32OsgP)2Y8L0gf1yM88a}|F3^C85o72A8B zi+>ba{wiJa_jG-06-v~!R(kXA4tp0ENdS#J$0}Cp$USgI8GJT_t#pXVp?3=5P>uFC zbR_6=nXZ^Fq@zsQSQqThCtw>oi@etl4Rs6G2sAjUc`7qEQTtTjMk^!S|e)^IoO%k`LdYpYmBB z?yD^j+kkji-AnSDlP5-`^qD$t2P+(VA|38=v+J3Ip=NJ&_7F6U?Tk=55z*_)HnWpG zz!U(77eJ;-JFH26#*|cDaJRr=a0$}B!rZ*gLKZn}3E+G+)NA3`F0hbEA6v#^w5C3H z%emwr_m!E0)@4M0nF>{z)OH*G%Yg_vi|0x-$y=K%%Aj|8qnzz&A z#J0^BmzrT#BE`itzKiQ>f2%g^_|DM21E?z|+VPLH?Qp9Yn7=z99g*M8t^2iCK8QOS zV~bd;)BsOYVzBmA-YsP@mS_w=w=y+sdd1g#*xzE~7GIc!XQlW3vf#j5mOe!C!nQMi zbUwHzM4;j>x-v^xNg=;-a_UWmsLj0(l_er7*{tuiFI|f7R9XjvE1OkcwR5c z*U{xH9X!(VI)Pa36Yht3S@z%sX6q8>^l1oFC8j$fB!Pt3g=liF>bJ)#}x(I3O6syH7Fsw} z9@Y>d&P|IW&L2C!uE+n@FuZHV#9!-U`Gp&HDu**!^yG74LOpwu10OYsaY^V7M@0Xc z-ZaZshig%~aaG~E`WkV#VB;o~BsZZBeqRX(wZ{HgNd zhrXkqNxbkg1-~19jIuISKEqF(>Hoy^lfHhL)a6z(Ld!!c^LNwV!)wr;H)Y#@Ne}G2 zi@9;0Qe1V7p7^SCYyBZ}B0LpuBw2JK6~AZbX)RCVK`^HS*?Uo{e3@PjzuC~Pt5BT| z=a2W2!Fe)OUaJpyS*OZxl@=>ie!WTP&r6lxp{G>5o}8lIB?nXSpQ&2@r{YcgZ6w;F z^OFa7GTz#$_+OX>TrbW){O0DIGCBUnpC$$W?vjJfylc|m#|Z@Z|CT%)+)Kst0fsv6 z#Jk9riudwY2ESB1hcD_*`r2Qc9p!ktz!_kDVRk7F$(*fu_>Nm@;H2uoEq{g@L7Di2eumg7KV$sr^ApN0(7E4mFHD;jSzi=Qs2Vi|d~8 zEe1~zP=zIwo=it%GuWYD-)3;Gzs>n(gWI3}8?!;}FC_0D+;?p7Thm(*>=m^>yS`;V z$fUCNgUpTeN8H8`{ct+%KgsJJ8Ph(T;dmMvZn;g4Dd{NXw15Y!8wNCMRze3AG%>py z27XLJ?OEQcTXf|ANZu_=%e@(8`?__04aA@#Gl6)^Ub3gO-$>dku3oyE>*jN4rnIB> zyrp|Ps13QM_AA$QF4phl>pH)z-!r`ePWU>?HNM;{C@bB)ML@KoQlXal`V&OH?0)O? z_x#4l0ZNMCp&uK*zt3FWN1L4U9Pe!0s!hRZ?&JqoQm>0&yhx?Q!3(HEKW=m)j~jR# zLA|8(Xy`WsE_a(%NyKSO@8mbx;`c1p7IW{E62WJctmGjO^5cqxY=3cIHj5ERb4tO7 z_2`n0bCarh#m~|1;YaZh&u(2|3EWBH*l%!n6<-}5&-ylx6;Pn#o#Jo`P@kpxeU)6< zEyfr~**w^u$34hNSqx$ixF%v@GL&je0b76+|v#K8gPP5V!zpateUtbz7iIw<%Kc2*@Z zXIqIEXhYtYtIp(siw@{?QkC(0>f(n$HD9hXmtb3yo{N>jA}s8JL5EY&^_m>6YORB@ zD9pQr+&;(PcZUE6)DsQ8L##i}wWZ+on>8+6d+71KYh)ScA+g55WA*vGx+a5R6r#>M zIBi~<$~CnZk7-k|Ffmln0M(5aLV^=I%n%>^q-{=nTB~|_B{~4D`4j9v13r}9zFVqi z;jKklOZEYkMIT!UEqx=T}*cRuD04u3ase4R^}No%{~gUs0^ zQn)O9kvHLMRGyq~;8mUXvWUmKiDdtA1pIf<&PPBou9-XiF6Bi|F$~hF5n9WfNpqvl^S2D!MUE$ z3o(CGCWnXg6Hg+7!I;k~CQGxBI&(537)fvE-G7+lId4sj_f6;8K9EK$jF$4g$3YKN zX@z;WKFIoj9R(Zs5BJCUwvPBfuC?kG77W=3`wXVqxCXpRC_ zwe(WERj`MLSNQ)P9)t(L9UuU7NYaB7IrHIYF17E3+;STdX)lZRnsrT z;*qU48&fL zH~l2++*ky@MR%{lU2&51tvnZweg9XWyk_P_9x^vFt3&&bHFfs?Wb3NM?enr{ko#j? zBl;th)U1=s<{(|{vVJtne|yuK`nL6>8vo^GYwD}kkM1=u3q0#klze6Lm4j8Wj z!qrdGYkiOuAT{ekK3w*aH5Hve>bBd>zzb)e^&e`i`W=vi8C(bi3g;AnKTK2gYu0>} zJXez@>S+WDiC9!uIQDdZ@zVIX@&co5Et~@|7LxGo4s)z?+?>M9i)O^{a2;3CO{;G!8ove-{@Q@%Q@T!t^VTvl4(AIgDPn&}1ki1FSd&P)ZbL&SSnc0#j3= zYD)k2P`N^71luy3)ELl_C9%NIt5(o(r0*QcU1S!F)E+99X`&3;7eBXpR#{v`amGfu zf^>AK+<4BOQaPU~$7gCN$b8$B*22>W&4|Vil~&u8)Dar0gAocRQJb3b*_z0d`8+j^ z)K8D(Ph_~Un~%Y?!uz3lsfOagO3aKROp00N;ER0Zb;~e6ICkk!6TY*Bura-2w3E|F zC!;LHSv}329q4Ep`b@2Tp8-N8}2AxB<2@(Ydk}!{e*H~<6qAZExo5$ zLIeArzTw9`lOOu;CmVNeu^L_<6{fGh8m~$YE>0P3yAPW|;q@0lg^ru>xKczI9B45 z)Qbjy!=q%x$`Ez$DQ+YqaSn?mDT%{EBT7(?x+=i)fCmQ zz|d3LYTffYl6~(=4ipcv!6-a1!E@^Q?mWr0&h*{(E_%`{dZvhyI6jv=Yoq8`*3kba z#5^l;)~6U^{}%H+`7>(c-r{<4Vr*_a>$5pIOZzVp4k2AFa*nnh&9@tlgqTPx(TC)z znyzo?_W`u@R1yp*w|<%uPNG;6x3iH|1A-ng5`1DEha)xjcg*$+{R*B`koJ3RiE9@u-pU;OZ4*~GshAdNL_w< zL$k8`jtHv+yoMwG%L5Zs=flMWBhlI7;PJDCx!6-`aN)fgy>4h&DeKKQgiI7ZLazOKlfGr>ufJVpHGb0032JdZax zamc)y(^+b$-Qqp@4Fhtnse3|Gt{i&Xrav0et%PL7=I4J=Lao87+M%?DX5s&R|AaMm za(%NPms9(ByJ4%T>QZXiqCd8E$-O2;D^88L>kN30%42ZFVyy_JHuTRWv$gs@lza`% z${`KGib#;27)}>(R!nK=SLIgX--hxF16LF^^vhyfXRtIoB-3v-BpOwhFHesS@X1}% zM>7Fo-1ZnNPK0oc+D_LjfDnRWLR-RinjR1M*!Ok9=V(#=nkfZctwaM0MRS}W!JxrN za5^1_-vk-NF^A0pgN8y58V00iF{*9u{Gmlb9pf}d<`ZKffeC!h^7zdzMmY^-K7dI2 z{OIh-kd5Wz8jgG$6_>SoDehxNUe7|)cDI_YZ&tO8H`19L+-!~`MfzB?i>=iMsld>* z)u&Dp^aah$`m^0+yR=gy($dFgBc1FPoYraIY|Pa{5IXxp9;@M#NU27jjuT3H%VRR< z6Q*eA$Bw1+e^I#nH~s)0r$S?#JteKdu8@2aKTZ3(9kU1w3{iO>k{)W$yhvhJ{`d8u zR&uE_(y#RAG&lDazr}9__7G{hIKODNJgzWvo_CVkoH!$?U5&{Wh2ge3A;REB&BNSl zq*-;N)41er5-wF$6Wyxu>G?k~XrMw_@&a!=O|w%^6Cd9LaRg(x1aDNmmFPv)s!iJH z0IkG+N^r)Ky5fBW*6N3NHM^y16NYNehIYvX8-dGIC7vfiy+Ic;4HOjp@K?ungUE9F9W>r`nL;sW()Zvo@ixU+wCi^OZKpl6 zjFQ9hR=n?|6}M;msfCs)I_^6R+v)jhv-=X9@4ET)RfFMnIA8(OeEM5q$(~p4IA~Sp z-TQB-7~g0+Hh9pQ!o8@ElO^af@DuH+r!$$S#Pyl}#rq1a)i)xxW&0qE%`|ZY>9_^> zw~KDo-7KI6vw~|04et}R*@lFyy8JB7hrtWyLCsjaZ?G0Ow*Z|WTS6zN!>n!Nvg#V% z5d}^_oH+;z?!#1+K1)266!(tV@zf~xz`-rz9B1nfdLaUotq~Ijbn(=}a%BZ43)8>e zevA>Yaod=L$~eHol^JxzP+eU`u$dPpDex%i`hfFb7@|)$yfg&^Ld{F9UbJ@g<$5de zd+`ozve&cbwdtx45zehroos;4x^CD=%YV`A3&+Tz7N$#eFXr2IG`nM&t90ML(eRmaHDpBQ$W%sX{3b;e3J zTE?22HqR_Pl!v}!*=KYlBmNjJb5`RQp}e5Kdh4{|^p+mW2BZ%s@j)iZ%G{0We5CYu z8XJ`PG?D0G2E$66%TndDCfiENja6{DL+c?k(Yy`wJ}JYkm`@cTSiJ9KoU-Jcs*Ot6 zp|zSR;%Gw_DygL41)L0eiaXIipZgH#Q^^PTt|vttk)BxVRJ7DSoCZpLXE^&?2S=Br z;5k8&Na*nWU{Htxv-JlILfUZlJ8OgvwVyFOhDxGfJ^=-DiVfaL>e~q3#b;@_n3dbU5aHX`AyrZk4{Mgvv>~7i*5Ia4C>%q-^@_A7Rxo*e~+& zfPmpVs9`x>CC^1*uG)sz;bORZbb|zgH1`F@xDzl|@-#P9kc{J<^I)IGvA$J#I5~V^ z6k)>?Q^0}r;jJug*dh(bXCc^wOkaIs zvV`g$wsAi}(*{eM;*jt2b#VxTY;<3NZPGLej9E!QCppcAht`!TsAueq(6~kpM`Umf zCi1z7&xHO|hsibAaKt~{_Eot13g)1Y$+B?}zz5QoeU0aT8eu~$g`uaxa#iS;IyisE z^VLsd$cZ}WeYv{%n#VXP_V;Y6+z*9X{W^Lm1CxHb0ZECV134T7=kQ72#v`|d< zPVhsl3IaY0g*k()>FSwo_I>%O7WK21=4?LZb2zb@KjWqv@Q zEzqJtYCF`0+ui%+II$#g5X!sbXim;8zvpY-jXd@I*5?YW#1V-6FfTrWL5D5REM^;O zIBJZRfvn_gm_I&WBaBnQOdJj_ ze)Og-Hwo~UKA-91UJc@47!YxlhaknS%X011BUj&=A49-RJOE8A5sT5Uq?d7=B-!#U z``cD>5(kU9nMWT@*rH{H^d}(KSw252GN_+fHJ7w3+|*1P9Q&((S}g`bKwwKTD-KJ@ zTC!w50gPNj&H?V}p;czG*J)9lBitumgE>WQf;ODOWD>N2`ouQ`2dlx2bs|HOBM!`w z0Ol_{bHtiN?C^gknOk+laBusivChAgeneRV`l_`;>!unjxiL@UTv&{hIYK;x5(u6g z#pW+?2E&O9WEeYh96(3;KV}nj9t7_|ysc)Fz;}JJ*+}7%g~#=DBwBJ<0*45Gb{Hm` zm=&^B*7SjIeJ7Bag_nd|ekUz!dfIGsoMyRW-$GxH9CxsPx87#ud$s zN;Ec6EJMFFwadD@SOVZw17+*(Pw|o^kwC!^B=V1Y*yPVrl{eWp+;xxB4z}2%U#dfr zEbhKtMXCtbrvh?M^tx|Z#y@NJk?()26;u&Ogl>d&H9pBAPJuMSGH z2fm8<51*>WB9jeg7*KnRrKE8V9_3%(bS@wqNI$ib-QJJ{_2Fu5CnKvync^_>kq0W*f#Ov4%bgX{B$&_40cd;J*`;%AOlP(UkJ{ z7b8#%wOU0Cfn9!>F`r{5?B1A?gP??PFMZhucq;fxTs&1y_B*#VM(o*ODm+aEmfDX5 zKc>Wsu>$UiTQ^l}}nV{ZkEn zq`7M}o$7w;fm}v#&rMA7$f>HE$z~%=VV|j+5`4@xkaa5sx)|ea)u6mI%gT%|` zV=b2Nbg2H;P)_YTS>1)tEuks%BDu)bPXGz1n5aT#D!LS-XieV7B@Z@hKs*1a?c;yQ zP96IJNEh9|eKFlFJ?N_sw#?$is@(6p6k1j7aD+}rRzq9T>C0`ID^y#c95Z`B@{zYm zVf@)0Bl8<21iXi@gcRtsIEEz)DX)IczR_+7P#|0gdOnlwKM7&{C+!$|%4#p&HCp#0 zM4KCX{6Pxvqfn%%mx!2#<66ke2vH(YX@(FeVbAAfqym?{+{~td7SAYi15IvbE?I+p zj^T=b6Ix^y)0tmztjnmtA6-GYOdhYnz5t^C#;E18Bvm^@N0fDkLL?S4tAM0W@8v2G z$mH+!1^B6j>?Yvv<5uDhrZ_wM%sXejs5rYVm_5Q@jsD)?ykxCE;`Fr+a$4H=-{C44 zSmq=hM2mG%HYAWQv9O^C;_!8W8p^DHHikd*UfOFVcJQ0sJOVv}w1U}DA^1U`CU4YU zp*4>{(GNna&XD$u5qrgdZy4SQGPP>XsD@%*-pdDpxfSi=@sR)6ky#HYv+~XSV$51b zI&iv(bqvS!tS<$`AdN*YeI%h_?85g!WkLww*Je#^vHrDXW}9_)Bip)A0xv&^k*Q(& zA#hwB%gQ>ECer7xN6uk_-va#lr|0yD=T}EOODfU7%-PgV%ct)Jw2E-NuuJ{e%m@fZ zjlEkMqiwwLtK%2IY(d^1%sb|8s~QvR6in7rTBH$glSaH9Sy%E=7QMWc#xxP>&C0-u z)8Kx*l@DmshEKh;cY4dYz8MAG%QWlfElI_EH%vD|zHo`lNx;`F_4K#odGxq;>HOkJ z1a>sEt+sfE2C952Bcs3ruZxLWY^}PFhmjvMD@pKX{MdO)w62pP_)T~-K4fEMxb3J) znzcMLlgVaQ1lLs@dQITRT)>@=;Ky2)Mjv^MkC5};(%%0N1F)X^82iP+C8#N|z%e-n zgSnpLC&oPxls6_*TU^>%g2oN(fU9n3qsBrg z9a$Z7`G>u{0Ph{`#*Tdn1+b{4x#&Qy!0$ zc5o+5huzR)^m2-TyD|f>h${ON5>t_6I|4}-n%9mf8#0VPy_tPg17I++yFtCo`J5Is z@+L9Ft(9D1B87EZW&#f~#?D~#O>E`T7A@}8XEJS>-}9zTTFYN+T9iNY38RnR>f0yL zGyX+;Y=9xdJNd`;fQLG{Gmu8jCz7`Z4-*AGFV;|t`IV*QOOD^E2VVlKKr%yOfT)4PV zFg@{0$bXQJ&0Z1oV7XtPZGz6I@DK-(-a}#*h-Ryorml+GmkQ*yo_CA^v%^ z;h#k>)8jZ=&*AZ_hkG@RGTVZ1Qa24ZndQ_Mk(3!l|A;1}B^tyS`~ zj{)YyrOLo1q*Vl_Tih z7PxleAreC(BRW2kfrsN}*Yb4*MmM083IyVMMGi-jK~=6amhS1lgla+G zwI5`DiIN1*SstC|vqCs)or9%5Wsj8f>4poK6@+O-gzOgT&4{P3{12a@5&~r&VEy|u z_&NVRQ;9r}s>$}Ukl|;tnvu*OfVBL3vM8BV5pI!pcWL|PWuG#n1xIUo(&j7sM4%il zHi0N%-30%5Ce0G>wl&V0&HsR%Vf8S%*kLAl9=o1{!9M_AuR$uktaV&+%sQhe~s%O|*A z3ln81eP~ypb|L!98m0Ok1*tF7_Nvd0fud$Ln-WtS0fH|YCR?QD^cDR>%FfMFg*No- zuXQPgHYvN1A2Y?YjDqk{GjE;v;SyKgy(}E+`zFD{fuvD7`_Z5Y`FMu7>TPWhFm6;rq4j+F zbHA2}&$ludcKYgXqgjOpuF}9DE@FCU;GBEF>_96z{e>#$HK6`G3A>yr?D^V|zWu7a z@M|oub2&I>qj^<-(S;VH6Xjx{#r{P~kBy=QPVi5pTBG-17hN!heffv4qXK=D)Vv#b z>iJWZ^Hx^LXxJ>HRy3Mi*764WbuG+*C%`D!i1T8)=){4+YQr5}nHkR(Wz^Hsj%L0K zucbFXpxamU2GBJ`)HH8V6^l=6Ejd^>MYDP@UqJrN8<;m4Oo=Srfy&(72w5E@w)rLP zfukNB<5s&tl(CR|ePr^qJc)n8)l5i%#4S(1RVfCFfW%f~KQx$IM9HXSbcesO>9N*b zCtTCx_1p~{JeFmiq<}fllfIBUvN#`;sS*2roaWHq(aa7Jpf1v3|CrXk(IvY}I(*MJ z-{8bHcE;C7ZezjTcH(h~fg0z-uW{u84g-^oYYf^IV@Z(A74t@@g(A-0h{n0Dn@&ec z_REay3uKbyX57t-_RRDb2$z7yN4bLU?3J9kMG^WpJErg3f@x=D1+TsA+f}C`U7ev_QU#UYK-003cqPtf=jCae&1b7xhdJJX7Gu=a>Z4bkqk_fnZ zze;lM&kRNw-L6Sypa8?)aU4#H0K$L<<9D)nS z-m@EgHb*GVZZRhr20c8J2=?-2kw!LT%F5xcz5yj%Ag-KrhfSCvwbXR=NX~hG;*cii0%}69D20X zfHjkX3LM91puW>yu02zf!RI@03&=$v_vYrZX)2Ub;z#VfKGDcdIro~eD%calPf$)) zJb4=SNpKcz`G3~q1R9*o`JhI_J5mi~UKdlbvBO_OVz&%Br_cUBLf)(u(l;O~NZN7Z z6Uh@{^Ql-cJl}n!FSn$9NVYMyeHrijpmdk^nn*SAfl=rXvj%_12>tEGCxZa1+6Tmr zWL_uAkW9fQa_wf{_JkGCJXn`Ne*LX<#aR+dc(qpl3GAOORmc|K8bxlS7`fCpIcDzX zJ5xKmqSluvrJVp{e8K1oTyp6%ec74dLY1l=!HP?wEzrDFn)01vOBcTa6p+OMyOslRW!rHs zA>NGxK9Xz^znp&a`eFRcNX-gjIf;#KFvU zr1{}=>MDHaz~#2_3^YESnV0rUXffD-Z;Q`m8VTm-ZJB@K6QSVl7eq}Png4-3Opp4v zV}n`WOg}!4m00nd8ZosbJ=JJ@KsSp`#@8it8%ahQAND^x-rs+K6Vm%*&ih14iW1)K z_+Xyqq~QwV7hjv}UUW@`w<&QNq!m8Gb}xZ%|EV@DZW2xK1N-pJnD^D@M@5uYX=c7T zS0HS5db4|TSZL=m!NtltGs__Dl%Wpd42g8QFg0VhOxci zb{}KT7P;pCxbQY~Rl2)(#etYNb`C9?F8v9mBoVHnPMYvemwkia$JY*AOYB4Yih1cz zKBXP)avh2+@{hw?vEw}{)4#f32X1q8(l&~-q|T2&J+HwZzRr+49}>3?EjW$1w_FqR z;#pX@a~8Wl5hNn6t8sJOc`hpC@;^zeHfOQt!r;E1KDZMKFb{rY_9Q+5jPcio2nkLc zuq$HDJHYQ7*ADn+_qb1GzSDMjdeM_6U)j)cUHV5X*m@*}A^0d-i@MkF)&|-haZVKX zV{w}I`X@I$+}TXu?lGqaD$$NSzIC=oI@1BpyDk+3I#ECx_^goH&Pi%EcSm;@d~+;D|Q zaaTl9SrWE@qHKz|BMQtISwvX{^7~ZZ$%2nQ-}iUU`_FsM7fxsH?b}^lU0q#W-CbQR zM3u;CPEWfYdf{X)deDm(5}AK>J6ZHXcMyL|;^F@Ms~@SD2<9Dn$udNG{?+$Y%=r*v z7MJli|LS@bvm6f1zxshZ7v%#J**8l0@f^-9%k)<{P5gKgUFFF0V+wK)n5G;*zCm&3 zen|dRaW#r$QH3felUG-%m|iMow?gB26_dtHOfUWyaPqIp);Fut3XK=#x#$vKtI=2v zPS>K5;toia^_Jd(hFf;t5~bxo5;k?OeVo5+r8QwbD$^tuE-$Es%i6}cg+73)BN~@^ zaJV|r$&Zpx_0asQaxH*f*iM!diq9zmU%EwNJ{IDYELQc1QE5a&%)fezJQpR_#`-)j z&Om7_w{4SrS4Z!iu4Q7FKlpzyA||1Rr9^7V(t(sExxQ8>opZ4 zmrmzjeO*!MbK3VGy!apR@u8Y_q2LlOX}eK^OZgO_F`H3D{?)e>v@r^P2mav*EyD}9?ar)co^&aiNMXvmzpHnaUU(~nH(iAmwgElA=Lpc~s?bOP zkGgFIkKwA+dh%Sf9&D<48Fylj89iZ;oi!q~q!g8@>tj!he&{y-b#v6zGL2wUop>;cwv1QgEdo-ut(30qa@P zhk+cI)YXLQr7}$;Qw*7|fm@Bo^$L$gl&kQlL{aefyT4C=l9cWN%Biq#KZ*aD9&*t7 z(pY`r27z6W$6pY6_J4w3Ebx~-EqUmXzN!C^p8A?6R5%P=nbiXSZt3xVP!+v6fu_l6Z&R%slrh%x3ag;kUFt{ct^f zrP6nd_$oOra|XRA3&y*KM!>4^Q4wzXs8E^pqL<0-c8l=?qPIbh0i*o!ONe(37zK6< zYQf*B;5YtT__M`t#DzLD!%WW#deOaL=Tf8kCdp^IFj;bw^3mJb1X@V#{(@^w`;*;N z3e5ILmHqqnp9bHu-+7W=WjaUkYuGimRIaA^bCnLJ7k&Zmfdd|Zv`u}lDUb=*(#i?3 zl*#2Yz*7ekO~k)!LmNCq4)HHps~=S3J4MQ0CX40@-@gBVuj&te!J#jVBa>fZ%+`xO zgDQv#nGr$w`U*lK^f8^Kq-17Vy?GSnCexET_u2=rf>58jB3aRbE#k=+uwIpRaY5~KEtjxfNe@_n% zaY7GiVMPx^rOo5@+Vs#vmLG2*b&uX`Xu;~-I5SD=uX0HJ|CZiY={4>FlN9hH7yhxo zSGNzR_(`vvnET%O=k(yC1;T9?0)J|4;BYk;c7D zmcLXH&yw)(`WM}y;L;dXAcy%e0f`oca6 zPHnG7^G!I{|9!sd_G=*c4rr&4J;PkQwtOEb3b*N}`~hDtRTITG*Tkc4`>vB7n{@#$Vyi1i?*0_T?(dt5$KJ~G$zpnlgCw_Zc=HOd)Lb_75DM{J1}Xroa1`j;4rRjZCVjirLPk2 zkIia~{XT1hCsdv)_^!Rz`h)#1@I6_#S*l8CTyc}X9slpa51bWJ1-?ne%~k#7{{()u zccyVmSYOQPj5RneJXz($7WZK%XB}kewc7t_0Hk(WSj@p0jODz8TgHA7a*H%&xq$ph zWL6-~;iI*e6WbTbu9k&^MvHa;2e729_K%=xvIUzZWxF7=e-q|D{OtfUfh{(UM;zAG z8ieu$fbKjOLcw9zG#^1tT&WN0h|EIv_GyvrJGp3BE~iaLx6j5Ky7NgqXwj8XF3jAz-N z7O%8YT4UZ#zURV%fkB#M(LgKLD8c`5{jZ|Eq#*e@^FKiL=dD;Yj}X`4=pEi=d=M== z?n4nVuJ0xB5B|6|vI*H^c(iqXM@Jl|L28oZmV2AaczK~R`x_-^gcGaQha4lfD$bHa zOTt0ksSEwwh4*sreZ1iPL6(_AL~FS$^eEUK%=JPJybY#io~W>mTasd_a1`vYB=x{= z_Ix?VlBSkT)dH2bWP$7hWxJE&-i;PQW$$Cz%G{(9&ELC+B5DJew^`s==TA%WObxCo z#JmTPLxtIWYNfT#zgrasRLv~x1`4YxNW4~j%BcnU>Yrr%;2lkAfXVtmXuwf{T4Ye{ zkky8&rb{#7%#tSC)~v?!9i)aPb!JdTF!ExoL=s7pi(<~Oq@yN>9E zR*J-vUV%4Al->oKn4g@&i9e*`PrKJC64N5(MKNRoOIT}Vn)+I_ zw>ongS$6WK=*r1Yxffl@GY&QL=sL|o037>y5+BBFv}g%Y>jjjaEJg;Bmb;S`PDPKK zZwcnxbG$({b6Tg4JXGl)?v+9S$f0WBUZ-k^k$PZ(T-UNuH9QAB$!{JHa4Vk2fb&Y zp%h}bU$I@=jJUn}3XHg?Ur#xUNURJcypQF}QIaBQD`{|O$>~^L7`|;d5M=XQ z5pi0K6FXRrWIJ#~*w&*u)VfZj10Sh%+60T&J%-V1qo8fc7?E|Kd$}|e14TR35v=i+ z3yryo3uVM3i9iog_SgFr{asEq0XC#9T^FnLEfg4rqqs60Sj*;wmVJ^Pb3ql_N)tKM zz7^Zag4_p9NFk0AT|cB?3zF~{wd7h9MaWdys<>$0;wj0zXCA#mla3ge?76en{iEQQ zz&^JiI6TN0qIT_^xJMr;w))P?&bUL_-;yIG*)#aE$PY=+K~=A$FA|<7!pV!7UR`4P zEyNZ6foQ7Dt#3(xFMNmQdDN#sF%Ev2 z&+{k^h#z-pO9Acdp|~8GD=?B>-|J=vaI21z>=`tWUT*5;HSKV3-YUpJ?Gn}>dbBlt2T^I%jLw9&Rx#FoIBj`ki@QgYyF6}ILYO=fKQT^G|dtlA{hjId)1zVwr zG7spjDEJEnaie$k=X6uF#7qp)69j#C(KKo+7g1ku&o{?ehr97xTow0#+!QNkufzVu z`RhlxXlFU@deK9GZ?!>tYdAHqGELe-Yg`(beO!c@6HNf25_dj#JzOliXIB3mLAS}! zbnOnBf4)LCX;*)@P;!uaXe-|J_jeAnD*c|*q_)I(O@6}c-rJZ2@)%BxX?RsRF#9{7 z^b~Os;aVwANWa;tEji%2F^?w&=N?aV4>9QoyIxU=C$4%rj%lH@;Lm}42)9OOe*?=a z2yO+zC&B@sCbZw-7=cDXl<+_mT&||DHSW>Z6MZ|xSuXA3$5?Gshc6d+-dxIofa=AM zKA)uqf)a>~AVG3LWfdZ?fQTy9tqSt>r8Jl7dA@Qc-2eZ_D7A|9*KFqCx6II^PwLgypDm{G`E(=hZMJ@1q9L8@)`D%t6Tl|4GyRbA<&K<{Ds$k9oj5&D~C_mi8@+#^FAfg`QnEqs*$iL7c- zH`!An(+%0HcCV9KkX5S0d`Db}m74p7v3moH1TTksg-ka3Rj!k|xxPwEa+kYNVFH2x^1OFYxBS4jVx}G?{QHX-&$;8t=9hP(Xl`@4( z^t|yJ)-QVDe5zU?C2isXi%c+(`3!*jT9e#;ahUGqG?42P@vof}%g>wqY?b?sVz;>V z;=e8eH*Fz~vL8eFbTG;CRg$GFmP?UBu%)_)se>bbv$URR(ASkRMD;6Svk^Z`Nv<-7 zyH7~ju~6~{b>3fg6+jn5k}Ri_EWSj`IdsguY)4cyG}l2~SD`Lw zF-jj|5{c6Q-!mDbqc$p>T{;^gS!B zMHT%uLDQxE5q;88=-(69Nz>d~uqC+Q2s4CB?&ZQCGST73weB<@xuq-F#l=j)DKZ^8 zZ>A%KB&>*(@x|TS>hKKarj;EQCMCtc!{^-UhOsYvV;1L;#EEgIl_g}NYuyFlVv`rI zrFzEHN6R^tqW3-0+uitmx_Q$%mn#cCQUW7;wOQ-9B0IoZjALNIk~n!gr>xk|>&5kWQzk!~WNVgUDek4&h=#ZsA$oB)`qzhY zmUEMA_M2Z_d{vWf82>#pk2jmRYpYyRpRD4K{Rh1`2>@u`hp8|YNT4m!R&MZczb+k0 zrU&xlDcUQRovxzi%(qUY=k0OcQasZJqCQ9;7UfNJdmept5c}r1?){0x<~qbytXa^c zy`8b_L~)eHWYWN2hwBhM6SYRf+9nw>Xbc4sug64*g1%BAWWK8;eh4)g$s=VaxeitC z1tnn`XP}ZMRdS*V3diF3s24h^zFTo$TUGnb7aG8TF79MjSh@RHU1f=}KY9j+Ug6HM z4}>^+%035{Yxx%>DF@u~IK|4@VZHEa(54gRUr?)5E4c;J;)pF3PwdETW^pzYbiv5I z&a9Y{{%H<(uqmkVg!UGn9Rmiy??UFZ%5_2wr|T>4(pQAIrX!~1a1|B3z$domnSB(p z6~n4b(Pxy;-PRDB9%SvjpQDuNmDwSk_b0~v#MO3Hd6o-Vyt&yjhml82xJf{ndwD@> zl`-;2)E6UH@Yfh{46E{Cw07nQ{yJ@ALIzA!}n__d& zrcBkcMRGl>x-hT+Y#t{cqsPa>pa?`!u@XH>@#aFW9oa`s7?dLkDM!#&Rxsj}Q1P9& z0|fJPkMCoU#!y^Ht!!n7s+RwY&%Gf+h->v+*9A5%xW(InyHp2dn2Vh|Z!91of=c98iF_@AWcG8Y&G7aV2YVcz#>@Ovk3CpD zo_NBVDglwX%TIqAL>fb`7^~GHY0@GGd{b$^^}w$5t>TH}N?_!Bf=9>1Z9QeM^-I-S z+mYZTWtqG?`x<#wWF2M33_ZaYqOz(hT1hwtB{5-5)KVwm7tz^nHu?0S(-$*g$V zD2?k0d{^09GUxIvKk3kb}=LfmT7pvH3 zw#1zmcg0(>`*ZBh+p4fMI~lV+*OdWE+j9NxeTkHt!33eU&HE%T+-puxCj5NCb%E>K z4_}D=0fWk)^fzS{)Kl0~v|X&K#w}6zf!EqkD>^qIyHP=1gs6GpLhvj}Dx6M7x%H<$mdS`)xIE~mk{?DH&Xqe?f z_5O~zFPFW>b*b~Yiv8o34C{POVeacq9_E|FlrS)(IuRwroggdr&C=8osO?#)qWsqXV=a_XbSZPQ6%fEN1&1pTNy8SKB_wH)75A{LyKKolS#XI1X5O3< zhdY2l#--4$$gk4R@-NC@oy{_JLy#+%c^VsF3G5_PL-@m&M(zCap{7ET(qAE8M-rI$ zD*jT}DHTcrP3>z};D^0R9~{D=g{tdhAihacCqzw~)i!RQ+K$<8ZpUP|z@S>OV?(tI zgM+*+Io11yMc-uADG#Jvc5kK8YOTHt{;96*Ty^K*qE**blwQ}DLSS}fcC%>{;=K(E zB)L>(iu{Vn?{=D(;guv=?NxtsT}pNN90PI9$@I+Ilyq_tb9N^ujhXmrN=}=YOEbr0DdSH_Bx-!R1M6 zL+C$hY0}&EyX-M>fy)o6u01Tuy?saIJ>n#*bW2)xMJ;Vb|4h~P~m|oiVDfD zEm`Sch~4y$a!2i#sjlA;F=>t=a_Mmjglpz~ouosHN;6W}P72B9X7v+UJzYsCj(gQ! z2KzU7H>8r@tVxX1o%gE>e;E2*Yx!8APKi#JyT3V{7*%Dd z+{rtey8FfDcJD-9xS&hyF1ZC2du6(qUi>;Bi8U=hZ49}3F}Gbvlxb`_R#KI$VDu-- zG;}_$QoY99h$v-DR@m44t}IrIUg10B#&oWuzOab7o@sO0$uwh*sKSm(=>D*C1{k$wK$-mESC#qilUd?1z@5~Q|CJrvMZ#l zDwLii>ROcC0j9NIDBFqp;!E;+!`&2y0fj~u+iah)JBSN7Mzg((#3@FS~^`^HC~7Q z1x9iyVMrBPPIu#ISw{DC?XpQ)$wUpOwifT22}%&PbXcs>B)8^nh2XO4FZHa(vjy0Q zEq5n3ts?9~qCF~6o*+mgXpM#9!p{hUsDewd-4q&$O(4m}kvDovl)IA}5sJ>uu8WtJ zY^%Pq^!y>xiamCWzEG52+>r#PRA+Fy%S+#?VC4Tmx8JMM*Em6`IkdNp1zg5PZ>x+t)-*0D1cx-)|$Hk%-5+ILZTw>o3L9}Pkr(8LbLqK zrak(j=8Kr3XGPI&roCGZ*-Si0C~FOR;Y1QvSN!4NfK3o3Ct3a z!R}5@j}wCrSPE-a*D{)3ah=oCk62v&`2MZ90sNfsDl*%&cZ=~!6DT?Jm-x|D_4!M@ zw+0U7`VN!bKMq|BH=SDi9o(6hs^cZUI4CjmD|~%Z_*_j7)6jmHlvs>;knpW(Y5$!` zOIgpsA2Q#4ZxCbV(~HG)jHKq_jYz)oqU_@fSCh)e0T3{g6wgWiq8So-uDTv6nc0lD zr(A3v?EA*tZY)p6JSqi88Bt@IxJ}H)w8wSI+vQvT*VN2&RS7D`$jmM*+PA89J=Bqg z!etcUt5c09<(tQ3SWd0jHRC4N)wc=JGoY_GW+u zzzU%QYyK6PwU_&s$UTHT#0YFO>%gWF7#mV6lEpH>Z$y?S`Pfsipg^mux5EQW3n#H7 zldLhagq+E>b73oFFI??oA$iK_k1&{}Os-)+_4`)&FXicl3yD{|@2~J68c0g!RmUL5 zz|_psC?T2qlU$z)3ArXobk9@^%VE(&I-jVxf%}&5oBHi41~q(RTYmS}m)baJom9(Z zN8E|5DDVtw887%|1mYK9^uO^7z!^qc&=8&~b}eBn#|q250}-PWWk1)Z8vh|qOR1or zfGspN80YHjNB^{m{<#0M`QZ?-s-7R-#moOVKa@Gs-_8%2Z>d?9zEB(^nFd;0xi*Gb zYEsAnuIwY0wP#1!FRhZeVxdR@`cURDNwHfJxnZ$H=4h_IRu>)wo!sTt2d4wV@A`X< zEsF*Q`>msPW}mFl1kZ{lD7UnRcq0$WqNZNB86bYu@Kq_on{{8UD&EfvCP6Itviq4- zH4{$F`~xxTUpG&&oK*s{M`pw(^8PtmDF;9NrD4dK*dxn2EZM65Ry?kxP|bXV*_Wd4tegHa*=kxf z*{WYN*=jy+Nop1UI;t-3H0SGzdaiTA#jei=ag6hd%onz$C>CzUsZNA(n0Ew(l6h7g z`Bn2QbB^V}?@p@g$3z$YzM)FF_bjzxD#Z*Wz!g}upBYkiJL*+?R%glwwVohyoOxKo zsySB$mL{jXmQmb#TUxP`)~>1VUt8I1)c>OB%Xm>s$M@^~f3N6|q{M2z@6U@P|B9&e z9A))rl3~n#WIfZtz1d$a23@>*gOBqrz+~I`4XTsDsfj+tx>%zYRNSkRiYcC zME+r)IlCSc{AJ5)8~KE5csPT^UU-9+~Ql&YUED7^|@*O__N zug9QQ-K?x<_oG)`L^dR1TkuP=E6#Td=+&Zc{uNX6Ry!bfD>dY-)W$488TTpp3i^o( ztOD{N2H$r8at8Xeh)p&gWIqCZ`sNf*yN*hqMp^PQ+7BC{`pX{QJLDR-1d?r0XwjR#!1NlNphviDwv%I=C= zuBpF_KUoHd$pk6uHl^8Ak3XX4%KR$KZ@7>_DKPeb%&)4eB1Wb)D$hwMkU_B(@Beik zA@shs$|>$!Q{^zvuR`8(=5Y{cfY^LK;BO2yWAGDzX^z<W7d?xc zs;l%T(UVSB>kWTN7ea9gpl=yTyd%I)O0Q|3+WY%Rr2(t}A?r>1Mlq9gE$<2lw%F78 zsWtgmc8jicF~q9fUyRzEJbPcG1UFkE{!R51&ob%fN~)x|mUk!K?*)JxMPffr^t9`r z6n8X9@B3?SxeEU8_N@~HY!kpLN#ZK%B=14IV_WL--}9~jb2yFetHuDhTUh%vMHig0 z$W9vqcOR~O$y@NFWsyggjGP|NaCtZPIk_}X;@r3i1jpsg`0HMN8KTMMQ>3ASf<0TE zI3wV}&u@uwnIZVCl!(46ljshfut9hC=pHRl!H0uH;g z4k4DlpH$4Q?!PKO@L^Czxqr+b$Pxdl{IXN3W=Dr}(kM$vd_6Zhe*_Cr0p-46)1R*Ny?vfaH zEcff``eA9{bf=1GRh5KVKyClB<)kkfNF-ReiUem*qE;DKB>hHTd>+zp6%x;`B56do zN+HZC7hJ)DqlknTI`duV;8yuSpVkwuBE=AXaF=yKc+s^|x;kd4UVcz2NY%_tC4AuL zBs!Y#nrmya>$943DvH^qmdTbqv7aQytrk?XrWAdXGZ_An4b0Vo0PQFcvC)*`9fMup z<96RwsW0CGy}VZjivEY^(nZHW0LuZ=xYwz&*>TQImtOgE*1r0O?R@H3>4!yA{X5O?wrjg6O7NME#szuc-fuX*SFzT3&a9uORjBvvkfcD3R`*}VAf z=gC_#M8p}|P7OaxpPFEC^ka=Q#S!FbTUXr#+4u38}lAZFlfpRX`jtO8U z6t1D4YP5386&weesIi9pva*LocsVG9_}&<# zrka$mmghsZF7eGJs@DEd=Ur;QvAVypsm`ug4L<%IH@)aV2*b6Zp7H$l7-H2+M)4rp ztJBjbMAYoqGcs2^N7r$E;q*K`OGpQHF-$CF3}?aHdRFk3mu7g!=5xUnCP3)niE6#j z6&8(Yn_f5v0WEiC7QV#;i$;`_h?WutWME}Aab|Akaa{hq-d8U(Z(6xcIu)Sw&5d%p zjO#HVz%&1l839E{z071Q&K;Pv~!ck>nZEI3O`@ zOmv98xR_FzjRmt>Im*dmLBYFF9$rLWwjZ*DyIZgE zr+z{VAp|S&ql69+WRbQ#?~FiEi*%R0mgG zR7o1Sm>twgPtsMak5fGJdIwbL>-uK9SVa}=2=IpVMW8$meN*GEW*_r6RpB7=Q9}~x zn_(UAk$e29d_DM5)n5AMK$yX5Ns8O1mlVJv{>oEvOTppGi$I8-6;T$|3Xn;rlHszr zBWrI<^v$63exq@i5%$+Nf9y%IaPV&&UL!U3QMrrAvQ1@~*Y;Yt1v^>6I=KiQ?%_?Y zLabt$62Dtbi5m!(pq9wA1d`1A<*xuNi!8p8$P(cAHjp;O-7eY(s7h%bhL_kMb#?Z@ zmjIsC{hc0a!#HMw=52_$_lx0cyCK) ziQVV4_?)gi-pl=2vUB~S&XFAV=J2MZch=2LeDg^G)l!$+PqO>rGDXm+>L9FdF&=@m z)8(6Bp{F(GFqi9)99X)MIv~Om^?OcdRJ>D74<>{at7JV!Az1N*_tms({GJ3&iN>+CkqTmXSWiR@V=y|E+~PJoSHc0UBW;(G{cGKE`P;Ll_$G- zty&@V^PrzO#jZHu4Wp3S@>(P^Qnb2J9w#l0(o+pgPWJd>hZqXSg3?@Z8lqrJi3e;qHYNz&5u^ii$q`&ubd17=l zm{LWwe1M2jQis?cp@aK}zAK`6IR(Nm1;sp`1Xn`bG>~OL3 zIm|pBjeb|4x_(qldfuCJ!6eu0Q8G02v{0-FwsJNCIYRtJ?199%NzpM`6Bq&#A$~i- z5AsitGTuq0LuWQ{bITT#opGDP+08Q^BQ1dP#mT+9n?IJa=JJWsARZqbx0p>$4FTu(8^p{MM@n zX^DbMfqKbuz!vQ&`=F5kNX>*mgl(!EgO0L^1F9p#F%)aDIw|hP(GU*r zDSIGjZb#QL`Rc?ut<(^bTm7pqzk!*Mo!DArcYoBqH9c{Ng>ILYf2kbA^b)z#-L*_U z;GI@ZT?gf_AhYMS=q1>;S2Xg=3Cs-Epy=}5+LS+w8%af2jF;m^DT5?_aU(11Le)_m zZ`s0W8r$M}rP!~V(HVvH@<5m@i&MoQl!wC9%RD#>d{(EaG-oe&y4~Bz!qQ?2WjH;{ zq$sCnt%?*T_dF#fIXU;)$MbHdP7Fg%mm(}V=Ltb#FF9im5+|TNkBBPH3YQ~)hctyc zBf8q*@$7|!DX#DREsz*nMhn$$2gol*5zjRPp!BxmiLSMZ+^j}PfAmJ+=ZgxONjT9) z7kK0uXy$ZVqlu4S15KTtR~H4Viq4BpabgCQo`MVK&)Jes@vMq&3<_KgU<(@2Mk1zB zwU>o1&Y(Op!JbrXtItI$_D3@CSekwoU#_14yqorzKsDpA2h8|Q?{NMh)SG$e^u)LM znRP>bNaP@J&^ufr=dZ+aYl*GRzxl#*1+0E@R*1wrnk6ym_;1c=^Ood`@#!&#^q4;! z`arIuA9#qPIqUKeAtd^a4DFwFOQM5%2Y?J;o`8Iq$=N1bWTpvPd`seH@+(}vO6}^W znbBVn?In-CK$emClJQ9r$M{u}&XPo8_>=yH{Q30vB>d1O>K*n-wdT`?WRI*b=nbi# z6D8H6r>28}@SrVn&!Z}Z4`Ph)sd`0jm?2Suaz^AKKAR`T!skUtB^R8)QSG1b-|%Q# zq8`gWJ~g?F))%5q73o8_I19F0lMA-N!uT)VW9v58rJ#Pw`!+qMLXSD(=cdD?I;wa0Ls%vwvXd%2qe%?EddyFH z%rBDpdNcMXQv9NK_*GwcMJl6boF(rcP)K!wEB}%b%s8;9?gHT!72p0x^E*txw*$^-hK@AbiQ-H#yCW+{=r zZv`2c_0wwhoi0U5jBxG&`SVE)`vzq7Cu{ruk_Kiq`BwF#7G~5}U_at3#k1{01dk3E zLE^hvai9@&ewt(xzr`7mjihvZQlqIUD7MJ2kjW;q?@{S8%J?u-SR`l@pDMOj&qqWE z*xHB;H#_~aX8Hq2hgp-QzQtxi)IFokD0dg zCo&XnTf$&d;FIU4|Bz?eqLd)+QXbv*s2L$+^x{AKFT3JkWw~2Q`n8-~wJk2RNjFte zG5s)+07yrk(`AM)F5Jt=!?!YF(Y@IZlRmN`+Oyu_TXmDx&*n{93*M5}i1}PTe_|>* z^=FhwPMBLy-%aijpn-7fQQ&Ir0F_rEI|CKs3%b~K2o@wt&d5LVkCaCa+`_-E{x8DmL$rGp2pwd(WCf_vl0H1)GxUwMW=DPx6J!y?`o;rMC>1& zo=2n8q}Mz2^c9UG1b5|sykt1f)Vuy&k@Aa}OyRs~xb+2|6)Z$3<=iV>gK}vbKN^f$ zCT6r2K*Kjz0adbLbgQ2 znrryS0$m@0V;y)a9rH?6*#xs6IrM%-pTpG9Q-4G(xTJC(iD8Mu$tn(6_GXJ%sK1IX z23K)pgewd#H+ZEkM zOp+ncKad5GBT_nSQjp$RE~<{zpOrS7xPz8DvO7>1kbb+yzQ)QPMN&yUu=_#}gkBo35e-ucPP@zB;8R1F5 zfWhc#!@ic{ot~f#OnY3v^m4a*&bJ)-Q&Z&})I)!L8TBA_hJ;dI6U0GE=9uU-HegqS zv6fu+b5L^ZwqE6hHzu~02*lp&oRP-uu(UY3r!;T5b}^tyT6uz#pS|i-hU^jh#DN+p z+f*~jcKS4vqqhMCOcyJAS{_W-z&yMboyRAoZj9nJOK~@H%KN4R2T6+O%)Bt)Tcngd zKstl13V^K&02%@SU|G5coR{VkW1$rHDkacxVj$HLi=Dq#Z9mK8ToWm?jNoL~K`FBR zi|BGW?U+JHtm2(JukCnOs^2?55_@Kw>zkp_`=hUm!c zK%tiMU))OWDYdz)%+^Nf)E)xe# zA7hy$rEO5ckfZfNjNM8wf`}*t*9t>E7w+~;#?m+u0qJxwb^RWqG5t{X8aZxWSg=Zo zg^?A)aND>+Yi2fFcSu;<|BZNI!cvnFM>6yeMX4RS?F=6<$nLOn=1p>$0dG6>4%=r& zNLnsgiiJ<16w%wc^46jE`GxDj;qnVjvRc8fuTg1y$oF#h%=1}cMJe!Ug-nG`d%TKqMnP<3q)11aU(#Y&>J2eu!pyx7kj%^rLFiX> zg}po#lqyj^d~tLsV8Ie0L`rh<5irt#3MPy-3R#E)ODOE#rgCL8shcZoJ(8XjUIi)W zF_b*~Zp{pZx+d5ZMDbz3J3aAn3spZ*0Fpg36HFHv$*wD@u6?O;mzgc-NvfLSI-Ljy z#O#qBK8AAhn3K&~Lg7sE#K8*}H>B^({@H=k70?c^hXhPW##sZ$2lFW_D}-2-(294> zp&Q8cHKl%1A14x)naGZUi=jDn`J%+^2pK7RMmt#%co_gV)KQBra69qs_c9{#+h#Yv z;_IdCi0Vy5HQ6Xpv0I!LG{O;RX+mBkxv3k7{w{#)x4ljPq>CCBpR0g{KP=h>?};J; zM+A*ku^H~Yreq~oc!50YF|ZJcY=8@^Oa^k^P zvezNuqyBnlNVi%X_;__?tMMvSk$&8wv$2yZFtIni$|PfpKwBk1WSg{u9O~m~gFJmJ z#W;8mPuL)iPS6{2+Oa^0wCGpZR?1Q;K}j$K!Xqp1?_?$DWwZ0O`#Fl9 zbxsM7sA`=TUDuQxHdAIe(R@XD+N+u|{Asmd?6ja&gm*<_v*igh@xtg}Q4O7EvM~{I z)?HEvbE*`V&4>b1UXVf-(7it+*GV=|x=DIfLAI{ZBJaqSCDUVD{l|(VRmMT2oXD4| zbf}Hq7vrjRJy9ZU@%NZ%gYGhaP2DYlFHc8*uBwsoy(!k5ra-eHT9h=4GC4Z^`)YjZ zADN?&H*@MS7uB3yX5+&@Q8VET)VU0_>x{^j4@t^&W^eUF)g$A(P)%R>pjBjahh6%D zRnjD)SyI>GK8GHI5@T!fwJO7=)(x>-{e)M2VRJJR*OuKanUK6ti0P!<6ggbDD*iBSAlwOyS5}i<+OW{kQwxHn$ z9j*unrU(bcaznRy7g7vG>{m%-loM2{u^=sLDBk->WR9#BK?ekgaWuKln=_aVMNiZPZQ(xxXlD2O1alaiKp-a$*dBq z+cXL!NzHmU(AD7PPn-bH+45R4?IJ=(gS=)u<5V@9K9TV|1(~R1e8(-a#GE0Zk%X_c zD$K&&(TXOv`rqbLDEkC}3out;(;pVF&NxQ5j+s{(!*e4yN#a(%joft^k=>-lT~pje+1>I&0cVrIo4g!6`af#kv{RE zUt&Dfj%ZQr5S@O(b4#gmf3CWn_&k@4V90y}QrPMrnkla%cdA!4T+t=N3k1$MdfvA) zr@9L|)s)5JSan%3|E(-wx0f4e^_Zi|)w;l7{o=GfV>EQ<6BT!Kb@-$CF7lo3A~(s2+3D*PK}d3b^k}W;xx~5{sj^ z@uVi|Z%LFM{;rz3BLbd|&NE}?si`|=2z=#SC!cU@>D}KAV-gfCKO`F6gv4Cigk-CN zgakJsL9uCIry#*PKtj(-^WDY`Nx}mP9m%WESz;Fcu0Jp0k-VtIek^zvEK<5wO|i_3 zlx}9E^gIOtfgpvdj8Z7iQfS&KwPIC&Mh?xy%Iy5eB{v~#nOE2%-(`;gTLs$3=J%0k&tgk%TP<$|=D zZw*vs3{N7>tcHA7iU~f9V}9`sQ48mQQ^Pmknz-i)s&@!dtp!hy7tAEC3;-aC*;tFa~D$? znH=XdmHqRfJRu?D^hC|LN z(Kx->z@&L)AYUQkj*)RM&kIG&@hpN{bjmv$Z(T2_RXohm8=taa+@JLaNBYEI)n7%Q z*m^4DN-K(G6s>9Rs{Q|DSM@2H?py)EGV?T9`e82@`)x5oYs?0C9_1wZ?Go5)ZAPlu zDQq+fFZ15g$@AkpJ9&xH3)$?zkMzZb3k7(V`>~K%{l0jka~if~ICm*~cXk=DNSRKYza3 zUgQvkIo%^`+gcVz?<7);9Q&B36>)PRJE>91h@_=nJdw}t7%>d##PJ>4;Y6w@tI$eg zMwSJ$9+e~=x=nwp?3K1F;-^;oU?%OkTawn(i+@9VtGW+KCR5gh@Ihh$^H)4Y$ZU6K zuJHIBF5}Kn=HB^Yxh1#1V#H)nm@{h_hN*E0rBMnM?`eqjXzYSAh<= zXp{}j)VM$NqEBIZvwagd+ocyTf%GYEY(TJ8p~&_ps4JK;+@7Tkimb3gOX4HrC|=B2 z{)7IKKrRC%Q9S|p0RYANwUeAmQ~lg#1#(7Wpfm$(I;tJAy-rWdTU0x2*B4wc+hO}d zLMvO)SRwp^pQ_p+35e{B$-Z;UF@0fAUM1DdQ>&?uX%RH0zwvicO&g>KwN))=wgs&N zrD+MPH>7=4OEhUet5!=$B~(j@d{N2$?V&(30#S@=4+d(vaWo@nKg=L9h&i8{Kb7*L zR?DUJXhWnBlensu*&_2Vl4NYFkuTCdNvxA^r+v=qMX#&&F?&q4T}Sp*Y&xW4)pS4> zBTtq3#GIN#l|Bp-q>IFh(Gk1k>54=UL@LyzId8rcQb?AH625m=-)(I!Lt;rG^!L52 zU>z_Gv(Lp|u9R+%bE|@FAzS%g{Vy;~@6@HIQMz^ap3}dR%3`qu1O^6H1ufy@q!uZa z{U08>_P!S;jzTxR_8fAkCWj~3D-j()EGN$-|#@SBPc;#bnJvakMy@K@5Jd8l+K zdxX zA)e5)e{$p<#Ml0pSNr8u+@-6%IvgX9`j?kIW#W{nv!+Cioj!f)bZyf3`=(CIo)Oi# zL+1`%v>Dl%nPX?n(8f=hIeOCgF;SzZ-=95s?366+zU*=1#!ipQnmRRV#^lkHCXpg* z?DQ$4C;7o-PMtnIds^1mF;O$JrjH#xS(`rg!R)a!vZAI;&59a7dD^700%q)(YREIP zMrV!HCXbywb^4qr08Y&uoi%>yl&Eo|$4?^JfBm=8t|g4HYo%7ZmUn_@7qsACX$p1x z6q@`G|0=br{~Y?WRBBhXD*^uBKz=JLpPn-K&K_Ob$FynPs%7(t>zX!c+^Au=&8F)O z>emnBU%h(u>ej6rs{Vz@zhL#R&R_lo)%s`sr++Z!wf|s=JZay52wDQQ`-hM~yo5Z$ zbA(cY=I{r8s{RRVE#W`Y9wtuG=MhQ?wqBaniQpuRBFrW%AS@v~LwJkuIiXJP0E-rJ zT>!cHmosnH>u}Y|yl*vXU*?v|U0% z$(FOcmu{~6<&7JsgIU0jtOJkFJJ7*xA4(HsI4&~_LKOj4GZq*(xrY#uFwICKIL-9wf{lh+@p# zLu0o`n@gBakbx?nP(UamEF`!HZi0tULRd;zMp#Z*L3o1j6k#RdS;FYVBgFA>%d zUM0Lvc$4rpVJ%@D;eEmfgpUXt37ZLJgsp__gmS_z!Y71J33~|p2nPsX5WXaQMfisB z9pMMUkA$BHM+wIXK0*cI1mP6nH^T3PvxM`6i-bQ3R|u5^iv_)&5JU(jgc9lzWMI|_ zV&vI~(1dUuA%YE$&OU@>!rg>aLSI5Z!T`b`f*eB2APghiOBhM0PaPr%v4nWSAi{%$r39h5&`Ihf zdngqco1Ro)T3DT#8q+r^N;9z33osb$z zn-In`@wq}+UXMC6S=vX)2DwNkO1lVibZBCuoe0l|!?(?n0^WoWCLO#z0#1-*v zA!%Hsb(6uJh-hO(anhZn(RH8{NlZfn5tHE?|coZkZX zwbWr9by-iHKBR7F@EMz_YZ-OkM%{NngI&<#6KL`owAl-d4nV6fpxGg4_YE}s4q6_D zrawX3qtMt3tt+7U321-Xlzmh|_1QTV-r+$ zOn`PgGEkdycc8ZUp+K$d)j)0G_kmhOBdeC1Y}Ly0t=jRAtlGu%R;{vIkY*42Wo^|Xk|^|Z~0>S>lfVcPNc!?ZbV>uZ~zudkIgZ=fxFtbrEMMAvd3(|NaP z$Dg-p7u$wwmFvSbOL9Xk_}hkB#Pmj*QLnL<|59V^_?=C(Ild;EQPNa%biYnp`15sI z1g343cSdNAD-qi9_nK=LXSC3AySCKwFSOKxOCz-i_x0N5j8>YZU6gj*(psDIO>1rQ z`Wv(|I^x2dXf5LYHd^k0o3ygtH*3dlkI^o6jMXaJ-a`7eT5zX!T15BunvvK+%OBWL zJN`f?ZBBk?&3NWk&9S))<#*L08r;T(6}M}SDc!Z>tKzhaKir|^w(6xyWXl0jEwd3>qY8M0hX_dwO zHA}03TJXDrw1|6#XvT?jEr01y?f4zTssFv2v2vv57(5#KXKE3L#%Pt#jnf=cAJC5X znxI{5F-gn4G+D{&HSlR@5WI!#b2Q+&DY6GyRMr9ha?lUciKEZvKTg=n^LgUBvNAEx zqLp#)`I=4vTIh2Dnxhr`@@AkGI>4%}sT-s@4h3oXTqYK~Ay^AN7@}F~*VQbU^|a8h z!?f6}23md>o91ZVP+N0LV=eUlrdrv)W}0Ji3oW$g_1c<*)>_&8Xw7o&W-a!$wp!?m z9ku-Lx@h?$x@)1a@mg#`FU|5&AFXUus^qQqPp3T+r zCoIxpUtX$(4u49sJhED|-1e3hI_4uSwpqEBKlp&=xbd*I=HU}s=$t>bvbuFGj-C;g z(1x*=HA~_wWgG6YSe_bgiS0Di5}N<8CI4TKS@OrfY6-1ZW{I8mrNy%4q^0b~Ist1A zw+aZ|78l@HIxwItby`4Z<>G)fue=iA7`!VWKiC%#yDc;@^j~cQEwkSRHdWT0zZVp$ zp9so-Ke|r-&-c~|UHN#OSnua`ET1+EF6-Yvcun52;Ls5VgB@p@hm<9b4hg+?O~{&F zzlS)k*hBLlT^t%~`!+OmcKf=P&-3b9+8wMLx~P4<*wYK@Xmwr0z-VWF>E z>X+>vTiNkI;~?#q}F*vwD#wycG~Nkx@jw( zPtY=MPt^k79;S8cJxMce%GDf?J*wS(;5BW2>z&%oyN+qTrlFPt!#Y}uPGng6-sH0M z8@ti+RD<)DRQGKG?6bW27d9ztiX{SzX=>Yv5&Rl%m!=Z@SZ_^dhZAd zy?a=l87(i@X>BS{NN4ieI}qm_PLIF?zhuy z`A_c%ci(nvqmA#p+xY(0eVfKU70|4aV{gRvo*%R*DcuygH26rXZw5u*;JL6M`g~Ho zn?G3jPV7$)NU!2}^x* z>y!Q7eqrR`xu=E?YyZTfqpo{0WZYNhKb%;w_4NnWMf@~t^9}drMBd1_o65M$7<=U= zi#9eaK=aKC)Sh@DNb5#_Za=NQ_T$fuwANc&YA4>0(X#*5UCVH$YO$B@*Vn0C*IV|Yo!wv3jG$Fk6&8dy|y|e7PjW;=4tS-%NwPtxt^jA+$jy?N9|BjP) z9_#k}zvJRZJBBB{{_LoG)}72qk0>6VIlg7i)T0Go%&Xjp{Ce4sa0! z5K{8=<+{I(PH$kmw76keo9)+?jO}{;Z~2XHs{He%j+UqI=%L?tL-KU51ZIt8ROY?8+*HqiiSaRJ56SXJK9nvPc zp0m{7b~T`tB`v7+SCOGzCUw%kcwtqum+lX_Irhr@o^#h79~L<)()H$Z?RULiJXdoa zi?GB!HXn(EK z6}RQTfAoRt0-r7`3#)7pH=*c;h?7h2&Y#`(nJzzu4qT2-b~|H1CAyXso$CJW^vN$7 zFMc7eQbMj#Oqg&r*I0Hr*9g9pYwSFiYaBe2Yjirvub1~D#DB~8&vT85yK{|_t+|Hw zVXm?9&0M2=Rjv{FM6OY~IM;Y9H`n;}!CYfzX0CDfz+7WWVy^Lhmt5n?8*+^oZMnv! zD>=r>Uvdo3!5rh0vK(XZYdJ=T$8wATxjDv;`*Vy1eRGUQZ_6=GwahUd56Ce}j?Xs^ zd@|n{_vU=#&VS7}va;qIzYUsiY`AT{@kP`5M$dEej5D9lGtRv;&q!V}�I*&-lhU z&u9@n&scMHuCegYT;tuh=Ng?JnQL4gJ=eG{Zm#jLKG%pp`jFxL@FC-c;)jgX`*`m5 zknw2nLq?~s<`|K$%rS;OG{^8I&oOp3n`2x&Hrtr{?rh_p{Mp8g)Y--_&1M_#{4~q> z^z~WB9kXT`7mZm)-H=(vlsz+zHjm9TIu4&{EN(s1=y@#LNO&dNSTQ-<=+!CPaGc39 z9$lMd^vKFGZtt39Ec|_j(e9lY#!b^^7&F_?Fq;1|-Dv#p>BgAR(~Y_jihH^o@6 zVY0D$(qtpDn#(EZU@F2 z%jS+ZQg0k@jQRKh{l=(K_Zv>@{YJ@4?=|+{aj)^@XTyyhqlX(Ae+)DFEf{9J zaosRu`pZL&mEDIL9d>3IHxJ1$79LGE`p!r_o%#|SM+HBK~0H5|n$Mo|3}qlf!$tCL zV^5aTh(6WFIPpLqBlgIh#@9pdG_(Ur##47C8LyQk8n<>&G&;V~+j!x|-iGJ#UdE}g zUdGNmhtd3x1mozq1S94v!#H}EVYJv_H+HwP8|R;nH&%wl8=L0#G=~4u!^lqWVbtAm zhY{K34&(J_uhJ^(9q7tZ<{+A#nGLNHy3p@2L0N>$nV?1xb>a(#`wnVjhkn-GbVo7 z*0{ZUTf_bMEyn#9VvXHHVvP^qi!p9(5@U3kakH^`?@h+R_BR=G9%*B|bS&B!-7DHy zv+_n`{)HQiANt>5?0K!Vky@vGX%apC<|MjKlzs8n&j9M*gIhM&Xtg zM)PJZjNX%*8`_o#qhHeq#Fjf~t& z4UM&TH8k>`3^$JZY=*bH%_v-`8y|hqz$m`4fpK+OeWUKCFk@}qFyqqTdd3eg)HO0s zh8hdvLXG6Y5aYGaf{izu1senJt7AO%YLHRzht<&ItwwxNprL;nU@T}HU_3v}VvK%) zX~(`w`%Cv;wKwoxwr`p7r+vqji}n@^FWAfU^Y#x{oVC|!^@siC)o1L_wEfNg>szPn zOS_%4FZtkCySHbB{mIQf`x=MW-el`B`wzX3+C#SeWMA6*h<)Cc!}gsCKiFq)`p&+% z$G7%6>%X=i>++So!<%2)e~3M3zxd+k_W6+q>{A}wXW!jmuYJXW&+PlJ?6%L(`o#Xk zFT3nFkJ@RE`C^Ct+2rl^M>cM?|JrGbeaDNX_K2pN?Z*~ww70+bk^Q&vAKGvIdcFO( zD}y~h5~;+O2F&aJke z8nwzk@8cKjE4n;yPk8!S`$N`e?1__}wm*O1N&C_}p0GE4euceL@MHELCp~J9-TyCp zz1x@C7d};Df2Pu7@0YpQ{=$w&>`P-^_Nc`R?P({A>^Gzp+E={&u>Gxu`S$OR<=EG} zG}pfM{@M19H)q>V9(~YmT{Xo%WAsFO&+8ws-}m(xyLb6$`<}EB_U845*>`UnVm~&2 zpnc+P{p|OiOto)beV6@T!~593ZkT9au`|K`+5C8W-mQ1o-#B)g{oW_L*gdJ8?7g)1 z_WAF`+Ix+;$-cD7jrJ)!TG_vu+0y>?O%e9V2bXHEc%+{F{Ussxf%YK# zqZJnW=}uST>pXHU{=p-s;=A18i|@PiNc^7T-^8zr{~|tc*=O;k$IIi-^eBsey5z(E zkG1yzt77NchG*zix`6bKAc%re_XH3DQHp>F2vVgt>3yRjD%cB0!GemtmxChg33gCX z#NNT)#V!c!Z)JJU993rYtH8^xK+$?&rRoqD@Su~9tz|%`gm~U-`I1WRgB^|>+5hv@f0|R zr;Bj@eDcmIQuUfsuGeuV>5>gjV-L)A>O1M{G-x=&$xN=zaor9_N6V6%jh*hZoAx|> z(zJcCN%NeM;mzIAi<;}K>YLvVu+2v<+-dHr{?a_=kT`GEa24L-B7L4x*Jz%$8;7@T zhZk>yR4{KaWfqUUoXLBwTE^38t>C@OTfz%7SNS;HGB-^??%-pRYuwV$W3^iSRe zhi2a3^HaRtE8BRjoDN>#%bPr}l@ECJj!${vPhayg7k}hEu>QfTxjV@7ZxLeq6~$PO zS(5D7V>0Xs33>KGh!VSY_i*-gpE}#&rNw&G=(0Yq4A^d46PBtlW4B+kV6W+pVdtgV zuzxn%va>`T*;RfF>rm^$hCXv+dn`TK-n_|dc8d=iF5%A}@twwIRR^={@6TY(^dne} z_-HnD&n#BwLjpT$Yzn(NJDm+|$Yhhg=djmo3)m%j#cXv0m(3}h!%kG6$2J}-XFH}< zunRvgV7r$uV((g1u^AT@v-NRH*=(WZ?4u1U*r#@@*g4l$vkj@$>>Tm6?Blw1>@E9R zHllMqTadJoH4v&}XRh1K8e45;OU~7^kzw1}%O7{J=PGuw9vXXCzXN;OF4z6+*Bb}e zWeJDaeSL>n@5M*iG_3|!e*ZDnifLr8w4Y#Khc&Zv-|*Pg1(?+lKgk-bKE-a*J;Scp zdzSrSd!D^^s+HCEzQ8`dd689$Y-j&`d6_+%(ZRa@xXM~^ud(w)Z?F@pZnCNJw^{z` zJ8ZAoJvLR5qnL)n?1SpF)MHQlx4R*V=w8yVC^=)WGS83tl|1M>=w0m zY~kwn>>jxu*1GZ|t0?lBbuanCUitc!-JSZKz4P=38$6?rHNE80x|2#3s!Yvov z)Is5=i)eh2gz>i|5gec|iUaP5;;+lZu${X&*6J6>TMkL!^Kp`Rv4#}x zxgv!>&y&WhY-RA(*D`qT23c(AHw@be$>Enrp%S0{-Ki0zR0lh+~YE@ctW0 zctyD~mbF&FI^8O`b?I;{;iQTmyi~=WYt*o(i#oplRvnA19f4b1HL%<}4ct?$iDR6# zaKbAsJh(y|8#(CU``tR&V398F8?A>UZt7wGVtssF&j3F;XMnlMhIogZ5e_?Igf|2k z^y@X9+D_;ju%E>Iec zj~*C}vnE^NW6!NHcg`4mQDZD#_vcvr+Q%C6URYzrG8_C-bsRI@%RSHo4*e_X(Kon1DBiy5Vn6-0-QCiCFaOMBH5Lj$aCU z;6;@lc!RtrHmdf-x*C)4(oK_ax`7uyx!ns_jGT;{_e{ny7E^HH{wY{!v^VbC?~S7^ zeX#vLA6#ngi>-J0;%UZy`1uw;{8W1?_N$qSO;!AH>N0<6qF*9lL4;^mw;Qd_*INd%GSFK3IBCith9h8J6tCR5RH%Yk2 zIT<&vPR1cGld-R33a(p{f+s&p!M;|hcwbp6p4E|xb9B=1qtrCKxhV}dNu*=TY3cY! zT{_lyn~v9v&%p6z8F+bH29{Htjh~0i#!8!K<3C=^#7SW+ER%(g zmu2DAr?T)F;cPs~EgS2XXJfz9*|?L=!8=h7?kvv1evLU;?`sa8XqAh3Nx67oeJ&v=iv|Kd3btL9#;66hqa9JabajaHd~sH%}?gzlF#{A&!_+o4=TW66$SXy zp9T2t(*mrhRETSw3vpIzA>OdA5D!0Fh#!3@#6Q%FaMXk%JR+qC>#r`tg-u0R_i+(c zl_MmXHOuE9Mn3c1KdCy#T{jICT`TE#^s8C(?V&qa6)7X=UFBBPh3$QYNRuvMj~HMSHb zT9+ahehKnzEkV^wOOUdE3A(5V*Qy=G=tWgA@^&jmA9{;W``#k-Dy#@ikSanCjuxVZ zutIc|E<~2~1?cjG0(7`5AKfp^M^hB@k;slbBx0WjdFG<0fw}11!yNQ&Ru0N}osHa5 zveB$JS?F$j7TVgKiB1J)BK!8)ND|FPHv2PB(})aISDucZzDYxseragc;Z#H`rlK2Z zDM+C$86DG2Mr}DsXi{q;vR6w)wX+gX`oVZ~;zt}RX5!HCIkQmusaRA`#iCHB7_=fM z8co?7g_d?jq7cPMwBIEHtw@`Rgx7^5iIZWd?)eOKMREpOYZi)rdWN8Z*kH7&bUJ#r zCJ1%xo`zz0foOAk09t&{ADO(EigJ4VP{DU!WYh11_6&NXM}t$)_5R6d@eeN~^=T6F zf8~j0J@h~xSKZOilM_+-K{xbl{RE`Dz!f>9yC9os&Pd4~q1z)Ew6M&k8Du!erwcQG#1VE7=zRmtk9|3mWaF20tH2nLY{`^DD>$_ zw0w&xdNb1m%~m%?MxBO8a*+WtVDwSWM_nYcRR?wYYon)>7UJyFK;6?vplg&mQs1eH zj(QJAyFV(UfmKTAu#F>H*_;U)7<=^2x!^q5&7 z|A;Y^zRv^;-(k#pZ!q<5JDK(eSC|9f1Lxn^#^9~zn8B*kj9O+3GdzgLPRY^KREjcNNcp7FMbVnVirGJNGgX6k%zCg!s{;~wG6 z$hO%t7p$zA<<+B@%swM#ZkP_!*{sIoYA7Z?1KX67icXQ$ru5)}8 z&vPVBG;)qd?B$dTZ{n=nwt^$>Ud~axkjg0(4dAR`>^Su~TAcpfLYxb{D^5WMHBM2( zCOMtm(d5V}3_2m{{;^5%K}@q><&I_-!w1bz!X}4{{%Z(i)GK-on(#t&#*HR&$Cgb7g(zm?QHYr z4wgE2js4hklU;E34twI#eRj@O7%N_T%SkL zu*E0^ymzr8Uj9Z2-|$qyx%I>G>_JuB5~Pl!_l>|)g*0*HG%YN-LmOZGrh_lJ>0!wg z`ndR>0X8%=!UIXhSm>Y$w)$*}%WceXUzRyuc4!nv?<}ym$!Pp!rWNj3JqBNB9g8pb zS>wBA4MK)a>exH z30U>38x|IG$7hs1aFCuSZZMyOyRE(Ob^FP931`enSpb(!m!KtFudh*I9|PV zCRWak!20fy_=HjvzVk2&b9Y4JU8ylRa14x1KE-0=L$mOt)HwXiI3E9a5Rc1NCg38s zMEvq|B0gQ0gk>ftAAl^6{$G z`M9Y!ADf01;5$tPxLvIf3uP7Jf(wOsv`!H=oLz*2TZ(X-Ofk+4D#j5Tit*g;V%()) zg7czEu*ZfH?0d5WFO@09BF?4wU`8okxv>=QYAeNGKbGPgRW2Usz{T>RTx_1l#rZ3^ z_{UBz-p%9UWmmX(+e0pX2mNu}7cN%#3G2`YzlQ$z*$*z-{+x>}+PJ8=j*Hf$a8ZE; z7ma#SiViI)MbZ|f2%RiJ{$3@>v$YtRIu@hvTZ#~mUx>=4!u{K|1xWjPK9Us8M@r^- z$lW~`?G4I7K4IC&ZaUmw^~gj@7PFD2LEGklx zM)uAUXdq4$y;vZGEZq6bjM=@+A1gjHhCALd6A!;&oQ`xeQ+D5j`&T!ZwxTNx8`Q=; zGCj>?d}?Nn9cf^GrW|DEXzylLwr*vzk~c6Z;(st_*Dq(zn^!W8N9Qr;(+e5B zERq>HA%Gdsb!T+H*)hha&6)az+Kh#V0yCX2%%sJ<pcrD_Eiq-Q{n^>NH!X2KE z^cUWfsp9PDwaV=GTYBs^`O)ll7biA0X%g#Q8N{~N#jt++GT4a+N?6%|`RvBlDpuBR zC9Al3EgL7iiN!Owv9}NJVH5d>SaY}I?Cmm^HT&}nd#~#PyG{5iJ5lQvn`7~S{b>D! z&9!>Pw&;Igmq>kOYhU!S*TN`l=PZoxX^G+5uM#-)yfps4au^N_R=|F$%DDZ?aJ+Yp zI_?;yiAP-3#;Iv~c#nu7KDNpjXKRea=WEUJDrHODG~Wsve;A98`HjQVcH817Kkc#C zL?@h9!C+hLjH^Dtb)4!%oHO17-<>iECx=eP@)6$nNT@Gnyr<%t@d5bA@M$>nT@XHd zA{ehJ4aFUHVL19#IJR3Jft@X)aC}QNUOy=oUv8a+-*Dpblbs28hh!2qiA=_UdsDE^ z`&3+Ll#YY_Gw`15**Jc2Cg!fo!Y^vG@tRdRxU?)6S4ZbT8<>wrixuFF=L@iEX(3)c zvIxswfU$l=F~0Gt7^@|gVCF#yc6Kktn)Rjl(zjCV&2aJhLN0FD!^P{aa`A+>TznKb zydC(v`Uw}Uui>IghFoMfw-gN=EK3`Y}hh9F@k2$`4pqgfk#(9CKtbSc>#C26~& z-u)cptZk2EQ*F@L^`p^(y=LgmMk9o>by2E?28z0N|qKymWv0O2iHF_ zA3r^3xG(QA+mBsl7Dk_9eBS)Ym<8@)rfyo#3|wBuq&}O=Ty9HdqBl)tto&@5Yh9Ym z$7w=Lbix%*F;&Ac{OQTjsBd!moEOv-%lX*c)Dpvs58uI4=H2HB|CC^}xCX4v3l3Xv z5zHFRjkdGP3(>0y{xrNBRit#EIZ@;Rkr>81J>`uEB5@kuk7+ha3v}b z!-je?c*#Kp9A~VGPt4K8YftK7m1oA->y0@Mx@LuEtRIKxO?1Em?F{a>nSh%MJa9?v zWL&<^7wcpN;LRq}aZE!fKBqksTSZ1;xx!d{J2@VUk4wTjH&XDf$?4d3?Q9%X5U$~ha7bS`Uw)ul$k3q>^e|EYuT=@{@|RREvVk>F=43BIa&;D2gQ3Bg-RBPe5PEG0%M zQreUmH6Gqi8cyj`mXrg$%_Ik&tR~={Dh?j5I^eZx3!bm4;LSQ(;Gqi6S%RPjWqVSQ zP^vDJ=tm`h9Hx{r6-;G-Oqw9i6e<>^G^CuUKq>`f8%4QMVN^Cqrw)=$qM|@1J&PJYmDZTU7`oA4_>r(IBxtNb3)uwNQi_ zxKg21Ce%k8>f%GiK@E-J<&z*P4eDh{xl=Q#T&S4_)M_&L#Y#hM9KnA!8ER+_ezr5f z7gikVY74%#@lbyg@WGu9ezM@>0N%F|0uR~W_5QuIg1RrKTAP~$qP1N7iWl~D(& zE~vi^)O|H|25RjFHLjMiJQ4CrkI_{S=MzGhRK!4p;wG&l!5YP&&q<3Mj~ zz-v|o^pykNw>LnC)4+@OPw<451YIYBr*0eQe-e27?gFpbk)ZQM;C=fFw9NrcZvYQl zEzo`mc z-cH>F{RdGMR0H)KEad=Js-Z4`?YyW$YBzNkEEY;tQYWa_U?~Qyw2`_Dw)3G%sr}SL zu-Hs$DZB{x9&Ba}_F4tLz)E1JEbuA52DS?T-{d3U-zyFliwFPX^I$0tu+k3j1vUZ8 zEdZb57hq*auy8H-4Qqhai@^W*9$0$@_%SzuFR&cgI30YIuYlcs!RPq^_zjN+TQ39u z;}2luNU*IgT}JDIO}i*(x{h`RD^qkN-9k%%{aPtg_*8)@SnVZzjB+RK33imA6X;f2 z9`MjXS<%aBD?msO1_HstqEAVPdU-+X(vEeKNUtd(_w%qO>jZGPt$;^li;;H zht>lub%RgaW^h~EOwn`{eUg?0+_ZrY^CEgApyd^KBk!Uo0e&RuM7oVu032QgkLDHh z7(nJn@J&8MPX#5 zZ=qcQ)k1VMeTtR>yk4Np=t|lQQ2LtkqIc6?fLkd#iM~K90{%OxvGhuMEHL5|; zix?e8pQDEX6E0Jh^itXq@c*9jq4(21z=&aV8hx1_4$Qhqji;;W@xZljR1n=j2LZ!| z)4B9bS{u0YkYebKGy`lJq-N4AJrg*jO_$OSX<=Z|Y4Av&M;iclo`7%pR(b-kNtlkI zPt(%ClZ)V=UPYS&JKlh&`5t;Q@I{(VrZ3V;z`JYUt-gx31}1(6zw;w>0Ps(V&Z4i; z8o;c3;JaQ+I|A2!f){!dJp&k~K^M{YXmQ}@dGLT=K$`$7Uw|+B4%!2FDo)44hg{`= zfmgsEei=O)c=rK3+Yivbz(hGZoxVb=0;6w%cl;l;EpYrh__-gWrvtN9={))ttpl8W z1itc{Xap?ggV#HzBY?X)G?#uvQ-XIZsj?XGo549j%~h|sNNV=Y=7M%EdU08oH+nl4 zIm`^=9mwJ$rBCyDz2msZ>_8n)@m(php4G$~SX+ujly35x?MqSCu^!&ED>PEqz^ zNC|5CpvW5CDMn#dx@^36G5VTl!LDt9F;%St%PJS4Q)fNc$MJ=z{dpiOd9VP@9gJd~ z-sK~2nRK>XCm*esD`sE2=b`uW%Gtb_T*UNMvg32${$bJz)~YxgO}YLDJ3BuM720lO zg_APTu~qf#7r)u4`Q>ib*CGSCj6cNc@zW4pe2mRKmx_)y^4OX4Qjp4r)9j0J$>^cR z1y=iEB5Fe&tYUEjS{Ztiy)GAzJ}2L2v)9c+yR#m%w0bO>J^LlQWN9=KpY@(K?TbVv zK3~}9Ga}IPQGM*KBjE@dK`bW}hBTfE;X3zFly^!LZ=4g1zST%zts_AwFI5_kxfh7; z+7H7Ydi^220#1>eiY{O!%+v5iY6Zjb4{dMMZmy1P)F-10w>0oVsY&Q#u{MTzTalrL z9=_V?hTIPu;P1QO{-LWeUX|~Ro?I}+JcdC=Q{Wy%zax5b)&lDvwnwy`6VTmx2NNiUFHpupI+7#9&JXY>L6Q4A>Zh ztr@U62HP`$0Ss7R023In!2m|!`lp@&%wWI{0~o@9B?d5s0b2}U3pP18NfUS>@&at3|wG<6BxL`07o!z zg#(7epsSH$+E7S43w- zcSMIomqe#Tw?xN8*F@(;_rwOo7Q`mRHpE86R>Wq+cEpCnmc*vSw#3H7*2Lz-_5=e2 z3j`Ac8w4W+D+DtHI|M@nO9WE{TLfbSYXoxydjx|7iv*Jdn*^f-s|2$Iy9C1o%LLN| z+XUkT>jd)z`-B683xpGd8-yc-D}*zIJA^}oON3K|TZChTYlL%zdxV38i-ePen}nl; ztAw+JyOfpewxMkSw+Y9G(hImx+JK?_1Z@LpBZkTov>l`k8Ip%HB%h$IA#Ki({DQWK zv`Itt6SP&N%^Iq|pe-Y9+K_&jA$lQw+_AA+`?wE08$5%dM5PZ+|Npsyf(#t{AleF^DP zhVUuqYe=6ngkLm-XF=aY`luni3;Hh7hYj&T(6^C3Zip{}zK`^QLwpkSjiiqp;+vrF zBz@=*9|e6Y>0^iZD(HJjA3VfoLElXJXu@4MN6>eZK76P>5cKV&j~{9;1bsgl0}Qn% zg0TS^BMh}Sg0TY`LkzV?XsCS>j5VOng0TnaKrj{|W0IlvO)yp=W0s-zPcW7N4hzOM zpku*Uhm3iK+E2k)h>VGb+E>9?2{Q5xVC+W5a6|opU~EUmctib#VC+Z6fJ6O>U~C8&6^s?hm~p885sW2)!-BCTU|cZP zBxBB@{!1_xC1cW|{!K7e1&a!=!w|VImLVFp-ap4~V>k!$f|< zVNxH$VNyTBVNzehVN!p>VWJPhVWJVWL06VWLmMVWMBcVWMxsVWNM+VPX%$ zVPYS`VPY@BVPZeRVPa3hVPapxVPbE>VPb#6VS)$3VS*3BVS*RJVS*pRVS*>ZVS+Eh zVS+cpVS+z0{v&uK947cA942@r947cB942@s947cC942@t947cD9434q947oA9434r z947oB9434s947oC9434t947oD9434u947oE9434v947n~M6yoykz*tcNlVTl=aM`~ zUL;SFHz|XZMam>)6B&psL?$8|k&(zsWG1qcI*_`MI+41OI+D7QI+MB+9S~g*oeofF*?8xUI%n-JR&8xdO(n-SX)8xmU*n-bd+8xva- zn-kj;3=k|3Ob~1kj1a64%nHyJ_q8U3>Q* zI%1$X#>FQjCOI>|w0z-`6>HXQ+P3E)fUD(v`?cHmyPv)M@b#yPo`Y{xM#-Yp8@BIn z;GJ%}a_7mL&p#CmP*74))!J=`n$BLn`SAI>K6M@2$ukmj$|_gZY~H#5Xd~O&aqHo; zH$7kZ@`f%UX=Ted?Q1-9<<8^RpZcUndc~Lhu@_(M{>Ya!_f4zZdg98HZ!#txF-6Pk z8_wN)`f)&V)YREacedPo!xtYD%B{oqzl&K%RP4U^T72~MqT1uv--+2oE!yAFBWj=Y zN6QOQ$MlUCK8xDMuWITNb(+2T@(&T0!UJ6*6SxiVHqw6%FoD+J!tYcg;g0f1xG(Gv zcZKTV9_hp12mZ1Am0~0uC%=05^}u~K4cY|mE&l!YD@73;CqF4#iXKBV@V!Vs`uCCF z%U>ya;2tFTG4PvCN5CDm6#Dm(-^*Vq#=vp%i-2Dy+;=U7`(pnP@IS6dz+HRtlNbC{ z;QqQA+$YzEyZZk*Bxx?O^Ka62kVw4mF!$Yb$3-!R9fi$AoviNLI~`^6oHVy?bh`TK ztkYn{N2l67F!Aj^Gfw#_cTT|bSdPM?xts-?R&g#K-p0Ag9_KjVOPs(1-5ll0@0?*q z;>?{dicG{99VX$HIaB$>j1@tMxIG6=f0_&LH07Z`I`h$!Jq0K$ zvk;k>6rmRviqM9c#c14b?vMVhy`Xf8Z2eejlx8a{JTCHOwH{)G4J2H+h#c$T^i;!B7F5Qpw9{=4Br z{U%RDc4JKSwUiZMj)GqyEjBdJ$HT?J+QLM4gfdK9KtgU>e0Y%GWOosQ2swJ~ipuh$ob<%#upmFL2^`xo=7!4jmfF=z=W`3PQsN>*1HC<rgm%viaEIeLJ^qT(^2o0uk%K1R9Am~WU*sBiYjEYnQW@)6}DRw!(iIVg2V zTJ4Bc<@g2T%g0sN&9^PLE$3vqM|uTM4xa86;yPnOtYga9eA7asD082&0X~6KgC_@h zP4@_$6z&!7m1>%4n4_Pgzf56;;!340GTWpMi}S=-i9?dAhsS53IM?WjF$Ta*c&bi#JEPYVo~;Tk+?x@XwrXwO84_btPohhmn;&F((A#QN&-nMaRvqM!KS@zt5IrXVZ(ShTQ6xyn$}6d;s*TXl)Y8_`)z#D2Hvm64 zBbZVIko;@jr+ad3XjeqcZIT>9msP|W=i{Z;Sv3W5amPz*VCI$o9{Rq%zUVR5%-BFr zM@v&bxlpNU{eAiO$t|~(D`ybbGV1AMR79`|# z|JxzK{?g)-;yDGSs^wfRx0G8re{RLB+`JW~LB;t+dAs)|r>5rT%FNEn$%}EEo{rKp z{49k+r-#q*kN%x$p9aT7^s8C02tDZJBG%9UImwRxt~68YJ0%k%CL-}J&hoRckgTwf z(rM}(%xH#u*ok9?70p?+cGK(!Y_ zvSzY6D*bkre7=G2XQf`3;P0Q5MW&8V!oni!syJFjv{Wp#CJb#2}DI=Ok3m9@3|_Q_lQ%IRbG zwew8}>enqTFUm}e4EFPMwjVpnSWin$Szbm`RERpiZFzBOWS|Gf+DunfPJ;5VGuKv; z5u=X8{5ro6T2wKJz;Y^VPz<&nz8tN&QD?vJh66Z{>+JYz$`{&|e7!QgJ5*b2cA z?`^nTq+sP#fV#&6vbJTCzUvlPc9u>ux8DaVZ6zL74s&5;d)g#>CZUth|5@Z>>lV9* z|My(~xy2tGct4B)oz| zJ1;)CyK_g)!UXsFZ+jM1EvmhHuj=~Y)pJrJr}_JOa~$pMtjAbcn2j_wHq_SvD@qAN z1;2iI`>OlSMfTu<&1)8xWX8>y>fvN#ZlDRX)XGSUQZfck0V(Ahj$VE$r)%pytK^RZ zZQV*{t|6I=wj96uTtGy{(T%jG7plxnR@L_HNnX_{+{3e% zZEv|ZLZ6u&mAhicsXOX=cJ4D~FWYwJk&3>xXH?FLJ!c*&YmJ={nzMZ8*$2aQtXv~< zRzewSde+|A6&sJXcByE(Pfsddv-{MY5qjgC19H~xyVR|r?-G$Rr*?m5xAF+jnA!7c z4z}LYH|O|-XVxBSf2OK6KB~BK>yfL^w2kdTa_4M3-19pZ&3j9Z35t1k`P65u5x4ofnZ+F!$g)pZ9C@7rI0X#bgpb1e;SjH{Dp z&a}|ng?}uqTUz_ql)u)23+qK{;6I=LBu*|&uyP|n&GRi;tDd5VZo-l+@HV$?gq5$0 zJj@-d$f0?zV_lO^0g7ci>l zM9?t7%7?=k2Y4tIlBU%C|b9pY6)K3Sep>J zCt*9x*IO>gNnW1vOZ7=^tcsu2aeYbEzI8?ML)S;(2_p!)ZVQU?^5Q2(yT#|{=EiwM zS1jCcykT8cMaRw`lX=Sul6A)bTPX#h&No#>jf)a1q8B7I#2(vI5$o>e?&_*P&v|>C zn<2t-|7%EDY%M?+CcnBxC@^Za_-nT8$PxBgLCoR$#kGsS(Py@kG- ziZtoiDREWf@e`-TX3tx-N7_ydh|b_H-LR+W;{CUBKpKuuSW@Z2wL2Qy zyL+Tm496nhh_uor8}{+qAG}jgHnMi~2}v%hsIEWW-qj-|r)xc7YGlTor5pG0F5Q1C zp<-n1;u}4?w6b>Rk(R4>W#sg2kvuJtzu7IVq&>?0yX(Y-yRT)Gv@GpC zf@AZ`S8r=LfBTh!s)41QcUV$U1;~5p;k#i97UR(5kmRiLKlU_Ve$XQ+uVrfI5gebl zsAdnZ{oy-#B||IwDbo{k%d2-ZUby>KMnP-5$JCh#r3=^8H?%!?C#N}@@r}xwv$S^S z(Ni6d-b)PAwqSf_rgN8VI?!_E(FX`)`IR8Cr0r%t$Gytl10s zzn4+ev2dC)Be|%uW>3?l2XAE+bj-)O2gGO2TLbmK|4w1JftiC(cv?wS?e6BwT|E+V z`eP>q#AMA|3HG?!^+8sCr0b-hi1e~W)mx8U?*6EtZe)WdhsEWUFRwd*ufI^z8RHTV zn=^ma=KW2rH=cY_)Uk03j?XErT(k8MkxyQ0G-pa^QXV8Y2>JEMsThpqObUuh%bT<0 zz`48c+&^1tn?IR6Oed~PO>>l%)ZHjg#dqt!h`qH^l76y$o5;I*Eg`8#FsaUe2~zQ& zh6S}h)gsFr|G6?DH6rR{>8>zF>YZ@3GFjdgx+UIwZl4@k>Nog{-tDWGBFk7)d2#4M z1fi>?t}N17m%6d1Y??XMUK3|cwUjwid!|wCPH=&y8w+<~pI3+(NNM>UVv zKhJ+#_~lZ+jc|qZLZw*sI4v(-SCjg2ig5SD7+PRU@RVf0Gx9$L5g3&n98XaRt`yZD zKv99|Fq*F?BlusHGc|xgIn1wC4;8! zr$tZmbQ)u-tF9y`EB(*QhQToty#2#t&Pgk(=@?q@EnR)4&rIkTrlMx7#XB@1Z^7@~|7AIsYIUGq%pE~}IX*>(>b*JFT#V{} zxo!ZMTVgEa$O!G{=SL^zdFe@$ z!A$?x=NC36+N%i$a|7Ss+&oeqI7;bP*VNbZ=**^!iH34wf(~ln>x-)g7lzwvNdM~8 z2KqldIJGfnikafyv^s~nIG%bvN0s_|e3BH^cWcf_Q6gUuk*}w9j-8wkHSpz5{Y+yi zni}}}m{;zh0i(r%Z!a!xO0-iIBR$}o8%O3(8?8jd9{l{^)TSJFBN>4RKVEkLTdal) zq#f+*xzAgZJi$=@mwZ1zKWW=u7HX>{D=J9b|LygSW2;gpnGcsDeeUlthq^MBdOJs% z`r7CzMfKj8VE54LxlSI>eO6DS%m6)d!;UBv;y=cJ$D-BO&uvs1bNlADVd{8 za_)U~d3RaRSXB_4-}nB`iPb6YCW=Jx{?CtFK>|B%S)%5C(AUwGX;Vh4OOwrkAMfs+ z+FBOQ7%52*%@6i{eB6F$MY^xGwm`wZY~)o zx93X7D+*J6@2_q0H;@yh`d(bzSr$AFrr+#;f4gyYiifG92sQAz`#eZtuOllANO*Of z=wOtpln@Bp^XMELanO?|(*FGNqVvy{X_GD0Wr(H+e!PEhroJr9$v{yc-$3uDXB|X- zD~)0QXtY4cd0tC={VF38Dk5TLl!Q+y%7Qsg{~A8Bhs&pXjT}ZjI=NwSlD&!IUk}2% zj(u`ndpj9X{SFgHPe|YXw>|z|z7eTqE9&;Ox3_ok`Ca_35--PzQA-+rp90H$S<@y> z3Cmisue}SBkg&aCcHFGEYY zbqy`>+=buO)lgfJo0<@pl%6{e%AEHv0{_cqiS-CYxxd{gIG1QK{O@~iY{?FAG}l#w zgpzPOL0E|T(3I_{DgW2o3w_U;7X(>rE6GB$^y`L0@0%Nq>&xN;T*sN|jZjg5`6LH> z-(0TG^|sWImlFS#hCk5z;XYoUH_hHiRZh@U@dti>d-v$#k+sFqlWk44U?x$xg8P1d zOVR{0O+^_=(&SMRQZjaaMnCmhF=4I8r%IA~#FV%wsgF4@IUhCY}Ii<5xXQ58C zj)RVr&TZ{F?PzU%?fY8GwOqB{YgTJIXx`Sy)R59xKf-LpQFRCPW;G|Z231Sdy5aJ} zOI2Pf`zRk&l2=MoY*o-!$d*4RH(V}u*nZg`GR`vP(yj3Q4ll_{iF4vY;*40n=wXr9 z!urCYLM!PDAkKJx+TiwqhyBC*eSR+NJJmb*!{JBn_l9rZzS?~){?hVU;=nm#@E zBpIu9u`9nTxQppB?Hb-C)g{ygF6Dm@l48Olq7t;w z?;cf70;Y6@5x%UHsF>uie>N;bXUVJS|Ly#r5_~bfSie-C)F3Q>N`03Z5FZrpmHk_y zziq%bQQ(hH4+;$q3JnMe5A+N7i-`Ob?fWU#D<&!d^OOEAln*O{)O?yR1b>izPzX-= zod9MrB?;gkIm(AWAtAo-;NT#9XociLcEV415cY|P42TZ&i}j0%{*>tZ*(>=sk^Z^? z`2c9ZFI|v39D%Hc{{LD7QOIG6&nGn%2mqo94GQEE6ba=CBp|1X2<|dViipF_5E*fC z!Mzc2I4VU6i786S2=e~xKOVJnAW)?MA zTHLcO{2+gkaLxy@fDQah!gD{wd92}|7q03taa_kQ6OQ_{-*OvYRQSr5nfi_V7@^JI z*ADOG@1i&N9hFx4y5@O^;^&b%Vu8AUE%*2O>g4z{3UEgqW_+c-@n7>FL-X{SFAQ&j z#KL<9pTV!a1bpGo|5C;8lm4=NI$iXvF!hQ5mj96tGZVvGAnH^PzmdO&e~3R8-Y-ZO zx+yFn3X=~1m++i9cjhw~KpEcI5T&~LH~8=kL3n3FoQmN~@UQcy3XK-Ckvjhm#U%*I zwtnNAz?&YO{Js2q>Ns_F@X3IPsECR)jMDx+EI7|;bEe9u3cewDv{M6~Le_>8C(6Jc z@UG|U(pCIT{TlK`zwXuk`{|U~fg5dC_|EVaObkDYmLJ?onV9o}?(oIn{f;3133wl* ztiMI=w)Z>!eSRFZga4B6Nl)sRkTQZh!h+yTQ7J$nSGeJ;2=k$O!)Oeqr~YSvBUaSw71g@-CT=-FtQijJV6}A;M@GUgn|7NSp`}M%aQ-_UDhMM2lV0 zmI}YM+4AcUm~SXVWGouGw)5A;MZ3T0==0Ss`IDaVhCxFy;Q=e`S!#U*o^_H|B};Bh59I|CW!E?;PZ}Ui*I& zGa#?!LwPw5`>$d5Hfp{A>DuO+>DX zUc%L-A6TygfGOesYf1D(wttxYI!>;yNV?z0BU67J|9$>ikm9fT^i2ED=aXx+zvcth z83Qtby~~aPR$bvaN-#X{aRHn{j(vb9KNr9PNVm`hK7$6!4A^dkTnas?IvEes1z({f3-V8}E%IxJ$X~ai)g{}4gyguW7__lN+hVXSA}YAE zP0lCj#2`vQB$uS5of!s^47A|$2=J_xf~Tz%r3=v%A|V}VG~FQjL5zf$53vqnE5zU7 z|7G64^Ze`bd8mzDo{zQtwL5M0D_2-MT#8)m5cRXoVO^=DqNtVo#B5TIK){Z&b#$hzYCNLp>o=o9RZ|0b60OMa4%t%l(nZU&{%qPP{ z#^^#CV_1~U?6oZfyq7V1Ud?5CZ_j7uw=ZP;&Q~$E=aw?x+g30~I#)BsU4JlgpK6#C ziH(e=!DfcH$Ojxr~_jxjIio?v=;JVv&^g?a3Bh6yS= z&v=}>z^oZ|nfV!fl_}hIo%#6r7NhBQkGZqvAtUjso7us6#ssW-$;iBZ!yIt=z-ZQd zVupSG$}F7H%jj?KCwxR7_R^?1L>Lu_iK0)3#n8wI3DhSgg@PKS(Wod{R4grrl>U@Q zpTZT9gqSj#uulce4Nyf5Kh)6u^&`*?q=}YwYoXpbI!HuM4=rZ((biByr25qe-2~r~ zPlh9r=?OEm)_WA9A6cNxw9)9oPb<`0F&4d(vq3wm#~~37TbO&u4h3sEAkI2RG*5|x z%&HjZYn+ivrVFy|c13yKZs>HwMD#|}0}XOL(c4Fp&`KwmKX%O&^!klADqwukvL$}V z{LWOQr5Av*W(6YI?bFbk$3duHBN&aI8iKOshN89uGtjU*VQ9i&I11K@K$D#!QGZ|* zN=l4I^9y2-)BIRew|EvRT^0xO!+cE(641BeM6^CN2~~z9qpQv-$k!khiO^~2Xa{*Fg3eg6bEBVxzB9yna2sOzSqfNQRNa%Jk`eI#zW>uCTw|gb%h%wC9oKlM3 zz?{xoUzDP|nq0)4!bNj(xk#v%i#i&?_vIQFoqf(l7r$`PXz+Id{E;ZY;s5Qj!{{jU zhy6ZAa@!`R?_CwszIPV$W0x6YW7WwC{U}Q!57v3GkA-6_q+uZ~3+J$KF1w)e5Th}# znu#=+#GG+m!hy(xbr$xKV}eN5$v$$7q#@kCL#|hkH|vg zCGrp%h^(X@q+X=1q>iL+q+X<+q~0Wwb+V5fBWXxlat=9{$4-{S&)8W81OEFb^mJ?i?&&`D#_<=w~7^Ot%M zH#6QhC6M>cg^Xu+4bqvPEa>Nl2ff&MK)93m^+0F@9Fkz@3}aLXZ-=&j?G-&~zh4VODpV_PF#XK;Y&Dfl%Vvgo*WS-)K%)W)E7^Ajpj9TGSMs3X(rd3J^X%@qL z#2e(%g;Z74@=gnF(lSJWgCmjUiqWX+mJN!zZjX8vGU(cOSG32#1F6bQMz@=N(7w_B zC@E|kD_5djtw3KX!3;uWH_M^+SNkj zIHCx(78D`fPFNZgBinSCTm5J;n)$UDby=05xA7(DSWO8!+E#+ZzLp>btx}}sT8eyN z?z?OAV9t-aQuMB=6rH|aijKU2Iov5OTA<8DON_Z_f-M*AcIToefm|dP4ct%TqSylP zjhn|s(C8qwYM3`^ z?}x$X?gX?ytG{y5%x^HS-*+y$0x=K#@CG2R?&Ts$@NMQo`~ooqeDn4}r2Dxj5aL>h z_aJIR`{f65F2p|}zJMq>$VHA2!y%SJTn6zV#7>A$Abx?U0)BnQ5N#oPKnxy=iLfjj zidC?z{Y%^n>m>625--F0zs85K??1&4u>b#W9BP|?x6%L0k~;Z|DgXXo9d;34C&3u? z-w#v6*cRSiomzIy+!45XjXN8d$*?PhM_{qF3{R-;HLt<^I{1 zUg$CU(b@sSvAGQFQ5viyxoHTRGE8HGx?;; zmgvJR{1;a2XkQa{!LaHVrKwD`+Bk8g>Nz*c`ayP??mieuY1z`R6Emhm~n2)&2ovo^bwnE zTZ>gMy>hBJS>Dw4ayci^Q{1WM1&S%lrP_HxjX#(a5g{fhZYA?{u+%B(=Pk~rr4yVNy01d^rgN}I=xbaR80g$N zZbpmjz-Qh|6Jwsb&SS@qp{tzs?AGMHdw<$dG^x7z+mc=fqc$ZrDQhgR^X43f&9TwU z#!dyM?ACYYfy@=ASWX!Aead8QtMZu9X-8nJXpI-f7`rHL8|fU-q0urz@WVot>l3C)?(;yj%Z3cNj+#yQq>tY+^% zUx^ndY-K}Ej>cPGH8aj*zcK?~9hj|oovg(2C}fhnszpzy8FhW$!)(6!5`UfX@ubAw zL(ct&_zp=b13aUzt9c{i=JEPph4Kt49`KZVG0*(nQr_e}-OW4Ry0L|6-Mqb;E1AUI zS6K0jJdVMvRczaf5Zr(2BJX-cI-5SH9?PbzK(%ci&P^uEc&;iBkOJenJx@4nYs&)yr@aL)T(-*tWeybssjzhT|$x90g-o1<5}G1#5|^N&?M z%6hqPyW{Rx$CTWBQ4o^10Zmp&er{NOho zD*w18GCA_Ej3Z+Q-@ z$2kus-+o_s%KM$hR304lTk`P69j`tgd{yPm{STz{3$|B&Iy>jc>Ryjkc6sKB%FEtQ zN_nPl!I4)Ubfv@&E>DSiw<=}Xrfx^q{QFh+)4v?69G`_roDot0tUY`1FL;YvK=|e0TJOHzV?rQ}(}m_{FV3N3I+2 zTk`Bd7ghc{rAx{WOaDl|^zuVTPImeCk-_u#9J#bxr^>C1qmCZlaL>_`>q?KlTzBu$ zA>ZENcK2BS#@RK`A3ZfQ=14@@qLdx~3afl%Tv&>G(ZVCWdW}hb{oTtZ{443U^Pled z@ZoP>SeEkWi(el({g__$c!$gI8*;s?wpt&USh4ViBk>*oJo;+YLn-^-Y)TnYbjidu zGZv=Y6V*^E$sK8ua{ot7mxDh9|eU|K4?b^7sjz zD{pY!T{$K0SjvW}JC8ou``g329_am=Yw514QBSUOZ>zi3-Q%(4ZoQ}V{8KnJ;41*R zPn|RB!Dl>s&TwIKB=@; zLCZlaK&wHkLF+&>>JdK-x`m)Qp!q)m2YM#OW7L7xPxctG*w}GQ@ff+J(>+EBX!atH zQ4Ly~?J>?!zu03$VY9G$t;fg!t-ai16oOXd0Z086z=1|>@EA!r7|jOF1g!nLCEF}OKZ3mOfYbOYi6S_Ya!d85b32h9g9rMwCFE(rGy#1k|hG?(%=k5L2~wcTS> zfI4;{UZ5GE_@OE7Op(Wk2hF_)=>e?(Edh1hi}Zlj-wzzlATu6-UC^=zfdh@&19#Bu zM_~`t@i_7m8);=_$WPFurx8EU+~<)Wln)?3K`UN?J0?!~2N4cv)M5Astp|aQ)kKyWxaB4h8Ht7e*KhW$CkuK0$(0b}W1`eBfg`i2GCAEk*=_iN} zXvU|=571iBGSJx1knfbg^%xDHj_*B&yEpVd00&wKS`HfZ8_ESV=?~cN1N^^H4xkwx zxRc^+N9zl{-e~ZhnR?J{&{#{Okq=rH*=Ur3R)AK4R=XMvS2XMm03Njdyhfu4v~U>Q zL8C^%y&v?TIiOMTumhS6S_E1>veBpmJ(JjIME6Iy6B>;?(4@3RqZG7kWus98S`S)J z_bVEWr~!!2hDIY3wD#IYqk{5A_>X}Mngm*XBkX`iZH67tvMs<-e_NvwI}qXB4tLPp zZEy#TEkZb;WuRw3vx^b$LCBB$5pU442M|7J#bXHnJm8;z9<=O9qzAOH4Cw)_1+Ad| z8Q?)nUP8WLGq$V>?w}>FH5%2R)yH6eFw%J(@c}IZb%U0ifL+j9(0tJBzri2q8PGD& zjMp2D2GH0yfgb|=J8%ard=L2uTJd+pZz$_eqY)2UQrl=0fL45p^nvDnhV+3}gSz5i z=UdnTP5K`B0b2G0$_=yvw3hmRAUx2Lde|EVyFWG>8KBueA%38R|3rE~%RuWvGftx% zh9ex%B+%Gj8jV8Gs9zC2sN*-_=nfh?0{A~*2lNbRDQLFdWHf-5S(^-ZJnRSKdD zw8=OFS|0&90scES8D*elouCKJ=-gzuMk2mA7s~<79^7P)J^Nog{o#=zc0*a6K?2M)9v zv zjO!2|P{*z&qZG9IktU-C^voW_V;tz?um_s-M3a#ZS`AtRn*U6bku)Ch0L=zX+Sg0HsS+Xh_kSG?EW}# zewG7T`vKwsTKyr)3AE%RyAv`y|jL z!^j4W9cLJYltC*%Ye8$NKi@DMlM&wuhLHoBk!%<>p!uK;pk<)0G}xa4chEA>e9)+= zhEW7s3t9)7kq+DxxMx5QS~3m(NoN^`dn(c~5C4e{v=Foiv<$Qyv;wr6biQFkr6WH< z<3VddGe8|#$S2S!&;rm{&=Sxj&~oat@$OCrWKcI~HfRoL#$u!sv>ucP;Abv?9yA}X zxz~U?t^)M)}{LbVg08o1AQfSKfU-DR2NjJnf0 z#TmWBHpv;g-3~ungHoMIn}ai*1-f;!E!3Hm>Woiy#!hlZ0}DTsoQ}y1@)SPb;ZwKo zoUtvanLS`z*_-1m(k&;PCHfL)sXobBrl&j0K`Zd7(l^p^KO8gQxCAtfigcxz4>}2o zl>s9&HO$)I0>l(}y;LEQENN>FC~YkOU7-S=(js6)oe%S8Kk~Ws#dF3_RJ5Nz)15h% z2N9vEt#T(#76{9qZ^F7?I%lkSC`-tC7!7v*DlC18%o z8iD4eZGpXl{pXA`;M=yB#`3m&)+!a$d)(oJ2@$%IhpS?8J!*Yw)pnp9S30(pcYhkD4;5p-J#PdJcvxdV~ z%L<(uwh+p+=CxckESA?P*snNr&bSf0`NV>*0N;;z^-%ADz8-qw%!lRF8TnKP z{T0p2$=Cn*mwTyh`4Ig?8k*}W&{Q;E>u_JqYFQE3r*2?5d~(jf&@0Mgvt@&bD@E43 zop6tad%d?FqwBrX8o1tNTCNFL>qKeF^860=sy;<}SSX_WQJ#L~Z~58RL#F}K8U3Vd zgva<7@`v^GPWHb$82)w}`q-`Pe>VrQ%3I!-wKUbQ{m6hP!0Qs&sTk!kx~X(1JIF_6 z2fY%;hc82&vHk{TnDuZs{FfwRZN&UCKF?OeW3{0g}xn1HdH`<#C_js99wSoqFFTme+pWlpt<2}m_H<_P5t%(`I&xUU>*9FmAODhG z%ecs6d`tx#mH#xa|4fXnkG1gbS1&w_FZ|=>E=@~kJDS3FG)uIjue{B076W8>acC&j z%RI(x)h=3vm*tGN&O+U1aeCvMBjU^UwifIl81L$3=J;rU+U&44_bKHzL-G7IB z0o=FK{bIW3H*@bCivAz&%jv#Sq`R4WBHZ0;u*X4n)L9s~(F8DFS#U3h`!c$#CkAva z^k<-7O&#L3)iT2wwb{D*xYLCmn}sCHcPH&%>@l_qjr^kjeb84xkENw*uc&03t<#** ztHkh;3L8t{^Z{@+z`dyY9aT?7{;PHsZ~3}KHBAq*Y;U2O8aAVaCN+%Zn}`}6e~HKV znKc{9SM$?!?|jlXKBPNqbn8Q*0efgMax=fSz)lVJ24{meAEtLV^p2}N#y%=V|0L2o z-5G6p$V@PCCx9yg?lf_WSR9tzP!!1AFmJJl{_!+$+1N{LAP(_X<1zXRjGG6&?R^Sh zqMh{$NBg+eV_-?`ed53+LhpwDIrdwv`ppdVo4HoAr<)1LD&VWI7rCOX@zgh;Pj_Zo z-IhSJc@+cZ*M8Wm+vwrTwBCpMQ_x4<=rJa-+||SIzk@z=lgIeHdA~K;+fQzeV=U9uGpK*Zf2R?d>$5`tf7crmnj$8A9e_0H4EXYKrANZWxJw}R(uYbAEMVH+R z@ne6DpfMkl6H12D%ZdICd%42TY|yQT1Fs9k1fS{iz+TCH9^+li z16qea7vcBzP8b+|TqMSWhtzz**Y17u!YR$x7uk9{^_ccH!d~vf9)s&SzkbAL&)1KL z^+icL25IjU?A1QvF&_TU?Q8~Co7TmF*DI6Q{?qX3<-#7qqaNce@c$uxGn|>0vOvjY zyjHQJ6`vbmw%S6lmDp0)Q;MD^=WqUn_xTPcN zU-Nmf^>wk%@%Gbk9WY;e(PPxWulX=OY0$^NIc*TVR0hn=$h9^(&h`|)qrQ&Au9Y1ZBjGd>j_V-CY@)qYTaEq|EZhV1`= zFTvT#wT!&Li}7SOW{DTb-X9~VZ2ofp2kXCj;D;&uo3YmsZP^j(bWL%})uP-dN&~Lp zRgYYE!tQ1ZhLrVy!JOG~vVUF+T*e`sY0;i~IDTz`-ija_Dbwq5mBE*h-Hv!%xqA{vG-p=pW~lqgB3fU9l~Q8OMge`Wu7! zeBDWpF;JDS>hDp$YX8Vr-_lUuz6&_o%W1o?w*mI5UiTQi|2unM1hkjVRx0OvCt$Cr z+9TKBBL6K}=6sLo{SNLmaK9@Yf|*{wb&2(VLYmc+&dAhwoQXvT?Dv^JPSGzj3e2B0 z;G=P7_DJ)72bG}J{@Q%@J8J@uhhk+ydplt-4`*(d*&z7(SzkZzn=ee~_!=F!9}_u5 zd*8uc(H9=$S8x0<_x4{;PxkiPbDUKc>-~Z4iF!Bz_7ZUh>aOz`o0UEPb?p?ck41a8 zu17LsG0E`mEKNs#Au8Gi_%Hg#V_+KYeK;@Q4t*i?V!kEH(YG%U2lst&FN6CgjOX5R z^p5*1m!Cwv<;D!d`5gE&|7so%^W%5u8=!Zo`lsf{zI7ue1zg!TTgFWZo7-FgLwFdk zw617>4LF-dyJ{UTj^odYev9#9_#1$4z}e=b|G9kASzqP^E)TK)#PCnRUS@Ekaldyy zG|g{5#QCV(ZdP!Se&DOZafZkAW8J6Pvv1t>jpK7MA6?90_c;3Plh}DXh4OqGE4Ozr zS9%wXjP}yH;me7$Hjw{p&+%+P;cZxG_nwa{ses_*Sf9Gm6Mksr&>c=c>c3C4(D$Qz$XdjGE z7W~(A#91cx7yR0l+j?>Rs2F6uoa zK>P>57xim2R`xaV7)Sm4yYr*W>LBvl)*bP6$icM9Tv)`+YX2QPF4?mWj7knfS3>SXD#$4(0@-Q z`t?@z%5q%h5Ztg35&gF)fB4H>+-RhG+qeI`h~*ICou@PW4}j0RsL{Bc?OQ!-K~F

@{M;Oe4(;89HMUZPJxcuRUB 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 BYNL65 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 z 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

4*pZgxf$fOnsa!e88-G%x>PXf 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ξ2YmqM} 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 kO-mRIrVM6)-zX|2dQ?P58Y~H*D?hbbO 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�q_{H_LaZ9r&L@*% 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�ek6=I>~QsQyBrJgtjh!Y7gj7N54S&p5klBrc3l`tT4_n& z`S$3}SPUj8+(V=7*`4-m61~dlb|4%{h;hYYqdod7;flloF}R+^_MI|@b^J+sYTb`T zAt%e$R^IeFzk#K7`{8TuMKx6!SPV72{bpi;mhD;y75eqIKva7_f)95D_%7yQR7P^mp zhrjbBm*b(8AMWwng%MQuHwZ6{)ruPO;cq8`{>V{r`4RER z-4s>EA#hbROLP?t8*h-CZw{eRYBPai2&L|_O0aJ%_;w#%p4ul)`=ZCNif9=!e6WRB z=WQRs@PmpoSwz@Xl(~p5VX&!P{2MGCBWLP;Exae_kYnO^zBaq&d9mCcEzUc(_gmu9 zHn9||&KKD64bX6VpT@%XS!-kAr^JZ1PH{&U79Cz?PntEOvK4y|L?gW38%uL3;1@d# z;(|;^MDp~~%D2T-J4s=Gezqt51)mc;dhAKxu>Ub!wy<(WdFKt-7>C4~^&5K|3A+u2 zSQb6zz+(^?VnolAVhH`<-#^(?kaX{p2x%6NwAl5%XsG#L9Bnx*zU@0LVy8vf>9>DN zJCc5|rEmi_F115;)V>OJ2z!Sbqusk3G)5`n_tp{meN)`O8(S;1a@rp(OyKd|J-gdf zzI#L)r93a%+&3Ho*Qe~yb(eU^UnyRMwNCcbaFYlWW5IaU zvZh~lACGL0+1S-#`t1q(Wo$_?q8{s?is#Wf@QPyb9L6LSh5F~~7^w{Hij>C6YD!~= z{*JaK_yPtl-|(HlZ^*iB+;tnS+pu86b&n#9{InR$^8f|)1@?H_9Rj=Cjw;5sx|13{ zxW`@}D+-GwNHL0q{b8){2RZl);sxu&+em3!)96C(CaXxa`cEvw(m0}Pzx_eFuHf4m zy3U{rW%LJW3gbm0Me#X{c>KlP#NmF zJhfE9k99Ft87&_eL~Bpjl^-A%MnKg|vSAR3qd^5!<)H2Kj+zl5hpWy-PS-(X-l$yd z`)Fg2U3Sk#q>UEqcoFNk0-Jbt0+lwQAS}j1Y9*qGLKGKa`OgVa2yu#6Sa!Xe=EV8- zlqIE1FZRelLIE~X;gv!KVh8oB;6_}8*kLWhx&prK-VHY%-~GaZZs5C*5_(ix5B)Z% ziaxR%h(dxTerd5V<4!+7DL^ED@z8E-DP%d{zizQyhPlJv9B{t=Rj#l18(;t0!n`Gy zv)^gYzgfJziG4=0MoTJ1X|8Z1*{J{?5YeCVzULlA)MuwTKEVyO~OEq{||@T&wS_Y3h@E z74R)_kI=>3W2DJqn25#Z(_(xVZ%_2i0EyBcos%fdd)%z$Wc~V$8;kDPxMj_qo@o0` zcdjmK+>+Y7mQzhTYv36Cfh49huP{zxk-0~S%#h#SaP!LJeby9O0yoP39>Z{yScK>l zN)Y8I2MNAeiD_!Sse=oNZ_by%9VP1Eu9hjV9%LT4vSkVclT2~)z(`5UnNzD| z>#VKT{cvH{Ps?;&=V!u9cN*oWhUt>srq-*5xlPq6=Nnzki55f@DG2q`jx3;tmdW{@ zQ<4U(3kSD42Wgm_XB5$*4Zd0Ae6LeLX{!HiI**fraiaXnfsy_So3Q&mTrh54Be3Pb!%M=>&BL!pl@E{4~JtWP2uv3 zEfna+sV~r=gYUlB;uNT1UDu_#vLF6(zS6y~bLh+Ig>KIaK26p}ZMyk0H9LM0K}?FF zT&i)Jq5eoTcA z9HE<}izZm;w771i(-K46$V@X4PQ?9P?&NXd<$ye&ru37?)@0#A!s(OqnNyjD?fF^o zr73u({@y^ZPIB1%1)rug6DSUce363T6y54?zevOCj5Mc34z`?>EYem+L5&jG+URuB zCE{#t)I?}DQOgrbQ)J)*NLv7KH@ftzJA!%XG!#2zpbIr%ruo%`nU>^cnuf&}TeLWO zfg%ODCd#MV=ycgla%y!Ea3rIR4q-UCU6^UEGuzWfHQS|PNRNHVaqJy<#GZZSj^p+^ z`;zY7qeqWE{f~QQwIhr5BwggPd^j!H&=lK`G&EOtCVJ1l7IS3|%RC=RbW9n!?+=F$Ce`NM&l?({^>;0+FcD!9L)Tj#vU zLX?`y+&UdOe+E2UsftMEUC`UC*m+UrF z(YVu4hvtoLDx_s1#O17hT9F0J@42N_qLG`e9jfn|JKer(9&T{pqr2FkAJV%sFbXwu$QC8LpU3EXr)9T1=p2H+gTTBEfSRjd!S}6&m zQ9miA?(|+4=E6*KZi5zQ6P*;N{SH641neeh-84~IR}SSl?N!}1V5eH0-Lm3^xFmtZ zlpY1KTBj@xT-TK7hn1YKbhrBvG_+)wD|PGAXd0sVuGWQ!GbC}ek_MYAYP33Yp=R)) z1OdYFlm=*a+Nez`^j z?D`~}6qAt^LbMf?rD?j>{+gyq&TW}CBaou1aHU&6<`dS*rxTxpbzP*}5Y3e?(P-i9 zrf34Cczy{YC&dMb(?>VSsm%elHkw>wbEwA2tQ9w{_fJD#8$CM~(~CYEvD#6Q!k)BU zn32Nuz%vWW?|fq6WA^xcGa~lbMK{e{F>^US@{6%{^zdDeBv!^Evtrv~C6&z!o`_+0 zf~V|Dc@x!W@Sm<0JBx2Pi2aTOc0B?qlUR)sw-@e<&>l5@vDhxO&clRAEu3AJZvi}A z@9pHsyWIlFncc`bNs@H~t1J^H2!0sI<)@EH#C(bL{yE{RV7n`%o$zYhJKyc@52PG#}Y}J+|Gy z3^6Rb>OX~;vimn2Xs0_C2GaCBb2c*l!zr_o$a0NiK@LdH^6W{%%>Ih zVF{6)ur8g{i~al8*~O>YvG=P;o$R$^?V{?$y*PkD%sE|Y@3pV0wAaxz?Bl$c=p`Qr z6Zf>n<0W2L^f--IoqLcrcF?MCuP&?p=z>_RGEv$t|JmPfFAZ<%D++G5O2&S8R^ni+ zru|?LkrN?o0@uzoh55ug?UU{8#}RZ<9N>Mgo&#VkABFJ$4UpFu!%_=wD*O6DSJM0;A3Kv`oXIot!M27*~4sEpYi|r|nsk zfHUq807!2r6j8qi!f7$k4g`w)-5|d;Z2~gxqQ#WwMJaX!M!EOT`o@xeZWyDA!3W`HfR!J6j4pht$ z1(j>&w63vnGli-_5PA=Fz_hU}Sq6@<5Fm8D_^?9PC_1?){jV5uy0ZFE!oE1x{g{2g zx^yBA^6aIl@@;LsII$+WYylv>j@a*lwLuLXMa+({H*aXqfbt#Bqce-?VzCGr5u^oGte)vgyIbt`}3ZPEbT9*z?l19UY6w8=01@)Y_}x}&K_e;M{*k6Ba3E?Aa|Exoy7fw%z6$#59%$+_4%PweOt zV@?)^-%K2xJ)Hh^29{5Wy^%WERb*MWNmC{c(FLK2cn;U}Y8U^XMC_Y zHMozif4=0O_pd8iP_b1!ffbtH#_H0;{t*4{v!DKWt$g$M{$iWv{wexkUs+hJ>%s>2 zo9t(Ay7jrYt>D;gvkpXpB6UIxJxwd?M#in7V8q#gvE}O?Yj9z#alV+4u&XyR=wT03F%)e8Z4*17y-L!4?nTGbJul1$6o7O!*a@?{n7GryG&gJMw z5Et43D-8J?a*w3-I1ZhUa-i0gXfe=kfj^jTkB;YS8|}AWEa8| zA-|hg!N$v#Ng|#VygkNzth~2GgvJr`JM3jRzrnh4JPzUb#|79pm6sx0Q~kY(x&~}2 zF2=Rp|JY4Cr{VNk`!am>aV+=qi`PM*mUxJVD6fME>7H8hIuBR$eb*BU=OoVX@nt&@ z1lW5Q)7uBZWR{Os4xEED32xqk^#}t9Rrm1hvo#Mqq>xpd$p#Ft9w0ZRuHyD*r`N0_ z=5%@`Nu(G5Lc(|@TRNE%`90UG$nWP^-y5}0K1D)8Jm<3zj7;K!hAct`hH?nf_4GWS zE@gD#sM+b9=Muh7p{opdX3^6yz)s z*gJrJJ|*w@6X%n3P*z5g#~imRsrJOs<|tr2O&q3PE#lS;x!+~ z9)5rycG4`Ce^Y_Y6(tMAqb)}yEPle-#J%FfE%h?xw}_tnn11*r9zM`w$K|VE<7pI} zKrj33HhbJw``%~mo%YJNv8$)OgDOB&UIBJ0F0Ss}`;TuP_;mI4zitoLUdT|i?)8rs z`&#Uti1@EP*sP(wRs5B|L%g-eE=)WiI&qsi#?B>JZP=@UUWAaNSiFrK4~P%>JM6{c z-}Yd`fCrI?wY1Szu^(SGo#dmn;$jpwqW~*D#~WziY%#P)h(2G3z1%7t8x!m8!l&WM zTAA#<3&WgbFGt>f723%1J=Tv!jZwEH(n9Ps%m^w5N{co7az2aqBkD=F2w#_{KQjS7$9B_!9IKC#1MmiF$}=<}(2o3H60~A06jfmb zQIE~rvDejhV%%`sN(t__E5D}}cl`^~&S(0g9es*#W}nZRbaYW(%F(Gg4n1{1q{&D3 zaj0>mF)dtU)wGIDpq-brl-=2%1=%?`?CtZZ> zxd$JF2n%7R%P+2{nPM@E42$dSLZV0BFP-CiY3L^&*l#~(Z(l;U6iJO`V8;_Ud*d}b zc>D!C`$dghKXNgxpSi=1ixDU7Cn3I%?2_j}fAI6<*2TdsN&B|M14r#L`(BC`$1072 zQ_v-(J>4ZVq+ch6xLCb5%7yc==ptV@W(_(rbn z72b>Fv&=L7?c(C#IhcNqZ{EVn=aiAb7P&V*_}o#65<1jgpKH7pNtO>W;yG2b7 zy8D9Xp&;@dMreaBlS}Bd-E@FyJIftOYhD0Rqg8q#vLOj$@^LGJi}Dc-Jc{~x1}*jgU`H) zAQMEoZ@Q>V@TBKh)wF&qRXTf)6a=g$o{@B-S8Q_!KF%Fz$)^KBr_8*&;%m}Pb{mwN zke90lIy-p4JOmZfSt+?j98URe<6QF1>AZ2r8D~l18QRcUDVeRO8cq3(ZuQUrqM2~D zRe?eT{9;HUPgu6aO3N`F^l(Y6G8`_m$9=ns&U*x1mTrNMF>2Q!4h(;GgslYuYet~7 znRb%FL0H%k$G+?Wh&di-j<%E5Ab|59P>toI!zOZqc74O#1{StH3#t9z;B`F>F+yI+y4YFE#DKk_Sg2Hszf&Vy`cqP zlhJyUkaM6oQ-8jwJ2#RJi+LMpxft_BVr>@>(kIaU#uIGdKf=Vn5Z8QqNmTzo{e}6|*Yrmbdk&V}d<8{_$!h7bI6)_F-|Ey*EzNHmwAEZ435q0Aix7(QKd-UdI z3*JujwFYagspBwPTz{WEHqq4H*W2FL_k{iEtXsA(eCyT~%kIHPo5=Ap)|!lo{fmH< z?=XV;J9C4mMU&xKB1r4Ye68&arIDWCN~$ee>&{`K#ES>AATzNBWGJ>b4;Dw>eoe~d zUr{LfE*u?;0p4m+UM!YabNn{#P=CytKE0z%$aa&Z|~mr*51Rt)xpPSinZ1hnhvz*j9v1C7+GAtCb&;*ITEv9B{JyY zdHWywXi~Vsj$0#u)+ZUQQ*iws$afh6*+nZ6+u1Okcb7TIUOCa)F9KiuXNACFa!i0j z7TZ?cw-0L*d0N8$)bmxei_0H)XWo1L*iDs0z$xCF_hCPl7Kk8Vvk1snK315v}XD}yrvo(KQ`);dY{0g{@yRbn-Tzt*n zgMAP?_ne?evHEzbeQ#{(-dH>R!DMLzHd_=w_IJD>;`WgV@L!9^k#jf>_uU*7qmyDw zd|zw{KH>Zy3?lPOGIQ5hnqq0}fuGhMeI@$U9us46w0&C)9ZX@1Ivlm$K>PL%rB;{DN3zNA>sLalaoHY8OpT0XJerwirWSZ=|os(ANj(Yn}uDB8bQGJ%npc z#l*rVQ{LojM0n+!*KC)LB4b>g#d7zNNrXRog!y}EuggL5p#d8XckITdvysg?nY!O| z?mQC2aD9PMi9468PS7Y60}hHl=)?=lw|(FaXz=8%U1$oMPv+&R@Z(+qzYp{m*38g>| z%SSG?{z=*KO=WMpM>qR+Y-x1h_}=uw)WX!G!tW}LIm&-%;r8h`zxNiqs@?9SZcUja zX{DXJc4t3bleTei*1Y_w#M$2~H+?*(+BQ~BtE9LY%kybQhPw9oocbKgL^`MyW?xiw zP4e?3Y3lh9NLZIJ9{MmdXyslP3o?%0{EYg&b1F8N-X&@66M7e$djuw7ixA>vUn z{fH>+5UZo&;t=)?ZR-=~+1Op#F9JutB(_ES#Hb?`*Igs(5O9iwdL&$MgtjvkbBjf9 zOB-yLBVu@mNWwlV7Rll#Xqw%Bm@bJ*SX8hAAEQEl?n9{`!7e|)hB*U+qxl$CeUe>; zJ#_2_@p~W6K&Ouijudo0ftbzrf$4t5K>sAJ8S=CV`yr(^ofEwK3k%X_dnQWEo#0#* zX87;7Cf7mdtu<1zd-PR4i4%A9f-$NWnO^^b(oY#tvNW`nL*CqBc6<@J*4DSuO>3W)ihDZL$sz9pAMhZZI2# zdpY{Uy^8V#br^wYsm<$=N71$`ijaWOxpPznzV^B_$;q>t4#UNpHCr~LiXwa5&0=T|mcAh8i2B;Tm`!H}0Qa}NL&Luzr^it?-ik{UP$;pe zD>zxOa>FDH?eGr?{>`{peRQEXBi_5qS|aLB{!^uWp{Dw8K7iXvR$JU|(5M)>zgcBc2hFgiW{#+YcwIuwbCR;m*Vku`Y!51V=FSe3A%% zrHvS6JCvxds}Xg@GmFIRBURmryEY)yZ$VXix&2y-wFdS(R zzw{yO{Of4kmoS1qz9%W3LU8xj_e8}}e;d$|MBr18_^`ho9cdF|yToFMtrz`C2rVVH zu4b`yML%MTEYGI(I*^|v=8t|XXi@f?4V%R-%u>VVhb-lK$K3=j+kM9SvHQO z)&a3L+WqJZvEzt%WzUHR>q@^@BewO}LGXK&kNVkgQjCsPq~4TY5tDzR zg(eMpcvt)H@;MwmduXwdzNesGeNQnl-}O`MZV#dW@o<7q<@)R%>mG|1Vf@%{V*%6P z6R#rd@29&F!;7?Iz7r444vQDSYNJn!Dr>&~5mD0h{9)0t2T?0c*mty0ob;a*e~%qK z#LsaC*2j?Z=X>g(!Obx^t%lUw2`oN~4jLqWyPE=BPWXFp|Jgk>iS-J?eFtHeV{$dU z;wzq=m=R74dLJBW6uu4vw9uZM!d|Rx;{KMCw~8@I@n6`NwLp9ZMc|CF-6vuBhIYhI z#Or*pSgXGS_kY|&#kC^Dab)pdAr#&|y+J$$Ir0^hbHaBLD2R*C(3R0)%f3nRp5n)}B=c4K67d2;D!(rN!5@FE7vOy7 zZtB?wMe=~?Xd%7j7bjsgCvj%j$6J!I{fYh1O>7~b1|?fQnp5pxX6TWCWcZvS;m;~H zOcpc7Dl8WUWPgVRnW^&^1@A%tI92Aw>84y@f&UA|x8JwGw@U7G zs0iwHYftz0L<$B2p1MFKJp*y?2r%zSJ9ryb|84B-#;)C(k=ko@1Th&nT@4S#aW3$c68K+lRH`0Kc9l@v^_`r(*O;@z9a+fo=h+(J`BhI-I_5;P8ws1K6dgTh>L*wV*+X<$ z$q>0M|2IW$Cw=}$E0)A!%OLg_SKKI?AB;IU2*^C@Ic4i9}i)?Rf>?BLoO>+@krNE1OX%4qHiH5GbrG z#$%~*H%z4;`n$v-{N4xC=~W+{2KX5md9T7<&<$hjJ{VVYe-H-Oy|51d4|{I{80S&m zjjwiOc@uC-px+&o$4?JTvnjbV0Xou({p>8|*)>OXQB4{U!A$Vdg`@CSIQ43A_)BKlvw-U_Z{a zN5F%7xCi89{G7Svx_D!W`F;r(SsvUIe~0W%zBeAfrX=3}0&F|F25YnEhvIWDJ%ELc zz3~d%Z^aiR|FYZ^xpfq;7mlL1Z4{#mXnAhsn;i7LeK~hROW?NAku`O-`%XM;e($(> zGmgVhPtkDM?|GiG(Wx$^kFbx;N;OzwCGw%EUJ?|JOX!UE6oswZ%V5J;2ePyg&s z9awhMV4WG;tJ>o$E?t^jpUjRu`KhBgF*%3zp`;la#reo)cy!NU?6!;7;UMR3-ZnJ* z?++kLfhA>UdL5vN^fT>>RCzf7i&^vhHQwi6@sO8kQw-lIlp}<=;aTZZ{(@qM6Ht9XaGU zam|vZB~{7nuz6E`?bwEq+6~JZ_jheb9IoqbMxiT?CeE)%DJPyB(b5u!mn9CHrsbw` z)HEH(FZ>_T#-v$u+{_db6NC zX;v>k46dlXOr^hlcHIG9ICmm(pblPlz&tcS;tx>6qx)fGqS?tM*8ts(9Q*CZ#=m;J zVoyAo@KWAIw8-@o+g#8(qvU3WG11>^uc#BewdpE}TGz&5&lZ)R|@&ZWWy-rR1Oh%t?|Fk_ zqw%@qm?U;m0@~`?aACwnBbRg$?`!tfk)F>R-8Xh6E(<{g%gxYnY`IzAkVF&O8*UdS zIbWAtlX%6!?=HRS+S@P(z~VX}8tLvt_cF-s`jc070|mn;hTnA+E($mTyRdES_IL|~ zdyH3CacP?@+e!eMFS)iGcZ;<;RX%zGXxiIE*4?*k%)BRl#QbDWBDe3l{n!5m*TUb5 zF5|T~G}Lly_64JLSKY*x3C9BRW6~%vFC+>6O!0EmupZn*zodnurf%FU8O3+)D4yMB zb-h_y54~nq)tf8p4UTNY+5DpruvKH{6I6X+M#pICo%{gc3T zdN!_m%b3?5!UW90#PE8!^ZZMa)=_VJN7B5a-n?NsE`<60`s!ME41|!ZKk(Y=L$YrJ z`(nV-P**p06wv$``r&7RN>JEoUkdnobI zgXj#iJfo2tx54}S1~xTW%jc3%MQewlqOIxm{Q<1*N5WC zOGuS~9nirC>`)KYk>HM+C+oV=^?e803<7%8vO?m7as)fz^}LDc;q}S$BBtpEvnn%o zXWQ8R_%+fmH9&VkI%{w#YX|iia+sgSxS9NIdozi0wNOvu{*RM;&OsE99KGG#A75_n z-!pnNnLTRmL(Co5wcn69I+A>B@xvp@#AP+Zd_5fh(@QYZhZ}H~Ct+^j4p$sW$|=HR z;{L?eD-&B2Ct#qBn>Q~Xp3`A2I%|dwoj|Hnuqd%Fa$EhUp=)pfEp#pKj(E>?9KC-} z=0e^B6IMPFS9C9vI8G+~yNt@-EfWj>Uc!#$-QqKJ(BK9de4X9R*_4BZX6)JBa%1~J z?3F#Gt0cM!=Ih0#8z&upOlw!5O~et3KSqiSSKNj^9jr{SYNX@xU;|hty|4mPT^N+~ zc4D+Xl-k&tO>02LJ~cwaIE1-t1AvgC#iOvV9)Z?``It%I z(pveu4?SVIzTxIp^Rc}c14lEyjf*)d_t#n6U0RZCXh=5LwNkuyG$ieBl7H~!|Cdim z!BqUuAEpTc^Fvvn6pB>tozLNpWCudrKW4K<1yv$|H2^62gD)tkFJE_@wYe~fZ)ixo zkcsUd$%pqKNDI;sLfU~`?$>*@!NaZ`smGRs^r%#RSbM`}{I_61Q#^IuX$1aHi{(lKcHgqE@|G$J31~Zxb!^;G*EUI`Env=xz+dbF8 z&9z}TDSn${Xkxei?e6ZzF)a2^2hRKJz=?m6|2P2fKu7eap`*Kd>;Q2BRH5F6hOt{* zvssk9!|Su5p?o+|3Eo3p_D^^4hBAV8LJ_9$-^Uo-K!6(>0OtWfh%fn5^i$&qvL+|& zk`+M!7r|^x#{qyOMWd~ezid2m`hSrTf7xWh;wNWf{`Hb;;$j(GVlP9OI6s4**k*_( zmJC2lcLSPdf5R7^+{kvjhz=l7hy_X^hX43&zd9Pakx+td2)_9bXzpf7K}t|vDr5*^ zyXCJ$lR7}E4MN5P_O;u+$TvSE09oZ9a^Ro5qG*NKZxi0_r$V700H16t|2htU0;DH- zDDN*p0;A`J3c*lsgm8|CQV#Ov{}n+Y%jsWKi9f)xZ9N|@3o)yI1;=3o6G((h$p%FK z;xqW?y)vIeghz3U9hT{$0U>38NFh=4KG9}BmY?M51KlDXl9-=V0AvV6@?W=m3E!zc zTqtO2|5^O7dVv5175)=OMv}b049=rS!1B@5L2y_^Bq&TB3D(pFL7KWC7-}Xg-n|tP zK`FrBC=q~F`2*1cn(){DNn)YmC%MFEsEf&P`~#HPKhUXoLv~fI_x+D*6;=u9k*|w= zZE3kGOw0g3gP-_+RI79nKI?+*z{`+${efTuVfZ9_S~2(^-Sc$p?f%4o;-okUNi==4LuFXa`x8fNRwhLsV?r2-AjxZR%?~LzL>4<#eN?+ zkZ2l1vBMY$J`~X)o!65*d6$ zMES)B%L*PgOOV!nAC~IbTFHeR%!Ww$D|PZyz5-C)_hDC4SfQ;K4=E;mAPImue4t_T z;RCEx2Obz2HSoXtW=F^W?z_8t82BC@mT&uh7|7H34i1RC^o8F=^P>PQPdnD2J^&jj z58uCy{M_g_ycvu(52LyAhBdISVfQAQgaV`kQDq5I@cgfj7SeV!Y$g;$3;#d@CP{{PfSZ?!9$OL2K?bfArI^mlJDKGE_gn4rypra{Rf-{04mcf)850 zeG&LJ^ZNK7%{CXqt*1S4_{qe-B>uVP&*Auddhx4Qkp|`>xgS}MDic?B!F_m^7*1Q2 zWZU$l#tS61*~aUijqHe%b2KHpWSYkac@q*#k-|apBZ+Tgk}zBNCP~&aR+vYAJc`R5 zZw5;%L5h`pGuuTTg_Xlf1R^Oq43mn(PxD3`-S#E0&BHOdu^^6PH^@Z~!|x4_EoVkX zM&h$DcYYHXCm!Q2!-?knMdbyQo3;Zr6wXlExjQKGCuQlzfJ~E@9@4P?EU9gS$5}FPz?jHI<3v@4xBcLmRULz3E)~xv>3nI;keQ9RVK5ZpT2lsUX-*j3rcrMt4|o zg!N5}aC1?~?R&R%{J8e&^ns2$6L%**%`LjzV`HflDG%I|Vq+j7RdBL4m7;hgmN z$FMc=_Y%t+OqQsazx>2aS6&4qtRXro>4n;qJ2BFb_wT%^P2|oeK6M_44<%myr2I>~ zLZA3eydnVy2Jin>@$X%DN&MLt&yHVz`Rw=&_+RXKE5i3)9w7u;u_kI#*ADJ9Xu|zjQ!oR14kT(Mt@z@UhPAJ$qdk~Oe z`ufIBE(AFzRyp@yg-Hzj;hCahF0xOJ$M)cNx?qL;6=kE1Y21~OF65(tcfb#mG0ZnD zXxzAX1z6^d*j;x;A`}1L7hG~BToo@F+7Q3>rL*JbUpjkzNBqv0@%Lvhz2w>r@xMgq z$jfHO-y&gu_cDh4Oj4bC*`@JUqhWez!a%V`M%v)K8uADcwm1|7pZn1;<^G5Wk^SEx z(mUBTP!mh9583a=eo^W~8UgqLVNZYed`LE06cAIL@e4Mf`Dnp=phKXJser%mHD$lc zW_Q0o_*egfVe|a)14pBO5}$h^_MtW$#{Xq?Tg`@?`4hNV<;<%R7qd%$GmY1mpW$nY zuXE(Jm9I3FAzJcH?>>Kmr2DR zk#N`lQ6!iPO1^U?oU7(_K;v8ho&S|9ACa%C;;#aH{~^3{*MAAD6KH;(tn%B@{dL4`Vxm8LrRo1kfk^=zux7 zcl>;!F6aoL{GtABk09?}H;}~pRq>yrEBKq2%#I&|y1xzoi#?Aa{C3+FyfT67G0nwr zys~}40Q-U$urC-a(ifm>_(|Ja5|=dIVg9V$Y>Ce=No+#;tn_Sb;6=HPCr;q+6DJeH z1w9)Ym1ur$-Nmml60@ushz($-2!D8Hl5`i}!$&-}8^2QsP*Avx#U_-UAX!9q zqC-WM9B1xPtwM;du#lPGD@ovxayY-IIKoI=BEL_T=~>}r2OdcrPRKBQ10!U#AcOv; zZ)gBhVMAB@PaggpZp4CP?eDcGWCUM!rYx~Qi13WGb{c(l(2NOMOF;|LJlCe)HK;_u zc}vBcsvG+cKZ3arHWL2If`or9Xfezz+`N@Idl#C#nN9xvLptMCmZ&dFyhqwR?K81# zdzL(BGsR_`nC)&G%456lK1V|648T-eXUFKa*Y}x@HZ2$}kLT{UVEtBkj;CVBV_We% zJqeqrsUFKc*LJq#ewPgQjw{&Uq6dap%5>sX8IEr%7cT1F)W^5}o@sO4b2Xz1nTFNV zDAMZr)^G34O!xJ{W`cR7?1Gg(|8raPGqj`7HRkf;?Dz_Z4<_lsfF1%u2v8Z!DI^O{ zB8eQLL+yCYR!hOJ8(K*JjBS9%%weB(W+x|*KZh-R#(V?kO5m1+dh>WGw~c=h`}|6H z1f?;5JA*OrpHYv^-?%{Bro6qByUxFeEq%tkYX&#MKedzT?z!;4D&5mk-rZA{H{Ep4 zNO{MmEYGFOP0`*TN_iiHYy9MRnQppsQr=xtmN(sW=cT+mihQn-i>_#IFbPGW#$qXVo3K(6pNkN;8+CFAiI@Yzv|6P z+OhwUCqTSocfI+M8OJ5wqc~)G+`Ngq5lvTni}`09IsH={Zt~~tI8&fqPUL!RySb6G z6hB1pjo5(go;a7$T$K{-br?zrzaTE4U2rPvErVDcNPMh(g*v0FE zq@c6|q*kGl5L%~9!oIKz`bXY+F%4uhOd6RhmQyYrGq)Qso0M^$+#_%AM3|QQ!x=8@M#zc- z6vysJx|=R=fIPJo56`LT|WloAw7hQC7lk zx*$`K|K zH{YGH+#Ew_sX4ieQ;|3EqIpAkjEeB_K%2A&QcG>}%66k#WMY}UX*UG=DN}E5l4F~` z%pLs|=C(bjKM1XPquo85z(E$DGB+4p&$x_BFEh*He_3*|F!ana^GVCmGtI*W^Uh@R znFxd$mA8kXD1R4WWUHCx<1Cyw|7xQO3n9o zVL4mgZYjmO4BlpxshrIyGe6pe>ns^$&X@Ao9A=qe-nmPQWGJr*n1N%R<c)hN}B-#K!QaF&43{w zU#CPf&0w#a_pODzNgp<~&8sSB1`PyedV}OtT{i=YK}$ksE#XjRwn@K$EGXi~EM(Al z$891_tQs$`X@fbB$spJpI_aLk;4Li9F)|SM&zKa~;K)C6GGeKVT%abL< zK_adeM^|u;V?5XM5%G@LewfEOVeVp?m7*hZ7v>CD(eB%E)#O}q^M#6)VjKZ36g(7* z19wT>!M*3?na3=u6ar=$l{AISqJ+s~5AAtom^Wz+J0(#*vuFh#vq%kK3@uW-LUaPs z6$XsKu5X438AD649B#Y58MH?w9lAbw-nYx?jd$*4OJ0!ZC_7SSzPUTTkX_%k9OS*~ z5Z~xe^eX6U`^J;NH0;boZ`{}Ws&U3b55WkRL(h(Y;}OFC^_OyT;gN0ex!_sz_Pwm( z$1!Lnj3;1I;HT$DJCZ}S~=>?qXlr*Fm46Buh2 z?Wbu&!|soE)inGg);0zJu(@}_rvGOgCdR&f8eMkAcG(=40AL7X9MHup*nmTO6UPDN zG3-{3o4ZOg97z9etq5Su;F?_RK+TtLe|Veu{%$TGpNZo{V(i%NqaAml`ShOlLM!7I zgR@93INnh=oOtZOemIm}Y+i8M3?9nG=UCFk@l zZoW{;LDXHyL_6&Cq*hoscKR)j>CO}Zp@6#}r!qGDEso`gkl)#;64vi7tJaPA$6fK) zg=0DNK4rprU)ZHqh9UO{VcPp>80DKo0vk!vYtXGhhG-Z&A=VcT$<$K8mR4`{1>;u} zy1veUQ@}uydCG+0*ex8-QGG{-X+;WiX|%65fl0&4f8DsE!?h~}nEyWw*ADK&*|{99 z{Q9(Xk_Lm zZ|v5Y$jmeE-km>koBfdaNGT?$Musi(T)!(m6p9VHRiWz_cHvwLd7DUTTsmKpiiIh^ zpR^+sPN}F}XfTR(c^@oQufNAjl|_$Hr%Ub2oygu2Nagn-m0IZaLD=;(oV+kh0e6Na zrP7shiJLnKCUIauhH@H;niC&ic5ydvF@Y-;KF#%MfjnWZ`3FcScbXsz{GPUS8 zvF|pVu#~5cIWYIgz;zmSV+lHYTgzwwz|%8btb<^5n^V-cCNj+cK zCU+^z`!5rY5uV!WIM|Ik$Ow+(+z=re=D5R8=eX4m!(6Y_7SZBiLWgAVR!4`)ML!;KfbeLq)&GC?=3@6=`eAAnB zv%I2Nbg*FTpw+;@m6D;`>qG|8X#{D@a+yFzhnzgtzynY^R(s%6&Eqkt82v1ItKn0Z6{Y{K0f0t7V%-~Uv%U>%jow!v&_!^VKHSVhV#rl z(~QheQJ#rFH%~Y+!_5=^cEc!uGtDndI8TVtfrToBK&P~3V({o@1jlw`KqG1Z$A9d^ z!W8n9nn!2gY)`y-^Mof6$x39NkYi4H_vZ=O=M~HhPBv>eSsaB4lZKRemML(}FjqrE zBIJUH%M#3dVVSvO7nLRz=!G)gmY2~P%y%IoF;LPdZSRHVRcGbmur8;tsTyM}N4^-+bLKW2(!-OU;Fg*b09A(c zpje54;IJ(-%Z?<@l$o8!%|GnQ!6q8VMLD>1fKqPlJM%9{$%_M#y3G9j?)>5DfsdHS zN+FE5^wh>*ahcgRZe|@>gQKCbMMsX|z2r>d=DqvZeQs&u-VO0rUuvFDPpg~%A+bgR z{ucull_c){hs32z6BQfca~Lou5)hyB!k0f`{u9^kVC$6r6&I((i|LQB1>ScPIbi4= zH04=Yop;_WS=>Ila8Y?SoBpl2CRlHPDXO3Jy3ClpKc^V%DZsA2NqK$^5zhtRJt6Q0 zg|~qPP778Sg~0n0C-)C-+|re)oTFIMXm@LhcnV$+zy3qkXW{8s$z|sGIN5c%9_9U3 ztTg|ShvVC|*^Df~z=Fbe1~G^5eFm$l{H6szj_=dv^LT$|PsWDTn{iyH@ys5VhAXh6 zHjN8ozEQ6nj_{91zQ-}C!ZHf;x-uAd2zj(#OqvS}VVHyWbfnw|Vz|d7%yc?0Q#-8G zL!2vR_l<_IVG2ap=zL&_6o-TmxEpcK^bc{T0LyUY5xCC-ks)$UO9P{2JAlImD1u$t z$1Pk(3i4{5ituQeK5~it<9P%b6{5kml6L14hvmY0p9U@zH&J*eE1P4%U%%|1?Ws3! z1*0gfINSOoxij?VGef3(7UR!nf%hBaINhIbr()bUll~Du-_BXKeKVQw=i3i8;p45a zbWvL3oaJSo|B0GW8(zo~--@ufTb9O?Ko5f zHo`#`iHZvr>^%{2dVyqRTEC8bT)6shX>AGh1?iQqYy2`C9{e(kiG#AGwmVwhNXc=F z+jCx9S%<>yREFY@;XVzhDjfZt-g4y?iYRgEmj`wStM1#unV7K)oTzH~zRoR7=ksK{ z6@`5}ICK2-GKzw}Ynj;V95SmThGTx!X<=idiau<#pU;&?CJGThf;+XI*+Yal1Zjh` zjF2I<UP&j)0naoH&L(gt-WXiREH^?I|1AZo)olh2X61;}mA?!}7~4 z1~2L1aKXONDIU@eYZiqX##OEi64d}c;k8hon^n4_T17P%rPxWfV+yB*Lf|xiv?Kf3 z9&+>BcTmay9E@x`23&H(PC$wFc_2@}#~}%{xZf@k_2V*1*V}inQ*iI~a9qdd^)oqB zdc7n=7r{FIVjEpoegeOs1O@%Q^<4}+sZ{?S* z+EjTmTDA&yKFm|qTde$1Iv@(pwM<{r`|yY1H=-v}-i!*iGoV7{>SQMhdttka!Oi;e zX_#+JlBPbL9B-*{6e^<-PlOS&0scN9%>Lb(VUOx$NDZk2B4baNQGO0cPx7?%BzQLi z8S_W#J9;+3k?O&1?XO%6X*tW85_3CeXw5e`5H=r?_b-bS#h18I2ixIrLmq;u1dso%Pj^Qhafi?=~2MX9~G(js$Jc> zLGJAM=nl;9m`7wt5^5Ojc|N*BE*1Jm>3Tl8L&hLqP9*3nc}zN(#}gQ?Vnn{c$%gh} zAr^6@NVKy&ZBdv%I&{Jxc7iG+6tMppg8ZgK5H)O^4kByki^aqptYa(HaqQHh#?R#9 zR=nKLdxnEf+c=AG9Af0uPJRdCmqoD)I}jg6HL^Y_to{Yd>P{r1>8Roh(>d6*Bl)Cs z9uG_Bq3>FzvV7DePz;?eP%wV2pwqCai0-KM;2u=f)s3 zCHyi&^G)09Oh$&gbp9BG@Z+EYMVuC@h{@N96hAjhLiOg5pn$u=!%7*>JU((6<|DzW zNxxjJN7(-09Ik)INq>47qiMaYCY_EEbEy@-rOPKh`m4MgYEj?>sh ziq7NlGLAovNp^G(5+~im18O&zR1~vLV0Gxp zVY`puhhw#QE&Rczs$jcb2sp@;S5!_1+y z;w)^x&yIx4i4$?4@K0y75DwE79@m}_cW%_dHjxtxRaq#0s?I_fl?!jgRDg~Yoz3Ao zC%-J>f#T-i2uGV*XDEhLpJAPac=0=n5N72mU(!?(J}Z*(0Pea{1HE`X+R6?? zsM7M;9rR;5F4FQ@ksLUJl$gGD)5BXI;q#h!;o#R!C3YlUmv~{~O^GHfft8dcj+gQL zpk)np9gX+>=$2<2UU%!V*DpyXE`90Mh&S<}%gPdP<2`>};?S~(-kA8;ua&1ym~E%A zgMDs8I{8+d?S*3jZ`l9d4}G!f>t-u%40{3BAPue+=3?>FC1>$|KrY;Qx}<&%i^T1d zrxPvlC6_j!!7$mLjh((JvFzhV%^Pz^cO8w-#QN8f1lPiDo@6a-pg+xvq&tUmn{iA^ z?~aQ3^A>Uutn#R{s{SLL);xv-TN>r{Cga^2xaShK?J+nxbU zQ3yfG)u&5c9&COL*2N0<0oyX&-g9jAwZ+@xttu92ncV05%$Mw%+27zCrRUS6|B77B zc?b7|;GLwugMK;Y2Q&G8%l1Q$n2T^r8A3i<#&rtN{cX6*`GFYCqEVb{1t)Hd3KrEP zn9SX7K8^plRi=Ja-!i5i(PZeaY&$oG>V{{_ax{neuK!= zvoe&pVMqK;n9Gv;vVSmxTR$JzNia{rrTf;s@wO849aMGeUhL%57cA-G?GS-9R)j?Lrdqv$1Wz-7MAV(fnd!1xr*)Q6yTJ_Swo5VY&3F!{=!jnAW4_4^W9!0+!s z3x5fD9>S#Ur%IqwG*LaCM-ae>b_iuV(Ygq~n)2xq0{2xJn;nO4`Oa>5aDRKxIBw>{ zb&90WDeN$NR3(CJ8J3^pw@i72zH;-W%;M8{U$-gm9N*z5$%F6;}(KHr`7 z*EDoqldRc-ppQt!C3>4Vgy$jQqQ`eYTbg4qPR{OuA2>*L7Tw=L zTw`{2&nRwTj(-SzzYn*RqeZgy`G+$`&FJ3vFXJV++8n$+3Yz^AcFmW-6Gy=cKL^^M zKxL=)9>LBqgMDD8|Add4}8{ z-^s*GavF>he@zKkg?tB2P-cp+W)RsbzJqUMKCBJui*jGcrH&g}@+cDWo27|_*SC}R z4oC^^747^_>A(KoaIizcK30}7ALGtF^Z6O$c+22Pd|ba14S4(B#N6|V%EKSI1$R^8 z+R(YU6f`mS2gz$X?lTu;%$C#UvNIpK8CU2oHy_+PmsjcH2KTd9bv54bcI*_FiH7r~ zoR53wuKIp>cI@WHgShz?b`t>OyO#5U+drj;$)ly@!v|&K=1GaY9ge%N#5CN7_GQVp zzN+rA)~e*&tIQS4%^NfGUcKSU~-TjpEAB7c$3s}rk}>};7fgz7}F0VG00p@hq<@}KFK$ptErzoe0y~eCbeA4 zPpMgQe21S`@<(cxHvyK13C86NWSkmESEIOju~dXJ1kKAbV@J)VBe*i~Kd?1)%{KE1 z_#K}4@n4ze9dB-|txMK5EV~*RejnI8w((fuMieDN{QqOUFBKIqkW(nCo|g zL(f5*zl-YUoLP>S@pt3sck_KiSK<;jyM#?DAy}nl3@j}p?4=|8khf5vHi-y+m~wv=&4AR<>_WQC@^ILGVE{_uF> z4T-l5-nV4?Rk$GYUpI6gNM8B6#HI0te{l2CA8$Ase+lfB*UYB9^5aPkPw7tgr-yoQ zUUqhK`NrPPEotun#GoCku09eo=E{q7y)1S@#h=E_bx%VxJqD$FH~ir*=|0A z&cc{y=QJzFtupOAXj3=1x@Tq0C;WNV6 zCm^El{bUE~uB*+(*$={TxyY%bG$K4rH zCqY-VqX}#Z3cH&-OaL}VV$kD`11w-F9@?J}%{eP7nLLhCVynVZ5EU#1QBi)55TZt> zKLz68I|?oN+^Hj$clS2-L4Xq5jfiUU>$o{COi(DqqGFM5goi1ZU%|V{@qa!-AHc~Q zP7f)sYfC7WdGd~QfqF(u$O77uPe2`ctn7so*N1>}jaMlS)eu+*X;s03%^9KmF>c6& zj)y4F=g+2kS00OBxuUx7tq=e3jrWgu`)fCEjtfiCn?xI2Pvc)?$b^6&2h)?^0a)7dL2#J zh!E)gFpX7&$ys4I8bg4|)?`(O^Wy+e%_PM&djjI0CJ}`usyQrsPY^DW89_A?s&WgV za#C5GQ^5Cs=1Zq9h3tUOiV~#WS6n|=yiR7>1PtKmj(i+KcL?%SDxGR3vyyqmEKoZ^ z!Hbv#NKjmvC{}$Pr|(LBHS4VI%QtF5^MDCH0X<0CJL8dRS}`A*2#AC6DLf-x5_nWv zq$*wCS@EM_i&5e4W8Bq@ZyFI|Ya;zI?5R{4&_*f1oUwuqLi~tK>HPwJE};@v{`PsD z@6mo)(`#evMSjS#)c4x;oD$jlMH%O{@;RwEM+N$ZiVg;|0Iv;FBj7$X%o)#2;~JpY z_Zy&%)COqhsetBN_-a|Qzqdf5PPKoic<-HYI$$tb|5Or=Ag+H^0uW)YABBa>58DXv z8+Z-o5CT={`6}I_*h;#hte6?f!kpcp>L_14q8*oGudr*K0_6lGuwV&B7$LUFw~*;S+qqQeNo_9jx#%PkN}mXN(U7v zJ0vDJCLI1~*>QY3rO9V#_&U@oIU*gDLdxNROQhTuQS|~PGe@BeMOo=U4h_0i*6z53 zEb5@7Qlj!vhGE4~Hdla(K&sk@f?WjC07At1os-4mWRUXgGKWZ&Myi{7fXLnl#;+4e zOHNefdiO%ZP?=ZRLYbO+5v!+aatB~q`vu>Mu>GPhLj>AhO5$1Xek@Y?eW+5~r@jyL z*-5CcM!4cvac##T(k_L$kobhb65oT__3zYwg)I9k9=iq^61)7-GBSbFA;c_gsCG<~ zV0jZ$DT?ioF?;}vFoVw}qACh7{AtXo{0L-pLc~H2ptt!EDpspRpATa5zcEkCY}$Sq zH1S)ha-fu4{4@_bLte_Cro+4GAC*~a&Rt^$?rpoy#1oiQTlNA@s=a)YML@eFt#hb* zp#QhG@E6na=VW?%d*^KI9oV$xxlFIQOAK^=t?1&OmalVZwk{qDtpS*5>)X;fXJ}x! zzsuGulWzVwyqtg=FO|CvVkTJvwT9_XV}4$$8~J(6F6W1hIYIR%Z$B;7z13md$*rNT6vS+Pu`#+U7S3_ zv{0Kit)m#!r%PK9cWfq3chd}ya}8G#9-FBEV6jQQu`Vjl5M7E!tW`>Q2)KspfeEv? znx?GB0OV7T9k`7HCS zoB=V5T3X8Y(}sjrL3<|`XC#%E%R)gN?ozQQl4R$(crS17+$+uEkpZ(3e`!lOoJd?D zv7zozfb(T^1dGI4&S&jWOS8<03wdImFoBKxmOW-t9mivfbzZ(D^KN{LfMcXLu#(qM*1o>aIBw=d<6yTdR~RY<;&+f=f`Z^w;_C$YvP zhu8}8h7lew?Tct;`5uWYbsh2xk)-jC7*2hh-Q$okA#tR9moMa61$HEUT;eghb8r<9 z4oEE$mS3+Ec~`D}yK>RK0%p9^{r2ZP@eY5r(0r6t_VH3cd42QfYL zVis5VU61nvEF-&w!e8GOwuO~*0mjvgG3HTw9IY|W;t~N3d+V;zx8Nj7Z1Oj`x#oGN z&G2&byhFE~ymEtClffNoJ&haIm>u;;8{WEf@6qJRlcl9*kiILpdk1ekTJmxpF~6Cs z#V!I7zWr^iu@Bh1-Hel`fxOoIqIQQ;NoV)7Xh`xnp zllgvZ`MrO>zj4jtMf9@4{k?J+^Uq>DcK)sQorhMJm`kxC=%a5-EIaVJhQ@<+6|2{5 zYV2yPy}H4?cDZ?FJzNoR%*3lp-ez`WUUS=(SDD#%#}S4GV&IwEwzhvN@h337@5i2Q za5n8Y*h+K&As`>3?Pk7?iDrsAj?<8Jocm$ILp{j&g3iTH;=gosNYBApe)_M`bqKB0 zJhJ*E<42TIGGAPMSSo#B&;zL9zR-<-}5zU4V`gIZfGZxHxyq~s}U@`@ut9uX!x&d0z zgi+fhMTtLQEm|Kyb2Nl^+Y;)S>8X%&?d{AaMZpPUb5V;^+M`; z@PHsyk;6(!jIeSy2jmdU@;Hx?pN8Q?yy(0Dp~7dVQ`gL)I|aeYchW5yu9s0pOu!r* z$||GSi3W>Qf1V^d;moeh0|?uwF{2Rzct`|7oz4hQq=8mg+$_j(MStw{F=EGFD<_VZ}L=NZtRjd>djB|p^I!6QKX?i8bNZd_?25t{Q zUGKzdiY}x&aSZ1a$Xd^W`;55(16aOO(c^;*_3U+-L>+)SBbwcOOxDG27Vnbp?;JHh zjg8isS0B1fRONkpbMcEXeemRkoIaR4$@GEVM^^4Gu`l16-t=4Z9=858MXD@zZccE= zpMxz0*owOI)^O}WA_v5k8}EkV=(6uzImygOL$vJNiG?G!;2D&o@#h) z?dByNuQeCqIOh~DqU~6}zHi+|oSnJn-L0>`QLYh}OX8*5eUN90$lJZvh&JXkK^R;^ z8P{gJ>wl1O4bLQ`;fB>rJC?#>lDvQ37DywBY4lk^02GHma9*cE8pXB z^!W02gqN+z8yaQPIyhaLlR+aNoH-ph9di79(=R)O-Lc7d}<+XA9EynYGmI@->o z!PF24mDf&}=H7rFpOHhei_xqw4R$VGa}hp^L#FABSDo5NYqHrpopG;6(I3~+sCfa?bW-p}XjFy8|c;@VH6`9t0)fJfjA z`TEX)uOBF&x5G7kxD|GIYuolu2B*WdpU=VJXf$!zA?%K>0WR}k|A^>+dP~cM@vnB_ z-1lL#gUdN@#hGuMPR8$XbMYv>tnDwoqjjEHf7M}H-w(X% z%ORF!@vASj==j?}mwhEb(H#LPRkegF>Z?JTznu_`ej3iD6jOD6no)}qr^X!0g1T+I zBgw<|whr8}7LYril!fJEGnAC`>$fEzPA5ha!FgJCko+5#wJxSb@E5x=^9k=^xUOLf z$L{u8eEbxv4)meNZ%92vkL||oU3$q+e9nt3rQX96t)vbAW@k=~`O66@^}T>n@0qEP z7h<4j8e7MQz5K4;!t^1dJK>lJ8(#}flSMnE71M+#k7|W5OsAX>&Z)TTt6Rt4WG*^G z1I#4okZnG73n+CzhK?ek2W8#rtWfbF$b`cb-?x`*Wk*Vp0xH2A5*L7fkran^k5?k@ zQF>}h>x=&Z@G43v#BQfDqT&uceBtoshB`(au9`XnbCaKd*xDugI+;(P>dX}=%u zuV*7ZUDBSIjqHi~F#idc-*mHuU*Mt*s$~8_miDT4)XWlasC@}`u&{*q^I+&!TtY(^ z9EkV-yl57FOX!r%??Nx`-;MKmdO<}|Yc=2byl@wqY<~LBKN4T@1x@H zc~99Hb2&1He&3jTQ5WOTd5=xwK)a>g%wuE6#H-~oaY4UZyk8#^zoEM$F5;a3KrTri zarf4Ss#mDA$d%6tBkRy1<7RcnnRu`rw1kYnmTZD67 zKLoebyo~MsEA>7^7M+m8#Ifa~D9pY`=zh!&$)s*D^_K5-fh(fS?cfGuX0wumppB3O z2ezBTGJ|wy*{C@NPq92VeY(3iZz8r#-CCa%HhQmcELw?hCl;DU8AvBF^j*U#8aRrW zo>)$9@*Sq~WrnijIF5cRcW;A-bu*Y1TvBTKa6mlT#P0228E=&NqKN065Dt)%Li9MC zHI9i}48KEXDT3vD@SsWNa?UTQlgyKFkdsfiewgNr<4M&LY=&b(pCL6|o2?WMTW9kK zEjf=Adf$<*z6-5SXSR^rHok$zIX9GpoYEqxv}vLi&@hp%0Dh_mI4t42ka|v0_@Mh# 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

^l}9=!?twxD(|WYKC{~;HDb{N4hk1PM4SMz ztwFMHEK*2(xg3wDV@w7*g{->@#`7)IHn$GKBka6|e2I#@+T5_bWN%FyY0KXDE!Ti5P31VQhF`(!EE$z1Y0&PAd(_`3A|p&`Kfk^Q(BK zpQ^oIdxsqW@u1)wIkn&}+uF z)zta;8pxIg$!@SpA@Td>*0&Dss_G6fwb}dH6ykp3mxAJp*TFvVqr6DFEgaA+b+M@I z;`Tgvgq@c{brm_>N|z1NK>7?)OKT^E#7VaG3`IPV^;$8QZZ%yTtrxcr!XxV()4Wkd z7HjIYVlZzq_2Je*cx0Wpy-P*T(bR$5r;o;N7{Vogb^!UhNn|a6T%uXw9zD3TBM@@s z03h7QBQUKT{CKzeQCx}lJEi|*zSVnF!+g_JU!)}76q2by?}EMIS*+$3t7~eJvVAg^ z2l8{8^*sC4%vsZxRHp8vWy1-l3EilYt27-etuJgF8f3-z)ld}US4(RGFE2JPtB?~d z>T_S3d1jF!JZ+Wi>*bSFXM`-G+RioIi&Br?kV(x)>MWC*pGxhbQm@jqXamrcQFa2u zX)3wf3vuAR=0Nruga)=r$pPq{HBV+X$QYA3kaRmiVebsHHz)PnnQe%PzK5?!?}mK0 zJ`*X(_h?q=-Eg0cK-8rvI;D9+zR0BJLZYZppWmgao1@BP6U`BwR`v&Qc)PiITZhC&srer+hrz?p{NZ*|15GFlJ_aZpZZ@GXI4WHa z5}%tm4XGu$*Hyee$Ok+#p_Z*)b%+ zDlFC-a8;|DMUaFl0O4>^G(zH{G+xN)?IMeo61lg%skaiLyWFboHGi?)gu-B5{$LFf zN1C{yUFl0*kx9)9T%S2|hy`vTB%vw-*Vll@i8zrJh!^+5iQW)&6H(}*I0$_4A5U_Sfif>lp2ztKAvta*a9VYu4s z3HA;{u+J0h%LMP!&^;BS3RxKy;^#*-7p!}Nc~o=3swbF7H5aUTf_YSP!Cp@=k7_R1 z=LzOfC3G`2gfeME9y&TiRmOkFg_;!t4fm4>Oj|VScQ^HQNTg)AxFZ`ba=EG_cUMcf zjm=&Sa)Eid2$BL6#i=#ma7^Z#v^ZZ@wRf2MZpZ^o{ah4%B4(wEexwS19Th=NF{wEy zI?A%TAAUc^Tdbv8cUvv_ZKscMkE=AAMR8Er)&pLAo@^<)O zwp2x1N*!Kx>ij})|vw<;ms5Atfu znh*JB%?jQdXA@e_XeE!btoe{E|3+0#KD+^Q{DA2Q?!$3}g?!lRz?-)y#hc9KI^;2y zRfD87(!U_BDAEz@4YBI zTr3=}IT5aT4(F5GPU76?ft`s}aFE2mS!S468QF;w8LZ-+^VbwIx^n!gld|b5MYUIE z4~glh{PDMUYVoyNnhCA+S_{o0NE+s-O8=Aw3_+6Nk~qE2n&cwLBQ>iTnto+2i?}>m z+2ZCfbqELD*FY&q#>8^r3K|GAkMt7As9GkWRE{=7!Cm_)Nb2j3yuLu)U@`Vbg4BgQ zG+=HtSC&HzLx{)9ZNqwQPpJPNdv5|}S5@VG-z1fy5(o)%h!8>s1{oxTQ9uHMh@#wk z>)xU&sR0oj5FtQFg@mMnVuJ&cn1FF;ZXD3GW1QM3wjD(!v{MvqVykVO5EV5l3gW=K z&OPh5_PKlQTZ#Spz0WuCJmmcMI&1ycu=m+#pW&YReo>zWqqU&lE(k__o+7Leq!TBB zzi-mopdn1Oa@B!*sc39zxCEYJvNdJ!Y?Wo_hS1l1;ITc;4;iD_3qVtOhqWi5yR{;`|+`0l5qpKvMtEQr>B%-UN zqVp>UqWcevt_mb1xt|3rMkjagw4(?~6oFJLUnbBZBvAwwd)6-#i0*!it`|s1a`y^I zJegCuSLdSZOGVe4s9j$wI)9-}bYHOO`hbKaZ!!UiCyP#Q;JN4)q@wFfM7JOnoxhqV zy02+;a(Ai(CMG#jfQM;7oubzH%sGhwYjJ?6`tGg8A)>0W*yd98I;>k+YXQ%)D~}%F zb5xX-u->3G5)_SB0rbB%`Wo;^v+4#yn9+41if3`LjMV)?*%^F=m&w&cV@??3@_Rt z{=v9BcPcTgvIbb?77DRa>gK^J4d+c3Rvq|G73Cv})(3(j@Y5}daj4!yE#;xs@E&R@ z5B@CTJycR2DhUsjlm~w%*rZ8)S+{a10>7f7yh^mb6%>I#ZBf*QZM=tC%0sQ;J=9Vj ze3iV1O3Fhe;h~c9usc<%raV*=9;zu1{+#D?=uLU(O?c={dGO~g@1ZZ{p)cW~FXh3X zd+>0d_I>tbgid9Qq@I@SRQ<j|4?v@L1KIZgZGQvNIDH zb6LCsVM?9AFymDbSwH)j+{@iqon&EGfv2iyT-l5C*OeMI@h+Isl zgiLC{V8uHpN>eI%tGc%;o4SJ7DyuAJS6PS)fXh`huC#1fgGLC-y_LU3^_e;g=gUWo zy&L#*73I?xtv>`s;2&EQwPBkriXPOh41QqI&>za*QiC6xVHx-{6-|vpYQCqF&F)x9;}pH0l_`SHQCU-w#&AKgT_6uwAT{9k z)u}wS0K%A!iduu#b;>V_KwRdE?VNtsoK}D{jB5ypn~bZHa5|K7>d%Li98Yrg0pdw6 z;DAM^)r8Z5lvBUZ@J@TZ)9#eh-h|WclvBS*@lN}2x{sB&2UyIsFX6N&<zeh@%3eFPeIBa9>pB z2hC|W@YgEpl%G=ERGQhK{e-F34Qds-a@AR58e@>y;3;=0WaK8Eyiuy>nu~rQ)#=JQ zqH{&*kOmTplzs3nlhdYX!6L3)*hBfKRU)?7oh;_?L`G8KCsxKzn!;CV?t$M8ld9$n zsSFc?YAsJlkF%qVkekA|TmPUVo+Dt-(p-L%FuQ?}u=g&_UGvyV{#43r^FXli{@9rx zL;br}agUrlOLxq&O6zcBN4`gvZou!WD82T;aJm`RfJH;U{KD`~^(;^Jfj1l10^lts zssW4iiSvunzR&2Zz)u_3LST_AaoSK0v}Jq(i-w7*-x>B{xXps-0e-_oWnhusPx8DI z^+$Cxu5{y=28}-l;n)U^4s{`#;~F%0?MZ|kjeAw&Yay6;th`5=|6RAzbHFLaf8DhW z8l-%b{5idOvuBNe{G`W^d+fL=?|)zZAN13^=0ASioX1Z(aZUpZ(mz_(8oj$`3L9HG zonW#DOBy6zp1!+r&6?~YJ7%{d6Jugx+ogff0b@%qY^%dTC2M=&F>0Q#>S&#%Qc(oX zH&OL@kxS7c8n#3QVe>)7NryCO6Kzv|@*!;_-d|lchZPNs6DRZ7Z+4{-`y5+3#rdnN zpG~?=RS_Mg6L|;)e3P0?g1c8$JLS`Z*U8C}_A8974qRrUDv()C zR$(J;Q+%n}^#GxiDo<$8pcFET)2nQW7Jpfl!FMSAq|%KOCpz!6` zdbM%&196jaRT{MJ42r;_Q-5yqPOCUwWLyJ4++rcwr8WuhJ+ zaU~`##?cf7GT4F7Hc=1oJQZbKS#Qwdy+nCi82Hi_MQymv9F@q_1w7Y8-9Vg=EiIV> z#`X9tkXch`Qm5=jjS>|j@r$@4R0{&B5D>#`f>ABo9Q!{rTcl>gx|L!B-({k1;Ja0n z7n>Gud`gPI54R|4!#2E?_)e81-l*QByB;tVH|=iIUEc^Qz;CK3k5e0N!?R$?85rIa ztpT^IU3L=+yj`z;a(-IhQ>pL)xvi8LgMZXw?4nWuH??IT0*Oc#hrs8X%K>1yKwoRn zB1X9Z1SCfB03^gLuUdl^0VkgR6Fp~e2@OcCF=ZwD6poMd>1>!MR#7VrR2(tbJ zzEySPMja408CNyow3>42=X#vuDZ8Ln*#*`KJwVEyIqgk!LJv{lT#qM{>4hlD@H8t(`s^DYs4t%qHnbKXU+p(n+8{jP}OWZJdtL}QcnVrx8f6&az zz>lbCTxro5Hy7iEl#eK_*|5BG-&w2pZ%o&W1NSd9kIR3gP4ZW0jS{lDbD;k zLV@S)RyA3Ak8wI!Y5us~Z2JtxxJ!6k`tBZ#0z} z5bJC{s2SJ2K@rFUu3Qnuczco=R)9n;PqBflgXD|>Bo5I6vIr0@;NCXM`hdhGT5&M6 zpJ72&fkYw~y}(O@7LZ6p3;5Nb1tb#D0#36ytH2N^%SdG^mCjK_B(h?pi&@Kwi2kKR z#+MeCwtEk>7-vV-k9od8_~r zH2QuZgc*G$k&wHK4Lu>tBmtai^aH>meKkSv?tpvxUg)P8{UESN-bs z9|9KX`x5j+R&)jL*P4G?x2a1ibnq)PBM`I1mCJmM?h=c#4(uM6dlxI&cViOzyNtd9?6IKwfe_|nl2)L1V-orWMqdSPGEpB8 zqKw|J$l>BQO0t9oLLiqmz#^Bwsj^I+zgxHR7Vt~l6c{U|#>{Fh(wD4Qb>RFC>wVxW zRh0KWt&yMz@~@ZZxMg;FZQT0K`qkRcp|~L*gP2`i9Y0fL9s)AP~ZgzLKDK zNBZZLmZCI&lSktMb5I6yzg>e0WUXE6Wjt7NN32mdDi-{x*G9 zm%BU*`zG3t5g<=2o`@Y6e{aqQYbvRZSgl3-fo_Ex_)pe1*=b)nY~u}UDMNo#&Kp)R z%3jKn$_WpA zR3veo=v7=WsLUS4({ps+W$knFD(?CbmFJG)i4(&?Hc8ik-!{=8@XdSV12R8{(fX`P zr5?b~o2U-l)?!QRF;jFW6+-)k6`=-vjatc-^rjISgp;2XX+2O>rGfWcmDYEQsx*G2 z!d#WsuZpTP$R$^ek73g3wz5`$WFYBmPNq|7kPZcIs?wmuGKT}nw5dmfM6&=Z4O-vQ zT*Mkk@=a?RB8^cNRG+aNdVvq9D0^T4e!Au*Rob+YMlrKq%j|CJj$R-cW{hA`lqEBe zZf-hO7IMxK>rHfdFBPDdGh;Ay$cPu9s99OGpohnyf!1 z0V$ENZ5*LaWZo3U#lKxi4zi=I2Y8K&WU07yW#_5#LE`BRWH{Pa_pJ$k%E@{JzlkOE zzo=LGS#D?nVU|Y)J63kins0RUs^|joV7l$HqdwUmk60qFlhP&*xv~U)Ktsz^7l|tE z$yT5tAcdNoRl73_cczd_$n2n62ZjnZwKDZgkNxC4-B+_kKkm`Q7smce!{4D>sTOdY zWzYx2u?&sdM&jamyK=(Le|zm0>iPon*AINZiH3kDcIJNNAr7!=q9NcUn`nA~#GWX^ zRz0gwUs=opvD#C9vd&wlHpG~xL_aRZSC#T1TY;2;P)ZS3*+IuN(iAe6FgrAbObQ(I zO=0Y|LkmXu*;*8Qiq=F7A6=mr+Zx3sm}Xrrzlc&buKQ0?ug&Of41pVJ|FSCnBB^^S1UGnjo=0uf<_$J*$#KaJ6 zkPtzaOwl zTG7EI(=|i>#37BD^0na3X^r=&-j_^&q^Lg<>&IEs4;yTNmuKh!8KNx5R$Em2JGvd; z9B;0ZW3|ML;#J&*Cn}#;XW0Y>CIC4{?JCASnlaAv53+sY)GO=1Xl48%XW@5pQ z%CGP(IT_YC5;O#PE5ODdvZ;>!MgOapTUbxI0Q-#dSxlBA-Ciu*0rO>{u4GD;S+^)Nch&TsB{a;(xN%f%CCXOnXrTCAD+`dh3c zUw^BN)mvRfzA4(+U$=6z6nKD&va2kAv(y{bQilF!=?tZv9XtZ(jOx)F)>4MM-_gTYd(a>k<4J#=_pXF4w zoT=OFb^7b&b$Z%Is66|#U?P_v#33PbENGK_W^t`p%y2`PVDX(zk&M(091^ zXwQR+q54M*-mo|2(LX?4q!n1KTPY6k1{I}?;|*&mLth+kSV)Xe&&x@2Zvu!_cGYqddhzx^3#$TruZ1;0 z0Q_iPmN!5?HYzazahO;H;g(rI?w|sB?L}_<0CAgDq1vDo=zE}xx6ik1dVyazQ9p1W zO;CQ1x~M?|FPYC?^Z9eDML+Oh?Tn^14Pwi!7tGK6MGjx0&XOl)9$Xhcq7Jz*FFQ0H|y})eCz!#dR9tVZTGfkxi z#EmT1f%wQg%2zhjCeYW~(VuSg6(F24od6-s=;eDFj^3@zXQ;|4MqdTODUV8k5N7o9 z5IAuBjLYUFZH!>W3Z(N+Rs=USM>%jNf&BsCD2UV2O*Bi9X?#Nja zrx)n?oVJ`^fbTZ?9*DT@DPtSRhlGV27~Hve9Cw43O$GRE6Ab|m*SPbprgeg4GX%tA zuGp@GuP_f);Cn2`ejvGKT-8Jg``gjK!{~c~yr?B#1zFUfQ4H2EC#Vnl66*n}!iko?PZ|y}EU>$f_VW`#{w5|?{anNw_d|M7Y zAe=Ib10l=?rF1F98i&5`%Y=lz_}R`BX( zU%W0buT>zNGW!A{%nv?Vf!@u&&|hNoy+AnS2m(Tw(f3*z1HGGl={44}a^(X&OZUkN z1~^|u^40uB4I0l@Vdk^mpmm{2g;0^(;7CRW5bKPqmf&)I4k-k3ng*V05%dF#^pym? z>s(K7tNtQaHNoY2(sT6^YLTlq!PSc`+v60RpxbQr0?$(!cRgsIs`7B3Lr{Eu}j6S9PGnKdR(-TzVB;87% z0#8;^x&ysoEoJC?%NyFSp^6@T*LXww7-!MY_k-qPzg?3Fg;U!NmUb_YUoMR+EnV86 z@t;8tws;$6v68X}vI91Oqpls29jj{ABV3{v>Dt|70Tj*xQRWe>p#^Z@0NvC0P!yyyo(&Uv%9y zmm}kkUWqw5yw-9k-=%O%5Z$Nn6&6bQRSMs2qAF>Hzg$@b?l7$ipY7r&M3Vd*O(&#P z0bUm}1ujw16nPMG&i?z)KIpJn^XD9XZRyCicatyD@UvRH=(;PezT%}fUWM#6mSqo# zZwR7~D%>1I)FS*9p&sB%Ez26^xg&_)s&GRPQL%3Z5%7B^s#39WR*UN13i%b83~`G1 zjG%RnLVn~gT3jvj>mLyTsjqYh@Mb00TW;5P&9GYAU*qL)5)&Z#bJA7OJSwuNAZE`kaLp!;uH9D-8C_r2PZr+ZLvHRL`L82 zsrzJM=N}o;(XX@g>T!Cp%GlCr?m&xmsCSq79WQA2cX_?H=o-qQcsJ6MtkR;eW|Zy# zGJ~g!;|*&mLqBr7VI^hgM~*kNm2NRqzx?oqy(y1=1-rVG|F=%JQXJr&DoPi}8`e^W zzBt~nk}~wg@rKoup)Za%>`fW^;%v|gygL*Jc+aTC@rJdOp)Za%tfUNmalBzQW$24D zzm)&?0^Q0002XICKUsOhTFTJph~W#>WAd>GN>Ix60T8=vT()ONyO2-O(C2fhhI6fM z#SnO-iqb~{hA%V28W4hUrNx&vXcXCe{IFf8Y{}}NgdgFb(V&4JDH#y5=C>9S?@qvn zej#^E)46MqrNb47A&|=hxy%QyP_5Cq4l=G9aM(oMz#^BgqUx9SH^T~WnTh&=MJ|76 zvE1h-d$LDjrNsSSui{?e#>Fc&#-yuQDe+Jbl}nB1`WX!xSE*3?3K;x}p6<5IDn(r5 zh#im%8VLdTh-#<%7%uJw$ruIxNDZZOz#kX5Y7JU=NR*f$?l-P7aEFO{fDp>HEHH5Q zsJ?A>Dw<+z^*ZoY6Ac1yQ&GAMaPcJ}DFd)*=*Kl5sd$HZtOF<8I=maWkBagjXdM_7 zEjb0yf5PZ%K&&z@AJ;e3;P<*s4%}F2OzDz10I%YX5loI&Aj1*(bql*6_@64uOF-*K zK@qxm%lk6YH9&61$lY~duMyRN_{a-I>-(nI4J3$kMTzGeOS1wD_f2|$xXHLG4O)1T z!xLC^>ZdxKKFyp~f%J^LX9L7d=Co=~@sM~S=P9KftHtP)+c4QD>8-8u>^)VH%WHuI z#P&=D#w0gf!86r5aYq3&{v@@$M&su>l%7kJ!abmPm2PFQDYA_>o7;c_e=>+nUqNiv zJYulJtvu!$V=;tVZ&e`tO}*H|MiqQWx7p2U@MlyeQy=iNDv}o>M;bJ~8}t;}W;FU> z=JMW2FWD?qAES`B7P9eFZ_wheN=WH}+~JcU27F1&R7Y#XoKR5<-^WoSj)Tpr2S_ma zu}bSCQ>+1pOwefxU#CC-qv*zkx=88xw$N^=@W8{!Jc}E)=w6^ejtby@44YCvaGHr~z_+VN z{R+3kQjl2mDk` zZa)Lp8T}v-!i-*ihp!5O9#dFt%MKYyz=w6GWc|o88c<~p{P5zY|JTg4%b##idcc&H z&S=p1stV=Q0fbC`OZ>>P&ctOLgc!)}ULdxT!%o+8JXZLK)v*qI%0xXte)ExKUT@Ii zaF?|Pkm)*C)O>7%(~p~nnn9aI`Z?@zlX2C|=?Os*Saj;wsW|sewXAq^Qmlc+Nc?o^Bk3g)4CT*~vbeAwpxo#d z64+|>aZ?>u)J>LKz(8argedDbU&8mOn_$=n42DbOv|%wTI6ym|^K*W3p*7QnMFluZ zMY&=-I4MPAH88EW$1JC zhSike?&R2;GW4f5@3Ajs=wAlCRI7Pas4DQ4DoR(?8`e^WzN+4^k}~vF^@i1yp|7ep z>`fW^s(Qn|l%cQcqEi0ft8^=475HiurK{={-$eZ9P4C1vRA{Ap({%hts!Y5ZJ;G7f>iDC)r%Zy}ZC*Q<0@!283(zkS6=$LAK)1KIW! zJG6oGrX~&C3nQ=)$#zCi97rM43X#0DBi9oCZ7XQpsKPO&g^A#{rGneG!UtDL1h=hi za0@kDS*ro5oCLRJ#X=2=w~L!X@3fk5y2UvqeQxv#*^U)7YGdb4 zHSCvJCJR61GFeC_^Fk&+kxZ6LCWy|myce!j7-Al_m=Cr?V*pqf&70hSNn8XcQhUTw z*~gy+{gS1&;4zol0#dsur1prUwoFn(bf|UG0wCQYe>+Y(X;v5Qkn-}bL^pNq zMmIfbxxCN<@4HOlmLQt00h55tX28=zE{{qsH%cyu&edI_ylOexsG6p`k=stotJYh-fX|dFZ_>v%EFuo;-KBMr*LFA9M8cFnq@%e-#k-c_@ zC?ruMiLE-#$vF&InEANVW}`2W*k3HM#TMVta)qmdh&lZ6Ao{bysdn59F%Zc{esc;O z2#Nhg63afygeW97L}G{9s2lR5Zpac+kjQJ*N=`(>7I80-`ZteF8U!kL_JFSlF|U%p z@ViuEMigT1C1xgTAs}WZ0}<^;%(qy~C5ySvk@D;y0{+@WJ-+aDlDH-$af>8zgCv0{ zBvB`cuiA*J0}CT+_HJZxn`JT1;-akZ+TavoF#h3L*Cs@SIPaeHX5tI!e~6fI#od;v9DNSzp=zB z98+JhkSojro!UKe+mf$m6S|0iOKpH&TUzs#W)_G-78SA}ZuUYYPdWkoIniCC7;r|m|O*ICFFi*Jxeh&P+4ev87w zJK@X%{}Qw|DI^>D@fPrrkk~p&Y^5ZIC?qyWVo$S)VUQz-!zA&ua?UE3X~MEF0CEX6 zR=zF-hDi?Y9q!8LmCCUwZ~?Iwt`2a4>nClwP!_{3aKZ2qXULV$$`Aw)d*Rv(T;O`N zEf>mSI0alV-02KotIppLf&gMKT>FCyT#vQoLRk!_f(wREIKwxq^S6c|fY=MyA>abn zU)pk^EQT|{1;bU8T3wb(_bB4U2pL~M?1gJKxWIKwTP~Ev@F;M>@HS`oF%9BhLnVON z3)ivW0@oYba-l4SCxHK|2dW$$TUXE+YZr?PfdvO!U8z5(K|(4O1MZN7$*DV#QQsv5rLcp;Tlfp6STPk>tRr!C^R1;~T*Pyh z#pPamj8!zQ*{&aB#Z+9ej>PrxR9wV!j>Y9J|6&!5>nImjteA=`){(dl;Lc>RUc__0 z#no5bo#9wT<2u&G6)UFVighHeC8@ZG=R%9C8pjo@Xk7m9y~m2FxMCfN>!DO!#KX5< z5*JRfipF)4t5>X;iYwNUxK6t`F@q6L#p+d#>lLeLT&KCXV#QQkv5v&`mQ-BCQ@6MV zB8iiPVw3$+4- zQ~C>7q^~6C-4qM`7Nf5MPqPHez#@G$LGPwm=pQutUSN@{H^JqmSh&blo;U-GTzv^H zcVzk!w&9A0JceW;&!~XKAp9#o7*a|(fPqCre*j}hu5Ej}U8upZ%_wYV$RQz9EHH4j zIXc>LQKUVyDR!xRyk?F}sR&`6R9bWC+76j+^WBK4&t#p6O<`BgI!n1H{6Lib2&L&` zR|JLLB^Y_<`%*A`*}?34{C*wt^Xxcs!_cd^69m@JRu(xy+}xd5WuwQSDvU2ovoQVm z!Vs;*l*%shE)2ovYFHV!f7#9(+OR1a`V)jVw6R+>^d|@m(HbQidM|Z?Sfpv~H6b4& zatHuVG*LJ36cuGf@VUU%VTLu}JQMW*i(EcExW<}c1z0rnJ%Qm`8;n)p&rDPX7PD8v0IK(>}-F=&tnPgdtjq z0m!Z{?ZngoM2GqmN`+baki!tIgnxET8pVICBZZ46OU$R+Sad(S^eVf-;-frn4 zs16)Ak>j%)xQB|;2P0hHHm(}5!?=2YMJ_+M;Cj%wD!`(lAI=!Q*bJ+{e>YJXSmg2t z2iMoLhW%Rx~;Ch-F+J{h1G*Jauc2E5fo13(D#9-|fL+xFNbj_dDMLRmdc#V}&>x82u$nUT9fsjuR;*qi z1kxA4V%qKJ#SZ1l7GB`vjlZhMZBQ+m?Pq2cr>}yP+5gkM?aRcJFtZlEoZ;7#5fU+Ebw%o4|uqG)`U-Z_qeFg>4R4-8<9R zYQUpSR0Tf0z*TF|V(80U11viA2m4`4!?4Q!5X&O@+92(t%ySJ$1gNTpZDPvtIc3Z^ zR=(LEQzoWJXesQjYK-^1#?+-)1ixaVf3OuF7*a(M5lOryGU@6?4H{629T4{H1%$eM zF%1{QhCJrqLk0Wjw)yQr8vC2@+K~ngJWVQ%+oJPt=iK0soTA;aU*h6;msEhKs&0B9 zd&64F&=1D>N_(Mh#Ut=}qk8m)wUnXvSXNq|Aws!&=JFd%RR>U#?s62wXX; z$A6e%HrL{ESY1w#V^l_E_BByNocs3BT@6*W%_>E==vFcTzD7mq@!<_?DMMeo4NChF z-HJyb=R#Q+1AnSoc@VUIZniy&Y_mZToH82$f1=I!i>I>pm!_k4?6mPXmLFKKeRY3kM7khvOx;|s#T{9{JM&ob0Lj~f*#eQ zJ5uW&GQv&KC=Ze?Hs2Tarhyi`T`z@##q*V+53dcT=<$7YFJT3qoiGpjoAP8H>2lGfXTq8<>oforL$)PPv$1CUnWsu_s_ zxCkaI9+)3(*=Y#DKdIxwsS6P<%?1H6qy+=fp@eh(h46Msl=t?XZvTUVU{EK65}re7pkavVxhtJOe9Yr z9#bV7%_a8o$`x=lstp>>2QAV%@C^N3q67szQ$_hWiYo!vmyN3ipR_*c1O81#<4QM9Y|z+SJ!4Os$R^1j4wNrZ zts8UFoGzh{yPPn7Vqx4^%JgXS*$&AS_zMeT@x%rV!tN~P_OYM&8s;k9%9I7%)R8O8 zgP+YKG(Mxk#MI`gYEXS&*|VFu;4Wp#M=q@^Rhnsnhg&phtt)7Pi8AM;6=HV1?PIPG z^LXW#Pb~lmGNZ3FXyHZ_fx)Aj)x5_l9;u9cbqI)$%wsj-amagg&uP5JUhlC#<+0a1 zUSY-P2htB&XuSZ@a;JtqtBjAQ{SKACL@XJZ~DI zQ7mwurHk*TDvb~b_X{kZxWw5k^*Rj-PjY>Wv-2(Y9$>GE&1CWDN7O%kTjBSA7K^kHR+?|Z5VU{)F z<0X@UaU*9|AcHGY1LL~+e1yhmanP6Fv?|sJgVM=FOkYwG5fQ~dTPb!q1!aNakGy3Z zes~0r1l$zT7%lpbXw)J4GF2eV8)kBnedZyBr1`CAaUTINm&s}gNK8fb zIJkA1_}6SS)d`MBZhsCZjMA`$(LbMP6DU@sMR7kkOv44#1<0{I6+B{}obuLg60c^N16nPtjd- zOr;K-Yoc!8DJH4|PgPNNBJgit`mj$99RoRrpEmKoXEeEiiRLRI|&(ig!xwGX9soBS0+bQEl zR!=@&_XvS_aV7D_#P@0x|7l~h48*EK9>Mx=m$3IqH5@hk$5aXB!~{i;>>s)}jun;t zOr;LQs^kt%Dv~S2DGeH5RAF8%T3-v+!2d2<$HlrycYfCF27q5MQT^)* zp-P-J7pe;3$N2#`{CFTZBrOWNxko|gk2@QikkpF zs@8Os%t63Huf@KxV%*8#0tPGhG-ZeS`lUr&2R^Ez{K$yi?bN-04u-(LjA~fY*V6XX zt&9NRUMfm^oT4Gj({1zK1C5JSD76A|K_#bu;G&`_jq6mH-8N8Yn^lVL(yaswJgViv zm02iQrCYRRQUv}?cS#35qVTaG0zRptPWeN(H_1zBw7cvP+Q0;bM3R_JRw)a<3-SNR ze0CGYIOFd2+-@Yt+#RKfr7;aW-DC9qKwdhKIDtP6S_Hw1+;TYkAl$Js3K5k|%nMj0 zY7nek!uM&gU$&sj1RbmxYN}Hz@d<&o}@E{d+%7Qa{-H|rWRpgZOF;)3Su(o^@;2>D_dn@<41ywZip5)Xv-Ml{qz1hzK3=`cqB7jg*bb^J(2Sr`6bLtdx4h9qS~1AWX)GS$dbm zo=}-?DrI1>a);&xs$JJ@swn7OY&uI~=cR4B?}xgT`4YI)R_xut8&#B_uV{s(y$jRR z*PuU2x#XKHF9Tm@vc)AZ?3rF1{?k?e<+@D_daf@~6_qLS`GzjEr zUp}qS;tv7HNCEOlELWuU99`ffhLn$^MjT(ZI0k@t&gg3mTH}p=0Ep*YkyePqtyy^hAT6h*ODmF!=+;r2*}e7zY;RYtlayo4s*yAaJ6c$9^K|*aZC7P&SDwb` zw%Ba{-;4qKpDIspX<%*F;M%Sz;3%Y-Bh9L=*`Vpoytdh1rnSC4-@B2$&D!JPSL*4a zw5Pw1`46Sz@}7m2UjzJKmj@mW(9`XLbRP0Sj^>cEZv3Cr3?H-9*X93vzLu8e&6Ynj zI5+#JdCbgA_7vWZP_J!jxw{#9uhwgLIQsu+et4U!USIM*t?HW9c^~@>lXb=4+3NSQ z(%LD}aklH4{+&MYwOV~n6rX)-yB4hNT6=;Xh_;!n=t$klr5TWELS6v^eqXiZRkzI} z{NiAx&i&bS?Ud|q`pAFdrZo`1UUv&KkV#+urjZ2#AfU@Epek^!i53FS*AyqopZ}XT z`?_qL%Rddox0&xjAU|}NBv0E5(IS46T13epe!CHtfrVtcNP;cNTw{^<0y)g(ul@qx zXUP-?R|D~8-7R;Zfg~m8ejtfVko>yl&B^`(HX@RkARVQD5%g`y+IRpPz?p7;&1lnZ#P6?FjEtA51!h7lTr=KQ*% zbHu^9dsPAF=ZBnDjaU&BoT}S1bSqa*Ko$+M!UEz=BD}3F6+cW#yz>I}F`ATk1HM#6 zp6hSlb!TJDvG(wh8A|T8B>gMTZRY25pWINgT+Lk-d78snX`K zNL<`)Qg(j$Avdak7uE8bXQOX54cjS9y@eIT+y?Dm(Vl%7&i-vyjJggT8ylOta zBqxEjGid%+cXwrCS%j{gie#R8YVPUI_8>V`_w1S3$ezq>3c}|`JL}m_guKDJw_3{1 z%(x5r2E9dI*k8-`BcHD~gr@}iHLI6p8tggg=)AB8mexEnEQ{IA**`n8e{wzc4;+{4 z?N`tEBRhN;;IXfpoK2N)PLTT+(-IW`Jf4>zCl>VM zLuNQg={Kxs&?0p43M9&`cP-?R5c1|_G>B6|0Uj7a-n@(krIk|yun_WQ7cvoC6P)fC zrhz93Z|gD|e=KU^-_qJZlx^SRy1faGNmj)f)c-5tSn~-zuSjt zT%tlL3y?UQ#xx!-8q?^s?kxk!r)f-siAjXp+a|XoB)4j1gBD3jazKWwux(sUqmc1d z%b0Eu&A+El=pe!u^R3Hh6mn_bQCmYUn^rbxk(1;CBz$qPI+e>N%jJU50o#_*pm)T4 zlZ~$9jSsHA#^Cc}8y2RXSbwwBz`_YD!wSx&v+zf1QY zR9dnA=2h8$mo}OdD5CITRh-oP^kWyh5%d1&fwFtiZB3#k6MF3bo6=Oue5X zUm(o(t#!8{4p4;|y3IcLC|5W%`GY@uXX2iZ>kMTL^BDXOCKI#a#AohmAyRn^H-z!olcd`=an78I5jD!sM~ zjr&#ea5P5>YON-y^0!hB!enh%t0D?#O~{YnDRLpysL>J zW6!awv2U})tCkjZ*msfY>~A`2ZWBdiV(&*(ORfPoiizU!V4hQ+bNKg9d*--9zYW?hGWH*?di&wD7(P4as*;b4J-ZRv-*i+E zq0FiNG?!9x%dc1|`%TTgV?zx<=-sDdM%JL)mvz$mhDs%lRZD-NWh(@?(M{9vU7(h7 zmJz;LU9{hza=AMSyl7$`%>Js{dHVFZvvaG?nGN<9yxz8y=-IaMIt8yoA&+gtpHhEc z(0nGz``3jVpm4Hn!#x%5YXbMC;nS7#dAgOtt#4Z+j#H@x@LVfT1-R5i3xS_2un*Jt z?;zaJ*5%7pN$zw3DQwpB!@6Q1_fm=MN6fGfc&mxZK)AAA&!+CclOx#fH`88VWa`c< zn4*{XK|3l{W3L0T(!gfKfid8x>)4Q+o8g8kL-4M!Gu#$sG@Y(aTPzXMM=dv05q>3D zmh6Tq2itFTCpS)MlaSnXigRIA!tbQy*Jb`spL?Y>?Uz$9$t3cb)Fi@w{@!VF+Da&S zk1+gJmmuvt#(GJQkQ}MwFj)w%l(?9Ul_ab$rV4?lYs_O}O`K5jYhoA})9pOQdQu3# z3TLoz`rln8-#;;vg!OQ$5a?~vv!YBcJBB-HeN3ft1q1xW-uW<=SN4FvHBkllxQP~y zWx1eRxziCJ2n6wbbJq>L-b4ey=T6G)C&{~3^RnMfH-9|cK>U=s?!)y2b6o*a;W4F! z?V{;6*F(U=)U{kC13ziej7T&iSv2xb199-v+s@BI^&_3VVVK6hnWq}?Y)wpVt8W<2 z&%Lsp*+3p#x!0X2@Uzubc1bDI{tVjVt!7o=o+c^-A5xK=|C`o%3^|4a<`mn z7^kmS|1GB)h7En%Vu|pz+7Gg`BbL@!E*KhFFstL@W+fh zm2su5wm)h=@H#6eCCXgGhjzi_$*^+dH5eQP#>Sci5?<3_RLO-wlLF#+$zef(j)j#;}T;;CQ@crG8F0f$duPWL3to`zAQu9Ep({5>!(EDX-34`9l zS`$ggR%Un%2?&ys&b!JL{1z)toFzTcxPf>!j{gGxefS`(oL3C$-LRiv%{|W zj|=gW>c49K`+#)Tc==tmc&ABNQ(9NhiTFOC+*r!h4iJ)f86KAhy@wCT_sBGte0wCJ zmz?HeJvl`DBNLSFv0*R-+@zxBq_bXwx?8u=8VK<_ZFkEW2r;Q0oe%fxOJ~hKygBfj zD7!m2Gwc7Eh1FHNDjl<<& z(Jq+xhhTO#gF)~q3#K1P1Ts4U@j9V2lFb6yTcn5xr0^E$y&Bs$LsmfQD=UPpsjC}$ zdy<+;@m4R(iiZG#=+)77dA~aFJksPr5O_vi2olc%OU0c6QQ2q%v;w@?tlU(C)k{pJ z+Aaq|l_R#D$_>WS9jkD#F#6==5pFLcWHiXmaC;HqlR89NPCN7m^=z?3$T2B9!#N2d zMS%x)%tk1)Cl@Np9j0G~9G8d2rp5;EtUjM5G|Gn zx27!V-5*&xOPlK{+CNpf3 zE-HZdmgknuyHoiMvmDB@#;s`1SBl4sss?=0L}lP}v&WbA&;e4J()RNS+MimFgj znb3e(P1M1Zx{Sj7cBPTI2Z*_>3AYW8W_yGdP7ZKj!FK(qwkXQMxqdhvKJ2{f5C(1f z;7sTx*9NhkINh|YozuImXS;#Vw>X+d=TzDQDxW0R$Av2u#4oblEw_mg-=VvoAq$I6 z88Bwxvd4f)+%#jv2cioZFfuI+68{Lg)|8Kv59(sKQ~bsc#Q?V zQUaIz8FRCL8i=P_;1wVV$Tb3xpeJO1T4vsy?EAln7AwJo{3lV_E<~?4?ml1`?J_zO zPox;d7g!=gz-gL@9ErdOEw`4Zi-@0PB_8#<448TT-ElM7 zJf_{-a+c#*s%by8>}0$?klIOy(=RQS2$|4iXLvsaA=6o>%yQXzjW+Wb7nZcI)Z)l} z7a#{j^Up5{1#ON7nHqo``>@9SL=AtYUfNv`CiIdEJa{%9ntSRj?RCy~$CTX4)9a@M;WeVIen2My%2XAteEGdm?Xz~blzzSl%m;B+O;COq)5=BQ=$lY0;U;waRl zC+y5otRf?8hnpW0N?UeE$)68mro`zt;nEpTUOB8;9CzqYcU!o8LKWfY7lwp3h!;jUPLVhb$ z__^J7cczDqUs;Lew)C&7pd-MhW;`zAU)jiX6#v9V>~^^6v!QP$-J@H%-4Rp&QFrmh zO;G{z-e%Ut%S+Q5u_;~3?`b83EtVudo^1*fN&5F;pyL;!Vi|ss#?L{U!UUbajDqfE zGxE4oUzJ;<``)ZuNgjBwin=8EY{>ZZzoi=g6^wz8?$VePmgs2b338m;i3{jB|-?%)|DWUYT+4-LA z?i+Zm$^54ku|sF{*wK;@R<{jdk6C#Lk_zw{DiXUL%V|6_2sbP_TVuRPw{qJKh||P7 z=R`kjE*AnXHll&5!oDB^2JW_Hf4_0}0MA#VY;{w(KtfF2<=6oRKmF}`?$_pL5cpdY zm4Sh1upQCg^Z=53n!w{VV5$H1B{Tw+dtycxU8VuFobRY`BkT+}=O_^=h-LWv3Bp4) zoEF-61Z01PC%dL$7|@F{GJy0Vj|XVKI&^egr2DiucoQ}t^^luuJC>(zu3?K}VsY}2 z(sx+T)qq${E-jHIvD|Q&oB!iZBEM9Q^~TW$grhUNG*3Kh!2R!R2$X@CrXDo0@55TR zv859m;7gClODIFf-wnj@#-QZqg;+^03m1H8Y}_%W5_-S3-mC68Cs*s%tpu@i$+Ohi zdAgM@1QJJLs(_umWOf3+QQ76r5%4X+;i};msH0kN_+o{@p<71a@Y}}T55!t-3aSiJrPyt>n-SlLA%!d}=2} znW#=$EXnGyurn<732ScH8E%mHmu9QBh6|E$T*OZ?(cDJR|<+Pm$kstHO9#@YtEZ}Q#QLa|8cX+50v9W=DQd8 zaTAq+*DCFJS?(t08v;Ttaf6M7-g{JDyYvDh)@nCL#CqARD>aCTeU$XpD6OafA2d-Nc-fJ85i&pFHMj=iD|EL^U%=qHHy(SW`8M;@ z1MCY#z|WfN;_0V>IQVggcI-#Wxn&8S4%5nsaP=?^$fEU8oWO_%{znZhJ2ip-Vi}aL zQx{9ElUnYcAjWB8?#B^9iwf{vR=jTDdrVXY!Yx_)+taY$9_)a0tW5O40+m0&p+YG! z<9HP}&!h4QtKk6f0Ii{1E(7tES{QK9oTp4Jt2r|Im#{O;&5SFCM9WeSAwAndi;#Y8 zIUmFaEWdK$NPU~;$GsNXB$>F}|Am_T=hO4?nR;&_*2zY@n|5NQc5~RVN9T@SrdwHw z0N<%1nIu;)@1*qsjZ8)Z@M9(#1QLH@%v`9n-!qRrz<)EM0pJ%*GzbjbZgzlszhDJ? z&_r(T!m8U;76OB>o_NB*>RQXA8~7F_lAhVNl189f7*kQ(`<1F?lu?`xC2bkJWOruR z8CE(Zu{7)q$3)zDymjy~RsOVY<*qo8K4D2hn~s5k_Ll<%kRouA6jy?xq9;?su2mMq zDrK$X)z&pt;5#&?$?{3b@F-VS6YRjVyurO?Wq#XSwz7h8iOd8^lYFIxbf^S-0}c z4tSP{YUe5>I$09NU4zdbg`xrXQ-@*&{HBVcCn|^^3L)-Tg7b?ko(izrL_NJOM0a2l z;_ocPI`Bpdu?jrr*gQpf%(7F*i)?2$kRPuOqvZ$UP%3xLMjR7EmQSptK`+S%cY!xq zaNWRnX>ihqTb9sxuL`qsESNAP3;FJT^Q#-O^*`bvrc;71;5jBL17RDp~E47=|&}&#;)z2#2>v#)d{qSSj__J17XOoPdi7>o7DEXB^tkiBM zLJ!X}od74DmxVB_|F6)k%%ng2@?TRPZ-id#QySC!XU zk1YUVm0UkOs&*r0*9W9~C(Caz!`Gq`w=Z_O@Z4dGn?I|n)B{)uZ-ZMuu=5qC*rDx@ z+E}UGQJc_vS?Y-`dgYVM>9!>_W@{vJ3Iv{JqMjEhB;Le21NQIQ;I0FIV4^bcP>n&{ z0cV-047@i)x?w4eEkO@>hDAC+q_rS=u?xN@KAs8w#~Nw2H~?Q@{`!E2oop3cy_CjW zbrapkKpaX}Zs+}%>b<#qpg{-8${DyUxZgHR<26Cpe!P9bdZHV+EjWE-n8s=)lY0!n zy)``v?ulUj|Iyx7ZWjuBMT7P=WEAEM)BZh0m8u$s_JGkcJWr| z*wT3o@SM|Zxcg5jVR)`8$t;zeeG+=f_e#*ixlA>{O_pi(>k1D&)k0f8JYGZCOSdu` z1BouN2EpNrluGIdoNPpW`zky*h=75+CmzmllYy*3fNwQ-gTSMWy8;Z{?l^$^TSheW zkiuZ)RxVim%B=eT;H=!Zr`#`8)s~e6)w(t845OFa?hiY|Jq+UgUf3Bd!YbINOHC z01)5u2t~dhoLIl$|8C`wLIJUrxVI0-`Lgqu&&>C%%tUTbqJk$vIVH5QMFFZZZD*BBj;mOR6s7zdGOxbZeUfd3f;hCtj2ZVX_jTn?GD6m4{@wost;tAN|BIj~rzqQWCyNx?4_Yogz@M3F{<+A~*OTDw|brx58lMj%=)6ZdU!*I;;M8KA_zHp#^DK zRZy)??5X;1H@iL{-Mh;>8?$(`i!dTH>wZJ5T0 z3Z-K0iof29Isp7_pn77MMhKz59n}wPfK`EaSOD$}OW^-*DueBagYThTtGMY3M>m-x zmjT1+PAx{ud6EJ0*VIn>mx{MoB78_ax6Ept+T{#kPNKAD>i)veW;}AGPdn6SAg&L) z&QUh`CEbY)8h@IftIKiV&#YMPcaACfLpWAycL<}0XE`{5ud+O=?^O6(3s%m^-_am< z=vL-xAfYAB$T&RNtOkKUHc{Wh3V#(uz`*T>CER2n*ZIJ!jc5q?R})o$fqSSF{Rj6( zv+8-j!eG@C8I`d5oLTih;H=!Jr`$7DRfcCcuTrgrVP`n6lH1$D&R|Kro5Idu8TTe< zWV)0dkzNMUBV6ax4)y3OMgLu>11PAtS>Xk$@|14nIv%D^|7s28~2L}lO!=URC-ETwU>3T5m8H(8_u zMEXDwZFj-DBa`5JHHPe21Nbu*S08X)i0ihcG~T0bqQwE?P&&6b!26}@Nk+rAB{b+D z8Tr891os<12d7`WYm0QZGvHFS}}U^UdPyDl@Ug;zQ&cQjM( z`?N+aix8^ym#{M|CCKeeb<$!@J^BnyX6fu8h!or-fGioWjW$8vpv?$F=b{ z-O3pSh>OI!0rqaQ8Z@YZ$+Xj?)xza)jMZOS=d7!cgheOKAiuHy1!vwoa=WvS{h%L$VKa&>Aa{Y%ALED@fg!L^)9DQs`p8D=!b_p5X#r&8Llv2=TYcbIB^ zDy1EY=MH&xo%=#N9#*+iDM~}C)b7wlZ<~cy{hPw`USRw?mdsI}V|6R@3=kKIQz`5# zluCZT4}69ZEjUr(=|Kbx+-{h`z1g^jfX^|aK42hngAt-X8&U5#B?wmTynxjd^VL7q zS-DY7ZLd^cEd!6z+!J<&6C%0&I_wMsFYX=AmUIynmR&xk5=P?L3$7QNpKjo^Km=T;BDo$~tyhe)o!LMh z9J$j+>?m8t4dd#U$}7UH!!(v_5u@b*;^3>=uAUWT5ZcX4Xk22nE#IU@yjXY3(g=tr zq1mvqov#&Ez$$QTplW9Yb>ai$6zo~X;^tCR0*jkCy^5P98NmB!C$!9xjH;2;PP+a3 zshxBqb#FPbBc$rGGt93XJ$Gv6d~<+yNLLj?b+@Txo-U=*UwMnQvW|7j@g3bc?Jsnj zy*ISHb5>U)c*{|&IJR`!E_GxYy7^mUW2RCGXX7<~bvnfn#)>JYv5q)>DCHDq6iuB@ zbxvc&l+##8oF4t{M5blUaG`Exx&roF=ly<6-38$dYbnE;Go;#jpq9iVaNU@Er#x5y zzE?#ZrBo1bamgUF1+Zx7gE(9*kJfGW?Q8IP9^xi(+xN5*lOf&#|xrr*kBE7Gd>X&|RhBe^77vl1U zkE_9;YMqdE$E>mI#&kV3ZT{>Gk7?r5W*?q4#x)zyZ8nmW&M18=go2UxJ z?~zTvZzy3Ow0a#YFdLGAF~*{f%N>? z(hWzcH`{z((U){9*Mh*BF%1HVBJZUG3fUf5%y$1g+f!#ZFt}a0Cdhl7S-|6_H4wei zc3sOZL?@YS(aJ2`5!*>Ag30BJh&L-L3xnU-53y2mjwB|IoW3;kgQhf z?C%8Rdys?>-O`ams?$R32jVdg@o9w+4=IK?Ef4Xe5aOGaYl8fBB&{Q&x7)5o>_YS* zi=Yf7?s26Xwoppj5+2kO#oP1dESGUPvw;lmiSnTh_8EZ!co>^|>Y#mU+J*ivxuZ{^H>v|wg@^dCF_(w@d7uRy6RDf7#T$Ki`z~zoSLe<-I!c_%g zopDtYT<#Ddp&=#B&eC8;YFFu*Yd$lwuH%pf66Uq8(iysknAp-=+f^V}tFyI3erO#t z03>W#yU*{0f-O`pF{-|gEBsXu%~w{ahvgiZer@N#|n?_)Nzd7uocfKD)YGE53zD^~wMuz=? zAfhTq8c{c^gtLN(ihnkU%#Q-x-EQ19xW5}j)NY0m)t;^J${_OnQfue#PsTkY2S@Y2 zgN$g1ad>kOy++|Xf{6P5G>F={`-{0-2qakPs?8%b!q9X#R4CNVMzw%`xj%@2OD(1z z!VKK*-Xq+%7*Ri+aHtXWQCZ0(5s;JJcscQP&YDV-bjD|M=d7ugivrw!+uRQRLSd)*STIrHlptb2 zoDf8(D*UmD27#?n91=(IDYf{5Zc}GquXB=HQN%iOL*i!->y>HICw~4z{Wbr#$*c~? z7we5Jd7rV4_`LmR37`1-T8mGAiz(Ji`HXeM=Pyz|@x{e4 z6JOtI$ zDW9>9_*{_k$r!#+fvkIhzt<46LkIjqC@&Sb(H_-whfi_KPyjr8%tF&gFR8>gV zbZ4|}cm zTl{<;zsK*N&;8@>wfB0hVXw9KKIiN+ykF>{a;JGT7V>UuYJUS2r) zLa&pw;*s1?ZR8M&|IeBpIVADRh%57_{dGgSH(j^OKcx#mWM)LQ}Hh zrUs`QXpw6&$di-8Yeix4bM7>~t}H=AVnYVJJKw+vBTKF@AkVP8OoikEP&R@gk1%^v zA@NdlL0*&`zFr(YQ5>d;aW81dio@>I1c%cJQaj||H1Tq=4mr^JFcxyKHMKzwQtxEA zt?HqI>!J;EY3jv|(u)(M7c}8=u=9q;Xp!%yL(WVJZxMy^YfW{UzO5`lLlT~H!5Bpq z(~{m%`OptW>iNM)Jqm|DmmE4@96CcBq6ss>7vdQ)XpxI~NPb&eR+igDp~SaXS!jJV zbrKRY(wlAb-VjObi5(*?tCRXD+0UBVAa}B+Ns#YX7bN$8@1cVCvY0?lPLa7?I&!*1 zhNi1lXB9tkO%uHdwm0a^_U2P7B$qxim>{=IZob|_1>a;kLe`TncZ!?Eo-9o(l_h9M zhEO@8cA<*bl7n3u<=_`-vO(g5Jb@4SOme5#k~&q~p$Q{`&TRyv_QGJ)9*vdfla&j_ z$`Y|c)0@`mqaiUYz1uUlyook!X1!~L#Hqfr%?gbw89Zk$$#viRv|sJCb7PSkHKHAoEJ?=tLsxX2>vSzvcg{4oS|Ra8 z4y%wARo6OIpHvkWBvp{eR}QrmRo6RJpH&r?B~_3d`DAYdGHGvvtZ2W{X}?;v){}Nf za+!7U+tu^PR36RL6};7v$HhsRNQBEyH^lbVdDbPW|1g zwq$tBNGo3R#i6)5)>^vwF&64~e`ijgS>p-*u{jh+gPG*h6FA z+MadjJ$03AsV#j|4$$&}9$NNQjy!c%a5gXQoem5>;KNeeN8@7TCE?dF9o<-@VCk(bayA5u0OQ3T*yV+kU>9%@OsgUj?1xBAYozY`z%T#MYy$ z+1%3E%yE&;93wXOTNU&ZTfbe+rvKgW92eQlF=F%ckxgtpxtdKsK5|@SGslR{7b2UC z9dglVH!jCTHgk;F-1l!mZ0X-$SL>&LXf4M@Hgk;F{B2|tTQ9F>b5A#ha$ICH$B4~s z(VNeMqJFS8R(8goRX2(y0-E&nm0fY@_1}JHjH85{EI=Y%?u=1Ox;i2+i?$z_r)`i( zmpfzBlCHK!x;SLZaTyZna%YTM(&aAyS=1j$TPfA^Rp@+&n=Hw(uZi7fyAaPavexZlTSCikBT{T*9GT2q~K90vn zbj!4aJW9<}Hri-PHahY+1asirCEiLqR*p_q*l43ES#dLso}fj}@gZj1CZ^cQ6b z8WI~af80i!H!>C@UC9WWV>B_y$elWU@!l6@>Lu`)GgqdJ-4DFw^Xpe_{!cA$1LUq`%N1j6CvNSrZ&hU&AW+^8>&5t)Zcrk;HRvRkc*Sc#b#NtBSsVc3EKQp z0{6Bv!>y1zTa!Jcy1zBGLXJxAz1~9wpJZbI^2p>Kn`AV7S6PCFWGLw-8C5zWf!?K2 zPq^life(ofa%~5Bc5;VJGMX^bWRr~XB{{h;7`;bhZNcOWaO{?|KV6?U>RmgE-XH?64ylJQ&Yh(TA>`yH|GsE+TNu2x98DoZwGMU~$X`;n>uEMpn6BIkF+ zSpQinE2}2*vJOI4R5jiatAPBD81~Ruyix_dhc1a}M~s%emGgExVywHzDn8l~^BBM5 zkz?eF`&n+5X`p)x>|Ct&%H0hA3{{ScuJUt?*nFJ3$yJ*VsIAp^Q2dTqj*D#O7_qti zKUII#CboE+uI#7Z5zBFr%^V{(&xvee>#@~h>vzO*Tx2uHh|R|$o7no@YBv2&QI3mj z<`}WL9glKUW6RjNW;L6BS2f2)Hgk;F{A6SkTjamdE?ka_Y~~oT`BY?+m_D;wKmCqa zj*D#O7_oWUzf^BEw$SfULQZQSr&-fv$m!ZtY!~_WFwwP+33fnEwWhIUa8*;qLBv;;$e^xQk z4taq3RIIzu_$wBdpGE~Yq6OM}(T*2Gtk2^i57MT7wT1iCsbFTH{LsUImVJiTX~1qT znr>5i!xJ#vVi!JBA=k5}4#=c^>HRLacPRcRCO00#lsP1d4wxUPntrtfrmF)I1>!zrRhM59(Di-O)dqhkXudtL2b*Vsr`yUVNBH33~!Cnh+-YqcYw`_&fgQ>XG94RycTiTl*4{K?|q z28oZoI8sQtQt^Q0+!gX2%5`|Tg?=Jn59P8J;!0j_rVTQ>AfFykwiPSyLMks0w8j++ zH`P7qowbw`Z^%paN=}4VETr-|Z4?~jjoLJzcB;JcII>Rt7Hw}S+c)o1r{x=&#P76z zy*^&tYccO0^=*}qLjWW_>y@MOMC#^a3#rg|xy123pGeOSz0e}`*g`7PwQ;T5X|-KO z*Qs`CvkU}Cx~IsXcaQO444ty_2VaN0rd2b5t2hG6!*r60<;J=RohJge;+u zzt)ZylL-2yt4dsaghmO=c&pQ)lGY3TmbBq}Lb7b&K8nqiz^ips~ z)oH#du~TsU2XNj-TOQmT9t1asM19RM($}SD1i{Ta69zX2MFw+>82oEwaJfe9M_LZ( zT_Z=-ssC8p<%Z{wJT|#(IL&fUG|h61IQz{-L3CEAGr!W31$|_lmPeYnn@fl8=Ag*k z93$>dSRA-Zyf`P8u>;wuJlQXR?9!(4uupAX0-`Q2*)Ek6C&-y5H5n3xh5C* zu9i9v8_C%s5~)I$zvyBMaH%;l4)V9wG#>Jg+EhlB z+Mg3pDJxKamO(lo*;SR>oRBCiqe?BQcTq+Cji$a0@+oVY0*S&hs??Ht7gevm9rb@O z^;02HSO%I}Qt!6)y!r{KN2<`}cbe38Z8LMiHeIf5DcgECU8sCh8|8}nQ6>M9njkN} zxFSmBYHbuz$ggTsc`-h+PW|iJ-qL%KK2o+^Xt_O;cuMOXI@EfdrBivitu|D)Tf06$C^m>_!MDM10)JcN>a>s>Sr0tEt>HFGt9i^2iz`yu{-JubHJ?~CQ|;7dSz{o{z*_RHFG1!prk*@+hn%Q6 zDn~WIyaX*fbC7qYEm8v#BuJi87?gm{Yq4M+wB$*r_eJVDEsFT^=O`+l?U>XPl z0(mDst8v4CETWL;u59nngmzf6DMS+nVFjB)*XvaHik3qej+gd1p|(YxW;6wx4C@Xo z`>~Cd5;Vx|t*LFA_U$wq8?BIwtf{TfC8e$nwG>^D!>y?;j~gCrYUWxYx3s185gh-vE%76*7f>|K3bHsb71-BJ) z18Zu7Bo*o$RWhT_QQbNz$RmeYAhB~uZJ~sma6x{_nkGX&XH8QN=u^@MYbi%~Wx8Td zlj?v(p{(O~_E^PK9qqNZIwB!d8>GB+aTJp3F@_e;e0vlPFWd659Rt5d}7QIZb zth7QNrn-8+c8j)dGhnaAazfXOJ5%}RYFQkzPN@yweR!Rg^H=A5aCn_N@5_}_T=78P zZ|D{Wf+JLm2WP}B+#vT7kX3(&wYFJwSKt~N!E zQCyb=vK4Z!HZ_|f2Q{1`9~)kOSQR{}WijZXUr6>KS5@uRG=43Vax+7wq}aPnTYjiz zp%t2IZRsuKV+sqW5>|Fl&^wzpEQd0*A)m8u{oexK8;W@R|K9>$1ZR0~gle_Ewf|ed z<#n9@TflWZ^cEcUShfFe0gry%;T`cwz|fSJ{k5Su?m)lS+IFl% zf6Ur;szcAQww>$H7g^gbb?DoyZPz;VudHpiI`pg7_Q5*za62yUUWeY#+CEf==Jc~~ zZ4WyY{fyy0T!+5h+V-qNKVfYjsYAbMZF|+BH|twE*tfQK!|f7c7=(N$?cRsAlpl(J z%jw}{l$}8V-RwY%RKr=#G$D0;0(nh8ROU|-$ouq+GM`T%uW4-!*f1@_-tDN&-4e)a zI#QXF6Uh6tSea)hkk@pbGH*;Eujv70KAb>a(=*EaO9JgffHf+$8qB{ZkT=Ji9HE0L zoWMCKxG4r?W7X5AHr*T{Ps$pqWnZ}v%>PgWCQ!41iYH6caxEU>oI#p?2VEMYhCco7 zQoleTkKCYaDo()0)v2AQtpbGn=W4**Pb@4@OEOC#H(0v_7kkBvsbHuu+hJzUR~x-h zDpkY&!4?cJGsA6=*eb3BL&I&6;X4;chW+Ds7+!3K+aa&EFi(c8_P5=cl`DhDsNd1R z=;zGn1jtn_GDNXsu}W^nE3pdIXDp# zL&YeVSf_?9xeWqYwJ^~w4_Kg!^39PN-NeVDE&mJTS^_!sJ4pv}!veWsNus0zx%UNf z@5|+8YqrPRtUMYq0uwwCpG(Oz`ok>W$n`en_I{{$6WA`6rR&=ogyojR>ABRQDus0K z1-G{SR?FhYJx`O{2h>qJsBAA@rg%s#Fo9qjEvQ zL8kFCrVc%IXlX;vqahE`>D<3I|I8(IYRA|lZ-qQ%U1X1f{Q7!jQ~%l`k)^gmTV>uu zK4DEq{cHVFW`w1?m2@*jdLuyPbi+-6JV%>~954g^u5G0&rHS-^fAxK;mW3qrV(V8c zXx5ewcLqV;a{~uL%Y8J5Uvn__;i9C4puDA-2{XtvA4?G z`;T^F8@1P`=1zi81hlWLWVtbT{Z&nIN(MbRwYl>&F4hr-j z-#i}2sW=G}iZF;1e+ z*GH{_gaNtHjP2`;<(NPX;&+*v-JKeEPaDSP3*J8rk4;#j3 z6y8e1_>98)hhe-PcyAcSXB1vPJ?-mT^BEneybTTGGYW5O!}yHC+rcnCqwsb&jL+yW zJ?|W4XSiMYqB?M3*}^jzeQGlx(|NI5ijf+w(tT>3jT8?xh&u-ErmT->S)8BcYOt`m zshOTbV4*HjbEJyTGE;uw!aJb}=0fFNWf<==yze!^z~j}v$Y*#fo9OumJk4+bm z4MPjn&0d^$wC(MCJRaXukH>pO;~OdZd-6SpyrHc129=!P)oEBeDI{7$;O%Z0zwYg+ zyu%ISkH+v87{R>4*l&KAeCe6Jxo&gF7)Q|U}6*xQ(QXN+#= zv*{H$l|!UA!A8R_PEkj03&<-&N=|WKfLnBi-AI{ZwCq!x-J#^X)MRiaklNKCvyfVl zni@&%VUU?fotc^%N$qWr8AyF1H8qktz#yGSeJV9Ik~-KR(~v(w@svvMs+r@`&Cc*x9L3({$@J1rjKPSB7}gWqZK5O-aLbearK zi-)*tCZyBka9TXXUBDsDyy{bPT0F$fr=xYeq?OHS@ens&kWMR|)8Zj+yda%cKBvV) z+;~Act%OdChq&>AbXpmm77uab1?jX>IxQaJ#tYJE<#bv+#Eln@dH>Oj7Z01uk7I7` zA4&o-NN-(%^xqi5qdQb*@GK2V*2|RnbC%~-362IQ0@!)f`mjiPF>>=(caj9+$qadn zLxRA3ORdy7-ytu3SGhJ_uVtUw@%duap}pi}COpBIub^|aj7|jM-P8mF@7qlI1A zb5;{Yi1UF#Z}0d9cx5Ir2}N9)G%HO1`+#A*Kieqp5X1QEJ$RE0_2yURm0t#LQQmi&VBn!InjbH!{F|o7&wO|TwO@T}9y3~byBWs&4DaA3m`#<3 zzHs8tR?x{!6k+6W#e|ArPH&s@EnTlWb%j!Ptf!V=LdQ$>~6~BVW_tQ#rqbys$jeK zO8uI}H?)-7dcRik#nhCWN9qoPbR+djYHB3)U4zU<>h;vrNa`Mg%tGqlsi~3FeFm9{ zR9|}_$erQSuZK)(22uk}%AL_8wZf!2ks4xB?hGEOcN@f?o~uHj(PjAp#Vpn`!oWMb z2?pLLn_%F5stE?(XPRK(eYOb(-shTNu2)_fyzbh>L+0c|1?e=HofZ%2&b1(&2Dj7V zA?|V)=``4#77uY}3`nQJ@3eS`n+!;&$>6kjh?^Wpr^(^8c!--UNHed3XO=v~&8L+* zUee0ueDM%BUXV^JozvnWZoD9!Rz9c2L)>^lI<16Gi-)-Jf^=FLofZ#q;|1xoQaUXj z;>HWoY2|cUJj9I`q|@T+w0MXcFG#O%OSHRP3Tq>U$bopdzdZ|g(}Y^#QE*2k)Jl(n zyH!H1@+i35CzL$Zn=e{$cTT8FJPIynB+|!gJ&N<3i&R%}gNge)JkT5bL>X|-jYPRT zmX-^at-1R-s)_om)GK-O9TJQ3LGJm^px|4xza7VyqBjK8pe#}njn>c6EAv)`*_kum5M+9uD7Kt7^Py>Ivb zMJvpoDBGV^40fU$yB_1Ow831X`lL74_SC7NT^>=-2QF7L+}JG#E-v#Jc|4qR*~0l; zGU`w+C)zLRagt^08u%+SHn%FW!90Fihr?T12CvHD8qnAY6ue8{pb%8>G%nn26&2+l z-cE+`J1x5@?;ykY6#?E{!}ysDug5TccELNxFn-m5cd22#EqGTL#;+RizGN7`YJ6FF zcN)g88t@)4jPDn`hYjOb4S0_l#;+Ricy}fqXf=K5dOI!U^+w2#YE$_hWInnP9AttW zkOx}Rc*v@*4tIKhuB}Y44H9SMI0;$R)z(ng7N)Bm^263N7IJTGlHa?SU#C(v(B9C% zDAP6p5)Wnn1G1`XLPK4fnXZYDC@8+Y4qa8|-}!4*C6h;$xsp^uF5jkXDpN`AEo~Jb zWdCieKx!@8DnQ6HRs-gP16P(>zd9hRf_@|*INJodgJ4Cs+UnH)u$2KJ zzhga}0!a``S!%>VUPFT<2qlmj-4I}-&VT9s_|XnYK4jzWvBgxdT^MMuQ(K`f_d==Q zlgtK494e)$ktP8`4$_SEDx^X;O6f*D`JVM;0wgJrTbz)@ztA26Z7L*PEP>SM zqiBSrk8&~qNe4?=YV=Wnko2$wQlr1Yomqz74c6I-koZ&RnpmfXOETLb@uvh*!zBSi z;ztQ=6n92Q@un_e!c@_Q0eTm`(Mz`~x>^EVErG61aI)>QoXO@<#OTsd6#Wm+Wwc8az=HIX8H@3ad&0Dr=pQAPK=rM>0M;q@)GX^9;~+9AI&y7Zub?F_lZr*@CF$~7_Me_K=g^B*W>`dF6RAqQxa zTox~>Q`suv$m%Jn36h1R=p*#Cw(7S+K4DE$ATO~4K^x=^+SI?+Bi*9LVL}!PM)(7^ zBFo#nRG!kt!WC$ysAPqi$&fB%SH>j$pRd9GgqDRe=nE|o6Cl5;@$G%(nF_&|CGZ^e zi5?c}py{7n3Ff}_s!L9l)Qvh#8LpL)%Zf6fc1G{p$HZxcnx~z5B`houEQg{M60aJ* zko;5ih-0c8;vn(p|Fgp@&ZTrlA2mNhr`vQb<(=op7WcmMOv@3L)G3e^-AX z@qNPZD-B2V8fuP-FaFT5tA1r6Ts{H)R?SI>S1!&63m`PbmmIIEiVf9Xu*Z%fpwZ1H zc>PsP@9WJ<4^D0Kb0?7l6PRB|#qltHy*UE~dXR4(54Z=aLYbP7ZQ3N!zP5+T^n}a% zcB!(iG{`i_voct)Ajo(9n_k>~mbv?Wn z4CAl0;k{uPzlQ*CZ4F?wg9&dv!}vV}c<(oi-$U3;c{>}%?;*fDz%agF@D4VN-$Q`c zZWzCZFkje_&ul`6R26H;y0KY zKg8fYY#2Yp;H@-_A3pH@VHmFm-W!JT!v|hJ4RZJbvGO)Fj2}Mmwl<6(KJa!hj2}Mm zb~lV4J`4!XqJvZbS!`;2MsrM{2Jwqcjn62&I}PJA0q;S>_>97P$}nCJygwPnXB6Ix zhVcu+-;~!+uQj4)oZziz7@tvi8yd!E6y8X~_>BI3csaBGre*NR{t6ZUiF!}#?R-b};z*#>WpVf<`^ccNkZY|D2V6W-rb=>hAaZ9=D+#Rq{-y zSJamG7)AFa-*d=Ml=YNBT-;#&TOrZn2d|%{+b@0tmA9c`{9*%dPs8}h4exNn_z4GZ zvSIu}@?GVz$0jk&qjQWxPB%5)9eC#$#;+rvR^By+@#_e@uNlU73*LVj#;+sr=w9EN zUq{x_jfhRPEK&-+mA1*+0=bfm8Bvh{?@qfavEPcd+It0qqGt-K=*<5$In%KNlo{4#_* z*y!{M`LCEBzYM|qnPI#wcqWQx$qVnFhVkbR@cv^MKk48N)Y}r#IRrfJ83w0M+``~? zR_|es$|AevF%~l2vYN!rzGLjBpuFysA2#JKQ8|Cpf9{f9W}fd8h`Eal;K_sW-k3Wx zM(R52N;~A;c1up4@%5_QIX|j!puDQe1>4x!h3*HjL z__+n|e8czy8a(dh#(CdOAK>|@mPN*(kJL6f6haES?(LkSh%UJS!7A~n-QXV&$rV5e%+JQl)<$+Q zQgj>>=quWCZBc;e1G>bbJl&jYD_e7YW$W8{Cn(vL2{cM;pix?LjgM=bU(zzTmq#~% z#;&2@pQgwyGyhiB#`+*gH1ObUW*C3XFj{#ZG>l)0;2mWczl6Y>XBa=N;Vm$XU#{St zV;FA>-uZ^{%N4w(hVjeQWy<@CVf=Ch?@q(`e!=^mVf=Ch?>@u$y}_vt`-xB`xI|=BG+No0=L)-Dr^6NWGAn8cBW4AhVEqH8nMo zy4@f%k$N*VHIll^ATyBaYs>tMMpDa7suQUelj>|Fb)QL1M{0eOn%+oirAbZ8Ar~l% zBt_4y%vQ_^T1FUnCpW>sJFN)@-r^=0cxN@i!23iK3_M~G_3JW~PlLBR521&2WQzNNP zgShGXS4|E{iVpSADdv{J=+8W@A)Pec*G#;*PAMz2CqA| zc}RDj2&B_sc3M2d9sZC`gWGBG5O?@PIt_NG#Y5cT59u`cofZ#qhd-p#WN=zM#2x;S zPLsoF@ep_TLz;ONJkjhSZa#fbr&?OsoG%{Y#tYJErE^+5#EloE)5_NT-$1 zY4H#@UXV^JqtoIcZoD9!R!XPEL)>^lI<1^ei-)-Jf^=G3ofZ#q;|1y2wnV$*C#+)? zA_wB-elHO2@d>rUqu`#HP%AwO?kNei%A??(kx;=GW8f}HsNjn+aCzfN`WSpM=1kp) zzFkY%dWL+&_Na^B`la@40_ICHx~?=x2js7;X*?tfi`P6m0`+cp2lY3Yt~N+qmJ>6` zs`|D-y?ek3^|zV&c1U!}eLcvk`u0G*8*-?>)znXbd_bGzMf+iODpdm$0s|8oMIR64 z`9a94u8DyzcMlL}ai-Wrg#MXzU@UqW6VYBHs=j5N9Q0P53OeQ1Os=b6O>lW1SE-U6 zwktU@S|PupO|mI^`5BGm-eYndkXKpLWXLaRQ#mrJVIX*`9k*IdR~zIt)-(kYg@yXI zI<=&JN+a*lDHjBgbyGhT5`~5O_CWpAw^u&_^*AL#y|H0X0n31ctjJyKaAyHT+ky=vklIYb>Ks{1n6208SK+Y#|zWV$%^L-rTIy;m}lv|XL@6)EDJLBrq z-k*T^m_+?$roIF6-6k~|5`|^1sU`K38>zq7)VD#dYwD*!qOi<0wWQwV8t>656BcrP zQ$H0Fg=Ma(CG{@XUi}2rBNgV_%S}Y?K@CLlMHT2*v`utfdj^%E>VE-*#^qih6+9_` z`QHdtGSz}H4)O=qG#>JPZ7K&3wVx$mBlQOwqyzFEYnlv+!gBCXOX}U=!TXacka`Z{gv z9TQZ(R{=ufaxahyoMq8xdSGUCL|}Ce zRwtX)dERQ5w>pPDQs!0%mJyBu+=bEI%;;QibhbC@uE+D_6=$HiSaep(Fc@SGxZIJm zH~W`84DPQG;HM1Yq5|Zb2625LaQM_$0+;{gm^6HIBwBD^w7KugnLv*!+3x8SKb7}cz?Q-*JBv(&vfO1l^Ya3K<6u{Zi+nSE6Tgi zFy853Detd_@lFrvTLxwmEu*CNRUX*T=?^GqPgCTb{;2Y%8^$~RW#!#z7$3zY%Dcia zzGKUk_n2Y4KYvu-e+=XO8QiZ7(6(Ckt$AB}D(`T^c%R2BZ?0jyKPM~i62o|ZZcyGG zhVlOVRC!Mt#{2UV<$(>8`mBQ9G)3O&{<=19s%12tcTwI)4db0YQhD8m@lLlZ4{Yf4 z2?{#T6nUpFR^H8q@sYk;dH-z~?=-w7MGZGdxt-(c->IQFT{ zD~a?U$eRY4o0uiVk$bPT%DQ}6W8piwcS>@eg7;o!n z<@FfG`+Sk|&=<~O*GY(82acT&tpwTuoj9m+e_Fy5b& zm3O&eygv^s?@xyDLA+LZ-!+U6;tR^FwUBu4&$`On!7$#RDat$9Fy5ctl{d~X-k%=j zebzAEpR1JjZNqqfeyF_14dZP+qrB&}lmWENoqi1&R0d{CEu&K_6!bTY@BA3$9by>o zbcgch8OA$(n(}(I6sP?|$uKW9Mc$!nl=nTu_(=1!)-M{yJ6+S&{JmO6GXviCw(=iW zMm7E4Us*e+YuCgqse=@Et<$DDeq##`0!n; zyl)!Dhwpjiy=54ms_!fBmxl4Ih~HXyhZx59>>TA? zV;JAFcI6#!7~iuV<)JTh`pXKs+Z6e9JfOUlhVf4SReAgvax|Jp4k-uB9$H4jV?X8b z%e7Guk5df41sk1GeoHYwZ({3w<=to)AH)}w_p)JpeEJM6`?aB#kw2R$Z$HC$TW!ia z)-XQthbj+jnADRLwA2)Nr>|1pt%mVQy-Rt&F^qTmdFB1vFy85Blm|9+dM#a7hHDvR zeoN&YU>NW8p~_1?<>{S1Sutm5DGvD~7|hR_G2gQC|qKMRz1kzu^8E0p(j!}v(wp}YqSWfY&+RemGGc%MI}yy=GV{v4;g3k>7^xm|fbHH`23Qsv!j81K&` z%6rx@-k;Z$_n!BZF^G;mn<(#thViz>DsO^eywArd?+n9uf6h_f6^8Ng`J(dfG>rG> zLFN6?Fy5c%mA97t43qa~sPeWnjQ3}Z@;+`D@6QC~%`uGkXQA>gG>rG>a^>A@81K*B z%KNinygy@fg+F1#GVgL18nSg1O=BTHv{l*E`^j-C9opEZHn!xZ|ERjiv>&^pYWmIW^4?8K z1^sGgEU8mT!8|Ir7~R-9U6bBr>RrIEPzavL&&}qVr77>rgDUlIQ|#gfWQ;-F72^J? z1vmTFPRb3{;NhoWbY)IZc$gH-h{P=^c)wSh(b?j&%Imj&DHE-Y8!B&%Vf-)w@-w7 zf3{ZMo`&)Mj8-1lFsTP9Xp$-NPV@Qq#fI@tU!c6}4db2umhygL81M9L$^#oZ{c{C9 zV~V`fFDkD^m(6Gm8l}9$4C9@K*JSB`OvRV$ktVnzc}^jBjVLF4pPIXD>%URSy1=x! zV+;^JIvE^LIQ)D`4a!}kp@hkm5IM-AhH_>A)2G>rFWfId*Nm6p*&Ia+xq8^+t(QF(_M#{0Zj zc}orB{kdLw_Zh~==Vj%!yuVCtlvF+|{jBNn{tQ!jKIa?_`dt-ssM+%VoUJ@Qe;oO9 zv|<*T9`Db!%DclbK0bVFm#^kV`Fc*}2kBZ8?P{&Bye$mlbGozg+709VnW?-p4ddhU zS>@ei7~gkzO;*uYRQveGudh6?VN&;2&=gbTot~|{MTYTCe@b~b8O8_b`^x);VZ75%D35QO zMoAr@tIB9CqnWY2@(weM_h+*578u6+bC&Y1G>nhWb;|ppVSId^Qr_CSXhune*JSNI zTgBP;2)^?6O$Tx3!5-qygMsi>nBY8^4IX@2OSVK#^EVS**%m zwzio!y`1ss{|{8@FSLw?%b%6^Z^QWX>^8d8dAOF**~MVxZEhGpq;^yu`ocrRcm;Kt zB0r|)EALZ=@lJnUd3PAbJG5MRzch>=<4-DYm0`R;uPble50rt5=G@1XH_b5K)~3qa z!!X|Gk17v+VGz3&bcQMNPV=q4YYgLqc!TopF^qTUVde4lyJ&Q*wM7}2!CFQm@jc4h z&M@AeU6nW9Fy5czm3NY1e4rO8?=yz+@u@5CPQ!SA9#r1bhVlOVMR|R;WN>(Y)>hsY zhVlOFpu7VNcwkuKPYh%>b)mD*(+}WC@K<;Tx;~)=NO&ztv6A*IpYCvkoBp~E* zs{u=A(|PSh^ok5nUHb{CPKHeF2r!DHvolBzbwAJYj>5$jMAn8=EAu9B#=wVx(8aWba zNc!0;O{LoDwuYS^Xq|3{JWHF3H{76CX`5JB-b00fTlm*rr$*lkacFv8BB{}Nx%&r6 z*9&22I$jD>qwgXNNzV&m=xP+&8%BY-D!;-DIeeRPbja)2ko2%{WP}-ot@}AJ3i{{MC&YG$_vzxcq#ALL*ioL z@I)K9cqg*?6#TFbul;N^c0g99;EhXIJBX?b#~YXA%Jx1U_xB9gd>>mwP-_et*0s^o3W;gM zHVOlQ93ZFQJ++Z_>NqGLCV`x)J{M4VXsAy8W{c#}ki>00B3X20q-0~jNa+w#(yw5ysg~SILE3fzD7JD1>$X%vNkd$98%H@I|Ga@o~nG5ZZ zghL#MM7KDwGV*F=Pwv%4dbE9g+ma&>KHycFS?*bg&#KhbcC2oNthlhsTwui(zgG1y z#aW4a8=2g!u)U4Bvp>-w(B0yB0O;$r10wjlo}0Atee2Z($clfzGyfP1y~4TG?RCwr zCktyBTqJk4Reu~L%GPWYpa`jQ2_#W?U$(xT`;`nM7(DHQ#dFQ|qah#ECJEMaE`q@< zLKV)hRXb6ZNw+*{b0hZ&oSer(;*i7;65qrP$S17_txqXg83R6(!6Zcc9j0pXqe{MD zP2(Y7v8Hig6bfs`=OyGlnH6ZO1zF4a)0RTezf7 z<(sK-alJ){{$@6x#zP)zvtnUSoyv@agFH!_iaDDP+`^eW@0c8Is#+npwx*69lsrhw z7CFM4QoFSOMu97>xrsdDg=@G=#)2QE%spF2Yz}!#{x<5VZL(MnaJirB$boM)03F!g zcjN$VT91ybCJ2}A2H#~pT@_rCbm#pBvP2>4imkmjDh-`n8@bb{CDI9)XB+4Q4}ys? z(R7B>)W|$S(XWHyBA5ZSmyg)FCD)Yd2P!E6fxKOt`qfT4rcPz8waQk(Egn#kw+*x= zNM3T2JM_oYsjR1uqsy;}$!F#E)7q_C2ANR%wS$$AODjm+=~p{pg!y)q`PPPSW6ZZU z$UCj69Wr^gV0o=h4G-l~1~NI@hI5p<8&SKif7v37`|?w7*9vmIjYv@5(yyfM)Ur>l z6Y?HwngN;;sfP?Q2Noreb=8aDcM5^5FfCn3Q$C}_Yg)?V9Z3D!q~?L9L~5-*WlQkm zaIpAxfw%`*3F5U&o>BM7sRZ%bB~<>VgHVJaNmefoe<;1txv09qRLuoV>7|ZG>S2>Q z9yBFVn>3CAP`!^|lO5Ls+)A!@hHDJ5=$AFXY_1yRMLI~t!ohcx;!oG|J+&_kla;tP zv6MJT3HCB==vzC)`3&!tcc2$6lY32k`LXJMK+Ar$lecuv!2G#6eDdx}TH!HcoE`>s zO%p2FYHbLr%oj5Pq4Eq6(esAWgAqVYX3+MkuLzi~fi+4@Qlbu-;AyRcRo(1&pcZw= zu8AwTOz_L4xNzz_aAn`VWnb^oGF%7v-U(m<-L`}nQNrZgAEBm$bP+sM%iur;YqCP* zh&s&W`)p;V4{_|~Fz~*h*uFLYTT1Y*GmPJ-hj*i5f+GVg*7{)h!QvsjpI!WujlSZ7 zLX?5PPL4dsko1xAGSz*pmM!uDyF*5wCl@EQp!>bvdIa}f# z*S6E9NsyRWFY~3>gbV4t+Na-XDc6~hPg_$PWQ&=b2>EVn8VfnenkGSZYSVz)3DSWr z>eO*ou1V-I<^5{@zs-#f$W_+V207epc0f+CriqZV%#Hc-sK*v{>d6gvasH6n`em{S z$p>a+7()J2Q9DX6Wq_2|vipo$eN5U&+hcSI*la;fp;cL*(h0gr@bQ zijsQ=kV$=20JW3{tKbo)paXKOH5~;>WZorCv}`+CUQXVpr><6jqz2>A^mG-)cjGB3+jJ0Io!er#$V~c`-NiUGTQ%?E6hKdqP^aB*n}5@bd7L_UHgQFrr*%A zi&583RNhybVBp=~1oMRQo@#TRnr!_q00vEn)H!nggw9L#b|hU>yjhGYn&T8FrQAKn;i&dAN4e{2JgL! zS(9FXB?4B4RNRLiSEqJG z0zzKB8j#wL5-`oElERPlowW|g^-XFlB$f+5I?Ru~5)cxLC9sjv7p?PckXVw3jv%W> z+sx>P&FFZ@s!{(0-4E0lmgGzivVYPAiSYsQyv%~yaA%fwZ11Nk21;bw3V|cE;k=}q zbbKo{LEfoNh1$g;O`R?U&tTCX(k0uAkaR+xK7dU9IZ^sE()vTfij&-;oqDxD9R-8_ zOfu)k`u>ciKlfOFPL%$PtW!_@aZkQ55}5}7f6a(zvvE=^aekn*5(mBmRluMxuo$_E z@26Bd`H(AZ#y26CrhLMzP=%Z5*DEA8kVEvdG%`XU*Vm?UwV<{|0ya{AyQ%MhL@J)h z`1PiBxD65oa)|?pE;&KEb4l*QbhQmw9+}v({u6Da529>S?FP!EDOdHDO0BD3EBZjK zV_D0%Wi1P8ukG^McBl9Lm&XZ;%4ua~WPRDNWy8R4p>i!Mw`{~N+A?0t!L?<>N}bEp zR`Ov?){)>5ps^0pp5#j^4@Yq9BT_@vDKP|jt~E`DT-(w=mT0CBy2*&{kC>u~kjt#8 z9Wp7JnD+xk#I{du(g~`dZi?C35T9Z=`{S-}(^t^H&82n2E$ zWvyLo%4|FOjM@RCHmlRf=hcSDM#li-(z>sT4pr_+EdvT+ni+^<403!dk*5Q9F(i8q zkZ6(*>9pix42Peo6?vMB+^5(aoe$9HER%I+fNBc2>tU{!K>p0{dS%|CWwfJ_W5OGC zIjDba;d6c~0yBgnGM8h--22?cLk<#itGu}}I`8+e`9BVFKW!?H6M3qm^|3m{;F{`cV~K9d&9`%xDMXE~>sfs!=<@jCMdC zrcIK7`E@Ed7atS7e{GR}ZRX!>^REr^K5H5e`Fm}W<6@sWmA>Zjc*wP_sST3;$teOP zU6GSu$ZD_r*|YCeJH6^>&Q69TjYWjo>(oeyT-ZSJ5j|h4yk19EUpZ-o ze%3}?TP}8FGq zQPJXn8BTO=GLeG^>j=spPt zN#Dd_NV+K(GW)nmLl^KjdI%Q`NtAd&BG#MFd}ts?Oyou*WRjEcC}e0iNE*+ndBrDxlbcB)a0RWZKsA92B-K0iJ180fBYKVZEJIFig#j4o^70X%G9?({==HaLSmz^*jA@D$}Eoc7RSE5 z#da(btU|qiqjshG^CvBfeZWC0H>y+L*4&s1i95YpoduQ#ECp{@?xSiBHFe`4&$g!V zkmqPqnRROCCt%)v)E{Gz4oIZRe7?P4TO{buhrPx2NYDp-KYjT05-sH(^1=G_;kUJv zN3<{3JMf$6op1Tr3r{dium=K;-C1u5U8bc7&e9X1A8FaAHtTA=!O73V$d?)~(%axQ zyE8oN2_-kRd$@D|q-49^r;~?4N9gt?KX)Ly`sm)@4BG=d_H`xsth+o){HmT5ciU#k z?7j6IuSZMK#ka8++2McQt~xMJwTUy2sljj&!6WpOsb^~`PYiFQUlg6Dr9@&|{XFJG zEd{l%ell_&E#(IRUQ}{B{Xn9`ex;Ipb1}FFPF_E4d7VaHe{6Z3MqYQYyv`=Cvn{W) z$!p#6+DTr2VR`K&uPo+W~-Q;zU<#jH3P4l&zye_r8&Lywkx4d?f*XJy+ zbII$!?D3Uu^16}bwTrx_`Pxlhr&(UR$ZMLf-Q@Kc%WD^ToniB}o4lT8dF>*vr&wOQ z$?J)h*Dmt9*z(#nczIKtPYnrcJ zG+(>OYnrd!d0wY#@_0o;UJ&@Y9yx!jr8EuHm312}`_?WQ@o}Ak$7xx#ouzZ|LYs^8 z$Qe%*iMAVb4*uBY;%sup(^T^4SbxpcW|p&gQlX2$W2!gaBY`FVuvRSVa#go}q2<@iUm7TUr!k6>M4!J195 zZncH$Sc3J41#2$B>SGJnY=ZSZ3)XCcwTA_3Ho@A?f;F39aX&*2TLkNH3)UQhb({rj zF5`5ftv{U%$}zUsbTTO4YayNGqdc2~$dHZ8cn3dK$3bMgUw5hX)Q7cUZ!INC zkQK2lbFl-o;h-c2SrHqPiyfv7ZAlEWBDQ-jHeMShB{4|EWS3`oE>=5QTRM{*WJT_N zC)cGdbCVooMQ(+YJ3(7cPI8bHxyPK`>Dt04Vk8NW6}gp8?i_77PfL-5tjIm*A-r$Yb9-nQVxW`# z4UWf^`HF#B_I8@q*X4L4EybJ%@niJqx8(i1Z17m;qy1HQ90MW@yeaBXgn@TTa@xlT zX633S5953Fz%xqAu=86gbJu2|4=HnhEhDetaoQbW;BiQdFz`6@i!ksOt3Sa3nKPg( zQonoJWE-7gU!BTvP5TFMrn!HN973OQWMFk9`) zJVwhXg7DaSi7@cEQi?F}xWbJvT=ia;oc5_e0pK7N$P=e<0&b<((+6o8MyO4hM>YdZ zQ|3}FqpsbcymS>mE6*z8T<}L~;Gs@7>2oz$xIekW}P`AApA6&y z2T4W#)n@j=|bzXp>yPtlU+}^<1O!-%NUZfbLP|FPedVqs(=5+cWAI zJhn(94BMvsbbUC=Pyjes6_B5-{)Bp9R&Fxo5rS2@Uy(!ZR}&8>Q$C3Ns{MaA1N~K* zZ)h0>2p&725e6Q+qY(yP+QE0D4AzmlZym-EX63G29-v!Qo_DB3j}Oq#6!g1f%!B@* z%$K!{ItGvZ;0Obcz2XQ1Z;N4Ne}W~E-TRL#Bn%MpfP<4MSZ%5Ae8 z@+~!SZ!+b>{Gc))Zw7i&nJ;M>#Sk7F@eu|doAeO|-d1*RWOm*$Sn2jjXAXgNvT6y_ z1+#LWG1v2`%Kts-@iF|TGKcDohH%jHbM#{r6!je*cP=6fJnm{l7VJm+C-UKYZ-YBj~lxY1|BzXA`HCll#nNAYQ8zS0czx-y6BjpV5JJm~Oo#e}^_0p3T7P|(^;5zNZ7 zTzQ0GRUQkse9Kur-=}DpEa>zC6#eXGld=T$c=Dp28`J)_B-ycu~&uSTA;Gr+V z(4kHA0gx~mFgI@og4yJmLRd{6PdiObd@h;tQRMNV^lb6CJR4W3{O!&3d`FqT)-npv zi^_Y;6b0W(MFEaQicrvBAB>S({{9|3J;JJh{4Ia_y1x?gQVQfIdVeB*bRR*z$gf2& ziNn()v)nZ+e<%rA%KRhg#drLQA5?-**{#GmS_XH7XDI6wgG`4+O5Qm0KNp1RGfZxp zQdR&#pFCy=iBzciD%G%D%i>u_C9U|hQa5NRx*?ZqljvT>b1T|ZtD*bb+7jsogTjh# z#6sN|eo%GGLsw>3iN9+3ib3Y(5Tt>Ii$V?xZb4(>efmU66UYFA%!EWrI_f_sj_S2d zZcg3{An21X0zx7cs>bg7P4)C#bq~ zGXA&)=q|H04HCKFZtpXS9->b#MF*E06Rfg1B(>Q6AMf$)@A@M{D> zc%ZC_mIOIIPYpisq*xF>ARjV!-N*;Br9n7um^}}1T4t$qk7=1};z|ISZxFZj4di5l zI4yMcV+P>}YW6(DX+io>)ed3hnZs_50hwwL7hfC&8akYV zg1vL{bB>vsmiNg++<-v(0@LDF%gdE@^V>tdWDvI!qU9QcG&GbTP77|LEtn|ZQUec} zA=haj{2WN|QXh~XHP-S=Wj$&THyk{~jbEgHXIfmR2lXoxyS|pe4G$;!`YNiC3RV9_ zRjy}Ge7Zx&BMSMqS)UGxRH52kkf6G6W7R;=C&vLuq(ar$-ON;X<}rh{r$WMIJqHE% z-I1SRrrde}gx`db*h3;!^g_9Wweavm|$`B5I2UfaAXrpIVKqM9^&GQg>x-3 z?i3!#$p)F8W?o4FIo%*m3!&deA>r`?5YMkm^dON7j*DYd<=)Ly1NxA;I13WFKs90E z*BXKgcMqAFhlj`Le_^)WG{nH=sSo}pbPfv6z z$xTC~62z^iK+<~z?&#zpP74P3O@Lq@!b9B2AJU)F9)*+nW@SF0Wwc!8nBel&LtOr` z@MsfDIVQ-ihq#6AGiu?>T8145bd7?fQ;^67*JZEcyxt)gR9jl?*AE`npWjQhS(-!F zs-0XwjjzN2)x^6aL9TO1qniXHRMnwc%BPzlZ`IcY#cX z<*$hCJZkCXM-CXdfx3hmpbY+ea9@e<cVJ)vchCTP5u?^~`(2Jr1y=D=h~eCk(Q zw4_c2ox$fb85mP^q!(U6pJt=K74k-PUOt<6`H@r@#`1D=K8kyBm}h|YHs;~!RAX2Y zWsunEmBRwzY^n^&{_+d3N7@uav}|qU2(mJNbDP1GeqP;QuaaHpr0Hm{i8tWQjU!aU z6fOJL2G{z#+n6~jn)EqFLUqZJW=Dzr)C}O*T#ky&<(S~B`T69Eje*)ohxaoAxH!D@nz1R0z6oVBR3ls1B#q|;lv1bOAq5-guvgiMMW+B!rPMe&0-PBD${ zbi<#dIF6kAw74VZClpfGGB_kIQWn3RCP!~bq+}1`%q4kfQ2qJFs)3-dq8h1C_3f(i zaV?`eL)RB^n)5SIiX z{9c}X@28QL1aVsM;X(7oUFzhJsMm-;r)t8B6hOZ+Thkzs3-&|)qv+8?%I-zibU7wi zV{=H zf)5S=Inf+;a}3BS266GlQJ|s2IViZ*O@6L6Q*KkoL)?Hs`b(z8jo)u5>ql=7x!WLa z4MWSf4bsq1f;cU>iMC*!c}NZX!3?=h16g4ZH}ZfyZV;#C8D%|h5H}n=WNtq0kbcRu zxK0n()8j4eG}##fGNLgA>Fo^S#*2rzP9x20z~KP`&cba>mlwOW2s8xQ;>2X*P0=hIv_U~#2La(pn;)hRQe^; zG6(W?YnqpL5~&0^t`X#U)8dvhv?PerLb`rtTHJXFKCHb?=|ZsNc!*mV4pr$1T1Ja_ zjtQ1l4{>7%3w)40vXoB6ED6B_N9p;!ZGuoNW-Nh0yP;knm^$D1G;L z4kU8HQE_)w`LSlI0qv_G2^S=Cfoj6C)TG?-^AI=u`0dokO^cg`7`Qg|!Qbf4LBV-E z@|X-p1(2VbH|`7($PWzShNy=)Ew8Bb;9(7C9T0xvG1wLX@|yYLmN^e`S$a{Wfd=!E z>;MfGi5;~kM_7+sT=*f3;|wwla-lW3X^2#Uxb+lBw`p-lCl7I2FmPUDEgs@d{gA#; zwS<$IAFX^yLD3?XV}grU4{`a&0$<;VEajLWyB^{ex=XY#H#X}ypt^#jQ;^67H@a(j zOK`B3wq5UUbT@?ho&9&Iw)fZ#M>lG6NTZwG92dT&gxu_g++$GLR^HjBwx6~N5b~t2@YPcjo$f|d3?)D$vT{p0#)A=;$x4R~?Y_qrZIhJoSpM$S8!QD}8DcA;(&; zIw0wYd_+C!Rfo@Lhws%Ij{Gm{;38*oHUgQla-6p~n?XtWRi|jCS9GjbG!q4sC`u2` z9?x@<`|IG4d)q5}7HH+H)VQjLOiZ(=9#1q0QSdq#CULm9Ve3;iiIkyHmPE*9HV{u< zQm2vz;<&uu(JkTK`;;NrPs_fwJ?hXiwM`zBfaHtMa(A*%eT+^QKI|(v$eqkJ!L88B z?<_v8koUEe=6m)1St~OjrBnRlk-pVHU^zD@VU}}Q=h&C0H`zbvq z!H!e%?9>E#zBUz-B=NokBfgYAI>!>7XRSlCasE_OG#lLyr6zPzGUVo1zNV3{ADHfG z{2toFsR@#|K8n6Pu54V9EjP%uD_tI@^v0Do=n>}Xw9!gd-f3vlrpXma=xIrEmXar? zCPMK=8-&vc0VQ*v*!HcZ;e4HGa_9WHSY_;oK6o74 zN5{tQ{nnu_oKJ6PcA@)Li#&&4@>TP?k0*DBneLhGN}iOOAWzq(A__~C{$hfCS;^Z{ z6XdtGsgS%|X*wa#twX+8fxWEszbkD&w6l_XX;~PB-ao+(QgU2sB8cC# zAkMVtDUk=UI_i&9SLN0ons%}IsgT@NX?~4DuI@Uu>C_|%*;A2Z$-KkjJmc-+ zEE}{8R$e8Qr-N|*II}ko-S?Pow;R9#VzT9{lYHH3!Rq{`lHW~DkU!L>A__lI8du~B z8}iKxtdDv)q!I?`cboT}8z{MVYC1s4BeX1xLU$zCL?ydY6QP)CgRnCXGZQ~eZU1}U zEX!%(-P2uhu?(b%?tepuMLI3RA9Q-)u_DM8%ZD83_nJ3A!8&RyiKW2zi={s;?!I3v zE36yQ9t#J8wAA~4!DF0Bzm~av9k0#;3i`#$kmkPknK7J3sm}%LL|O^F&+r(|VJ=>9 z!{1G1rUApeZ_Vd|)hDelzF*7<27QzZ)}pl9_VC#xg?Q}BjedeSv zo%Z=${9a9^Q)}-tJkAfpT>MKF0SdMiIj`irG0Fv}^XY`$_luKE&LX2+aB`nc-+jN} zalRSm;v!wj0R{cywbyHG)pu`Dz+z{mvdQwiN|l=|`5MWk;=XnX*xd*+&Ng8>Cn?Em zSaMu|>@rjrZ-Xthrq0WhyfHOF-fB(LzpdnNQqvPkKAoB%pR=aU7nB@gy_r5t$x*2Z zaw}`<psW)>V>*hfhuA@+H)<7O&y4`gHS=iMSP1{4skEJHaL#?T+Rmp|c zH0=x}&rMB`7g*Eui;h{O8(87roF1sA{qOTOAIyR93{VKP19~r^3K!*`8{iz!T#N!tZ5pN+1Vm9 zjjjK~Q&Xc5?`(>u)0?lSCd@sSnjn)0v+#iZPdNv~gEP&8S&ck+#B$U5n3B(=CP?1K zl5?8BDtCxE)j3Sb4O0{3NNbw)0VV0E=z<(;sLmsm@?&yX_>HKSX}^Q@`!(@I{N znjq7UP0hGQxi=>iQBEQ4^dX&2NIzjAot}r3P!gi)4|Gs9#J;CSBAocqA@dLhsRj0Sfv>mN&AL zPRzRwYa4@1$RP}jgA~%QcG@s^od)wL1D)zYCn@uE1D)o-4GZ&g20GP)xSjZG1<73$ z$U%e44#>GIhiZ|(RGLEYKKID z+>U{)>hgC}(FI!Wra~epH^08SBu})Lo0!WL5uE5E_`Es|TJB6jVz9a3E7t32kO+pJ z`Y^9yXuRMW=En=J;UMvXYd9Lxax$3j+OGXU3;0Xc1RRRSRt#r`~rb4(6T^4 zep%HQd-%{Olic3s77ed!BD#=^=l+3e3A8L4kZUG*c*WH`{XWcV7#c6QhWYV=YdA=} z;2I7~esA(78xdn637}-mFA&IG(jCdf|NBO*U3nlpq}*hnhGJ2H4d_AbWnz$GAtX}JH&eKAXAhz%UlZ1nQl`i zZ%4~X4CKyhmqz>4#zXQtZ@fmK>oxPK0}`EbLIk;!sUHhjRqt0a)c?cOw?S3~{j!B1 zmSw$ztP1)y>OL2ocPNN|(rw79MeiyWiJL6*khuK62_fpq=NhN>VU5HNmb4=wQ-@?_ zcBf?suC%1N=Wl@gvN7a0%KELA^4g6*v&RIE^{K6)j|jGC=b~qtz>vmDMiDC}h0iG5 zp-q(M7)eV$-}h1RWtM<(katr z>h04{YgydfKU#0&J*A~=0p6tN0UxzH`Ntim+uZ3Ra>w=PX5M>jJFJ@xlMU?xsqHpZ{chn0N8nr4)| z^q8dKi;K`2F$=2;FZ(KyLldan|-uP5lC%b*{WVhDIZWlb+u{zmJ zf)C=>I@gZ|AH=ab)u9J*>(FC0@GqU$(ZTZ?tMj@qcwXD;pP^^x4m#D32G47({`q(? z6g<_T$8}qs>Z`$19jjAaB6zA>>r{sx*ReX)p~rP=o$AozI##E8L-6^!wN7>DaUH8u z9eP~1)~OCXu48qoa|a*St#ztHkLy^S>d@o5wN7>D`8rmoI`p`1ty3L(T*vBEhaT6h zb*lBazVS1nQ>};fjh`f)>IZ@k;aEMYF9btjXTL0GJ#8ipzg6FlJ z9>UKDpRZeg$@yFzJg==!@zi}W_!QnIH4ojpgAd_W1$gMz2|k2dJ-=qm@q(T=`eD^4(bZ z|IA%WzdN|}uW0F01RqlEwe;m#`u}8V?HdHwzOB~&W7hsZnihXTaPeDd@xKo~f40)% zUkWaMTP^-y!C#i`v+*SPVDQQEMV*f)f=`w&>U2C2JRL3d2zr`VJ~!50XQ*ZH480hB zhF;X^$jN4iH-4|%)1l#pG2D%Jm=3>XC3R{dH>9m$lAcg?5#^1CtDaCh2TyEUJ$o+X zHSP^d&x-?sCo%ZEcr^I<2|h1g3ZB>C^P=|YyYXzG=fx_)$4~HiQK#~TrRPPR${Ul= z^WvJ|ufX8*qR#FOOV5isyEkg-c~NKghNUOLdxNJi_{&Y_?S`diyqdvZZo%JV1%toI zTI;!NZ}1V-+Mb=G1kS)4pQ+9Yd&fjcllaGtcjOcj)wP7cjr&`Mza4Urt8tIQ8-s=4 zOYIz;H*RA2KmSFPlF+H2n@Arit4}{uksS5ui6xSwzGoQoKM!q=G6+2(bq!5Ad>K_h z@{QN|!2mmU9p#@Flj8_&x6=S?r=ZPp>O zet{9shVE*SgI6mNrMz@j3%;ZYzg}D~d!EI)@#ngokkX|_IvYyYtEUK$7IlpeO*#D0 zqRyNCuCdd}!|(A@Fyf)#PiM7TNzc*Q7DhTS_32eaBu9OEg%Qb7pI%Z%a@03FH0g6; zziHRg8G23H%C3;QPKWA*ue3UE`g76N$-&E`{4mm-JJY9Y>>{3x(MVHaL}><{+P6K@ zXzJ4+wvin5>BU_nM}2xVAIZ7Qd_u4E!xmaydMo9|afL6mI&bs6mY^dv|cZ{sEpCNt=4HbUE&e0jepHmTk?laPPPw?;N@ZVzU z)8A*27FvD!+bxo#KK-p8$x&aU(4@nE?$xP{ej`3O)Tws_BAhXG%?S+_{tTneo8GOn zr^9Z!8gZp-@GgXQ6^$rq|5Uvn7-@;rr@x6KInx*{^uE)JcGBwFg?eK?;RmnIo8E%9 zb;|NqN=+E?xa!c^b&V~d%KM4y6Np+tF-0qjaOjAm41!RKDUyzCE%w>krqgOdUGX`qdvXy63J2D zw$Oya7h0WrZY8PnDAJ8r{C0`db<;cKR;kVVe6cX%Dz>Nd-CIf8WKQqFM>=}->3yh3 z&UOab6B?{;*eg?Y9zlw5!wtQInUJ?FBR-;)FFC@GwDMEms*XBu`i#l0w7PEkY{Du% z7~;LqP~pGG`qDY_R?=s5&VZ2?T77yaFp{G_y-OI$`Ij+5Z_anH2d1ujdH+7*xlrd# zAIjM}Gss^NsuR9IYw6s5E9n58XJDiQQ=i@!jpV3L@0mt&a)rHH9`;U~-binO8gYTt zdDG`sc7Ya>|6{05_yX;x^XjdnguIWRE%^CL_)8)6>An9*2Va2vs<)`4&kS1PL_B&G zkR0L7E#<# z>eI&{ksS3^W6Vg7KCNkr6Y*rIfaD0zo62uGO2E((1bDb6BhFV~Fdap~6o_ zVm@-p3vV1(xKxnN3NX?F>9ecnLxsYBg{y!*XNpuveJU7X5jDmuw;D^GH(h~XS4dqq zeR6G;F$^&wG*tL&$y0Rx6OzIg@fw{e`9v?`O6!AjeT)=ofznc-IE>_|PxT@>^~n!? z#Q3s3dUd@OnsfL`Rp(6~_S-tA$v+>e6TUzf=}f}sWf2!B1)bSpqytl*K7fnls81ix zMRL^FC^Vt)qgQ9wTS@A?>EZ{wMEZ2MNbtIsuwRGj(ns`>-l*8iG=2|FCw!&eGcSksS5uQ{hOC`pWUi@r_d!zKZI6=vIjSV7yLa0votiPml-mRoX zbgqSwX01M51rW(mpRN#yvX2O)zuH`yeA}u z?`l?!&c-1r`~f?J&M!hz_z#;pwHe!uiHC1C_6rsM4pj;tt|nI;=%TnAmBNQpXNS<` z4dF*Og3hl)QuuJ^=}Z{5hng%77)1K$Zr;lrtOXh;e_I(3c; zN#QU0X4APiB!$oE4>}X`*?q(nS7(-x6n=u$nIj~HHVRYFquoU}je>mez8oz&Sc zB!#b&ItPcO@Hvg8b6Q9WpVMhNuZ5)WIjJ*s=yUn-bxKd?T_GuaP6g1q)u%H z74a$hT|TVu10$}JDx|rUq^)&IhNSR`KTl_ekQ6>~b!u)m<`lk|!>KSaR4IJ8opc@# zN#Vn(Q@3M}xK8TK!Yh@C>!dAh9t=t0b81KDTOlcYPU_TasEA9TJ6%ic z;YOwK;nb=#FxCH9dSAQce!7(b`bfHA}aJl(#UUvbHIGj2wg+AsFKf20v)(=VH!`bgiMjTFG zl>97IDf~HeJe{*cQuuHO=+wQSBMzs|%b`l)M|YjhbhrA5{ysV@hotZy6?HxnlERNp zozEjhxYAl(?Sge8{HdkCm?rZ#$80zcTFm6-^nADiu7%dG$ZM%;P`3|gK->D-`EeA# zGbh5S(E4QvRD_R0ea`hNe~NqqZT?IGhv8;CT{mw1hY3`NwV>APSMpzS*5fk%lXxHE zU32_L@Tprx5=N&W4K|e+BVXa4X#F_&*ar3eUnzj(?qag2I8B zrh=KEoqrDEx!}F9wBtWW{9#xFJ`U@``p}MNy(W0gU_02s$?r;h9Q+b~1HXd{;S#t8 zZh^buPw;1G=lj1k&PB$%46nmP_XcK=725d}DjJBCgf-xc(E3YD1R`r-;*x=OUTFQ4 zJW<^VGs1iH1ZEP_l?wzi!IH2nG!mw4X%$9eudNBmEC2hZclo#*pf#2dmk z@MYKqz6tf!9qr$5=c_u+@Ozs)>&w&cC*9;@8hO^2r+F^NTjlsVj*iCjULVNQaW5io zsZ(F;qT?Kkr<)hp`D@+!o4Ps<>&qLAzY%VM)|WS&{_SwLTqkxO{|oRnuZnn;VMnOfp>NQB3z8m03gW4uUcY5@e9ybf@pBT- z1NHGiA;NKaW)>ZeC(oMhm(Qoq=A3*;w zIMVSIA4C7=aDwA2K8gM*aGK*QuD@4i%QX>uq#= z{r>!o{tNJ;TZdJ9#@fF`e ze+fQ|x*yv4?8EyB>i5O3PJMa$JtXgp<6kCz4eB0RNu2q3UUJ7zOFTWy1hYE6=jCwx ze8daD!mz00d!EjNUH@mOqwiQZrmgQ&TVL@Oc%5JuX#JOn>y~2eO`i2t=M6mFXsMS| zU-9?o{}A?beCtiY)AzLPe3sDv16&I?LhCEOh5p@ezvCYy{xduQe{=j}#yd; zyua}Nar`U9ufrs~Zj$ej&Iamo+cKnBoSA%wK$FE2H z8Q2Kw7N_?7dR{Z9zCQPEL;uULqvLy?zR7Rr(~UZB!=6xI?jJ<^6KM0jybl~-bw<;# z`;dN3`&&5Q$)9BMW|}-Zzt!}wgB#&iXnoJy;rRQA{{#=iV~+26CmsJR@$>K!yzKb$ z{-j@*A85-Wd%W^&UFBI{`xlf*66n#*Ma$8)zAjdHnEtA;rsFGKoBsN+k>e}gnEn@F z3&&UdCHiCG%Z@*s_$W9YPIP>EpBit9`tHdAbP0&Po?$l&0SOu!2+H^K_$hTfYi*bQ88(wCg(cJ+GeQ zHzM8`z5ts$zUS#Y*!h1%o&InT9Ol$ld<6a4iuEhUA5Hu-IKkxE`KZoxyg5)eNVC4; z3-A_0-J;I=*82(nXK4LDh+l-)U_!11vA*I-=uZuGg^cwx(w_z9fZ9I9`q_-9n-&%# zZhh5}R|Kzw!8>tLOObhJ`63+;;!0e9idAS^4o4ypHzc{?l@#PgUURlSNr@HdWJHBo; z)`0#OU<=3BEy-f(*VS0su*R-`JLBo*fIXc0s?&vjdG9)YKjH(R?m#!v@#PJsU)~tU zm#4b&#yb8+;#=TuxXsKRQ6Fvo>aeR5TjrXkMw<6vKz6?7$zUS#yZ+8COsPi`L3Ey+-dtM*MA3%IC90o@? zzUS#Y*!llJofU93T<_FZd=vc#;9x`G4 zcqWsV$MH)OzaKsTA9j4td(`o(6R!oeEB8~5?|IKSeq-VJ*D98Vl_*ggzPIdeV#+yZZuH&oDG~+FB{N=<~!3}VWwx5C|y-<^05 z_yPRL@#Xb0-T=q{l=xUU0ecDW^C4v(I#y$J}~`U}CLj&Hr1cy%1V zDe)GtE$ra;_H#~tb(2?*w({)!V(D)OJHXD+ z`kvR-@!uk@of_Yz{ek0q-bao&Vzwr;fR^RMv|<0W-` z)sdG9FP-C;C;lL;468Z5yo$!F<@nl~vpxNtVOPiRPkay@3nx3i;?w9)nl7+{X`o%t z*?4o|61WUnU*3G#NQac+bE_(E5rurvC-l!tt&5 z4qk7^|AhERI1Wy9e8nfzuWeQ5IR1CU7r>=(h2t+a-fG(G9ba|iZNmG}@plm44S#|^ zJN`c79ix51@l{9OIlMm|U%R)aV<*$Q;N8&vJY+In9@_aGzX(&^0kky^0Z~H^6dP^ zQfC631gARnJ#V_>&msODTmY9izUM7-{58ba!>w?K@h{*MIL-03J@RV$cfy|>U-2XKKg`C!RiHgzC-HuR+64KMQ(xX$`sH1A{N#+A z3Z{h_ocVZO7RS#)JU7e-3p&2%6>TqcNEO>cf87J=$@ni5LJOgv{{j4&Oa1a;x*F{C}5F|( z*N`VFo|@~=v%%u96f6ssC-&fa=HBo__%U1tcS7ZfgNSSQy4ken!lh7k{-Hg?x!&}4 z>*=~(%}c!9dRd(LY2FLzUjkP+zUOUq{1>=Ru^H?Rb@RGWw7-EmPVsZD=lTjxhjXAj z(er+A{N7wgqw9{w(Eh@?zQ*&ki`cj1Eq3xfZ;j*Yx}w}%uTT;;gFirRyrp#z<;CK4 zhVManqMoPqaYKGO9+6=92wUb>hfly)q0wXd6CVmkz#rjB*oIwpZT>jozrr){Jp2=0 zf;Rt60^Q*VIMa%>6YxBm9Apx5UMfe^Z2q(Y< zJfGlfhXt}xW=o(j&-6Y=~09$3No{jcvg=i&9nJy17;w)Nxd@1@>x)sJI7iIN9KYz^DP9?;Im z^FDC=$2l)gLG4e`i1xGa1sDq(vF^HMcW>HuKJl$Tp89q_iN~G#gNXkKcfzBNukU@^ z?{({Y*yA`aNu8gMro^??^INp_eN}t>o;S>?zlivcP~Yb~>iC}byW=aKgy+eOFblNv z_q;NWuXru`^?cpL@vYYsuQk;7^_n`*-|8w8{BdHt*JIqCJWonLOexbpP6+UDzfV)|ZKIcHoiU-NpO zygpFhx3c4@&UC!*;6iA9&-1=tG{@9kO55`lFOe)TvcC885N$gj&(j9Vy2rHsPON5_AMxW51LG3|klulQv8XTVu-E}Rb+!tbG7uW0jDkgvZh^}QBb z&-3&>73)tRFcr>#v#l71x76_!Uq=5*xCU;3yP-u~dDd5*y>uLahv6}J7V33+@cl&M zLR@v^iK_EAfmFPH$_nL)isz!gBz)NM<>~K+q9#vuMe9|;*Xv7pqVDvfedk`of8Ci+ zcjCR_`>>DWd)^TIQSdV-f4Jj~BR&g$@8rvyO#gI~r*#mmw*h~TQ(xmQqkkn_>-e6h zaSoC9D?A7PaO#~g-c{NuoY&uqXQV$1%u?Fy|2=Oxbj5LYlGhfYF|<1iSo3s=_~l!f2}9&zHlJazG|u?dUZ4p zd7`a5iu#kFJW=r}^v{5^9sg^`TS)wSxE!v8+V@T4iq_kYuYEz~iJR%y-<#SePWz{x zr$6|97k^JCf~q50F9lv^$5&kYv*`{{dY?jdMeWOGy<*fa1ydR-> zF8c3<`kbyjZQYMSOPt?9&+Mi2z4$I}dU!nLt^lP84%8oCuIQ^wf zp5`H1Pwyu+bn5H#Tzy^;*M3^^bQiM8)cxA2uYI|!Hv?av`)+pf<>`H+B_>bDEn06s z{t2hP#{H509dM81d!EKQOWxnme(s`qir0;IC+}zFgz`kii_m``)V^Kv#2WNJ4z=&r zQ?#Ff-hNqejTy}^%Y-F|BrB|<8OAn{lt&JU*TDJ9%`PV=Uu|rzFwJ~ z_a_q&PYjd76j1wp6{KAZ>SlSGhiE;$AFG?{$rBaVeq6Pw|0JvrpM%X|EL0s)b!yOW z>&O#Tr#=41a4^(B`uD=09N+Vf zdGbW-)y99;ssAGJ zH{e_F9mnrYydTuQAA=m<^G4&3huQ~3$02_1cvFaLUys$al_$#khJNiEqC9z`^|q6D z*r~5^*U`TbZgqUm(>N!{I}iVcx;LTbDgI@=B<$aiUi&ymgo@uye=eBM@jb7!<11d4 z{_@c7Gg6cI6R;jM(~XI%j`eL_?OW1<`mJGGXFSjAg#R|w{v&pLd9UHU4!glVa4;MJ zM?+iBtD|{X-_{*Z-RVw!#kG&g?e1T)ocgPw_9@v&dy6x^^^W3QaQt1w_re445Y#>< ziMXIL8BD1QEX{&hPy3SObbQ70&>!FZMzk+US@Iu%55r3EF=(b6W4*d~Pr>@IF>D33 zZ;7p^ajN6Bhp$2FYd;iQ*XH#g-|lZ>>v`UXt6k7&P<1bo3GF-!_mKwCeqye#D9ck&f4NWbqc;Q2RjGe0e|MY2OLuS>Jj`$@?8zU*l?@iUW9u9pCdb z&PC<%{rcoEmGgaj?Gqs{D_#M|S6ur>XkUnmj{hX_r(py5EPNiefp&f3%Co-eyiC1U zU}xABY9EOAY4?G)UR-so@6{bh{V{N?GoHL5^xOR?z9g=FCg#$f@6_|^XdZU{w(fH3 zZgJ`>zK#C9Q2R*O`nw$ODDhM9JiG}1fwrFKUB}PL_vmvv-=|MbJQYj}(?jheQG&Mi zi6~Fo&c}M%58`phSG*4W^Jf_?63&5$CH+L zM&oH8gmT0mgVkXzXzN+8K3+4&Z%w={d>M9he9!BF|32*ROOe7?!x;%iLT?*bvl!|o@6U^c0zq0)=uj=uD{avbaY*vu5+{g6nx#s z^IO_Gp!FYQ{AlN+`^a{q-Y0ObQ$IHY4u<341UMOb=R@D;zMuLJz{g-+sOu4%(bo5w z+R<(g87>IjhfepaOUCEy-u>C0px@r7Z9MT{VgAtRT-n*f$`_%UobzLWV5I^9j=I8WDsP6#=MgF1dA-^E+OQ@ei{ah?0Zu6g}zOIw& zMtd+E11Cb8e~h2sbI`laMc@BP!FkH)oUfPp+)tnL>T}&8&gX}^-_RoZ^}Xkx9lt#X z& zwrh#WO`-CzzAa3<8GISO1&2e6aRjEp#c&t2I7#47ScB(}meBh8zCaK9^?PKC;}0UP z`=O6DdA7dVdbsiNRE+cITudwpuR!e=&_jhB>em%-`^SvO)9?4+ojiqY{$1)Y%uTxl zECcU{9`e&s1eSEf0bJiTir;6t@7@O52lRVR3u@}jBYzRpeJQul-VS%cBk&h!%EjDn zoqwHriI{&9%w%OKR}IZ=c~t$UiY3u z(DRG+pXB+VA$%6rtoC*5fL!`r1!PuY>hE%6onEfSHfJ|K5wZ9Z&PMo~}zi zMV>vLUL1$^GaBhUUZbslF`o1L0KYHn=j2ysUQfcO;WN&BPZ7Tg^|;k_m3IAf9i;AC z+L6bDUI$t~zK;hz4)puCEkEDA;3BvRhK=WV`S`gn5AEM|Yl&-Lumt*fHv`O!vVIln zne-She?4_KLGSg%2~6ok4Q*< zDwq*wgH52FhrTbP@1=Z$w+60 z^9Ih;BXB7E3{HYG;CFBZ+zNNY6VRT2yDptr7d=1fe&F8yy7m2#1LQrz@9D{T>_~yO z_4WJykKEDuX?Q+~jne;%zoY(zckp*dH(ogFI=nQz(9I01 zfcL^;uq4#|i65bD>;Jdv>hJS@j5Ej?&+{%izT(&Dzk_v70n@|WP}d0;q-~G)cI&+2 z)KlF1Ik4m3?$5;}u0zoE5p!wlz8<@2?}vxr33v(WdWKYd?yUPdEK4QpA=uj=P%k{dJFB{Fmr~$$T?v}XyWG&p0^HvGrR&5@Bv_Am>i~tcGkCB$NPO+ zn%52X^~f8}>j}mGw_dN&dG8dknSu7HLIJ*UZ-6~vUpN?!hg0DkI1jFbYvBgC9qxj57XQD-U0F0R@>=*< zu|T^jd>-2QMVptigv|`J6;D|z(9Q&>!0B)STnyJiTlIG93@B|Y1=@vK2M@!e@HjjLZGG$gj`ugb46nfi9A^^ecr{LZ>)h`8 zF5vw*Z{I6>yxP~PVZuO<-5*K&7->JH5Ad{)k*%jX&G5AEt@5ld?%_2p@v z+Mj5Z<7vuMix5b%{ zyy5h3hr1nLo~{d$x8L#Q={V&bbbPIYJ+HIybsltF_W0#3!q;)@xU8@D!+*ioK2>L( z`FY+2$FEAfE{uik9ABQ^zn_5jrQ^%f<7gh9_V2RCE3Yx$V(9(6%4=#o@8?fmOZ=Je zTWIGaPwOI2$6mxlZT=ebdCdXZiJbZBbDiDBONO5VmUr@ZB?`>o zC#cV5f1z#Xmz?))i@?&b0!AWE7;cYdl7#h_J#c&ebSdz76hz`y5}7+wA7?o7;K(>i3AAS9as+_o|)0;%Rw& z=Yd6_KF6#_+vY1z*Lx_h41N_;r$6oCa6Fs_ZGF|%ylh>~OP@c-Qm36$PoKkDFRpoM zzrqdF?VLC;(~sd`I1+va?eS=Q?IWpqc5~({??w9M^>Tc9IzD-Q9A9xA|7bj&7dwBQ zr$^+&ZoxJ z_bBZ3MYg``$jeS$?HBnhZC(G=g7)qHyy-fpG}OrqHLjhXy!3dQm+muTeR--|h&)|K zZhh6Uo_D>u;<~?GMe0|Ew!Y%k>DTod^&MZ{3Pi7m#4b+dCvM%s5=d6ztDxwd}bN%d)mw4R=5+| z@l;oNYw$L}gYc-6zt4Do(f$WkVcl!MI`DSSm*#PT`sbj=wa2GdtR*{?RnPq z&R%|V=GO*xbdE>fOUBdlf~_x4b?x(p^@mb-1RMt^LF<2NJl!W~I&oc({)3aRy2_i4 z_Z?gZH#_;OjCYv!F<64@#Y#inFUdO}8fP2%+V@p;?eS}zllbT0U(ovUP8-j={$8Hy zUL#M}<=gtIV?ABJZ+*p6vOc=5KPzqPE1rY?{P14KmzT$QIxn`qJk_=5&H8Jpn}PQe zbUoYMv~$6HP}j?Sr$6jXLDkzv-Tm+|`~{waf5C***Z1H4+we>i)a>zJ~7KrTtdzd~KfgVIAX)HFN{-N$wn9zB=S@(Wi1;J0CamlDy8oQKdUy@s zi!j#7S6!R;9KP-++u6x)N?haE``6j^Q=P8l={|S*UbFQT?~nfp91X26Z?N&kI=(#B z{Q_@_bGb@A!*|%R5Z_xa0pwd>71=Dlp^R(9U0; z>YgF*52wENBaWqBXV~4TKY{pUsQqxSIsOddb6{eAev(5w|9Nu6FWOcNqPn;O9`^Z&O{n zJ~mJL4=d05c3wLeXD_tA9^di~;_2~jeedyq*{PqL=Ycd(-@CiZd4BM`yB%L~eUGjP zUIoX0j(D`sS9)I5^R)Iqujo8p3K6%@(>AXPUVZo+{BJ$)KIXihimSfXr6uds9rlC+ zp!PSOOk4XH+n*Qvdtwv*c4&Q#Yk!Yu9v_mYdDwi-Q=Xlt_F-P&jIZOc-uL)xppL_i zFK;=X_Cx-O_OI{^wE4=@I9eywxjB8BhBwr%V?pbSKONv%_4_3>Rbb zO5ok^__l6kyqb=${hQ^zg4f0I>k_XA+d-SBeUi&&))$vuwdI_B8PsNkap9W@de8scSp9|jO`0}zFPv_CD zr##iQ=h^!DyL?~9Ku;gur~A`+ziu4!Sd70F#y9^k-}^oR%j*JDGr@_BHv_JK>!8tN z78vg*+D9FK2XT3qXkT%B?Yk^59rMow?R=6Fmsgl}amUY1TwWd8^&J0U;?-bd=4!{Io`@5yIR9h7$5;Fr`d@%AI=F)@; zIKI4g#_Q(z@>I76-g}O(I@Z(U+y4CRqs}GxkLo(VU(#d>R7elA!Q9Z+mzUXi1sq?V z>dGtX`1cd904u{9j$g@mwP`;IpNB1=Js#DydG+yI!XNhZ^H);29eAVe_yxxwl z_=oflgu@(PUO(fFa(sEJ`x)K@$5$Qeed+j$e?|WsIN$LVUrhf>xX$tA{b0P!jxSGj zwLi^n$5)*&&v`t};tM(7!;SEezNlk<02R+__Op4|+0RB^9{TTf@~RTA1)qXu_!wKq z=G7;!HEahv!k+MbXzNFt_c8gyV2iAQN^iklFs}Mt$nWmVNAs4ad24)IUv+exqp3UI zsXvMMR5%;XbNm^`TSR*)+z5Y!c7CdB^H$*Rg!`QQwZt{f3EHO}U-M91dFLHp;~u2{ zFZi$HtB$;socFY_CaeSN!DxS8H10LVzk_^@W7k(+LOjhQBW>%;Q{B7payY)~STB#` zE1sYJ;;^*iD_)NNO0bIK%X`pxT6cTA@>JKJ7wdcHsRsLNwScW*2iO^U^;$9C4zP=J zeDc~FPtP;9zC6{{^H3kB{!rp0;5azR@jo@*RNB+wBKQNe^HW{r&BprBp~FU?~c_4h-KYmZO!IEi--{spZs@3is$b$ofMdks(fy4m`wV?FI7 zXMM#}vThk+R%m_2bI_k3-s|}C@)%F&&DNKvy7s(UKic#BkiMvF3Mjue^Q#XVJI5pM zN#p5x!IY1Yr@Hoe!}@Piw-@{f4usbKz<5JxkARclSJ39GuJS&`8wcmW`A+^f##>K& zGtA1m=YV;kcRn=EV)9o()wT22INR{{!9&pc@^%^TnB&V+-II7{9A9;;ci!<8|BL=> zFp=}~s(4cR)5467FE6F>bYATG$WvW=-mE{8x?ACPxECIPN8m58x3gcP>dnMk2!DX9 z;0E~L8gD%HG{4_y+vAn@CH?X)IKI5E=}*P}ml>d~FHgsRnY;uhFN>3Z5#Qz|b$rD& zueQiL9;HrI_&9tTHiAu{&9`~&@H#oZ>a?K08|(@D z!v4^Xr}$9%$HU2vKZ5ueI2|r`e0jF6^6Y$6XEpV-zv>pJzV&wC?R9+Bk@pkc5qKV6 zbn;bKc_;C-Pi$hIC%pY)Rrg==(&J}wo?p@smsf;#3D_2PfUiRD`AXy5jaLAwu00>} z^5ALQGPJEPPj$=VJ?!|ZW4%WmU-7E+KLP7IzT%DOZw6m-e0fcbr**c+D^GRpd9eN< z>W+lFiv)~A(E3a8w!>X&v%l|7_yil;{6L*`w^{E70z&cd6SH%^J3RWp6c53X8qIDjrRFR zUPGR*UVw$}2~^he)>h~FYb$=$+yTD^tP7ulO<+@)i~2FIq~>gl+r(Vhe6!5H(O^)hlkvqPiDET_(DxDjrJyWl<;WB#*w zC-Kh0OYky`G5^_dwxJLe;=MO2!&cj>c_;DRaU-J4p`8rPP4Z$A+$2FTu8sZ@mt9uR6Z!$a@3tE%*@}=;W)e@_OOD4?l(DoqW|DO8-~z8^{0Bct6ly z39rF~JU=Fd-t(o#nM2+psJiy&OWr&@jk}Jv_2sGVCcJHquR7M-<@k#4qyH#8>G+DD zrvFd)kK@ZbXFRR5JzjaLYtMuA^>^;p{DGcl3I^B=CNCOjcZW8=8RvKIZRYnO|7$oy zZR*7}{wMNpGk+d=i{J{l4%*|Dx72uB9ABR5?!?>g_=kueg{R>;_z%1aQ?gF!pq;Pk zoG^9%qHTS}HBLh6-T^bhtj>6vhrB#^1sq>>au~0OdzPyKw zSIhC`scv1oryXB)tk=--6>m&`OW4No6>m>}7ue15<#jUNJB}|;b$jFWaeURW-q((= z=b>Nd{}rAqV1H5r?W^=Bpg%cG>-h4L7%!9K%Trx>*&RPW@xt&vSkCc_8}C8dm0)f7 z6tt_Lx;C#eegoLp$*)0NKW8s{1kCV8>S- z>wV(*ijSgy0-WslihoW295~fpKIOfP|2iC3*qVX%NczXaZ{b2{v%WUoCfeH_em z`y&1F?!wFI_-TpDD@D7U;};?>?+Mz^IDSRq)nH#Z$noW=ZWFxLj=zuiVR#yzbNstG z?|EQ5*wOiUC`7!N@wzyE8R8E>dEFfU5#m*$ymuVGHu0yRy!RZx0rAFAUSG$T*Npzw zQ0ruW>WnPe*=cXy=oZxV);gA9s8^zovLE zIsQY$RrgKW?>K$~;;K88_9(~iNL+Qt(f-o$KO(NW-_V}x_^Kms6`t-dYu8hCmf)R* ze>?THO^m+oq|1h!x3gocr-yAZI}zHdBd-kc3XZQj@+#p~b$r#a-iz_{>*7BRpLOz8 zw-fzcVRy%WkN9x-DVzl7zRzQkVS>Ovl0uu7mUsr31KtZuzz1MOSQ$oJFF(HOm2vVF zk9IuGTlcNfyjnQ*J--hA)3A|~Z|9}^SoMjg-x>c6*u%+J-B0Kr4aYkEWa7FX)-2lF zEx^Kee{=u4>^7{;*H?*ur<{EA3M_S4&Q-xeN^vh`c8bz9Ki z8ouoKU5I}G`@xY=_i39%+s;?{y-fZf$5%Ys`tm-dp60QX_6oSh8PCg~jz1gDbMh6B zc0B8Cr0#L2zUS}2-wO{q`Ko(?{!8$R<0noWID?sBHdqjrgk_*T-^x!%zw&h-H|r}N zZGCw~%sgt*t_$lyJD!*S5dNdEnv<`1wBuQ?A$2=B^*z5SeoNTK$yeRC>3ppP*YMxGh4Do2klb4*lEHFR37nX;1zFvNAlV8Hg*E(q2=kav^vsY;Mh-ZE)eC2m> z^6ha}#Cse*2{kW!{9b-Flm85Do9`Xxn0WfSuiMAu4RP{ScN+b(;6nI4Tn_Dgl|Pw& z<$L$nQ#{)Gp0|bZcEDep`FZ*4P5xdd{}l1FFjexv3S@=(U`c4#$IH)X@(Vfn8uwqu zzYY^SzUGyae$7kwhpR%oemwIl;48nDlkbhw0$=x)do!N-&zpSRXU?v754?}yKsXFq z|1;t<;C#3YZh*Q^nwLM-oKI1-M7cK%+yxA0YOpp&n7wBu=> z@0)pjM|&as-Wku!pMpOf&UW$@k9ItJT&Jj;C}m(Jlfl%`uCJH>Cw2aX*PZz)9_@JE zaUFK*d;S{yjc}Wj@6GF8XFWVWGk$iM$H`aS;`En>kHD(19<=Af%YV@1*K+dhIKA

O#JWQA}3$*Xvg!s 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

SIxr=y^IWcH&?s)J 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 z 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 Z{iASPr4n%yE Date: Sun, 24 Mar 2024 15:41:27 +1300 Subject: [PATCH 11/62] Added data files and config file --- src/EllieBot/creds_example.yml | 115 + src/EllieBot/data/aliases.yml | 1391 + src/EllieBot/data/bot.yml | 91 + src/EllieBot/data/fonts/NotoSans-Bold.ttf | Bin 0 -> 415132 bytes src/EllieBot/data/fonts/Symbola-10.24.ttf | Bin 0 -> 2440452 bytes src/EllieBot/data/fonts/Uni Sans.ttf | Bin 0 -> 50856 bytes src/EllieBot/data/fonts/dotty.ttf | Bin 0 -> 51848 bytes src/EllieBot/data/gambling.yml | 261 + src/EllieBot/data/hangman/animals.yml | 276 + src/EllieBot/data/hangman/anime.yml | 766 + src/EllieBot/data/hangman/countries.yml | 390 + src/EllieBot/data/hangman/movies.yml | 400 + src/EllieBot/data/hangman/things.yml | 380 + src/EllieBot/data/images.yml | 39 + .../data/images/cards/ace_of_clubs.jpg | Bin 0 -> 3794 bytes .../data/images/cards/ace_of_diamonds.jpg | Bin 0 -> 3994 bytes .../data/images/cards/ace_of_hearts.jpg | Bin 0 -> 4250 bytes .../data/images/cards/ace_of_spades.jpg | Bin 0 -> 4856 bytes .../data/images/cards/black_joker.jpg | Bin 0 -> 5591 bytes .../data/images/cards/eight_of_clubs.jpg | Bin 0 -> 6416 bytes .../data/images/cards/eight_of_diamonds.jpg | Bin 0 -> 6658 bytes .../data/images/cards/eight_of_hearts.jpg | Bin 0 -> 7120 bytes .../data/images/cards/eight_of_spades.jpg | Bin 0 -> 6152 bytes .../data/images/cards/five_of_clubs.jpg | Bin 0 -> 5219 bytes .../data/images/cards/five_of_diamonds.jpg | Bin 0 -> 5487 bytes .../data/images/cards/five_of_hearts.jpg | Bin 0 -> 5677 bytes .../data/images/cards/five_of_spades.jpg | Bin 0 -> 4957 bytes .../data/images/cards/four_of_clubs.jpg | Bin 0 -> 4583 bytes .../data/images/cards/four_of_diamonds.jpg | Bin 0 -> 4933 bytes .../data/images/cards/four_of_hearts.jpg | Bin 0 -> 5106 bytes .../data/images/cards/four_of_spades.jpg | Bin 0 -> 4434 bytes .../data/images/cards/jack_of_clubs.jpg | Bin 0 -> 9471 bytes .../data/images/cards/jack_of_diamonds.jpg | Bin 0 -> 9763 bytes .../data/images/cards/jack_of_hearts.jpg | Bin 0 -> 9558 bytes .../data/images/cards/jack_of_spades.jpg | Bin 0 -> 9157 bytes .../data/images/cards/king_of_clubs.jpg | Bin 0 -> 9331 bytes .../data/images/cards/king_of_diamonds.jpg | Bin 0 -> 9386 bytes .../data/images/cards/king_of_hearts.jpg | Bin 0 -> 9541 bytes .../data/images/cards/king_of_spades.jpg | Bin 0 -> 9248 bytes .../data/images/cards/nine_of_clubs.jpg | Bin 0 -> 7033 bytes .../data/images/cards/nine_of_diamonds.jpg | Bin 0 -> 7151 bytes .../data/images/cards/nine_of_hearts.jpg | Bin 0 -> 7499 bytes .../data/images/cards/nine_of_spades.jpg | Bin 0 -> 6577 bytes .../data/images/cards/queen_of_clubs.jpg | Bin 0 -> 9574 bytes .../data/images/cards/queen_of_diamonds.jpg | Bin 0 -> 9785 bytes .../data/images/cards/queen_of_hearts.jpg | Bin 0 -> 9530 bytes .../data/images/cards/queen_of_spades.jpg | Bin 0 -> 9613 bytes src/EllieBot/data/images/cards/red_joker.jpg | Bin 0 -> 5742 bytes .../data/images/cards/seven_of_clubs.jpg | Bin 0 -> 5965 bytes .../data/images/cards/seven_of_diamonds.jpg | Bin 0 -> 6213 bytes .../data/images/cards/seven_of_hearts.jpg | Bin 0 -> 6617 bytes .../data/images/cards/seven_of_spades.jpg | Bin 0 -> 5796 bytes .../data/images/cards/six_of_clubs.jpg | Bin 0 -> 5736 bytes .../data/images/cards/six_of_diamonds.jpg | Bin 0 -> 6113 bytes .../data/images/cards/six_of_hearts.jpg | Bin 0 -> 6416 bytes .../data/images/cards/six_of_spades.jpg | Bin 0 -> 5563 bytes .../data/images/cards/ten_of_clubs.jpg | Bin 0 -> 7417 bytes .../data/images/cards/ten_of_diamonds.jpg | Bin 0 -> 7520 bytes .../data/images/cards/ten_of_hearts.jpg | Bin 0 -> 7770 bytes .../data/images/cards/ten_of_spades.jpg | Bin 0 -> 6862 bytes .../data/images/cards/three_of_clubs.jpg | Bin 0 -> 4052 bytes .../data/images/cards/three_of_diamonds.jpg | Bin 0 -> 4303 bytes .../data/images/cards/three_of_hearts.jpg | Bin 0 -> 4660 bytes .../data/images/cards/three_of_spades.jpg | Bin 0 -> 3918 bytes .../data/images/cards/two_of_clubs.jpg | Bin 0 -> 3441 bytes .../data/images/cards/two_of_diamonds.jpg | Bin 0 -> 3804 bytes .../data/images/cards/two_of_hearts.jpg | Bin 0 -> 4016 bytes .../data/images/cards/two_of_spades.jpg | Bin 0 -> 3327 bytes src/EllieBot/data/images/frame_gold.png | Bin 0 -> 49859 bytes src/EllieBot/data/images/frame_silver.png | Bin 0 -> 13319 bytes src/EllieBot/data/magicitems.json | 314 + src/EllieBot/data/patron.yml | 69 + src/EllieBot/data/pokemon/LICENSE | 21 + src/EllieBot/data/pokemon/name-id_map.json | 3622 ++ .../data/pokemon/pokemon_abilities.json | 1930 + src/EllieBot/data/pokemon/pokemon_list.json | 29770 ++++++++++ src/EllieBot/data/searches.yml | 47 + .../data/strings/commands/commands.en-US.yml | 2371 + .../strings/responses/responses.en-US.json | 1064 + src/EllieBot/data/trivia_questions.json | 48987 ++++++++++++++++ src/EllieBot/data/typing_articles3.json | 242 + src/EllieBot/data/units.json | 757 + src/EllieBot/data/urero.json | 1 + src/EllieBot/data/wowjokes.json | 302 + src/EllieBot/data/xp.yml | 58 + src/EllieBot/data/xp_template.json | 145 + src/EllieBot/data/yomama.txt | 170 + 87 files changed, 93979 insertions(+) create mode 100644 src/EllieBot/creds_example.yml create mode 100644 src/EllieBot/data/aliases.yml create mode 100644 src/EllieBot/data/bot.yml create mode 100644 src/EllieBot/data/fonts/NotoSans-Bold.ttf create mode 100644 src/EllieBot/data/fonts/Symbola-10.24.ttf create mode 100644 src/EllieBot/data/fonts/Uni Sans.ttf create mode 100644 src/EllieBot/data/fonts/dotty.ttf create mode 100644 src/EllieBot/data/gambling.yml create mode 100644 src/EllieBot/data/hangman/animals.yml create mode 100644 src/EllieBot/data/hangman/anime.yml create mode 100644 src/EllieBot/data/hangman/countries.yml create mode 100644 src/EllieBot/data/hangman/movies.yml create mode 100644 src/EllieBot/data/hangman/things.yml create mode 100644 src/EllieBot/data/images.yml create mode 100644 src/EllieBot/data/images/cards/ace_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/ace_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/ace_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/ace_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/black_joker.jpg create mode 100644 src/EllieBot/data/images/cards/eight_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/eight_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/eight_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/eight_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/five_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/five_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/five_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/five_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/four_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/four_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/four_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/four_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/jack_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/jack_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/jack_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/jack_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/king_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/king_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/king_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/king_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/nine_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/nine_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/nine_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/nine_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/queen_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/queen_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/queen_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/queen_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/red_joker.jpg create mode 100644 src/EllieBot/data/images/cards/seven_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/seven_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/seven_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/seven_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/six_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/six_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/six_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/six_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/ten_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/ten_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/ten_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/ten_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/three_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/three_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/three_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/three_of_spades.jpg create mode 100644 src/EllieBot/data/images/cards/two_of_clubs.jpg create mode 100644 src/EllieBot/data/images/cards/two_of_diamonds.jpg create mode 100644 src/EllieBot/data/images/cards/two_of_hearts.jpg create mode 100644 src/EllieBot/data/images/cards/two_of_spades.jpg create mode 100644 src/EllieBot/data/images/frame_gold.png create mode 100644 src/EllieBot/data/images/frame_silver.png create mode 100644 src/EllieBot/data/magicitems.json create mode 100644 src/EllieBot/data/patron.yml create mode 100644 src/EllieBot/data/pokemon/LICENSE create mode 100644 src/EllieBot/data/pokemon/name-id_map.json create mode 100644 src/EllieBot/data/pokemon/pokemon_abilities.json create mode 100644 src/EllieBot/data/pokemon/pokemon_list.json create mode 100644 src/EllieBot/data/searches.yml create mode 100644 src/EllieBot/data/strings/commands/commands.en-US.yml create mode 100644 src/EllieBot/data/strings/responses/responses.en-US.json create mode 100644 src/EllieBot/data/trivia_questions.json create mode 100644 src/EllieBot/data/typing_articles3.json create mode 100644 src/EllieBot/data/units.json create mode 100644 src/EllieBot/data/urero.json create mode 100644 src/EllieBot/data/wowjokes.json create mode 100644 src/EllieBot/data/xp.yml create mode 100644 src/EllieBot/data/xp_template.json create mode 100644 src/EllieBot/data/yomama.txt diff --git a/src/EllieBot/creds_example.yml b/src/EllieBot/creds_example.yml new file mode 100644 index 0000000..8146199 --- /dev/null +++ b/src/EllieBot/creds_example.yml @@ -0,0 +1,115 @@ +# DO NOT CHANGE +version: 7 +# Bot token. Do not share with anyone ever -> https://discordapp.com/developers/applications/ +token: "" +# List of Ids of the users who have bot owner permissions +# **DO NOT ADD PEOPLE YOU DON'T TRUST** +ownerIds: [] +# Keep this on 'true' unless you're sure your bot shouldn't use privileged intents or you're waiting to be accepted +usePrivilegedIntents: true +# The number of shards that the bot will be running on. +# Leave at 1 if you don't know what you're doing. +# +# note: If you are planning to have more than one shard, then you must change botCache to 'redis'. +# Also, in that case you should be using NadekoBot.Coordinator to start the bot, and it will correctly override this value. +totalShards: 1 +# Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it. +# Then, go to APIs and Services -> Credentials and click Create credentials -> API key. +# Used only for Youtube Data Api (at the moment). +googleApiKey: "" +# Create a new custom search here https://programmablesearchengine.google.com/cse/create/new +# Enable SafeSearch +# Remove all Sites to Search +# Enable Search the entire web +# Copy the 'Search Engine ID' to the SearchId field +# +# Do all steps again but enable image search for the ImageSearchId +google: + searchId: + imageSearchId: +# Settings for voting system for discordbots. Meant for use on global Nadeko. +votes: + # top.gg votes service url + # This is the url of your instance of the NadekoBot.Votes api + # Example: https://votes.my.cool.bot.com + topggServiceUrl: "" + # Authorization header value sent to the TopGG service url with each request + # This should be equivalent to the TopggKey in your NadekoBot.Votes api appsettings.json file + topggKey: "" + # discords.com votes service url + # This is the url of your instance of the NadekoBot.Votes api + # Example: https://votes.my.cool.bot.com + discordsServiceUrl: "" + # Authorization header value sent to the Discords service url with each request + # This should be equivalent to the DiscordsKey in your NadekoBot.Votes api appsettings.json file + discordsKey: "" +# Patreon auto reward system settings. +# go to https://www.patreon.com/portal -> my clients -> create client +patreon: + clientId: + accessToken: "" + refreshToken: "" + clientSecret: "" + # Campaign ID of your patreon page. Go to your patreon page (make sure you're logged in) and type "prompt('Campaign ID', window.patreon.bootstrap.creator.data.id);" in the console. (ctrl + shift + i) + campaignId: "" +# Api key for sending stats to DiscordBotList. +botListToken: "" +# Official cleverbot api key. +cleverbotApiKey: "" +# Official GPT-3 api key. +gpt3ApiKey: "" +# Which cache implementation should bot use. +# 'memory' - Cache will be in memory of the bot's process itself. Only use this on bots with a single shard. When the bot is restarted the cache is reset. +# 'redis' - Uses redis (which needs to be separately downloaded and installed). The cache will persist through bot restarts. You can configure connection string in creds.yml +botCache: Memory +# Redis connection string. Don't change if you don't know what you're doing. +# Only used if botCache is set to 'redis' +redisOptions: localhost:6379,syncTimeout=30000,responseTimeout=30000,allowAdmin=true,password= +# Database options. Don't change if you don't know what you're doing. Leave null for default values +db: + # Database type. "sqlite", "mysql" and "postgresql" are supported. + # Default is "sqlite" + type: sqlite + # Database connection string. + # You MUST change this if you're not using "sqlite" type. + # Default is "Data Source=data/NadekoBot.db" + # Example for mysql: "Server=localhost;Port=3306;Uid=root;Pwd=my_super_secret_mysql_password;Database=nadeko" + # Example for postgresql: "Server=localhost;Port=5432;User Id=postgres;Password=my_super_secret_postgres_password;Database=nadeko;" + connectionString: Data Source=data/NadekoBot.db +# Address and port of the coordinator endpoint. Leave empty for default. +# Change only if you've changed the coordinator address or port. +coordinatorUrl: http://localhost:3442 +# Api key obtained on https://rapidapi.com (go to MyApps -> Add New App -> Enter Name -> Application key) +rapidApiKey: +# https://locationiq.com api key (register and you will receive the token in the email). +# Used only for .time command. +locationIqApiKey: +# https://timezonedb.com api key (register and you will receive the token in the email). +# Used only for .time command +timezoneDbApiKey: +# https://pro.coinmarketcap.com/account/ api key. There is a free plan for personal use. +# Used for cryptocurrency related commands. +coinmarketcapApiKey: +# Api key used for Osu related commands. Obtain this key at https://osu.ppy.sh/p/api +osuApiKey: +# Optional Trovo client id. +# You should use this if Trovo stream notifications stopped working or you're getting ratelimit errors. +trovoClientId: +# Obtain by creating an application at https://dev.twitch.tv/console/apps +twitchClientId: +# Obtain by creating an application at https://dev.twitch.tv/console/apps +twitchClientSecret: +# Command and args which will be used to restart the bot. +# Only used if bot is executed directly (NOT through the coordinator) +# placeholders: +# {0} -> shard id +# {1} -> total shards +# Linux default +# cmd: dotnet +# args: "NadekoBot.dll -- {0}" +# Windows default +# cmd: NadekoBot.exe +# args: "{0}" +restartCommand: + cmd: + args: diff --git a/src/EllieBot/data/aliases.yml b/src/EllieBot/data/aliases.yml new file mode 100644 index 0000000..6bf6b78 --- /dev/null +++ b/src/EllieBot/data/aliases.yml @@ -0,0 +1,1391 @@ +h: + - help + - h +gencmdlist: + - gencmdlist +donate: + - donate +modules: + - modules + - mdls +commands: + - commands + - cmds +greetdel: + - greetdel + - grdel +greet: + - greet +greetmsg: + - greetmsg +bye: + - bye +byemsg: + - byemsg +byedel: + - byedel +greetdm: + - greetdm +greettest: + - greettest +greetdmtest: + - greetdmtest +byetest: + - byetest +boost: + - boost +boostmsg: + - boostmsg +boostdel: + - boostde +logserver: + - logserver +logignore: + - logignore +repeatlist: + - repeatlist + - replst + - replist + - repli +repeatremove: + - repeatremove + - reprm +repeatinvoke: + - repeatinvoke + - repinv +repeat: + - repeat +repeatredundant: + - repeatredun + - repred +repeatskip: + - repeatskip + - repski +rotateplaying: + - rotateplaying + - ropl +addplaying: + - addplaying + - adpl +listplaying: + - listplaying + - lipl +removeplaying: + - removeplaying + - rmpl +vcrolelist: + - vcrolelist +vcrole: + - vcrole +vcrolerm: + - vcrolerm +asar: + - asar +rsar: + - rsar +lsar: + - lsar +sargn: + - sargn +togglexclsar: + - togglexclsar + - tesar +iam: + - iam +iamnot: + - iamnot + - iamn +fwclear: + - fwclear +aliasesclear: + - aliasesclear + - aliasclear +autoassignrole: + - autoassignrole + - aar +leave: + - leave +slowmode: + - slowmode +delmsgoncmd: + - delmsgoncmd + - dmc +restart: + - restart +setrole: + - setrole + - sr + - giverole +removerole: + - removerole + - rr +renamerole: + - renamerole + - renr +removeallroles: + - removeallroles + - rar +rolehoist: + - rolehoist + - rh +createrole: + - createrole + - cr +deleterole: + - deleterole + - dr +rolecolor: + - rolecolor + - roleclr +ban: + - ban + - b +softban: + - softban + - sb +kick: + - kick + - k +mute: + - mute +voiceunmute: + - voiceunmute +deafen: + - deafen + - deaf +undeafen: + - undeafen + - undef +delvoichanl: + - delvoichanl + - dvch +creatvoichanl: + - creatvoichanl + - cvch +deltxtchanl: + - deltxtchanl + - dtch +creatxtchanl: + - creatxtchanl + - ctch +settopic: + - settopic + - st +setchanlname: + - setchanlname + - schn +# thread stuff +threadcreate: + - threadcreate + - thcr +threaddelete: + - threaddelete + - thdel + - thrm +prune: + - prune + - clear +die: + - die +setname: + - setname + - newnm +setnick: + - setnick +setavatar: + - setavatar + - setav +setgame: + - setgame +send: + - send +savechat: + - savechat +remind: + - remind +reminddelete: + - reminddelete + - remindrm + - reminddel +remindlist: + - remindlist + - remindl + - remindlst +serverinfo: + - serverinfo + - sinfo +channelinfo: + - channelinfo + - cinfo +roleinfo: + - roleinfo + - rinfo +userinfo: + - userinfo + - uinfo +whosplaying: + - whosplaying + - whpl +inrole: + - inrole +checkperms: + - checkperms +stats: + - stats +userid: + - userid + - uid +channelid: + - channelid + - cid +serverid: + - serverid + - sid +roles: + - roles +channeltopic: + - channeltopic + - ct +filterlist: + - filterlist + - fl +chnlfilterinv: + - chnlfilterinv + - cfi +srvrfilterinv: + - srvrfilterinv + - sfi +chnlfilterlin: + - chnlfilterlin + - cfl +srvrfilterlin: + - srvrfilterlin + - sfl +chnlfilterwords: + - chnlfilterwords + - cfw +filterword: + - filterword + - fw +srvrfilterwords: + - srvrfilterwords + - sfw +lstfilterwords: + - lstfilterwords + - lfw +permrole: + - permrole + - pr +verbose: + - verbose + - v +srvrmdl: + - srvrmdl + - sm +srvrcmd: + - srvrcmd + - sc +rolemdl: + - rolemdl + - rm +rolecmd: + - rolecmd + - rc +chnlmdl: + - chnlmdl + - cm +chnlcmd: + - chnlcmd + - cc +usrmdl: + - usrmdl + - um +usrcmd: + - usrcmd + - uc +allsrvrmdls: + - allsrvrmdls + - asm +allchnlmdls: + - allchnlmdls + - acm +allrolemdls: + - allrolemdls + - arm +userblacklist: + - userblacklist + - ubl +channelblacklist: + - channelblacklist + - cbl +serverblacklist: + - serverblacklist + - sbl +cmdcooldown: + - cmdcooldown + - cmdcd +allcmdcooldowns: + - allcmdcooldowns + - cmdcds +quoteadd: + - quoteadd + - . +quoteprint: + - quoteprint + - .. +quoteshow: + - quoteshow + - qshow +quotesearch: + - quotesearch + - qsearch +quoteid: + - quoteid + - qid +quotedelete: + - quotedelete + - qdel +quotedeleteauthor: + - quotedeleteauthor + - qdelauth +draw: + - draw +drawnew: + - drawnew +playlistshuffle: + - playlistshuffle + - shuffle + - sh + - plsh +flip: + - flip +betflip: + - betflip + - bf +betdraw: + - betdraw + - bd +roll: + - roll +rolluo: + - rolluo +nroll: + - nroll +race: + - race +joinrace: + - joinrace + - jr +nunchi: + - nunchi +connect4: + - connect4 + - con4 +raffle: + - raffle +raffleany: + - raffleany +give: + - give +award: + - award +take: + - take + - seize +betroll: + - betroll + - br +luckyladder: + - luckyladder + - lula + - wheel + - wof +leaderboard: + - leaderboard + - lb +trivia: + - trivia + - t +tl: + - tl +tq: + - tq +typestart: + - typestart +typestop: + - typestop +typeadd: + - typeadd +pollend: + - pollend +pick: + - pick +plant: + - plant +gencurrency: + - gencurrency + - gc +gencurlist: + - gencurlist + - gclist +choose: + - choose +rps: + - rps +linux: + - linux +next: + - next + - n +play: + - play + - p + - start +stop: + - stop + - s +destroy: + - destroy + - d +pause: + - pause +queue: + - queue + - q + - yq + - enqueue +queuenext: + - queuenext + - qn +queuesearch: + - queuesearch + - qs + - yqs +soundcloudqueue: + - soundcloudqueue + - sq +listqueue: + - listqueue + - lq +nowplaying: + - nowplaying + - np +volume: + - volume + - vol + - defvol +playlist: + - playlist + - pl +soundcloudpl: + - soundcloudpl + - scpl +localplaylist: + - localplaylist + - lopl +radio: + - radio + - ra +local: + - local + - lo +join: + - join + - j + - move + - mv +trackremove: + - songremove + - srm + - trackremove + - trm +trackmove: + - trackmove + - tm + - movesong + - ms +queuerepeat: + - queuerepeat + - qrp + - rpl +queueautoplay: + - queueautoplay + - qap +save: + - save +streamrole: + - streamrole +load: + - load +playlists: + - playlists + - pls +playlistshow: + - playlistshow + - plshow +deleteplaylist: + - deleteplaylist + - delpls +streamadd: + - streamadd + - sta + - stadd +streamremove: + - streamremove + - strm +streamsclear: + - streamsclear + - stclear +streamlist: + - streamlist + - stl + - streamslist +streamoffline: + - streamoffline + - sto + - stoff +streamonlinedelete: + - streamonlinedelete + - stondel +streammessage: + - streammsg + - stm + - stmsg +streammessageall: + - streammsgall + - stma + - stmsga +streamcheck: + - streamcheck + - stc +convert: + - convert +convertlist: + - convertlist +wowjoke: + - wowjoke +calculate: + - calculate + - calc +osu: + - osu +gatari: + - gatari +osu5: + - osu5 +pokemon: + - pokemon + - poke +pokemonability: + - pokemonability + - pokeab +memelist: + - memelist +memegen: + - memegen +weather: + - weather + - we +youtube: + - youtube + - yt +anime: + - anime + - ani + - aq +steam: + - steam +movie: + - movie + - omdb + - imdb +manga: + - manga + - mang + - mq +randomcat: + - randomcat + - meow +randomdog: + - randomdog + - woof +randomfood: + - randomfood + - yum +randombird: + - randombird + - birb + - bird +image: + - image + - img + - rimg +lmgtfy: + - lmgtfy +google: + - google + - search + - g + - s +hearthstone: + - hearthstone + - hs +urbandict: + - urbandict + - ud +catfact: + - catfact +yomama: + - yomama + - ym +randjoke: + - randjoke + - rj +chucknorris: + - chucknorris + - cn +magicitem: + - magicitem + - mi +safebooru: + - safebooru +wiki: + - wiki + - wikipedia +color: + - color + - clr +avatar: + - avatar + - av +hentai: + - hentai +danbooru: + - danbooru +derpibooru: + - derpibooru + - derpi +gelbooru: + - gelbooru +rule34: + - rule34 +e621: + - e621 +boobs: + - boobs +butts: + - butts + - ass + - butt +translate: + - translate + - trans +translangs: + - translangs +guide: + - guide + - readme +calcops: + - calcops +delallquotes: + - delallquotes + - daq + - delallq +greetdmmsg: + - greetdmmsg +cash: + - cash + - $ + - currency + - $$ + - $$$ + - cur +currencytransactions: + - curtrs +currencytransaction: + - curtr +listperms: + - listperms + - lp +allusrmdls: + - allusrmdls + - aum +moveperm: + - moveperm + - mp +removeperm: + - removeperm + - rp +showemojis: + - showemojis + - se +emojiadd: + - emojiadd + - ea +stickeradd: + - stickeradd + - sa +emojiremove: + - emojiremove + - emojirm + - er + - ed + - emojidel + - emojidelete +deckshuffle: + - deckshuffle + - dsh +forwardmessages: + - forwardmessages + - fwmsgs +forwardtoall: + - forwardtoall + - fwtoall +forwardtochannel: + - forwardtochannel + - fwtoch + - fwtochannel +resetperms: + - resetperms +antiraid: + - antiraid +antispam: + - antispam +antialt: + - antialt +chatmute: + - chatmute +voicemute: + - voicemute +konachan: + - konachan +sankaku: + - sankaku +muterole: + - muterole + - setmuterole +adsarm: + - adsarm +setstream: + - setstream +chatunmute: + - chatunmute +unmute: + - unmute +xkcd: + - xkcd +placelist: + - placelist +place: + - place +poll: + - poll + - ppoll +autotranslang: + - autotranslang + - atl +autotranslate: + - autotranslate + - at + - autotrans +listquotes: + - listquotes + - liqu +typedel: + - typedel +typelist: + - typelist +listservers: + - listservers +hentaibomb: + - hentaibomb +cleverbot: + - cleverbot + - chatgpt +shorten: + - shorten +wikia: + - wikia + - fandom +yandere: + - yandere +magicthegathering: + - magicthegathering + - mtg +hangmanlist: + - hangmanlist +hangman: + - hangman +hangmanstop: + - hangmanstop +acrophobia: + - acrophobia + - acro +logevents: + - logevents +log: + - log +autodisconnect: + - autodisconnect + - autodc +define: + - define + - def +activity: + - activity +autohentai: + - autohentai +setstatus: + - setstatus +invitecreate: + - invitecreate + - invcr +invitelist: + - invitelist + - invlist + - invlst +invitedelete: + - invitedelete + - invrm + - invdel +pollstats: + - pollstats +antilist: + - antilist + - antilst +antispamignore: + - antispamignore +eventstart: + - eventstart +betstats: + - betstats +bettest: + - bettest +slot: + - slot + - slots +affinity: + - affinity + - waifuaff +waifuclaim: + - waifuclaim + - claim +waifureset: + - waifureset +waifutransfer: + - waifutransfer +waifugift: + - waifugift + - gift + - gifts +waifulb: + - waifulb + - waifus +divorce: + - divorce +waifuinfo: + - waifuinfo + - waifustats +mal: + - mal +setmusicchannel: + - setmusicchannel + - smch +unsetmusicchannel: + - unsetmusicchannel + - usmch +musicquality: + - musicquality + - mquality +stringsreload: + - stringsreload +shardstats: + - shardstats +restartshard: + - restartshard +tictactoe: + - tictactoe + - ttt +timezones: + - timezones +timezone: + - timezone +languagesetdefault: + - langsetdefault + - langsetd +languageset: + - languageset + - langset +languageslist: + - languageslist + - langli +rategirl: + - rategirl +aliaslist: + - aliaslist + - cmdmaplist + - aliases +alias: + - alias + - cmdmap +warnlog: + - warnlog +warnlogall: + - warnlogall +warn: + - warn +startupcommandadd: + - scadd + - startcmdadd +autocommandadd: + - acadd + - autocmdadd +startupcommandremove: + - scrm + - startcmdrm +autocommandremove: + - acrm + - autocmdrm +startupcommandsclear: + - scclear + - scclr +startupcommandslist: + - sclist + - startcmdlist +autocommandslist: + - aclist + - autolist + - autocommands + - autocmdlist +unban: + - unban +banmessage: + - banmessage + - banmsg + - bantemplate + - bantemp +banmessagetest: + - banmsgtest +banmsgreset: + - banmsgreset +banprune: + - banprune +timeout: + - timeout +wait: + - wait +warnexpire: + - warnexpire + - warne +warnclear: + - warnclear + - warnc +warnpunishlist: + - warnpunishlist + - warnpl +warnpunish: + - warnpunish + - warnp +ping: + - ping +time: + - time +shop: + - shop +shopadd: + - shopadd +shopremove: + - shopremove + - shoprm +shopchangeprice: + - shopchangeprice + - shopprice +shopchangename: + - shopchangename + - shopname +shopswap: + - shopswap +shopmove: + - shopmove +buy: + - shopbuy + - buy +shopreq: + - shopreq +gamevoicechannel: + - gamevoicechannel + - gvc +shoplistadd: + - shoplistadd +globalcommand: + - globalcommand + - gcmd +globalmodule: + - globalmodule + - gmod +globalpermlist: + - globalpermlist + - gpl + - lgp + - globalperms + - listglobalperms +resetglobalperms: + - resetglobalperms +prefix: + - prefix +defprefix: + - defprefix +verboseerror: + - verboseerror + - ve +streamrolekeyword: + - streamrolekeyword + - srkw +streamroleblacklist: + - streamroleblacklist + - srbl +streamrolewhitelist: + - streamrolewhitelist + - srwl +config: + - config + - conf +configreload: + - configreload + - creload + - confreload + - crel +nsfwtagblacklist: + - nsfwtagbl + - nsfwtbl +experience: + - experience + - xp +xptemplatereload: + - xptempreload + - xptr +xpexclusionlist: + - xpexclusionlist + - xpexl +xpexclude: + - xpexclude + - xpex +xpnotify: + - xpnotify + - xpn +xpleveluprewards: + - xplvluprewards + - xprews + - xpcrs + - xprrs + - xprolerewards + - xpcurrewards +xprewsreset: + - xprewsreset +xprolereward: + - xprolereward + - xprr +xpcurrencyreward: + - xpcurreward + - xpcr +xpleaderboard: + - xpleaderboard + - xplb +xpgloballeaderboard: + - xpgleaderboard + - xpglb +xpadd: + - xpadd +xpshop: + - xpshop +xpshopbuy: + - xpshopbuy +xpshopuse: + - xpshopuse +clubcreate: + - clubcreate +clubtransfer: + - clubtransfer +clubinformation: + - clubinfo +clubapply: + - clubapply +clubaccept: + - clubaccept +clubreject: + - clubreject +clubleave: + - clubleave +clubdisband: + - clubdisband +clubkick: + - clubkick +clubban: + - clubban +clubunban: + - clubunban +clubdescription: + - clubdesc +clubicon: + - clubicon +clubapps: + - clubapps +clubbans: + - clubbans +clubleaderboard: + - clublb + - clubs +clubadmin: + - clubadmin +autoboobs: + - autoboobs +autobutts: + - autobutts +eightball: + - eightball + - 8ball +ytuploadnotif: + - ytuploadnotif + - yun +feed: + - feed + - feedadd +feedremove: + - feedremove + - feedrm + - feeddel +feedlist: + - feedlist + - feeds +say: + - say +sqlexec: + - sqlexec +sqlselect: + - sqlselect +deletewaifus: + - deletewaifus +deletewaifu: + - deletewaifu +deletecurrency: + - deletecurrency +deleteplaylists: + - deleteplaylists +deletexp: + - deletexp +discordpermoverride: + - dpo +discordpermoverridelist: + - dpol + - dpoli +discordpermoverridereset: + - dpor +rafflecur: + - rafflecur +rip: + - rip +timelyset: + - timelyset +timely: + - timely +timelyreset: + - timelyreset +crypto: + - crypto + - c +rolelevelreq: + - rolelevelreq + - rlr +massban: + - massban +masskill: + - masskill +pathofexile: + - pathofexile + - poe +pathofexileleagues: + - pathofexileleagues + - poel +pathofexilecurrency: + - pathofexilecurrency + - poec +rollduel: + - rollduel +reactionroleadd: + - reactionroleadd + - reroa +reactionroleslist: + - reactionroleslist + - reroli +reactionrolesremove: + - reactionrolesremove + - rerorm +reactionrolesdeleteall: + - rerodeleteall + - rerodela +reactionrolestransfer: + - rerotransfer + - rerot +blackjack: + - blackjack + - bj +hit: + - hit +stand: + - stand +double: + - double +xpreset: + - xpreset +bible: + - bible +edit: + - edit +delete: + - delete + - del +roleid: + - roleid + - rid +nsfwtoggle: + - nsfwtoggle + - nsfw + - nsfwtgl +economy: + - economy +purgeuser: + - purgeuser +imageonlychannel: + - imageonlychannel + - imageonly + - imagesonly +linkonlychannel: + - linkonlychannel + - linkonly + - linkssonly +coordreload: + - coordreload +quotesexport: + - quotesexport + - qexport +quotesimport: + - quotesimport + - qimport +showembed: + - showembed +# NadekoExpressions +exprtoggleglobal: + - exprtoggleglobal + - extg +exprreact: + - exreact + - exr +exprad: + - exprad + - exad +exprat: + - exprat + - exat +exprdm: + - exprdm + - exdm +exprca: + - exprca + - exca +exprsreload: + - expreload + - exrel +expradd: + - expradd + - exadd + - exa + - acr +expraddserver: + - expradds + - exadds + - exas + - expraddserver +exprlist: + - exprlist + - exl + - exprli + - exlist + - exli + - lcr +exprshow: + - exprshow + - exs + - exshow + - scr +exprdelete: + - exprdel + - exd + - exdel + - dcr +exprdeleteserver: + - exprdelserv + - exds + - exdelserv +exprclear: + - exprclear + - exc + - exclear +expredit: + - expredit + - exe + - exedit + - ecr +exprsimport: + - eximport +exprsexport: + - exexport +deleteemptyservers: + - deleteemptyservers +stock: + - stock +# Marmalade system +marmaladeload: + - marmaladeload + - maload +marmaladeunload: + - marmaladeunload + - maunload +marmaladelist: + - marmaladelist + - malist +marmaladeinfo: + - marmaladeinfo + - mainfo +# Bank stuff +bankdeposit: + - deposit + - d + - dep +bankwithdraw: + - withdraw + - w + - with +bankbalance: + - balance + - b + - bal +banktake: + - take + - seize +bankaward: + - award +# Patron +patron: + - patron +patronmessage: + - patronmessage + - patronmsg +eval: + - eval +autopublish: + - autopublish +doas: + - doas + - execas +cacheusers: + - cacheusers diff --git a/src/EllieBot/data/bot.yml b/src/EllieBot/data/bot.yml new file mode 100644 index 0000000..42753e0 --- /dev/null +++ b/src/EllieBot/data/bot.yml @@ -0,0 +1,91 @@ +# DO NOT CHANGE +version: 5 +# Most commands, when executed, have a small colored line +# next to the response. The color depends whether the command +# is completed, errored or in progress (pending) +# Color settings below are for the color of those lines. +# To get color's hex, you can go here https://htmlcolorcodes.com/ +# and copy the hex code fo your selected color (marked as #) +color: + # Color used for embed responses when command successfully executes + ok: 00e584 + # Color used for embed responses when command has an error + error: ee281f + # Color used for embed responses while command is doing work or is in progress + pending: faa61a +# Default bot language. It has to be in the list of supported languages (.langli) +defaultLocale: en-US +# Style in which executed commands will show up in the console. +# Allowed values: Simple, Normal, None +consoleOutputType: Normal +# Whether the bot will check for new releases every hour +checkForUpdates: true +# Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)? +forwardMessages: false +# Do you want the message to be forwarded only to the first owner specified in the list of owners (in creds.yml), +# or all owners? (this might cause the bot to lag if there's a lot of owners specified) +forwardToAllOwners: false +# Any messages sent by users in Bot's DM to be forwarded to the specified channel. +# This option will only work when ForwardToAllOwners is set to false +forwardToChannel: +# When a user DMs the bot with a message which is not a command +# they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. +# Supports embeds. How it looks: https://puu.sh/B0BLV.png +dmHelpText: |- + {"description": "Type `%prefix%h` for help."} +# Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response. +# Case insensitive. +# Leave empty to reply with DmHelpText to every DM. +dmHelpTextKeywords: + - help + - commands + - cmds + - module + - can you do +# This is the response for the .h command +helpText: |- + { + "title": "To invite me to your server, use this link", + "description": "https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303", + "color": 53380, + "thumbnail": "https://cdn.elliebot.net/Ellie.png", + "fields": [ + { + "name": "Useful help commands", + "value": "`%bot.prefix%modules` Lists all bot modules. + `%prefix%h CommandName` Shows some help about a specific command. + `%prefix%commands ModuleName` Lists all commands in a module.", + "inline": false + }, + { + "name": "List of all Commands", + "value": "https://commands.elliebot.net/", + "inline": false + }, + { + "name": "Ellie Support Server", + "value": "https://discord.gg/etQdZxSyEH", + "inline": true + } + ] + } +# List of modules and commands completely blocked on the bot +blocked: + commands: [] + modules: [] +# Which string will be used to recognize the commands +prefix: . +# Toggles whether your bot will group greet/bye messages into a single message every 5 seconds. +# 1st user who joins will get greeted immediately +# If more users join within the next 5 seconds, they will be greeted in groups of 5. +# This will cause %user.mention% and other placeholders to be replaced with multiple users. +# Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail, +# it will become invalid, as it will resolve to a list of avatars of grouped users. +# note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some +# servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited, +# and (slightly) reduce the greet spam in those servers. +groupGreets: false +# Whether the bot will rotate through all specified statuses. +# This setting can be changed via .ropl command. +# See RotatingStatuses submodule in Administration. +rotateStatuses: false diff --git a/src/EllieBot/data/fonts/NotoSans-Bold.ttf b/src/EllieBot/data/fonts/NotoSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6e00cdce1dac34e409a0111296c90e98c6f40701 GIT binary patch literal 415132 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%0Du4=gPtyp&Tl9Yh|7h{qy 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%0DX?)du0 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Ó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 ^ij~u(C>=z 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ÕLzM%u{gXc%dOmJ9T`pgLNO&jr=dCO1E2v?fzJ`HT3XUbd@~ zFQl%S;CeBIv0?EQrxO0=$fD^D6t`QWEs76%fmwX_ki!-q}^DP+*!4m>Cmr}yhO z9lx5?4sqLLMy?+))FG$#y;-F2MQw!>Y3SbyEy&|!`YqsH+zPt`>ZO9x58#6mf?N#Q z`XH;Kp>paXvJ{x7Ya#3PF0v1F(GHTw$Wda~MLP|ijepyeL_Q~9GW&y#fl98h$QQeR z1MLryG}@-1YPUb2Mw&eucQ7c5K&vq=&}O5Xidhu?4ps+11=Z21vbaYbio{=s1-12D z|1V(ylPnL-IKs^U7c^VjLMwjJ5@pWXMcw#SDwVaY5kSG`cAp8kanaPKHYO;G){Y#x z7QbSe0WfH0HUz8BWL57X<#=Jo$m z@0wjhlL0A^{w5Hiw)R&o66H-G1SU(OvPGOQO>|T?gQQN*M9F##5q~eIL^FU0(=z*+ zXBPIGHogBHZTpPzO(`1oA98&adT@rXzkJUz*) ze>+=(aH^!3H>Vnf5V%^3gq9&R!#3+*(r z=iACf@fE2RrA9S-JOgLT^a#EeB^jX`oF&)X!rvG0|JMp1PxPqPWH^s?A|>y z+v~2LaHJ)==7bv>+v=bwb-v@@3NHv7ZyjEE5YWP7kgv@dEy$e5&se@TS@S~XJR(|f zvuR#n&Ndk>#8;z*_DpdLqd-S9tRUxXldTPPv$Dw62F%6sA>$<=PPhcB7Z_6^a~?6K z!kh6D?9rg80h&Tl{X%9Yp!$WZ04gh)kEIiB(V%ld{bE@&RjR1%rY~l-$@H##yb)l;ll29HzVf$26a0%);zIdI zer;2N3BPuO#zm!+D5V1lZCl4?yOOi*BU>hBkZsKeQ(WHsgg%;*`BPY^!}h63{*xkv zb~j6KXei|K?_r3bmSUmp3`m^Z_;!fDuHlJVT6za9tyWB595cRMuN^{WJl3dp%9`Sc zEPiDc2*UKV?0yVnJl55juxETL25oU?KL+MVSxh%ILpww@oN&Sx!r#H6QAdok@!T0V zlBVr%>eDdU)HE>TbVf6X*`(cUsN!wgPol8?-u#fo1CBbJl>-_9Q{3A?)CSq}x5E{J zZ!^*A6g$~4#T{*=6}Fe#yEY>)N98$3?aeDU4JjJPt@iETh&kyj&)L{Mj-xC?$w{Wr zY1gazgga-;E|2VpKdK`%F_OX;R3Ok=5y3Ld+kG3TUL`Xo`+`1rO*Dm^L)Px!z>FnZ zfid|2)9F0OIFb$LDnWjP2UslR+-q_qMI1zFra+XYtY3vH5Xh30`4K}QXNjF3fw%&5 zudSlnnjN+P$s~;mgo(h(5oJ=DGC)Kr4f36tGBl6@Ed}zOL8|fq4NG!<+jJuSV$1~^ zUs%%lI&_AcpiKOKfH7)O&kZ4sc7H#l@maUD^se2~(z-RF2}ArfHWEfskV{F4OAx$>jBQu@59F!lWX;&W zXV3B_`}Yem|KJVpRRRp2uIXvrx;1((lGSj>E!=i)2e+HCGY{FA70ro&42Vhpn8Pcv#dujyJ%bY}HPYGsvMg1w{Wo~8qQ~SvQn@+^j;yB&dZzs<-I~iMp(DTODsZnoY>HLu1cj}7IE+a zvE0K$@hG339+F?K>e1BU8&o}Uh@XzSXu}4kCO08~ko-O+PgmY*giz_>ocl}o;;*Y! z)(OOL&K}R?wi}XwkToN&?&XkjHol}}-j+j^Ue-K8Xs?g3Xa+WA5C{2V$V7g*^sSK9 z>K4Rw{&lS2#;g>`z_eQ_5?OZmwxk`?s>Ha?zBXm;8lzAex&{gwh!@G`f9Z8&jU#&mDlcPsiNr829-$i`n=TJR28S%!WPp zI>vpv09HWFNz}DQkA|#kjUElm!j2vd)PSfUva0oBvYgnnonpo@*{UF`TFX|2nrx?^ zl5>#l^c$P*B;sa8vFsNP#s32$RL*V~)*y(qn3jnA0zQGV z75L?g`P1Nc17r=c8(&N;(OMd~qzoDOTK+Fe@e z{^qRkRJXXkZ@xRGvh*KBk>4+i`~sQEq(PSPDzXG$t({CQ?So3ZgUmm>j45|72yCt2 zDM#u&mgt{fp0^x6)ZSu=fgj!@JuRfUAc_}0`9vrp6-5I6l(rYqmbcs<;W}~TnkUD) z4t0O_)E435KLEpGA(j;(t4n*0FZE59F1Wc_d@Azvrns)7$~@zrXrev5}89uy-yp5|n)#Tm$I ziqW8-fuh7kKo+vk0u?0)5p2<*{-7ukLiCVF{nlprvZD%?PzJ5s3l#^aLZ2R@1 z4u_Aj?asCbLV>lY4|w(Ugo$FxbCoF)@JB|nBM1p2|ClmrT3GIj{|hMO52E+i(YRO= zo2tzpmM`YPenmx##rhq*P$X9PSdz8*TCH`l$uqwwhjgbp_VInO@SoV@T6ly`jg5(k zrT)d*$VeKg%|by-$fnO-p`QRh8I*IoKh>0`g5U2JR&op5!S zBKC$4i9e5BS(?!w=!ScZV#` zz}dW2*F2mq($^A4If)|%)r`5HULAH+jlF5a@%*H|OO_Q3bl0Zbxn<6Dtpe`(z zs2@$DsELJuZvW(tK*Fxs=t@M7ni|(Tb=%e&;`XqgtK2Kk# zke9WYsd4+&NN=Jm1PB!=V3h#$kzva^>dy=y%v}Omq-vQc>b02IoC5wgZz;KLS<&lB zNRCg6<_PGo2AvoVu?wF^X)x|9# zz*V6jb6s4v@Dr!|3Lf)Szcw*(MA#p#4>y~_!_AVuiPNS_>UJ?EqbWT`uh%R6mA>(Y znVC5;(NR%pX1zXC@D&1+!l#m5w;JEviX`e^)XHdnrqT1AmN{oQ{X%ziq&lx{$;x*$ z`}Xczsyp;t(t2W^WtnP`1~eh>L%E=YvMaa)_mE zhPhAE!f!v8X=sP9RTE}cxVCbrooP{xP@KIbPVhrXVaI03B1*;pYi74vIKZ8& z+^pK!CL<&n=v5=28_L&u4To9vO&y-KF|97mAc!_gnm|^I{B6N0og3KGFI#WQ%u;Xe zQ)w}MTe(gcI7smTP0Ms~$xJ5Jo)$}k=}>PxWr@_Xq3B!M#2BRs17O6Xr^sEm9&t3d zTMJMAW%EjX8Bi6akH_A+hqn(QX0xYNw$@;>(=_X*3e z{x$bKXUlE^HW$pW9>_GwBS|#Dye4TxRs*{O)W90bgeo&#H-jem4wmQaVRDE(;S?2v z%3v5p`w8Si{hj4NMVkwv4a}~NXag0&?D@@FvHa>ad=xv{z#OP{w6OqeFI$_Pg@y54 zQ~nCYm4qWmxe204ctmv^DzIE@8*gp_%%~@o>Mem74aEvO7;KstSv1>R>x}N2u;oUX zu8I@VS~AYM`ma$-avW2gUzTnG+ORkzND)spF3t$A6Dv&CG%>;uo^3`M*TwUU@%n_+ zy@-0<2==hPm7t)1i9}N5ko#P4Yh=iAmujHPzKLtr&ATUHsOql91sjFVk;BrmCPW!@ zPVMyT8*VG+c$<5l`+)lxFbDd1?3km9VGcdZfMU<0mc_EDbs^nZUR6{eEeET{D5h>c zg-l~=9qS3AjRznD%7YMtdx<KT#|5`p4umKpPjyx3>Hzs6HxV4cW30Pg{azL&h4i zucv?((h_Fb7)BkjhHTkbO*b?$1V}^Xlzb10=a{)wq#P)o*JN%DWpTXD5jTiAFmr1mEvl2bb#^n<{rKy) z4Ych4#Q>UGmtChBgBVhgxBx6m236pNzace;_@q_mR!#BqWhN2_Bf`yOP;qcsIJsgN zKxshh%uYI~h|pwC;@?G5%U$%u6?d9|Y@0S2yC!sAP3z)MJlvLf zXbh)Fa;B?WyG-(uQCZ2~yzpp)&Jw!3j;(^Wf@q(rvxV9Tk=krWfYH>NVNK~Jkz;hv zN&4Fmof~xB=84Oji*_CEI`X{^Q=-qRQq@Z5}`4`AY9me<< z6Uh{^lGIi*e~cWpWo$h~PLns7QrLe8qK7XT2emPj%(u|J&CW`p%0cf&V(pmMx;rIO z5*&F3Y`d=o0r0A8Y>F~#02RXR%AB{yBck;8hBARm%hb;0)FALnjhUiR%@a4GfPRez zlY7FM1tK@1Op498*?~t zGu)TlM??ffK<*?WvWNUd#0ynCNl`S z_^pJwx~r>x_3G8D_g=lK%I?>iEwOV4mc2a+;hY7a%GFy%xCpSOSmdv|0Hq9%o8$_c7ObD$)tCqu4oZ zQ#{U7*?0}^K$ez5Y~Y0WjRQfOm_ktPMG~M_L*p6n=CAM?lMCEAXWon^e#MRS0bZdMl1dT_3rOA?f55EUl`d`*P{+s>{QQFXs z9QoBXjo8IegRif@X6XyoIj1&Kvj z83pDJ!cV`-{K&NwmH|GFt1&N9!!3gy$kuS{xJ{7XHge9;eT7$GBHuA2K{W z^KyJ1T+*<+ac06q%!a!_AR3N)(GouM-SRm(wrJ>|zz_x4zT>VrSsKythQT5sL} z>6%A{)O2t@Mj$dYHYT?)CX;P4(wU$OM3cKmPAbwkGtwwLen{i(F-97t5w6gQ@mnen zZ;S7@BNxTz!JF@~YuK~Dh1PI+^B{wKXaEfl2jsJ8=-GsaLVQto+ZsdH+S~f-HW`hA z@Vh%~?Ke>kULryNB5!)z`YYzw)(Qfj@@VMgb(q&Z)0A!yhzcN#oM#*~+%QYOV(IR+ zU2k3IxaD_rax1R?xEeZudi}>Q-_I+InArG_JCRD`e-5kx=}5Y;)uq*J#|>$9X$@IM z@bolX{ekhA7#)Fr2FbJVI{81g-UD|w{|ZL_^W-~N`O!!&@d8_C8o`_SI6jHTvrsab zk0F;Y;5+hN_!8KOv@bu9ujGfp{^q0kYPWqiZsBj`*Z#M30BI!g9Q_H-aL5jZ-*}os zGdpsv=>k^GF)M5{2{-yC9?_WgM{l1ikt2H;V z9M+Dm;nu?*=D+m(Rot;Fn4ks`BcH2=XQkj?6~6YTxP{zG)4s2OnyqCy9K(dt+o|NlD9o^Qv^UxWr-)M9cU5W37eu zoRN!oNbe{A6EhB80waH4(+*dA&Y>1oYup8q2lsM&xP9D1>;$wYxu>~jxua~?sgn?S z@D|$v;xq0v+v)o|?jqN~c7QOD5E4$JNF2ePzAdoFCGG}MN^lnlJX>`*xdC>8sFtG- zaBs_{WI6Z_aQ0!dd1OcffP-k#qLpd--%#9qjZS%15w$r=-~j8{eAGR_$@w z%em|K4bIb5=kPaOYr24DY`!*K1}y#&EqM$AKvUj}8SlRAz(+m22O3;ICXB90#f?Gj`ig?ZxAxu3HM)V;DN9GB+vey+ygg`(O*BET=jjf zf1y4gpZXC+V%Z!5>H@9V9D=gnbvfw^I)VE>*V=gm>BMzuAIc}l(`;ub*AA3l!08{Z zof>c_N?dt~5ed@SsJIhl8+HowYMAvut`Wew>TFQAM+;Z=>@Xjj zB{Ur+;8i<71*z%Bq}$OLqM$4kjkPwpEw-QO6-jwyfembEH?%Ptd!%Fp5}fFB3x>um z&Mg;c*R4klY<}U92Gw@e|IOVO+zv^vy~=wx{X*TK310#3zi9Rvn`(TaDU=n<4q7c8u-*hjYTd}!K>A@j?& zkXoMpm|yhwxl?}@uiR(gbBm^Hc8)+lsP~{vGkf)m9JFHBumOL#2TmMJ+0wY^qiuUj zY>lMFJySj?i0;i#Y6)8bwhnoa-o0_u(fsIK`b6;N+l01P>NE&MAy6M$@!!+}_~rH0 zv$Cq_V;}TfG?nAFT=RNB9-NC+OuCYuq!;PO&I-MrjBu`8oJHo41*C?pS*T-YW8s>G zz0MsSpCo^i&&I;tncgJt65Ja>@)w+kwTnLy2iw^Z=MY@yWLZHYXveG9FZAID{-Fh2 zwie(qD!W_KmoqhB7BbRO^+KG%sI%u0g4@@jMAR_g50Z2S5J1bN2r+h~psMWsz(V6|7ke$6WL{aP8Vxogi(Pb4kae7-jyKJF?Yjm^?I-e|Me5ZrTl zHM7$nV&_P??DSX333g(owBIt0%D5sxveS8XhPN~-D?1nAsEl@cv2#U$%T9;Wy#E-X zH6yfDM@XrSjvbt1_rJapLsY-_cb4Ro^GzYWm@EuOMZwfD%&1 zV)q7;B2NysCru@5x^di|nou8=M5OmH4=qpXXjafsN01kh{p;sM!@1TQL$2PA`DT_E_^D{_@|8zg##Zo}D>rQSwX+-N+wreCUdTulVd>J8c|LHVj2r>oT z|9dj7VeBT{ha9JGqu;jE4dcG;m6m3a^&pdl>4E)Hmr{%`z+hk?YN~_pl&B`JV zS$Tt1c+qMl^Bc~>`!1`MuG7a_tx|rMsBjVTi{?11Ge4Fc=9L>GT+GT6*Jou}`TO9_ z3LoNVn~gtViHCH7x^)3W?vNm3g-)zqHdZecAQ>W~lZ=*;jlmRikzyu#9xHqTzSHx> z#Oh6U*=%&3?hIXLvoR8mLV`BNk@<*S2kp|JzeU)~@tmFu;+jFJ!GejH!id$RzePOA zSBMXb2X$TPJ9Hj>rvcm!L+Jr}fPYB5M27A&JWLO80&Cko`WxY!5py7E01W>0`07I| z$U%IG&FLbtMmRzaHf$ybzY^Yo>dMbf)P1aemRL-7%tJqst{^wl7B9R2rNcL&Jvr!@ z&i8UmCkLI+#=Doxo`vW2@%V)J4|w*-3ol5e>h5hEqq|os)6fp`knyI;L&t}e=$$7fj5b$m>86ilRNMCmQ2yh4c2v)YaQKBJ31`IIjC{4=uV zlTXQQpU-}d{`sY2^pRuFk?USMMg|=dmv0KnyuXy_>i9BO!quPQgLog)zd#>8_BacKn)z)n@*DZbJ{W)`vZkSM0zH--+zQgMt_FIdv4P_lWE-%}$VfLn_ z14d2A?KF2=ht^OH=x^#aXvJmwuZi9gW64iLN0OZw1bcoUz;kLg(S>C7mKy3P`iH|W z+{~9=n#gw*-yqw^(^pp=t^v&nG`=>9{&f##e$h6!z*jYPOu%n)C zL~fBc)eMBoz^KXYJYzs}lAmt=hH6ZzXg~N;_YyA3S97%&r{@I?Y&CF@Pk@nKQiDP7h4#9MXNp zN{{}T&vo-(J0f#_s@dW+^Wqr)uv!%s1X8d0w6afr+bR-n4k=r=qHgcn-9!4VdurhI zyGo0?`K=fU7XK4b6GJ*ps9Uk-{&|xp9v@e6AOi*+ZF|{3-W2+;ku5SU73}6zVu6@( z8=O%WX-PLl2Gl?=(J$#~P>K`9taUo;y3#Xse7{ZW)@|}zhgWGnxIT_KR`TaErc@uG z{m1}%km4|}>C;#TztUf?AeTP_X@YeKxa@2ljbmTV)ceK!jfB-vFMWDqEeeQ#pm(SS zSqMFsM_GmZfq-u)&!88{T=Ddq)p1?Qi^f*>xOwx!vfg4%pmiZT$B)gWUoD&Y<@B`c zhZOaIfwyxvkyC2sK5lj8%Kf(iaFH@1c#gjYW9(&A?<0C_>7<&GPamtQI*}4w^6Rf0wl@DYX-AGeuTae@GveUUXZe;@{y;|emp@^?~HNYJXU%2RL zPs_V;oCcv9Un?$8iw~9>`nI@z;QY>qk?nZX7gBMkH}l%@f(ENj)sE3z3(n$(Ry}r0 zjSDTzMsHPnif<@}wBw?JMhHcdTGObaMK+;Dn>z}DVRQR zDL92yPWxC(&86=4u;Z9JUQ(tQ$ZEPqa*1lx5PgG|unVTTql#ZTjbFzn3Lq`vb}*yY zqnGM6w94T+s>@|dZau7B7YwA9yWOiM*{d1@*VSKzi7H!HOR!Q8+t%@!JI(l`p0=)g zo4faBuU4&lEfo7!jsJodL)P)OLSbQ#V$*6WKnJ^DdLUZfq>6{k{?tQFo8sL2AsO;VNq|Wx&;-#mRvDk~% z=>eYEIWBr;aXDPErsaK)KPrpU#l>!PUJX{}#F~+ZUl=iB|H?r#N@~_KEAx4A3TuEf z^}g#N4t29H^NVMz?Mp8eQOl5Mt~r;f;bHaYBs*bTY^)un=m8IFlD@03h;Rn&N(~D; zhbzU7)ItHoNw>`Lrie-h6N>H9j@19tS<$2`Alg8-LTs3?Q?By`fc^7 z&{DJuCqJOrg#-I2cA>UHFy`4>b(8EwS09Mv;<D?lPyqBpWHyY(-~j|&Qzq! zF$Jv_<90XePm2p}K^LAB&IY}*16QKPQC%Pg^Bvs05>LbgAqX_RC93Pw-{o zsdx!Dmym5eH81UST6LX}i~0bbZR<4ZO#oH?lR{*DmX?l z@6>(7#Kwb8ZY?K|rM|5=SH-*yt{0t_+cxJI;bytf4$ihaz-%~eo#e6Bo6Xi(?XKad z$6cP^!7bBo6DZ8on&b!phzfAcvg)^uuBsYM|D@P!AC4YfwO29BIF9Fcamx&Gx(Ika z)%Cp38Bs$V%kFuvHW%hizVNiJKt}QWPHw3ol9kiaRgT};OGD(Ss;W`+f)Cs2!?B~Q zyc$VRBq#6*K$~NXHc?!hs#MjegJX>T7^~E2#Rg)NiCCF5kNHBL-vD`jrX%k3^66vL zeMYg*TGjsyp8g}L zILRJ)tS3&=U5E+lw&SLaFiBU~CEI@80W7q}&F;8k`TZHKda!vop5Fsy&jp$pxNwe> zXW7ir5Htb+bU!$)iDgJKVLP)N93MlLU|aFa;91JrIGMAeU(ba+pqVk)UkzLPJ!Tth zU*=`<3&Ho0Y=FuoP0Viz{5s(4aG8cGj`KTdRK^p0L30CyN*@yi%Ao6 z=3rFB#PlI@RD^@N#1$tH=o^OjWI2-S!r@nvsPMeU@O(La#MV1!LD0i{bLSr2SY6W# zf*$$}uYW|etEo}BvD7WXp?DrdIM6XJ$^hS!O2BkVmNU)O?QK;_8mCK*&7BxdA&5&H z$eaaa&6XN5VY5Vsdh!|gU62@x^a0&fZtpuJ9}AfX<^4^TL8`X!DTP#Z{~N3OcZxjf zeuG*bi4~iI^6pd^!9z09@dzYmCNP9l=eOnlWdog4)z@Kq*dxxs1wrjaF}%&-{NzPm ziOC8<_^KvE7agY%2PPO4DF(8iYyldL0UDtkgV;BXBy)8O{YUgb9fSw;;479R7{@CT z4fJ)w4oM;WKncQ2+nTd7iZd9Z%0k&fb61tC4|ba3cMHemZsmXj^H_AV+aauW41 z@4jF~Y<`F1kV|Y-NpWh-kJ_3Fn*?!Nb4Mm!?R(C>!z>%3_v z%mPnJ8+si^Uv=t6pOD=dYFjWF^n9F$S9!*5z~1?J)cAh^Iv*7Oqaa2Xl(IEj$)1Wx5KUr znLifv8#PX}tf3F8a7tF65kmfAjBzX&MFo=?ddYA^UaUJ-8dB1ywq|fl_39wQz&Ts` z^l<#$iS?O16S7iMvL^4+;-yjBhEJF_UfA=+a(?23;f{C>;7`8oZl4h|JHHflGB+Cv z;{~0R)f*LqAx07)Z1%_n+Kr~$Ed%-;I#@Yj?67Tv`wy(#FDIHd zMpymmp5db!N4lf)OGgW~w{tG5(3Wp^K_dBV3q4OOM?6^_Gq|RJmQqegDr{+;0v(b&1r)a0p!xNUwT)5+*zJu#l_v`KWK_RBFD(Lq0FeiFQQ+(S_S=JvLD%=sd(<=isQ;ZIBa-O0S=5{89?yc?K z){;HzhVET@vTo9>Eqir_em8FJ*P~~@O^XMH&2-IC2zNZTXYWBRTE`3Y^X&N@4|Gcx zCQTT=^^Oq}r;llz?2efnjlXc=8!a8NpR19BQUR!dh;~yn>*lJ4b_4qD%GFP-UL6!t zev`xD^qG0$BKvATrw4>R^y`v%e)7++`7r*g!%-p&hgkudZ*y{T~;u zUadrOk8n;^u#+LQDS ziCg*lG1F^G3p|-sBZCsT4DUGY44@Ba;=8L>A6h*w&CqM@c~`&IaxF9s>p6(U8xVEB z@tny~JhaYu357`{Poeu5ExtFfa{C>X6&00t!Mo#Yg-Al(RurQr+2_y!*q~(Vs$Fs%eOF&>bg?B9|$m=pigS+-Tti{>5t8qD#*R@qsr;gGJ0dhS0>mR<=_CaiGRo`Gb4ycGI50IGN zdxLn)l$m#3ZuaW=L8U9Q#9{@O7SP`L;l+iO^iIBh^A0b1je7jWSpgLef(IW-5ezms zELjfJkrXgkPzq6G3J0pCx44IXJ7xZgF{`&uwDlO$bIP3AZD$OgclX$=?xMvPMseA( z)=N8A7Id^F+bhOoTXUwhFUc#;NV7Zs?cU5y>I(#PnS4+bx`N7pN&~Q5p%0Anb1GgP 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�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 s&|F?&E&K`&RJ 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 H>B* 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

@$%UOnCy3 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 z zw@kY;8gkhAxtWD~t43rOEOj_iW1~t$O5J5a^TZ3Q*P}W3mpRr%-z-#@Ds}4Xpxk6|6ciBRHxA z(Qv^YbM{WJZ!9Q?sl4Yro!Eb|<6NARUR4WgA4N~zTAEC+CNB%0Ah9hxyYCbFukh@+ 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%0A6kkYOl<7(LHlBb1q-r2IpeKA#>gPM^@ZN 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
Y(BRji6-58t2q& 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

bSfupmslN-*%+92oPx9kKt z2NHMtEx@V7S>nhEVGW_Q2HcgMOSZmTuyWI!XM2};2gMc+_*{Y3;S%Z7hFq1uw_oz8 z@z4LBJS^pzw~P1TlQ+B_0h_Ql%Qugh6)>aTlk2LGlk~RxTlLSsT7MdXyO@kO@LVp0 zS+UP-#ME2(N~X}#EHErfc`8{susXm6h4|qg2TVkgeV0d-xE;d&rh9TV!6zy0!!2i# zixehTd}elS^oq(^D64AEK4f!l{!eIhQC8t(vfl(azqt+O%fdVmNO*7=7YP9g0ArPJ z!vunD(z2ppw&m=d;h8p|0Do>4-XjqIv^{wrBX`TUOC1%B0)@$$k;sOw{;X~3cHs>f z>hKIdF)I6ui3&w$u%E?!M?A()_RRp|+oS{U1_AF9--dYlA~;R+R*Lm;7#pUr_GGQe zsn;O*I34u`^4D#Lua_|HND<=-wAQ(1;@4kKtaWZ_f$#3$ zQ|rD{t0_12z1zH9$YF?Gu;;WBXBQ+eQ5sxA*f9+G<8zMxG7yMqoA0^)r0&gs*a-{# zcf<`Px{Wr!XD!HD@;46z?I1%^sAhn5CPj$n<=T5-Ig*Og_e9(7nADCP& z=cFC(3?L!_)7D_pA$Ow$?@N<(AfXlTppuq}+3#B0e_VC}zgoQd@z1CpQA^k2{R!!F z7c~tG^F|I!MplO^W<}x=k#sKB-TuBdrF|yM02%fVo;(vjT-a+sL;vNY=HmS$s#Xpk z`v$~-gY{3qmn#SBu5MW0aL<5ABlKpk0iPs>CT^#U`5m8W)a}E^p;@w)5xj;>8;=9Q zCGPhCbNXjX?s-4AX9{paa%P77kWi)t{B!@a84<6ahtoqMx-!D)ipbZ`BiOi?FLi&x z|L0!5gm)S6C2;zHz{KI3;8O@Th(JWBsDli_S%h>yz!-aul&?NwN?$|Qq@F%m94rSo zSPbv8hO7wD0so7CL!tmuMtTwe@+Ut4EbBlu(Ej& zV7}|t`u2vxCKhFRos4#aQGn4`yqEkd~4FOW(L_yuowz0 zcuMd`V*~}l{hH?=E{H9}7xHEJlBTt9Wp1unKJsg8WJ{k2@dJ`WT7oJTEJa^gJ)zX$ zii3rVOND#CS*XSff-A}?WU_9wQ zxHm+GKvLM>xILcW_V}5Rk6)s`i%P4ix7vD`G!Ow?74ygiiNcJ4mM042cvq-#;Xr#|0k--&) z8UtG~rzm&n)R~dn@S7ub%{FS3{xf1LMs312=gucuFPV{*AQRC-x0a@*dxA(tDX;gw zgq%l+AvvX%P5Apv&GM|oIgnhY-kgA3z(){=+3K^5#C4)&{D>O9rp2X{)OK&tNctl* z%txObe=)m$2)>2l{daA+ys&os{zLfl`MCo}AMql7m!Eo?TNe-A;ccNLj5_EU=k54fn!En%F z|M*75$%c$ z!?bb3kDd?&>juwXbiKCy;OcQ1@yr)bHk5^@R0K7w35)r1%!s7?O~+)P0!B)L6xS#4j~su+B@hmeaQIg@TkqTpM|cENfoVqnNbKYhSJKUBFlPrjBf8dT%I z|NOa4E8JCIUBQhyH1_zM6Km)R_Ywz(nNug43VMB$cI(SbfnxN=f>?r53C?FWL(Yjr zAwo#t{cFQopeZDvU@5K5I|(RebBHdkL^yBiw0XvUdzM_22dN5zuTI7RrbXyg)0BG8 z@>Tr?jYwwa+`xW#k&Cp#+QLGyz*&A`Kp|wJ#%BEO833h@PKUgE4KD7az-%-Z`0WAg z7tB7$C@2H245|Ny54!;25Z^zrc!s~aD;ZNhZxOz=no4DIBDV$~KRP|P7qv?j-X)+9 z_HirY(oiO*UM3_F6_)~1=M6EP8_?Fl$eoJ`gd`CKJWcQ?*BVk$P-j#?x{KByE+K?v z-2!uaY&fO6Tw5l}4J9m++rEE>0PJy;tu` z&*yJzZ@wPl+y52b9Qt}duYWc+kUdU-d=!Z*LFW;_99AZ~)W?*h#K}uCm0djbS78%! z669-(w6VgG$jP(VN3+qv75xQczTP{BZ*+Z6v_d@JzfI&xHU;0>=)~r0dTHW>!D#QhS*nZttNrusUAaURdb0##>Zt#>Je3%@ zL(4?vCRK(+iZXEm{(?H>o!@T)yLQ5+{6x178X7VwGgo<^chXeV`FpuE72v}UV$WZ} zzjO!W(1feG*ppC&({_-o0u0HBTG5J`UpG3*dJ9UXER3E!r#e-U!Q%Z2$y4OLDstGE z!j&N2;SxxsK+0;Zs%ngFNo95)L(Yn`H{i7}M*&A9w@IRH0Sg%`L&i-EnR%raGFC^K zkh2vS<6kmZS8FMor@CPmh;p0+$kdmPv9$j5@yNfZ1O7Chw#xY^Smfvn`*4MM+f{%k zs8;f_%4usT5DN`iDPp&Qz?|}endaR|U2xaq(A%CMrb^{Ly1j2gT3S^8z7YJfuDEZp z->fk{rN+Jo)?SbYh2?0j^uAKDy>VzKmDyY9vu4rhHLUDjqAI+1wx8n5^d2>N_U1I4 zgl=+?9~@jR_|CGW&^>(Zn)ZpFCe}^a&Ta<=4FKDs0X>%uF@!Z2wE$RTYCfk(xNwbA z>;NiJG|=ysZKKAAe?B~z*prN(jtp+bmzVl`^ot5vem22|Doe<^$Z$&U%;-Bji&Ddm% z!MC>bDlB&iYMMr`yo3=UE%5*QIkGp;Kxdrh_Q7in9=$|&bnk;EtunBQ(>AJAYkn9u zq#ob;9JcW@m`8kh$+bjv$+X?^)>K(y&bO1Nayc{DMPBc-og`(3q?z0vs&ELBXE1$Eo%`JV-^}FSo%O`(tCbno9eg1xYnEI+yF74mzU}SHo?N+$ zfANMiQzw#?NQvfP`G;FC5tMMMu`}<<$v?eoFR0-*&R={y0lm2C_~}NS_Sz zhrQ6Q9B3ET!6AXBo<|9%M|4i;jhi{U!bCMxE-v>vVq#%`!LNy8XN@|IRm&2oG1=us zwYsIKIa&#~tW{LP1!iC+T#PMORKg+26QIX933?2SMIatSmk67egoDl?4*&@kgk?Q* z(tmB}{x<$?*feXgSWrs5#rE8bDEY;kXVm9V737T{h1QI~O1S_!*uHbc%H_+hZ26N9 zE9P7qX5FVi2>=IKpqD#EKGHh^Kze%A2|AZq9RC0&{Fn;>`U;X>&_th_IPI1(i%yP~ z?R@mwaTB$b$n$XL$k83?t*#);reOID+{lBnr!Beb@RWU+;;aX*WJ9hDd{6n(7hG< zV${^Jt8N$QNf7jBim-l8qJ^C&=5r+dETMd8qlrjd^7Ruqq~v=hwu8u ziYqmNhwu6Jesb}rohP5t817r}m#R@y9xoaB*Ujs&9Qz^E|1jw1QiPNKte~L7t4uxo z4r|=88iI+?eZlT6mV7Ywfpt*oVc!E~2OfI+Uw$b?#HwxdsMHQ`no2!mPNP3DC+(%l z`yPMzMO47@|6C0Yv2TCCM4I0F_{ejQ+DnqCSLMO%`K$KNxe__^kDfkugs&{Fe&Wg5 zZA~o;0M_4!@n=C-hqa>OSO-Os9-^YU4%&g=9ylfdo{MHLeL17kS(`m?{Fj>Q@ss)2 zuV3*>`ch+^Z++osy7~#7C>d+(?kJcA>biecG$iMOzV0_0H?__JZQU1@6H^o4YlD6# zCDQ@UrvaQ}88EDsg-7G=KK8KFPL z)=fn-;zmu~byo&72VidmKStnRiGm(AA|8YR0bbu{5~O@s^cj?)`43=*rv7!?(upL+ zaa7K+r}$>W%mAte?sf_P(sgf?=QeM@2XnWodd%GlvyMAr5$O6#t0tktK=J$XIRfJ* zW2RX+{Z)-AfoPyqAk#f48h{=e3P(jkDlF*)TmWqte;IR*B1zj9b^VW^d@9-VAjaKl zSW6Uf*Yf7!Pisr3zk1EOOIrDzM>YhDR{)zLsLJYSg#PnWU?=RYw=q8Z`Io}@ylDO8 zM(gNBw@>z_&7SZS;$HDNoR!eWVLzKsgPtJ)B7*uGmgPhjo7jD*fD=7VYM&OI)WYn3 zXR#1Uh;mm;jTGF~^5gjg@LC(XDavateh&8c*A2W9>oXki;@HTn4;1Z*j1}}z*zX@! z%{su1)$4b~mo=hvet)Jb?1l)vO`IKXSeKqAv?RT)qc6ukTY=(7jl`B)wYtO^r3OvHhp z2!zj%J)1(i0LO*h4fvp7|8`+IKt8Z%3+$KLFk?j3^bKQ|v?XZvwa0@Q&^?#TsmiOH zR8rP7clNeBmR!+T)3tk28(R15;@RU`_Klb}y=sfSWOeCwl$38`z%LN8zEH(Y$S;{R zp=|5qi6!;>SIlV2vQL~2Gyo>QFI6Q$s`!u0uXf?eMpPQSF(PVo%ep; zOT3)etQ_q=aNq#Hm~V%ke`f)?NAK?5y5JpDMT`hN0q@@i?~nUGFY^A-;o;Y3oZ|aq zN-vy(!tfIm5(RpTJIjdkl81J0f8&}{pa2UR6h4dO)cZ`JDt~6{Ual!tS)X4x8rfHV z{5y5LaemE00yU!5)Hm#dr{x>ISi^sj-!Qrm9YR|Us^V@Z;xGvUz7u(8BdpnA%@VF( zm?wnCC9F;ZN0-8D!@1Rf9*%$Y2tVWlU;ON`m0SLB=W9m~wlBZ$%pbaDHsw{0`liD% zi~nv@S>^JM$~tt_&pvLR`Oq7iI)8ceSEDA}aCE^{=+2qzovGvMvJXxUZD=pMd(Qn` zb)$1Z67C&?1YunVdpH)FgNMBbL&PS+l9{kFA67Av53IO?|JTN`6C3jLMlZ;kxHs2Y zu<*G>b3cCt9p-<(`TEW64lQvT|L3Pa7+H5|{+Ncm<=W)O=ANFuarFzY{GG2st^5P(Tng!?t&<(7$kEU(dLyZUT)4?(Ttpzg`v0!WxD`W(a6?hP+ zgWhQ0#J|eFvZ;N}MwE+u8|RG5tGKDC@?aI5Z8&o5SPQsAzO%CU#)`cBDq=tX#NpRp zJB&u6x}$HubCf^%-R`>rv!4sCJvz^K`>rv>WvGIGG;|&R?4pJ{=08QuKQ$+K*OlM> zbJuNf?jPnrASW&XEQOUm(MC}r(n2?d=}4F~dSS~4tN~Ijflyg)`8~6j1k(1EEgZ8X z@v#d2@wB2Ux7+QamfPG3luB!>b$r)Nz3YoV+Xemc8PvZF`Xd!&w$jM{ZGc8$xyTo$ zq9Bh7RJ1?2Vl^&2a9CCXdzJt=fX^VjI6vz$3O-5)!< z0QPA(d-*%ClQ#=!QH5l*WRhfNgeGAG2typm8L*ooOp?RWJ|IH>cZ9POln4?A7Mw_d zld$lMqFmwSOAw?1s{)Y&Y|v7Bwy*!yeLL=$IdVkn^vYSA4%{-`wPaF?^|FqplIBUJ zWs@&oap%D$+xZjdvaPk1OTerK8Tv=2BTt**s3WTQk27ob+!?wx*X0SsRk(A}%2SKl zN44BKa>mRNm9110nutKWxwL7~JL9RzC8bSGr8iBisc78y-TY?sWOIH%J!aeSCGEG` zvk20iVNVb3e`sp!(Z96o?=JHA18!eBMPNQjN`4MwelPS*9PH(FMMG5&^#>6+4Qb){ zj~3odjkKf|QTGNz$AcBu@D#DyRyk*WMaBI272h%j3%6(#-;4na=_itxrPaf%%guj= zs23^u&1c_5twc-c4or^#)?iGw!E=j1&KnOlbq8`uaY({k0zh1wi-|EF9G_R%4&BKOWjNIZc9MQ= z$t^E4WPJO$yz8zlXxVZ9Q`;{8VEgKohnw>nmaqO~!q|-k^*bj_4qaAN#cf2l|7!D^ z>2vNWnlPcLD#cA)g{GsuDdyai1mc*DsHh-P6p3R>t)sR4qZ=>XL|mKT+pkGY@BVDd z>>0Ls{D*&@>u8&kGh&1%iNtXE1oXk9&<9CCk@LV}4(!?%WQB-y1uqtn3HmT3fI)%u zfK~~x4l-%jq%egPh?6*F00SoA=$U%->Kz~P@2s7+Zn5_65 z0R)-wHW})Ut@~w%8wv^<54QiAKO9m!w4-WA(|3&Bgr08&=KA`S7}xCDYII{3fBfmv z5}HumcUsM#3w>8GZd?J6^!FpJ%61zOo1x)G`A#TEqB!&>|2F?!c{u`Q8zb2T?K=bG zVg@>!CMgG+F)%x#x9&W zcFN?=Z7JU7x}4iuLT7HfJoWU*Ri4Cgt1ej{m=p|7+Bd#(ws&sXJsl5iy1RJ9nD(nK zpSN_AfS=K@nFBalB>_#Uz#XHww1A+X7{Ry~?h@EY6k(YfJZ4DrYyn^i-JuCmU?x>W zNm#9Vbjx-8XBZ^&^2b)?PT92~m{isI$8{U7-u@9vUIV7TD{m=Yc&KSC|L&f}4%OZR z{OPhX{@eRX3$;O25^)p%$1prLHs=r;|bu0j+A%7$Y^f~-cfmpHOV;|&a*KL`y@Rdi&6E9smcEaSk8|v~l zk8K-Qwd%2lkDZ=TcSm``fyFt&CEj?nYv-@iZQ~zYIeP5&D@(jPe8p?qeQ7Hn9Is1W zT|9Qtou)X>oH-xwdxbFyzTA)FU##Ce`oyvcW3S%66$t)S{B~|aM;LY}1KkXA8P+UgKgQy= z8`$m!l`||hK7o(p2~Y$F1VkXB41DO+^J@8< z*JFIfEEua%%mQHp_6jip6e!u%+n#=5)1H4Wp0jK1@q1VATD)Y_<`*W`FYc_Jc>SU! zcgAOX+BCm?;@-_$8YiLUk1d@$YvD7WEL9h7Z@+V9Q)A2FDfjv`c{dZb1w{dGe#hqe zpkpylwdQ4JvW*?5H{Dh-GCb~0=ROv2GhWnD5n*tICIo``@GGW1!fHzdPjO@M%@RbO zOCI~THFvfajau;H8GYL|la4IC36ZB>SaZvfMdMdpSzo=xi~(zy?*-9RgJf@MH#H%r`UrNf7i z!MS@>pJ6nicH0V1wO_~oansrmvhQy{RcPg(i_6)&Hz&^Gz3OUjJaOpwcK*Aj^!tyX zS!gDjoH3dIZu9ZeZ6_XXeevhB9)4sN?gxbZb5Ruo=mpRXs-pWK80`G$>X9u!I9!*vk_m&tz0pF!nckoxX-h|JI%;eNgh-fs<*PZ;=q z7#D!-M2H1U{?_chng824$w}RF_aCmQy6bS)aWi>yXy>H*&WX>~r=#cI*|2R4GImuI z&z?0el{j;TKSvw0cY&x!Nan+Ht_8Ybk4QlnlmVCpT?C+8cpJP(J;YO;qM=X>RoCvi z=JS;^UTa9b`(d=Ad`xk?X6lBAei_@kf6~qKZsDIhl$kwt1~Dl(c|x!p{rs)XI~*fF zTzd@7d*MwfOMR94@N98?V{SA1%vo8eLfBOsI~XT;p|HM$U8j^1$@S z=;}oi3LDVUmlrfIZ$CP7e`#F7q4_6fG*mP_IPL1Z`270`Vti(DVsdS<(_xo8%!Ly| zCu-|5wK{_?ePPvtl00`V9)pH+AH!HrfiZv`mk|j^WOZE!sL`!-g4K7XfUX2Ig@b z+63$9gJ~atnt*23OCE0soo;MCy?8~fS(U!0EiR?vbW=q|MHP9lt-_;{GKS~gD7iY^$ zPS4x9@vdK9aov~K@b3|FBvaJjY`jIh)Yi{D9X5P!OSJA zfAPEDU-EUp02|c-0KlgHpQ$)#Q-uiA0&@}Rq|m!z@h75j>6N@NtoKzb!*Eb>`>%NH zp&fSzGm`V;YyP&rwPRk}rrFJL>P%_Lju9Ig19mdg^7bvc`Nq{dA6-;ggEpL4 z*;&(kdqx4gOw7jGhD+8pRF6njNhw50^Xr#4c~h!ll9CIH(sx$*>YMhyywW?R4Y!@Z zyd3t*Oo82c!ij@4*s=hVccD)ULB14T1^W_$*TF_(L9yinWf7tZCm-9e+&ev~PkPv3_Fq;!vhB=Uq;%>P5`CB*a31*}OE!EHNm_2Xw*h}tSn2o0yQ(Vq*3xrAA1s1)Ffe{j zVck)b#RM&Tc)})*Q5d@L(<64?vCP1Nv55f1@c($~UzbcDKjp5~n^!eX3uL6^nNr6* zw60UX>#0Z2UO#T)hGmmyP$W_P)~5T=ktg}?j~+z2mySF-r98KIX+~jwN{Y#O=*p)y z@Mj;}IHjemW|7EHAoIsZ&@M{HGsn6O2 zOcF%u5$*^Yz%yF7!-5K)w?>3LL2!vXu=~-Idk(ZtTEDb*@^zOTK784={O9W@ww;{Q zyl`RDoHYl{e8`tnwo}7)-=}EHUjKM#w|(k%4R?jv z2yV0>pbBkf>L=c^Y~!Yh^Jk{y8G=*p>6)#Eal3T=&K=MGW98K2QoF80UASs)eu~@dy5q{nHf-JW*fX0qoO!5So-QXyo z)W8_h5--1+No5RRlfW$5D7jX07!n0E0~Hm(H3{oEu>1zP3WrxvOo6}*3M(vW3De{t z*50IHJPeA&8@u}go&zrhZ{QEVdeCq1n80@e=n~-q{ejh60I*moiF*e&WD2EoSrZ;g zU`;S`MpH20^g?#XoDFJfzmvtq;bgwhn;s^0=UL0noz#ar6X%|_%$-YpIQPh&qD*<) zUuo7=s8Eu`tXVhZ1y-)wUP@BxY`cs#viYvG0J0)u^8M=EY|7?;F}127Mztd$#ebbz zK`5vfXmvYhbJB5{iE@sLQFSo?hs-fv1;1IbP8GCi;)qhtzDVj`lf-`)|5(`)wSl06 zG6${Je7$cU)3tBkzph}qmM#0&70ZZR7w!I%Cf}f%>8g>QT+&|@`_Pz%Rb$7_oJGQu z;*>ik=Ok)SZUZa~$9o#l<=Uk63MFSHVl5t0UqX6v6iQ{LUtTfKO2dK`^GY5qB?-bM z)fY-h#;UazDC9d6MkoDDOUWjHdo_ZB?d?>b@w`U@cskT*;+b#{XnJ5g@Se?Jt_OaF zu`rogpDEu0BI00TMP zFtdQ7LdCd3{4tra`i~asEye~82N~aU5;vui#e*AUrYa{X)q>JBNI}4#BBpL+8*Ayf zMqk>XHRWbe0bs%>ciRCM#qc}Cc+nS?uC|zVG6Nl7Z z#91h?Q=godU(eDqS{sm;kVP7g7WA9)662KFhFG0i16Cg|G3Ato9+fNgF~;=R`2NFA z{*9PoB%j|ip`B>0kj7Oo?X6^TN^V?kjM8|iNv34$VS;6&V=28QgRt5>nklU$V^ONq zGE0NXz{Zn{xD1-e;ipQo)m7Bv)a6xiNtUGS=?rC;$}|b)Y^y!s&tmVV2^ptz>I@n~ zPD(0`iU^bSe!0UcPiW|e(~~7LB>RSj0y2z$;vj@&c4wmC#R!kG*%ZVwg7CoumgK~n zNW#Mfs|+r{a+jZlwRzZD2Kj(XhY>rx-wLY*h0ItNR19V{1hLMHOPMjW4Kl)i&>E;1 zqbycxmRgh4dPbRG9A)Mgka9N8CXKD$9DhKrl%bj|8@FQo2sBbL(VL|6&9x;=WEk}`Eknd*$mIZk9Yx|Y|yyii8i_Dbze5-Fq!N|~wxyj!bD)|e33M0ngO zaUWTeb%*BHX%u@+vh?^k`&f69jJw1+)v1WDpP=?xb(GVs*fJ?6R_1rET?XX0AHEi0 zZ+t`HYnZ!w@M0aDoHdzAqZ#yTfJtjfq=erK?h$l^oB zc&`Wx(i#gqSomPVB#<8{-(Q*=9JhGmy{lACA-dNpkUZ zF&a{8f`cRp$yb?JmNRoQ&Xgu6TWCKRm8Lnia7?^jtE03?W-iLR)s%fdqwuo@hxp^) zYFWB}pHcTtFqUU?TB96XiatMTZ%#(+DzM9hOgdWO!MfN+i+8q6C6|-*;(OyvvCKrO zlT1iVD9$jEYB?{B&G<5@cBBO>7@0nORt&3zS4!R+y4OfSmKA#kQ~PkgnBn~~;DmX$ z3D^Zp6)*u0W3@=i1x{{OAwX*Q=z#-x!V-Z%IfNRp$&E0>fV!~kfXO`oYq(;D#j=2y zj;n?>FDHzTU=l7YWd!_~t`sA9GHfr!nW16saHY7ca8w4)Ne&#U9Yj-+BTb!lG#D6> zu2W~k)yUMAY(}{|Da)0X$rU@yWdZ+g`K(q-o@>@|w$ZgZ7a2!W(}<{ z&)?dyDJFlu)9>*F7N~R@8$E@R8snI^brw%TvMe*Ri0^Ec#ReA0<&<7Kl29imOJ#)2 z9hc)6vsjj7)@Hg}^%lE~DYV4}7H-@B&$ObT#-!C`XEHK+45iI_jO3c0kaF~5+SVT| z$frzdh4W-_NxegnmON9Ak^JyV;#&w?A;BSvOYUS2|4!eW$U(-rDI)*QO@9 zM<=S_m;%T9P>OAFYiyOBR(mWKWh&!JRL5APa(OYMi#5=><$8z1M+7>V3`Rv5nF>y= z(^9b(Y03IRL(-g>+F+J%Bx4|b`4;u~#GII1%MGx&o7!kG8q=?*RpyFp{+CkEKw9R+ zv!|hGnP&(IbCB`tTG4G=v4VVmMdJ8w+xYS1`{Vof&sXc$(<|4n|86I}a_ZFYcEa*2 z9EIxx|5=g_$%~RdNWK`lMWWv}$`_H-fk0qBg=JoVGXP3az{TJ#0v^mke2HcTqX=+1 z4A|LtcvD^fN{`3!-N~ic$ohJ9-7Rh2ncr~ zepr}x1CR?EDZDD!FE+oyr$8;?A0M2y@J!~U9Z$kHbfmX&FYj55n%Gdw}Til^r#f=zU2 z4DmM2+VQ$Ff4t4FkJIMF>g~ylJnexr{Sj`BQc9_*Sb1z-na!ZN$E9RtL^*+EmKZgs zkIC&n`t;%$Rkg-o)RJHu)D(JA&Ki=OGVqJUTJlheJvK4cR;V`kNqtPMTCPwSq&~(N zFXd+?ZfXnI$I6-$J zsCDC}#xP1!tA_bd+GwLTowPinjLBu0IISupGpRY7B*CbzAr}O4Ms^DvqLxUwKClQz ztH2iAYmyHn|2Q8s0>I$`bOrPVuv{(1z}d(DC`^XFQID!y7sw5uF7M}N{Yy@2G$*a#hCBIVL-MV{KgultFCsk9G_;`5p%l9iHo zU{#kt50qkpBtR)hqe2*{r^^J(C|C#JOvJ?01v?)h3&j4XNT}MBq@I0AR!J(_U`TZu zRF0BowJ{)`j6j5o9ILL(e~Q0P>U9$D`)XVMJ3+TYE2p(aTLUHM{|-*8XtS+=;eTT! z)NouTy&(fEef-o2ZC^TDC|NFf3&nuzSf5Ny9lwI1daQ7d}R; ztb+;ePZ@j#l_wUW@eD95h6@NO25@Vbx}J z%SorTo;9k-SZ1GefdO_WR>JTq(h0wkE+juWeiKRj3~!Orh>vU2F$-fR}8Rd z#7Jl|=Jsd>!;{4D%n+~3V~0aVjH(zv{h-^&1@PPyD?NU?3Y&=3?O=VCN+X&RH0Q5tN2XE6itNm6fyxTsIkL7h*Osgj{Act4MpIs-}!16pD&zlrmqc zySZWSoWwX2TCIu6%E~7{*(%SKG0yJQ|9PY(*C=T0;OSodJiI zIAZ6>YT~L|iY&qMl!=FENdH?@*Y zk`E={BI)^{8UrnB1U4aV9Kq_6h%n~_6XyZEk|AhO;LsYZHT^G6OCHuYH?J7YuoC0UE2bfhp`~%5&Yu`)_no5zU}w%6&`W-ai1R>p4-|(d zCLsRg!nzNJbNs==5vJBj0NekAq?-RcJ2s=(qmIesT(PVZVitH8PT@iy zF1I^pTjCJIS@r0z|CR7et<-R!M<1ms%bePl>yG1Sj+x-~?$5u(NFb^FmQ+i_M+ZYo zeqw+;K*v5qa)YEBsgdJ6kQ^2<^nzj=Q)|ZT!~#5CpcH2Zc!mmxPw@IC+{TM?!qSic z;HVCD5%@UU}O@~q^K zlD|m41|y+zq(||vH+})?LhI00bOky{q!IyQ3^9l3B)W)8iOY#=h#QB-B)n?_{5JuL z2unvSBUt|tBp_IP#moOeH*B@Wo8<6LDsib)Oc2yt*lK?mxx!1l;i)uE6jrzJh7L36 zio!<@!JrJRF9pIV>4Q0Y5KuD^G~jfY+6K(<&~QWW)1gAFX2L6Cct4RE!CW5pcL_OI z;R+eDvDL2JfKUSwf|eRw76;96 z!B2w+(3eQ9%Nz`z{cZ)WL;e`!gyk zRc3}!dQ}BKOSoa~*s8p|v|`oLKpL0Gxvp>(?(mGhv4P4k>oOM3GNt6#jaG1+Uau{q zNTWCHNYR7U$)FH(`T%%mnz zj3K5`CuKQi9;Zpn0i^&fV<5ZE%*Dt_c?J#p7Br}ZidV2o^$JCb%Cl0ci_@!S=6Yo+ zd!YhJwS-qm>uH%rWEMhzj=F!5T2)NgUQ3gQ?8!yz^4esbsfSvAuX z)mJXmj;Q#Bnq}o0RwE^yu|}y>>ok{7A6=i(O!I$EpF*={o!&DB48@+4bi{HbqoQXb zuZ!b1#hdRQ_M^ZqsUjuSvQkSG3K;{ z&@QP{D$~dL$a7i}wny=YTr#PGl;-ED?Ic3-vOKkoRPitC^f68+qje8h!aY4QsfquL zWo0F>$1zD-k!nqrTPup<4KBM)m#9h8sP%brIBCYJI3-h<05XU6g z$jo4hIzdCI5@P3mSE_0PziynuOG*i&TxDFKR@rSDxm>FR179g7zs$rU!X%3`nXO7v zuT(K6SgU3A$>2c__PuFfT(vakR#9^}6~KrF=q13yzJlu2#l+f#9#qn6I-GbTJ&kpmL*3 zTEZoIq;6VjK=63hs8cjjYNx_X$tiFIEH|Vnvm zvz$&c%C);0g=}_!tCKN|ycTv&F?K>KlTx<0gk%kU2SMFzvl!h{k5R8P$138GFRNx= zGCf&iS0`BFR3^k}8J6@U1_I;c8ij16+v?10=F+XjIc#jF#%Q!6nZiJG3RRYhN|wr5 zQ#R{Kbm}~)O&3R~Sen+@X0g-VjGQHHt#+2bft|>ywO1$|iOzJH!Odh^^d_6!R6R-x ztM9Z-E(3db7JCdj17@jIpy#5b+9%^vbXucU%5jFY5=+pjM}m6!<)A zUp*JzR}ui_&m|}G zf7#Nx>{9X{{o;84fU1v7f#1In=8YraB=-bKv!qqh4*TJj4zC|zi*8S!&{1JDpa>0X`$*8{U)2~CN57oP3CnEq(;Tr}}BwhxT8e{}|yE>}Z$)uhE zh)N~S_V#(W|4AoK>HcFExvwkKgu$AehJS}WI?)5t2hyW&41juZWI_R9fQYTh$=#19 zCllEMN_3wTE(1r;H0aokmrRjNm&}nYg!SJwZ~}0%Ac60b+$gyXWbk`_*cc8UeEdBzI5^)Y&j3swNL?c^BSKIFbozqLFzPukjo`a_2t!mbid;mc zMg^lO2Y*j56$yujq9OxxhFRx%>3uZ3M2Cl@F438WqBOk>_j{3^fdFUg18;V)hM5H( z*Rb8k2C&gI1fQwD)NEJZO4e9?7cfM3}^rTgRlDZP0* zi;EG_)kUzvm0vE9sTadwgu!dDo1rElopcJEEbjb;1zD~?K+*(IGlWQv)fGn`t& zwMxK?RWxlZ6lvlj$qIpA_Cn{K0G;kZjWERj>3}#amvsyEvk$|pq~8SV^lhHJ%-S? za}(>zuQ0cok0?B?6(hKR=4OwmXswyvYHk(e}QUY~Q%OgqBS{;q zZ0%ss`wmxoTV=<#N=GGX5sF|*5I8(hTUq1T$8_8j76|9#aBC%@66HdeIjtj+35wY( zJ6fO;L_l>za8r=R; z!W)veM11%{@{Qy>gwBf-7`iW>ehU~BRSsZVq~`;v?r>=JkCkWO(}$+{fFT0O@1^1q z+CPxe_ppV5w|a^bp)j2nNcHz6`u#b`kIN*Y3H@*w!*KFM*V)TFejHXYkOln!1|#o- zTM^lNt>l>Gq~!VYO4r!J0eB7p^G6ak7l(}o9QO1{2UdZX5 zSZxj(ZrA`@2&6t2>!~s0fh$)3!!MhghOlxQYEdI$sly0t0xxrbcadB|Ef8(vU_%~4ITW=vaB=(P|p5p(3 zICayYW^HyQu+7iq}5dYTB$g|_vyv!{X3*l+{CzS~>emXKAIF0ZRo zq?BbQ%&PPbNXe?(Xfjz+JR3Krq}z@9jdlIw;Z}|Gh8vaTfJRBc8&)(Oj=&0@r!9cJ zrAH+1AQtwPmZQr<^m}(6sjj%`jwYFDm!YZ;N3c%*6_(48h#F@eQ@Z|2hrb*)4O+{j{e$CZrXG*`m1XyO!X%v#WM+ZF3#-?q!%^~NO9*3 zNE$4YEq`&IG|6b!<^^?@LTPYue*WU1EXkOl4d&_M3%NX;aG@Oc`du!6^w(A-{@Egb z{ZWXXC-%bGSH%GFTd^BL7BN62iT!Z)b1^`CBX&f0NDNTq_?nm`pM%Q_O6}Q+=1~Yu znowhoPVsh6x^Nz{Ew4?jHQKFhZT38srY$dkP^(rWCTLY{-49(L1Nns52i;9#fNX_c z=zbJ_$Y-G+x~Ibr)=68>i?>@qS9&ApR9=#N0Sh0cu+F_79YlAb`_M`B3_68gMZZPo zIgK2R$wP*tFc}RMj>7OCR*!(lc#Rn&2QU~B=YhKbg%KDF3M2au&m&@Wggr$_K$tuE zykX`PrU2;Ql~=@ld?pstf}U$`m{y?v*Z%p$_#m_+q`7_h^4swjr4I~+_U&J=U_bt% z^nsz!&TZ4DZ^K`dJ}?y8w`S6$HTa9t2Zlm76?iN~Hdj(Yk=0WW9Y*QVvFPy7cS8Hz zbuQLpP`F$QT{7dUbN7#<^!_RR;}^~m%Ec52rT6}Z_F-0z(tCeH`wZ}h(tCdgP^oj_ z{=Plr?;oIw!=1gK*Y^+5@!_7{7OLwXpvHx}c}Ybdr|d@ z)Dq4p_Mx^t@!T-g4cmVQYTQ45f%1b;;p-!$H*_QtBAO$isI;mG5e^-Rgox%yC@QTW zLXJa6A|awV5{gQziV)_|kw}PWj)bDp>Z8eUbU1V*Iu;!!nxkXU;q#QK>Q9vW$3sW@ zr}U2#&HYpQ$1hw5`Vf=&&=LGgG)IN2Frg0}!M{W^{uRSjnB0es;9sJ-H{74}Q)fhq zFS6X*L&|;$gi<8@BHP^``m|pH@u^7vMb^75l-MtUNEF$C$bQ#^-s+b?yg3L5=;Z~y zq0oq7W+bZ5!wmYehQ6`To!_${aVH)Z_zP8quSJ9~Iz5Ae$4D3vJTwdOpuiuj0-bMu z+n<+w02WHl!i+Z!HK64nGe3dO5PIMw3yA&1LECc68 zTpVZZGm#4O+9>|oXHsSYf`~pV!inX;u%f9WdRB-07KiMVRiu=~v`V z&or!u`wp0nMeg)W%X--GfazJ}&Y;t@UM}1l8vfL+w@h#7ywkb9Y`Jgj`%m@y*3&m8 zOalcD-ZK@%F=0B0$Gdk*h-1RE5VP>!siDBoVSbqRy?DAF=83TMfTp4i=yuS7eM+c_ zLYN!w1&;nHX(sKYhs+{_WGPuqHjqtZE7?IVCRdRg$nE4FazA;Hyz7T?`97Te$C~>M zB_Rw||HY;cRsY4N4`cp0EKdDXtLGx-uNO5Z{co%H0(0R0(!l_!qW_$_fBYirAD;9v z=$!k9%)@`k-28{k*Z+Uc;s1;0{r^_o!Ep2l!_X<5Prop<%o7oHdUVc_grQ}hh{)3; z3`G)#mVqLoPmhi|k}$L^6cK@Xbk~uDA0`v^3O&7{L4~K@+r6QGkDSz3_~{!vuYlDz zYu{L38LCH^8YoBg2vh@QsUD#!B2Sh7AbF}1bR|DS3WiJ{LW=35y^qQhy?Y^A@6soIh_?Oo+Ie9;jcXXv)^PF+M^7Ve*7(8ex5KLE z-y~iAyCl5GPLm&dP5Pqh6(ulNziULYi|kh!5br0+^cFA z$nyu0{4zF7nX&$D+eS-ytQ@`Gyk?9T`rp=sd)i)&eVS(@3pWsoF+Cq<@@G@1N2?e&HOX zq<@)EE)iNjg&$EWxHk`f%of1xAcYgQKVr5*nG^xj`mg2VVPbR>MW+lj9< z@W-e3{*n?L#($wB;j3nVyByja#*qz0{jS~H#Dvg;VgMcJpF-{qqsPim`dvdlF@bLt z14MQI6sjXmZwYOhyg<5;h?Pwb&SvEkqA z4xOhUpK_j?g!Vi)&s&nB0cJbIZ}$TjivIvV=ogU?`51uf!{WF590d3@_#yO>5XAzd zZWF)VuR$Qx4L|6^NJt{7`%&c9<)9DTC9L(mN06|0WEAWc*$eA@ACPLY5OjchL2CUp zT1KU+sRpWvYNa};#ndWl1GSynL+z&yQg>1JQ75Tqs8iId)Nh9;$qpr@MoX;23HPaI z7!qr=^g5jIP!evR=SE4s!)bGLo<8;b+uMI($#+;%{(OCN^SX7- z&FdrA(Cd*Hku|)up8N@22_oyKQOAYaiQdW-|3Yuz03pN%hJ|}}yUiwiL$Bj2k%i*}!@|7; zjase2-_Yy$N@NWl#`pTKi!%|-4E>*oo@kkftKIrY%5pK#trKsdNJ{7rVhYU(Sh;*T zze7Y%!Xl=0KP3hTt9YyX$-XI2YP*<1KPX~k=yMS*(PlBF+bIOv+tC*BR(E1=3dZC1 z_Rwcy3LPV2BfnY*OrK7GJ#hiUy6+JKgi^fKeY|hVv}yb*F@?T0HA$JClbxz?r>8*( zW&;X0&-El`^n}nYJ;C0b-6cJR#GENgcT~>a;@u_T;&8vWIJ#w!;=FW_oOG@=o0GiAYDpV(+zYJ-AZ@Ri-$ME7;4u+wDf(k;XZXn zN$W%D&4)9?7%ESnI-_P7ecBL}ezETooxe|=|Izol@Qmcg+8yzqoNfGA&l=XdU&QR< z-=(MjDa=IvU2V9iJ`-mYJ$p-sIm3v|KzhoFGn@Wv21Cto`lt7l`;po+$joPuwFUHM zWZj^kSQdw|9ktygssa(7Wb<-i)MmH%CIfX}zJr?)KI~UL9Fe=v|9IZ${F( znoqQgV4P@p%X^F@cd zo1-(<_^p9V7MFYLrzfAvlcXR)g{_zXfap4?4##1i*w&WO4 zDvN6;=uI5%ZpOdi@W7PtDhqi%Xqv^f6!azzcQ@nTaCl%!c-4ix0o2dp+6sCThr65c zZ#XyjHniy})a{})+WiKLw8R-`m#5|>oOMaq?Yd}Og@S7fmz zl5(C~kQjE?XZIs-pMQzX^~134~c|C?yosAxauEdA-(RNup>u+pJJ% z-Ac1gt5M2sMrE{9sq`SF)*oZkSk=ayG|G~wBf&#;CS~MzIY=`TN2#QQS+A$`33M!? z>n2@l(>4%Ni*GuoiDjH%vfPwN-o2&8nV7bvrDaRyvX(6qM~s-brDa(qj;AF$TegI% zH7d%Js$)6dG=lK8DfQ&IrHv&%sj6{lW8+e(#-Q&gXj9 zRondCXB(HgRN8`>xY2eC#TC}!#)F}7^|HpsC3S@yWl6yIW)^5wNlVGU={U}0(ys&C z{3h1Hc0U?^>n$zemj;vA5{b5tPGzy=4#`o;DU<^z_D7?3v>2TL4avI%ODGA$(E1Dj zIdG_efe&EYZAIWa!R-OG5}YJpTogQN0QiD88@JO7$YTOjaf43|fLZYRF1SkoyKPVa zK4BEXxJR+%TAP!F_9_0q`(zxIqfo4W+SX99&vx zi|EkdL3B({qA;3n4#m?s;f=NP9NCD)<&BiV@1qb#%ui&`@KN?qxT|bzE z0eB2NPRxb-Ao2y|&c*M`G9F{V38cYkWZe+On2+7~_`y^P+{BN^MZkC+ykEc!Gynql zB)jMs1KgJ+`VH_nOa!p!50l^E#O)8?2ZCS{+KekP<@mA%!Ua?aC(__KLwG-20KXLY zClTrsnh&?kK6n*9G+%fjOmuL217J-O8iZ|63J(MqB|y)hLimEANEkO3e3tl3zQM@I zz1+1rgUSFa@pdDjN{Pvp`Wb?zC|inEMS!nlmgW#6m)fXu4k@Laa+WzZ&0)<_n8Dh= zg<$jvWipZ=%1(Z(xgQMQW~X*^_5wwky@>F%to}zDos?`)GU=Hb%1Ar zEGm|8=G&Ax*DJvOzSb6RU`SoOn&7}wGXl4}3>BzpTvp{sNXSlhB0`zUxQ(D|w3iti z4sc`;mr$Uup{N>tK|&nO#W@^?GCL^kjc&%6NFZl&c0z)qYFT5=q?R2mrT$s7{G||> z)cvYcVd11QCXG}w$$CA*#Ke=y`hye|M<+2H<>X?>)C3OY(~8mYsU(@GQj#A`XkJ~P z6PJgEX*b?v3eHk&J$qB40+s+6G1W=k$@udCoQlBG!` z8E4V5+3II3aU_`}O;%^KAI8R|RutJ(EF)K{a#cz>IDN4dRiwtn!uaRqd2;y-g_)63 zwHol!A*Tiqyr(G67Aw`7NzJoYI`iUu1Z^y}Di%t0(j<$;#l%`jaA#maq}f2}$ascQ z>s_=?XQyQfo5>ufOyXE6|LIJXR5`_K)|kNEg`N$nP1S_F8L2rnqtr@O7LKJ-5f!UY zJ;!As2TG0eI1)%Dv20YH+Cg}=&6%y)q^jGzYW_-ZRn_clTBnp#)`=!1_%~s^8ubE7 zQ=6YPBzudff zF-e!35kZh#rd+QwOi>UdYl%VV0Oep97T}KpAJ+;UWl?e@x3!eya!4|yS=-)OkkHzc zh@|NG1m|j(Yqc}sd59!7wI&pFwy#~-zO1%tM6Gwi1TVfWYwzM_>ZIxbCu4lFxCE_K zSuOK1GA^K&>SjXgq}l}jg9IzHim~~TE6HfGBa6plL3Wcd$%XtjxM58IQ*^W!IIAVs zppr?HQM6env4hRzO37I8UV0X-Mw`$b=rnq>FHNRNCkvzi;ni+%T>+8{MBHh}3`7Me zkw7m5sv*!Ed^h}Iff|EXA0Q?q&Z&hMxV-@~fJ=mFhagg65+=%4AgKfcIf*QZWhPRf zJ7!D{!J~G#a!m9ciAF8H1t}~z5P~2OkAN=`yB`ul*!ZB=2Q(CafY@OP43n@vA1`hh z{uGDlAy6zESRgbT1FSy_1TgqGvB-r#K;DD|NCcuR5LI{<&^E{j?alQ7wP)RaXbb+p zqd5Y=;FAd6SZE&ZRA7Rle2ST!*cAx(J$xWzu$QKSiTCmHtXO25do@9lQft$E zeq<%HwML$kg#J~-xT@UcmRMJLtR4K07`FLUmLz{*3qukpeiEf%jVTG>yc+@GG{$HO zva(bf%1R~Yv?6nYB8zlcxis*#rBbjAVrB39>f@CN2F$iJG5r*(FGjx zPOKlb=Gr76wIuhLL!RY!q^hVKDi)+Vg=tH{#2MU-v50co(~CG6K@c26g3lhn74zI3 ztdxMT)IkNS)mpinrkfXOfiBvzH&)&3E3&6rtv-}lTUKUv&`QU+*D14>MoBdID|C{o z44VH|eb+Ij=CQcc>NT6|D~pqhWE82RSe2HZc&*8O!?+?eAz2gqe`fy;hU|*Qn~T}R zpeDA<>W=~Zrdb7Bq$J+#O3WjamWMRnx#~n{oismHX>_=p=Dg*EN$zT)*_#afHyT$i z_!Xq3QiXvu(r%8-^VQpONs}sOJ}|EJlm=-|Dr8h#QUxhj+C=jCI;y-)H!_K@BIYjR zLoqQKhVrF5iJ4=rvltZJi$5Z~(vd3yGqc>@7GyBTIn?&}Mip=H|B6kzZ zwN$;#<@90-0NEJF8JTpFRO!GY&%RWtRD;r%Dr3yanHk9m zd0Jg;2FsE+1(tQ+Fc!IuI$is`N)215bQ|UItU@lIZ)%uQM%zuaR_(RL+mcGXIrH1x zWx;uxT^bdqFlJ9m8dZ(18TqNTl5C#U{E4sdI)+(z^$VkSOEu}VK_~TlJS8z|qBPT$ zB#kkqb&QN9_l~>X%zT?*DB}?S_a*msGE7c~CMLmVm(Grp$z%$`;^mb2fh||rR%)Gh zrv*|ctT9lCQ`$|eY$jn;s9mH?KU00RI*D1@B+VkYI9;`xVs%pEIf+W8R%olq%Inbh`>i$fPMZ=A#Dn{JiNksmBOscMgBaq-QI0tHFCy95{4N zjiQ%kuq;1T(gHpVc7y+d+rYN!?<8lyDmM>cX+Rd3LwZp$ss*c=ZD4(GCG0WWfv!e3 zqC3&OV1w^jpslZ?chLvvGdM9LA*6(^FQp}6vkslimSz3Ul1{n#Kngg zlaF8T@Ad`Ze+uVg;D%!nO3vXY0PwgC!8MqLFz^Mpcf+CZLc%BJ z$T*$cF@ra4-iaetnnCQsyO1DJL8(MhBj^ z$Lr7?&es^*T1RiPXS|;~hoaDEFpy}Tc-?FYjMkZZOphTeQx%T6g0I+*_WRrv$*^l$ zTeJ0TE@yqK$)DJCn8kz4j5}x_rlROHa@1@dCD*J$uP!#(xU&F^&a{~p7oM{*uQ_{? zy$*6`b0QGr9)=g4-e34B%WzMo@`+R!t(p)2&{mv&8yYyA;$jrVozstRC$GSduEk|= zcXMY!flxRMwXd&PBfRe_?qOW(esnrDhi?ls%EeP4g@zgQbW=3seFQn9*R)0&EDP_m zjVB^-NcV?mUNg69V1VrFBhjl}q>XzVEwGVYg+~@z>LcxT^5@OmQwU^JI9a&&5jfhb zIf`xslY~~ZHOl>!&nWzj`w(AmCLgrl$3MmG;~s}Hpfu8s3mzDFl6$H-8Mgb-A@|wa zBXF)L_t$81B;?iT&OfwTYf{c;3UtX(JP>Bw{fPEEJ**wkRed3rZG=(usypVYK|V|2 zN|8=^@@Npo6V7aN)*moEuqfC{M{HgBxwOscBIBgPS$IVvcr*7#k&ZneURNgAW9eR0 zo3hxf*Reh@#12g%0IDm&oHT0Cq%6i+tuRtQES7f?h+{U~Yk48rzo|605_D!nD0gyTU&flhuk0fbcs3ne^>fY<0P78FkF z>1|fdtD1blAmh6<(!tPVjlK^XrVhn^+l`9HT89*Z7z-0t#Nq$ zi1N0Evw^DCt>_yLTkV4_=eAbWB)O*nXJRN4h%Bo1nQ0ed>^n@RQfy)ReY6Rp@C?K= z8Na#ORUJvV2et;9YcmdH^`|U>pZn{UkQW~giyUOYR2wy!DUZ2@rOhU{(`&7bI;+t< zOEpYC<79$$nkc8u=c3(qcLbqUnl=Zk@AT3fmrOL*?mFhe)7E_R<*i3~JkivW=5%H# zUcIHIrMj;zkYTPHs3wmu>PJskwF*g-GY2eJT5=Agfy9)o{_>Y=KMHS+Y)WD z_~QAIdT`6=gsBN*ANkK{u6Fq*AANMgNnfz$miv@;S~}`UVaulO?AIx}ia9MxX04}eLYrK4U4tWfAnW>GzX?@)={Oy7+H5e* z`W$WchbZ*JUOV>(lf?@vNO0a3WSl3K99ELw=Djp4cV5N{h;YN zE&-=@GQt%y8K&xN(8_#%Gq)K&mcb8n)>&J&@PAxahT%XtLvT1xef^8baW;ND6tI1Z zF&$JBu$Wd4?=!pNUFmd$Ze=$+y(xMq4I zmgo|8Fja5ywW7WIEGFtJ_8bK;WF@^eyFH((rPxrKA}O0SR=0jxFaT%DGJ!f&TeD|r zisXKGmQeF1Xa!ez530!BQfwbO5IN3T3YC3KXvtYy@YTn0V=`Nc?WFgdz((SZh}#sP zx~gGxyJ1$`Vn}zb)pfqa0K5!mK;d|3;!&4@;RWsJ&fwP<6TH|2xd&Nrlr`)C2;(%LgVB)f znB&jF(hQ!_gkS|f1&MZ8S1PVM;al+)6K*Pu77&r$@QvqXc;3LT>_dsg|B9>Oc)bSy z2i3^}eLItQcGLw_l`EeC9N}dr#sgTh1{T9hZ^9p@5GH~^8hCxN62%l$KuAF|`TD@N z2JD1DaUhOyli}QL;fnABZie4o-C3+BfQEr{gL>nxgXj5emCQ3S$ecN?1Tm4T80dpBQ+K~9OpGB?MNpq(JF__ zWUF;__t|{k3Lppg)dgZt!UE6Q#-?^h74?ITMLR6PP|WP{xfl-#lO~3CGZY=pktyU| zgqRS9NLR#q8Gwex=46o5>Gd^`WYkQXX}X$*6MgN6I34~F9iVMJh@o3;aHc)&pvk4_ zK6f>p@>%K~Zqi3(DcX~8R>$VUreO~~-0qxDvc2vE>xfb80-LoFo?%Q?j0M)IElh%K zqMK=&q^T-~27SVZLRpd_-7K7@>k7N$CfG@~TwWbuefAv`+jobLZKs-Gd9;7c5)?=iYlV`^FCo zlW@c`_pia_YyAvzqXZp~T4@HwU+*=$4)B>xUH~MM)d4CroH|_Put%!B(QAAwZEfa} zHMz!cWR9z?^PI!U+E`)-8Lp|RtFuj9;BT4FSglT9{Zd3%r<**!m?iA<`C{IYfaf5W z)r)9X%(i_~grovK1Zr8FMh-+edz^8P*~NO;Kr`(1SXpPlj4X5@wZv8BnQwR01Syxx zZ-Q-~l+~Xcq-<;&(FqUfM#yS~$ui5#L2&dn>2p%Hz`Ot*qyuEs6KCwmmo|Gm$(opZ zo9RYwK^47-w%bFEfhv=QqU;_}2Q6)sg9$d!4x7uCBt4XeZjU(wu-r+Kc9S(|fy{2k=IN1E^l9azOWVXcPnYEy<5UdK9DTnDilmlpB zg#?2ikGKF^{K7c^1YYI`3@WN7o%vvZ*V6f|Pf$Rzp*AuQg0ECJo9)iINc@%U#;3RO z-`QF+2S2l&Y*I{?b~+r#4qw3&^ug3 zuIlU@Xo|K6N$Z*6>Mu~sj@a}bvN6HtnwkOcpx5e+3}w>8wS!gUOPQ-pZLXi+?Eezg zPhA?g`E^&D>6*IhzZ$#yx4*qR_SNg_u7S(1-yFCUE`P~?^UvY()tT$Birw?>yZ6Md zDm;^SRRyDwc(PVpfc@kW(}{ccesalP=A5crbIY909yDZW8(h>fFt9rB^aNTU*gWdE zz(jT@!iUnCXcfxY@3Dht0@>)BxVLBXZSIHnP3&sj`rw0GTX#+Dd)R&3=AHu=H*MH= z`nsl(E!~@McRjYRu)A&R0}pI%+g;fAnCte<-CIVQ)}6j@L(^jV8IvuN1XG9<^s)L3 z?v!&`~cQbLMU0Tr&&-c`Ncgfhj>8&pCEAfZDW{X@tYokF-oq>#cy|{JNVsg zn6d$9;K?Vxoo59s4nS6ckl=+{5`JNM2U{1sKE{Ifk}xZatEL`z@nfe<0+nCH3QFp$w?>xH^Qld{L5jxJ2Z&+ zy&D!Qu!1}c;48XL8#USalbyHL*ctx$V z*_?1jKq2d(<5y&c7cCqbYHuH2=m?|lwEC)BfqLI1hc1NPE=FdmcTjwM+@g7VkI80V&^~L5mYIQ;j=sEND zc}IKN+v2Wl($x|Pl@%1e&ZSCwEq8bYyhlqV=@^nDkjsuwIk>xt;r`Wjz|HqiAzivv(bdP9$^j19zFsj!>*-eO1m0lXjoomIy3e z1@&<`?8zZV6*)1-T3xfd8df0PRWwDPSZ%M`FmbHY?K%!6Juq|#y8<6QM1Y9E={X4^ zO*9ZK#2g|Ar@5C#@6LMitS2?;e_0PU(^8<=$jBE*7HR%dh}CV5f8Xl~u$%sU`(%F< zyT-HilS{DPPQ#3}p8c3Ug0Ml#M}!ChqTwWxIZqdC4+JPr!jn#T5(xg-k30T-c1H($ zMhASe%O@^@!^Ah^&&?ej)SDe06ZO=a6ZIXC3wf9}R7u&Il2cH+qST4a9TS^Xh2a9V zb*$Ca5tpR06_e}Amuj;2*4OvqKTY}Q&%%XXf+?wQEzvajo65bF{*Cxna+8?Syq}s= ze1Bo3SP`I|NvAH|Q>#s7HABr}&E%AE9l0+T>nJ6luB>id7ffDT)@;z0Rnu?HOj;)QiJY2B8>McN5{kxJ4BNV8^46-N zYWP8f;t4W{TV-pNY32RKeJb{-+(x~=74I_cW2w2QrgU^kInq72-%D|D8W=-%8P;ot z7*lRM$jCNPKl%Hm-v89_Mee_`3B&qnF;MCy=$mQdi<1A0(xtp8W41ivpaL@I}cT%2t-PtWxAGte?D}L_X4BsG_N`CaBgeusrPsJFrzm1^8mrDrF0e?y02Z za-Yg68Fi*Y1F4&(gh(9)F|1{1v3>udt&(EKlo9(}rhz_R6@v_hTQkY<4HtAiB-i69a6wr zl(EdH04FPHbtU&yLK#_Z$SD~qr$-}+O{7E_V&NIPa_+8_uiJ?eK0T>Y8BdAWAk#?Z z9yw3EYijh9$fX5FDMz|TkMH&~&dU-=<`p?*Ja(iyONmcgAJ&sla?RzGrVUzICAC3H z{FmUo%!e|%%Po^rnl@_ZEfQ}@ZIlu-(}$H~Y^v!}G^*e5ZY&Qa0!j&fb#_KrUkOzzxo4`BlPMynWVDx2UcM@) zCa0l9ASoeIcM{&SPa-?d{A{FWWz-dAq)bN{!Q?#guIbWPBB>-nC61MHqId4g=6*r;#+irGzxljfpkm zd5IAvj3{T6uPmo@G?ka~GUd=d5l`einG0p!n*yFlB$Ni7HbKOc9-nzHNJN)( z1c}R~94R4PD%&43khw}8HKMTco>D&6($#OC%ae35i%UmbpeeqRgK?%E=Uw zQ?e|OsU%;OQ}R{gu_h5nN=OJJl1#cHCB!TLKa#mJ+RN0{!+4pxa;g$KizF)p(IU}Vs{lzkQetZTH6y)2X`7{_s8L#Zf9W`oHKxiaE#6fD zmTO5P7i8K-)NjcIz zK&$xcsd4DP8%4=LAb!2)?iH2qLE{RYQ>BJ3urX`!Uz zZ1qef)ZxhGONAlxQl}%_$hGNyFg5Qo<-o$3=Ti_>D zk3Y5b1Uq}Z(v%#aDVba$cB|ey(5s>w4cL*Y>dpJ}O!l_2Z>Fvk-(2{dn9{2Q`5)1u zai3Tjz(}w$($oihdZtpN3TwwbD%DO-75i7&A5uNJyNdOc5>Q{*x7DdH`1MRyW98UX z)>xUZ=~bDwV%=pLi#e6inrzonAJ&j{+X8+)({0TRTBg@OQ)?rli*1w=1&P&QE@;qJ zu)Cj1YnATD@TN&pLEzn&6WOiBSwE6U>ybEi1O zr-e6V=_kLr9Cf4`Ob}vK_B+zM zR#Ie2E!XScY0^N#Tqz+F126~HpA6{%Htdrjuu*H3EwALBDN#qHggl1D9Pzs{K9Poi zl#m!k%8?R4t7&1Tvh|u)%6f#{7QMQg-q3-e{f?V@wNqe_j*h0Srv#utzyBLLn$!kK zLZMAX>PtB@!c3#Fq2v^0x(wHd{4R5kqJPS2(`8yIb(xa)XM~$mZL#wHDYc%wSW6Kx zr|h_rdRE)l5+=+hZYo=-?CVO>%4erZovF%~GTb6lu8fw?uiclCGvNO-nWRy++K5U< z_bBs~>1k3=Z%CeJLUJ(TuQPS#zUwg&ZokPHvNyBg=B4wsBhcgZ`Tl_8YablKhJLRgWp@j0DS>caqOG=3f5?!=BBcYcpGGXs_X85n9z)aG!Og#mEN%~er zQlJt#N>er|ArlmM5cY7((iHrHCX=dDrKFO2%4e1N%Jj5Hu*{z#HMQ6#UYWg-Eitat zJ5mDZ{eNu!BJqmUDk*11GECXOMm(U*FT(?34{G~Xf#BujwA3PP8zp?2nfx+pt+Iv6 zwDSHbwOr;L>QOQe6%FHCKEOQnq{3-LSg#FU^|Lo;&CB3rWsb3Cl zE0e(zqe}@b$ICfowUb?Sdsye@T_ti(Zo><67eNj)Wh8|5qSsU)o| zXFvANv~@d)-KB&?dMQU58(K_~6hSGW>@e^fszApBzoDsUc}j{Zd%!4Pd56-?Q;2mW9h!oRTCSWq;}TQS`Op@vqWH?ApD1H~gVR@WI`SQ>(?F zh3BQ8Qr^USyLatEYbv`?cuI9McdPjG6i6tJX5!CzyTe3}`I*hv7G_< z?uNfWD%8o3yKKtMgc99#o|JF^3>?db4`ze^kRLh*j)Z|z)ZidEIF1<3@$T#ZP)KIs z#8v)mRCpxUH3X*#qhit7V$t{&aGWuV;59m3JKno0>|W{)uZrZuM~Cwf>hhyjUcQ7x zeN15!gZil@m#;kP;H?MmsjfN}z7XS|+vl%?L&lsIkJ|$0B_>kiE7ZU79rVk^;);cj z6V-6M=STh3bZI}DmPT4zBa!Puq3a4GE04W}yTOu3SkU3O9J}(c?FVf=<%}~QTXE>DVgRkjnBnJL~voubsIK}nKnTGm{nu44MyK#FxI|I+*zh~ z@aa2Bssh3^pa=0eyzpO& zO?9V>-HcDmQ}na$sjj!B!kuPofhb9U~p|j2Q4zDATrK$$z*-gzU zYB{3cs<6{;(>@zU+;&{D{I-A-zpbNjq|#&SQ%YzdlPz)KEqs)O!@Ik$5BwGk@-Q%@tVAnqle zn??`gp3il{@PhMy*&KYrz)Im`nD7ybMt!W$Ek;8#lS&5s!R`Qj!YJuF~@06@}kSlOxWE#TU1y zT|pG7P1Gl2`GmtZj!O6ey&tY?6d0+oF6_(f*^@!PFCFWyl2X#K_y#=&QJyCl0!cgy z=dJD{&IS(oHk=Lr>~y$<_o>&zhg5(^^js?2-5CHtp8{gDsT_bb{tG}USpyVc4DwM9 zusxsy?cA7dH*eO<<(^3R76cYLHiQy-9HWczcfrm4Q%~vfLt(RCE_Zg0vF0j355ERa zPK|}bvCx@kjC)I1Mk@UWR*s)YM0 z0xX}RgoO*WSfyo4n9G;);~~WH#07AgFqUrb5dR|ngV?EaB|l@+!7o7rRcMo<-UHk! zXr3t$Ugfw{tu_^vQIXe0CWI4)1s*Teag5&YF}fd1XOPv17pa{c6?3Z|`W5ss@!^4Z zX0(@#GO-2}sOq7g*7B|{Fy5wk2#WZzK7;C2MDI@Src^M%Ce!qN@R15uz{7>_YGf!` zuffyvN4mO>9?C8cjlEOC(i%V=`wM^L&`8%s8bl>~G%qXMpt*~&W}`i0NAxshvEJs; z;q8-&^NH(;`#>(gMSP4bv&Y$K1C8E@nu4dXs!e`RYRLJbNo+&=_Lp|=*A6j~MPLHwwq~UASpvn4V z!RByy!-A^(*jFZH^$UZ=n?KSpab>Iy{O#4{Z;ajd6F(q+N&F4jPzp7nPSl4W0tlmu zEz>2f`WSJj5r$8h(*d1f`pLt4xjBwLva@hbz5KkW@M>{=_V6B0nnHm4_!||!+2Z%7 zH%6XVxTLOTaDGjyaz$CVf8i4SnG;&4HykP-INS}HbS6zVHZ(TS5AdJ(_kJ8sr}g!v zot{`O7xOsB>B&aac(rtMx)0r_8CBdDHCdGnH0IDmqIRIJE3FjK+ztC@a)UKSt#mtS=bI z6@0f^hclK;`lHoIGKtz39*tNVo6#uL=Xmbn(H=6w)YhXwv=_7~>O;NJ@|sp!RldrB zdi6vkwFj$z^1BVxIKA5F<#9KdlIdiSejynQK&pb_$sHF?H@4w5wZj^VYiekRMz-C- zt7h{SbxjcbYKbqLY82MU8dKaoC4;k)$qM(V=C$MFi;BA9&6=@_j?}*P7|mVG5>Wj< zc^#BMJVyOGWAtR$0lAv^20u#id|Mo+8_^*M;(W~3NHvm?#`(hR*=XG2)qGy%o2sH% zT#D1Js+f>=RO?Q- zUhJuY2PSsu4&&j$fq}v6bcf{KmFMc-`E)#yh|`BB;_<}v#`7K8;jGE|_RgI<$6wG4 zGHPY`+Q|Lmi%UkhcJ6lJ{o(MnbW}5_Cu*T!?NY>#G-LMy&AU0B0p7l5&6=@g@B!mH zrW)T_Vt^QiJx{#b`8n7byPx_qf60M=n?b`dI`Obeu>^K zGv-rR^UQXGz!|{fPaK+FD=;6Gk+W2L$~#0C`~!4Rwkz*8wj6?5I4 zp#Wb^#3r&s2crEJ6;-Ya$c~NJkx^R>6YibeRXN1ZqUxD8UCFFfM+~hzy zmkPk+s0~4#f%vdRr6vO|3wAf)kwGNFNeEsG5A&}^e3C^Oyo%(**?K!$QxS?p$>Ow`^Xg&E%>bsdbrbo%6cqS*`QB zQDNQr^cicot!J!pt~;O12)U{ox%b2pPS7i#%NE}+)d#(5<P9|7jUn&TGzS*K9~Q{^#B@c)*Sw;O~VW62DTot zd3wNPUP*3iUqHK@(QZf8meWt~?Xm@;@zC&aC>{;ix_aw|mqw#YhYOdk3;Ba9-w&>I zt_u}Li@9|rcV8zIvTDHo;DNni4o!;SPedj*ate(gT&ua2U>%6pcBw( z=xlT`x&mE;ZbG-Ad(r*qA@nGE68!)@hn`12MX#ba%HS%78w@?60AB1B_9&+et{8HQ z+o*sDsT_ty9$_gAyKI)i2+PA1EU#ho!s?T!JLCZzFN>W%43-!!!TbRdfL9p0f*}mO zA)J8gCV+9c0cY_T#b0U1HWUm-Tk$Ro!tJ;)jAQU004dywA+7i*z7_5f$^azwmB(t7 z@~~MCv_oi6r_j7k48uMwrn*DOlVv?X2`b@(Pk>{AzN`vcrNs>jqoWOZ@RuiqEqq)k z)eRD<6Xs{#V1Cd^!CwgSaUQlE!1+45+qlnNRddu)skA9xw_ss9W}+XR3Z%ZEcoG-% zr-}7c&jQD)!NFCI1y=N}-7%MIrOOqIWwWuuc`7Ir(D7q?ZKBCmL%AF-N63W8VOzvv z510>V@c2EoW{=NpuAOJ@G1;mtb19p%!RyGlSaZbIm_SaQ%<76t`=Smo7aX{X#oD4T zTe;2FVl&VgKA+8O?&tOnEuJ^DSx%|q86z;U!(T#i?*C20Q9rqDU4sxgXe1C>sSSCU$hReb|=t7^5I|a2PFHLhF z)lt8Gg?t6Q0{>nnUm+*_g*yKjBz^`N2(A#VDhzE01jW``pC`^D&Lb{`)uHbZufnRV z2Zhiov@zwd5vp8@Y?z zOMae&cqYd4R9=|^SV{6I2-w0~eHa*)lu=&sA`iwmTnwO92M;d*Y$Bu}&}Nw;yvSN@ z2y{dIKVD}_0kR2&02E>Pn@nlNkPdGU*L$%Z$BPNR5j=iFg?Kv|Y{7uh6i^v9Yc*l2k+!B1w%j}e#+Bbl%u#IyebXN#FG@3|Dh)Xy4HF@ z(RENJXS>60wOOt6=eD-?(brBz61;>T(UddZxOjAQG4;oZ_4FyDix-b_S47?YOP2Jz zqu#C-cXPA5rRyM%^{W=f+T6VH^wT%4Ts|7K7hcp66l5muvXYcN9=B7Z)fE?h1^W`- zeBPVr3ktaxEL}#Aj&eU69knf8c8dNz>T<|)b)*4zbFnIN-P)uIdy7p#mJDtI{Gajl zkB;_lv&VP0*6nkh*&VA|b^P(GS~@%jVBrw7!@mxlkHWJ$nf#4G{2ZFkm%*3DeSk~0 z$I&YORX*{}@9=tfQ?u3Wcg8#TA4j|JbqJ$sjVaG<|` zV32bRt}r_s3IFLEH=e#^!RjW?KqeJps-7_ZP^+9+ODD$GKpR}}9}WqE$f#sk2eFt~PHZDi2O0KN;%?#v z;!niKux=VeIkX%d#?JSCmJ* zR1!o`aXyg65&CfywK`M zWNl=Acy(}aUXZ?hD&prU>A7M#@4!r?U0mYv&S`Wv&T;dfrz@r;Us&EB_4+I(hucpv zHjCeCas_>{BTwD1;ZzRk2q9G1{5ATr1G!T!JJ7ZHYouLIbliZS)-RVkPC3c=hO$=P zVpad0ayK-%J38=ZDu5Szw)4}Eb$eE<*t5Xq3%VS3KP(t9eukp#0iV}yj(LMSc4L9T z&r1GiBmYiX{)pFkgsI7m#!ulgxwZV91-;0>ETDM(+L3j@|J9av6=|Pz2gQq-E_l{&9hj#tbCyQdtcgUfiAG09;cw0OXe9#Y!s6W# z;o)QXiOCdm{A06yBH!LrWoA7(6&*wvXzbux9SR9)eh{1*cmw}61j4l^t5 zf}|<6t;gprEFm@!JBi(}?qod6!62gXZ2`?5w13cbVY0)TSYBHPNC{xuddLyx4lsY1 zq3a5LZGBTy!}@iFKg?~0e{)BpbLK=x3p>`Y!};{{({M={XB*P#hS0?qkvFw$8(Fky zWLwMPY$TFJ=R#f>u8qB|<91TwchW#CBGwRFVXg^Ltjf#}ODMyX^*B+{RHh)NuYq?7 zycy<=Sf=p{WH9a1nJW~&ucF-sU4N3d1v-zfC{p%jUB8i21o{i*Y4p+6Dtemqd_~6I zEE1pIB~tredcGkhzDpJt3&i`&YQK;Mu=`&}90`1T8SF1lr3ZLo8GD4N`kB)x2{aQ~AtGc_?J{k?+DY+E9G`2x+ zokM(uxQ4iHYCTqpFHEUlhN{!#fm7;(Q94$%y=3fn!SOubI~r}r_;aFiL~%FCeip_4 zl7`W3qCdrB&@1iH(Ow?K3MVT2h&w{hf5N05P2x}xu!{GD0KbW`pJ|5E9YsHhc2$=M zkBNmahwJ%A;C|Ww9ug;j)yCJrpYHJ)_7YwlGVqB|b=c&i3>4K;&j(h6eA?dB!9uQF zKi;V8-SAA=A^1%l?}Z;2_w^*0DRz+1T~4)^!u694%!gDS3FfMedQT?C@%%TGnYb50Cbq zE|}TCOh>e8o0KQYjPvVCdu+PJG^loF3hcuLK0H%T_^8YM)s zRafbTXrwZB(RB7NtUOSTHo0h+PYF;gorK;J81~-M$l#*6YewJdQ z4*&Ag92gH>f*hR^B9`dM*C{NovDG)`MoA}ry_}kb)+(WuTCKL?E)ld!;i^n?XO^|r zE@5D>k4Q%DYr7NqvpCRW@tz zx|z34K3P@T_@z*QdO~uesJ$WX#K9R&Reez?_-C zEM_?%h^^n=C}%&6h~@(hOePOJpgCN>Vnux+s4yFzc$Uu#H{Y8~-iw;b*b286UshtZ z=EoJ`b}21}$FGfcwf?{2E)U+d**`|Z+}p+Np261GwNdVa62swAyWt+9A8ZD;!n)lq zkoaFEUPE5+L!OHkp%rL7ItU$(jz)XY=h0c{JaiHGV_X4Na9=|=01|!^eY*?>VhF)P zTx~a81_(g}PuoUVoJUCr_u1M7mm;c>Rlt9VC2%q$Spq+$2YAmNCEqc*#cv6qeJ0kv zD%AWhv-2JMsHpNN!R^W^n)Q+yHFjNBq3P}H8}k+}R3hb=-oE$#GvI}F=u#WreqtV2 zKpn~NN#otso4~hBuz_kr^Uwyg9eob4>@svUx{>#WcnCZpo&zt4H_$uiJ@gl_g));N zu;r~I8_6zmkX#7%yx_ma7{+5TwBap>b%K61oA$c8Y92r;Z==g=jJ!Q9Hqr@A#YPun znNWtIjjp0h$<9~sVO6S?cr6U9vOukzU8`K|NCs`n2y-#f$`*g)o)MJIP+stLoBTde zIsNpka{u>?q!?3m+`uaLMm<#i$!uERmVh?dS>slk-nwgwze|j7-6t!JZ;vs!Nqo3y zj_D?^QsMLLTi*6K7`vTm!j_mFcE$m}coSQ}_}1X!e~10;r8=_VikX_*qO(-OV&XQz zU{>nXV!yZo4$;om5pWsW+3MUTcC6UZ6E`YlLULBjYx!<0v89DP^q#?m9iU*(qM5D6 z&UO$y?pE@)PiI4P-zQ*&>s0biCCB@9Ru$;?>azSd`8SF7^j zpepm%(Avu0ttS*7)w79RsAm%!&%?i3U8B{df#3VB*f%;KaNGUAv7NYb!>NT2OGHGe zU91YyV~QuszoKvet_RwtXBdm(3e!}3J>7!*#{qm@8aLiF#31}MXli8 zOC%13T<&jWO z#qWs^h`$p5COFvd2%svIKpE5w5HSL%z7f_#cB12925~;R1YHR})n7+;)XYBJ$^C)zl(PigHMDYf`o9hbcvq4_kjR}dpx*0@DQ7W51?_bOZg0+&cix6JPMK(m#M8tu{uIqvV7xU)`BUF=Q2Jo zBY2ME_l5$vmK6U+;l1!F5(6j(#Y08#Jv;&73B`5(^+BO}!Y5)wS++ad2|noXx*UEe z1s)>Z*-$rIj6MXdgiF|u2Yf?WaOLO@Wx>UU1yKhcB05`L<7W>vH4WfD+SQdz&B@Z? z>iW42acjdNYmPsD%^?kqM=T9=<`c=zV1{Na%_n^BNOa;HSD-aYcR^-Xs>Zc)(F1Fo z7Q4e5PIY%B<9Yi=YSq2loe)nX!lLW=oCd78X$y6u8mmvvG5CnM^*P$>hjm z{Z{WL+T^Akw^=MMS0v(TvD>+r)9s$;a=8z{)pK~Pzk*sgN!JjB>EQmy9Q34P40WH| z>8^vnTTNl-_f2*?<=klXd+1?YEH0iq!0z=HR(l+dlUy$6`3z+rjc$%aHb+NadyU)Z z^EurXhPK+@_c)-=@GkBQ6FLIa_rga^#Fr(lUaOr%M|d1o?%WW0tkv(jz~wS8w)&m( zt$r(aL}#F@%ilTA=Ocfd?VDc{>qgJOk0Cz0aBp3#FWb=_dnUDcb1JiOW8u*#xZ?ZG z0l%4U;lBcqp|K~rq-mfJ_@Hm%<77uis--$!RXg0ZpmF)xw_dz^_rp1fu0Pdgb~&#P*MSRv z5{=i_6}|%vOy}|$_$&CX53;9_mcLOo-2a$9Ldb2h)n4rMJQW`38`+Y2Di*tT4tiyi z#WdnR_%yfu$k35}6xqr;>**x72Q`O6m!%_7a!>HN>Q3%oG`hZqv;--$&#}sGqusRU z-&^hGMc#BDOLnj?pJuAQ&HPR)*)V?x&FrHldWv;GyVg|27uS$i?W3$m+IljKEonKd z9j43Nssoyu4)``Vf#~dE{hhhUPhGCls-hl~^TQ;1E#VC(BZaFLhC@RE)Venmt>yL& z1pGaAGTz6APO`XeW1`NJY3{-$wYBSgXy-xhs_MccIY*?;y=PuHJYqk%*HJy-Sw6=e z$=R6gnf?s?-`6*B%Jwx(;qJaZK7;J2?bu#*<9X+G(MJV?u8`9i8tdi1T)|+e9lv;% zj&O#K@hTmjO_lnffO8s5DTKe`wW1p$e+J7G4oIP|Sh{Q(m)W;(U*Y3rOP4aW({U@A zf5Z_-pzqvu*PUn;q;#D~)MuAe70(dD=LQ+K99me`Yeb{~)*}qOMDR&KI)GpJ7H;r+ zy6zya13|{G23pYn)O7?o3LY(m4d%l;@4Qpj>toyp6rt|GWcin#x5rj^Q0wDSMfCDf z#uo9XDwU@Y)@zK<`4DM@zlA6`M(1^uqtu`E95lYK;v9Nh&m-diLTF5$v(>Ua@4=FH%mVtz_khsfAG+ zKTCmbFqv&WrXc>u^Vh2-2KbLlO!iN;>HW{eC-9?xE^A-Uvt1#9ar+{mjBG*w3yJ$A z%lS*;26PMDT3{hXpI~eoFP;^bC*~4^Fdo-{XU&0=Qxj8%|0}U^FA@#>xmB^~i`kf# zM%;%9@T212YqAac6B6bACRv}q3b*lO#?R=o8&9USciwr|7oqvG?fB&qr6im2zp5yO zv0WWMU8Ik2ik`@Ehd?~ZW5ENZT+AJ4D{ikyDa?B+`|cu5U^@*ah4M8?Qz$-8&fRcGVmw$z}FO}qePu* z?NB_)6QAL^7IuR0KG5Z0LG^X8n0^UPEcp%bK0c2JfmRJsZM#rET7Z_I)#w1U86Av{ zK*yl6Uh^1z6!C0<&U`2pzE^=WENtfR!BJY_+`>HG!@&!Pc`(~l zhCwOj@gcDB;v>IJ(+zyV2Rex%!$>D3L1sg~qSdE5s0kD#6e;ev3u|&>Kv^+Yj9~&* z76QBo%XlS$ON8jL#b_l$$SWxvBEN>k$47xkB>WE@d{D)geE@jy6yD&|h39f6rM0IV zUIZe@o+R2?f}Q6V*3Gl~ZC)GyXP>uD2q&_lt7`@PkxSJfM2gwm2l%d%2TS6GD6BWf zi;-Xz!9h+l!>W_h?}VUF=F{YOAVSF3Vki*RJ<8}GFAFA_WIMlGv6PSb5$DqzHgEp> z=FOx0zD81r=CO$XQ7Y6G!C$cq=N@9-`~!TCRc5Lw1StIVqTT*sx`#rr3qO3pQ_F0Dpx|itUO*RWbM5IP`|*xoZq;kK~xG>KGg6v^3IPH0tg~@YUFYqdcm@ z3I4O>hI5pmH2%(;RsIXM7LLI&G;EM~$j^27FM}P2AsjOUZ#`hWrPSWCo#-NZc#ZBL z9;F}VPwfiAE<*#vE$o54;}NtH?3A`bw5B6ruVFXrHk<_Zm#1S3%yO6x%+1S4Wt>(e zXka**W(-ylAOI)$1@~@13fMXLRD-RGb@gDVBv@+k<%P}4*hMo8ka}84fYb|)JC6JLamO`HB|>V05@e=oGKqd7V#Alf)?053@>a`Mndg#mgbC#!tXw|8-;njU@%~;ub>G)2)C( zy8(Yr2kY-k!SWl&j=LNDUml0Z(Laayr+>mbog_)xNiP{8Ys=sh%%@=SgVn}5Rbdo> z7~Yf1fGR&raZEw05wsgVQhmS=JCZn(XetTE1PBwnJ_OrzJal5km!D|hFrZLX(24}5 zh{eVs{A3WT$2`(XPk|zaA6AqMc01x*g(F0G(40-HM^Qf#ZBfME;<_CaRh&)q!0clXT`tuuJnQm^V!D`{jn0IXJ)*(a8(nk6Jfi*86v@o zy@V6?=Aymg9A!ArJ;hj|+Pe#97K^$EEE1vUnFajZjC%q8g^GVTjb6r|@K2d}95!E> zwSb>$|3$oFk5>o}1RUQ>Ttz$pQFng8Te5tNe5fA$c=%Jz&=(+j^~GSN@&s6^JP(np ze~1292CD(&jBF2;XpOOOsNCFiKwL2dEUYUnqZOijJeBZfMObH3ozWjeH;3nxL)P;;-wf#*%Q5pH~l8W-y3%h^0ApWtM{Kn3z*=j=V)g-Ng#8$U>r+`_Ob9 zBG;BP8Z74^$yg|tJVypLg)OyPd_MSi|NUygkm;Ec<0Z}NRjHZM=KXG@ z#N1Ofav5tEjbF&4j&5o?`a$jk6np~AU>MQ(1+N{cV^%i7s?iA$C+pk5h2Nb-dY9U| z;Kd(t3WNI?Z>E6NB$iO78UzwYu=)eVA2@-{4`8!EekK&ctHgMAV`BNcpd8grd`aS* z3Ewe8OPXsMD1RW6@%yRz`Wn_}cDv0!wz{G4yO!u2N750C!N;6v%P0hW56_<;w#O}_ zg`LVf<>%>_relV)ENhK3*(@8gW-~S3`WQvU>b*7Sjc7wx?V>!xoi+ZE z5r2)-jUH9pmywRom|jfYx>zod5hV#Iq`oBx;iD^hM5 zRtyRAWBw2kA#j9>y>#Qsey^lY*`&~?Np`ewpsrcbujJlU_WAg7~+4bS9 zaN?obD7@p0E+0-E#>PI;M(f>PjzQISWdmS)hv%ga0*C$yPEzuhj~@k6XHu+Vc-=%L zg!B-x#5S!0<}H1^_bm5l(M2?jS^-oHiH zSn{b^1oPWH@c%`8sJ}0MTFMizN(h`!>J@r zG#*DdKJ??D^L`8w)&{_z?ih5!Oh=QaBAHOx90%(cf1|G?>C2K{a zr?NWZ*o2eIBGE#wTrBG{W3EIJ2{W*eJ#H>9iEb=0x_wrE92$zFZ>mjme_U>usRhxf zIW7o9m?V}FSLc_v?=_ZNg$uBDE)N3br0{=Lio0^G?ilIn;-i0#{Z4n78VR+x#Q59S z8A>%WtbVJaLWPSxLcSb3UEXDr}ujs^?WS^3x^u z(6ce1)wa}pV1r3#!LvDpN>pd_f|Eqe8DfHN1O3~22Hl>lhSB#X7h|)nSfy?xUHY^yZ z?dHYt{3P)%qF{%x7aanY9e2W+;E%$2;ANxlSE5Z;CWmKrWW!Ka+3(NB&@Qq4=dIK$ z7~7S|;L6%wxjdh$55lzMy9Na+MTlD^4~HpFLPbA_7me`&Vj3$dq6RTdl`GQ)&Z)@7 zVp=M}bP#2$BDDRuc`BeXZc>E3H&)zH6OT9ovf+8SjCrrBajr65f?2L{8UYMa$H^Dx z08isJOVk8WH4cZ!qW20XYJWPqMP+iBUujh7?EGwbQY64}_a|F%uLMmin44Fm{or!c zGn&~%vLtlfL&RQ>8qsAiTOR4p0r=qgc znc^-NKgTL5(s=dlobsMY#@NLTMH{q4ZoLo@6lLQ9#5(RZ-lH zy3jTC1qtp-T&}2=sj4{sws;c4_Y9RNw5_y?Qc>K|rB6xoBPJ(%VG)G-yaZ97dI(~_ zy~m?j4sDU}Y#bs0**+aat4yz`^e$nCxH7cE_VGoJu?lbxkWn?I)2=r1Wx?uwWf+a? zh|8!9(Rf6k6u&FGt3urCl5r2~YO{uW8U;t83Tdt>XKl~&UUxrMf|42u#~&A*@uK>O zXt+@Gyx_8TehE@36fY`^J^8Miu0}U4IJ~WlpWw8xaGy#`!Ye!C%I67&Ao)dn{>86L z!AF8xs*m?dT&|0fM(aU)`ExQ@LqMD$;ibl!-(8A|s};ZNOY2z?NLDKxB}@GzaYTt@ z!7KY5;!AMC#uLPE!87tBh%?`W<`<*PV-JIK(HGH|;bi*n;nOwHkI_pIP3`CCSCiSQ zV#5Q4pX8(%Bppa!9*3rSE{Eu2$%3yC#Nom|mS8I@`B)k$YP?XK?Bv5&Hcsa2slU3#{h4|5BYiWMXhlbN$o`-Mbid#a+D{J% z{-BqJ>so_D?KIs!6l|>v54zjzgM;=qcVWBIKQt}n5326}e?@;$b-7dZ7aiQ@ZKvl@ z*kP2KL$`ak{X*k0s<~xQ-)Hn>9GtRG=`%VC8Gg0TsL$jF3)B$N3~`3n5+}mG*`?s4 zbuaNMti!K@_`(I{pjTiH{T5jFzYCsOe}qWGAESSuPs-?@c);-r zn9^rdgFL0cQz3xja;E8TS^-#owg-Ha&hNG0jQ%_PRDBnZcV2uk{o=(CW4?384*JC% zI_>a%l^{fhyJquV}hmsvpG z4(=3FV-bhj0fi4BP9d&<)6H)HJ@z5u1>%3f$LdhfT)zf;D372YqE{ip`@8%(BL6_+ zBqCYTMFz+!GDXfI`|(L485P04Xw+XDwd5>DKJO>XbP-C&w0i96Pk2}Hb3zS4yJ?IRmopBY9c6RX2xQgPz zfmcH>Em#Z7BD3$M%SVU;A6uCBi<-3X&HLSUph>Qa&-_<;<=&t#Ey}CkFU+Rzt{Syv zG$$i{ws0sxQ3-#Gsl|^I^B2;iqc+MMwHJMQxfSZ)I!};xxk&Y^X7!*FXT4yWE%rYeixnDMD4Q6u5Btl1&;aH!GL;;6U#?X4ctA^HPD#z=ud||g5EC8Id)ckf-@>P)j_N$HW8(DK*zVZ|FGRzi!0n+M^yp&3iS%^~)v5Lq;$)m{KWI3BWz-1%< zU=7+%bM}B2m1pc*TwIe8mSpg{OcMejqVTOP2EeLBY)x}mV;fw>NLdJQW7SIm#{FsbeD4!KE^)K zA+kYnWrzQP9iB71Pa(f32QLYN(IbVI(}XJ^-uXQIdVVbkzZ$Rp@IQ3c$H%pv%6Cpj z2tA?W&nyS@QXW8Zx?=M3g)_q5h{bC6IV?_w@>8_i;bYRf~$ zZz)+RQr6R3bjJR-#?4s~By5Y{7hr96zr$o_{BFO6t@2jym6wp-_0W|06UuD${54~? z*@{uabRSZ#D7~n0WqzDrHc}mma=)X=*GN-Mz9xsyQtik(;QwmNyNa|=x&z{)LjhAd zKt(KS3XZQpRFyH0QpU%hwl z>f%u#xn#04P)Ay)(=$9F{d+-~bbq$gF`iQ;JP9Bszam4Jg*aGVqdqX5zzdCKV zB;n8@?}|$j$C_)+RrT3uq@LOmb@t2~a8X}bvNdN*R6$;2C#pW+$TkyOf8dg1j#+YG zgSBl({qk%k8m;$;$90UqEuE-AZ<0>Z;GTT{{VlOAen0-;&+ph0f%7}e*}hmEoVhV& zSM|C)@2h^!Ef?+CbI~p52nTAwAu7q3ua%u#c=Asd~4+{U*1J>j+o zT5Rd6XnkV@&Z0 zenHmO7>;JMg`wh0ng56m@?%!hy!h=DKp@lpN4^z~aMBKpx+XueUlF9>X2w4*;{v1HQ zc42_yAuWt_3MHu>tCD-i+xPCJU*0=zuYrtVOZ>hG|duf_=l8gztT#i(e znRd}_p0LSoig@PK*7!VqgZYFn8Y{KoHr)$**`M6bygBB91akx4Yu>{=H8w8=DP~i) zBUhKs=f*FCDlp7}{r$aPIEnj!VS+3T}{bImF==~F4#-GobX2?$yk{Cz!q+Hrc9A&%GAc#JbrU^?_66CE}u_Rm)P_$P=ofnzie!HLAiT!$w+@CP<8nD3-`%UR$! zHK&2LO{K8mNzNmFQNVmTf46TC=64;zkPkfVH61?oH{POyw%{KB4sWLM*u*Zfskgqq zr>DNY_lxN`)8K4vt8Q;`HZbut*+O^3Uy66oEu^L=mSR(dv4fd6Ke-bdARLE#fqtug zaG;@KV6bpyJcHIxJd$ljZ*$4!EH%R2m5DQMbX>fpCC**$E{$n{N9H9P*JAa-Guk8$X#9A~RaHU?{fw5K?8=upQCNLj&5EXD)cC|DP4mP&zvbfUzEw0Ew zy0xk;rhDtKMX5D~UgXPj}b|@dma-oa@WV^c7D; z!D%(a<~nkKnb3VeUZ69?xy2mL>l6lOs0jUqAyw!dywk@9J$@H*XYnMQSB3EGR=AGA z6Wn|JA-&G=>Ui~2AK<=uUdJ8(4d|LJ;+VM9er#9f7;@8w?3Jr7jG)UhbL`hQZp>Cy zXSlZp>omP`uGR;CEChYhp>>}h;fKuci$jL%Z?_G6={fGLnv@0AuD$u!^}jkIaIBAI z8qRShQ!W2*`RM41<7($NQ~|bFRkAHZG(wNy^UfDQ^!H=S^hk*>JnjOuFFW=>$Kov& zP~iT~$- z=IZ6k)>bXLWYy7&kA8afcY?!*R4+vCrV%(t+7WKl(0E_b8+@!D2-{Hf@n)U^f9)sh^Di@kd7W&TX(yZz7oX8UFV_5JE)FvBeOo_o%@=brth5?O7J&lH}X z?V{hrI|Me#)cY*t&aur>`lK?Ln((#^ujkOpm2h$u6k;xG}U z5c!d#-K;_ol*ij^u0IGq%E)^mq@Y~fkkh&^}roSQk;B^<3%e;Hd71=I@7hp#<`|UYAryEg#_|Jwyy*l@w1-d~_F9BG$j>7_CMI4%MFa-AEAad2 z?r!2hC-QBuD^mXLXCPv_U45}>W4x~n2~SaJ(o?VR;#0GfLVRiK0TdLR=@TC2b8@UK zrzko*OtgE&BdyMKBz5aChEg=_$>dv>*X`W{A%;OEC|)Nqj%P<5&Z(whlb)BNVG)PFqLlX+>Qu(mutTcd|GexX}7A`O0QWnId0^F-M!UFvWQ4JiE zTSFwMNC4#2Du`fpMNhG{rjq`V(DG$#q2#;9_SH-3(Zu@7%8Cio@kyWo-Fs$S;PXJp z=L3O|Hkuv=O5bTCDc%j#L#NWiQz{8T$qz0EVxpr!^w7)|DdFi()coC2%lO+vMAfra zC@v&a?6~b3O9}e%>Su$-J@d@Cpl7*M{RPO~X{9Ri00QEQwW;BMW#?YHG>E0NkmCGsa61)v1SJ&fMx{O_Trl~=j zHnU;&rf$T4R;|_;=Qd3VkACqEU-veAw??DR2oF~-Hg6+`{)REU1h7*|;jXD^(50al zvUNw^JC1_Sq}Rc#EFo<7c!97a7$nMtX(w4Eqz$L6#$k#TnCT*7DFIeA=}+goJKv`^uW@Nv1*=KkL3h{78Q}y!ey_(e#+>552KMJ7e0;i!6DvlLh$Uu%HRGJ3ert z!3j&9%WogShWO4>Y$BvVW?j!Q?F#%XNIMgD`PzrB9*$4@WS5y9gbK&;@BG*c!0$4< z^C+B0Fi$)brQoBO%xeTG*3RpOjK4mRVkdd8j!p-{`Jm0YwjhBbu5Nf5UrvGN|_EW{gwG?iL?Tuvik;1A{wGXdOw9om1IiPV8ddd zl^fvD5&^-&kq?T3hPVE#&jPNA03RYK=Y){1b(2)$ix@E3r^Q6#eaqUXlUcvSO5&HG zFM`?_Li`d8Q~Ox^s!bbLw?AfiM2|H#qRxF^?V}=?|JnDI|1*tu6(uJtlMRytVnThq zeJji8BIHR2(3C8h3e)(j=}=WF9T_4N=qL}hTRfupJ`r@VIxSD+5yX!O_9;$@_Y2PV z&^j>yaY4LeZ~TsTc1F;B$PoR@FVT24ew{o*$Aky&zaPJjeDF`Z@lVnBQ=iB10~Em_ ziku`-0*)30hw;Pw`E-@oTOdmk$prpMAp%VjrPd0hK_PH^y~xvB9)iyDBfU^svX?~e z8^Ck$p({aNCV?eD?jfpxQ;^) zy8+VmKvfY$7=^G?Nqc=E^ebk6Oo}PXGQa~w&YFIM%msmK{sAFNx+Q?rPB-X)Q(zGI zx*o)YEAg7dvc^&;23g9o$x3589nRFkeJNA$L--+TF8&e!NLT?$S|s7AYD5X$`0kXO zh;ru(1fI0OollEADM7TzEllp^?V&($Su=9?@TYyejrEe_1bv07kClG{u@BAy$v$d9_F3ly#n28e;S1oh-pqtbcG7!1dv83(!o_H zBZ(8(%Wxj*Sn{PCR3eqZ(Oef1^PlW`GlgN>`y&-C6v>nz5x7E%-2)IH}~MPN!MM191WpjZT*nzG3~I1~wLAb)v!={1vn- zX39jJlN6zJunv5i{0ubTiK|-7Z&$**0Z0voPB)H54=ioy`BFjS^d zr=WjteNilXn3;7gD?se!^Ot9Wg{9JP_tdD+SYK!o)-YySpr>c3?{p7YLvpY<6!EV} z1hw9wa%F^v4?l$OFGiI=%Dlzm#Pz}6A=HY4GemBlZb~;>fvM~+W7*|&DZgcK`+4P zp-25W-kZGh&`0@W-lx1T!6*Mc?`OCP={nq)M#G(Hp0F2Wkh2nu!r?9wEmR66Asxul zG0@Mx5S5}zxJPZuC|pgLaK!t3M`Z6C`=xBW4K_J(8N#s_1)Qsj(yB}xFJsS3@GY88 zO`=j7*nK4U$IicueW=wEAt`Q2Bq=pJYoOYWFf8I>{E!R1cXYcGJFOiyxkBN@*@)6Sp z-|LUetbIaE3D8r5MHNM2xF;_7g|*e)5=tDQ&k3M5y9qUa_ejrWRgtX0tOnW)&N0_5x18~r?BW1u6>RI zastuB=ScPl@jAi-F)EZYP!-5aDvwY zf<1@Kb>*Uzn*F{%Mxrn7Mk#0B$7^EuR}2;6N&~uDxx>G_$U6!(AHRUm^E>etX;KM( z6wF^ooi7C}LV3;4i926QHK+Tl;#CyBTe1lLD-;2-J`viLhMT){iVG5bA zG)%1X5=4o{CYIsnv?_0nf6!EkLZZNz{5(YNf_Pt1pj3%ERp}CCa#WPqTcwB%O7wPD zc*oOX0YBc~+no;bcMA^^dPoHoW1N`J-mQ9vJqs>$;b46$B2^y|Jh|v%OlC@W63tYL zBktNA>P2l6hsXw(E4||QG@Z;Bi23Pm{(f44CM+zdfc8Vmu~D&+w0{)-LLMUjADNfX zM^x-37DT%RGTYG{Ul0FSb*fq|pmce`rE*~+4FeNGiDuHHtWipzl3aepWL`l&+wznW#e_-Op%TRRQ0_J?m%8ghL;Sp> z9*qo$^wL&n)iJ&i<;8j7xUSqYG$zPfDvr^l3B43m_VoFwdq^BXE(urX$j^aUkR-M3g8JnW}9^hM{ALfe{$QuGrzEW?u zIFElsR=M#flx$E-QBXk0`~zr)K2TN}E%)aWbZtBpTH&C@Gy!ewa~8;p0@%m{_DwX?6sB5;~5QVr9TS~nG8PzFcMgCZ$jcYf3MKF`KZhU+?vI(4%6%( znHPhfu)>%s@iGJcK*<6YG6(;RmPaCsxe!~N%9{x%Hu$uW1Z_k2j>0V_Is+L^UhR?C z1&GHUg1{5(XDxm{OI|ne_i55hvd!Yn2Gt*2bwoCR&qf5-D#O|91EC6F4-iRO@Z}M~ z1%@@e4w>2Hbz;m%fep^S#l8SQt}YGQ8exD?k0(Fm$-|f-90?~ z)gr+hw*UbWxFc^ruOK(t3xchDA0h2V3-g5Tki{qzQxPKMuJNEfXt7$LQt3tRegcUf zElZL3#UeNFV6Pl%0|KQ2Wr&3Fe9D~?`_OJ;8io*gfmto^^T~39at{G5a?9j<2;5_( zZ;QI+-t-EEkGluoTPYMF$~Q(Fz?X>v1foC@U&=@R{D>%lhXB&Re7rJf-f4FK`DRpU~Y$C<=8Gi9Eao9(2%HH$OM`6n`WT zi6dzb!QrGyrDc3K3Jq1o@g+_>nH%zGu;0uBj=_%{h;x_@40m&cgP+N-lXeP{Vg!_r zM92q4%0D2La?5p-s0F3M3>iQr_oPz*d2S-mQ+z~nN+1xqc?mtdD6xBxp$af4@{8fS z=eR54+=T8j&p;1W-25Q_Ma=H|&4P_&0iBnU?o%@@Xt70}2|EzfM{<5$J*(H@?n z_{1O|y^q-61JQv=aHFc67Rtn-;A^3SDJ1d|fQ`fVR0!N7v?AZx0EIkWC=y7ckeKq| zyU9?npC{tG`vTfMgrSt59K1)_`arF_H*zaapn$&<_!|siK|z!+KQ%N}4EBMion95g z<~-(uCwMx@oOy6(&@IGrMwT}0$pRaN7zS(*93F|@WQi*f_Xb1=6tIKj5GMtr5CnxD zq>BL_wFZSjYkJhe*3`q_;9-WaxSU)rPr~COtq69e%eZK+eZ3dAcslC)j`xU%^R!?A zwm_BFDzMGB!_5Sbfluu`?{nTa;6V#QQQ$4hMdQ$H)CD&`-U+w%o`Cw~H_$uKQRg4% zi&3~irB}*DdL>aE$ms)mmz{r@xQ9V~poJimHBn&KX-PVr!6ZJ3{y_vS{Dz-UNNtso zbXG@?v3Y2bQmT+D^$N?O1tq{LWu#mxBO^dXl7=uDP1I=tu$4iU4pt(0NkCqbNz-)f z2iU*BJ_I1xzghj;-2{~R((Rc7=cgAdbeQ>=I=t=9{4=rZ4(@1{%{0vu%*dxN1Jkvdd%$_JOeuzJw)SPbxAOVThtufY!>78O@f+>|ali8EG(Niza! zqs36E=;^g7#xue*+RH0OtQ1FkhDUg=$_Vxg;?urY%Jte%c&mI zTN%L&FG9o@327lM@DsQTAYmvrT_+6A@bjhNV+=)x*HdCIv1LlixHJOl1w`%=TIR^x{jR3krxO?oCUnF}e6l0)udgP-=XCEb0&iQv4|DtpHi19A$b{tCeng zsoEAnEzhNnYTP8bbJTIz|oWBx_eTSdr; zF7- z5)<@E5SdDnE#^WN+J{+5*a9{+$Qpl{N~?nNlZ4oybTn0AimRF4<0fgsrH*!=(>VNX z_gT*Pf7bW7a5}ERg*>{R$y$=F_JKKmA;|>z-YyvD&jx&#fFtf{O>nS={FEoVyKi=P zPZkSx>vh5$%ggwncgu<6$4`7RYi2$2#RjNI zKa0np3HStt%mp&$@9zr5Fs2aV6aG9N0_zlPGN&QMnn^R`0*5Z!4T?f{J$>{E6y!84 zkD~Vd{;ps-jUl@o$`POnJIw%QrbcHTpRe2E7WF_e;_pBen(9Uvc{`=}~>Q^8#OVXiAMR|M#MJTeKWUV2t* zfYv8Od9Y4IVvP`^C1?`x+Us}k>D;*d^^X=Ve0g~8KjHdO(ojcb;syEaIpYI4a1n{_z0vg!I?y9Sp@-K252KH7HEtn z`1$AY$-~uMYtFu2(2x_3zQ!AUE8^DH&b-XdID{U?7j#2qM-K%=qlbGw6&IG{?@h#^ zsRo$mEbxt-7s87s7$XRa(o2-73VD<&g4VI()ie!pj*!#?5;Wkyd*9~!YsaCJMS9%? z{G;40Z{Ka3P3RiJ8xEBi#wO_|A4QLCKHS%K6w-#4`r>mfyYP2p-oXddv4vB{1c^1bP$r)sPux zqIrbL$3xt7B=8~fhoUAzXp{D=fEqD25(3NkaC-Ia_`SU=ri@?MQ!#nVF~lQN1rFin zp`qb5fro?F96W>umKEn**;!q)tTQ(=J-cH?)r2c#9SAR6IBkp$ADx%uk>3FsfUplY z0z9vq@kuz)Ot}b|%6eK^$wr`IPdP(6ALE(|eL_9*mU)zHT(#ry(EU>?-!!cnpL}}a z)PuztdDMF5e|-kzD0}XXRqG#E+{%2*LUGUAv#XA(V+jBA$yqIW$J~R7_|gCZo-%?b zWq;G0=jOcu2dD{4w4R6^ImjK+JIrf%KAz9KMrEMgXg8J7j48Ym{!s{{cKC;x>zOrw z|NG>uteOu#sLA@_b9)tq)0X)~5OR@zzaf&SK`rBvF`wze32qRO!svv{z z`ea*@-uS9LnAC~o7+>3h|4!&MiE{Z^Jy#L#^f7%0QPfI^un2D<_6SJHT zm;=#Zc?rlVQL3c62rfvtV#Tu0@KqFXp|{_-+yV=I6+gFnKAP?b6ITAuqHeltLD%)S z?V*9@l10n{dpyZaQr$8=QF!I-KZtEwIgASnbDX(Kx#2aiYwkh=OrQlCM<|SqbXSkD z1AoN)WDkY?{4!oBmzM^ANAu6)~?_wxqJ!gfQZFCbf(jRa$u6h zQi&b*QXTo)UZXuQQ$<1)d{EFpus?y$>hcM+uy`gL@_iLU#h49fnNWy;Xy;!Ga*!)uyUK@jv&F zE@|t2`@PP2tsUpz>S{9%T41Ap8dI`mYe_cz-cp+FC|7a7djqQn`!D>zr7KnqT>ra0 z9nqyd)7#sp@42&~qhq?A9^ngGDXY;~U}KLNa?n^_fRo2`R69V)$J?uie?@i1m#qLE zf4i}`Q&;Q++DrH={J68+r8e%z&xAzT!9#c~-42HmkpjY)Le`UFQUtk>jfTc6Cyp#B zkV=nyG$JNTH@n0nJ~{jNP67J$;;6{nJ%b<<{^Rlh;l)@x_*GEi4-(p>=G%kLDnfRo zPr3j6o?#?BFmdiFX4s0?yR#E!_VmBth*!|iTJT=FD=B-&!6M@a_9UnFOjQPAQl7%& z?qO0{;HaZnEH?{F0jm-ZFR#tde^OaqBMB!LS6C9N&V{wW9D}6 z9}_UEPhVv;THtqto0+htFe7Df>|kD!G&WgR+_q?Jy1pZ6adE6PIyJtS@v>iu9sES^ z<-iYm0pNC|lbE@Nzu$_#rye)HJrXQO84v18pVPLso6}LgfCnTHjAlPD)<={tJbVD} zAHHyYloOZPhR>jKDua3Dz4xeWXAtaQAUYy<-5_^$kV2Vmkhvxf*5DU6;OF<9)Cs9E zN13rBtzT!{0aEsdI}^N~q@*{1f%LxM!T^OuB&h%lSK0&%*sm;1a2UEi2_OG>@eywy z$ymL<_tKg*9^M}LX=#i1D}_F~*f`_vQDCGp6We!w_}F6r>o?lvga17CF!Mua-q44~ zAGra{j=F-%6G36VE_meAI&j~`k9Q(1{`Rid-`s(}XD*Bcmaz#n;RDbm_y~Rh<>7kc zU8C?Vk+WRfA*o76z!(8h9{7{Z6#mDK4=*wmBh9a4zQIROH5H5-z$SCB(j51_qdv_# zwumdkH2}<;xD1_Q4xp#-1gc@=t-OY*@2#N@^*T*YWX@KwRsRh>#01Ef;Rzt^A1<7A zxAS<7EODTL0n`gfLEdO;(Q#Z|i!QSAX7@snH|;U0J!!?K(sS-uL*z}gs%?F00du$( zYtY47TpfW=w4elj97=BiGxle*uo;fW z2^J*r_Y?Uks{9-;{q!@u?2FIQ`cFSYYrp7u5kGwHEPmwdi)iw>vuM&;+!j+i{qDN5 zmmB)$Ex+ej&&rScsS?{a)_qP!ARi=Od<7pr`w|elqd(^09e+8W-mgD)&%Yjg4$dAf zym63!3I3%UK{>opvGMeWC~$ahO<}`@8$yfrznhEK zq1kvp-SO=Td>)umU z;`4%k-zvJqH$pWiu^)@csz5Xfl@S`XRH9KUBNTi{P?Bh(ln}0zN(BDO2!mP#?pN4^ za-<|>novXzzb!J9eUynVZCw7*7x;6$4F7~rpem@OS&R4=5VdhdJFa^jU&Rl8hu=eg zc>^wVp8g$5`570X82mLlgg-hQQW^5pTomDN|x@8EJ4fWO~4ze1||=^Tb$O9Q>Yj40?#Gw z2k*E8cjZ)OqEFd%U-~^>6fBqpJBLIIz`IOrb(&w>O08J=c!$%dAeQ z0@m~NH=+L87(vaoV^>WcC+uPJFbR0vvHeUQFU#l_9|`MS(wa0>i%-cqQ=HYIbnoe7 zZ?4&WI{5AVhtFE)Lzk`Yqpz*rA|eC0^Mc&A&S~E3cHSb9Wj6YAtAl9zG;k1o_5M!l zO#C9QL+Jcf;1}*3zQmHV&SLhP0l$mPJ|D{z{CbnaNBOtj{%zppS%B)TQ&4Bj?wt=z z-WiIM!jWn%y-(YkRy%ZR44|Lqrp^jrLF6gIe*PVJgHr6n(|) zfN>fNY-;Q3Z8B6r&~5X!SjXnO-2)DmH7h^a2M(4laIlm#7rc&Yt@9u`_){+S_uBj^ zj<9oa0Z?7=+IVbM2^$~c zz(y1#!Ob>`kx^#_w=&AlQa=g4%lt1RaHUv1WV11!!S z28o^QAOeF}@3hrsx6bNqHrRK8mENT*vQ9-en9Oth6EVlZ8DKwt5V2>iYjn28M_DEq z;C=Zv1KhIG(#`fOwKuoTizU`IEY=%3bI<-U z{>@8uRaPL-S7y~TKT#T+lxDMoVlFdS z@N|@?5w>x+n#+G9rB9bPAB-I6qgO+bl+o#8lcFiPnj(*_(up<3fgl4OeCh(1s~r z*690i=Z6=q-#M#D_n~gTIZu|Y^%iUiD^JZK_n>gn~ zQV{-q{|~G074hll0p^z__^(TrpyVaCX-pLEi;4<4O8FRfpnbR*T-$e{d9LOKv17rE z{k&-g0E6RVwysW~eX;xH<-I~aKd=#(4Y(bveq7Rfc)M7<`;a3H8IYCCF&;sVDtM#cBfZ)^-JtL;@QN}8ke2%n!*^`#YP>I}}MJMQSjJxkZ8 z4CD>v#s$Rc)5kW?U#@RUS(dL2iq483+YL%yhZFtcpen_NN0ay22C+Gi&IOp%=USpC zr2m5D@Zx^PigEtG>L%VXIDbXYec2)P?@cUQ)W1kGyJ2%m(A4h4Lgt9+&F+IP-n6a_ zeYLVMCuMowy8J}{n5Kuj$7bpmqz#nB$fI@f`OTxeM|ehLM<*#S2rR8wl0jg{Ilin@ zj1U6O!Bpr!XntZk5H+R;>zV|*$9uLdFLM+5)Z(W<(siDA8`rWA$k3D>*Mn;sv*Ws~ z;DglKMK56P>YU#|`QTsizrn5DVSW7RAb#pF{5bP>D6z|}P!i-?j97E2AvBN!HV1DS zyXU~GM>d|pCPf7)s?w@AKd!IHpL=>*dC`=I7vqBc-93EDV?ob71ND@DeNUrU>R~%u z_(gM*K$0I)bwzAm^6E4FyZwOsSE~ZXGh09aHbmVZt zt}A6UBroc93TImzSL6E@<9jx>qRRQ(t~La_g*sW&Ob6X%+(ryM)PJo!b%5nv+q@wx zEuDN95GR4us~80SbLg|+$L=nf>A?jQ`qTHqntw*6LsOcMo!-6X&ET_#_rL7~3T``~ zPulj0aa%?K<+%m{BJM(vS;V6_cu+fgB}hKH*&1Op1x#*oCqEDKUFXjCze3Ngo;H0s zK3`P1V^O0M1Wy~Tp2z7Ci!-p5FMg>k&|MmT@1;%aNi!S0vs9pAJCZ2VNS&<&5)U*Gf*O{YBi+RZ! z@4xCa5!2Cw)E&ki<2JG%xVR-zONV(hFb|jy@Y}^KUo&3}6I;@0iUlw@THcP}1m}(q ziAIj&0|P-*151L3g1sdT5}W*8xxTP3KKgn=Gd_LvKo=O8`#xE@=GV{mI!(@OK+i3@ zE=5iEJ#FaG_x4}>^gD-jy22+hlFjC(^GdOw+3a+ltPA7}MCRcbg(&?^%%j&z4d7Q& zNJVnzc^HVq6NA*nG#sn6#*uC#tcQf(y0E>MKUlC+i}8kGQlW zSsxC(;ZCVQ|6`G6K+cQ7xp*sTIfSodCT!k34y8HI)rEdW1NhUiIcP87uet=c+Rq8> z<2Wbbd${t`nd7hE)tg<+&`Vu4?r_8x$2>$2|pSmz-eA84~QxR3hK4PBYH!>m$~=BMw~1KBBvVd?oh-NFZ+Dv{pDV&R-aY zy1*u$G+Z0-cRM#gR=W-#-!Jopm5zvAW?_#FReMdu-0af`0`%wM{r`bMYeyCo! z{o}_T12M>z=Oh=xfxB$;Smpz5Hyuhyp+}|j0^eS}!e1n+G#D1|4yU9k@o{TD?Y&3t zA(kFm>;i~yrcdm;eEc}`b(e0(TMs`Ba>_7%Vp%nF?k3g`=Zqyd>;jHBh^P4Oc=PqU zkRSeV=f@YFCTF_PIdqr}1=m601B8Yh=L~R#3z!ljaITmqWccET5QwIn&zp}(#Fx2* zk0T<2?eOhdw~{Ln)G;WXm&JU|96~2?8P$X4ou+PzAz0f@J8Pp@KDV z?H5bNtkl4U6j|3Q1lNUoVrnN`zFc2j*?~8`bbJNVvs&o(ZpSNb!hsiFJa?LZwN-~N zR|s!UU>yxKYJa*Cw5kk&EMk5R!%@h9e0M& z>>b-|EiUaG^OVNRuB;o%YCC)KBJAfBxU_3*vxPa?Gv=9|aj;^zxbr9ZyACUJv|nsf z>~gYO%u_ID?9CP6MT`I4lT;?z%>X(ZYpD<`!a6qdi_J!{62)ejaK{5Z&~ZGoO=2Al z2bpaV^HBJT%>=Q7jrg-ToHL63VH>;9mEB>U$S8NVHn^}m;sOo~tDRw+q1bF+SP*f| z&Z-z~Jgz-q9gn%&WJg$sv$q~b8_#sEnd}DJcy(rb!LsNTRx5!!7KxQ|aBFWLSO>%1 z_I804NEg-sk)bxeB3@O__-0$cHn0|K0PARG&7b>y5~JXL--XU^8|;X^u5TT81Pz}% z51c0s^Kf)~+YF@~ot`_qohHxSyTQPeopek zSzou!T5hkWo2PD?B}UUjW)bNPmNOu77db9%OIa`mYCwHXlOS2xhA?e`psxNu>z=+w4Zb6H*5 zLfRkADl~Up4syXkceagGY|)u5go?A*l(}O%$W;MXN4AYPpQ{_2N4<-q5!8uairobcX!PW^!(SAo+6IbuG&DY?d@0usMe$83S<&F*h94;LNM5Si+TieLvEqbj5 zZmu@V9n0Z777(5=>9MxKf^7P$dAM)PTC07$z#Vkg0FWt>tZV~C0s7^V##t7rg7i@4 z4SG2!Ir5RuN`4nV-)}5lhGC2q!P=N6% z{Byy+6qD#-?tBtGp2u9E3()+ZPZ>Q>JD&C=z1-w3;L3mqxW&c}b41B@@-{=49h+Ov ziiEvgJ6MNvUA@KOZ2a8rV0KW{m~i`Z+7|yJIxq3WJHSG-ab2YhV#dUCq>Ip)0s$m? zWOAKYVVQsr_Tv2;ArPv?saIgtU7EZFN##FNjSqUUAAZv~yt`x4G zEQ6f&JbUa|Aky5F>_XdZiFbH%o?fA)ld~$d$iff^I zPj@sx)MI(?+r~>5Cj_|#n*rw-1K%$$q(u#=Nw*1mpTF~+6DP26<+y}N6A?IC zDetp$nwTF6er>!<@(*PYz2Ziaxs_qW$p-u0RaV^zC=bii%pS%co73wqEOtt-vnE*K z8pk|48?O==yoil#iS=pNu!bc^*p@fQrU+Xya|FIvxfxAjzSPw&*ie#%{CcZv`*1^R z=W83Skw?(f88_-eTSEKv9pf<` zVRmbJTwGRHa(F~?dkOWbcR*^Y!mC!N@Wws$b+x)ciFF;wKw)M&ioy%fF0>Q3n;uiD zjBeb{XR2nEX_0AyX-R{RwTc;)nIm<|661)e=~<}7}uzOT4? z_{}bS<-Id!YLEsgIt*jlxXUrt{i_aNo<^A;Q4Kyu886(YM7hQ~e1bB5IB0a@Q<7(4 z$ERjF3f>J)`XC#-<|Z_KFsbp`FRwm2eFBq*cXf221zlZKl0)vmtBcps9jkhnwHz4_ zcX5+!0RitZ;Fa-aUI_#U(mA+;$g|dzWs^q2&k7lv)oH<|B?p7l14TjEi)j3BEyBG$ z*UAK4b+x&k-eYR(8k0Oy>c;Yua2boe)2GkkyBoe1*EA^0@^U?EtT^NA7(RM)?>=mx zjLeDD2J{kRtfFcdz6FI;Nf!i@DdVz-wrpuxff~s^x8Gyo>-X` zUg+Pd@5#dV~6>dIEDQy0Ge>YG;RuAwct_ypMR z-OW-Ij8~+cUcUG4+n;)J`CWJ2_SCximH1w~58$(%KSVagz)3nCdX`!tbjoaFo$W-{ zTT@ybpuUN3n5BkoRmv3o?E12%g6^WcyrMIu)d6|=vlM;>Q{ifg6>ww@<|ZbNU3JIU z1m+riaC)ivgQv@?19Ju)HeRTyne@c{6I4pK_y;)3MK z)kz(c21CBd=?E|;?Dqz_dun9*y3Fvg4xk++ulD?>|XKaSPL$|ar)=!%j zUjViFq}Z$>Frb}kbJ{z;0QXpX$XQf^Ok`WW7{D$ky=K`iIphiGBieN05r+N}VaPG{ zO5ko4mQ8mpdw$xC;=atOb2DenO0TaILil#jgted28II=X#TH)LN8 zoz7odpP5lNSgAKu_oqLVTiCuoS+Q-9`|AG&Z@bUU)Q0^l^tgc}y-^M>K3LK_8C zL|L+;T@MAx(lk)*L&>o$H^I;92i6zJ4ikZ?L(;VzS`U#{1lFNUyA*iMELfm_IcXmR zYM3RsYTL(_ri|7-$^UA)Drr(uY;=5eg1QOcJ|inUab~?XBP}KY&4`Hg)Hl=xs-v0O zc|&r9@L)<C4X3G`U$>D@~6gf;l{RjW=GmEZP2 zV_Wu&vC*msbzW)Vyf}yno>PpS)SjPdTMBhHAaI$xFC7_X+aAAh#Q53E6l|lG}+yZEWuW`ka1b=|9EKg8_)k5u^g$S#aifPsHy+z@#6|+XSFF@`i@Jm2R$$H&|JvbC6Xeip+8b5lo^H z-zAWa{(b8@1j(}p6#vGL@|8J>3Hl;!u$-o<;?_+}jAlM!-#JN#V|v}qb3v=!>x}pwine@b z;VirNfM#wEe5Qu_#__xFxCNIpb#H!*u)fGW^dyy(b>+ z+kMx{=byhFzuQ{Vj!qn0^^(S0rImV>G%cA@UC}b(`^1=J{C$FUJ<0(C?$tww#-`|W z>98A}aa7Ekz;@HWIUIqkCO2x^IE(F>#~ymD6+lA7?0yDq%#1G!wrm(m(k4%foW62e zk_PVxiEU_z4Ke-3cdO<7K~lj#@L&CXnrp`9OUJnd$)gJ@V5kpYUwC18VO>??qZ#UeO)Gqh5+2!6*!P!Qky}W; zx~QR)iKJc$RP@KB*#sUAuPe)H!33jQQfTaoIJKb08PkUYAsHtr(B0mC< zBQ!LYl@oPRXOgI(BswdDAeAjv9l5g_whM?9xym1oIFSlaK?X==TM@!l3WT<#sFwIg zEN&|5dUZAOe)38DV^!6IGd49g3^!8QaZ!fbWeF-Ty)L=fKRHIN>+uiPyCo&16a}Q< z*VKzECQmBg^ND+YLco^`^Yjso$CK(Os3JqIc^EQ1{+*GZT53fYe_S1Yx%#iD96#~w zv*_8QM~%Juu;AMT!n|-_PpLRapBxg{DR56yNIWH8!P@1G<0|I7R-8L{>==5kC~;;) zM1J}{y?$=$0=R#gi$hWqF`c)9w+6cAKh1lVcNXp;vhF3b_#GWvCJ{aAXEemqXhNw) zq>uV}@U0M^+)a$^NGn2bi#AUaGFj;((8OyE%Vm*?Ug@dHMHXVDyCs^4@k)G@>0Q^P z+Fu@{oiwhznv%1ls1xi+Y8l0N5Pv!6Nh)&Gv7T4=R#aD+$&NptGzqOOt0*t;A~d&> zo6aZHrQHd2B|zPjkiag1yFP%WZu%(ic^uazRaDNL$&4o-;=8#V0PR7~;(M6Ck1~#p zgU}fyn>A}TZqe%<^h9sS0LtfZ3#rZ^Jv-p=1~PC+XtKFrFO6V-*@)zGU-^C0=P$qu z>kl?G9IVIVRPj^OV*ElQa&CUKj>6H* zn8eX%@@=r54XePkttJX&;sXy8nHV$u;B@#Om&T<|s7Z~fmnsq_)zcaN%Ce%oVs(&} z?$j|CVvy;pDXXb1n@+7{?oE%&dXSoeE9O_5B%*yBPXuwiNbqB&u@NDQ2hg?(vn_0~ zfc@EGG9Z~v#1p4Bm?o@)+qMvm+Q15T4IZOOZ|~G=H2SV~y#^N^C_mURe*wK31iU^4 z1U$}a&kdEf=Y>d}mo&U%#Zyn-zH3MSiAM)exP@T2!YtfdQ105vE%>obQ+dEwpZ^{s z3I$)R0Q?AE(9cs2d2XSQsjOk|57&eLDIdB>l!Nv-3G~Nla6i>7-ds2X$en6Dko-i? zhaaLvgGRuf1(q`byq|V|+j@h-t&Z>x7?BR|+y1tE*D@xVL$0&*5)EyO*?x6s=xSRV z4j39jU$wO{F&j2eA3&q}He=?{5Phz#?Rq&pW^HbTE-ahS+;-}V?J;fF>SEfq^G^&7 zUDvj?(O(Y@8KFTwb#222Mo7L&c?=CPSK8W8(9qDYo7*(B1R6sGHuB$0fH!gfw&6Br z2r50=jCXIxgWKr3wrkIA=a;r!*O?kdT#sr?5M(Co{_V9ke%ZEb&$ZEY+pZsPqvn%O zGed2|+ws!2w%rNTz_o$Qf@{Pc488&Wvw*)!;Qs9iylP%8uO4o3pAGkO%;$B&J?;Z= zOUJEJfJl1aR&y`Z|CkIW@1mv8#Z6Nqn9~OX?fVbt(QIv=aU+@-ldL^8jKAF+S?G1P z<{N=Gpok3;`Q;C-!e^rv#qT+~yD< zlD$=y+)>^H8fq)AowtzJf6J6G?+!M*mqU~h#FT6Fo01bEZkh_Txp^+>rGh#v6uAW% zb==f|-=IYPSFruAwHFWi z>W@b?PBFLjx!GfwoWD21HIehKr2GKfUVW>)&E;p4upN+lv8@k7{DwjBF>Ct*cYC3+`XOW!Y}ufBjF_TxgA5uQZzaGg#cA@0#(x zn`ZMH%5lQyxh}OB=qdoaA9(bpy$Yt>MlQGiIUG)X#P*Uy7yk@gle|hCcGC#Hk={bQ z2F^B7H+T&o!S)vM>)a9Vzi?dAGaP#Dq53}q?XLRv{gLPAA1h-x9RvRhB%qAkUWDk( zpMrn8zJ@oC`5XBKh=t_rv+UsYfQM$?E$;y07qBHfL0tDgmG9QPW^<$Ku_Ed9T17;`A@rZ)^t*)A5Lj{OIF#@s;lMpS`_jO|Ji#^dJ17u{v*zJ^hcii0CA#&3~$#!Va-&nd1pS{`B;znF< zJs(=Q-HQS7qn-{ow4XWTdFRgIOxB?)^s@cLLe&bPvGr?+`EKsp2cs7^Kyu{ za5Er?HPH*2>T;0%w}^9+4l?qcMI8SBbEG}}7__SP_L1hMr$evmK@V^DBE5d`UZv10 zJw5@g`*UbQWhT$J+?^D=Y~a$v$Cw`$X0N;W$nigrMt`Kg+S-PT6g>R-G?Ci(@}}PY zZU^N;I2?j5|}cxT178u7l4){=^*n(pj`uEtHNqQN=yO0(xr zY4<2ugCxhjW)_XzE1Nqn5#wPSntlm&Bq5VS9FR2NJ)Ug8_uOxoT&S%RkO324I5hDj)W3_q6E@fi~*4YHx@V}PzJYK!Gr5kS;BxU4-XvrW7 zw9Q9<`R$W;ZYW);o!@)s_xKHzJ_r>PZ<8O#xk(pj>)cYmIHV=Uo~1*aUMSG=H434? zl=WhRU^DY$%d63A!ity=DJ`x-Cl=s`^Qm66G3N~aH`6vmU))?=h}mmzYQY#o43xRyuEvw9DK=8-6x7g9-ZT> zYg%XSsD}$gAo16ZK7ml*k;Z{c6a_7aV81{y89+hNzGNSgS7c;ULSuaZ4ldR}N@%ig zgYTWntp~ULz3i)v%M0~XM8e<@R?W@MS$wthi!GBMo;H7ebO0`*;(e+Xq37_wCsaH*t*M^^b`8jG9er4NR zum+*s8oZ!FLP5GISn__GV#MEd=i*E{*!IpbF>GG1Ebuy@9AMj<-~7*=htkb(V!Z}*A_-Ub;* zn1?*rW*o|0^7?l;ungUEDRyydYuu%3ylowRX)-$cG=3d#EJlX)(My}BmEC(gUb6P_ znW*KJ=Fo9yM}7B{@C2y8v2JzROOnO0{ zu71+8=|$7#|D=x|2Nht6dbsj{)JSvXK_ukT+A;-gSR(24fF-?(@R}CDhr~>|jpS5;N0|n7 z!8R^e18x8TYQkS8u>tsi96n#$N}sI4MK#e!?tW(mdaD+M*~>lxhT->On(u}_#a$H~ z!1L=~Lnq%ld1z|mNi^6x?ThyIYlW?N6QQB~e)EA$^Ur4)Cx6GhGiPvd=~F99*AyMzT)X_B@l;#Qi^sa#YmWE69rx7y&4<(8Sp5Lh z7;^b847yy$!%ZQ2@RrzNkb*4)_#pPIFq68P2Jw@!*P?!EV38}vw4|0asV zr~cCLAQH5pcVB%Kr?mar*x5;c2F2JdJ;`T@`?NhBg+PJ%Qn&*CQ-XglyR|5J(SUv8 zTjR#@ZL1<3TVORLlCLNG!z2{oRZxY9_<+Vgq&mzbA6emUK;|t%9xXov3%2z>{KApz z3l6{ic5U&vj~C634W~<1y%4A@s#{Yxguic3ojuKaIsKoU6@yCD+RYVRn9C(x&{|RLo20i`%zX(P_L4(*4M~YLEl$`2cDyIRR)tAEZqck**|!i)p_kN|A2Xy+m-llYV;Er3&_4 z&qIxw^$V(-KCRKWCX7Wr%XTh^?DMTyc)6qFr#qX}+e7eg9q7{z{2LPC-#F`AKX0xf zC-uQ8n=)pX8pm`aG#?4H6vK2;I;O6VLals(;xPV#&bhdF@jq{epozUaA+gBuP-S6T z2az3waZRd+L8OH)7_cx){)~;%0(E_ae|&Y|DGS0AIiN z^vAjHJW;F9Ur@ed$z#Dgls#{x7ZxoU+p@H5;jEQ&-gyO0of=m2WJ#@GEMDZTK#!(A zxQE#@_uZ*)%pE=9N8$5QmMltc4r`rs$GE%+6JPR}Lrdq~ zE}IhB+nKW`zohCfSw9a;CVFM{@2u3N`^RWn7q6bnpZW7}*&Uza+IwS}nN(4Q=cIb% ziL+-{6H+_ycNE-lln7N@(5uNxX_efp&zi^yTivAB%0c`?c_0v${Ltn{8y22A*!hyO zaG8pUYd>@d9b|ssZ)d(m_aDUH;df9fey4+I)c6hC>L{_v`r=PYw5}57v%3$bJ0L5oEc!4S^xdccQh*&Dhl^WnyB6DTrViw2UNMskh z%i(67Z4svrckDkt^T4Ioiw}H>9%T+QYmsLU7UQ44`6jcsVp48vNBz+MC+e<{ zQO#CKtFo)ME^?7&TkcJkqVI_-Pd{b)p*SMj?(NAD;t-N z##_+ht7na$d|Su*&iO-pBd%(`EMvwfLhFV8UM9Q+(MKtHHNDSWfwt!r;V8O@iGet} z2NZRH;Q>O)n}oz~D+%_Id5wnmKpqu%|oFM*R4E{Qcz%r?y^s zwqp-!T!4eqN@GV&npzS5gvu^#oi(^~)xu7s`%`z(W!Ja^3kj_k+8wj9x@nwl5{%aS zXjZIhWTXJs%G;4XFhbEbOGXaRbX9q3?V7l3;IO#t#BES|B^dTAj6z;uQNOn9E!*=z z`75Zf=H)vc+-GlQEi>mm0vpt1OrBEio?1R@Ok2G^qiNdmJ06aSof62pe_?56$>{c@ zGbadkG&E`d<))FV@V{%qxMQv>e_9#7RT?^Dh(sUxN=hF+vyWF)=7eqKtqtBO^#^Wm zbtgD-a02>#@rs(p@;2MwZYz9fOTMAvmg4VUYRK|7uj%R;GNGlW?r*5llh*j&k?rAg zt%nx0Ox_uDVzKM;%bvO|d;6nQXKee-o&i2RY}TZ;38Md`(MrGr;=ek0q6MV=D*t_Y za9{5X^e4U=Ey4fFx}p1fS9j76-RK>hNp{bpiuwrnvI7-%BGZc7D&9fWp5j%cJ$K-r zJMpVTju-mj#GaJF8$9YNkSI=|n-QCvPJ`Ym!cd$AkY9;J17c2($h%-uLl5|##EU>) zkQ8wlWcVi@cOTwoVuIH!pZh?==?N1(<&Ly#=H{Tng$Y#`WoFtXIK4Xj6?$uLL-=7l z3O)4C)Cb!3XJ*l39`V5ZH~f&{OGeKe zG=yH)jlb%~pZ4L;oNDgqXztj)J)C{nf{Xp*3MS9!M6>bFx5Li>yO{+06ZIdDD<}{J zfi>CW4S$aWn&RTYgQ3B5B|?$Gk#p$4SMBGVHW-78^33?=>Sg1*?(Ie!pES;=WXd+` z-1>?5(Q$vyn$k_{4M+@qd~ZJ_-*{}Fck#57i!1Pg=2`Rv-2Mz&Cv>k24WH73hT(4> zn7ZzfyHSR9+_0v__*OK5iV6Rd=+%Y3sp^SkgQrd6q}uzdeOxA7gnzL6z+upS<=*M( z^UGB43_cag(?|p_m=;klU*x+_3|DrC+q==_3((fF;cPhioNE3B1w#*w4c;{LGNz*b z&VLMjJ@mxz$ye0xr_68PQ}^@#x6wn)l2z&vc(Wd9oib z4z3H+Lv4CAA4#`h3^wOgdg;2(Lx+ky74?nbUrO<;>|s3HL!lHj!|9ti4yARV82rzU zP=$ZZnxC({@@M69fbAFhX#?1qJ}sWxdk-_AuXdUz=a5|JPpSKW^y6Rv+RwnqQhvxm zf72W~PB+}uyOg=A4_W-yP;jMB=jaotQDU-V zA~9+_-d99|@ElQPMKeqC)!7U1;v(Y?C+M*f!t`tH+LPiVKok+W`ceM+dqFoyACKQ>9c&5vlGP`x6JCULAG8ZhkZo z==RR=xk&?L3cK<|c?a@P`f{Bbk0IWT$_YsB6ZXBmXVAa#M_q@eqtem%IGW;N=5aC9 ztKpd3MCx69IeN1Xb)@S=TVK0lC=$`u&ZC(L!!PN4YM=l$GDKvO`r!h$1bPGy zPkIbLtwj0BWgi+t7vtL&;oIoN=*=ZGI-}g(+*dPIJA=4CbE!)ZhtJ~{GzdRQ{s;QL zWVeET8~~C*#w556su77x5kAlt)V(J>H+ML-vpf7OH@jx(Km_jaD?c(C(Z0|oN9a9ku`Fk*#y z4xVs3G6e(Xoj6#^q#jA)AwU!9;(-1A(0mAg?MWSUSMvTKzJ>ZKJpX-tLQ<9^JG;(z zQ}L5c$nxQbi=KO~pR>q(7}{K)Q;4Yf`Sixl@S!pIx||drg;1v#6%Lv*j`UWk_`^>8 z<%j`en}pR#YGFs@0f75{&&PJIC8|f6#Wo7 zMh|_h=Dnxuo;Vo(WyXCOw`Pa`#atV9T?w;0Ki}3T8~Vi&trwp=F=6J271wm^+0&8j zxto!e?s{nnmaJE~4ys6}<|tri6a9?A^TJ^ONbVF?ZjMY`5HU>bpzYIzA1- z<{&263*_g&;7WE)A$z9u;R^gGzZ~-E>@u_lWfn+l^)w*aX9r&%-neL9?a&)f;kBdD zvA5>sbl&~Mv2ZhWaQve1EsN=T`0R(+?r8}lhgA-K_(vR?0K<;5VY%xszhPN-=$qE* zlmj38>$#I9pRBOpQHLV5SatlPGu+wL3Mvb8ec$*a_0&W7hkj&!*AjlBC@q_&I$7jKXYn5=@eNg_Xx2%j4_`yQ z-_p6YqZ@uYw(e-?s%sdGmyGHeRo{U3;r(|FK7;IN($=j5`X@5hf}K~R_KJ82+LWvs z!h#m2BeRQ2puj^YyU_YR77BT6)D=6I7S)Ze34gIT^<_Bkpbfu)S{$hh#3br{{6+W+ zDjp8Si_TXuH_!5fQ)etR#9f15r|z$QV-V8!b{5SY85cBG)LpjG&aY70HZ6ci2_uR!e8GVXVs6I5%#O@^=N=7l^ zw_4vsCh7)!i&0k zH+Tcbx>0L4YS)KOpmq3tFi!7uzxgIg!5^dX!@BXrE@}gO_9JH8+&ClE1y&3WWlyDp zhZisYVAZPd(wReM)_1nHcGk}v65ik1itaeO680k*VBfr8+laOAqe~$}Qsd{5Ko!g( zs&Vwlvmn?uAObvZn76-xlnvdXM%cTkvTNMR=Dc@P=d?_#8@hdBURT~Ql)Qd^xV{H< z+wf^Bgb#@5_*3DJDNjpyP#-DuQ3%GGyGK?xU6DAgqjdN--=(Xw=FRTyZEHjKk4HoB zW8+cL3fyuP%*I_9$4SuT!dScHFMbb|jbQIC#Ug`gfg?o8SQGYriW(Xa5i~Lg*+5v< z1w*Mk1P(tK6{j7XAEIJ?a(Xze`^*v;;k}1;bnhxzUg*ZHZ#}jMkM278EAB$GGz0gWRiyOzW5---GaA_mxtNJ2pa8CSs64Y8z( zv6LvJx|?eMY(qR`lM(p4_;3SR8`6Nr;_pVkzUbny$cex1#{WjPm3T!fn!f@srnqiO zhu2RJeb|5xqp=P6hT*q+FIDY{hO;_qi-$xNZ^T05(8g{55y$Zt4&izq_>U<492w4G z^M!R2|Equ934Sdhh#>72?~;`h@WD3#(IXr&gaGEPSzYW{g&2 zq}33S*u5Ojz-(JuWW@p*R(gUmA4Law)QE3Caa}tvv}Hc}b|LycOQmr$s5%j%q} z`l)d`63K#W7ieQgxEE~=ok78Fid{W-`nHz4!krD>lUMwsC$saSxj3MaL|N+}n0eTr1f1ysF%HTIxS(7NrtpHw||art$3WgJ?PbIIYP+t&Iv;N1Q+A>s65p~d|vB=R!$(|s5CgV`Xf zvc3ppv;``jJh&g=jYG&ivP^;O{0-w&WoB6M;lT}qSexQx(GgohqL4}u7QQbaxyR&R z5+8%RbEnL?$2;3awGGCf?_UAt=A$VKTpjv^o5FkAYxlKWO@H5OzL`F@C$w(mzR3^F z->0#FIdEV1ya2th)lyn=rN($D=T=wD{#r+ z0svE0V+`xDzznFLPBM~G`XAsX=dEvV>-6WtNI7b)LpQes=Z@>5wlsPMTMcPT64yJO zLn;$(PAh-MVEjfE63QQT`s*7q=H{?t2XCZYu_MOLMoo7VAOFr2_dQ~5%mT`a>OQm> zLa#N1ilV$Ou=BBY6Jk4ZcD78rXKwiH`t|FXg{uZt4qp=AJFLImf3$K&b!B7tqE>tA zdujXKi)p7czG4}EamtL^ADV0_6?m_&YC3c>!JDRZuBy9l7hNB&UewT;RNXoBobmJe z&f0{|RiRJ%ON4sAHlabrA5NGJ+Ph%`+WO|3#1-r>A0B2U@}N~#M)xAotc}v=DQX)~ z_z1lp;kn(V#F@Ml9hpJXxUJ2kDceGmDH_$GR-NiTKI1PY?q0HW-N=`lrX*1@{!v&! zzwAkEjN@a_qKW#go3Ly0$oZ3&;vpIbDSh)j;~%M_-LDH-*(q(|Z-}d={$HTMy;GYz z_8)0(x^4?~;^>HBiTFG{Dt!JF+RbvCHg@87F@D}rx@vHB6OQZ8qjwHm(z^6|sv^Nu zc;&Uj-$8De!MX0bFj)yj_>_$2@Sk$&uuC%WmOaqIYa)9z>X4}OBs_z3j&^TJ0cShIotMm5d~|A4Q@*N1-qS*=rA5jHS~u|>LK9zfj^BtHUD#a+_ef(?hQ zgZTT|Ux5-Mtm=tT)@+r4S5XbS3h0nGJuScxdAi`h28Q;Q=z@sSu@bz|1AZWJ2#K~k zDcC*V0}Di8tOPxD3Ga25&|qfB0_!Po@X{(Ju3iFh^R9SQ2-lUAe|keOX)uFk{~hwlmZtNQ%lwi z&@f1J$-#6_GFd>Nc*P{ACpic_c6dHEmn(41aX?q1NwU+2{-3wLWw< z{1N3P_b7;h_+ z&#D5v3~#{83Rd;B3~$|w#`aL#>^HWZIn#EdJ>1h1?$K_jZNH(dkzA)kzoV^@@?aYn z(4Ae1?zq8v4uhRqL0_me7~FUx5j<~6FhG|zWw&hODL7WhxxI+ACKknVP@L04sH#`krxz_kmBe`pb`;#IN;?>FF8sDSi!KWbcr! zyY|B#d_JzzR8e8-jDxkXA6|Q%)L}=rBM8%&qV15JuScR++TORTbZc}s>Fy*}h2~fo zJNhLE2f*=aFvd*vQSe>`td%4;;2gl7De#z)Z74wAu^>ksk?jSbl@ftS3~02UV!?R^ zeu6SX7o{vdgijcyf`bsbSKI`c=p$gAkgiPpfsukyt6xf08VCs;lYkO-5 z6+(e+S5sX8(F2gd7(Vl-uD1m(TYx{eSWv0q>7g&-YoU4RlS7X0}Fw5+A~ zPaQfqnWiVxVMpk#S7(N=S<$f_t$YjLIS$|X7FxNzV@3FynXkS@O>S+)%bQ-DhCiJ4 z0=h!EX~I3NthuWbO=D-sni0a>L$D! z+RTga*3Co*uBFGH`sjH0-QyoUb$lt>h126iiV2_Pa_P+DRK{^SGj|0N!}ksf zze|_lLr;cp4&N&xY7RcMlm2&2*{VS$^=`+~r4Dy}$)HtbIL;r~R9U&{vE{2==;WqN zxZ1U9`C}v{;J#9|~YmXOGzwc}u5qk6ZX4ST+{nGfz{sTJL zAl)Ou43`tEhU6ig5X^azmH_QQ2TL2kgakY`7Ia-<2Lr|eERW=|>BvGT z+`ua;4S0p1F!?1D{Up{z!!>_D6@CI0Eytnmk;~ARg?I}--!!_pd2|z)&@F}N%Vi_G zacDUzf;T}ZYA}9fIbt9ujw?hf5U1uu99mI`;~*zumg85b!BlwA@t)(yd*`Y`VOdTCjQq@bOSQs$x|R5B1m$_!-Cx z$2ObL4MXw2P$sDGJ4haiAwG}pfV`;chVT$i_&53=p{*XB$*^C2p0SbUB5(*v*7w2ns% z8a8Ud;xpSHr`Atu5Bk?^dg*W7J^H#SPkxh=KV(=zUZKBccz!l|1OIyF`KhI%Ga>2b z&2e(|led43s((dPf;TU=vF#Wv>&CCYxpMXKt8KPR_iebXVtLP!*RJ1v(exeFS8sT2 zADZ1zR#{y>yso0Ax>TpTRI#z=px@`=eUVu3Wl8*mL|e&eK^MUu7Ykv>q_w)Oy6bg& zz~Ua#J)(P3_pI&}-P^j4bzkYe*ZqzVf>$;Xgr!j?@}mkg7>z*9aAxi-)P#04|9n>M}2=yfOEOnYXL%mO(rM{+qqQW#wn`tMV0CUXQbTM5? z*V4o3adaC!gPu<>p_kKZ>C5Tu^o{gw^gZ;0^l|zm{WAR){So~INFBsVX~S8nN2Fj~p1OAfu6^ zd3|9Y#iVxd@FB*Y6)q@>DrU%g__`t6jA(?$hDTHl}1`=?E$ML zlxQh^S+#m1;0cy0HZBz}rz3g+%!0>kq}CEygQ@}54v2}?AFU+TNpS`z7gv;(w0m62&BUTW zpyRzBqlgqN$>!`1j^b2Wo3a0g@Hif)MTeU zJ>BUC0A5=Wt_fC_J5#3y%Dk??BmQ8}|6pEWVcx_-S8_=q-d$c+Q3}t>0*?gX=Mg{r zv;|;L1ee8LdtrDpf!zil&QxUb=NA^X7Zw#2w&myN7Ea8}%gYSCM~G+(%Bg9tATp8q z+l%uHiyp|$%gb%g&rgL8iIKL(150_}d6C+J5D0)>SET&8fLv#_M35Sj9FbMx?xg^o0MY$COw)1=twWUn_l z{2{r-Ba$5c!obAByu8APN&>-RWX|^oa@%u@inG~gexHMKsWYgV8hRd#1my0`_xtnP zN#;ih%O53)Q?ub`Qj*=CSXh)o@V}U(a&sE+j}2&d!%Ynj56WqHpD=QY-;o4750n%K z@%L$tLVxfPkIU~5P9=PKf&dKtJe!UKYJ*cs0)diarNOci9P~Iq>{AJKC?-`7!n%o> zgm+I6N<)t(#Kk2{CDlGPn;I0bdp*v;v0yOO830L?1wwOXqcz3;Lc8}EJP4FbB~n9+ z%L0KiT%7DGEG(H41Pt&Mvmtar_~$3$I+o;eBtX8HvOq9+ELdC|oKgWGp-2goK#LW8 z3G1g21q?b<@V^y&D~e0Xju5oir$J4=1ue-0RdOb$!`*c*54pS^5;s?r1@NPgwh{i5 z7X<@wQQ^nOoat#U|0j^P4gN{SZO+tmJCrFZk&@4X8YefDl{u3M+;5AD{h4Kuoq$M( z(j@Vl;$nYx1*r44g@yJ+v?l^78NUs9Z!0V;yt1e$cWZWLF4d|$N|9Yj_y`ob#$Q-? zE;Bp3sK_tH|D2SRjE~tIc18!eR3ZT1)=2rQAm63%lrlj3@CBizD38$1gs64^hL1rF zXh>O_BY=-Wh2bwC_Z*KW1ucXNbkLDj;on|d6xa-O<6}@W!Rq|0)IPKd=TrM{f=oZ; z`|}lC3AheOs00-&vL_|ka~16FgrvfiD_>Z>8qZs~@@3_3<;r8glk5tpHa!sZZ*!yp ze_h^SkZ|W4z?B-ZV@LQpAc=66uni4YQ7QJHl~c+BNlPQ?)JO5Laf6eSlWy9v0}roA zwL4QFyDCKr@7NInP9z?1rV}y%zo&t4G}Hyvr2_!eymKe4aD|KEh5r1lt~3zGXOQDt zz$ueJL5-x)GZB$xy1X7&FnLL&YGPd=4uK$^bBsI3o>ty8WLOc4 z2LJRL-E}}V5XlF9a!^LRtX}bHuz;7)2~+}!5K)PC=g};r7aQ0eYYThHGtxDaZd&PM zBiH0PN!Olh&saz!|0F;8=BWu(;pB>nNdXG)nMc)k3?154ONYN-*gWjO3VuZM@?{6v zgg!I*$D|;YT9%p`$e_7-{S4qEU?hz*3^T%+lvCOfT7uxdt zc7GMVYe0K=ef|2^SFXetuZExF>(`@&p#8?xt6x_BRJ z4{txhECc9ai61VMCnN#X*Fz2^CBOcnL_}2BQ=|i>h478~%NFaDVH#0za_%C05Os!! z+@-6GiK`zjnPau=G2+K6QtTBXda8UOYb{^Mg>NvKIgvAoG0)k&$(+E&aF=sFexfxo zVLG3`bxwBnEMw!IM*lb7k4y1b%6%MVf9b4-Owo!N({^`kAudt@1*9PO# ztE#isZZk=h#f}BciB){!s^>H7ObK&&l=viPdXfqMoK!3(Bo*7J{O4)-72uLItjf%kj)v+S)9)iuF6WiHqWG+BA`xI$T>F%nKKQY26kEb{de zL3DdHmC?#4Oh>3pClLglUtu+QcZ^7cP?= zh_gP#l|S`V=!N29+O45e62YKvT||1_fWQWRQBN~sB8*l{NsDQSh|9? zU3%g~^8LK=Aj7oaubw}Jzv`m?IiI<7g(ZGa$(~y!=2k0CYmz)o5`M9q8hxVonPgjo z$xDljbSr1YA6OG1=O4dQS6;sx2HE(9Pj0)4f{?<-a_2 z*OqJHydV^CzsIjou<4ic)X$hRRb(wCv?nd2hy8CrUbtiPs>t5G= zr2AU;ldcyg5lqMdEAg_G@ozmEh1$>zc>i=UT7@>CD`E6|JGvJ=1PA;*gI+{$pbyaJ z=zH`#rK9weNX1aeR0dT*RZ&BzQB(^xg_=VxpjJ@ps4dhsY8Q1Yb%6Sm`X}{0^*gPj z^|VOG&=4r3bLavX>y|2`-FkW$J(6yso9RgqxSK}LqC4m=x`$p$ub?lb*U=k6;+!%V zftCP4G;Khl3{l7^h>Tf4#OhO5-(z)T7|9lSstut?8B$gq4-w<4r3}oWjg(0Gf2pPK z@jxIN@Mv`;LCLPv4CF=e|6dhV$?ngU=tx+rO2bsr|Cu*% zPRfYQwlYkco}tRhD}$3#(>0-lS*Bt12qntE#K3CS=Ce84S#LR&Pd= za+Y0gv^YHn~iqu%yt7Jh_GvVjq{DOjfB?rE}GA`3#FpS~_mMN{MDw$X|Xi(Y2 z^muogLC=q44My}ZDbY^Awdd#L<>KD*s&u)0VwF2R#^H)hZTGrs%nUb{W-aJQG;3=v zc-Z*7lC`b8uC5$F#-|$%>^Po}fILD*hiwEdZmh1VibD{7`QRKk?#i% z89nfW_vZKu^N>Cje!@Ril$OZp6TI=jjrP>|m>d(&HM5+c;(J)he^X9=Zk|%b{iMwO zi3tgb;rgob%8E9qvAVscRxfZ(j8TuMoc#P8C1)FL=Q&Ejo`Q2<;*X%yO0nq86H%bCz$hO?>NHpiHcDELj`Q2=Fl0$gapxGv;YM9 zV)}xQ*gt#&D(u4$|4az(yML6B%Dw#m*dIKcnI7-7F^t~uPFY1|Qmn7GCTVa+yxq#N zJZE{aqO968Xi!yBO!i=s#Ihn@l$n|32O1#^5}W2522XJVByEGFtKb_o56O%Zt*k-M znqDO!YoT~tW@ent3J{^Zla!CbsEA4R49bdgOP18Zu~~HvI|OVQ3EKu{>H{OPoSqS} z3vz5LD9R;u{t8H>E~}`BOIba5FsVn+TB7yflfW?41nA+%f!SzcMMY)mkeDomDqoyk zWb`c5=m0pMX*mhdvyl12#KZ*30aSPf5xxwzTR4v4Ecm5J#g|74RcLva04BSEX{%$h zeL;a|XdAXe9zw5*M~SN---%z>^1CXs67zkRM0ht4T<;#$8Asn(5);f<8=w>qKLbBI z``4hMQUkPT*9kxd{>T4&PJDCJCo(8IwWYx--vF$EXaKM1BD4+8Hr@wQ#ScS7|5@}3 zMD)*s_cB58UKUcTs14Ls>N;vKbtgpZAEizx@%j&`e^B30KS$#A33M)9MUSE{qPywU z^wsoU`VjpD#N|JtKcl~(e_>e0z?d0{@i2u<9W#U(&a^U}%t~f8b2YPKH+AVyapP5pg9oo1s5=cfkiAA_!ESG zeMuJ}rqly~wQsdz1u0Td)Im}mBA_^uSM#F&2S*6NK=A<@2q{tS@S1W)Q#7^J{1u|D z1gmHU?EwPdQQZTW%7kP;>GW5*sM_><9@VpmTBQwuH}Ls?gFo>3!14p(55zC(nEe+# zNIq>=<-hS@AP!pDf#n9~8+cF3{kJkv*d%Y{UzzoRYZ59V*EE05nl(5xF3UQ(66R?q z+kCOgp%^|68wuVro6OnLMi+_P%Vjq!%`HJ&XiL|iscOD z=(IgO&TbLy@v_ZOQEirDVjbq1L1uD}y4hE^5V0m}MU7w0SW*)Hps)@7}(Fxz8dC1Z`x=15BrExhE+ki=}K#mJd$ zX)fL{N#?DRXyROx;`LVe;pIsQyv1s@iwjvzeBg zOkzQdrOOl_W9dK?gJv0%va*tlOZ5hWekb|hO=h3ZA{eZB1!nN&oMKA+LVa$x2iV~ywkMc?oP-S~{MMbqDpY{?twW6d|$SCzVttJDNNl?Iki|lvD;)O(NlYBA2 zxXc*eL**3}s`hd`Ta!?rPzy$Y-y7U3JVJ+ z=H=(-wddsK=1k7dE0Ej|5yFm=5AJ!h9=3=RdERQ1#~L}KRkCshvqQSe$eDoQyxwGU zbnu)gLb~4KaCDpWW(W9ulH_*b-3HDK9A}|`?R9u5*=83FlEazU$}?t2;tdXmb-$i7 zOE!tqTV1v>1`v?d%o!~<`wODcA~{8aAj&Sh3s?ryg z0ESgG17ebWKD>@=lb}vfaxfE>xt`v~44f#5B4?EB_Hlrd)oKAy4)H|`z=(H{Ccg?1jy7;oid_U}SWK1dDIyWRM6M(YY+7kcm26(PGKdbZ2up=5Bww-< z(nP)9Vo#MID=BO9*pxId04a7U#bMz&6Fjwf0WT#VXBY#m*kZRC+@YKN@v*5EDlIj| zP+c9a%*(StyWlp0LQ+R-tK(94)d0^z8`Hssf`4k4$Ln;W($ZcJdf#f@2>N4MWQi*R ztAl9fg@l}3&%a^J!LHG#`}iIziD?C$R$E1d&1!X&rOKcV_Oc2|ME**U!>))J zc9y5fW%s0&IMR7f`0r2?x=bobwB{fuhz4Yok>~ZiQC?ngV@XN*&XQz@GkLQsRk?Mh zr7kKd@%!ywSk1FA5Gc4hFQ@QIz`p>#6HfyuAN(`46yvZ8MyuU!H8ca(FfcZYpqS8H zEG8Bji)3Y{TSbT2U?6srpJ#Ic`}Gzn&SiVZYPXm<&SV9(JMD~)i76b*hQltL04copSyZB2d`g;<2t zBxpl=i1fqjT1ZE82{5xt601=#71s2n!%P6D<2g!>z~VoMK=WKA36^A+R3Nev z6ZSzP*-5$$K)`PW;*a7Cc!%?@FaDKdL6>=wl6S(qk%@X0U4CK@z8X&3`esH}_o(sL zjQOJntwGytQ#U16K84p!nvuseS2{{IQ%;mKBw!W)ja%o>)Q=6sq)$UD&b0F*+RNjL zSK@S&J%JihbmbK{#T3o*jA1WfLoefd@a=fT+S%hL9y%}y-GY+gjphLM(CKaXOMDJr zd24gmup^&-f3oYd+IR69Dqb%I@N@V79e*=o%>3sDcOeU!7sufT5&rS*XI~#bW#{0= z$B^K);_rE|kM1unPOMzg5^F=1yKg8mh_O0&D`6bo%74kl!TgH^E7;wUcaWN3H=s7y zHEq65n?2j4%$@Dh?b9999f7#^Y2BN!vP%cskGft_BA)7_h93c zhVY#&(Aw?m+uF81Z*Q6Qb6Xo;FwS5?0(4C-q;E00U9lU+kEfsRJWPfmP%HoUdn(Mp$1EH9r}M&b2S>GBCMeON}LRe2~i zHz_GQojx^%s%R$9>F^tQbV`0wQh|r|x6{RBqOp|9S;iPTsY`@0=~G7e_|#;5c;nCU z?j*}L^zJPyyiMYudtcrb8g^~?ndfb3nVIR*P3Xq)sAce`U5~vpO}~V_;*aB~?3U2S zA1vH%Ns5pExiM#%-;kc~UzXEIUB<^HvU!ce^T%4kYkoB3r092|4{r&t{9qxfx&^21 z772 zbFt5wn_E8yI>0zSP1S)fRZw3qP-YKYGhKJ z3{{n1qMpR)@b`M1NmU$QM^CQ&y$dB=v2ekCXwxV2)?{YqvlrJ0L{F71q8WG$4Kf((4X zoaGuTSd7WkK~4_bJm=#dCgsm+IJj@*w2iQia~!^kKgot*g{uK(1E=a{!R|^I>o)54 z>ORo@OZO{ckpR23=@3ocr=#H&ZFqIXA8FJi)&VQ1puwm63P>~0N6PpX#@O(L@KL=j z35fmfNP0CQ<6!b)hmyH=orr}zutO?YFb|ufs=vghLp;C(FOQMmh&52IT`*&d z2o$**7L;lQs$tLsuSZ6TlT^v3ROyl-FWeLHfxt+b09Hd4pr3ZhAZQ14BM||U<^P`r)fOUW&~waEzX^V7c$l;5^Jm_!K(%!d* z-LSAJ^=i}P2|4D9c6QIwFFr&k_x_lycL@f`KH4&**~k?3e%zQ=BDjnrVtAG-Y&DgR z_t(r`lEw|~eS02re>oL%c{(v!8CsO zswdq>iZ^?nTeKpRPl*fLzue#}7)jSHb;h!F>3WB)0RIr1m?xyjCcVMMoPXyO7mG@3 zvki7jEE~eNo!$xiK0n!72)jUC^V8bjzpxcmiK53TPw`ruX_?Y}3wvrS{d1k%HQlQP z+ukLs=}E_y|6y|@YR#dw*l40^W?j5>T=nHlb;a}F{0aTsjdwq}49^ZZZtQ4Wg3mYO zbJV6M!i@&nVDS{^cT!UB$GyLxT0?wdzF1q@+Sn-O8>-sU3o`TLn2f~ZeEy_qr@e!H zzB;twVdLGKE^tYt1ixzY$U5rVJa-BvV~u&)TI^tqqH(HO#qb#9DMGw4ZJK zhnyQ`d^hW^)$P#Tth-BhSof&zY26Dj>-!$`kDu#))cv9hLrb#2%x@yRwOWA6Q9Wve zmCx;HCTw=ngO;F6l(o;-q8nlUcR#uh9YrUV)z9z1E7PB&f1-b*pV4^=Q3gt)VyQ$b z4d#LKsUoVJs-+sKW{9QErMjtQFcZ9$+5xfD1JwQ0G3puWCF*VJJ?e8MmWpW(W`yl@ z9Gyz%(E+*!W`f7k?euJz|6Kxeznkf8^lthN`ab$7{TTfW{Q`Z4{*e9${Vn|)qhpMW zok?JPOdeCp)IfxF95b1j!}Kt#Aj-Oq*~(lGk=DDI`3I`cmB59V9uca~yJ zti;B%iEIX2$X2k`>=1SoJArLwXR;k^54(chz+S~(%kF0PvUjl$vX8URvaho5u%EDB zu-~!2a};ObY@C}*<#MlH1Ac;r4U)aYwn6-1FRP+`HUI z+!x$;+^@V2rji`In@{Hp_)@-(AI^{E+xc017r%&K#c$-d@;msw{2ly3{wV)6|1AF^ z{}%rV|1bVWzE{ucje4g(NuR0r>#Oub^<(s{`kDG}{c`MtzUjK(aWPov_A;yqm$TAcgstiL7V-1rHvkdbLOAX5n>kV5CI}A4)4j3LZ zJZ?B;c){?7;UmLWhVKpMjjYjPl#MCIY@^>;W~?+e7@Lf3#+k zHkz(B?J(VJI$*lj^q}c+(=(=*OmCS!G5yQ*gQ?fdnk{CRImzrZ7nsY;gUut&E#@ia zIpziCi_MpqFEd|h-f7-r-fzCo{HXba`Ly|r`7QJN=FiRFn13;cEu2NP#96!+pC!*y zYzbOwEJH0#mR8Gj3mp7{JVC{A^99Ja7u-l6@A1KB&_|p&Z=i;_ZtACc5 z&*xLhNFJF_LS)IHazP6CiAU&{gFg88%RX`oiEyoE^h-Wo=KVn@)Bq)s7koxi8(jOm zaxe+0r~r(76tE)VU-C)@nZSWd*_lrfWZ_l@50qTwBlSVwJ@4!X4c3&^D1e|KtU!ax z6yT(2lH!~KOrVCqU{wzlkb%m89e@#_p;V`41=M9gnqU@$csF?{2Nc8<5=be6VFaPR zZ^#zpWd*$QoL~Wvl=2D%G9eri6|w-8$YUtt1SDi1^7>S60M+o=sW8vyRPZM^8ry(I zC<`TE~$d@2aCQ23x=<%`HPkPq)kE7U3!D9lrGL25+6eyCre70@Bz2pIs*3&;~0 zC^ac8)VKx6_5mZK69PZrgHu1qMgK>HP}pT4Dr_hjp)IOg!0(8b0S5u~ez^&is!X5` zg~|vdU|T;qz&b-B;GiNY4Vuaq!h98qBJX?{>-LvCP}(0ijXuB;#>_-=0hQ&N_V|?C z5tUGc*sr`w8Ih${O@G)CMY}-nBif~*9_1210&4yJi${1I1+8MDHid}d5Sb~p0CRj^ z;ANCWswS&yp=1HNHBBLz2LcZ$HG|-yS^;A8Leo$&1iolhYLEdStx>II8^Bxu(4Qba zik+%^AeeqK1!osjg$R_WFKLxgCGo0_UTF}lV#uOOLa6VD9H>6wBf&P%SDg=zpnw#O z4=PSpM6iuEsy_On%mIoO=n5hPA%z9~DN-QzS6?NoUu6er=?XU$qM|^es7DH4kVi$4 zg0zV809va4Mymxu^G>-Ya<8;jD5WT9q&6*0;TP1av{0>)fS?J7B9iUXYnAh)tAdUN z04l9g(Gp^t6wOjOMjonHz>Wx4fK8e~xllievOrsns8xg!Dv^Zwsun7wI6;icMZ_YJ zW*pU*2t)lua|v#KMIoZPs-~*YA#MWANE54Kp`40BP{hzE5(Mp_RV{(8E5b+8@xVLI zgj@a9TFI|asq%#A8sP?!tW0_jxPYB_`&nim-=}E(n{zZze??O`(I+mY`2chRJX*6N z4Parvwn7*av1)*D#AHW!3FQ=NC=C`kG=PVFA{YR&UxixL#Hy)$f(AtB*P5EDK7AOF z7NfK}(q@%heI=t;5ep+b*(g*+v4Fb(Jqkd3s8+5jme!{#_JL9{QF#?XOSvJ60T+Gj zS9qgnW+Y$+Pr*v6{DCN(CN)jp0gZ^6P@6@R$q^A~wGcKCvQ*^221hv&;SrG2ztKh- zSu|I)RmsFs@Bm7E6fx#nHIZVfTmx!-pq$Xwlb}Gf6k(nhcH1D%U^KD6*fsD_SA@%b z6-CXZ(vK+3I>JBDH;pgR-c+kC<6jGE{tr~UkH~N5U^g<8dlLJB0)v2UJPzgr7J`k2dutKJS z4WO>bR%ugCqIG>epduAj%Rv_4i1t@BO$7jBVm=`ou?rC+)2}V7?vCPN$chU|vI25_ zYOF!(mqZj*?b8_bn*fX`lj=5T5P)^jCxjtNDWW-wGZS&h`|~~8s%gR{V&|gL(-4SQ zCm>(7W&>HK>H#4k0zu&#ffTXS;0j07o5;!ug6wmMBDw}Fh?LSaOmz_Y40Z$>yygO` z0EnnsqmT$yfghrAM!`a{|0?l>4TQs*4nt?A$Q{I|c?v}J)tY40w}_yr`S65+D*s`K z6YUFtkUk@zF$=h)_S|p*rHJnNoJy~wFa(&Z)}>~Os3qZOBzg}iq-~NRl$ZZ7Tqe3X z!7YAmb?A+5E0@DdxPg;rxP4Sxn=m{H(u^J$aC3H}F%fp=iIF8E%yctWD`z&MNnG^= zDW#>9MU|X89;R7c=0aL>E;Pet4JMgRWmdT11SIn@mvhU=@D8mmu>xzb?h~v=xY!6E z9K4ZI2k``sMaV5>q_F83*4T80ftTkEEHlBx8Vt0aJ1CiDnUmvr6Mj<`WSf!W0sOc*4C3JjjaU zO-?H-x!Ae!Mz5QVOEODa;|$0yK@A25|2928p}k2M(Vo)f65O&R3nu&n9HePrfN6#& zynt%Fl$*f3&T>$-1+6i0E63Q%OsAa;5}x2#Bcr$MPD^D4A&=z%B@{1+MxZCpC>bd| z7Xy5Q)V)?tki^PlUjmAC8gCLfpWBqO+beey9E?_Ui;~XS$HZnPn2KXIi=0hhC7GWC5f>wEOTZ2;)3L41`R<<6doK3^2Eg4p|Ve2k?K`#mcN88%;6zK@Nz7#oXvCk##|g zEFSW`=H~DZlHie9mz#4T3y=pSohI@H$ZtbNIFi@NnQ^ZoYZF@P65WT< zxp}O|Q+PN-NKB5G^4u)-aRO_MkvO}P!9Q>U8}Grdx`d1rE+y6KN&%3BUo5qOC?-%9 zTJ1DCC8*m(J?AsoJT4){%@#vB0gaQGY!}Dj8j;gGffW*!QxpS?BxGmSiuTmaR`f zi4l!N(44GpHz&JIrgjNXb;a|R4FZ=du^iqef#Sg<&K81Cc#3yQ#<&E^EE?_jQKC); zj&VBlrg+idklD~d0VeTTtCK}@<9S=0RdBlv>mq4p^dl>d0txPGk&B1><@#D~rzD6r zWRkg)Rz`Btv2lVaUo?tVT8!avl|m$kN<2KY8O|o*X$DFUi`VB6+F60xLxURIP-wO! zSY<}<A2J zze*hFu>{Yka+8GWpsl%Gf}Btp^em&02#fuyu^Jpw@kC%jGJBya8iVy3| zK>tM)I!|ikjVv|YXOi9Z_*$UEN;_nMqbCz(ga#j4AqtWV7;_xD37Q)xvS>SzCfKIw zz$Ex{g1s|Xzz~8RpjHTw2f&A#0C5{9x`d;ka8}ytq)e1S5Znoz%Rvb?H)*DVfk$QV z)*m6#h6fuMs~wb&Lo)>?Rp!bj2ot8~j_JzF!bP$G#~HXxrU$IF%gM&L^#c7{E}!Zb z+_?$n^Q(=b5!M+n%ZZ_Z)@%#OF2d&&j?%g1;*5+Eb0RtcDw@E_aTe2B0mv3=1n3hu z0WSrmp?UpIK#xQDdWI380V6X(i88|)Is8B_2RvrOd+mCVwb3PQBr8x@vJhpCPl$0# zT!NQdY+xnce76Id0hj}@ImPjU+smaud&f5kq8>N~8)E@#t`rl#lm@fP3gLw!kvMc{ zQocz}kGH0$aC8Y_E@$GxAE_6&(}>Sj^_jyjJB_f_BWRx)ZH7k9p-D0etDL|_Y=q7d zM3M={&}h8D3ew>9bcKhsEkm50lQ?Ryk(F#57+c&`T^61qg2_JGm?+m5o675DP)Cl3 z-V*u_YO!c^!}>uv!*oW`NF)1+2qr~f*Sa~gQvwhimKb37?a&rPmUQMcm6QVABA1bC zlEbHn=>bw@_GqR6*3Rfj;3#i`l#;@F(t#a|l^!%DO@vjL7GMB0(&wRpxdhH-LOa1! z+GICxLRU7)nJqO5jU%M*20&|T0_7+9S`^F|=p$b}0f&TO{|E)(~qpOf-9 zJR!zt1G5RTrq_cI!4|^$RxFhcg1V5#D{}{BRw*O*o-7t^ zWhqi_v4GH9U}8YdF776oi7~Qn7PZP8VUon+_gE)7>N0_Og}czFEDsIula{wxVz-kc2NG#oBftJBa0u`F001;%Cp6N0{0mf+yFY}pYD$OnW zQs@9f%(;=lYswf$ocRfb{W7c%!(D<2t#=DPFYAGhDg1#5JOIt$o)iSA0Tv;0)U_G< zWFB-k35Nuu+f8~uDN|+v3BfHKrX23E|Fr1vjV)r<&rU8V&XG6DhS=10CeL80t;=z z9cz`sC!qHQs$DF;i`Z-fKi>kySgM7U(G*~gRfP46>`K`fpTc-Dpy#NU06iD9d$dWg zf=|Ykb1b+=R_bg4rqohP|ZQV%-UXX?#3uA`YOFIgldd<-$(E`OcV;V}!}m^G3|g&#F*7 z4&j9a))wb9#>?CafJ;Sih;bd4aYB3sJ0+q`OM#+;W#7{Coo2cxhn~pf zz%a}VFhdyf$RKfGNRm+yMLH17=LX1yls@6%a)cB@2i!(}(ZBPxUZ}UcC4B z-u>?T-h0$g)hF$zBt%SG(`u=} zr6`AbHiWbWc|vBr6z3L=-&BTpwNm7-1P}|kBtP*WNZ%qppgB3y;|Dp-VuNFWK2#SQYA0Ua0SpoSMJ!><9 zF4BCe!_V(~s89q6j>TN%T_MRRs+i#knSc3I#$>10Oo3>LdixmZ8$2)a;r|LA;2A1X=^* zpA8Y#Rh|QV$~Sp%SSn@027%^wgZNDX=KHM5Iauv>rL7fFmGiaf7|6>^c>IECP&ap= zwsg8uDIG~_v$ywUOkx5Y;oA^yK>B}!-EQV(NNfW4PT<`~)fRKE#`y{3r0Kf7WK_B9tE?ZXloAAdpv0UlQKo>Tv zrr$bfnp@#%N+JBMlXsp>Z#M|X%?XS6NwMmuD`~Z*+KIlx%-M!Y(JMD#o`K2uCRyYe zB#lCbh@ztilNze=C@7?e{4En_+YLjj?o_qHIG`RaK3{GZ{#RA4Jnc zh69je!z$l}5rC^hs>w`OgI{sVqk`&J&AZa8F*x8Z>Zb)pB7E?BJE{Q5xUo(QxdqpF zd(ii(+yOg1tx)xm4R;=s?HC^HxB)@{V%Uo?57lnf6oY}yHzq1 zMS3|Kg$Hi}2y-A8=5awpE4g3@4pW9>i>^nYWYaMXJ`IEnSSO~^WPnre_lxzUS$IsV zREr%5{hgTQ85Wx35}{qOky~bAw%tp2_*%8SZb<>6*0)~;J6PyA9%H536;#ZoR@~wRZX`SF8u`lP>Qi0v@DpIh9>hU zCH!(i%olc;U_CI+pV-}rff80&mI)17NKc> z7iFm~(tQ}68K3uE#Ype{2?1sS@=%#?7Rq|EE2$Q-6<|23vizo%!aXJkcpUl+osyn+ zf&~_X+MQ+K1$j$!-RGJraf4i(LB(-b5r~4$JdWeoy|!p*yybFAid_sH4`4-%%AF_= z1;@M#=zGzfUZ5Fk)Zlr4e8KRF%FxP7(J89xd&X^XSD_X5{bA|_u2@1WMt+LfA<8%k zo&YC-pupT9UkGO?w?@JRFoB6v8BLKn_9mTD88E@+Qgc30G5zZE0|~3tmzI)wQWX;p z15%0QC+@VsT?`c(GJCBCk*ImZHG?r=7Se-`qyon^CVpnBL4Y+kbh%lYqZv@;0C(UB z?16)Gia8<&*LH-RbOX3!74aX;8juSb;|FKU&w~z;ZqzqlL!F)mW1&sBNC7$Wn$|Bm zt{&qR=W)(5A?Z}}BT&b#cZ=m*Ppa6%1iw&)8*+IgRq+Kd$yYgA!bU0l>WE*<8pw0S9dWN*LcJz8h<*RLRvwIu=Xl=)S#Q(m)*G<_7z< z#*CC=X0Qr$%m*J1`xJ~|DP{>B1`n7B<)GdZmr76s5zKst8IxnU6f-}sVFn>6CKd~H zGaZr*lS~!SR>~}W!GQ6X8eSeZ(QoJ^BY4VFvi3&kQ3Enbc5;PUbG08=mx0Ek*00ept>w2>6ouSf- zYl7nriOq#LD5nS>4&`n)9mS%?XEMPHnSzmSw}oPc?3m;yDhAukz{E-}7APYn3iEkL z0dbjr$cc8uKx8X_p44X`tTVX^0U_EHix$ zxEod5Y8s4agu7K$almh-(}~ik$xnPffN+Mx$iA$)!CKsme-n@;0uRQ|{E?(Qs<)};Hvw&|(QfjnobWMe!Me`D zgrOY8aoFFRDOF9u2pp`=p1SkEv&UAQ{YkJ)+rf;xoJr9KVrg!t)!o*Dlz;tPP^GL8 ztj9cAa9x-}jo^MaO6XiLNivlR&JYl&>@2@(Cjq+=cmF?(w7LD$_yvN0GR(hbfOykkr_i_f z8RA9gPu~o7gQ4+eGU_C+5g5lM7EGW9`8P0l6($06;_-dhi+su{m~M_W(TU7vU>_4e z#U&fV(PO#8Q66Zrpax%+9M}TT<+1C0z>%^qm8;~3s4nHOt`VF=;RXxAJOdC2ppGZD zpRrP(!Y;?(hJ=9;7Lzd;r??0ljd7^}3h8psUhreE0o7nXgi63*2x+r^i;F(_0o`^?q)M)XXp1vjvVdSK6}&VzDbmG1?~Z*B+o3;orGfUHCKfNVKXNNCsfmzN0@0(p#mIirEMxF0)a8x5XwfIqD}mWNHThcdtQW*Ar|+8 zB3~*ArGnw)m=`5G2Fokv%QGs+IfBy!<-IVQk`lnV&pZn-i|O<{@H8Zq;Ckbfk%RZT z?(-@@6}tHcbc#z87Z6RA*x;|0t0;&zLtCCPK?+!O>daUj#o6F=Ud0qE#feh{24IPT zlnnW!U%ii~W=vkW(VRbj%JTBSs*h`xO18tK>wt*r68JCa?Yyux)%6;T|5PTCBld0fW#js}g0+Y)T5nBFV$_g9ZnqaawZ~ZY*sA zpW)k+$?^s07)oCzQ?r02VhP~JPo@2Krd%f1hxDW&vTZjyQ8j7Tb(u)}?8z}F_%cO$ zX#HX6JuoY7c1R@riI6S?AeH|ly+}Fr3z>?MYDpE&Yv>`mx z!B@5RmU(=&R`n_UXeXdW5VmP=sW4Ql_GL=7IT&?FVXkJTv4q19(JI0i%q>JgA*#AR zZ9C47qQDBXYqo+W-wswakW}mO1TCUIljwr_;E^3L_S}b zWjIYsOqjjGx5-)5pTdCcl*drrku^9-%U@HiqgVC`OU?Jj62B1=AMi?(^`hnZ{fPV^eee>1v#?0Jz(EFs#y1Y> z2XThzicZpliX$%qtud|50G>f`5SFSD$AXujwe$yXqr1S<53RP?Ny0+PxW7aTtRbxj zn%nr$l!JI257JB_;fFTa@5XoI6s^tV6}? zPMr<=o6wHKo&7`*QC0YyA#ny?hFXWoR_NQ{;xK^Af>`c%P^Z3u7%5_avGoDn2_C&P z&`rPU*gC0bw<`|v7-(XF7uv9PnBxmsE!rDRzT)v!Rzu)}9OI0FCW|Q%x%kAW zFR|u#v09834$(!RJf{rvQD2F|T&d}Z%@Bz$>UvB_vnuCSg=lmUZ*vSAwPapSA$(F| z2$p57XjHZ&QOt{A*ov5HB7CdJYOEeJU9neGs*2XBaWO0yNw8QaJdTCE)pD4U+{Cm< zEYG3eTu`;EkwaSECSs2=W)YiU?`% zU&K}6X|ZYyDJ&#LtN3#z&Tc}Sh}zqhUDPThTe&FH6fYT^>@%gfT|`4w9l4?^){ra| zR1v8m`b0(~h><5&GhqZB03qX5c|F+!OPegHvL#DOiz375uQCF|A%&XA7*SZY4uIaK zr=gZGvc(rACTZB{SVf`%+ma2H2YaoNSr)6P4q-G&Gow+iHmr0u#n+lLC&P^)#kwG| zOhVxF1J`wQDAga2E@uv1MP&B+I|P<55~z9FM#e#e&vnfFz2|c|j%soILA=BB5+ZAO z7GPbU5ZQ#tKo8eMcJJL*HU`*24&bn`;BqmJ%z-gr;yWw?%OT_>Wh+*RS+-V2I&VM2 zR2<1*R8PciE$^k@o5|~%B*vJDE4(5Dg6U>>i3_fXCh8=kB1%7-ZUxTakUb$*k`VSWeUwQR#wJgqV787*&iDx~^0l87V**Cay?aGKpRl4I!bX zWP?QAZs>@DuJf)7V~VOF%3n%pU=MPNH`8n^ngkLTML`h}tdV-nmc zh628$Lr%ES725>N8qS<<8e<0Esctm#nb}xQ7X`Kp{xq_t`yf|akMc3UPq49a93!@D z>b8&u+=*sMPV=?6vBZseAd+Ssq-~}J#p@iktDq1oA(c~c$%GS+rfo4Y_5mYx7App7 z5n6fcR8#3fI#;;mK>KiYE}CWy zO!H`>yXLg$3B|LEB37x5E|_ffI6!rd6Ed=+Xq?VQ86)j#p2TBp3FcTK z#w4)Gn91jfYI8EH3(y%1SzYiVk-IiI55;D!O6cE>DSeD zLV3C+sCsZ;a3VARViw%O7n6dh107r3E0VO=5m{tuC^IlgXbk8-Xq6duiz`NhZ7{+I zXM-@w8(hl5@Q7)+Krr2cOxQhNaOcfzX%m~Ic+!-_sG|AU1uTLrz58)T49LSrF4O{| z^xLuf*)+NbGh1T^*b#OXdkVXYJ&(PRy^_6=y$PAS?m~Roz3fAXE_;D}gMEwL%O&53 zNs!&9nR=wcxeN#zGRDT43Zx6fB~H3L6>{P}S>;3Oh;=-G4O_8$BRztddY|B>(g>nw z@&h+ADy7P}nF=5KWEU_<9E#@(baiRK|t{VTV+lEW3R)Vg~}NOn2o9%Rx;L z9|~C;!k31SqveM}3x}aJ#xcDcLYvC4ir6>M7d~8~at<57p&nGASL!`|<*C>LVX^{# zZ+{t=@UF6m47{OyZA7iUM^5h-+mOk~eFffxs}QM>aa81^{s^gWoTBvxz=A9us6Zm) zfC_m$;}?Om!v4f#=tkhDdQUGpAMgbI1fbIBF*FB2pds1uH=gwT5DEes)d#|N54a(? zp$Nf2k+ciZG&HI44G>ZE0dK-8HgYb9;0bSZ8z^o7eb* za`9Ec=81c-qvo~Aq6Qxan~!tmG?|aG?CG{`v%pV+#)^y$WQJvYPhce(iH0oIVX^8# zOowGOHrXsDJsrX&w=AJ^oeXF4L}Ia0#z~B)L+mpNP4lBtt|$u%Hh2;^cpXq%89W8d zT=WDPP(VmvrV6mk>M#;RKg5C-YYAA+Wkea8rx0aTxNk(cET_6);t1V`$ytH7Rm?+W zMaU9JV60KKNB#6v5lXPka1aD=;1XCY3n)Aw0nZ6qoFu6sLK3uG3aY2dPz=R5c{Ky$ zoZ_&^MWk|q2ced!uvooK@w!|PSPQr`XY&kkRBHioAgR0*BX=scsAJzIk%45yAfV9- zMguM{vcttPitR%9h%F40j{Sj`uz znW$q69RBGXk6cbgfGVvS$TlwI4Lpa8ID!Y5%A|QIfej|$F94I7EM~+$z($W#+v&oV z8x663leOjMJsFA{@ySgkB3eFqnX}r?5;hVGf$CuT+$* z&AJA!XIiQ8vI_4NQI-19Yj9v`U(9Opp5X-HV^}N77vQz9o&0vs3mE!iVIXamtTJ!& zr6YKbVpFZo5Lyo&9)aj7!N!PkTrmnf#JjDfmgEw*4P7Biz-NizQGfw)CYSv8Jf7u*up?%n-Q&%ZiIa+r&M==3ompKvfwn znv#?HHeF2erjA#zk=9JckUlcAE%aE98RrMAc?EmE~01m4J{_zBp=U z)M(2v7h{E{aI{6_7)nb(&j>cy5~8#p{X?o5Ctwp4AwntU?L+p9MjqQ;b+r;$SKxJ_eihz@rdRAQ$8eyysOx z)NEMjjq*a#h^D5tCdX7aU2FkA=EW#fkXTaT2N|sWK$j8)EY2jvgW-jegTEXKlPt^* z6scBIuw;T1We5cZW_C1NS_m#f^9u7^GbRSZ#d27D5HwMjX7J;(#q9leP5Ugvh;XtW z#iO6Y?QopL1YmBk7;9n+C`ojwebCN>Z!;veOcWug$j$QGti=7c8LLc^U6u*@)ziWF z7=t94$iRCr^%8P8c*SvK2Que=5xH}}hU~cylSj!DOgq!Z3?hT>hnZc>dC2>J6Y@O# z2s_+8!~B7Hk$IJQgLxa-{{@!zSc=Ud%l{U3EBkBqS+1KK;-+)UxgE&au#5XP_e1VM z?h)?M_n~hJpb@P>v9};jZtnuw?d^jv6`D7tapVJG?n6x!BJ6{%urM~$?bLz8C=vl) zqo@RMpnDQe?JJA|RR9r+*XWKi6xRTlgt(_v$NgoXL6Jgln4|VRLy-%`FR<&;q+M7g zefKd6OK>yAjtxs5g@P1n0|C+3Q&(a60@_kP zOf*At`r-oc6j~ehgNv7;p9kupqTwJ@Kv@0$dW8b6feQZj0jRw24>43W0Ng1Cq_4Bf zz*eXVtRhv%0TbT23p9dozhF}0hhU)sXU4VNc zRjGUjU=nx0R|F$cqGsTJXd(k)CjoH#edy|tmMUdfn`vg%u*LO$m~v@#1O)gx;c1+q zkQ)bL1Mt$GLYDw(67)U7?`wElsSe{Hu)Ylgb*~?u#JFR#6QEw&q5%*Zy&C|V){`n9 zs11Ip1|zsI93x1Vk`=0oHao}>6&~R&_)Ow_yc9DgM*68GG9;vTu{g!WbpU2M@{|a1 zBc;~xgT4t%K}i@3jQP9M4pvO`Vi_ftdfr3c4Jr-wf_~WeQCDau z=p#DCpsj=?jT-OMQt3ES&2h5&_=~m#6Pr>19_q%6&?O)wXa%AAC_wce0mDBOIwY!*BkbnDPFn@`xxtNPM9}Kbr~L9 z692&!8{a&WNjUH^0pH|A$nLZ;jO}|Fpll|}sd6pJZ4G7xH{~^lOLQaYQac5sGSrYx zrB36)r!$^e@6aEu^L^#lswEzW8Z3@Jq< z#uQ=avKU_RWjj4=#;H3u<8`gb#&SZ`B3OQmLHc8(1IZ9!A$C+$*@7X}B8*|HOdPA~ z8Wq_{j>w9*KWef%!^x#23lz-71jdLV4L^gWEMzo|;u>_IteS$EiQ{Z0K~9aE#e=P; zt_|@HlE3-Zx7R_i1$W|${T{OE$`wAz=u)qO@Dzw+3Fd8}SQp+z@q8yy8Dw+?T&BiN zU2xbjC=hSJ*aaVbR@lfCNGl_xEhM>dL>@>4=2-H85>xlCMG=m~JSOEOzQXWE5~3UG z03fhvi+q9TIdmxu+Jb07dt(u##ptjCs&-0s`C9X~mB68~2-!F5{ddbc^f># zNboxj$&HacOHFG~24EBB>HyxH%u7DJ95fip9oR3S!+9smatoYO1P`V?-~lo_mls_N zfqn~tKbYIP+ob%IV3{mFr)dbAA;H&L9gBMc=#1~Stj{89jFo=~2rn=)D{zOzqKh(U zyWSkbz3Hfn!3BMBP*1T7u8Mj95F!Vx2Cx{z0>8+#Ce~Mdk!w*$6^U5^_a@Oz7claS zCmTi*&W*ChCe%bM^QvzUxzK{waCE$)r9l=+ci}V0ut`CNA2hVD7@Lh6qUJz_!ao(M zm*u6V1Kmznu*?8grXutsGs+4lB0sL+P22)It6~Dvaj-e!2@e^Cp;WOhv4M01gNZ>0 zg5CtBTSP<`N8%(eCkH^xPzd%uX@&I^o_jE{YT_>lXG2#ugWrHyNh>z0pxx-r!erwZ`jntqO}!Ep#p!vL zF5jA%;$kd?`N35{u}Uy67R|6vVNYt2$q50xGv8-hM+>6%u#mwFbA+}Ln8abvZW0-W zG-GEIP9hmt92jW0Cac!=E+Ctj@;EPhE_}TObTgoO7R`sZwhCYL7-#3H&L{Q34(pUs zE=Vcb4c@`noFwrrFr>>(90TwRs|Bn2(o~G2j({+$=rKYb!C_d}X!q374lkjRb`>KQ zP7WysCq8{X^29;`gqs=PBtp-JiY}-%!O+cV(WufZ!!jZPjY37#5Fnw!zsP3VSjlC* zgyW`E06$D6Mb#y1{#Zuq)ikk=%wa9r#O8!72_`?v2D>Mo_F1BXXgyXx_4T(go-jDW zX2LM10&cs8Bs$PAV-7Mi3oo?mV4S2{%X#+?cN_~ReTY{D07?>4G zny?W1S3&52zQg9>@^K&Bp+)AUxCV!dEHiO2(@ZQDQAL^pcK~cGf&_Tj%}YnHD4lc~ zv<5_*X1Q9N%TgV;6RH>|1P5kwQa)itnP)*-G<__~`vB%qIB|f%U>6Sz2G;D*a)pcX z2ms?fV)J}~iPl)c%e>M-IPDcE2<#5908kLak}^kN12S2~%0O*_hKXXji6ua#R~%?D z1|~t8g)7DVJai!>Z%a^d0bM+{9&7p>*Nw5AxP4Zd&rT!D(Q8lfM@!fwXBpp_Yl;Pb zWTEXi{Jlv0{8b1H28AnUfcWn%u+#{{MzPd|BpkAgcd>$qK8`|7l%VT*97sh=rwSIs zCVpNtC8Yox2^YMa>rmrPxrF7+G)TZ93HWXaN5Ra54OB{PTr5>(S?n0cD2Wo4h_c1T z@&*=fn&3mH&`{+JtV`9IZEd38#K>)$gPhB}Z>gB7toB?*#L~%4FdS$$L2rl>rlGEY zT^ATzGjtVWlM@_*T)^OmLJt>%%>i4zd*HoFoV^drea(o@fdK}+%0NDGE~wB#%doNp zy9PQO?OcuS&=KEhAy$nu*m1^zR*OgAalwjkGlZguIRhOM)6+(fiIRvBMopTUgy)4j zl&BaRu%Ur+Y(bLXu7;eq%iuq;EcBnC`EPUK{&zL(hB+3Q9a#`rhW*|*Mh-(>Ol&;) zcb*eUCI;0rP7IlcgY);i$1AX1Nu2wT8~0#5Pt z>47@@S8y|ZzF-l02M(oW?_a16F8apnJC>Y9Zd8N4$6vZyxOvTaBYihKQ5!jT?d{A} z!m_(>XTK0E5>{V&JmL0id;J@SpS6Va-FEjff&F4I`}Vt+eH|xuyuSD3OOHpe75S1t zUPf^Ivb&l7+i&O_IX8IZ)3>9*;F{G!un1t`c(M&IJNz5(XNV+!>(Jf*I& zShr9=Xd@=AQABt?(1M#@430i_19_FKCEU*+Ibw9m-1YZ<@28m+qes6?a?G0Gra*t~ zr?)?a%WqtA;VTz??Mom3-mY`rdb+ZbT-kVEL@e{aj6|`1_nw}liv;M2NTEo3ppg-` zmPh-`6MKSdg3AMVIFPMx{p_KW){F*~;O?*NK0IsOKhQIFB$@U6bIcLJH4}Tt1UZIm zW%zT>dirxulLh3NM{a)j*pq^VFHO%?Uw<`hYg%}MzXfeg|HE;h4k2dft|UAWy!oe3 zel_@9;F0IZxm5HFVEceug4wx^UpmJWO3U! zUV7E2p8uzi?p}qz$PYlX?_cvYp_?HCw`0+6uOUr+fKI+DV9PGVO$x%iw0WP>6+xbeEG>4KcWMc33?ip7s92;MMQ@WC~G9P{G$m7z9 zpKSTal@~E9&^rwJ<}lp3Ct&uR#dd9b{=2{Y-Ggth#X?HriVH5?z2m^((PxjJzhtsb z@5sVW`A?xngOhcl+>@FrXv>TH=2=4#4mEt*B`h5p&!zNOp;RIKbmGrQ!G8AMWY2It zy5**wXYj*MAF*`vs%)nzjnB*5Qu<5F?(W~T<@WP~Sa9204UE)aPD$^b)^oz4%TL>V#iHi(cZ*J^z4MsA22Ve7&%H-I{8n&lpq&$3MP5VY z16IMvaSnDU79^sWnh^^XNCLhT{`nuf?E#jx z6n(=d56`6XYdkHtL@6oGvV7HE#^bMrR~J$pYd*D5F6{kATQZkOr4!jiJ9#bBT`!3X zMRAGfjf^s?Z_l^g5yhTsTXU@RI=*+~(cbX*EarGrNWy$siweCOSP#vtB;y_TsnP*k zx*a_T=2|{!&!pnMK#ctCz2Z$PG~_8M>x)e3+DdL|c}aApG!i{v9+AaddvlAkCD~#+ z*^FbgP5dUC&UJM)HQNLZuJRRXp`#6BNBL@jKbXG}`Ry;FV z!ZTKlZ=AnH)1UhuIr1$MnH~%Uw{QNzH@C-2mGkAn<~)`khWnrvTXxz*u3mTMye_vt zX%5JPQ&MwXV|BODT4=xSyit>oyilwnk5PXs>BlouF*Erqv_%+ccvBIQ9y_`v;+q{Fe zxh59%7Y+3|HeXQ&4S}ClJZAY^#``^X3JCep8_4;41^h#3M{8Gf9ocC|RmCrv%xV_|<2Uq@JOK|hE&;9G8WI@jzGemyp`Pa1P z&=a{MV*_o8sGo^hNn>tY9c5~BXTWBWBw0Ian}q?bsce*3Dc&-#YneB;c?n-~M6uel zs{c?dRjOqr>9-%!$?~Z~yR29*ys`Xjmaw&!b_2Og7MJ>3I5? z;0wWBPe138MXQg=Plp1GEqAdnVtR_-l1s@~lhe|E8md`g?H_J_1 zYps!p2-)#_afJUF9x_6oxM3*f81Bk)XV= zZ<75r*d9GaXPO09mj-_f=Uq5|TnFx;A<)7&hre`I(Lccg>98~op?}k7a1{C>G)fG= z!vVzY;f)lvpbq$39GUoQ@X=4-@@DX_usdxhJD5m!V1TjT9u!}El`Mx;cr{otmTvDz zO#itjJ8LhS+jGEmOVlzF2esNQ&5PssbJ_J-({EdK*^x+^^o!dLEM+f>$JFAisBWgP z^NWfIt|l3=GuMw57ten#RaEzWvLmx%u#jwHL_2NGx19NoK58WnO|a9Z`qCmPK8q_2 z^{vu|yPNu!#gAUc929(X;`KR)BJH%a`D*9H$7MMl=bUnLcXvMX<+vGZ@4_6-V=u>R#4qxDupfvFOlU(V%D~&J z0?)3g*cE&(cDddLZRoVf#gQ+79)1z|_sFj!FGOCA`~~}4GXzFVViJ#}A`uzliBurm zWu{zd_Mzi66CBxWS+r|}uUC+NKxAS2ZLY)Q8_s&zmBXzH5jgkmCAI|9ILIKBqWy5e z!dQ#cR1R{$UC4$hf=yGG6x$JCA$j5I0If(fD#D^7&Hc@=_>@?judo&D3d>jE zwaHfq8ihl239@T^CisD$Bpbi-7-lgc+kz9LF8SPH!5CJBADTF3Q=xeIk4mM4!+t(! z!T3GC=gnealg*vR2fdnbgQzAqCXtDFwgQk5+TDI+6 zM;mNs9MXHY2-RwDPVcZ~&XcT^@VKo-yQ6Sul$s^{Vc11w%;a2;Pw+@!4%Z=V;zc(a zoT%`+8N8Ft{;VzzFj2S=Cvr|8X-FW&a~Il|7Yh>?1})@qmb{a25~gJxdAYr*5PT!( z<;i!2S;2aRToipcc*lG!J09GilM$bLn%10*Tu7TqE&?P+>5si}MX|7%xs3J;`ED?W zcGliG*nulSeoXt4-*c9|xlnvTDM^USjYf$?J6d`BZIlcC35zrAx3R@D|UzYy4|HR!esdTM9$Gm|@s0+z%PA z{Syec^L;1bA=<;!$(wY9&9`5p?Qwh3X;=0g^1DLu3VY9qw5b}o79CK63WeSv61s;x zq>=8;_7%lTA49T`?6=XE8!rHW>uY zCHQB{lc=aZz_ZQ5?oIhbe`kwrq=xsl*Nv!h?2xB9g;Dy@e+qurA|CH##C07OK1{cFRW_4~}x`b4ZC2iavqSuz{#===~=fS$je?{+8bG_?=dq!G5 z^W}-Vx%diIzF_VpYp<*k~i-uPX4Xv-2o0c3z5~ClUzg+!%a8XNn&zZ|ttX#1Q zlJQiK;|UWVC1(YvFgr+l@J6tZ#DZ6g#TK`JW`Fn`f^|f21N1W$S(7|w|H>cbK4B;0HaZ4&V?ZW{qf(}ex1kIz;4WGo zm4JQ$3tn^x(BV8gAlel%ygC4%P@3ERXDz`~PPb0VYRs^6?UzkV^*d#!`?5R9<~#f@ z$*N79-mct~8P&Yrmb)@jEo98Fl$Ep2J(gXjiaNf?7f-}kBhe$uEo&1$wt$XQpKARb>^?sI2|K2k0Ltabpn_kBz zWl1fN)%Il*Q~Y+R*SqvCviV=)9b)iXuT8l*Kdf~7EqCUJVtbpjmNM3JNbvck-1cJ@ z&hT5!G0dV(#%(Q?WPSLA>BnUj=2nlMI?zOp2tM(L;JPQDB!_(Ev%w3u{!8=pVoSbo z0>gZJH=PSC^SyUwVPA<)!ID>sbVnlL4yhFInIS}QO%IFSCRLjRWP}P;vpUwTL!>fb z)(|E)^35~Pym!ZkmM=eH$2C(%T3e@1Ie5m5gWKnHchBj%v~&9zx7>2Z#cSE!%a1={ z`QFpko;|OVeW?}q?KL~*PhYiadiU5^cW;RqpSZh(`jE)&kqCD_|6@o_YFWZ&W0ONZ zfPu`x^X&ZKsRthjp1QH=^l2jpvYr2vA@qysCB>TWUU#VWSd*}DRzw?|6t6!mb zc}4II@iwFe`&8s+l*Xg_IRe`hetn9bCVvFDO5;dm={Fo;!*9DD{y=Xj6?y8dTo%Kh zN;5s^BF*79@6o?G3bEJ*(yD~N12#Q^yL0%>3XNa-VtTgmJJ1|fgl|-*k2ckHBDLO# zcw6wNjPY3T4i+cB`$xs9ocvQ&g40*~wPLiuCe|r&M_TW|cS^sik4fs1`1omgA$aTS zV$ld*{)1Nz-g&WDeS@UZ9t>Em{I_6<_fCD-(sRt<&4Pjw78yxjTVr#@m~l-XjNjP5 z@mHq^g{bkH&qb5)pLCyzmx-~boINu5(km|`>~PUbFO$XOw;q%C)sG^*tQ6z_bP}Hx z-@a9DGT(es$p){zm2%(OQ?>scUZKA5)j-Xi{iLKB7CUrp%+0V4^v`5;g~Ozi(JO0W zt0MercLA2`TVq+oZHO;RWn#Y2U3hb%*MBOQFf3R7);pS-k&gR`iS@{#YY}b8`m6M~ zt)^cgi-NmeehGWDEdsr8@cH=$;`f-ywXjfhkU1egq3po(DJZIhTNcrA|N9}fLJI=M zadLzwf8IC37~22L2scJHMBwikU{Gx6k%C1b*sLix!fXOzHK0_eSb;*I8;7;n$Mr&O z7iZ{=P?xFdO#j0Fg4_6^1}8XrK(TAk5{jnf&^Lsx4EO`gv)r_grl@9z=keXp&v0LZ zJJwk$=jf%$f*aMu^HSss%`4{2P4rwjP0hA4Cp;nL$v>jNX6dO(@@r*-KfRCq$|aB= zmQ?;@@i zq+oWnPveEua1WVLU(t)W)6DQfHOjs8Ydv@ea;3xnnYqMbt3o=?VDyHlgIV&o_+I-a*_|4XcS_ghL~$q zKq4BmF|+J_3OpX)KeOm2YPgrqtygE?b>vSxwf)BS_`&h*5??>5V@sW(S)P*t{Eb80XJjxBf^5&@Ky2r9CNO@wzx4ipl*pvuIPD1q`D)qtOrkG z?Bh(cdlX$nl=_8nwog#34VKk3R9(4y!)0o@d-;x}ZLQg`?eN8eGgj5(mv#5gNgi98 zG2GvjE3cdqjTY5e7tW{+vK@14AL<-5yLErl&`Dc!-8&ol^x1L5jC<>EnNJ z)tSBD>0SSY8IS3%Yt&C~8GNS6JFWG@WZj-S)}4Ri9mlL)o$|H8z8kZcKAhZQDzbtE zJ}E#P)|u{^$QYd;#P-Lc zgMEeDumtXSx~^G9Le~x<-HI69YzoVa)@5ow->r45CUXZ_xmIdQO&#pW=inA`fNK>7 z%wx?lws}4?^s!S9td!Ifm)8fm!D+MWX=kL#JIrvK5ZBgZwJd`dvN^~l)aZ(G%QQbe zrKfM@5R>h5Dt&_sU%qhG+`~o>+;Xny*k&mz$=P(#^LjdWe8{rKJ37k3>{(=x`O>j> z>^Ohj*Ojr^(}N$tM`~=OtFy>d+VX|v)5!w1uN_8v1fB=qZpcy@E-uE@QSA4VP_ zvtUa({{NwKibC?n%&ENl7rd({&+Wgu|J?rj5K~6yRA@c;Taoww&&U1qaiS0IQ>@xH z@`cG?0^gMIMDX4BpV@Z{|LFhcCvlMO=p0omgX;$;e_x;cC5OE4#J(F?_J3&JW2K$W zdwyMHN@UKY-QnoS&d6Dji(vW7|FfANN{)v7_(xK2{~X*u^Y+ii{Z~Ku-2P|(yJqb_ z2CVPOQK11xDQ9U&V*LKC+&uQae<(LSy?680lpkBZdg(~Z%H0QD3R$<}#D=V!xO#F1 z?VC6sFt`5W*(Q8ya<;7=P9~2lHbmx%sZ?anJ^x*iIb`%`?-7}WR6}HHEJWrh_qMjq zphEMY8)xqmnj=pm&3)_C(RF)04QZAHv1%!@T(FVUyCEkfiOR{j?~{`&yM~&*+Uv@) z6>CTSMyk;XF{YNo2@(EcLWI9`LVWNE%#iSgcV|c;mY|Z+Y~3drHT`cSW4~SQf3IY; zoqduKkuuhMWn-~4NLJ^WG3;UA5Qi(KQE}Kd1WZZi#hsJ$VjFe={Z8ZsIK<7u&Yqt_ z93gBH)cn%`ZWLuv0-=HffAseOW&X2yK^2@(_CWOspTT-0g=sKyG!(7yn<|W6X!QF} z-fRCC$_+zI{|_qnztRu?ui_KG%f?#NbXLl{nJJ^LVwKfwTB_>Vgp2;DOCZQ`O#Qz2T2JB32hcdSIBsX3Y}SgAZ#1mL5~iSd7OJ-GLu z+(4Xva>M_I68>2u*qM{q<-eUXLs6l&HRQ$uUYQa3YUJCIC--w=*h)zWyC^o;@PCOP z|HlTf|7+U7Kfx6hvBD0(XZfGPi}4K~mmgXh{HQ{f&z(A4eZPACK`>*VO8wu14<@)7 zo95p4;~C@s9418LB$#<{@Hyt|t53Ek73=>HFzi!<|8FI!-~sCgtAnGSTFSok_fj9U z#lA~hTR~TQ_EQ$dhuTpfj6-7&q%`b42;iIiM_1dBpJD%ra6tbHaNvK4{Qf!JQCKUA zo9CY;%)cP9itx>Owcc!Y=3-qvn?$%%Nm*w3nZ%r@nuXgQKw$hIbj4^y0^l+=|>j4_yo9q4~Ax&9+;N=-Ep zf!q?gR9MBG5{bdLy$hP#{KzU$E5;MXbyze*!+YpH@j=Iw@06(xgjzO3UyFZuz_X`+ zWpVK0{HB_H{Dv8Sp0VLfvh%ci7U4{#yK!dyS;2Qt56?8$tm6)v@!E{_yS8_C;@)h2 z%I=fL7m+JE=us{^vU}(Fg5cNP?YIX==jlOaFGaqM1Q}&A6CQ}+ z+IdLeh&~LLxL{NbSJ#Bl&&YOYLK>W*6C3x1C+WJwzS|q?F!1-lxyfFl(?49SK)@nh zAb|_WyJzT93tbbz2gOoDaxEVg5k^nKrW@L&LX$AP5j`D3{pPShoDoDkGD4_}ODQY> zCS0tVg!~5IRM)7$VGhNFWz&_F&^C;EH`3Bfz8qDBCmq!)XpN{!flB&bvlw1L>!@Nu z-$47KaRa?Xt4EuLt2m-pCRLdI7vZY=?%76TCZF)%y&unr&n)imY-${zaMTLJ^J_yde2NENJ#LuDopTeM#R> zVs}3)In@{{w@lyq>1<{9wKL3OS9e>dY+3Tqh`lJWo=mN2JzAmE+MCTTZ5{0GYU)}! z^4v)9+;so7k!MEko~BhwrM93&8Ec#V%Jf$^ELmD=>iGWj*QWQh8;e(MoYh+!o^#Go z-By0&fUf?f+2uQybP1)NL#K3gP2HLzrimVo}-st-{emn8lHO2 zhZkj+tQtMgAKlR`ZCJf}Lt8p^(5lr3-7cicXWh_#$kOq6M|ExQ`KL5bXE0~Q$g1Ga z;w}7v@IC8=m&?Z@pNxDj@<2n@f(kj2qiCq{*{4cVTBOF9{p1`@7wX#IAl=E?HA$9K zR5wVqp^4M{VboQ-;SrBj%EmvOY1|o3AiM#=`S1OQSHeO?zyIbfcqXh)qf(RK;d5c0 z0Xj>>Th>qg(AI6iUv>t;14k~~T-}su%g0Hy_3As1UcU8={MJ?OI)AO-nTrd@Odp+i zC0;0qDtW!9zOK-+=-6e;`p-XWAXaEuF?;sfc?YeUx#64-oqd0b#Lx0q^qm_VS93^o zs62nF)7`dWhBuTsH8VciUS4>x>BM7vy|;JPl9BA`*|B=7yUy)aX5~f?nYh#_<`Bqd zsZm>=^U=c&d+@E9=YEb6u0QERh;Zrf+InX%D&&Ot;eBTd58&K5WtQwnBIRP5xg`@D7;&O>#pmwmRo4$>cSzmd$(xA%I%$4oA;a zXC$*l3%Pzq;fY~*#K zAfZYHkweFklgZiSLUJql3b~IwL>?ngl0TAH7#4|Dl1!fIV1}8M%puHf=A+CF$h-S} z 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ĵ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

D;lqR_ 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ðQP5*h_K=;T6=E&zRE!rUS#ztQUdrj5taGy~lwb@RUrh*r!+! zxZ47T{-;TY_2SI~m}<%^wy&-V4Q`#{O7g?+_fna?ySpRa`Z{l`HMC3K1#iH}Kn>fTuHG?xaklCy>Y>f&TV~ItF3rYz z3>j!Wrl-B}%;dp}(LdN%!(_W*-8-oUuu_Vvwd)47)j30XbDHH|Z~qqc-+G6S#&uku z$1$bl=B)<7LTU^%QW3!lqKi{1uQt?&l^(s0KI#Kjn0Od+@UX>$AJMM?Q3mU!!f|!% zXq@zI_^d&IakIj+?rbSuF^#&ubmFMNvtY9s<%o?YF^VV~q~+A;v7^+7w1-3b_|3}v z5DUlY$V7|f@)KDIDhY3=mcV_%zd?OSzE120>UAaf<2VG1U*pB7LuQ+Y3n*eKgG091 zaY(z08HR^d1-uH>zRpBX zv7R;Z1y#i%B84R&9#?SmoN!)re1AxjSB&~9hrlQN!c6LDLtY_u$|#01GMEN@)a&Gn z#M%E+tO6B$d8`6_?J$!WFh?3JjWNnI1!m|oesxS8*sIF;Utm�anKPEziV$6k^p% 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

Y-EX2 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 AoB#j- literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/fonts/Uni Sans.ttf b/src/EllieBot/data/fonts/Uni Sans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a7b39d02e5e7a21622648839874e4277332031d1 GIT binary patch literal 50856 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

Z;>+L8& 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 xOZuz!D?_)g4eVHaeR!~^r{_p@zJ=0) +minBet: 0 +# Maximum amount users can bet +# Set 0 for unlimited +maxBet: 0 +# Settings for betflip command +betFlip: +# Bet multiplier if user guesses correctly + multiplier: 1.95 +# Settings for betroll command +betRoll: +# When betroll is played, user will roll a number 0-100. +# This setting will describe which multiplier is used for when the roll is higher than the given number. +# Doesn't have to be ordered. + pairs: + - whenAbove: 99 + multiplyBy: 10 + - whenAbove: 90 + multiplyBy: 4 + - whenAbove: 66 + multiplyBy: 2 +# Automatic currency generation settings. +generation: +# when currency is generated, should it also have a random password +# associated with it which users have to type after the .pick command +# in order to get it + hasPassword: true + # Every message sent has a certain % chance to generate the currency + # specify the percentage here (1 being 100%, 0 being 0% - for example + # default is 0.02, which is 2% + chance: 0.02 + # How many seconds have to pass for the next message to have a chance to spawn currency + genCooldown: 10 + # Minimum amount of currency that can spawn + minAmount: 1 + # Maximum amount of currency that can spawn. + # Set to the same value as MinAmount to always spawn the same amount + maxAmount: 1 +# Settings for timely command +# (letting people claim X amount of currency every Y hours) +timely: +# How much currency will the users get every time they run .timely command +# setting to 0 or less will disable this feature + amount: 120 + # How often (in hours) can users claim currency with .timely command + # setting to 0 or less will disable this feature + cooldown: 12 +# How much will each user's owned currency decay over time. +decay: +# Percentage of user's current currency which will be deducted every 24h. +# 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) + percent: 0 + # Maximum amount of user's currency that can decay at each interval. 0 for unlimited. + maxDecay: 0 + # Only users who have more than this amount will have their currency decay. + minThreshold: 99 + # How often, in hours, does the decay run. Default is 24 hours + hourInterval: 24 +# Settings for LuckyLadder command +luckyLadder: +# Self-Explanatory. Has to have 8 values, otherwise the command won't work. + multipliers: + - 2.4 + - 1.7 + - 1.5 + - 1.2 + - 0.5 + - 0.3 + - 0.2 + - 0.1 +# Settings related to waifus +waifu: +# Minimum price a waifu can have + minPrice: 50 + multipliers: + # Multiplier for waifureset. Default 150. + # Formula (at the time of writing this): + # price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up + waifuReset: 150 + # The minimum amount of currency that you have to pay + # in order to buy a waifu who doesn't have a crush on you. + # Default is 1.1 + # Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her. + # (100 * 1.1 = 110) + normalClaim: 1.1 + # The minimum amount of currency that you have to pay + # in order to buy a waifu that has a crush on you. + # Default is 0.88 + # Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her. + # (100 * 0.88 = 88) + crushClaim: 0.88 + # When divorcing a waifu, her new value will be her current value multiplied by this number. + # Default 0.75 (meaning will lose 25% of her value) + divorceNewValue: 0.75 + # All gift prices will be multiplied by this number. + # Default 1 (meaning no effect) + allGiftPrices: 1.0 + # What percentage of the value of the gift will a waifu gain when she's gifted. + # Default 0.95 (meaning 95%) + # Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095) + giftEffect: 0.95 + # What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'. + # Default 0.5 (meaning 50%) + # Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950) + negativeGiftEffect: 0.50 + # Settings for periodic waifu price decay. + # Waifu price decays only if the waifu has no claimer. + decay: + # Percentage (0 - 100) of the waifu value to reduce. + # Set 0 to disable + # For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$) + percent: 0 + # How often to decay waifu values, in hours + hourInterval: 24 + # Minimum waifu price required for the decay to be applied. + # For example if this value is set to 300, any waifu with the price 300 or less will not experience decay. + minPrice: 300 + # List of items available for gifting. + # If negative is true, gift will instead reduce waifu value. + items: + - itemEmoji: "🥔" + price: 5 + name: Potato + - itemEmoji: "🍪" + price: 10 + name: Cookie + - itemEmoji: "🥖" + price: 20 + name: Bread + - itemEmoji: "🍭" + price: 30 + name: Lollipop + - itemEmoji: "🌹" + price: 50 + name: Rose + - itemEmoji: "🍺" + price: 70 + name: Beer + - itemEmoji: "🌮" + price: 85 + name: Taco + - itemEmoji: "💌" + price: 100 + name: LoveLetter + - itemEmoji: "🥛" + price: 125 + name: Milk + - itemEmoji: "🍕" + price: 150 + name: Pizza + - itemEmoji: "🍫" + price: 200 + name: Chocolate + - itemEmoji: "🍦" + price: 250 + name: Icecream + - itemEmoji: "🍣" + price: 300 + name: Sushi + - itemEmoji: "🍚" + price: 400 + name: Rice + - itemEmoji: "🍉" + price: 500 + name: Watermelon + - itemEmoji: "🍱" + price: 600 + name: Bento + - itemEmoji: "🎟" + price: 800 + name: MovieTicket + - itemEmoji: "🍰" + price: 1000 + name: Cake + - itemEmoji: "📔" + price: 1500 + name: Book + - itemEmoji: "🐱" + price: 2000 + name: Cat + - itemEmoji: "🐶" + price: 2001 + name: Dog + - itemEmoji: "🐼" + price: 2500 + name: Panda + - itemEmoji: "💄" + price: 3000 + name: Lipstick + - itemEmoji: "👛" + price: 3500 + name: Purse + - itemEmoji: "📱" + price: 4000 + name: iPhone + - itemEmoji: "👗" + price: 4500 + name: Dress + - itemEmoji: "💻" + price: 5000 + name: Laptop + - itemEmoji: "🎻" + price: 7500 + name: Violin + - itemEmoji: "🎹" + price: 8000 + name: Piano + - itemEmoji: "🚗" + price: 9000 + name: Car + - itemEmoji: "💍" + price: 10000 + name: Ring + - itemEmoji: "🛳" + price: 12000 + name: Ship + - itemEmoji: "🏠" + price: 15000 + name: House + - itemEmoji: "🚁" + price: 20000 + name: Helicopter + - itemEmoji: "🚀" + price: 30000 + name: Spaceship + - itemEmoji: "🌕" + price: 50000 + name: Moon + - itemEmoji: "🥀" + price: 100 + name: WiltedRose + negative: true + - itemEmoji: ✂️ + price: 1000 + name: Haircut + negative: true + - itemEmoji: "🧻" + price: 10000 + name: ToiletPaper + negative: true +# Amount of currency selfhosters will get PER pledged dollar CENT. +# 1 = 100 currency per $. Used almost exclusively on public nadeko. +patreonCurrencyPerCent: 1 +# Currency reward per vote. +# This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting +voteReward: 100 +# Slot config +slots: +# Hex value of the color which the numbers on the slot image will have. + currencyFontColor: ff0000 diff --git a/src/EllieBot/data/hangman/animals.yml b/src/EllieBot/data/hangman/animals.yml new file mode 100644 index 0000000..b0d264c --- /dev/null +++ b/src/EllieBot/data/hangman/animals.yml @@ -0,0 +1,276 @@ +- word: Alligator + imageUrl: https://cdn.nadeko.bot/animals/Alligator.jpg +- word: Alpaca + imageUrl: https://cdn.nadeko.bot/animals/Alpaca.jpg +- word: Anaconda + imageUrl: https://cdn.nadeko.bot/animals/Anaconda.jpg +- word: Ant + imageUrl: https://cdn.nadeko.bot/animals/Ant.jpg +- word: Antelope + imageUrl: https://cdn.nadeko.bot/animals/Antelope.jpg +- word: Ape + imageUrl: https://cdn.nadeko.bot/animals/Ape.jpg +- word: Armadillo + imageUrl: https://cdn.nadeko.bot/animals/Armadillo.jpg +- word: Baboon + imageUrl: https://cdn.nadeko.bot/animals/Baboon.jpg +- word: Badger + imageUrl: https://cdn.nadeko.bot/animals/Badger.jpg +- word: Bald Eagle + imageUrl: https://cdn.nadeko.bot/animals/Bald Eagle.jpg +- word: Barracuda + imageUrl: https://cdn.nadeko.bot/animals/Barracuda.jpg +- word: Bat + imageUrl: https://cdn.nadeko.bot/animals/Bat.jpg +- word: Bear + imageUrl: https://cdn.nadeko.bot/animals/Bear.jpg +- word: Beaver + imageUrl: https://cdn.nadeko.bot/animals/Beaver.jpg +- word: Bedbug + imageUrl: https://cdn.nadeko.bot/animals/Bedbug.jpg +- word: Bee + imageUrl: https://cdn.nadeko.bot/animals/Bee.jpg +- word: Beetle + imageUrl: https://cdn.nadeko.bot/animals/Beetle.jpg +- word: Bird + imageUrl: https://cdn.nadeko.bot/animals/Bird.jpg +- word: Bison + imageUrl: https://cdn.nadeko.bot/animals/Bison.jpg +- word: Puma + imageUrl: https://cdn.nadeko.bot/animals/Puma.jpg +- word: Black Widow + imageUrl: https://cdn.nadeko.bot/animals/Black Widow.jpg +- word: Blue Jay + imageUrl: https://cdn.nadeko.bot/animals/Blue Jay.jpg +- word: Blue Whale + imageUrl: https://cdn.nadeko.bot/animals/Blue Whale.jpg +- word: Bobcat + imageUrl: https://cdn.nadeko.bot/animals/Bobcat.jpg +- word: Buffalo + imageUrl: https://cdn.nadeko.bot/animals/Buffalo.jpg +- word: Butterfly + imageUrl: https://cdn.nadeko.bot/animals/Butterfly.jpg +- word: Buzzard + imageUrl: https://cdn.nadeko.bot/animals/Buzzard.jpg +- word: Camel + imageUrl: https://cdn.nadeko.bot/animals/Camel.jpg +- word: Carp + imageUrl: https://cdn.nadeko.bot/animals/Carp.jpg +- word: Cat + imageUrl: https://cdn.nadeko.bot/animals/Cat.jpg +- word: Caterpillar + imageUrl: https://cdn.nadeko.bot/animals/Caterpillar.jpg +- word: Catfish + imageUrl: https://cdn.nadeko.bot/animals/Catfish.jpg +- word: Cheetah + imageUrl: https://cdn.nadeko.bot/animals/Cheetah.jpg +- word: Chicken + imageUrl: https://cdn.nadeko.bot/animals/Chicken.jpg +- word: Chimpanzee + imageUrl: https://cdn.nadeko.bot/animals/Chimpanzee.jpg +- word: Chipmunk + imageUrl: https://cdn.nadeko.bot/animals/Chipmunk.jpg +- word: Cobra + imageUrl: https://cdn.nadeko.bot/animals/Cobra.jpg +- word: Cod + imageUrl: https://cdn.nadeko.bot/animals/Cod.jpg +- word: Condor + imageUrl: https://cdn.nadeko.bot/animals/Condor.jpg +- word: Cougar + imageUrl: https://cdn.nadeko.bot/animals/Cougar.jpg +- word: Cow + imageUrl: https://cdn.nadeko.bot/animals/Cow.jpg +- word: Coyote + imageUrl: https://cdn.nadeko.bot/animals/Coyote.jpg +- word: Crab + imageUrl: https://cdn.nadeko.bot/animals/Crab.jpg +- word: Crane + imageUrl: https://cdn.nadeko.bot/animals/Crane.jpg +- word: Cricket + imageUrl: https://cdn.nadeko.bot/animals/Cricket.jpg +- word: Crocodile + imageUrl: https://cdn.nadeko.bot/animals/Crocodile.jpg +- word: Crow + imageUrl: https://cdn.nadeko.bot/animals/Crow.jpg +- word: Cuckoo + imageUrl: https://cdn.nadeko.bot/animals/Cuckoo.jpg +- word: Deer + imageUrl: https://cdn.nadeko.bot/animals/Deer.jpg +- word: Dinosaur + imageUrl: https://cdn.nadeko.bot/animals/Dinosaur.jpg +- word: Dog + imageUrl: https://cdn.nadeko.bot/animals/Dog.jpg +- word: Dolphin + imageUrl: https://cdn.nadeko.bot/animals/Dolphin.jpg +- word: Donkey + imageUrl: https://cdn.nadeko.bot/animals/Donkey.jpg +- word: Dove + imageUrl: https://cdn.nadeko.bot/animals/Dove.jpg +- word: Dragonfly + imageUrl: https://cdn.nadeko.bot/animals/Dragonfly.jpg +- word: Duck + imageUrl: https://cdn.nadeko.bot/animals/Duck.jpg +- word: Eel + imageUrl: https://cdn.nadeko.bot/animals/Eel.jpg +- word: Elephant + imageUrl: https://cdn.nadeko.bot/animals/Elephant.jpg +- word: Emu + imageUrl: https://cdn.nadeko.bot/animals/Emu.jpg +- word: Falcon + imageUrl: https://cdn.nadeko.bot/animals/Falcon.jpg +- word: Ferret + imageUrl: https://cdn.nadeko.bot/animals/Ferret.jpg +- word: Finch + imageUrl: https://cdn.nadeko.bot/animals/Finch.jpg +- word: Fish + imageUrl: https://cdn.nadeko.bot/animals/Fish.jpg +- word: Flamingo + imageUrl: https://cdn.nadeko.bot/animals/Flamingo.jpg +- word: Flea + imageUrl: https://cdn.nadeko.bot/animals/Flea.jpg +- word: Fly + imageUrl: https://cdn.nadeko.bot/animals/Fly.jpg +- word: Fox + imageUrl: https://cdn.nadeko.bot/animals/Fox.jpg +- word: Frog + imageUrl: https://cdn.nadeko.bot/animals/Frog.jpg +- word: Goat + imageUrl: https://cdn.nadeko.bot/animals/Goat.jpg +- word: Golden Eagle + imageUrl: https://cdn.nadeko.bot/animals/Golden Eagle.jpg +- word: Goose + imageUrl: https://cdn.nadeko.bot/animals/Goose.jpg +- word: Gopher + imageUrl: https://cdn.nadeko.bot/animals/Gopher.jpg +- word: Gorilla + imageUrl: https://cdn.nadeko.bot/animals/Gorilla.jpg +- word: Grasshopper + imageUrl: https://cdn.nadeko.bot/animals/Grasshopper.jpg +- word: Hamster + imageUrl: https://cdn.nadeko.bot/animals/Hamster.jpg +- word: Hare + imageUrl: https://cdn.nadeko.bot/animals/Hare.jpg +- word: Hawk + imageUrl: https://cdn.nadeko.bot/animals/Hawk.jpg +- word: Hippopotamus + imageUrl: https://cdn.nadeko.bot/animals/Hippopotamus.jpg +- word: Horse + imageUrl: https://cdn.nadeko.bot/animals/Horse.jpg +- word: Hummingbird + imageUrl: https://cdn.nadeko.bot/animals/Hummingbird.jpg +- word: Husky + imageUrl: https://cdn.nadeko.bot/animals/Husky.jpg +- word: Iguana + imageUrl: https://cdn.nadeko.bot/animals/Iguana.jpg +- word: Impala + imageUrl: https://cdn.nadeko.bot/animals/Impala.jpg +- word: Kangaroo + imageUrl: https://cdn.nadeko.bot/animals/Kangaroo.jpg +- word: Ladybug + imageUrl: https://cdn.nadeko.bot/animals/Ladybug.jpg +- word: Leopard + imageUrl: https://cdn.nadeko.bot/animals/Leopard.jpg +- word: Lion + imageUrl: https://cdn.nadeko.bot/animals/Lion.jpg +- word: Lizard + imageUrl: https://cdn.nadeko.bot/animals/Lizard.jpg +- word: Llama + imageUrl: https://cdn.nadeko.bot/animals/Llama.jpg +- word: Lobster + imageUrl: https://cdn.nadeko.bot/animals/Lobster.jpg +- word: Mongoose + imageUrl: https://cdn.nadeko.bot/animals/Mongoose.jpg +- word: Monitor lizard + imageUrl: https://cdn.nadeko.bot/animals/Monitor lizard.jpg +- word: Monkey + imageUrl: https://cdn.nadeko.bot/animals/Monkey.jpg +- word: Moose + imageUrl: https://cdn.nadeko.bot/animals/Moose.jpg +- word: Mosquito + imageUrl: https://cdn.nadeko.bot/animals/Mosquito.jpg +- word: Moth + imageUrl: https://cdn.nadeko.bot/animals/Moth.jpg +- word: Mountain goat + imageUrl: https://cdn.nadeko.bot/animals/Mountain goat.jpg +- word: Mouse + imageUrl: https://cdn.nadeko.bot/animals/Mouse.jpg +- word: Mule + imageUrl: https://cdn.nadeko.bot/animals/Mule.jpg +- word: Octopus + imageUrl: https://cdn.nadeko.bot/animals/Octopus.jpg +- word: Orca + imageUrl: https://cdn.nadeko.bot/animals/Orca.jpg +- word: Ostrich + imageUrl: https://cdn.nadeko.bot/animals/Ostrich.jpg +- word: Otter + imageUrl: https://cdn.nadeko.bot/animals/Otter.jpg +- word: Owl + imageUrl: https://cdn.nadeko.bot/animals/Owl.jpg +- word: Ox + imageUrl: https://cdn.nadeko.bot/animals/Ox.jpg +- word: Oyster + imageUrl: https://cdn.nadeko.bot/animals/Oyster.jpg +- word: Panda + imageUrl: https://cdn.nadeko.bot/animals/Panda.jpg +- word: Parrot + imageUrl: https://cdn.nadeko.bot/animals/Parrot.jpg +- word: Peacock + imageUrl: https://cdn.nadeko.bot/animals/Peacock.jpg +- word: Pelican + imageUrl: https://cdn.nadeko.bot/animals/Pelican.jpg +- word: Penguin + imageUrl: https://cdn.nadeko.bot/animals/Penguin.jpg +- word: Perch + imageUrl: https://cdn.nadeko.bot/animals/Perch.jpg +- word: Pheasant + imageUrl: https://cdn.nadeko.bot/animals/Pheasant.jpg +- word: Pig + imageUrl: https://cdn.nadeko.bot/animals/Pig.jpg +- word: Pigeon + imageUrl: https://cdn.nadeko.bot/animals/Pigeon.jpg +- word: Polar bear + imageUrl: https://cdn.nadeko.bot/animals/Polar bear.jpg +- word: Porcupine + imageUrl: https://cdn.nadeko.bot/animals/Porcupine.jpg +- word: Quail + imageUrl: https://cdn.nadeko.bot/animals/Quail.jpg +- word: Rabbit + imageUrl: https://cdn.nadeko.bot/animals/Rabbit.jpg +- word: Raccoon + imageUrl: https://cdn.nadeko.bot/animals/Raccoon.jpg +- word: Rat + imageUrl: https://cdn.nadeko.bot/animals/Rat.jpg +- word: Rattlesnake + imageUrl: https://cdn.nadeko.bot/animals/Rattlesnake.jpg +- word: Raven + imageUrl: https://cdn.nadeko.bot/animals/Raven.jpg +- word: Reindeer + imageUrl: https://cdn.nadeko.bot/animals/Reindeer.jpg +- word: Rooster + imageUrl: https://cdn.nadeko.bot/animals/Rooster.jpg +- word: Sea lion + imageUrl: https://cdn.nadeko.bot/animals/Sea lion.jpg +- word: Seal + imageUrl: https://cdn.nadeko.bot/animals/Seal.jpg +- word: Sheep + imageUrl: https://cdn.nadeko.bot/animals/Sheep.jpg +- word: Shrew + imageUrl: https://cdn.nadeko.bot/animals/Shrew.jpg +- word: Skunk + imageUrl: https://cdn.nadeko.bot/animals/Skunk.jpg +- word: Snail + imageUrl: https://cdn.nadeko.bot/animals/Snail.jpg +- word: Snake + imageUrl: https://cdn.nadeko.bot/animals/Snake.jpg +- word: Spider + imageUrl: https://cdn.nadeko.bot/animals/Spider.jpg +- word: Tiger + imageUrl: https://cdn.nadeko.bot/animals/Tiger.jpg +- word: Walrus + imageUrl: https://cdn.nadeko.bot/animals/Walrus.jpg +- word: Whale + imageUrl: https://cdn.nadeko.bot/animals/Whale.jpg +- word: Wolf + imageUrl: https://cdn.nadeko.bot/animals/Wolf.jpg +- word: Zebra + imageUrl: https://cdn.nadeko.bot/animals/Zebra diff --git a/src/EllieBot/data/hangman/anime.yml b/src/EllieBot/data/hangman/anime.yml new file mode 100644 index 0000000..f3a5368 --- /dev/null +++ b/src/EllieBot/data/hangman/anime.yml @@ -0,0 +1,766 @@ +- word: 'Fullmetal Alchemist: Brotherhood' + imageUrl: https://cdn.nadeko.bot/animu/Fullmetal_Alchemist_Brotherhood.jpg +- word: Steins;Gate + imageUrl: https://cdn.nadeko.bot/animu/SteinsGate.jpg +- word: Hunter x Hunter (2011) + imageUrl: https://cdn.nadeko.bot/animu/Hunter_x_Hunter_2011.jpg +- word: Ginga Eiyuu Densetsu + imageUrl: https://cdn.nadeko.bot/animu/Ginga_Eiyuu_Densetsu.jpg +- word: 'Fruits Basket: The Final' + imageUrl: https://cdn.nadeko.bot/animu/Fruits_Basket_The_Final.jpg +- word: Koe no Katachi + imageUrl: https://cdn.nadeko.bot/animu/Koe_no_Katachi.jpg +- word: 'Clannad: After Story' + imageUrl: https://cdn.nadeko.bot/animu/Clannad_After_Story.jpg +- word: Gintama + imageUrl: https://cdn.nadeko.bot/animu/Gintama.jpg +- word: Kimi no Na wa. + imageUrl: https://cdn.nadeko.bot/animu/Kimi_no_Na_wa..jpg +- word: 'Code Geass: Hangyaku no Lelouch R2' + imageUrl: https://cdn.nadeko.bot/animu/Code_Geass_Hangyaku_no_Lelouch_R2.jpg +- word: 'Haikyuu!!: Karasuno Koukou vs. Shiratorizawa Gakuen Koukou' + imageUrl: https://cdn.nadeko.bot/animu/Haikyuu_Karasuno_Koukou_vs._Shiratorizawa_Gakuen_Koukou.jpg +- word: Mob Psycho 100 II + imageUrl: https://cdn.nadeko.bot/animu/Mob_Psycho_100_II.jpg +- word: 'Kizumonogatari III: Reiketsu-hen' + imageUrl: https://cdn.nadeko.bot/animu/Kizumonogatari_III_Reiketsu-hen.jpg +- word: Sen to Chihiro no Kamikakushi + imageUrl: https://cdn.nadeko.bot/animu/Sen_to_Chihiro_no_Kamikakushi.jpg +- word: Violet Evergarden Movie + imageUrl: https://cdn.nadeko.bot/animu/Violet_Evergarden_Movie.jpg +- word: 'Monogatari Series: Second Season' + imageUrl: https://cdn.nadeko.bot/animu/Monogatari_Series_Second_Season.jpg +- word: Monster + imageUrl: https://cdn.nadeko.bot/animu/Monster.jpg +- word: 'Shouwa Genroku Rakugo Shinjuu: Sukeroku Futatabi-hen' + imageUrl: https://cdn.nadeko.bot/animu/Shouwa_Genroku_Rakugo_Shinjuu_Sukeroku_Futatabi-hen.jpg +- word: Cowboy Bebop + imageUrl: https://cdn.nadeko.bot/animu/Cowboy_Bebop.jpg +- word: Jujutsu Kaisen (TV) + imageUrl: https://cdn.nadeko.bot/animu/Jujutsu_Kaisen_TV.jpg +- word: 'Kimetsu no Yaiba Movie: Mugen Ressha-hen' + imageUrl: https://cdn.nadeko.bot/animu/Kimetsu_no_Yaiba_Movie_Mugen_Ressha-hen.jpg +- word: Mushishi Zoku Shou 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Mushishi_Zoku_Shou_2nd_Season.jpg +- word: Hajime no Ippo + imageUrl: https://cdn.nadeko.bot/animu/Hajime_no_Ippo.jpg +- word: Made in Abyss + imageUrl: https://cdn.nadeko.bot/animu/Made_in_Abyss.jpg +- word: 'Made in Abyss Movie 3: Fukaki Tamashii no Reimei' + imageUrl: https://cdn.nadeko.bot/animu/Made_in_Abyss_Movie_3_Fukaki_Tamashii_no_Reimei.jpg +- word: Mushishi Zoku Shou + imageUrl: https://cdn.nadeko.bot/animu/Mushishi_Zoku_Shou.jpg +- word: 'Rurouni Kenshin: Meiji Kenkaku Romantan - Tsuioku-hen' + imageUrl: https://cdn.nadeko.bot/animu/Rurouni_Kenshin_Meiji_Kenkaku_Romantan_-_Tsuioku-hen.jpg +- word: Shigatsu wa Kimi no Uso + imageUrl: https://cdn.nadeko.bot/animu/Shigatsu_wa_Kimi_no_Uso.jpg +- word: Vinland Saga + imageUrl: https://cdn.nadeko.bot/animu/Vinland_Saga.jpg +- word: 'Code Geass: Hangyaku no Lelouch' + imageUrl: https://cdn.nadeko.bot/animu/Code_Geass_Hangyaku_no_Lelouch.jpg +- word: Great Teacher Onizuka + imageUrl: https://cdn.nadeko.bot/animu/Great_Teacher_Onizuka.jpg +- word: Mononoke Hime + imageUrl: https://cdn.nadeko.bot/animu/Mononoke_Hime.jpg +- word: Mushishi + imageUrl: https://cdn.nadeko.bot/animu/Mushishi.jpg +- word: Haikyuu!! Second Season + imageUrl: https://cdn.nadeko.bot/animu/Haikyuu_Second_Season.jpg +- word: 'Kaguya-sama wa Kokurasetai?: Tensai-tachi no Renai Zunousen' + imageUrl: https://cdn.nadeko.bot/animu/Kaguya-sama_wa_Kokurasetai_Tensai-tachi_no_Renai_Zunousen.jpg +- word: 'Hajime no Ippo: New Challenger' + imageUrl: https://cdn.nadeko.bot/animu/Hajime_no_Ippo_New_Challenger.jpg +- word: Howl no Ugoku Shiro + imageUrl: https://cdn.nadeko.bot/animu/Howl_no_Ugoku_Shiro.jpg +- word: Natsume Yuujinchou Shi + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Shi.jpg +- word: Seishun Buta Yarou wa Yumemiru Shoujo no Yume wo Minai + imageUrl: https://cdn.nadeko.bot/animu/Seishun_Buta_Yarou_wa_Yumemiru_Shoujo_no_Yume_wo_Minai.jpg +- word: Tengen Toppa Gurren Lagann + imageUrl: https://cdn.nadeko.bot/animu/Tengen_Toppa_Gurren_Lagann.jpg +- word: Violet Evergarden + imageUrl: https://cdn.nadeko.bot/animu/Violet_Evergarden.jpg +- word: Natsume Yuujinchou Roku + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Roku.jpg +- word: Suzumiya Haruhi no Shoushitsu + imageUrl: https://cdn.nadeko.bot/animu/Suzumiya_Haruhi_no_Shoushitsu.jpg +- word: Death Note + imageUrl: https://cdn.nadeko.bot/animu/Death_Note.jpg +- word: Fumetsu no Anata e + imageUrl: https://cdn.nadeko.bot/animu/Fumetsu_no_Anata_e.jpg +- word: 'Mushishi Zoku Shou: Suzu no Shizuku' + imageUrl: https://cdn.nadeko.bot/animu/Mushishi_Zoku_Shou_Suzu_no_Shizuku.jpg +- word: Ookami Kodomo no Ame to Yuki + imageUrl: https://cdn.nadeko.bot/animu/Ookami_Kodomo_no_Ame_to_Yuki.jpg +- word: Ping Pong the Animation + imageUrl: https://cdn.nadeko.bot/animu/Ping_Pong_the_Animation.jpg +- word: Yakusoku no Neverland + imageUrl: https://cdn.nadeko.bot/animu/Yakusoku_no_Neverland.jpg +- word: 'Kizumonogatari II: Nekketsu-hen' + imageUrl: https://cdn.nadeko.bot/animu/Kizumonogatari_II_Nekketsu-hen.jpg +- word: Yojouhan Shinwa Taikei + imageUrl: https://cdn.nadeko.bot/animu/Yojouhan_Shinwa_Taikei.jpg +- word: Natsume Yuujinchou San + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_San.jpg +- word: Shouwa Genroku Rakugo Shinjuu + imageUrl: https://cdn.nadeko.bot/animu/Shouwa_Genroku_Rakugo_Shinjuu.jpg +- word: 'Hajime no Ippo: Rising' + imageUrl: https://cdn.nadeko.bot/animu/Hajime_no_Ippo_Rising.jpg +- word: Kimetsu no Yaiba + imageUrl: https://cdn.nadeko.bot/animu/Kimetsu_no_Yaiba.jpg +- word: Kimi no Suizou wo Tabetai + imageUrl: https://cdn.nadeko.bot/animu/Kimi_no_Suizou_wo_Tabetai.jpg +- word: Natsume Yuujinchou Go + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Go.jpg +- word: Re:Zero kara Hajimeru Isekai Seikatsu 2nd Season Part 2 + imageUrl: https://cdn.nadeko.bot/animu/ReZero_kara_Hajimeru_Isekai_Seikatsu_2nd_Season_Part_2.jpg +- word: 'Mushishi: Hihamukage' + imageUrl: https://cdn.nadeko.bot/animu/Mushishi_Hihamukage.jpg +- word: Bakuman. 3rd Season + imageUrl: https://cdn.nadeko.bot/animu/Bakuman._3rd_Season.jpg +- word: 'Kara no Kyoukai 5: Mujun Rasen' + imageUrl: https://cdn.nadeko.bot/animu/Kara_no_Kyoukai_5_Mujun_Rasen.jpg +- word: Sora yori mo Tooi Basho + imageUrl: https://cdn.nadeko.bot/animu/Sora_yori_mo_Tooi_Basho.jpg +- word: Zoku Natsume Yuujinchou + imageUrl: https://cdn.nadeko.bot/animu/Zoku_Natsume_Yuujinchou.jpg +- word: One Piece + imageUrl: https://cdn.nadeko.bot/animu/One_Piece.jpg +- word: Yuru Camp△ Season 2 + imageUrl: https://cdn.nadeko.bot/animu/Yuru_Camp_Season_2.jpg +- word: Fruits Basket 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Fruits_Basket_2nd_Season.jpg +- word: 'Haikyuu!!: To the Top 2nd Season' + imageUrl: https://cdn.nadeko.bot/animu/Haikyuu_To_the_Top_2nd_Season.jpg +- word: 'Koukaku Kidoutai: Stand Alone Complex 2nd GIG' + imageUrl: https://cdn.nadeko.bot/animu/Koukaku_Kidoutai_Stand_Alone_Complex_2nd_GIG.jpg +- word: One Punch Man + imageUrl: https://cdn.nadeko.bot/animu/One_Punch_Man.jpg +- word: 'Neon Genesis Evangelion: The End of Evangelion' + imageUrl: https://cdn.nadeko.bot/animu/Neon_Genesis_Evangelion_The_End_of_Evangelion.jpg +- word: Ansatsu Kyoushitsu 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Ansatsu_Kyoushitsu_2nd_Season.jpg +- word: Slam Dunk + imageUrl: https://cdn.nadeko.bot/animu/Slam_Dunk.jpg +- word: "Vivy: Fluorite Eye's Song" + imageUrl: https://cdn.nadeko.bot/animu/Vivy_Fluorite_Eyes_Song.jpg +- word: 'Rainbow: Nisha Rokubou no Shichinin' + imageUrl: https://cdn.nadeko.bot/animu/Rainbow_Nisha_Rokubou_no_Shichinin.jpg +- word: Shingeki no Kyojin + imageUrl: https://cdn.nadeko.bot/animu/Shingeki_no_Kyojin.jpg +- word: Uchuu Kyoudai + imageUrl: https://cdn.nadeko.bot/animu/Uchuu_Kyoudai.jpg +- word: Aria the Origination + imageUrl: https://cdn.nadeko.bot/animu/Aria_the_Origination.jpg +- word: Holo no Graffiti + imageUrl: https://cdn.nadeko.bot/animu/Holo_no_Graffiti.jpg +- word: Hotaru no Haka + imageUrl: https://cdn.nadeko.bot/animu/Hotaru_no_Haka.jpg +- word: Banana Fish + imageUrl: https://cdn.nadeko.bot/animu/Banana_Fish.jpg +- word: Chihayafuru 3 + imageUrl: https://cdn.nadeko.bot/animu/Chihayafuru_3.jpg +- word: Kenpuu Denki Berserk + imageUrl: https://cdn.nadeko.bot/animu/Kenpuu_Denki_Berserk.jpg +- word: Perfect Blue + imageUrl: https://cdn.nadeko.bot/animu/Perfect_Blue.jpg +- word: Samurai Champloo + imageUrl: https://cdn.nadeko.bot/animu/Samurai_Champloo.jpg +- word: Haikyuu!! + imageUrl: https://cdn.nadeko.bot/animu/Haikyuu.jpg +- word: Mo Dao Zu Shi + imageUrl: https://cdn.nadeko.bot/animu/Mo_Dao_Zu_Shi.jpg +- word: Mob Psycho 100 + imageUrl: https://cdn.nadeko.bot/animu/Mob_Psycho_100.jpg +- word: Zoku Owarimonogatari + imageUrl: https://cdn.nadeko.bot/animu/Zoku_Owarimonogatari.jpg +- word: Nana + imageUrl: https://cdn.nadeko.bot/animu/Nana.jpg +- word: Nichijou + imageUrl: https://cdn.nadeko.bot/animu/Nichijou.jpg +- word: Saenai Heroine no Sodatekata Fine + imageUrl: https://cdn.nadeko.bot/animu/Saenai_Heroine_no_Sodatekata_Fine.jpg +- word: 'Mushishi Zoku Shou: Odoro no Michi' + imageUrl: https://cdn.nadeko.bot/animu/Mushishi_Zoku_Shou_Odoro_no_Michi.jpg +- word: Owarimonogatari + imageUrl: https://cdn.nadeko.bot/animu/Owarimonogatari.jpg +- word: Saiki Kusuo no Ψ-nan 2 + imageUrl: https://cdn.nadeko.bot/animu/Saiki_Kusuo_no_-nan_2.jpg +- word: Yuu☆Yuu☆Hakusho + imageUrl: https://cdn.nadeko.bot/animu/YuuYuuHakusho.jpg +- word: Golden Kamuy 3rd Season + imageUrl: https://cdn.nadeko.bot/animu/Golden_Kamuy_3rd_Season.jpg +- word: 'Koukaku Kidoutai: Stand Alone Complex' + imageUrl: https://cdn.nadeko.bot/animu/Koukaku_Kidoutai_Stand_Alone_Complex.jpg +- word: Mo Dao Zu Shi 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Mo_Dao_Zu_Shi_2nd_Season.jpg +- word: Re:Zero kara Hajimeru Isekai Seikatsu 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/ReZero_kara_Hajimeru_Isekai_Seikatsu_2nd_Season.jpg +- word: Sayonara no Asa ni Yakusoku no Hana wo Kazarou + imageUrl: https://cdn.nadeko.bot/animu/Sayonara_no_Asa_ni_Yakusoku_no_Hana_wo_Kazarou.jpg +- word: Mononoke + imageUrl: https://cdn.nadeko.bot/animu/Mononoke.jpg +- word: Saiki Kusuo no Ψ-nan + imageUrl: https://cdn.nadeko.bot/animu/Saiki_Kusuo_no_-nan.jpg +- word: Gotcha! + imageUrl: https://cdn.nadeko.bot/animu/Gotcha.jpg +- word: 'Kara no Kyoukai 7: Satsujin Kousatsu (Go)' + imageUrl: https://cdn.nadeko.bot/animu/Kara_no_Kyoukai_7_Satsujin_Kousatsu_Go.jpg +- word: Kaze ga Tsuyoku Fuiteiru + imageUrl: https://cdn.nadeko.bot/animu/Kaze_ga_Tsuyoku_Fuiteiru.jpg +- word: 3-gatsu no Lion + imageUrl: https://cdn.nadeko.bot/animu/3-gatsu_no_Lion.jpg +- word: Cross Game + imageUrl: https://cdn.nadeko.bot/animu/Cross_Game.jpg +- word: Josee to Tora to Sakana-tachi + imageUrl: https://cdn.nadeko.bot/animu/Josee_to_Tora_to_Sakana-tachi.jpg +- word: Kono Oto Tomare! 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Kono_Oto_Tomare_2nd_Season.jpg +- word: 'Natsume Yuujinchou Movie: Utsusemi ni Musubu' + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Movie_Utsusemi_ni_Musubu.jpg +- word: Yahari Ore no Seishun Love Comedy wa Machigatteiru. Kan + imageUrl: https://cdn.nadeko.bot/animu/Yahari_Ore_no_Seishun_Love_Comedy_wa_Machigatteiru._Kan.jpg +- word: Non Non Biyori Nonstop + imageUrl: https://cdn.nadeko.bot/animu/Non_Non_Biyori_Nonstop.jpg +- word: Usagi Drop + imageUrl: https://cdn.nadeko.bot/animu/Usagi_Drop.jpg +- word: Baccano! + imageUrl: https://cdn.nadeko.bot/animu/Baccano.jpg +- word: Chihayafuru 2 + imageUrl: https://cdn.nadeko.bot/animu/Chihayafuru_2.jpg +- word: 'Douluo Dalu: Xiaowu Juebie' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Xiaowu_Juebie.jpg +- word: Grand Blue + imageUrl: https://cdn.nadeko.bot/animu/Grand_Blue.jpg +- word: Houseki no Kuni (TV) + imageUrl: https://cdn.nadeko.bot/animu/Houseki_no_Kuni_TV.jpg +- word: Hunter x Hunter + imageUrl: https://cdn.nadeko.bot/animu/Hunter_x_Hunter.jpg +- word: 'Kaguya-sama wa Kokurasetai: Tensai-tachi no Renai Zunousen' + imageUrl: https://cdn.nadeko.bot/animu/Kaguya-sama_wa_Kokurasetai_Tensai-tachi_no_Renai_Zunousen.jpg +- word: Barakamon + imageUrl: https://cdn.nadeko.bot/animu/Barakamon.jpg +- word: 'Kizumonogatari I: Tekketsu-hen' + imageUrl: https://cdn.nadeko.bot/animu/Kizumonogatari_I_Tekketsu-hen.jpg +- word: 'Mushoku Tensei: Isekai Ittara Honki Dasu' + imageUrl: https://cdn.nadeko.bot/animu/Mushoku_Tensei_Isekai_Ittara_Honki_Dasu.jpg +- word: Natsume Yuujinchou Roku Specials + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Roku_Specials.jpg +- word: 'Violet Evergarden Gaiden: Eien to Jidou Shuki Ningyou' + imageUrl: https://cdn.nadeko.bot/animu/Violet_Evergarden_Gaiden_Eien_to_Jidou_Shuki_Ningyou.jpg +- word: Shiguang Daili Ren + imageUrl: https://cdn.nadeko.bot/animu/Shiguang_Daili_Ren.jpg +- word: Tensei shitara Slime Datta Ken 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Tensei_shitara_Slime_Datta_Ken_2nd_Season.jpg +- word: Ano Hi Mita Hana no Namae wo Bokutachi wa Mada Shiranai. + imageUrl: https://cdn.nadeko.bot/animu/Ano_Hi_Mita_Hana_no_Namae_wo_Bokutachi_wa_Mada_Shiranai..jpg +- word: 'Cowboy Bebop: Tengoku no Tobira' + imageUrl: https://cdn.nadeko.bot/animu/Cowboy_Bebop_Tengoku_no_Tobira.jpg +- word: Hellsing Ultimate + imageUrl: https://cdn.nadeko.bot/animu/Hellsing_Ultimate.jpg +- word: Kaze no Tani no Nausica + imageUrl: https://cdn.nadeko.bot/animu/Kaze_no_Tani_no_Nausica.jpg +- word: Luo Xiao Hei Zhan Ji (Movie) + imageUrl: https://cdn.nadeko.bot/animu/Luo_Xiao_Hei_Zhan_Ji_Movie.jpg +- word: Bakuman. 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Bakuman._2nd_Season.jpg +- word: 'Kiseijuu: Sei no Kakuritsu' + imageUrl: https://cdn.nadeko.bot/animu/Kiseijuu_Sei_no_Kakuritsu.jpg +- word: 'Kamisama Hajimemashita: Kako-hen' + imageUrl: https://cdn.nadeko.bot/animu/Kamisama_Hajimemashita_Kako-hen.jpg +- word: Kingdom 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Kingdom_2nd_Season.jpg +- word: Kingdom 3rd Season + imageUrl: https://cdn.nadeko.bot/animu/Kingdom_3rd_Season.jpg +- word: Mahou Shoujo Madoka Magica + imageUrl: https://cdn.nadeko.bot/animu/Mahou_Shoujo_MadokaMagica.jpg +- word: Psycho-Pass + imageUrl: https://cdn.nadeko.bot/animu/Psycho-Pass.jpg +- word: Tenki no Ko + imageUrl: https://cdn.nadeko.bot/animu/Tenki_no_Ko.jpg +- word: Heaven Official's Blessing + imageUrl: https://cdn.nadeko.bot/animu/Tian_Guan_Ci_Fu.jpg +- word: Uchuu Senkan Yamato 2199 + imageUrl: https://cdn.nadeko.bot/animu/Uchuu_Senkan_Yamato_2199.jpg +- word: 'Haikyuu!!: To the Top' + imageUrl: https://cdn.nadeko.bot/animu/Haikyuu_To_the_Top.jpg +- word: Bakemonogatari + imageUrl: https://cdn.nadeko.bot/animu/Bakemonogatari.jpg +- word: Given + imageUrl: https://cdn.nadeko.bot/animu/Given.jpg +- word: Hotarubi no Mori e + imageUrl: https://cdn.nadeko.bot/animu/Hotarubi_no_Mori_e.jpg +- word: Katanagatari + imageUrl: https://cdn.nadeko.bot/animu/Katanagatari.jpg +- word: 'Natsume Yuujinchou: Itsuka Yuki no Hi ni' + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Itsuka_Yuki_no_Hi_ni.jpg +- word: One Outs + imageUrl: https://cdn.nadeko.bot/animu/One_Outs.jpg +- word: Ookami to Koushinryou II + imageUrl: https://cdn.nadeko.bot/animu/Ookami_to_Koushinryou_II.jpg +- word: Romeo no Aoi Sora + imageUrl: https://cdn.nadeko.bot/animu/Romeo_no_Aoi_Sora.jpg +- word: Sakamichi no Apollon + imageUrl: https://cdn.nadeko.bot/animu/Sakamichi_no_Apollon.jpg +- word: Seishun Buta Yarou wa Bunny Girl Senpai no Yume wo Minai + imageUrl: https://cdn.nadeko.bot/animu/Seishun_Buta_Yarou_wa_Bunny_Girl_Senpai_no_Yume_wo_Minai.jpg +- word: Boku dake ga Inai Machi + imageUrl: https://cdn.nadeko.bot/animu/Boku_dake_ga_Inai_Machi.jpg +- word: 'Evangelion: 2.0 You Can (Not) Advance' + imageUrl: https://cdn.nadeko.bot/animu/Evangelion_2.0_You_Can_Not_Advance.jpg +- word: Kemono no Souja Erin + imageUrl: https://cdn.nadeko.bot/animu/Kemono_no_Souja_Erin.jpg +- word: 'Made in Abyss Movie 2: Hourou Suru Tasogare' + imageUrl: https://cdn.nadeko.bot/animu/Made_in_Abyss_Movie_2_Hourou_Suru_Tasogare.jpg +- word: 'Major: World Series' + imageUrl: https://cdn.nadeko.bot/animu/Major_World_Series.jpg +- word: Doukyuusei (Movie) + imageUrl: https://cdn.nadeko.bot/animu/Doukyuusei_Movie.jpg +- word: K-On! Movie + imageUrl: https://cdn.nadeko.bot/animu/K-On_Movie.jpg +- word: Natsume Yuujinchou + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou.jpg +- word: Natsume Yuujinchou Go Specials + imageUrl: https://cdn.nadeko.bot/animu/Natsume_Yuujinchou_Go_Specials.jpg +- word: NHK ni Youkoso! + imageUrl: https://cdn.nadeko.bot/animu/NHK_ni_Youkoso.jpg +- word: Shelter + imageUrl: https://cdn.nadeko.bot/animu/Shelter.jpg +- word: Shinsekai yori + imageUrl: https://cdn.nadeko.bot/animu/Shinsekai_yori.jpg +- word: Shirobako + imageUrl: https://cdn.nadeko.bot/animu/Shirobako.jpg +- word: Versailles no Bara + imageUrl: https://cdn.nadeko.bot/animu/Versailles_no_Bara.jpg +- word: Neon Genesis Evangelion + imageUrl: https://cdn.nadeko.bot/animu/Neon_Genesis_Evangelion.jpg +- word: Dr. Stone + imageUrl: https://cdn.nadeko.bot/animu/Dr._Stone.jpg +- word: Fate/Zero + imageUrl: https://cdn.nadeko.bot/animu/FateZero.jpg +- word: Great Pretender + imageUrl: https://cdn.nadeko.bot/animu/Great_Pretender.jpg +- word: 'Hunter x Hunter: Original Video Animation' + imageUrl: https://cdn.nadeko.bot/animu/Hunter_x_Hunter_Original_Video_Animation.jpg +- word: 'Kino no Tabi: The Beautiful World' + imageUrl: https://cdn.nadeko.bot/animu/Kino_no_Tabi_The_Beautiful_World.jpg +- word: Kuroko no Basket 3rd Season + imageUrl: https://cdn.nadeko.bot/animu/Kuroko_no_Basket_3rd_Season.jpg +- word: Bakemono no Ko + imageUrl: https://cdn.nadeko.bot/animu/Bakemono_no_Ko.jpg +- word: Beck + imageUrl: https://cdn.nadeko.bot/animu/Beck.jpg +- word: 'Diamond no Ace: Second Season' + imageUrl: https://cdn.nadeko.bot/animu/Diamond_no_Ace_Second_Season.jpg +- word: Nodame Cantabile + imageUrl: https://cdn.nadeko.bot/animu/Nodame_Cantabile.jpg +- word: 'Rurouni Kenshin: Meiji Kenkaku Romantan' + imageUrl: https://cdn.nadeko.bot/animu/Rurouni_Kenshin_Meiji_Kenkaku_Romantan.jpg +- word: 'Tsubasa: Tokyo Revelations' + imageUrl: https://cdn.nadeko.bot/animu/Tsubasa_Tokyo_Revelations.jpg +- word: 'Violet Evergarden: Kitto "Ai" wo Shiru Hi ga Kuru no Darou' + imageUrl: https://cdn.nadeko.bot/animu/Violet_Evergarden_Kitto_Ai_wo_Shiru_Hi_ga_Kuru_no_Darou.jpg +- word: Planetes + imageUrl: https://cdn.nadeko.bot/animu/Planetes.jpg +- word: 'Stranger: Mukou Hadan' + imageUrl: https://cdn.nadeko.bot/animu/Stranger_Mukou_Hadan.jpg +- word: Yuukoku no Moriarty 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Yuukoku_no_Moriarty_2nd_Season.jpg +- word: Gin no Saji 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Gin_no_Saji_2nd_Season.jpg +- word: Hibike! Euphonium 2 + imageUrl: https://cdn.nadeko.bot/animu/Hibike_Euphonium_2.jpg +- word: Initial D First Stage + imageUrl: https://cdn.nadeko.bot/animu/Initial_D_First_Stage.jpg +- word: Kawaki wo Ameku + imageUrl: https://cdn.nadeko.bot/animu/Kawaki_wo_Ameku.jpg +- word: Koukaku Kidoutai + imageUrl: https://cdn.nadeko.bot/animu/Koukaku_Kidoutai.jpg +- word: Redline + imageUrl: https://cdn.nadeko.bot/animu/Redline.jpg +- word: Tenkuu no Shiro Laputa + imageUrl: https://cdn.nadeko.bot/animu/Tenkuu_no_Shiro_Laputa.jpg +- word: Tokyo Godfathers + imageUrl: https://cdn.nadeko.bot/animu/Tokyo_Godfathers.jpg +- word: Tonari no Totoro + imageUrl: https://cdn.nadeko.bot/animu/Tonari_no_Totoro.jpg +- word: 'No Game No Life: Zero' + imageUrl: https://cdn.nadeko.bot/animu/No_Game_No_Life_Zero.jpg +- word: 'Nomad: Megalo Box 2' + imageUrl: https://cdn.nadeko.bot/animu/Nomad_Megalo_Box_2.jpg +- word: Quanzhi Gaoshou Specials + imageUrl: https://cdn.nadeko.bot/animu/Quanzhi_Gaoshou_Specials.jpg +- word: Ashita no Joe + imageUrl: https://cdn.nadeko.bot/animu/Ashita_no_Joe.jpg +- word: 'Douluo Dalu: Xingdou Xian Ji Pian' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Xingdou_Xian_Ji_Pian.jpg +- word: 'Gyakkyou Burai Kaiji: Ultimate Survivor' + imageUrl: https://cdn.nadeko.bot/animu/Gyakkyou_Burai_Kaiji_Ultimate_Survivor.jpg +- word: 'Hajime no Ippo: Champion Road' + imageUrl: https://cdn.nadeko.bot/animu/Hajime_no_Ippo_Champion_Road.jpg +- word: 'Hunter x Hunter: Greed Island Final' + imageUrl: https://cdn.nadeko.bot/animu/Hunter_x_Hunter_Greed_Island_Final.jpg +- word: Re:Zero kara Hajimeru Isekai Seikatsu + imageUrl: https://cdn.nadeko.bot/animu/ReZero_kara_Hajimeru_Isekai_Seikatsu.jpg +- word: Sennen Joyuu + imageUrl: https://cdn.nadeko.bot/animu/Sennen_Joyuu.jpg +- word: Stand By Me Doraemon 2 + imageUrl: https://cdn.nadeko.bot/animu/Stand_By_Me_Doraemon_2.jpg +- word: Yuru Camp + imageUrl: https://cdn.nadeko.bot/animu/Yuru_Camp.jpg +- word: 'Nodame Cantabile: Finale' + imageUrl: https://cdn.nadeko.bot/animu/Nodame_Cantabile_Finale.jpg +- word: Ookami to Koushinryou + imageUrl: https://cdn.nadeko.bot/animu/Ookami_to_Koushinryou.jpg +- word: Space Dandy 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/SpaceDandy_2nd_Season.jpg +- word: Youjo Senki Movie + imageUrl: https://cdn.nadeko.bot/animu/Youjo_Senki_Movie.jpg +- word: Boku no Hero Academia 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Boku_no_Hero_Academia_2nd_Season.jpg +- word: Danshi Koukousei no Nichijou + imageUrl: https://cdn.nadeko.bot/animu/Danshi_Koukousei_no_Nichijou.jpg +- word: Kuroko no Basket 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Kuroko_no_Basket_2nd_Season.jpg +- word: 'Magi: The Kingdom of Magic' + imageUrl: https://cdn.nadeko.bot/animu/Magi_The_Kingdom_of_Magic.jpg +- word: 'Douluo Dalu: Hanhai Qian Kun' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Hanhai_Qian_Kun.jpg +- word: 'Gyakkyou Burai Kaiji: Hakairoku-hen' + imageUrl: https://cdn.nadeko.bot/animu/Gyakkyou_Burai_Kaiji_Hakairoku-hen.jpg +- word: Hachimitsu to Clover II + imageUrl: https://cdn.nadeko.bot/animu/Hachimitsu_to_Clover_II.jpg +- word: Horimiya + imageUrl: https://cdn.nadeko.bot/animu/Horimiya.jpg +- word: 'Kuroshitsuji Movie: Book of the Atlantic' + imageUrl: https://cdn.nadeko.bot/animu/Kuroshitsuji_Movie_Book_of_the_Atlantic.jpg +- word: 'Non Non Biyori Movie: Vacation' + imageUrl: https://cdn.nadeko.bot/animu/Non_Non_Biyori_Movie_Vacation.jpg +- word: Wu Liuqi Zhi Zui Qiang Fa Xing Shi + imageUrl: https://cdn.nadeko.bot/animu/Wu_Liuqi_Zhi_Zui_Qiang_Fa_Xing_Shi.jpg +- word: Yahari Ore no Seishun Love Comedy wa Machigatteiru. Zoku + imageUrl: https://cdn.nadeko.bot/animu/Yahari_Ore_no_Seishun_Love_Comedy_wa_Machigatteiru._Zoku.jpg +- word: Shokugeki no Souma + imageUrl: https://cdn.nadeko.bot/animu/Shokugeki_no_Souma.jpg +- word: SKET Dance + imageUrl: https://cdn.nadeko.bot/animu/SKET_Dance.jpg +- word: Wu Liuqi Zhi Xuanwu Guo Pian + imageUrl: https://cdn.nadeko.bot/animu/Wu_Liuqi_Zhi_Xuanwu_Guo_Pian.jpg +- word: xxxHOLiC Kei + imageUrl: https://cdn.nadeko.bot/animu/xxxHOLiC_Kei.jpg +- word: Initial D Final Stage + imageUrl: https://cdn.nadeko.bot/animu/Initial_D_Final_Stage.jpg +- word: 'Diamond no Ace: Act II' + imageUrl: https://cdn.nadeko.bot/animu/Diamond_no_Ace_Act_II.jpg +- word: 'Hajime no Ippo: Mashiba vs. Kimura' + imageUrl: https://cdn.nadeko.bot/animu/Hajime_no_Ippo_Mashiba_vs._Kimura.jpg +- word: Kono Sekai no Katasumi ni + imageUrl: https://cdn.nadeko.bot/animu/Kono_Sekai_no_Katasumi_ni.jpg +- word: Majo no Takkyuubin + imageUrl: https://cdn.nadeko.bot/animu/Majo_no_Takkyuubin.jpg +- word: Mimi wo Sumaseba + imageUrl: https://cdn.nadeko.bot/animu/Mimi_wo_Sumaseba.jpg +- word: Trigun + imageUrl: https://cdn.nadeko.bot/animu/Trigun.jpg +- word: 'ReLIFE: Kanketsu-hen' + imageUrl: https://cdn.nadeko.bot/animu/ReLIFE_Kanketsu-hen.jpg +- word: Toaru Kagaku no Railgun T + imageUrl: https://cdn.nadeko.bot/animu/Toaru_Kagaku_no_Railgun_T.jpg +- word: xxxHOLiC Rou + imageUrl: https://cdn.nadeko.bot/animu/xxxHOLiC_Rou.jpg +- word: Yoru wa Mijikashi Arukeyo Otome + imageUrl: https://cdn.nadeko.bot/animu/Yoru_wa_Mijikashi_Arukeyo_Otome.jpg +- word: Bakuman. + imageUrl: https://cdn.nadeko.bot/animu/Bakuman..jpg +- word: 'Cardcaptor Sakura Movie 2: Fuuin Sareta Card' + imageUrl: https://cdn.nadeko.bot/animu/Cardcaptor_Sakura_Movie_2_Fuuin_Sareta_Card.jpg +- word: Chihayafuru + imageUrl: https://cdn.nadeko.bot/animu/Chihayafuru.jpg +- word: 'Douluo Dalu: Qian Hua Xi Jin' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Qian_Hua_Xi_Jin.jpg +- word: 'Ginga Eiyuu Densetsu: Die Neue These - Seiran 3' + imageUrl: https://cdn.nadeko.bot/animu/Ginga_Eiyuu_Densetsu_Die_Neue_These_-_Seiran_3.jpg +- word: Kaguya-hime no Monogatari + imageUrl: https://cdn.nadeko.bot/animu/Kaguya-hime_no_Monogatari.jpg +- word: 'Little Busters!: Refrain' + imageUrl: https://cdn.nadeko.bot/animu/Little_Busters_Refrain.jpg +- word: Dororo + imageUrl: https://cdn.nadeko.bot/animu/Dororo.jpg +- word: 'Dr. Stone: Stone Wars' + imageUrl: https://cdn.nadeko.bot/animu/Dr._Stone_Stone_Wars.jpg +- word: 'Fate/stay night: Unlimited Blade Works' + imageUrl: https://cdn.nadeko.bot/animu/Fatestay_night_Unlimited_Blade_Works.jpg +- word: Girls & Panzer Movie + imageUrl: https://cdn.nadeko.bot/animu/Girls__Panzer_Movie.jpg +- word: Golden Kamuy 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Golden_Kamuy_2nd_Season.jpg +- word: Higurashi no Naku Koro ni Kai + imageUrl: https://cdn.nadeko.bot/animu/Higurashi_no_Naku_Koro_ni_Kai.jpg +- word: 'InuYasha: Kanketsu-hen' + imageUrl: https://cdn.nadeko.bot/animu/InuYasha_Kanketsu-hen.jpg +- word: 'Saiki Kusuo no Ψ-nan: Kanketsu-hen' + imageUrl: https://cdn.nadeko.bot/animu/Saiki_Kusuo_no_-nan_Kanketsu-hen.jpg +- word: 'One Piece Movie 14: Stampede' + imageUrl: https://cdn.nadeko.bot/animu/One_Piece_Movie_14_Stampede.jpg +- word: 'One Piece: Episode of Merry - Mou Hitori no Nakama no Monogatari' + imageUrl: https://cdn.nadeko.bot/animu/One_Piece_Episode_of_Merry_-_Mou_Hitori_no_Nakama_no_Monogatari.jpg +- word: Shoujo Kakumei Utena + imageUrl: https://cdn.nadeko.bot/animu/Shoujo_Kakumei_Utena.jpg +- word: Ballroom e Youkoso + imageUrl: https://cdn.nadeko.bot/animu/Ballroom_e_Youkoso.jpg +- word: 'Berserk: Ougon Jidai-hen III - Kourin' + imageUrl: https://cdn.nadeko.bot/animu/Berserk_Ougon_Jidai-hen_III_-_Kourin.jpg +- word: Bungou Stray Dogs 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/Bungou_Stray_Dogs_2nd_Season.jpg +- word: 'Douluo Dalu: Haishen Zhi Guang' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Haishen_Zhi_Guang.jpg +- word: Fruits Basket 1st Season + imageUrl: https://cdn.nadeko.bot/animu/Fruits_Basket_1st_Season.jpg +- word: 'Hunter x Hunter: Greed Island' + imageUrl: https://cdn.nadeko.bot/animu/Hunter_x_Hunter_Greed_Island.jpg +- word: Liz to Aoi Tori + imageUrl: https://cdn.nadeko.bot/animu/Liz_to_Aoi_Tori.jpg +- word: Aria the Natural + imageUrl: https://cdn.nadeko.bot/animu/Aria_the_Natural.jpg +- word: Asobi Asobase + imageUrl: https://cdn.nadeko.bot/animu/Asobi_Asobase.jpg +- word: 'Black Lagoon: The Second Barrage' + imageUrl: https://cdn.nadeko.bot/animu/Black_Lagoon_The_Second_Barrage.jpg +- word: Bungou Stray Dogs 3rd Season + imageUrl: https://cdn.nadeko.bot/animu/Bungou_Stray_Dogs_3rd_Season.jpg +- word: Death Parade + imageUrl: https://cdn.nadeko.bot/animu/Death_Parade.jpg +- word: 'Digimon Adventure: Last Evolution Kizuna' + imageUrl: https://cdn.nadeko.bot/animu/Digimon_Adventure_Last_Evolution_Kizuna.jpg +- word: Hinamatsuri (TV) + imageUrl: https://cdn.nadeko.bot/animu/Hinamatsuri_TV.jpg +- word: "Kyoukai no Kanata Movie 2: I'll Be Here - Mirai-hen" + imageUrl: https://cdn.nadeko.bot/animu/Kyoukai_no_Kanata_Movie_2_Ill_Be_Here_-_Mirai-hen.jpg +- word: Maison Ikkoku + imageUrl: https://cdn.nadeko.bot/animu/Maison_Ikkoku.jpg +- word: 'Naruto: Shippuuden' + imageUrl: https://cdn.nadeko.bot/animu/Naruto_Shippuuden.jpg +- word: Non Non Biyori Repeat + imageUrl: https://cdn.nadeko.bot/animu/Non_Non_Biyori_Repeat.jpg +- word: Noragami Aragoto + imageUrl: https://cdn.nadeko.bot/animu/Noragami_Aragoto.jpg +- word: Ouran Koukou Host Club + imageUrl: https://cdn.nadeko.bot/animu/Ouran_Koukou_Host_Club.jpg +- word: Senki Zesshou Symphogear XV + imageUrl: https://cdn.nadeko.bot/animu/Senki_Zesshou_Symphogear_XV.jpg +- word: Shoujo Shuumatsu Ryokou + imageUrl: https://cdn.nadeko.bot/animu/Shoujo_Shuumatsu_Ryokou.jpg +- word: Toradora! + imageUrl: https://cdn.nadeko.bot/animu/Toradora.jpg +- word: 'Working!!!: Lord of the Takanashi' + imageUrl: https://cdn.nadeko.bot/animu/Working_Lord_of_the_Takanashi.jpg +- word: Boku no Hero Academia 3rd Season + imageUrl: https://cdn.nadeko.bot/animu/Boku_no_Hero_Academia_3rd_Season.jpg +- word: 'Douluo Dalu: Jingying Sai' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Jingying_Sai.jpg +- word: 5-toubun no Hanayome ∬ + imageUrl: https://cdn.nadeko.bot/animu/5-toubun_no_Hanayome_.jpg +- word: Akira + imageUrl: https://cdn.nadeko.bot/animu/Akira.jpg +- word: Gankutsuou + imageUrl: https://cdn.nadeko.bot/animu/Gankutsuou.jpg +- word: Kamisama Hajimemashita◎ + imageUrl: https://cdn.nadeko.bot/animu/Kamisama_Hajimemashita.jpg +- word: 'Lupin III: Part 5' + imageUrl: https://cdn.nadeko.bot/animu/Lupin_III_Part_5.jpg +- word: Mo Dao Zu Shi Q + imageUrl: https://cdn.nadeko.bot/animu/Mo_Dao_Zu_Shi_Q.jpg +- word: Nisemonogatari + imageUrl: https://cdn.nadeko.bot/animu/Nisemonogatari.jpg +- word: 'One Piece Film: Z' + imageUrl: https://cdn.nadeko.bot/animu/One_Piece_Film_Z.jpg +- word: Quanzhi Gaoshou Zhi Dianfeng Rongyao + imageUrl: https://cdn.nadeko.bot/animu/Quanzhi_Gaoshou_Zhi_Dianfeng_Rongyao.jpg +- word: Toki wo Kakeru Shoujo + imageUrl: https://cdn.nadeko.bot/animu/Toki_wo_Kakeru_Shoujo.jpg +- word: No Game No Life + imageUrl: https://cdn.nadeko.bot/animu/No_Game_No_Life.jpg +- word: 'Nodame Cantabile: Paris-hen' + imageUrl: https://cdn.nadeko.bot/animu/Nodame_Cantabile_Paris-hen.jpg +- word: Sakura-sou no Pet na Kanojo + imageUrl: https://cdn.nadeko.bot/animu/Sakura-sou_no_Pet_na_Kanojo.jpg +- word: Seirei no Moribito + imageUrl: https://cdn.nadeko.bot/animu/Seirei_no_Moribito.jpg +- word: 'Shokugeki no Souma: Ni no Sara' + imageUrl: https://cdn.nadeko.bot/animu/Shokugeki_no_Souma_Ni_no_Sara.jpg +- word: Cardcaptor Sakura + imageUrl: https://cdn.nadeko.bot/animu/Cardcaptor_Sakura.jpg +- word: Detective Conan + imageUrl: https://cdn.nadeko.bot/animu/Detective_Conan.jpg +- word: Durarara!! + imageUrl: https://cdn.nadeko.bot/animu/Durarara.jpg +- word: Eizouken ni wa Te wo Dasu na! + imageUrl: https://cdn.nadeko.bot/animu/Eizouken_ni_wa_Te_wo_Dasu_na.jpg +- word: Fate/Grand Carnival + imageUrl: https://cdn.nadeko.bot/animu/FateGrand_Carnival.jpg +- word: Kaiba + imageUrl: https://cdn.nadeko.bot/animu/Kaiba.jpg +- word: Katekyo Hitman Reborn! + imageUrl: https://cdn.nadeko.bot/animu/Katekyo_Hitman_Reborn.jpg +- word: "Mahou Shoujo Lyrical Nanoha: The Movie 2nd A's" + imageUrl: https://cdn.nadeko.bot/animu/Mahou_Shoujo_Lyrical_Nanoha_The_Movie_2nd_As.jpg +- word: Dragon Ball Z + imageUrl: https://cdn.nadeko.bot/animu/Dragon_Ball_Z.jpg +- word: Fullmetal Alchemist + imageUrl: https://cdn.nadeko.bot/animu/Fullmetal_Alchemist.jpg +- word: Ginga Eiyuu Densetsu Gaiden + imageUrl: https://cdn.nadeko.bot/animu/Ginga_Eiyuu_Densetsu_Gaiden.jpg +- word: Given Movie + imageUrl: https://cdn.nadeko.bot/animu/Given_Movie.jpg +- word: K-On!! + imageUrl: https://cdn.nadeko.bot/animu/K-On.jpg +- word: 'Lupin III: Cagliostro no Shiro' + imageUrl: https://cdn.nadeko.bot/animu/Lupin_III_Cagliostro_no_Shiro.jpg +- word: 'One Piece Film: Strong World' + imageUrl: https://cdn.nadeko.bot/animu/One_Piece_Film_Strong_World.jpg +- word: Tanoshii Muumin Ikka + imageUrl: https://cdn.nadeko.bot/animu/Tanoshii_Muumin_Ikka.jpg +- word: 'One Piece: Episode of Nami - Koukaishi no Namida to Nakama no Kizuna' + imageUrl: https://cdn.nadeko.bot/animu/One_Piece_Episode_of_Nami_-_Koukaishi_no_Namida_to_Nakama_no_Kizuna.jpg +- word: Princess Tutu + imageUrl: https://cdn.nadeko.bot/animu/Princess_Tutu.jpg +- word: Tokyo Revengers + imageUrl: https://cdn.nadeko.bot/animu/Tokyo_Revengers.jpg +- word: Tsuki ga Kirei + imageUrl: https://cdn.nadeko.bot/animu/Tsuki_ga_Kirei.jpg +- word: 'Chuunibyou demo Koi ga Shitai! Movie: Take On Me' + imageUrl: https://cdn.nadeko.bot/animu/Chuunibyou_demo_Koi_ga_Shitai_Movie_Take_On_Me.jpg +- word: 'Douluo Dalu: Hao Tian Yang Wei' + imageUrl: https://cdn.nadeko.bot/animu/Douluo_Dalu_Hao_Tian_Yang_Wei.jpg +- word: 'Honzuki no Gekokujou: Shisho ni Naru Tame ni wa Shudan wo Erandeiraremasen 2nd Season' + imageUrl: https://cdn.nadeko.bot/animu/Honzuki_no_Gekokujou_Shisho_ni_Naru_Tame_ni_wa_Shudan_wo_Erandeiraremasen_2nd_Season.jpg +- word: Initial D Fourth Stage + imageUrl: https://cdn.nadeko.bot/animu/Initial_D_Fourth_Stage.jpg +- word: 'Interstella5555: The 5tory of The 5ecret 5tar 5ystem' + imageUrl: https://cdn.nadeko.bot/animu/Interstella5555_The_5tory_of_The_5ecret_5tar_5ystem.jpg +- word: Kono Subarashii Sekai ni Shukufuku wo! + imageUrl: https://cdn.nadeko.bot/animu/Kono_Subarashii_Sekai_ni_Shukufuku_wo.jpg +- word: 'Made in Abyss Movie 1: Tabidachi no Yoake' + imageUrl: https://cdn.nadeko.bot/animu/Made_in_Abyss_Movie_1_Tabidachi_no_Yoake.jpg +- word: Baccano! Specials + imageUrl: https://cdn.nadeko.bot/animu/Baccano_Specials.jpg +- word: Detroit Metal City + imageUrl: https://cdn.nadeko.bot/animu/Detroit_Metal_City.jpg +- word: Hyouka + imageUrl: https://cdn.nadeko.bot/animu/Hyouka.jpg +- word: Kanata no Astra + imageUrl: https://cdn.nadeko.bot/animu/Kanata_no_Astra.jpg +- word: 'Koukaku Kidoutai: Stand Alone Complex - Solid State Society' + imageUrl: https://cdn.nadeko.bot/animu/Koukaku_Kidoutai_Stand_Alone_Complex_-_Solid_State_Society.jpg +- word: Kuragehime + imageUrl: https://cdn.nadeko.bot/animu/Kuragehime.jpg +- word: 'Mahoutsukai no Yome: Hoshi Matsu Hito' + imageUrl: https://cdn.nadeko.bot/animu/Mahoutsukai_no_Yome_Hoshi_Matsu_Hito.jpg +- word: Mobile Suit Gundam 00 + imageUrl: https://cdn.nadeko.bot/animu/Mobile_Suit_Gundam_00.jpg +- word: Tsukimonogatari + imageUrl: https://cdn.nadeko.bot/animu/Tsukimonogatari.jpg +- word: Uchouten Kazoku 2 + imageUrl: https://cdn.nadeko.bot/animu/Uchouten_Kazoku_2.jpg +- word: Pui Pui Molcar + imageUrl: https://cdn.nadeko.bot/animu/Pui_Pui_Molcar.jpg +- word: 'Saiki Kusuo no Ψ-nan: Ψ-shidou-hen' + imageUrl: https://cdn.nadeko.bot/animu/Saiki_Kusuo_no_-nan_-shidou-hen.jpg +- word: 'Tsubasa: Shunraiki' + imageUrl: https://cdn.nadeko.bot/animu/Tsubasa_Shunraiki.jpg +- word: Zankyou no Terror + imageUrl: https://cdn.nadeko.bot/animu/Zankyou_no_Terror.jpg +- word: Angel Beats! + imageUrl: https://cdn.nadeko.bot/animu/Angel_Beats.jpg +- word: 'Ginga Eiyuu Densetsu: Arata Naru Tatakai no Overture' + imageUrl: https://cdn.nadeko.bot/animu/Ginga_Eiyuu_Densetsu_Arata_Naru_Tatakai_no_Overture.jpg +- word: 'IDOLiSH7: Second Beat!' + imageUrl: https://cdn.nadeko.bot/animu/IDOLiSH7_Second_Beat.jpg +- word: Initial D Second Stage + imageUrl: https://cdn.nadeko.bot/animu/Initial_D_Second_Stage.jpg +- word: Kuroko no Basket + imageUrl: https://cdn.nadeko.bot/animu/Kuroko_no_Basket.jpg +- word: Ansatsu Kyoushitsu + imageUrl: https://cdn.nadeko.bot/animu/Ansatsu_Kyoushitsu.jpg +- word: Diamond no Ace + imageUrl: https://cdn.nadeko.bot/animu/Diamond_no_Ace.jpg +- word: 'Dragon Ball Super: Broly' + imageUrl: https://cdn.nadeko.bot/animu/Dragon_Ball_Super_Broly.jpg +- word: 'Haikyuu!! Movie 4: Concept no Tatakai' + imageUrl: https://cdn.nadeko.bot/animu/Haikyuu_Movie_4_Concept_no_Tatakai.jpg +- word: Karakai Jouzu no Takagi-san 2 + imageUrl: https://cdn.nadeko.bot/animu/Karakai_Jouzu_no_Takagi-san_2.jpg +- word: Kaze Tachinu + imageUrl: https://cdn.nadeko.bot/animu/Kaze_Tachinu.jpg +- word: Skip Beat! + imageUrl: https://cdn.nadeko.bot/animu/Skip_Beat.jpg +- word: 'Saint Seiya: The Lost Canvas - Meiou Shinwa 2' + imageUrl: https://cdn.nadeko.bot/animu/Saint_Seiya_The_Lost_Canvas_-_Meiou_Shinwa_2.jpg +- word: 'Tamayura: Sotsugyou Shashin Part 4 - Ashita' + imageUrl: https://cdn.nadeko.bot/animu/Tamayura_Sotsugyou_Shashin_Part_4_-_Ashita.jpg +- word: Wonder Egg Priority + imageUrl: https://cdn.nadeko.bot/animu/Wonder_Egg_Priority.jpg +- word: World Trigger 2nd Season + imageUrl: https://cdn.nadeko.bot/animu/World_Trigger_2nd_Season.jpg +- word: 'Yowamushi Pedal: Grande Road' + imageUrl: https://cdn.nadeko.bot/animu/Yowamushi_Pedal_Grande_Road.jpg +- word: 'Darker than Black: Kuro no Keiyakusha' + imageUrl: https://cdn.nadeko.bot/animu/Darker_than_Black_Kuro_no_Keiyakusha.jpg +- word: 'Evangelion: 3.0+1.0 Thrice Upon a Time' + imageUrl: https://cdn.nadeko.bot/animu/Evangelion_3.01.0_Thrice_Upon_a_Time.jpg +- word: Gin no Saji + imageUrl: https://cdn.nadeko.bot/animu/Gin_no_Saji.jpg +- word: 'Hajime no Ippo: Boxer no Kobushi' + imageUrl: https://cdn.nadeko.bot/animu/Hajime_no_Ippo_Boxer_no_Kobushi.jpg +- word: Hikaru no Go + imageUrl: https://cdn.nadeko.bot/animu/Hikaru_no_Go.jpg +- word: 'JoJo no Kimyou na Bouken Part 3: Stardust Crusaders' + imageUrl: https://cdn.nadeko.bot/animu/JoJo_no_Kimyou_na_Bouken_Part_3_Stardust_Crusaders.jpg +- word: 'Kamisama Hajimemashita: Kamisama, Shiawase ni Naru' + imageUrl: https://cdn.nadeko.bot/animu/Kamisama_Hajimemashita_Kamisama_Shiawase_ni_Naru.jpg +- word: 'Kuroko no Basket: Saikou no Present Desu' + imageUrl: https://cdn.nadeko.bot/animu/Kuroko_no_Basket_Saikou_no_Present_Desu.jpg +- word: 'Kuroshitsuji: Book of Circus' + imageUrl: https://cdn.nadeko.bot/animu/Kuroshitsuji_Book_of_Circus.jpg +- word: Akatsuki no Yona OVA + imageUrl: https://cdn.nadeko.bot/animu/Akatsuki_no_Yona_OVA.jpg +- word: Dorohedoro + imageUrl: https://cdn.nadeko.bot/animu/Dorohedoro.jpg +- word: Durarara!!x2 Ketsu + imageUrl: https://cdn.nadeko.bot/animu/Durararax2_Ketsu.jpg +- word: 'Ginga Eiyuu Densetsu: Die Neue These - Seiran 2' + imageUrl: https://cdn.nadeko.bot/animu/Ginga_Eiyuu_Densetsu_Die_Neue_These_-_Seiran_2.jpg +- word: Gosick + imageUrl: https://cdn.nadeko.bot/animu/Gosick.jpg +- word: 'Hidamari Sketch: Sae Hiro Sotsugyou-hen' + imageUrl: https://cdn.nadeko.bot/animu/Hidamari_Sketch_Sae_Hiro_Sotsugyou-hen.jpg +- word: 'Koukaku Kidoutai: Stand Alone Complex - The Laughing Man' + imageUrl: https://cdn.nadeko.bot/animu/Koukaku_Kidoutai_Stand_Alone_Complex_-_The_Laughing_Man.jpg +- word: 'Kuroshitsuji: Book of Murder' + imageUrl: https://cdn.nadeko.bot/animu/Kuroshitsuji_Book_of_Murder.jpg +- word: Mirai Shounen Conan + imageUrl: https://cdn.nadeko.bot/animu/Mirai_Shounen_Conan.jpg +- word: Omoide no Marnie + imageUrl: https://cdn.nadeko.bot/animu/Omoide_no_Marnie.jpg +- word: Shijou Saikyou no Deshi Kenichi + imageUrl: https://cdn.nadeko.bot/animu/Shijou_Saikyou_no_Deshi_Kenichi.jpg +- word: 'Shokugeki no Souma: San no Sara' + imageUrl: https://cdn.nadeko.bot/animu/Shokugeki_no_Souma_San_no_Sara.jpg +- word: Tensei shitara Slime Datta Ken + imageUrl: https://cdn.nadeko.bot/animu/Tensei_shitara_Slime_Datta_Ken.jpg +- word: 'Ramayana: The Legend of Prince Rama' + imageUrl: https://cdn.nadeko.bot/animu/Ramayana_The_Legend_of_Prince_Rama.jpg +- word: Summer Wars + imageUrl: https://cdn.nadeko.bot/animu/Summer_Wars.jpg +- word: Yuusha-Ou GaoGaiGar Final + imageUrl: https://cdn.nadeko.bot/animu/Yuusha-Ou_GaoGaiGar_Final.jpg +- word: Dennou Coil + imageUrl: https://cdn.nadeko.bot/animu/Dennou_Coil.jpg +- word: Ginga Eiyuu Densetsu Gaiden (1999) + imageUrl: https://cdn.nadeko.bot/animu/Ginga_Eiyuu_Densetsu_Gaiden_1999.jpg +- word: Glass no Kamen (2005) + imageUrl: https://cdn.nadeko.bot/animu/Glass_no_Kamen_2005.jpg +- word: Kill la Kill + imageUrl: https://cdn.nadeko.bot/animu/Kill_la_Kill.jpg +- word: Koukyoushihen Eureka Seven + imageUrl: https://cdn.nadeko.bot/animu/Koukyoushihen_Eureka_Seven.jpg diff --git a/src/EllieBot/data/hangman/countries.yml b/src/EllieBot/data/hangman/countries.yml new file mode 100644 index 0000000..5899c5d --- /dev/null +++ b/src/EllieBot/data/hangman/countries.yml @@ -0,0 +1,390 @@ +- word: Afghanistan + imageUrl: https://cdn.nadeko.bot/flags/af-flag.gif +- word: Albania + imageUrl: https://cdn.nadeko.bot/flags/al-flag.gif +- word: Algeria + imageUrl: https://cdn.nadeko.bot/flags/ag-flag.gif +- word: Andorra + imageUrl: https://cdn.nadeko.bot/flags/an-flag.gif +- word: Angola + imageUrl: https://cdn.nadeko.bot/flags/ao-flag.gif +- word: Antigua and Barbuda + imageUrl: https://cdn.nadeko.bot/flags/ac-flag.gif +- word: Argentina + imageUrl: https://cdn.nadeko.bot/flags/ar-flag.gif +- word: Armenia + imageUrl: https://cdn.nadeko.bot/flags/am-flag.gif +- word: Australia + imageUrl: https://cdn.nadeko.bot/flags/as-flag.gif +- word: Austria + imageUrl: https://cdn.nadeko.bot/flags/au-flag.gif +- word: Azerbaijan + imageUrl: https://cdn.nadeko.bot/flags/aj-flag.gif +- word: Bahamas + imageUrl: https://cdn.nadeko.bot/flags/bf-flag.gif +- word: Bahrain + imageUrl: https://cdn.nadeko.bot/flags/ba-flag.gif +- word: Bangladesh + imageUrl: https://cdn.nadeko.bot/flags/bg-flag.gif +- word: Barbados + imageUrl: https://cdn.nadeko.bot/flags/bb-flag.gif +- word: Belarus + imageUrl: https://cdn.nadeko.bot/flags/bo-flag.gif +- word: Belgium + imageUrl: https://cdn.nadeko.bot/flags/be-flag.gif +- word: Belize + imageUrl: https://cdn.nadeko.bot/flags/bh-flag.gif +- word: Benin + imageUrl: https://cdn.nadeko.bot/flags/bn-flag.gif +- word: Bhutan + imageUrl: https://cdn.nadeko.bot/flags/bt-flag.gif +- word: Bolivia + imageUrl: https://cdn.nadeko.bot/flags/bl-flag.gif +- word: Bosnia and Herzegovina + imageUrl: https://cdn.nadeko.bot/flags/bk-flag.gif +- word: Botswana + imageUrl: https://cdn.nadeko.bot/flags/bc-flag.gif +- word: Brazil + imageUrl: https://cdn.nadeko.bot/flags/br-flag.gif +- word: Brunei + imageUrl: https://cdn.nadeko.bot/flags/bx-flag.gif +- word: Bulgaria + imageUrl: https://cdn.nadeko.bot/flags/bu-flag.gif +- word: Burkina Faso + imageUrl: https://cdn.nadeko.bot/flags/uv-flag.gif +- word: Burundi + imageUrl: https://cdn.nadeko.bot/flags/by-flag.gif +- word: Ivory Coast + imageUrl: https://cdn.nadeko.bot/flags/iv-flag.gif +- word: Cabo Verde + imageUrl: https://cdn.nadeko.bot/flags/cv-flag.gif +- word: Cambodia + imageUrl: https://cdn.nadeko.bot/flags/cb-flag.gif +- word: Cameroon + imageUrl: https://cdn.nadeko.bot/flags/cm-flag.gif +- word: Canada + imageUrl: https://cdn.nadeko.bot/flags/ca-flag.gif +- word: Central African Republic + imageUrl: https://cdn.nadeko.bot/flags/ct-flag.gif +- word: Chad + imageUrl: https://cdn.nadeko.bot/flags/cd-flag.gif +- word: Chile + imageUrl: https://cdn.nadeko.bot/flags/ci-flag.gif +- word: China + imageUrl: https://cdn.nadeko.bot/flags/ch-flag.gif +- word: Colombia + imageUrl: https://cdn.nadeko.bot/flags/co-flag.gif +- word: Comoros + imageUrl: https://cdn.nadeko.bot/flags/cn-flag.gif +- word: Congo + imageUrl: https://cdn.nadeko.bot/flags/cg-flag.gif +- word: Costa Rica + imageUrl: https://cdn.nadeko.bot/flags/cs-flag.gif +- word: Croatia + imageUrl: https://cdn.nadeko.bot/flags/hr-flag.gif +- word: Cuba + imageUrl: https://cdn.nadeko.bot/flags/cu-flag.gif +- word: Cyprus + imageUrl: https://cdn.nadeko.bot/flags/cy-flag.gif +- word: Czechia + imageUrl: https://cdn.nadeko.bot/flags/ez-flag.gif +- word: Denmark + imageUrl: https://cdn.nadeko.bot/flags/da-flag.gif +- word: Djibouti + imageUrl: https://cdn.nadeko.bot/flags/dj-flag.gif +- word: Dominica + imageUrl: https://cdn.nadeko.bot/flags/do-flag.gif +- word: Dominican Republic + imageUrl: https://cdn.nadeko.bot/flags/dr-flag.gif +- word: Democratic People's Republic of Korea + imageUrl: https://cdn.nadeko.bot/flags/kn-flag.gif +- word: Democratic Republic of the Congo + imageUrl: https://cdn.nadeko.bot/flags/congo-flag.gif +- word: Ecuador + imageUrl: https://cdn.nadeko.bot/flags/ec-flag.gif +- word: Egypt + imageUrl: https://cdn.nadeko.bot/flags/eg-flag.gif +- word: El Salvador + imageUrl: https://cdn.nadeko.bot/flags/es-flag.gif +- word: Equatorial Guinea + imageUrl: https://cdn.nadeko.bot/flags/ek-flag.gif +- word: Eritrea + imageUrl: https://cdn.nadeko.bot/flags/er-flag.gif +- word: Estonia + imageUrl: https://cdn.nadeko.bot/flags/en-flag.gif +- word: Eswatini + imageUrl: https://cdn.nadeko.bot/flags/wz-flag.gif +- word: Ethiopia + imageUrl: https://cdn.nadeko.bot/flags/et-flag.gif +- word: Fiji + imageUrl: https://cdn.nadeko.bot/flags/fj-flag.gif +- word: Finland + imageUrl: https://cdn.nadeko.bot/flags/fi-flag.gif +- word: France + imageUrl: https://cdn.nadeko.bot/flags/fr-flag.gif +- word: Gabon + imageUrl: https://cdn.nadeko.bot/flags/gb-flag.gif +- word: Gambia + imageUrl: https://cdn.nadeko.bot/flags/ga-flag.gif +- word: Georgia + imageUrl: https://cdn.nadeko.bot/flags/gg-flag.gif +- word: Germany + imageUrl: https://cdn.nadeko.bot/flags/gm-flag.gif +- word: Ghana + imageUrl: https://cdn.nadeko.bot/flags/gh-flag.gif +- word: Greece + imageUrl: https://cdn.nadeko.bot/flags/gr-flag.gif +- word: Grenada + imageUrl: https://cdn.nadeko.bot/flags/gj-flag.gif +- word: Guatemala + imageUrl: https://cdn.nadeko.bot/flags/gt-flag.gif +- word: Guinea + imageUrl: https://cdn.nadeko.bot/flags/gv-flag.gif +- word: Guinea-Bissau + imageUrl: https://cdn.nadeko.bot/flags/pu-flag.gif +- word: Guyana + imageUrl: https://cdn.nadeko.bot/flags/gy-flag.gif +- word: Haiti + imageUrl: https://cdn.nadeko.bot/flags/ha-flag.gif +- word: Holy See + imageUrl: https://cdn.nadeko.bot/flags/vt-flag.gif +- word: Honduras + imageUrl: https://cdn.nadeko.bot/flags/ho-flag.gif +- word: Hungary + imageUrl: https://cdn.nadeko.bot/flags/hu-flag.gif +- word: Iceland + imageUrl: https://cdn.nadeko.bot/flags/ic-flag.gif +- word: India + imageUrl: https://cdn.nadeko.bot/flags/in-flag.gif +- word: Indonesia + imageUrl: https://cdn.nadeko.bot/flags/id-flag.gif +- word: Iran + imageUrl: https://cdn.nadeko.bot/flags/ir-flag.gif +- word: Iraq + imageUrl: https://cdn.nadeko.bot/flags/iz-flag.gif +- word: Ireland + imageUrl: https://cdn.nadeko.bot/flags/ei-flag.gif +- word: Israel + imageUrl: https://cdn.nadeko.bot/flags/is-flag.gif +- word: Italy + imageUrl: https://cdn.nadeko.bot/flags/it-flag.gif +- word: Jamaica + imageUrl: https://cdn.nadeko.bot/flags/jm-flag.gif +- word: Japan + imageUrl: https://cdn.nadeko.bot/flags/ja-flag.gif +- word: Jordan + imageUrl: https://cdn.nadeko.bot/flags/jo-flag.gif +- word: Kazakhstan + imageUrl: https://cdn.nadeko.bot/flags/kz-flag.gif +- word: Kenya + imageUrl: https://cdn.nadeko.bot/flags/ke-flag.gif +- word: Kiribati + imageUrl: https://cdn.nadeko.bot/flags/kr-flag.gif +- word: Kuwait + imageUrl: https://cdn.nadeko.bot/flags/ku-flag.gif +- word: Kyrgyzstan + imageUrl: https://cdn.nadeko.bot/flags/kg-flag.gif +- word: Laos + imageUrl: https://cdn.nadeko.bot/flags/la-flag.gif +- word: Latvia + imageUrl: https://cdn.nadeko.bot/flags/lg-flag.gif +- word: Lebanon + imageUrl: https://cdn.nadeko.bot/flags/le-flag.gif +- word: Lesotho + imageUrl: https://cdn.nadeko.bot/flags/lt-flag.gif +- word: Liberia + imageUrl: https://cdn.nadeko.bot/flags/li-flag.gif +- word: Libya + imageUrl: https://cdn.nadeko.bot/flags/ly-flag.gif +- word: Liechtenstein + imageUrl: https://cdn.nadeko.bot/flags/ls-flag.gif +- word: Lithuania + imageUrl: https://cdn.nadeko.bot/flags/lh-flag.gif +- word: Luxembourg + imageUrl: https://cdn.nadeko.bot/flags/lu-flag.gif +- word: Madagascar + imageUrl: https://cdn.nadeko.bot/flags/ma-flag.gif +- word: Malawi + imageUrl: https://cdn.nadeko.bot/flags/mi-flag.gif +- word: Malaysia + imageUrl: https://cdn.nadeko.bot/flags/my-flag.gif +- word: Maldives + imageUrl: https://cdn.nadeko.bot/flags/mv-flag.gif +- word: Mali + imageUrl: https://cdn.nadeko.bot/flags/ml-flag.gif +- word: Malta + imageUrl: https://cdn.nadeko.bot/flags/mt-flag.gif +- word: Marshall Islands + imageUrl: https://cdn.nadeko.bot/flags/rm-flag.gif +- word: Mauritania + imageUrl: https://cdn.nadeko.bot/flags/mr-flag.gif +- word: Mauritius + imageUrl: https://cdn.nadeko.bot/flags/mp-flag.gif +- word: Mexico + imageUrl: https://cdn.nadeko.bot/flags/mx-flag.gif +- word: Micronesia + imageUrl: https://cdn.nadeko.bot/flags/fm-flag.gif +- word: Moldova + imageUrl: https://cdn.nadeko.bot/flags/md-flag.gif +- word: Monaco + imageUrl: https://cdn.nadeko.bot/flags/mn-flag.gif +- word: Mongolia + imageUrl: https://cdn.nadeko.bot/flags/mg-flag.gif +- word: Montenegro + imageUrl: https://cdn.nadeko.bot/flags/mj-flag.gif +- word: Morocco + imageUrl: https://cdn.nadeko.bot/flags/mo-flag.gif +- word: Mozambique + imageUrl: https://cdn.nadeko.bot/flags/mz-flag.gif +- word: Myanmar + imageUrl: https://cdn.nadeko.bot/flags/bm-flag.gif +- word: Namibia + imageUrl: https://cdn.nadeko.bot/flags/wa-flag.gif +- word: Nauru + imageUrl: https://cdn.nadeko.bot/flags/nr-flag.gif +- word: Nepal + imageUrl: https://cdn.nadeko.bot/flags/np-flag.gif +- word: Netherlands + imageUrl: https://cdn.nadeko.bot/flags/nl-flag.gif +- word: New Zealand + imageUrl: https://cdn.nadeko.bot/flags/nz-flag.gif +- word: Nicaragua + imageUrl: https://cdn.nadeko.bot/flags/nu-flag.gif +- word: Niger + imageUrl: https://cdn.nadeko.bot/flags/ng-flag.gif +- word: Nigeria + imageUrl: https://cdn.nadeko.bot/flags/ni-flag.gif +- word: North Macedonia + imageUrl: https://cdn.nadeko.bot/flags/mk-flag.gif +- word: Norway + imageUrl: https://cdn.nadeko.bot/flags/no-flag.gif +- word: Oman + imageUrl: https://cdn.nadeko.bot/flags/mu-flag.gif +- word: Pakistan + imageUrl: https://cdn.nadeko.bot/flags/pk-flag.gif +- word: Palau + imageUrl: https://cdn.nadeko.bot/flags/ps-flag.gif +- word: Panama + imageUrl: https://cdn.nadeko.bot/flags/pm-flag.gif +- word: Papua New Guinea + imageUrl: https://cdn.nadeko.bot/flags/pp-flag.gif +- word: Paraguay + imageUrl: https://cdn.nadeko.bot/flags/pa-flag.gif +- word: Peru + imageUrl: https://cdn.nadeko.bot/flags/pe-flag.gif +- word: Philippines + imageUrl: https://cdn.nadeko.bot/flags/rp-flag.gif +- word: Poland + imageUrl: https://cdn.nadeko.bot/flags/pl-flag.gif +- word: Portugal + imageUrl: https://cdn.nadeko.bot/flags/po-flag.gif +- word: Qatar + imageUrl: https://cdn.nadeko.bot/flags/qa-flag.gif +- word: Romania + imageUrl: https://cdn.nadeko.bot/flags/ro-flag.gif +- word: Russia + imageUrl: https://cdn.nadeko.bot/flags/rs-flag.gif +- word: Rwanda + imageUrl: https://cdn.nadeko.bot/flags/rw-flag.gif +- word: Saint Kitts and Nevis + imageUrl: https://cdn.nadeko.bot/flags/sc-flag.gif +- word: Saint Lucia + imageUrl: https://cdn.nadeko.bot/flags/st-flag.gif +- word: Samoa + imageUrl: https://cdn.nadeko.bot/flags/ws-flag.gif +- word: San Marino + imageUrl: https://cdn.nadeko.bot/flags/sm-flag.gif +- word: Sao Tome and Principe + imageUrl: https://cdn.nadeko.bot/flags/tp-flag.gif +- word: Saudi Arabia + imageUrl: https://cdn.nadeko.bot/flags/sa-flag.gif +- word: Senegal + imageUrl: https://cdn.nadeko.bot/flags/sg-flag.gif +- word: Serbia + imageUrl: https://cdn.nadeko.bot/flags/ri-flag.gif +- word: Seychelles + imageUrl: https://cdn.nadeko.bot/flags/se-flag.gif +- word: Sierra Leone + imageUrl: https://cdn.nadeko.bot/flags/sl-flag.gif +- word: Singapore + imageUrl: https://cdn.nadeko.bot/flags/sn-flag.gif +- word: Slovakia + imageUrl: https://cdn.nadeko.bot/flags/lo-flag.gif +- word: Slovenia + imageUrl: https://cdn.nadeko.bot/flags/si-flag.gif +- word: Solomon Islands + imageUrl: https://cdn.nadeko.bot/flags/bp-flag.gif +- word: Somalia + imageUrl: https://cdn.nadeko.bot/flags/so-flag.gif +- word: South Africa + imageUrl: https://cdn.nadeko.bot/flags/sf-flag.gif +- word: South Korea + imageUrl: https://cdn.nadeko.bot/flags/ks-flag.gif +- word: South Sudan + imageUrl: https://cdn.nadeko.bot/flags/od-flag.gif +- word: Spain + imageUrl: https://cdn.nadeko.bot/flags/sp-flag.gif +- word: Sri Lanka + imageUrl: https://cdn.nadeko.bot/flags/ce-flag.gif +- word: St. Vincent Grenadines + imageUrl: https://cdn.nadeko.bot/flags/vc-flag.gif +- word: State of Palestine + imageUrl: https://cdn.nadeko.bot/flags/palestine-flag.gif +- word: Sudan + imageUrl: https://cdn.nadeko.bot/flags/su-flag.gif +- word: Suriname + imageUrl: https://cdn.nadeko.bot/flags/ns-flag.gif +- word: Sweden + imageUrl: https://cdn.nadeko.bot/flags/sw-flag.gif +- word: Switzerland + imageUrl: https://cdn.nadeko.bot/flags/sz-flag.gif +- word: Syria + imageUrl: https://cdn.nadeko.bot/flags/sy-flag.gif +- word: Tajikistan + imageUrl: https://cdn.nadeko.bot/flags/ti-flag.gif +- word: Tanzania + imageUrl: https://cdn.nadeko.bot/flags/tz-flag.gif +- word: Thailand + imageUrl: https://cdn.nadeko.bot/flags/th-flag.gif +- word: Timor-Leste + imageUrl: https://cdn.nadeko.bot/flags/tt-flag.gif +- word: Togo + imageUrl: https://cdn.nadeko.bot/flags/to-flag.gif +- word: Tonga + imageUrl: https://cdn.nadeko.bot/flags/tn-flag.gif +- word: Trinidad and Tobago + imageUrl: https://cdn.nadeko.bot/flags/td-flag.gif +- word: Tunisia + imageUrl: https://cdn.nadeko.bot/flags/ts-flag.gif +- word: Turkey + imageUrl: https://cdn.nadeko.bot/flags/tu-flag.gif +- word: Turkmenistan + imageUrl: https://cdn.nadeko.bot/flags/tx-flag.gif +- word: Tuvalu + imageUrl: https://cdn.nadeko.bot/flags/tv-flag.gif +- word: United Arab Emirates + imageUrl: https://cdn.nadeko.bot/flags/ae-flag.gif +- word: United Kingdom + imageUrl: https://cdn.nadeko.bot/flags/uk-flag.gif +- word: United States Of America + imageUrl: https://cdn.nadeko.bot/flags/us-flag.gif +- word: Uganda + imageUrl: https://cdn.nadeko.bot/flags/ug-flag.gif +- word: Ukraine + imageUrl: https://cdn.nadeko.bot/flags/up-flag.gif +- word: Uruguay + imageUrl: https://cdn.nadeko.bot/flags/uy-flag.gif +- word: Uzbekistan + imageUrl: https://cdn.nadeko.bot/flags/uz-flag.gif +- word: Vanuatu + imageUrl: https://cdn.nadeko.bot/flags/nh-flag.gif +- word: Venezuela + imageUrl: https://cdn.nadeko.bot/flags/ve-flag.gif +- word: Vietnam + imageUrl: https://cdn.nadeko.bot/flags/vm-flag.gif +- word: Yemen + imageUrl: https://cdn.nadeko.bot/flags/ym-flag.gif +- word: Zambia + imageUrl: https://cdn.nadeko.bot/flags/za-flag.gif +- word: Zimbabwe + imageUrl: https://cdn.nadeko.bot/flags/zi-flag.gif diff --git a/src/EllieBot/data/hangman/movies.yml b/src/EllieBot/data/hangman/movies.yml new file mode 100644 index 0000000..0883253 --- /dev/null +++ b/src/EllieBot/data/hangman/movies.yml @@ -0,0 +1,400 @@ +- word: 'Underworld: Blood Wars' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/PIXSMakrO3s2dqA7mCvAAoVR0E.jpg +- word: Fantastic Beasts and Where to Find Them + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6I2tPx6KIiBB4TWFiWwNUzrbxUn.jpg +- word: Suicide Squad + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/34dxtTxMHGKw1njHpTjDqR8UBHd.jpg +- word: Miss Peregrine's Home for Peculiar Children + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qXQinDhDZkTiqEGLnav0h1YSUu8.jpg +- word: Sully + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/vC9H1ZVdXi1KjH4aPfGB54mvDNh.jpg +- word: Arrival + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/yIZ1xendyqKvY3FGeeUYUd5X9Mm.jpg +- word: Doctor Strange + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/tFI8VLMgSTTU38i8TIsklfqS9Nl.jpg +- word: 'Mad Max: Fury Road' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/tbhdm8UJAb4ViCTsulYFL3lxMCd.jpg +- word: Interstellar + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg +- word: Jason Bourne + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/AoT2YrJUJlg5vKE3iMOLvHlTd3m.jpg +- word: 'Captain America: Civil War' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/m5O3SZvQ6EgD5XXXLPIP1wLppeW.jpg +- word: Moana + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/1qGzqGUd1pa05aqYXGSbLkiBlLB.jpg +- word: 'The Hunger Games: Mockingjay - Part 1' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/83nHcz2KcnEpPXY50Ky2VldewJJ.jpg +- word: Underworld + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/cPhRPAJWK8BuuJqqf6PztzvOlnZ.jpg +- word: The Secret Life of Pets + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/lubzBMQLLmG88CLQ4F3TxZr2Q7N.jpg +- word: Insurgent + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/L5QRL1O3fGs2hH1LbtYyVl8Tce.jpg +- word: Jurassic World + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/dkMD5qlogeRMiEixC4YNPUvax2T.jpg +- word: Ben-Hur + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/A4xbEpe9LevQCdvaNC0z6r8AfYk.jpg +- word: Finding Dory + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/iWRKYHTFlsrxQtfQqFOQyceL83P.jpg +- word: Guardians of the Galaxy + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg +- word: Ghostbusters + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/58bvfg9b040GDmKffLUJsEjg779.jpg +- word: Inferno + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/anmLLbDx9d98NMZRyVUtxwJR6ab.jpg +- word: Star Trek Beyond + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6uBlEXZCUHM15UNZqNig17VdN4m.jpg +- word: The BFG + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/eYT9XQBo1eC4DwPYqhCol0dFFc2.jpg +- word: Pete's Dragon + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/AaRhHX0Jfpju0O6hNzScPRgX9Mm.jpg +- word: 'Mechanic: Resurrection' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6kMu4vECAyTpj2Z7n8viJ4RAaYh.jpg +- word: The Imitation Game + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qcb6z1HpokTOKdjqDTsnjJk0Xvg.jpg +- word: 'X-Men: Apocalypse' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/oQWWth5AOtbWG9o8SCAviGcADed.jpg +- word: John Wick + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/mFb0ygcue4ITixDkdr7wm1Tdarx.jpg +- word: Deadpool + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/n1y094tVDFATSzkTnFxoGZ1qNsG.jpg +- word: 'Batman v Superman: Dawn of Justice' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/vsjBeMPZtyB7yNsYY56XYxifaQZ.jpg +- word: The Revenant + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/kiWvoV78Cc3fUwkOHKzyBgVdrDD.jpg +- word: Now You See Me 2 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/zrAO2OOa6s6dQMQ7zsUbDyIBrAP.jpg +- word: 'Star Wars: The Force Awakens' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/c2Ax8Rox5g6CneChwy1gmu4UbSb.jpg +- word: The Martian + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/sy3e2e4JwdAtd2oZGA2uUilZe8j.jpg +- word: Bridget Jones's Baby + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/w9VNDcQet0TUoLRWHg8JbT4QjpW.jpg +- word: Minions + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/uX7LXnsC7bZJZjn048UCOwkPXWJ.jpg +- word: Star Wars + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/4iJfYYoQzZcONB9hNzg0J0wWyPH.jpg +- word: Spectre + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/wVTYlkKPKrljJfugXN7UlLNjtuJ.jpg +- word: 'Rogue One: A Star Wars Story' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/tZjVVIYXACV4IIIhXeIM59ytqwS.jpg +- word: Big Hero 6 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/2BXd0t9JdVqCp9sKf6kzMkr7QjB.jpg +- word: 'Independence Day: Resurgence' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8SqBiesvo1rh9P1hbJTmnVum6jv.jpg +- word: The Dark Knight + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nnMC0BM6XbjIIrT4miYmMtPGcQV.jpg +- word: Sausage Party + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nBvyktlVHjLx5nZ9Oxaoqo5jwbf.jpg +- word: Gone Girl + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg +- word: Zootopia + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/mhdeE1yShHTaDbJVdWyTlzFvNkr.jpg +- word: Allegiant + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/sFthBeT0Y3WVfg6b3MkcJs9qfzq.jpg +- word: 'The Hobbit: The Battle of the Five Armies' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qhH3GyIfAnGv1pjdV3mw03qAilg.jpg +- word: Fury + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/pKawqrtCBMmxarft7o1LbEynys7.jpg +- word: The Jungle Book + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/eIOTsGg9FCVrBc4r2nXaV61JF4F.jpg +- word: 'Jack Reacher: Never Go Back' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/4ynQYtSEuU5hyipcGkfD6ncwtwz.jpg +- word: 'Pirates of the Caribbean: The Curse of the Black Pearl' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8AUQ7YlJJA9C8kWk8P4YNHIcFDE.jpg +- word: 'The Hunger Games: Mockingjay - Part 2' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qjn3fzCAHGfl0CzeUlFbjrsmu4c.jpg +- word: Hell or High Water + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/5GbRKOQSY08U3SQXXcQAKEnL2rE.jpg +- word: Terminator Genisys + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bIlYH4l2AyYvEysmS2AOfjO7Dn8.jpg +- word: Ant-Man + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/kvXLZqY0Ngl1XSw7EaMQO0C1CCj.jpg +- word: The Shallows + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/lEkHdk4g0nAKtMcHBtSmC1ON3O1.jpg +- word: 'Underworld: Awakening' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8iNsXY3LPsuT0gnUiTBMoNuRZI7.jpg +- word: Inception + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/s2bT29y0ngXxxu2IA8AOzzXTRhd.jpg +- word: 'Underworld: Evolution' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/lLZTsh8qDZsHCG9GMnqZKIlluZT.jpg +- word: The Hateful Eight + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/sSvgNBeBNzAuKl8U8sP50ETJPgx.jpg +- word: Fight Club + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/wSJPjqp2AZWQ6REaqkMuXsCIs64.jpg +- word: 'Avengers: Age of Ultron' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/570qhjGZmGPrBGnfx70jcwIuBr4.jpg +- word: 'Underworld: Rise of the Lycans' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/gVfnoiCJBdv2SN7poIbU7eyNVq1.jpg +- word: Tomorrowland + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/fQbc5XuB4vWA9gnY1CmyxFaOufF.jpg +- word: The Matrix + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/7u3pxc0K1wx32IleAkLv78MKgrw.jpg +- word: Furious 7 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/ypyeMfKydpyuuTMdp36rMlkGDUL.jpg +- word: Pixels + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nvZVu6inpwLHKqRXZhye3S4uqei.jpg +- word: Emerald Green + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/ioKU3dEgx0HeUWp3KI2X7YF8FdC.jpg +- word: Whiplash + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6bbZ6XyvgfjhQwbplnUh1LSj1ky.jpg +- word: The Legend of Tarzan + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/pWNBPN8ghaKtGLcQBMwNyM32Wbm.jpg +- word: Lucy + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/eCgIoGvfNXrbSiQGqQHccuHjQHm.jpg +- word: Allied + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6o4KCKjP1WcefXLBNRyhEenB2nW.jpg +- word: Eliminators + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/lNhwy85HjhieIVfmWoDAL2wCchB.jpg +- word: 'Ice Age: Collision Course' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/o29BFNqgXOUT1yHNYusnITsH7P9.jpg +- word: Batman Begins + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/65JWXDCAfwHhJKnDwRnEgVB411X.jpg +- word: Teenage Mutant Ninja Turtles + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/OqCXGt5nl1cHPeotxCDvXLLe6p.jpg +- word: Birdman + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/hUDEHvhNJLNcb83Pp7xnFn0Wj09.jpg +- word: Avatar + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/5XPPB44RQGfkBrbJxmtdndKz05n.jpg +- word: 'Kingsman: The Secret Service' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/pfyWJUxrBTT2UIPoEQF3iFTHcQT.jpg +- word: "Pirates of the Caribbean: At World's End" + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8ZgpAftUiYTU76IhUADITa3Ur9n.jpg +- word: Bad Moms + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/elPpPBuYB2Zn5wFwz2FSlJlKUjp.jpg +- word: Inside Out + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/szytSpLAyBh3ULei3x663mAv5ZT.jpg +- word: Harry Potter and the Philosopher's Stone + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/uD93T339xX1k3fnDUaeopZBiajY.jpg +- word: Dawn of the Planet of the Apes + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/rjUl3pd1LHVOVfG4IGcyA1cId5l.jpg +- word: Iron Man + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/ZQixhAZx6fH1VNafFXsqa1B8QI.jpg +- word: The Dark Knight Rises + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/3bgtUfKQKNi3nJsAB5URpP2wdRt.jpg +- word: Don't Breathe + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bCThHXQ3aLLDU3KFST0rC8mTan5.jpg +- word: The Avengers + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/hbn46fQaRmlpBuUrEiFqv0GDL6Y.jpg +- word: Alice Through the Looking Glass + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/rWlXrfmX1FgcPyj7oQmLfwKRaam.jpg +- word: Now You See Me + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/9wbXqcx6rHhoZ9Esp03C7amQzom.jpg +- word: The Accountant + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/i9flZtw3BwukADQpu5PlrkwPYSY.jpg +- word: The Maze Runner + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/yTbPPmLAn7DiiM0sPYfZduoAjB.jpg +- word: Forrest Gump + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/ctOEhQiFIHWkiaYp7b0ibSTe5IL.jpg +- word: 'The Hunger Games: Catching Fire' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/wRCPG1lsgfTFkWJ7G3eWgxCgv0C.jpg +- word: Warcraft + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/5SX2rgKXZ7NVmAJR5z5LprqSXKa.jpg +- word: 'Eddie Izzard: Glorious' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/2XHkh7xLqH168KRqMwDuiTmuyQi.jpg +- word: Office Christmas Party + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bzguuhqUI9G8jJ3EBtJ9p12g1Lr.jpg +- word: 'Transformers: The Last Knight' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/lQmtMCQgBwcODAyNnKGQrW0Kza8.jpg +- word: Skyfall + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/AunH2MIKIbnU9khgFp45eJlydPu.jpg +- word: 'The Hobbit: An Unexpected Journey' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/jjAq3tCezdlQduusgtMhpY2XzW0.jpg +- word: 'The Lord of the Rings: The Fellowship of the Ring' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/pIUvQ9Ed35wlWhY2oU6OmwEsmzG.jpg +- word: Kubo and the Two Strings + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/n4FeRnlH0ERa1kCUh0NXOyQvxnd.jpg +- word: 10 Cloverfield Lane + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qEu2EJBQUNFx5mSKOCItwZm74ZE.jpg +- word: 'Captain America: The First Avenger' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/pmZtj1FKvQqISS6iQbkiLg5TAsr.jpg +- word: The Shawshank Redemption + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/xBKGJQsAIeweesB79KC89FpBrVr.jpg +- word: Me Before You + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/o4lxNwKJz8oq3R0kLOIsDlHbDhZ.jpg +- word: The Magnificent Seven + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/T3LrH6bnV74llVbFpQsCBrGaU9.jpg +- word: The Lion King + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/klI0K4oQMsLhHdjA9Uw8WLugk9v.jpg +- word: Quantum of Solace + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/hfZVY8lMiE7HH1cDc2qzSFF6Kbt.jpg +- word: Sing + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/srpt7oa3AmmJXd2K5x9ZVzmV0I3.jpg +- word: Nightcrawler + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/ts4j3zYaPzdUVF3ijBeBdGVDWjX.jpg +- word: Snowden + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qzGFm7uF1HExPUAcAPwC3Hzk5WR.jpg +- word: The Equalizer + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/b1uY9m6sZLLfa8jxtBvZg9esSvd.jpg +- word: Divergent + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/g6WT9zxATzTy9NVu2xwbxDAxvjd.jpg +- word: "Pirates of the Caribbean: Dead Man's Chest" + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/hdHgIcljPHli4xaJGt0INz8Gn3J.jpg +- word: War Dogs + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/2cLndRZy8e3das3vVaK3BdJfRIi.jpg +- word: Pulp Fiction + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/mte63qJaVnoxkkXbHkdFujBnBgd.jpg +- word: 'Transformers: Age of Extinction' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/cHy7nSitAVgvZ7qfCK4JO47t3oZ.jpg +- word: Gladiator + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/5vZw7ltCKI0JiOYTtRxaIC3DX0e.jpg +- word: Nerve + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/a0wohltYr7Tzkgg2X6QKBe3txj1.jpg +- word: I Am Legend + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/u6Qg7TH7Oh1IFWCQSRr4htFFt0A.jpg +- word: 'Teenage Mutant Ninja Turtles: Out of the Shadows' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/999RuhZvog8ocyvcccVV9yGmMjL.jpg +- word: Cinderella + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/aUYcExsGuRaw7PLGmAmXubt1dfG.jpg +- word: The Big Short + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/jmlMLYEsYY1kRc5qHIyTdxCeVmZ.jpg +- word: 'X-Men: Days of Future Past' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/5LBcSLHAtEIIgvNkA2dPmYH5wR7.jpg +- word: Shutter Island + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/fmLWuAfDPaUa3Vi5nO1YUUyZaX6.jpg +- word: 'Captain America: The Winter Soldier' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/4qfXT9BtxeFuamR4F49m2mpKQI1.jpg +- word: San Andreas + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/cUfGqafAVQkatQ7N4y08RNV3bgu.jpg +- word: The Mummy + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/3qthpSSyBY6Efeu1sqkO8L1Eyyb.jpg +- word: Chappie + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/y5lG7TBpeOMG0jxAaTK0ghZSzBJ.jpg +- word: Bridge of Spies + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/3amJMLyjx0rDbwhnKNG8d6gzDSV.jpg +- word: 'The Lord of the Rings: The Return of the King' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8BPZO0Bf8TeAy8znF43z8soK3ys.jpg +- word: 'Kill Bill: Vol. 1' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/kkS8PKa8c134vXsj2fQkNqOaCXU.jpg +- word: 'Pirates of the Caribbean: On Stranger Tides' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/l7zANdjgTvYqwZUx76Vk0EKpCH5.jpg +- word: The Nice Guys + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/a7eSkK4bkLwKCXYDdYIqLxrqT2n.jpg +- word: Harry Potter and the Chamber of Secrets + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/avqzwKn89VetTEvAlBePt3Us6Al.jpg +- word: 'The Lord of the Rings: The Two Towers' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/dG4BmM32XJmKiwopLDQmvXEhuHB.jpg +- word: Titanic + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/2Te2YJoLtT2cHME7i5kDuEwJWZc.jpg +- word: "The Huntsman: Winter's War" + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nQ0UvXdxoMZguLuPj0sdV0U36KR.jpg +- word: Thor + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6UxFfo8K3vcihtUpX1ek2ucGeEZ.jpg +- word: Taken 3 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/razvUuLkF7CX4XsLyj02ksC0ayy.jpg +- word: Lights Out + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nQsdGCVTEq78XwIgR6QUVxiNERI.jpg +- word: 'Night at the Museum: Secret of the Tomb' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6tKleiKS54focE4z0sdtLOIEgK8.jpg +- word: Up + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/qMjbMPkSCc1K19zuXNM2BgIsIRz.jpg +- word: The Bourne Identity + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/2Fr1vqBiDn8xRJM9elcplzHctTN.jpg +- word: Frozen + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/cAhCDpAq80QCeQvHytY9JkBalpH.jpg +- word: 'Thor: The Dark World' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/3FweBee0xZoY77uO1bhUOlQorNH.jpg +- word: The Wolf of Wall Street + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/rP36Rx5RQh0rmH2ynEIaG8DxbV2.jpg +- word: Resident Evil + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/s41Er80jGJf3tNkgYHxUCttjmwv.jpg +- word: Iron Man 3 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/n9X2DKItL3V0yq1q1jrk8z5UAki.jpg +- word: Ice Age + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/oDqbewoFuIEWA7UWurole6MzDGn.jpg +- word: Central Intelligence + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/zaGmoSackrRF7w6NieQ0FWY0M7k.jpg +- word: 'The Mummy: Tomb of the Dragon Emperor' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/caB8JFUigSHdGsdxOxaK4vZtOiN.jpg +- word: The Man from U.N.C.L.E. + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bKxcCNv2xq8M3GD5iSrv9bMGDVa.jpg +- word: Gravity + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/9aoWzwOwy9NLuSk9LkBwwrBdPYM.jpg +- word: Ex Machina + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/9X3cDZb4GYGQeOnZHLwMcCFz2Ro.jpg +- word: Harry Potter and the Goblet of Fire + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/gzKW3emulMxIHzuXxZoyDB1lei9.jpg +- word: Man of Steel + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/jYLh4mdOqkt30i7LTFs3o02UcGF.jpg +- word: 'Harry Potter and the Deathly Hallows: Part 1' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8YA36faYlkpfp6aozcGsqq68pZ9.jpg +- word: Iron Man 2 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/jxdSxqAFrdioKgXwgTs5Qfbazjq.jpg +- word: The Angry Birds Movie + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/3mJcfL2lPfRky16EPi95d2YrKqu.jpg +- word: Room + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/tBhp8MGaiL3BXpPCSl5xY397sGH.jpg +- word: Ted 2 + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nkwoiSVJLeK0NI8kTqioBna61bm.jpg +- word: 'Exodus: Gods and Kings' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/hOOgtrByGgWfqGTTn5VL7jkLYXJ.jpg +- word: 'Terminator 2: Judgment Day' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/d9AqtruwS8nljKjL5aYzM42hQJr.jpg +- word: Harry Potter and the Prisoner of Azkaban + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/wWdlIBxn9xCmySxnSWtI2BjZZkF.jpg +- word: Genius + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/5eovlgVfijObBm4TtW1QSaj32q3.jpg +- word: Inglourious Basterds + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bk0GylJLneaSbpQZXpgTwleYigq.jpg +- word: Hacksaw Ridge + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/zBK4QZONMQXhcgaJv1YYTdCW7q9.jpg +- word: Trolls + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/wc1JxADaBLuWhySkaawCBTpixCo.jpg +- word: The Shining + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/h4DcDCOkQBENWBJZjNlPv3adQfM.jpg +- word: A Walk Among the Tombstones + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/e56QsaJy1weAUukiK2ZmIGVUALF.jpg +- word: Dr. No + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/bplDiT5JhaXf9S5arO8g5QsFtDi.jpg +- word: 'Mission: Impossible' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/7CiZuIPCLvhhMICT2PONuwr2BMG.jpg +- word: 'The Purge: Anarchy' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/1sOkQtqmBji7iquGfQlHOrFqplN.jpg +- word: 'Maze Runner: The Scorch Trials' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/iapRFMGKvN9tsjqPlN7MIDTCezG.jpg +- word: Jupiter Ascending + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/4liSXBZZdURI0c1Id1zLJo6Z3Gu.jpg +- word: Morgan + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/g3XhTkjUxLbzVVa63vuopSNNZE8.jpg +- word: Se7en + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/ba4CpvnaxvAgff2jHiaqJrVpZJ5.jpg +- word: Charlie and the Chocolate Factory + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/mrRAx1OsNVEKJv0ktQprspieqnS.jpg +- word: Self/less + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/fpKyGCOZJsYe2TAKLtziLe6EPj9.jpg +- word: The Prestige + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/c5o7FN2vzI7xlU6IF1y64mgcH9E.jpg +- word: The Departed + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/8Od5zV7Q7zNOX0y9tyNgpTmoiGA.jpg +- word: Monsters, Inc. + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/eKBUYeSgGVvztO2MZxD5YMcz6kv.jpg +- word: Raiders of the Lost Ark + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/dU1CArBM4YsKLfG8YvhtuTJJaGR.jpg +- word: The Terminator + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6yFoLNQgFdVbA8TZMdfgVpszOla.jpg +- word: The Mummy Returns + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/22SUPrwoHNbMjZci1kRvBmCqrek.jpg +- word: Pan + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6Ym6bgfhvpgQS5Sg8kKnfW1hX7P.jpg +- word: Fifty Shades of Grey + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/zw3fM9KYYhYGsIQUJOyQNbeZSnn.jpg +- word: Casino Royale + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/xq6hXdBpDPIXWjtmvbFmtLvBFJt.jpg +- word: Free State of Jones + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/zgo0s1fmBCWUweNrCVIK1dZEOJ6.jpg +- word: Despicable Me + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/yo1ef57MEPkEE4BDZKTZGH9uDcX.jpg +- word: Creed + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/nF4kmc4gDRQU4OJiJgk6sZtbJbl.jpg +- word: Seventh Son + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/lNnrr7OR7dkqfgIyju8nUJHcf8x.jpg +- word: The Hunger Games + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/1LTLrl06uII4w2BTpnQnmWwrKi.jpg +- word: Saving Private Ryan + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/gRtLcCQOpYUI9ThdVzi4VUP8QO3.jpg +- word: 'Harry Potter and the Deathly Hallows: Part 2' + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6n0DAcyjTHS6888mt8U9ZsLy9nR.jpg +- word: 12 Years a Slave + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/xnRPoFI7wzOYviw3PmoG94X2Lnc.jpg +- word: Dracula Untold + imageUrl: https://image.tmdb.org/t/p/w300_and_h450_bestv2/6UPlIYKxZqUR6Xbpgu1JKG0J7UC.jpg diff --git a/src/EllieBot/data/hangman/things.yml b/src/EllieBot/data/hangman/things.yml new file mode 100644 index 0000000..d31b78f --- /dev/null +++ b/src/EllieBot/data/hangman/things.yml @@ -0,0 +1,380 @@ +- word: apple + imageUrl: https://www.randomlists.com/img/things/apple.jpg.jpg +- word: bag + imageUrl: https://www.randomlists.com/img/things/bag.jpg.jpg +- word: balloon + imageUrl: https://www.randomlists.com/img/things/balloon.jpg.jpg +- word: bananas + imageUrl: https://www.randomlists.com/img/things/bananas.jpg.jpg +- word: bed + imageUrl: https://www.randomlists.com/img/things/bed.jpg.jpg +- word: beef + imageUrl: https://www.randomlists.com/img/things/beef.jpg.jpg +- word: blouse + imageUrl: https://www.randomlists.com/img/things/blouse.jpg.jpg +- word: book + imageUrl: https://www.randomlists.com/img/things/book.jpg.jpg +- word: bookmark + imageUrl: https://www.randomlists.com/img/things/bookmark.jpg.jpg +- word: boom box + imageUrl: https://www.randomlists.com/img/things/boom_box.jpg.jpg +- word: bottle + imageUrl: https://www.randomlists.com/img/things/bottle.jpg.jpg +- word: bottle cap + imageUrl: https://www.randomlists.com/img/things/bottle_cap.jpg +- word: bow + imageUrl: https://www.randomlists.com/img/things/bow.jpg +- word: bowl + imageUrl: https://www.randomlists.com/img/things/bowl.jpg +- word: box + imageUrl: https://www.randomlists.com/img/things/box.jpg +- word: bracelet + imageUrl: https://www.randomlists.com/img/things/bracelet.jpg +- word: bread + imageUrl: https://www.randomlists.com/img/things/bread.jpg +- word: broccoli + imageUrl: https://www.randomlists.com/img/things/brocolli.jpg +- word: hair brush + imageUrl: https://www.randomlists.com/img/things/hair_brush.jpg +- word: buckle + imageUrl: https://www.randomlists.com/img/things/buckel.jpg +- word: button + imageUrl: https://www.randomlists.com/img/things/button.jpg +- word: camera + imageUrl: https://www.randomlists.com/img/things/camera.jpg +- word: candle + imageUrl: https://www.randomlists.com/img/things/candle.jpg +- word: candy wrapper + imageUrl: https://www.randomlists.com/img/things/candy_wrapper.jpg +- word: canvas + imageUrl: https://www.randomlists.com/img/things/canvas.jpg +- word: car + imageUrl: https://www.randomlists.com/img/things/car.jpg +- word: greeting card + imageUrl: https://www.randomlists.com/img/things/greeting_card.jpg +- word: playing card + imageUrl: https://www.randomlists.com/img/things/playing_card.jpg +- word: carrots + imageUrl: https://www.randomlists.com/img/things/carrots.jpg +- word: cat + imageUrl: https://www.randomlists.com/img/things/cat.jpg +- word: CD + imageUrl: https://www.randomlists.com/img/things/CD.jpg +- word: cell phone + imageUrl: https://www.randomlists.com/img/things/cell_phone.jpg +- word: packing peanuts + imageUrl: https://www.randomlists.com/img/things/packing_peanuts.jpg +- word: cinder block + imageUrl: https://www.randomlists.com/img/things/cinder_block.jpg +- word: chair + imageUrl: https://www.randomlists.com/img/things/chair.jpg +- word: chalk + imageUrl: https://www.randomlists.com/img/things/chalk.jpg +- word: newspaper + imageUrl: https://www.randomlists.com/img/things/newspaper.jpg +- word: soy sauce packet + imageUrl: https://www.randomlists.com/img/things/soy_sauce_packet.jpg +- word: chapter book + imageUrl: https://www.randomlists.com/img/things/chapter_book.jpg +- word: checkbook + imageUrl: https://www.randomlists.com/img/things/checkbook.jpg +- word: chocolate + imageUrl: https://www.randomlists.com/img/things/chocolate.jpg +- word: clay pot + imageUrl: https://www.randomlists.com/img/things/clay_pot.jpg +- word: clock + imageUrl: https://www.randomlists.com/img/things/clock.jpg +- word: clothes + imageUrl: https://www.randomlists.com/img/things/clothes.jpg +- word: computer + imageUrl: https://www.randomlists.com/img/things/computer.jpg +- word: conditioner + imageUrl: https://www.randomlists.com/img/things/conditioner.jpg +- word: cookie jar + imageUrl: https://www.randomlists.com/img/things/cookie_jar.jpg +- word: cork + imageUrl: https://www.randomlists.com/img/things/cork.jpg +- word: couch + imageUrl: https://www.randomlists.com/img/things/couch.jpg +- word: credit card + imageUrl: https://www.randomlists.com/img/things/credit_card.jpg +- word: cup + imageUrl: https://www.randomlists.com/img/things/cup.jpg +- word: deodorant + imageUrl: https://www.randomlists.com/img/things/deodorant_.jpg +- word: desk + imageUrl: https://www.randomlists.com/img/things/desk.jpg +- word: door + imageUrl: https://www.randomlists.com/img/things/door.jpg +- word: drawer + imageUrl: https://www.randomlists.com/img/things/drawer.jpg +- word: drill press + imageUrl: https://www.randomlists.com/img/things/drill_press.jpg +- word: eraser + imageUrl: https://www.randomlists.com/img/things/earser.jpg +- word: eye liner + imageUrl: https://www.randomlists.com/img/things/eye_liner.jpg +- word: face wash + imageUrl: https://www.randomlists.com/img/things/face_wash.jpg +- word: fake flowers + imageUrl: https://www.randomlists.com/img/things/fake_flowers.jpg +- word: flag + imageUrl: https://www.randomlists.com/img/things/flag.jpg +- word: floor + imageUrl: https://www.randomlists.com/img/things/floor.jpg +- word: flowers + imageUrl: https://www.randomlists.com/img/things/flowers.jpg +- word: food + imageUrl: https://www.randomlists.com/img/things/food.jpg +- word: fork + imageUrl: https://www.randomlists.com/img/things/fork.jpg +- word: fridge + imageUrl: https://www.randomlists.com/img/things/fridge.jpg +- word: glass + imageUrl: https://www.randomlists.com/img/things/glass.jpg +- word: glasses + imageUrl: https://www.randomlists.com/img/things/glasses.jpg +- word: glow stick + imageUrl: https://www.randomlists.com/img/things/glow_stick.jpg +- word: grid paper + imageUrl: https://www.randomlists.com/img/things/grid_paper.jpg +- word: hair tie + imageUrl: https://www.randomlists.com/img/things/hair_tie.jpg +- word: hanger + imageUrl: https://www.randomlists.com/img/things/hanger.jpg +- word: helmet + imageUrl: https://www.randomlists.com/img/things/helmet.jpg +- word: house + imageUrl: https://www.randomlists.com/img/things/house.jpg +- word: ipod + imageUrl: https://www.randomlists.com/img/things/ipod.jpg +- word: charger + imageUrl: https://www.randomlists.com/img/things/charger.jpg +- word: key chain + imageUrl: https://www.randomlists.com/img/things/key_chain.jpg +- word: keyboard + imageUrl: https://www.randomlists.com/img/things/keyboard.jpg +- word: keys + imageUrl: https://www.randomlists.com/img/things/keys.jpg +- word: knife + imageUrl: https://www.randomlists.com/img/things/knife.jpg +- word: lace + imageUrl: https://www.randomlists.com/img/things/lace.jpg +- word: lamp + imageUrl: https://www.randomlists.com/img/things/lamp.jpg +- word: lamp shade + imageUrl: https://www.randomlists.com/img/things/lamp_shade.jpg +- word: leg warmers + imageUrl: https://www.randomlists.com/img/things/leg_warmers.jpg +- word: lip gloss + imageUrl: https://www.randomlists.com/img/things/lip_gloss.jpg +- word: lotion + imageUrl: https://www.randomlists.com/img/things/lotion.jpg +- word: milk + imageUrl: https://www.randomlists.com/img/things/milk.jpg +- word: mirror + imageUrl: https://www.randomlists.com/img/things/mirror.jpg +- word: model car + imageUrl: https://www.randomlists.com/img/things/model_car.jpg +- word: money + imageUrl: https://www.randomlists.com/img/things/money.jpg +- word: monitor + imageUrl: https://www.randomlists.com/img/things/monitor.jpg +- word: mop + imageUrl: https://www.randomlists.com/img/things/mop.jpg +- word: mouse pad + imageUrl: https://www.randomlists.com/img/things/mouse_pad.jpg +- word: mp3 player + imageUrl: https://www.randomlists.com/img/things/mp3_player.jpg +- word: nail clippers + imageUrl: https://www.randomlists.com/img/things/nail_clippers.jpg +- word: nail file + imageUrl: https://www.randomlists.com/img/things/nail_file.jpg +- word: needle + imageUrl: https://www.randomlists.com/img/things/needle.jpg +- word: outlet + imageUrl: https://www.randomlists.com/img/things/outlet.jpg +- word: paint brush + imageUrl: https://www.randomlists.com/img/things/paint_brush.jpg +- word: pants + imageUrl: https://www.randomlists.com/img/things/pants.jpg +- word: paper + imageUrl: https://www.randomlists.com/img/things/paper.jpg +- word: pen + imageUrl: https://www.randomlists.com/img/things/pen.jpg +- word: pencil + imageUrl: https://www.randomlists.com/img/things/pencil.jpg +- word: perfume + imageUrl: https://www.randomlists.com/img/things/perfume.jpg +- word: phone + imageUrl: https://www.randomlists.com/img/things/phone.jpg +- word: photo album + imageUrl: https://www.randomlists.com/img/things/photo_album.jpg +- word: picture frame + imageUrl: https://www.randomlists.com/img/things/picture_frame.jpg +- word: pillow + imageUrl: https://www.randomlists.com/img/things/pillow.jpg +- word: plastic fork + imageUrl: https://www.randomlists.com/img/things/plastic_fork.jpg +- word: plate + imageUrl: https://www.randomlists.com/img/things/plate.jpg +- word: pool stick + imageUrl: https://www.randomlists.com/img/things/pool_stick.jpg +- word: soda can + imageUrl: https://www.randomlists.com/img/things/soda_can.jpg +- word: puddle + imageUrl: https://www.randomlists.com/img/things/puddle.jpg +- word: purse + imageUrl: https://www.randomlists.com/img/things/purse.jpg +- word: blanket + imageUrl: https://www.randomlists.com/img/things/blanket.jpg +- word: radio + imageUrl: https://www.randomlists.com/img/things/radio.jpg +- word: remote + imageUrl: https://www.randomlists.com/img/things/remote.jpg +- word: ring + imageUrl: https://www.randomlists.com/img/things/ring.jpg +- word: rubber band + imageUrl: https://www.randomlists.com/img/things/rubber_band.jpg +- word: rubber duck + imageUrl: https://www.randomlists.com/img/things/rubber_duck.jpg +- word: rug + imageUrl: https://www.randomlists.com/img/things/rug.jpg +- word: rusty nail + imageUrl: https://www.randomlists.com/img/things/rusty_nail.jpg +- word: sailboat + imageUrl: https://www.randomlists.com/img/things/sailboat.jpg +- word: sand paper + imageUrl: https://www.randomlists.com/img/things/sand_paper.jpg +- word: sandal + imageUrl: https://www.randomlists.com/img/things/sandal.jpg +- word: scotch tape + imageUrl: https://www.randomlists.com/img/things/scotch_tape.jpg +- word: screw + imageUrl: https://www.randomlists.com/img/things/screw.jpg +- word: seat belt + imageUrl: https://www.randomlists.com/img/things/seat_belt.jpg +- word: shampoo + imageUrl: https://www.randomlists.com/img/things/shampoo.jpg +- word: sharpie + imageUrl: https://www.randomlists.com/img/things/sharpie.jpg +- word: shawl + imageUrl: https://www.randomlists.com/img/things/shawl.jpg +- word: shirt + imageUrl: https://www.randomlists.com/img/things/shirt.jpg +- word: shoe lace + imageUrl: https://www.randomlists.com/img/things/shoe_lace.jpg +- word: shoes + imageUrl: https://www.randomlists.com/img/things/shoes.jpg +- word: shovel + imageUrl: https://www.randomlists.com/img/things/shovel.jpg +- word: sidewalk + imageUrl: https://www.randomlists.com/img/things/sidewalk.jpg +- word: sketch pad + imageUrl: https://www.randomlists.com/img/things/sketch_pad.jpg +- word: slipper + imageUrl: https://www.randomlists.com/img/things/slipper.jpg +- word: soap + imageUrl: https://www.randomlists.com/img/things/soap.jpg +- word: socks + imageUrl: https://www.randomlists.com/img/things/socks.jpg +- word: sofa + imageUrl: https://www.randomlists.com/img/things/sofa.jpg +- word: speakers + imageUrl: https://www.randomlists.com/img/things/speakers.jpg +- word: sponge + imageUrl: https://www.randomlists.com/img/things/sponge.jpg +- word: spoon + imageUrl: https://www.randomlists.com/img/things/spoon.jpg +- word: spring + imageUrl: https://www.randomlists.com/img/things/spring.jpg +- word: sticky note + imageUrl: https://www.randomlists.com/img/things/sticky_note.jpg +- word: stockings + imageUrl: https://www.randomlists.com/img/things/stockings.jpg +- word: stop sign + imageUrl: https://www.randomlists.com/img/things/stop_sign.jpg +- word: street lights + imageUrl: https://www.randomlists.com/img/things/street_lights.jpg +- word: sun glasses + imageUrl: https://www.randomlists.com/img/things/sun_glasses.jpg +- word: table + imageUrl: https://www.randomlists.com/img/things/table.jpg +- word: teddies + imageUrl: https://www.randomlists.com/img/things/teddies.jpg +- word: television + imageUrl: https://www.randomlists.com/img/things/television.jpg +- word: thermometer + imageUrl: https://www.randomlists.com/img/things/thermometer.jpg +- word: thread + imageUrl: https://www.randomlists.com/img/things/thread.jpg +- word: tire swing + imageUrl: https://www.randomlists.com/img/things/tire_swing.jpg +- word: tissue box + imageUrl: https://www.randomlists.com/img/things/tissue_box.jpg +- word: toe ring + imageUrl: https://www.randomlists.com/img/things/toe_ring.jpg +- word: toilet + imageUrl: https://www.randomlists.com/img/things/toilet.jpg +- word: tomato + imageUrl: https://www.randomlists.com/img/things/tomato.jpg +- word: tooth picks + imageUrl: https://www.randomlists.com/img/things/tooth_picks.jpg +- word: toothbrush + imageUrl: https://www.randomlists.com/img/things/toothbrush.jpg +- word: toothpaste + imageUrl: https://www.randomlists.com/img/things/toothpaste.jpg +- word: towel + imageUrl: https://www.randomlists.com/img/things/towel.jpg +- word: tree + imageUrl: https://www.randomlists.com/img/things/tree.jpg +- word: truck + imageUrl: https://www.randomlists.com/img/things/truck.jpg +- word: tv + imageUrl: https://www.randomlists.com/img/things/tv.jpg +- word: tweezers + imageUrl: https://www.randomlists.com/img/things/twezzers.jpg +- word: twister + imageUrl: https://www.randomlists.com/img/things/twister.jpg +- word: vase + imageUrl: https://www.randomlists.com/img/things/vase.jpg +- word: video games + imageUrl: https://www.randomlists.com/img/things/video_games.jpg +- word: wallet + imageUrl: https://www.randomlists.com/img/things/wallet.jpg +- word: washing machine + imageUrl: https://www.randomlists.com/img/things/washing_machine.jpg +- word: watch + imageUrl: https://www.randomlists.com/img/things/watch.jpg +- word: water bottle + imageUrl: https://www.randomlists.com/img/things/water_bottle.jpg +- word: doll + imageUrl: https://www.randomlists.com/img/things/doll.jpg +- word: magnet + imageUrl: https://www.randomlists.com/img/things/magnet.jpg +- word: wagon + imageUrl: https://www.randomlists.com/img/things/wagon.jpg +- word: headphones + imageUrl: https://www.randomlists.com/img/things/headphones.jpg +- word: clamp + imageUrl: https://www.randomlists.com/img/things/clamp.jpg +- word: USB drive + imageUrl: https://www.randomlists.com/img/things/USB_drive.jpg +- word: air freshener + imageUrl: https://www.randomlists.com/img/things/air_freshener.jpg +- word: piano + imageUrl: https://www.randomlists.com/img/things/piano.jpg +- word: ice cube tray + imageUrl: https://www.randomlists.com/img/things/ice_cube_tray.jpg +- word: white out + imageUrl: https://www.randomlists.com/img/things/white_out.jpg +- word: window + imageUrl: https://www.randomlists.com/img/things/window.jpg +- word: controller + imageUrl: https://www.randomlists.com/img/things/controller.jpg +- word: coasters + imageUrl: https://www.randomlists.com/img/things/coasters.jpg +- word: thermostat + imageUrl: https://www.randomlists.com/img/things/thermostat.jpg +- word: zipper + imageUrl: https://www.randomlists.com/img/things/zipper.jpg diff --git a/src/EllieBot/data/images.yml b/src/EllieBot/data/images.yml new file mode 100644 index 0000000..73ea5e6 --- /dev/null +++ b/src/EllieBot/data/images.yml @@ -0,0 +1,39 @@ +# DO NOT CHANGE +version: 4 +coins: + heads: + - https://cdn.nadeko.bot/coins/heads3.png + tails: + - https://cdn.nadeko.bot/coins/tails3.png +currency: + - https://cdn.nadeko.bot/other/currency/0.jpg + - https://cdn.nadeko.bot/other/currency/1.jpg + - https://cdn.nadeko.bot/other/currency/2.jpg +dice: + - https://cdn.nadeko.bot/other/dice/0.png + - https://cdn.nadeko.bot/other/dice/1.png + - https://cdn.nadeko.bot/other/dice/2.png + - https://cdn.nadeko.bot/other/dice/3.png + - https://cdn.nadeko.bot/other/dice/4.png + - https://cdn.nadeko.bot/other/dice/5.png + - https://cdn.nadeko.bot/other/dice/6.png + - https://cdn.nadeko.bot/other/dice/7.png + - https://cdn.nadeko.bot/other/dice/8.png + - https://cdn.nadeko.bot/other/dice/9.png +rategirl: + matrix: https://cdn.nadeko.bot/other/rategirl/matrix.png + dot: https://cdn.nadeko.bot/other/rategirl/dot.png +xp: + bg: https://cdn.nadeko.bot/other/xp/bg_k.png +rip: + bg: https://cdn.nadeko.bot/other/rip/rip.png + overlay: https://cdn.nadeko.bot/other/rip/overlay.png +slots: + emojis: + - https://cdn.nadeko.bot/slots/0.png + - https://cdn.nadeko.bot/slots/1.png + - https://cdn.nadeko.bot/slots/2.png + - https://cdn.nadeko.bot/slots/3.png + - https://cdn.nadeko.bot/slots/4.png + - https://cdn.nadeko.bot/slots/5.png + bg: https://cdn.nadeko.bot/slots/slots_bg.png diff --git a/src/EllieBot/data/images/cards/ace_of_clubs.jpg b/src/EllieBot/data/images/cards/ace_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1acc9d8c3c45d2a5157ebf601e6493662299e0c6 GIT binary patch literal 3794 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/ace_of_diamonds.jpg b/src/EllieBot/data/images/cards/ace_of_diamonds.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9a85d9553b904a69db9afb0f66c7f6df2e97628 GIT binary patch literal 3994 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/ace_of_hearts.jpg b/src/EllieBot/data/images/cards/ace_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..11b90a7fc4ea30f84472d8dabf778ec4cb8130eb GIT binary patch literal 4250 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 Dr`|tQ literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/ace_of_spades.jpg b/src/EllieBot/data/images/cards/ace_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35a9cb3e1e4311623255e640c4347055a8b9b3e4 GIT binary patch literal 4856 zcmbtYXHZjHyWaF>=tXLziHd+6njjL7ND~ne=|U8wi+H3+3FIi!o1nk}1f)cedZFz zY;5d+1M3061;7;GVE+gIj2tX*a&!IzUT$tKZa!Xqem-74KK^4u$M^*V1^DF4o)s^9$r3v0oH_8 zVSt^DgM*!ugNuuklQlbr^&Q|8;SyEU{+(OQ?kFM8Xk>cD%-q7#>Z<)M2S+Do7gw))-afv5{sAGOVd0M> zBBSD-#U~^tC8uP+c$t%%_g8*FS$PHOO=Z>F>ZazF);9FJ_w9ZC1A{{!hDSb5PJNxm z&dkou6Nt;-S60{7H-1ode(mnXD1{gG(c< z`+aY{!?7FBa9?=1HLlD)X{`(x$Ynb_Y0yq0%%_>BH;R?W=piH!0XL(7KzwEMJ51x$ zF8Mj*DRWx${&#*_;R)R=*m<15F0qTo6wwlZ9_H?1=Pw#2EcLgAealLv^sv``D2U`r96_sNd zo@t`ekkNvXStj6;RGY{xQNFX~FI(ng22weOkUoG=r&Gn4oZ z0`gJoCHucXprxjmdO*7xabe$$Q9|lgrWQ>Sw>I|o+x2r*7EYEUzC6v+DocA1{^8^6 z;tGym7Id*xCco5M#2?rOrVt`%`nAHj_V@3

=zPHmU^_$!Rc7oV`rW311}+iM&t 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 V3cK&=&c7XDnwLJPsY!ry{{>ZU!X^L! literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/black_joker.jpg b/src/EllieBot/data/images/cards/black_joker.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5894c6721d99498f07fadfcf1c14fc096e1428f6 GIT binary patch literal 5591 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/eight_of_clubs.jpg b/src/EllieBot/data/images/cards/eight_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df789839e35adebf79aa05b1fcca625b8628c711 GIT binary patch literal 6416 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 Y%S=Q^ecMb%7 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/eight_of_hearts.jpg b/src/EllieBot/data/images/cards/eight_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd5e725829495851357305a834cbbc3959ce06ea GIT binary patch literal 7120 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 QWmagxDYx9*RL1;&0q4XzT>t<8 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/five_of_clubs.jpg b/src/EllieBot/data/images/cards/five_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4826957ed51ea057b4ea2ab4a2ce39a54b534b88 GIT binary patch literal 5219 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ė|ZlUiQe$ZV@6oUVljanh0?pTChA4 z*DzQY@y>a?z6;~N5L@6Xa(7U#y_HfrsUzJ&veS!!e|T4>pg6H`DQ)WLS@_M%qUWQD zz|)=}d-a(~Qd2I~0Zl$XZ8KPniS^@sA!%rsV&jy8|BnEYXl5FF5!(x#t{$eL@P zJ~ruBH)w=XFK-?-OqzQCRsObkxF@df*zJi7d)L&hyg&O(ySR18YBCu@ggnZEJ=qvm zvB8}Sd`EsaJ46H4rAhMJ&$e6z8nje~a79iAc_rt@Off3*F=ZK3>T#{a=XV11nfjXH zhW`{?k}>XU=zoNl*Ig0dSi(J4&(s&&#{WiOIrVu(+Yham|fegCir{WPrAkn z#^F^8$1qX|s!q+oEbegMceCWh)_}C@!-8X9e5L{R70tTPgK0(v3lhXk z`ivh@3-iwmJ|6X=;pYg!B&z=2CZ^k?{{BRj{fhb&dU(364DGA9Xa*X{l!f-;yub54 zJaLm+b<_kD8&#Yv$=srpMUdJ+pnklSZ$NlJ;5(0^0Y@(nEPnojE^qs2Y0wt~DsfqH zN9~8Fn;R>Lk@_Z~t8A7LWcNxpF^?90IHxdo^V$a3(CO38@=5+kCDZuU-WIQ_Ew4@- z3*xye2)`{akazpm{ol{oV&Y-!uJ#NYi<)!WfUGIoQMfvaq2YisSUv%VShJjAp^ z-C!q%CQBj3HXaMRxYL9(=yP`H*UAum($dNST2uoDmF*A3+rP0uK~OzlzF-dUU_vs` zM7s2OEmmd4$dmr9G~BN>4t;iV#?8tS6bnsn-Oy3`S`}J6Qf0>7DZL+2yIgXsr??|2 zqSg=%m+1|eSpw(Ok++stcFe=7=n*sw{a1?EuT*4>riV>vv*#b;qQ&_aYmGfdW16Nn zIY1Liqk@Ku(I72{M%?EYV8r~qA0UMuiiji{e z*2DNwz~etvl>Sn zRJI_a^L39_0?Ul8`m|ZNie<$ee)MC^C zT5=g>iX#sDS_fOtj@=UrEsD zsj$fgoZlP!&9l)$KW{2&QyvLTl0rPQ`ns-8iz%SvgJw>XT3BcSb8)D|c7fCJ6=de_ zTUMP}G4?;lQ}@cKBOKsx4Tb|;+d=Q{$Ci0jP!D;@@7S=r$g(R!jk0O9zM&=aLGQ?f ziui215HLJOrIzO+Qv!(?oqu2I7#C&~EYojXIoc`n?1p!8)3@frKp*^I?&Mc8^2wX* zTLQV)1C$%E@2y33xTRlvfk<8m030X!yKA_-c{~-+G1g%D@L?a`nf`h=d!w8TZXv7X zp6DI+SFn61x)5@1jDG6Q$$Y+0zjkQvpnX|nfK0l-cI&zRw;wWxGki|JES3@V*%yU9 z_$%wEAK5ZH4}K~Fl>!`-ytjM;oHFqm!G|oTU$pE&`Ui#Cw01ll#my7x->2p6uvSD`@}j> z53NgIrA671i;C9SeC$4$C`v6#v&Y1~a4~3v*H@h2$Ue^l=F2_ea7|;H) zGWX;FEKM*k2k7||J*hvzve*wTjB-FX_fjFd0z@{iE%#u;kpt|t`pm6$6u}HJLk=Km zu^;&Vw{Z5DLPrao9wO0dvN^!x{6yYcL9_N!enuD!-sQ~%qLGi`ooBU6@P4~U9?GO= z8fauA;H{00YJ=9}jy&592r#{Qx5i9?WlU2`plBLf58|!gp5r6Qmio#)3~;sA`pREC tjQ{{|Mr;_Ltb literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/five_of_hearts.jpg b/src/EllieBot/data/images/cards/five_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..70aec60bb24e6f08b9c20d1ead1d1566be114c36 GIT binary patch literal 5677 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/four_of_clubs.jpg b/src/EllieBot/data/images/cards/four_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fec10981b7c426542b8815bb5302a986561c000b GIT binary patch literal 4583 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 QkZ*W(MC$8T0v7!EA4kRkB>(^b literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/four_of_diamonds.jpg b/src/EllieBot/data/images/cards/four_of_diamonds.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1dfa3aae3b270bb7afdfe39bad7cf9e925f8ba9 GIT binary patch literal 4933 zcmb`Kc{o)4+rW=?ENSf26H`cwY$;@!Q9_a?sS%2@#3XxSn57bhm=GdN63UXw_E^WR zEDwXRZ)49oWEqS(zv=nC*ZX^(-|wIIeXsXE*ZsZD^*#6Zd(P*+ukU@I8|(we0O59 zLVKaY!Xm-~dql-Vg~izS!oN1*__dOYn~%LvSdd?kJ^Q~Duo@8I1D*l5xH#khP7w|+ z5e~2(fB^sp567PZ{FiWWa&hzULiqRv1la~f!T=}x-JIN9JUraoY-=3*IlwK#BYH^v zEU%cw9f+K__{qo7X?*hMzSKxurO*{L9DJVe3rI>y@7sS^@yO9*$4{Ns)Y3kqV|d=k z*yMugMayf~QC2ssZ5*AP@4C36@A*FPd*~m42@HN368h|USa?kAtGM`t*NI8*(%)xf zW_|dW{k5R5sJP_!(z4pR`i91)Z{M3cySk}8y?y-ywDF0_sp*;7A9E|KKiAebHW^#n zzqmL6u76^&$A5zT8SI%J^4S8{WsXZxCVedTpaA+aftv3U}vJHN|1q| z+m1DoRGISI#))rdZS<`CE!#X|zV(Hfwa9-~K9L(3W2S!4pR*L!KX2c|BuuD2_X_w~ zYhz3jdOC1(8x^-p;)_KVm6o7I&)hhu=up0|<{Rp;$;G(}3_T0Q$QwgKer$V2zNc^h zP<77MNrCHr^B6gLt^RA{B=0q>HbmYhIEu#?#*LT3TG2-vN1q4IL{vEYfA~=%kF?Y) zQ_!T$?^S*-ntn`IFZD_Yt;Dy@iyC+R`4iLC(R7>H%{d&LGn8XWI`Q&*TtQ^#JuB2l z!J|7BB{7xj1A|HhgC-$*Cor-HI>~eaRhD832=FC@kY{Z>LEz7cB3^^_>iM(Sho2^< zwN8QnO@v;uD;Q|c;xGb%dJ5Z|_&4)cGeydP6QNd~=D97oMrLwGfIwI}O9UoJ=qSkm zfiZD=rn%eQH`Bn$dI6vX1fH7Ij;<;HATW5OKtRldDF>GXfizDu5U4&%W+YLClKlQ- zzx*V!8>~NeY^MH}l|j!sc~4Qws)?^)d&cD+Wv}4ofy1j`rrl@I9tI9NR@Asj5ReI+ zC2jl!fx-`5TI20aq&-+phL+G1O@l{BAJPLZLR877^ z7@$-b`3KPp#-oZ6#is>-EUyLaJgXfl{KF}}S7A)e!A5=9)MC>BPTDcTx9Vs$jfU8u z(le{$SsIkW0K!*KjmIaS2mfXrB<|Y*0)oPUPOvwGJLLY8Fqyd$gc$w^`l=A@T&0_t z%tYnXzj+4C8+b6t)W|&0$V>e#%wCDme`WM(3b?CW_zJd7VEe>h*?p5 zkGU;$OI=%^Ud~%|!pG)czK|aZ0v^i)v6giE2&@);hc=R#^Kn+IXL~7M4$&;LcUBoD z^V&H%P<%Zfwfl*1ZxGfG0)|Lv0G{%R>6kN^ctZ4s?ZU-5Bu1eitv0Q#HD@`fU`+BBDLv}LuhRYV2+DrXFCgexYF^p*41^04v+YVuM z%AVQ}2HA}^lci?yL(IdBI2s5uHN)_X)VrY5OGrDr8r* za|7R9X0`B>)|dNW=LmVlu0SwFWq87~pz-Zko6_1LQ`kY>*As82$w#n;`SbAOy`D^y zab;t-UF6l2C67;c&tRM!W00$W7XWxEwYC3r4t>V<8*X_D1h{tyd=>if-eFPxiH5tW zQd7vq7I$(yB4W*D5mAGP(1A6Qp6Qqn3y+B_FP!zrt7)+rRu!!snd@)*aB%a}23ZCK zoIzl~-hMZQiQ1ICSw;*!jk3r=r_nEKi#4QjXCrtI$kyYF1GE~-U{OraZeVNWN|AwW27fl zXBa0ZYT@by!#!q7echN1jfpS^$FAW(wXxob(FS73h$2IGVi;L1dptra5KAgg6o0<- z*26IgasAHLfvC5=OUl^g9Tckt1uHy|D&FnBU)S8kwENwY?Fnu4sgE#?xBC6wrMQ;B z-r$reB^l(vRl9AbmE$^D5POy+;4lJ}(OS120fC{oLbu+#RXFGy#2x#7xu!;uK`fe) zn7Orm-e;+!@O#&>hjW#t)7>Es+Gf&o!*4C}c2S?izN&Df#jD#^_y^vuw zUeSE{{`umBd+$v!_v^QORWrSxAVMC?Sqb~Oy& z-GpYf$93OQ40@R!NL*IYP5Sw>;-lk7-!8USke}!!#H`wYAET)veg$x`^i@(f*=X^hQkCaa|D$U49D58dJ2$+pQfr-wtk?RMk|rBXG@9G4%5Sda2wx>eRX#xOVA!YN`n<$nGk#9RmSIQ5 zVGxijCW6529m1}7QJyti6a=DeO+er?j?43Pc;e)R8JL7K?FCB_;dY{UgNU=U4q zWk+@^Kw$AWu%^mS_?DLr0)6mN5HM19Lm{7%CsFKLxB&A6fp_smAAon^NB^ezM;P2H2y8%0K!9RqLye`WZb=jpb|8ZwFq@HQ0~|l&A^!{= zM=?}08me|C8tAuYT)0p(O-2wrJqP@+bYVTyu-XhvF2+h$jQq^Hdr1zPKbWrjwnTeQ zn4R%I%j6JcBC{U7o9l*0g#7NZuOab;4^wtgbM$=7Fms{OdYe1zR8b99m{E|1y~ps* z2-rF2XMqtmE64S_*=9(`OKzfm%w-@0mrv@uWhPIcj(hoETJgSN)3^U;or8Rfwq_D; zKP64W;=8x_!Bb!5cyGV`QmwFdpsSA-*jq!QUm*^hn=qpm5}(@fP+PUO&8Mo0a)xS$ z>h#W=x0zKMv zDq1#hjJEe!Uj{mZF=`%js{DcEc1m`tyQeTzUEiCOi1fSd*2VtL!0Ylh0`FzI`c~Cn z>-6L00&ZTyxbSu%%Ow9A*(#GfjLE-Z+cEtg(TI#%PxyO0u4)*-)bIoLMT%K;CBxv_ z5z$VMrm)it>A`!xw$W%8n6aOO=6AJ);H628hmh6ArPXQHbkN{@qKb-#6FM`=_{6HN zsP*eqGf~qc-Mx#O4XPpdy^NZ%`B9#L-b=RSzhyLQkK3XRww%MrA>FCaF&};j#>z_h z*yi&p2=jb5mSk<5>7%^Xsvd`Uwe4gzt7l zb;Y1!z`aDjBS#cKAP4dY?vdfW*>`h~)t9wQ{vlyPyV27jv4@=BL#!k);wdJw2naHq;34?RO>8sQQ64j8u|2s|1U z@zfK`DY!Why^*5A&Xv@PLWgtYw_ZNE>FLmOO3mYe(owEG9&0-fT}BxaZ=9OrE|rOI zse4)}E-%WJsSH&*{_M52+f5<6dP?Hk?bKPrl$y#;)#8R6v-`iR)5}%(Vb*H_hwQD-Gtk!hWy!Of#f)@?OvtD zH0|PP2sbUS8+b7PdfM5;W72Z-mD(YWv6nYC@{94ROtVfF6su3IAmpHJLeo4m8h#(_ zKj#$PM=zCsdUL|Jq&Yp-jtK3{52-DSn{xF?a2{f`OMTfw1(BK{uR5y^!A;xr4=cZN zr#8$^t|A1`joI@umM?zpK9T1a zpmHQiaPVQc69`=6I~Zkrwr;QV?IkE%&Ln zpEN*hNuLX{`nU9(bL8JM>O727f<`JNFSMlLJ0fTpRRuHKJm~eXCB+&c&Ey3*h1bM~ zGj8qRc5f-g8kH_Ue=w(%>F-<`uXMD*WMA-`kP9Pim>fh+T;cq0=9)zSn(_LAUS15&% zx(1#1*OcX&b!~;<+{ML@c_oih&SgKI1tj#_Dx@B++6>hl_}rX%Mn2k5>EqZFD7Q#o z_e{pwhaUKrV};kyPt;%Nx?g3CiS@Z0=!rMAJ`i;^dFu^z-gn$wbpt}lBcQj6&}&pe z=x2kn;mS8Ykq_)S>$e+o_q<+ugQ|MY7~XFv86ti!`-6)3@kan)^aygtPJ))t?(AeM z_@VVUA5Q@W^7_jF>e~9}*m@~Xr8&_CfhL!`Ri-2FUz!Xz-h9a!Yd5^|czLF);FLpm6?jxSDcvtpD&~QrUsZ28*w+1rsgvCKKi-W{w v?msLsw{!6~A4g%d--S0uYIjDy^S>)S*B@eZwY=Q)FhwCQVXJCs0qp+=H>aoO literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/four_of_hearts.jpg b/src/EllieBot/data/images/cards/four_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cab1d8a4a2eef1e6099482f26be12d16fe04fab4 GIT binary patch literal 5106 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/four_of_spades.jpg b/src/EllieBot/data/images/cards/four_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fdb1ca2063e730869fbe6f4aef2e3a3765056788 GIT binary patch literal 4434 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≺uh1iT#I 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%0D(Dug)-rPo(k3@xPh@=bJD=bEVy`T# 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 H#F_sCN70>+ literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/jack_of_hearts.jpg b/src/EllieBot/data/images/cards/jack_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fdb8e82797fab94d3bae673f74cabadb04c5e2a GIT binary patch literal 9558 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 N>4AY>;?RWI{{=OR6QckC literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/king_of_clubs.jpg b/src/EllieBot/data/images/cards/king_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01955d28419e0b5b19db8527d4bce2b4d146d094 GIT binary patch literal 9331 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%0AIV4=P^{zsy<7!i2#~H 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 n^0l6onklq4F6G7=xq~)cF^iGrxp(z4_ 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%0D&dIF!jiYBRJ#4QgG*r7H4HyP z*gJ1VBhHo_f3LiWljMg^L)e9Z4vlie1{uhbR)1kB5vgB zfWd9!C=w$758(m)hw%6`AHqa3pQ{$6Kx(IVjtJ0^gmMxAROUoL%2;m?5%Ac*_Uig* z=h6RWEutfqD`1D5ILk4s=6@cy@6KKQC@Va{U@fMh{?x>@P}erY!~nT4Bg&DOQSK$(LQd1QuU|JKtt=n*VWa z%&xSDw>}blH|V5E=oeH28MZdObC*l$7L%;2^4ROX2izrsReER7Ypm{h!xfi7DfiN>ofx%a2-`+Qrp9bxttGzMnp4(HIY>14fAIvW=D@X(^ z&}GQ7SmJRm%Cg1r9ZiHDlLK(h76+4Dd#WnuKZ%fa)gV8@;Trs-iey_*IDc_)|e zf|WGM6xAkkll?0$$2XT)@HE(5o0+|XrY`nvuI62zpVCeFa);t7j$)%49~=JS`x`G>D;?ji?ob<+TAjH2K$}h_EHUjGy^2H1Ys8nH12A7uU=NHHs)(g9 z$3@m|6Zoeb!x%4(xbmm=GWMEYtI3PMuUE^s-n|EW;+0Jvoo?TMX&TWxRfnVTfss|G z3MEXjEbFxGrEV2zD9`HQkLi-Sl;-z_Uo?)m>oI95OrD!xEe*}Y)jj=*9Y-kdE*RWf z^wO!WS<+sUMqZxQcWLrLHM*D-$)sSI3EW7h^3}rL`MKvUfeOk6rm2F?LyTTBULC8A z8p%q+%lb6BT{ORc9IdHfQWqD0#RC%4`%;TIG!SetxF2Q|MskxWw{utcPHQ?C6G*?6 ziBc{fv=`eVx%4q0EQ{~(&j&BQKxaDNmM+cjM(+0~M!4(3LMo&s$FGu|4v)V-xxb*E^bmzL!Bf7hTVAQ`9YX zm)j&IL4f(Yd-c17e~T$h_I_iEt#BixU6UqS!O1xQJ|pEq+jE#&)p)f0Zbr~E;Idd< zTh&|>^dE$!z<&~!)5^)f+g3qn4{5Vx(3GE~mv)+g!XC&ll^so$@nD$Knt3HnnJiGC zn7*P8aqlkLRl;1jJH-72Q#$Fx z^H;Cg@J)940am_N>oc)>6|s`M)tR{P@f?!`f+X%Yf{z~0P_c#7LwEte0^4W4(n#US zlWSJgElIp=sciW+ddvD_kr}lmtE9A6xq$1~9^1+<4(5!e@gB~7raxa52e-N!UfSry za5=>d5CMFH9-eKck3*jE8VELWYc#SLNcb2C7JTjujF$;+!Z0x*w)5N{eg6?SAqr}2 z+Y4)!L-a;fj@X|b?uQ3$YcdeT-IlKVkA$KvW7tn6<<InBdLVqXHm;W8A{ftl)Cj1LJ@72^!UE>ccG1ym98dLuS=Bi$ zAjvGHXb-7OFFV9nS$t}jZ~SbfEIDh7J)IQTnd@GjYE7INE@(cTBuE7f>>n9q&s*7= zI2E_Iq-7xOg_W#z#Z&Zq`k|TNbZ>j!iVW8$Yi%A6o`Ide3k^F}w0Z6w!@*BgewZm1 zs*+NVpzUx|cT$jA$^gH^X?%Tjbyt#_zx_=ZHbTK}E(8r~;TBeM z@4vX1dQ~gs*fK%Z8gKmM5wQQVH!sHd`xAXia-A?wLv2-r*$3|mDMq?a5-%k#7&R8F$?&S31_g0?J7`!R6zzd9y8G1L^2Fs;J@9j#Cy)WxvKsDat)^mz@Ur$-fek?$!j@I^_jvP zFOM9WtObUK=08-)_t4~=zW(MfA?Y>~H4TnC9t*v{@_6u_+`O=Le8!5FVprcmad>J2 zSb6fC8y&b?%G3{w1T%Kt#mlrLcyVYIZceLpRQXVxX4`X&zx0M>pyx{pu=^`(YvRa)c3WLAb$zUwf_EBBvcfRJm}GT2<0=yd)<0!2{O@IJFoWR=Vvu9ZBxL(6M$DGOK(} z1hAxC+p_DzOB_%}{CX9!tgwXFVYRGC9-|D%H zkkw^K>`7rq=DS3dZ!*5KqWa)Mp)oTWLCOQUO2@${I)xy^McUQ4!6#U!v(xE9syqYN zoaai@SRLN;S?B~>82aTrgx9sG-V7BEaSt4p=~D@n@(TD4DoyX&s0@XFBhLO02Y$yN literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/king_of_hearts.jpg b/src/EllieBot/data/images/cards/king_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..467b0cecd50949214326773c35f700a1580f5ac2 GIT binary patch literal 9541 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/king_of_spades.jpg b/src/EllieBot/data/images/cards/king_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e7a6857065c352ba5d9316fe9461e0569d249e2 GIT binary patch literal 9248 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

n`(zW?ibx0xq|k&!wNVv4L~86q3;8VYe+&9y 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 N=hn(!r(Y>E{{!TV2VDRF literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/nine_of_spades.jpg b/src/EllieBot/data/images/cards/nine_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fad958b811582f78be5778245769462ecd59df6c GIT binary patch literal 6577 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/queen_of_spades.jpg b/src/EllieBot/data/images/cards/queen_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69e953157e7bd02c50f4364c560ae2de6a932266 GIT binary patch literal 9613 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 V{@|Mju~|h$eInS9n~FU5KL9$X=ehs@ literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/red_joker.jpg b/src/EllieBot/data/images/cards/red_joker.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e909c5bc8b0b4874360564b4bd693d8b44b811c GIT binary patch literal 5742 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 s1Fq$C6Ny?_Y2J$_OHtLo9xztq{)c^nh literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/seven_of_clubs.jpg b/src/EllieBot/data/images/cards/seven_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad0c1cff9b1d50bd23d83e704e8437ea42da55d4 GIT binary patch literal 5965 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 iY8}I>33;TPC*yKMp4&z!uJRO literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/seven_of_diamonds.jpg b/src/EllieBot/data/images/cards/seven_of_diamonds.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c15cad88caf99ab62ff133723002eff9c179d1cf GIT binary patch literal 6213 zcmbVQc|4Tg{(r24WULV}vZRuIDPPRo7KG$WX|gBDGMJET!-QlB6UtUmBwI|Fu`~7w zA=#GSG2F);%c zj0d2P0apPQ=HK+YWML31JL_-aU}tAz=j7nx;^g4ush{?>G;bmzR&1 zi<@77pI3nK&HH;0rr$kTSUDISd5>`(W7Pg1iQWM4aR8BkEen$rz|6>v(Ku44=aJTJh^n46iEg^i7smBAg%Xa`vN*!WMYTxJ(Aa{x(s z395!BeBhA2Qqm}7-b;~DyYC&w$#p_l7lcWtDDbb-zR?l0fFJqBA!P^MaLv2y?ULTlA4yDmHjd2Q*K^Bu(1CZvVQ^lZ(O4QHwzPE^H}%*7;unzje7i}t39YzYjQ0@ zI2po?puk1o^bZUfX0(L`wd2ZG4CQDyk_NJhpH;0-heBa?X>kXZ) z-P>a7+TFSDI4>Ve=0hQmPK0!lgtzgO4tjW2|Nkgpw-j#nw8Y6v%_y z2oEVzLV`@LST{P<;6e~r+D&DQ`n!a32pBGGVfI1zoNnSk+57)-DFb)L)s}7+sHnpJ za}h&b_IS*4JH>~rSoj_hNP2G7y(e82G4~@Eaia3_j0gYT-A&C+T!o~Hxcp+r20Fg( zvFSko9T>gM^k&_8y61Ta6Y5mSI<(A7aP;k{yNau*=lZOj&7M4tsb7j>Sqik=w*rND1cb^Sx z*>qSPXs`v}-=5u@7&Mrl{g5}ZpsBVP_p<@HUon)VAUk+a3 z4S^o&b-%cfNr`b`Hnx=&lb=gO2Y7b`3O9^pTwz*7EJLVg<-(zw)Rd_$zYx}b6XG*> z-p=Cr9j^pm&AtQ`N!pI=q9brGj_60BIUG$T^q_{`v{dfrA6cBqt_eQU1>-5OXJ7a~ zZSKF8HZQ1k6rux)2Nh`C;7^4Cl4(C?*m)-nN6nw?L`Op9`}_R~&E-q{dqtaWnl6Ch ztIXO(<>EgmVpYTeBYmcAYzr*hPMDfR?ui=JOrxZE_OM2ogR zXA0`Yl}I#Bii83s1N3|oi3lwyvf6mO-&jwWLLwIN##eR<3taclyz%|)HuPm=#ImJt z+~&rVbd1Kyhxh#f9+MC~+7Jw5^Qcon4)D8RFfU&q?J}?u?2{AvB}(LP+4jZ`DWZFl&r9s zfBeaauDY3;)Yim&vE0O)G2xfAx_v4@m$0Ks$E>Jfoz0`ZxiNTc4}-hU2l)3_M@e5} z0-o-@bCg+O-RYsii(XDIPAl*HmL=m#XoNx6krB$LG~R4Zy2)GAzJq>2Qf7joD+wib zrt3q+(R2U_J20xVfxkleE@h#|dT2ke{)cb3z?{V>h3s%T06j5G2MEUST}hFH>m z!pdUNoQJ`nSRL_CrT&Q4KFv;-TQfL9x1AtMR=wZ*?FkS7UkrBe&uyfMt-sF6$&AM3 zA*a3&D*9J`TyC;yI3Rm%IoO3br8FyNFV7GRh7Tk-$cF~(vk0-98{sB5FH%!X(*vLFHT~Z z79|l)J0#2ga;T=&wW-9P>wVq#ykV8O{qVeyJ~SQ_0dvOkxTkdXqu_bhx^fmyS9xZ4 zr($Y2JaY^ALc6aYzFtSaKwX{23M|?wt>4U+WvFTQknk)hiDBC(0XF}tdIwX5 z_h0V9T|e6_mvXwhjcO_PNYv8RuJ+UA1fv;S8vt+8n7+Hz~&&2sqF)$hCDD&f{Cx zdvX@POR9}@#-B7@KTVU-QQo>Fy&+77H)91*=hn+}Ct<=?9KH&wwz2S6>1rLuCs*Su zC263Sh%JL1{-a!Xnv}o!(3C-}hLF9GizZq7+!^#6^U})^l9_cf_t+fzpNb7upxv<} zPwX*#RA*~Si&=B=uzjjDCjc{047->p^Mr2{azSxoI@ zu?*24k#T!!dBenEbvsCJH5anli7nc_vFEdM?kLfb+Kgt{Pzd>WHXUdZ|I|}D+8b)W zf_Mf~O&V&y`gHh!I5RI=zfa9v_iKPL;m}|(uZX)l-uBLzURfAW^7;H6yGeHFDMZ-t zyoz{DWham6Q|6vuU=4Zjng7zgxPT|n+>+w&xQL_{0j&zr4)q9FthDe-r_8U4leQ2$WMTr;i)nYOQ9gjPIRA zY34o*=jt$>NK}dNVu*7HVh!ps+WnH6?%!dA*Uj8^+;FD@(yf$Phg*tm`ai<=G=3OY zBh0pc(E;(m`OKY7I)E!2XbmtR+EvRP)zX2L^9wqTe^uYSfs`qwJs}+W05nDi=5vbN zfIYb#IzV+=Pa@i}W6UWMWg4W&$FDZGkvwCq(Zx^R9=%tdy%$cilt>*{^@pTttu1wh z?7ifeB`Cv?u#qNMBvc!>z8i-7Bq|)M$c;oGCG^Ta5znZb^*XgXK_t6Yp1rvrtRU)#?8Y%-Mft1(|)DGUC*F9D)hH=y}Kq)=CX;9wC8J|}9p zJAH+g%|%j7Z%bbUOCH43*L4dr-<02pY!da0Qpa+;1|nm8TL$q#K@Z}0jucvs`J9EQ zMKzxG4uU7q+6iSdkqzkQ$%B4(dMl#0pBdMA&V`|VsD5EN`r0@O@?qQ)UP6lx(hv=1 zwWK-)t9im?CL1|L>=t>sXT;%sU7T26$HZ1m`EJ>KjobFvFC_IWsEH73r$e#%qbE$G zYOPi)`$Oe`&PAle$eHto2iK+3%E5aN1B0iM>{DBOw%6?Ixz)bIXTd9^15HdMgxCEL zITIo0#omb zUn|s_kaaE0*KBH7E^H>WNYVjsc&y}mj((&rjmRXJZN|RXk|&a@iMvk_AL#!JRl87ON+}Z*-|DV z$=8>shHzh%vcJ?u{#kCB@+h8s=I5#KpQciHH5*I|GMdIqwRinU@~<(szV7?(4#}Wg z?o^MOgW=q2tP{qe>&A>o+vf1taU;B2fym?WiFV}1AKyVDxwizj)b~H$7y8e0x@l+j z-@Z|*#9st*Yx^^n6aBS_ap4U^8DX2Af|~|#)yLPv390aNe7%|V><>ekSRp>3{k|!{ zlxVnMp9CxSTM>p3?W0^Br#e&6oc=!FD*8nD*~W9DJxgeV%((}W5Hj{NVe&(|Gw~Q5 zhu5Gx(>s_}7EM$>15AQyU|8nQ5T@X>osSEZL?l3w=Ar)suua zmEMOpO7JvxgQF0)V;AMyR2Z(ar|rkViJM1{k1UQDD(Pwsi-od9HfG2Y?5Q_U7d>B& z%YQkJc6)!`2Aj{qMT-kRwAdQf`UNKoHx@#otuQU`c)-u3wo$hgS%&MfJyfRGw39YI z-wWO#DPGdm3+eOMhY9LUz0*_@HO=iQE-F2K#YFd{LIw)err~|vW`C&g<*bkjPQgr@ zXuO4{1ZA?2hd3NAIci!wvXE}K+Soz6L6l~YQ+vfJ>Ppxm^#iRn>}pm;MS0w(WLFz0 z{TS76-~1U8L~PvJX*O)nWaiZu}BiGs9B`VjrOUS&$5Iir97sg6h%lB7wbYi>t%;BDjKjxTwATIc-}dLQt&iXai#`F9AWbiqeH{JR zCsbK7p;t4!bs)0JD=DIz>bdlm7VZCrIEriqGgB`T15KWPa6%L|dg(l}x5nL)+kbzV z)mxQE z=%vD2RdtfTv{hMamwZd^fK~g{fj&qEj~>|+`?Q5HQwS}`w8deqfi`f8>u6kgp(plG zm={VN+g#KRGYH)Dxlykb2Y$Fa--Da9Q^7W-rMEV1o;{aIB62x1Z>%;;Nv#QRB%4L2Rriwo!BMu~}YJE(?)dxE%z{ts!faUTV-i zcd}ewhj{y&N@DHo82VRjayxGim#LVZjIq?E^Bv9SFHeT)s@T6Gm6MidAdQ%)mrEG} zeeW3AnJNim5vePBIm23sBf;@kCAVbJ&k69QjP;aIl+tvi`jWlif*Gkb$4zq|UqGPP zG>v7W8+KOZlhiu1Q_XgezGcuCq5hqGjcF-^QvtUUanr#=jG!oYu{uNRK%CZ{Y|jD} zZw@N7)JNHpIkKw;K1rSkz20G!znq`pHLwxH9W?V3U-uK2T%j!U{o5xkX~=J6nPfp`QK9Qj-{J;%fa^R}zZ{f=*Ze(L?1z$8E9hH<-ljr7!!(hhsC2ikQH z@4D4MI({$Iw-BK@BRXHj+_K;HnLBm$4ScXZib@h~mWU9%UXZ6Kc$N_!y#ROyGRZ&9 z=|HPJju>`$I@`XxJcIWK5~Wx4*}U|FYeNMt=5IWla$S##M!f&HlR`Wlng!n9qnW{> z$BrBD%;xD2q0xtICClrIzG)Aaj_Gt4zKK&$TrU2BtVuL7*{+sHi5z_h5u>h6wY?}B zcJr}TwU*5p!0nW-Ra8X_ImNy#&r3XORhVkvT2t zd{QdroU(QH93&DdNgbL*)cIM}ey?RIMAV<{H=$wkjSETA_0YQ?^iF(~G1F(33STsp z8MI&VIB=kX8un??Q*lby25ODbtZJsH^7Aic^IjUvgblG>Oy(labgT5p37Xjq-}Tlj e9N+eFN0n?^|1g0DuYp~6J8OX3KGKJs6pSWWW) literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/seven_of_hearts.jpg b/src/EllieBot/data/images/cards/seven_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0dfe10bf89857bcb5a8b3d430c6d20e5c92549b8 GIT binary patch literal 6617 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 GCjJe1Dl#?z literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/seven_of_spades.jpg b/src/EllieBot/data/images/cards/seven_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8458ab5ff5fa33e0c8307e022ac8bd72e7a4ccff GIT binary patch literal 5796 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 YT75e<%KH?mDux<*rZG6!k6_IH7kUD;RR910 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/six_of_clubs.jpg b/src/EllieBot/data/images/cards/six_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f205dc0c8dee32a358d8ba8f292f887c94ffcf5b GIT binary patch literal 5736 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/six_of_diamonds.jpg b/src/EllieBot/data/images/cards/six_of_diamonds.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76a36be4958ce25b0cae0fa7045c2a75a1ab41e1 GIT binary patch literal 6113 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 ZwhVe=S%o@JtRL4A*}n~n#os4S{0CTP1;+pY literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/six_of_hearts.jpg b/src/EllieBot/data/images/cards/six_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2bdef7df11575b22c3c27dabc40b79cea48986d6 GIT binary patch literal 6416 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/six_of_spades.jpg b/src/EllieBot/data/images/cards/six_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3877d2f6576cf02d73236baea53f70c35d7a2b2 GIT binary patch literal 5563 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 Ld~$M9SX2K6NAedw literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/ten_of_clubs.jpg b/src/EllieBot/data/images/cards/ten_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6322cec56816cdff6bace4c726ccdff9fd669471 GIT binary patch literal 7417 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/ten_of_hearts.jpg b/src/EllieBot/data/images/cards/ten_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a39d0440b37dc3469b913dda126ece76add1fe3 GIT binary patch literal 7770 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 Xr_1=J_8m2w&0cAmm2SI|PM`f>jt-Bb literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/ten_of_spades.jpg b/src/EllieBot/data/images/cards/ten_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f300fb5c3b0473ffcd3a650d05ced2703ce3083 GIT binary patch literal 6862 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 W@0^;el}6W>ZaIJUHK|*ynSTKay|;Y; literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/three_of_clubs.jpg b/src/EllieBot/data/images/cards/three_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd2cdb5a96c61148353f9590859df57074715f7a GIT binary patch literal 4052 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 E0&US3{{R30 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/three_of_spades.jpg b/src/EllieBot/data/images/cards/three_of_spades.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18772596cdafb449848020bee222383720012f60 GIT binary patch literal 3918 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/two_of_clubs.jpg b/src/EllieBot/data/images/cards/two_of_clubs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25edc74970b4d3aae0e6b3c483dd78c600fa239b GIT binary patch literal 3441 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/two_of_diamonds.jpg b/src/EllieBot/data/images/cards/two_of_diamonds.jpg new file mode 100644 index 0000000000000000000000000000000000000000..758cf6fbfff7eba8a0c48e654359618e7a5d2592 GIT binary patch literal 3804 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/cards/two_of_hearts.jpg b/src/EllieBot/data/images/cards/two_of_hearts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2758ea24331d55c79eba61b8ba2badb2409441e GIT binary patch literal 4016 zcmb`JdpuO@yTBLYHVA`Cx~SZf>*w1aX<@zFdxd{2w?~d8_S_^u(7eSK{+@%p&U>sCpRxQCl?PF6nX@9gol@p z55~vI%`d>uC&0MpJA4V#;YtV#2V)^07nF-J`@a;h5rA<3v4Aav={&#;V}ih#z*ay6 z0GL>r{w=_N2op1eg_Vt+1Io$8FsR}Km>J(@W`VG>vam3$Lm1Bi78oo4xyu@C0;Ue^ z=Y0g_!;^A2L^aEsj+*t8#S|PLML;=^9Tz$wEG{7_C4J$FqLT8jS5>rbXzS?e=^L2e zwt!n&-LZCZcDe8Rz|H-!?-M`&fWV;0sOXs3xOh}@%8S&r^p_c!+`N43+k(QPcNMtG zs%m`AhuY?r*0%PJ&aO`bgF|13M@Gkpq}jRog~g@im2Z?En_EA(cc{C2hg?hmcKI-_W zpYxd56_PmR5bfV&|1+?N{}b7Ng8dg45#WX}F@gty0qVehVt149@urP1qGxt9I%->Z z@}MgE1spEH>R(fn*{xGklN#;^@k!Rb>iN!xh}$wUY(FDFEg%tMMFh4?m^@(A>h|r$ zFB@6|!o!AF*DZu^BwszT)2c-|dp6=1-Sf56XK1FCR5h}h$jJ$}L6K1Vozab?7!!xPitj?{znI|$2S#W%vu zhB9`;Gbn^#Rhs0;PBX_?l3b31fPgUwMCmq9Z^^D8sjP<+)=rR9=9{)1pHHZheN6%pG?`2uZjG{9AR>eppExpfWpD(bW6%4`Mb zQ^@U901>}$LLbRKK^La3-Xyb!$>sD_9!P2ry1Lo*NCYpXP2Me+XJ&EwPV)JLzy69B zg`CM1IrG!#QOj-e`uEJdJJvRuxY3Yj5~y!aG#2Y{E)h6a&U{Zhc@xE-=ymCRxlvj$ z)go_IMbNZq&WKk(Yz23Qbt3eZ#IV+KN2)i;Y1s(Tv@aOil}t0Hh)tVx2iR|4;2jLlzEBc~RZr&~(9MDpkm3TtlyLf{QGche*o`ZGj{xMyRz%B3${u9dCn zW0ODQm;`guekORKuo1Y&v|^y6^NYvoECyv_zWeEYo=V~^xY2T*%o-wd-#(Pch&|*< zH!^mLW#D2NO-sDOcIxi5*Mp05h+TJ>-la7r)#pIRUDT$17$aP!CHHqM>IOoU$J~lN zwha?9Jq?Y+b7aI!)A{OM;;uEP!dVclkl_#6RO#bQJ;4T)pM-XgYk`-p*m`jVpBxi( zwzh4pyQQ4l8U8!6KHvW+1$k-{Lq&8bb=;#2Sninj`#zu-&y?}jSjJJ!UL0Uj^*g38 z-WY{%>DsOX#FCxsbwlbiSfntPqVP?{KDJ)bJ9jq&ZG@T97wPWh+>B-SQ+a+lE27~i zm7S8VL){<~TRQgCipMIyZ;zyTjbnxvRoT)0KAmTG;HPCM20|`bR-_2YWZir3;;uMRR6IFAX?2Xad{w&S--8_smh zU4AnE?h^$+@g1@A^ptoDLhVI=7IQMzwo5F<|HZ@I%n=*6vJjQ54Q)Zok?b!Hb|#dO z(s&T?R^K=H==j%j8^j)!e*IYgE(p8~!P8OJbq-j!z1t?;4| zxfvFsaby}jCSdo3LYOIwreCGPN1Ex9ae;n8snt1xIgh#*I=SPwlGP~LJ2+zf)9H(e zP6pj`HtKx`ye*|FB~2O6zA2G62YhJx^&_*DYlxhE*3hoL7FKkJeH_rJ< zQM-}E0xFt@V}G+-n}n|KyZ5B9q~r|_pEx`$h!VQ3D}1&&H$3c(9{^miDE-XClf{O@ znk+5$zMf4KZ}+itQEd_0p<3#7Vu$gn2llDy@llgFtRtRUwdzlKPvLNm5rwZh!zj`v7ZK{?{0W zsc|*i|Bzvn$ZcLc2=p6Te@!9D?H;W}?z4}Bz%sVP9gxaJ{Y_=M=qf+^)z_Cmz|Hc# zWeV-dYA$lTmp<@@SMwiHb*389wLL}XP1_)_C+%S!#wnE>#)nb9WfXv3*WcG($;K^3 zZS|PICf$jpSQe#i=LO7|7`!&+OoVKs$cD+$J{D>8xKJOr3Y(y|40-vNmCGkrh_5UC;kfok6*@CV)stvE9=H5U1Wax}GUhLk zgcd929YaaI)%(kq%Pe~Wbq~Eed`NSPJtyGr8?HczgTVP}Gzi?=M;-`PmHftfW!}8# z+2B;T0-9PzF=`L~ow(y6^pg+ll%beWpch24au47pBVx6wjrj z_ypy%1BA) z6ywbKmx)nx9K81mhDN$RCCK7Xos?g-rX)6mK$a7m^x3HUIT##4Pt3F@s%fcD}#eGtZ+Tv z!g;ziSy-*L-dxmHfVaYH`)vcvn63Jy>3M|xGlW1)qfOlJerVMf?z;7u0mGj0sr~(I z{XwWuubNv2Heh63dtc-50JIb-ZnF3XExuiM&AX%I*L8g&Lqz095Buk-dLCMck$Yc` z(NIx^I!kv2O~*5#Afj0plRuffNyq=V)~y~#=NnQ*79!*;zvdzN+^i8QsXc|F(%kPq z6-s-SOudrNqzOe&28##H$DDbM?W0T8| zp1mJ2Ufr8GfS^^C+Q=>{zb1MGJ=QlcTpOw`?mtN1**$>%BdNOnkto5giw-xh>`6fy zk#6c^yiLf;n`uE`zZ5*q2|%^W;o1tv+bb^qF`sm*{FN7wtib|H89HTolB__7GI|x0 z=-QHzI8}!dLPFX7D$FM#=PEuMjZ>XwI^)TAJ}F$%pAiU8!R$4oNLe<~uf5+JaAkhj zqJ}E;{_(-%lhmwpA@UODQWtS0P|}HHt4oIllDZK3VtcM_r*#H31O3H|N5$}$J6`QN z+BVrh!rC5xI}#F3?jRAO8w3JmjLDLb@1Ip?yv?~iHJ+b3`aSS8A$}}gY=6(vLR(eI zKBlSb%TxY`PgfH*8_wr(Uw4gra_&ekk&xG$aeX`t4cJHy=mLSf7XYz zx^bi)pSCm5w)k7QeCSV?yODTK9*s_!X>4%Y?V<1Q*DCijKkDcW3~<=#6E#w;zUn)M zgt6hvbh6H8Vohz;dgU&BF2AFrl%>onDg4~u$Y#*h_j@HyU4HQ(9qD>4n{{O`G-Ka_ zs!Qi5RMn?UT|o`wnn{|P<*^fWdYun{Sk3#EVST;BF|KPnG-k&oi!`oYin zq_|dGZ6i}cmcdJeoSfN2W?|Nj;iAzHJ%Ej`BVbH*RPn%Q_1W}R^IaQkDqF~{hd#nIW+;K1j%$bk9uHOwClykNNJcSGVeZr|Q-_-#OobKf=>M z_Jpm2EkGc)0K9MkcpO*(ku87VkFSUjqGF;V5`y zYaB`vt-O7Q%HDli+B&)hhDOFFM@+4(ZEWrA9Zvjm67TBf?&0Zs&d)y}kQj97@|E90 z!@?utuO%cVT~DUo&bX7Am3{YKPC?`(SU7< z7~5m z-|!&rFN2ZB1rBGq`XASA0|OF?d#4moiJewD?{0N<7_MovvlFiO@--p|0)!0=TKZrh zk(NMT^y-HJTM{GKmj+o!9)yAAWHt<9oGBawN|OeYyn$Y$^S9i9L2{u$PHijYLroD3 zrWFZ%CpGqU$V-sWfPn!hfWb^446fNVO|2bVqCiMx7%15B)y>f`$R|6(;H@?t%E2<_ z*fpD5|M`NEZbDVsmrnMj8NITHq=>0R&z^OS+JuGv$0YP?i}_&rb@$(met%W7`;hAX zzUV{z3okcmlz=%X%{(@|V#3RP)N^Sg_|b*#E1?I1G+edIT@Jd=Xw7sE&=pAD>aZKs4?W*uc2E#4Z>pUWa2_TQPS1)@?K zkOvi=Z4{k-aGa5+$uJ;ec_(UD(8;zDfz@X_&=%q^~fy%Gt+M~9gH%R z?Mf|ZWyBf=HMGqlf(V6SL-EIqh0Y39KuEkDCf>YS9;PR=ZOnu5W9`kO!MdzuV}0+e z-352PCP&Iun@QWsbkN0NaE>r0-twk5L9jQv=SibZbrnamI-TTszDt~oXFcc`-}^Q_ z-a1t+`*6(>yY@*@x3#VQddPB1R^NhzS(`-yChcz8`2{7zFdQq5_j4G9dlEVtHCy+Q zSwBKXJ!1=USZP(0FXqsyktOXtbHDA3cviVk**0m!!L$(2L5(Jytmh$5NS;FjlRgtY zqv3wOom_Al`2!McLlB%O3^V%q@zqhvOi-YYc4HPUDNpzHO;vyNS=T1t1V^a-?0ppA z^(~a*D<{hwbFX#<{*|Sto`*_5chmj;VbdQw{50YucE^8G$)WD=6qtVN!?G4&Ky(Yq zU&>OU$9^$r_-XiPu4A|E{%~eysAhWo9uN0WQF)0qLr11Cz2roiJP zbXB)IL@fJU*3toL9sb@)VDF>9bjnW&VhB@A8;bM|;aNhyc0(EuB98?y!#?-h4$PbN zH!E zFGTj_YFnrAIJzzDpwDTmPG8lQIrDY|!$4eG2CPW0J?W7~b+Xl>TRfTg>JK~Xv? z3Ssckd{6u)U|&+?ch10y1$3>5WcDQblvsV zC@m5x*e_V=!GrpX7F!O4*r*__ZMNfoHW508NRgwB(i{v_BNk~~VUfKm`%u3Z2I|#m zFgVSlY${e&*eJT3-Zgl+sNmnTpC9HZunATZFt{+-&>?wJwF~~(Unw^mF5`INFc`xx z`pCl|-OCOJ&!Xr8s^{>Z4DEt?+HB=11;HeRn;D^ejXvip?6+Uk$S^3#sw(+A=U=PR zCxMAsS9(R^iI2lzv8WR)t?lFbC0}R)Nszyp|7Vz=qi;bww0<53f*v=LLJ87jGll0BY zNy|BJ;$W3_cK3})sYI$<>U||${rS=z6B%pmu`nQ2#;Ltnh&5AUXLGMZtnkuEn+&J8 z)fRp4qTwRLilL@t4?WG)?bc=W>ZJ_Hhv_|}l{A^KcpHvuvhNH|I;i?hUUsQh(a?kW z@&fySgf@I%lBjINaH^tP2LH-R0cE^b&|hiE&gN6cu$%EL7_7MrS1BeHMH^5Uf%P&o zbuu?6(NOG_1t;caKyz~OXlGByh2Y}!;-nAq`%>GV;=YrnS>o;Hy6o13wv0lOzSrof zQ)2{Na7>>=$ocml?D4V4TQ5&<=u2Ot=2wt%=*d@dr({WEnXQ7NQg4UQ@X(9%^LfPW zFFU@3A8^0zL^&?>#-Dmc!z$mZJzs6^7H{+UHAvp0x1^%JR*Fo%6r#y)vzU|nff_RY z+flcEgM^qBAHSmLeu7vPJw<4N2!mc_vq`i5eg}*J<;!?cps)R~v}hq{(KvSDs@jI%f2cr5qN6n&%R0g{3$x?qKz3!37>-Lh=A!vP(K5o=;W1&i z`N@^#!zW(AKwe+^8=oEN0pVw{aZ|E}v_!hB!Q+8%4d`ixS(J;-^6j>%_MK06c)iwW zB(11H`;xvmh479;Tr8C!B*GveoatEg>+Pq??sUr?!Aai>tg4ER$-JYrgz%`;l6=L} z+HIiKv{7gyarqOGX9lo-6?Wc`)zhE|Ut&aNLr;U=J^j{8oA(mkbQi5e-2(4%_`4Tk zNSuE1Sj}uo-;_5dRgXDh=%g~xJR;abwRLh`z*T2Hx~W_%9^UzJhk#dps7xNwyFz(u z4b{M4TN%4}cGkQsDr&~D&T+ib_-FsC&jU0|hRgJg-}lbl6@2fGL(Hl0#G43T_X}qa zu8c6K&(U+x*&!xkqzhZ!`vt?qjLnQRkKLZKdkE328{*JIw-3~hdD)xyiO9_Ox%8r= zSK>^hht`yv=}7`b$YZ)&gZVvn?fR>38LKKU$D@JmlJRASmV4R{ybt$3i`)0+glE|k zPvZBDD??djWb(1h7L3w+H%S#8b-z7BjOkJr3-J^MLXHno_>ThlKd`^E2%)nLc5MRH z1_=N7?zdEB>ui@e2hD~6lNWcD*B@Rhxrm!`O_jd5&bvB$9dY@`7=$2WU`Z)L?Z0-6 zvL_a2t`tvrEj*0ca%9k7Vi>qFa_dIujYt``TT`?w zWXPPb#|4ylE}_tcvkt8LF}^0Nd#IxiZbEcY8 zmA#$~ey%=O?dVuWWcf{zFUjk6?a(dqlH#AR*Vz7aN`Oui_Jc(uEL(*vP)~zA&BbBx z@S||hBhn!%mKg}C3F3W)6;Ldk47G*gDx9WlNTu<`a$#`2@c)W_5ko#=SYlWm}cxOb!Ch)ns<>tQ=}pdIKvrC@;1KQAT}^c9h>MQU-yzkTx$^H_O=)g zqhBP|Jj-F8`|9hht9iRE_Q6SZQF3wgh+4H;jG4@gs&dnYYjPQsvmxQ1x8|XHyt)8~ V=@R{d&@e+YFw)W;Ln_@ULrcgILwCc# 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/images/frame_silver.png b/src/EllieBot/data/images/frame_silver.png new file mode 100644 index 0000000000000000000000000000000000000000..4dcda7562f57785c3ded15e513ba66387a00d87a GIT binary patch literal 13319 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/data/magicitems.json b/src/EllieBot/data/magicitems.json new file mode 100644 index 0000000..34ffa45 --- /dev/null +++ b/src/EllieBot/data/magicitems.json @@ -0,0 +1,314 @@ +[ + { + "Name": "Ace of Spades", + "Description": "An ace of spades from a standard card deck. No matter where you store it on your body, you will always be able to find it in your right sleeve afterwards." + }, + { + "Name": "Arrow of Euarere", + "Description": "A silver arrow, suspended on a string. It always points to the person holding the string." + }, + { + "Name": "Amulet of Extra Amulet Slot", + "Description": "This amulet allows you to gain the benefit from two magical amulets rather than one. It cannot be further enchanted." + }, + { + "Name": "Amulet of Feather Fall", + "Description": "When worn, this amulet turns into a feather and falls to the ground." + }, + { + "Name": "Anti-Matches", + "Description": "A box of matches. Striking one will make it begin to drip water from the tip while the match shrivels away. The amount of water a match releases is about enough to fill a tablespoon." + }, + { + "Name": "The Artist's Bludgeon", + "Description": "Inanimate objects hit with this bludgeon will receive no damage; they will however change color." + }, + { + "Name": "Attentive Guardsman's Pike", + "Description": "These ornate and deadly-looking ceremonial pikes are reach weapons and appear to weigh at least 20 lbs, not counting the weight of the fluttering banners that can be unfurled for parade use. Constructed of shadowstuff, they weigh one pound, and inflict only a single point of damage on an attack, being almost entirely for show, although they also have the unique property of remaining in place when set (although unable to support more than 20 lbs), allowing a 'resting his eyes' guardsman to prop it up and leave it standing under its own power, while his hand sags off of it." + }, + { + "Name": "Attentive Guardsman's Tabard", + "Description": "A dozen of these tabards were fashioned for palace guardsmen in the Empire of Sard, 250 miles from the nearest enemy. The bearer is placed under a glamour that causes him to appear alert and awake, even if his eyes are closed and he is snoring lightly." + }, + { + "Name": "Axe of Big Numbers", + "Description": "This axe shouts \"Big numbers baby, come on!\" whenever it is swung, but always deals 1 damage or less." + }, + { + "Name": "Axe of Empathy", + "Description": "Every time you hit something with this +5 greataxe, you get dealt an equal amount of damage. Both you and the thing you hit are then healed the amount of damage dealt by the axe, even if either are dead. The Axe hopes you have learned your lesson." + }, + { + "Name": "Axe of Pain", + "Description": "The axe is always moaning and groaning with pain." + }, + { + "Name": "Baby Oil", + "Description": "An aphrodisiac made from the finest mashed babies. Strangely unpopular in the upper planes, the judgmental prudes." + }, + { + "Name": "Bag of Faerie Gold", + "Description": "This sack appears to be full of gold coins and jewels. When one attempts to spend them, however, the glamour on them soon vanishes, revealing them to be nothing but leaves and pebbles. Obviously, most shopkeepers will not be happy about this, and no amount of 'we didn't know, I swear!' will change their mind." + }, + { + "Name": "Bag of Holding", + "Description": "This item functions as a normal backpack, however when attempting to retrieve an item, a calm female voice tells them there is a wait time of 4d10 minutes before they can retrieve their item (actual time is stated time plus 6d6 additional minutes). During this wait, the bag plays either annoying muzak or advertisements for the bag's creator's other products/services. Upon attempting to retrieve an item, there is a chance that the wrong item is retrieved, or that the intended item is simply missing. Obtaining the original item requires an additional 4d10+6d6 minutes and has only a 5% chance of success." + }, + { + "Name": "Bag of Holding (Alternate)", + "Description": "This sack needs a hug!" + }, + { + "Name": "Bag of Trading", + "Description": "You can take one thing out of the bag for each object you put in the bag. However, you have no control over what you get, and there are no trade-backs. Past research seems to imply there's some sort of correlation to what gets you what, but it's extremely convoluted and far from understood." + }, + { + "Name": "Bag of Trick", + "Description": "This bag operates like a Bag of Tricks, except it only works once a week and produces a rat each time itis used." + }, + { + "Name": "Bag of Unholding", + "Description": "Quite a large backpack but even the smallest item doesn't fit." + }, + { + "Name": "Bagpipe of Stealth", + "Description": "Grants the user invisibility as long as it is being played." + }, + { + "Name": "Ball of Eyes", + "Description": "A snow-globe filled with miniature eyeballs. When shaken, it grants the user a blurry, jittery vision of some future event." + }, + { + "Name": "Banana Walkie-Talkies", + "Description": "There exist two, and only two, of these items in the world. One of which is possessed by a cranky and lonely half-orc. It appears to be an innocuous wooden banana with a coat of faded yellow paint. When an end (doesn't matter which one) is placed against your ear, you can hear a ringing followed by a *click* and a half-orc yelling at you for waking him up at this ungodly hour. If you drop the banana or \"hang up,\" the call ends. If you stay and listen, the half-orc will yell at you, call out obscenities, and start going on about his daily problems and mishaps in his love life. Every so often (2% chance/day), the banana will ring while you are sleeping and the half-orc will want to talk to you about his problems." + }, + { + "Name": "Barrel of Holding", + "Description": "This large wooden barrel measuring √(12/π) feet in diameter and 5 feet in height can hold up to 15 cubic feet of matter." + }, + { + "Name": "Beam Sword of Severed Nerves", + "Description": "A beam sword. It cannot cut anything but nerve strings. Will pass through any other material leaving no harm." + }, + { + "Name": "Belt of Pants", + "Description": "This belt creates illusory pants on the wearer. The wearer can suppress the illusion at will" + }, + { + "Name": "Belt of Tightening", + "Description": "Every time you put this belt on, all of your clothes permanently shrink a fraction of a millimeter. The effect is compound." + }, + { + "Name": "Belt of Unbathed Breath", + "Description": "When worn around the waist, allows the user to breathe underwater. Does not function when wet." + }, + { + "Name": "Boogie Skeleton", + "Description": "This pile of bones is small, such as one that might be obtained from a bird or a toad, though it can look as though it came from any creature. When a song is sung or played in the vicinity of the skeleton, it begins to dance appropriately. As soon as the music stops, it collapses into the pile of bones again. The skeleton, when dancing, can be no larger than Diminutive." + }, + { + "Name": "Book of Canon", + "Description": "A book that automatically transforms into a copy of the sacred text of any religion, translated into the language the user is most familiar with." + }, + { + "Name": "Book of Confusion", + "Description": "The letters in this book always appear to be upside down, even if viewed from different directions at the same time. The book is a bad novel about zombies." + }, + { + "Name": "Book of Curses", + "Description": "When opened, the book verbally berates anyone in the immediate vicinity, calling into question their combat ability, intellect, personal hygiene, lineage and profession of their mothers, and other delightful insults. Once closed the book continues shouting (although it is muffled) until placed inside a bag or some other similar container for 1d4+1 minutes and ignored. Replying to the book in any other way causes the insults to get louder and more childish the more time you spend replying to it." + }, + { + "Name": "Book of Exalted Deeds", + "Description": "Contains a listing of some of the finest houses ever sold and the specifics of the titles to the properties." + }, + { + "Name": "Boots of Levitation", + "Description": "These boots levitate a few inches off the ground when not worn." + }, + { + "Name": "Boots of Stylishness", + "Description": "Knee high black boots that are always clean and shiny. They never take in water, thus feet are always dry." + }, + { + "Name": "Boots of Walking", + "Description": "The wearer of the boots cannot run, nor can he take a double move action, and takes a -5 to Tumble checks. These boots are made for walkin', and that's just what they'll do." + }, + { + "Name": "Bottle of Air", + "Description": "It's a bottle. Full of air. Congratulations." + }, + { + "Name": "Bottomless Beer Mug", + "Description": "Any liquid poured into this mug treats the bottom as incorporeal, but solid objects don't" + }, + { + "Name": "Bowl of Comfortable Warmth", + "Description": "Any liquid in the bowl will feel comfortably warm, so icy cold water will feel like it's a bit over room temperature. Do note, however, that it's still icy cold water, it just feels warmer." + }, + { + "Name": "Breastplate of Secret Detection", + "Description": "If the wearer of this breastplate gains a piece of information that is somehow connected to the concealment of a hidden conspiracy or plot, a live and still wet red herring forms on the inside of the armor." + }, + { + "Name": "Bullying Gloves", + "Description": "At random intervals, these gloves instil the wearer with a near-irresistible urge to hit themselves." + }, + { + "Name": "Bunyan’s Belt", + "Description": "When worn, causes an enormous, bushy black beard to appear on the wearer’s face." + }, + { + "Name": "Cape of Resistance", + "Description": "When this item is placed on any living thing it somehow manages to fall off, untie itself, slip past the owner’s neck entirely, or otherwise avoid being worn." + }, + { + "Name": "Case of the Litigator", + "Description": "Translates any document placed in the case into legal jargon; non-reversible. Does not confer the ability to understand legal jargon." + }, + { + "Name": "Cat of Schrodinger", + "Description": "When this cat is not being observed in any way it is both dead and alive. When something observes it, it suddenly becomes either dead or alive with a 50% chance of either." + }, + { + "Name": "Chair of Steadiness", + "Description": "This chair can be moved but cannot be tipped over by anything less than a DC 35 Strength check." + }, + { + "Name": "Charles", + "Description": "This small, unremarkable figurine of a gnome refuses to be called anything but Charles. No other name will leave the lips of the speaker. It has no other powers." + }, + { + "Name": "Chime of Interruption", + "Description": "This instrument can be struck once every round, which takes a standard action. On any round the chime is activated the user may ready one action without spending an action to do so." + }, + { + "Name": "Chime of Opening", + "Description": "Commonly affixed to or near doors, when pressed it emits a sound on the interior of the owner’s home to let them know guests have arrived." + }, + { + "Name": "Chime of Opening (Alternate)", + "Description": "When struck against a solid surface, this chime emits a loud click, and opens along its length, to reveal a tiny compartment adequate to conceal a single 'smoke' worth of pipeweed or a blowgun needle. When the compartment is closed, it is seamless and can be detected only with a DC 20 Search check. If hit with an instrument such as a small mallet, it chimes." + }, + { + "Name": "Cloak of Billowing", + "Description": "This black and silver cloak will always billow dramatically behind the wearer, it has no other effects." + }, + { + "Name": "Cloak of Displacement, Minor", + "Description": "This item appears to be a normal cloak, but when worn by a character its magical properties distort and warp reality. When any attack is made against the wearer the cloak has a 20% chance of falling off, no matter how it is secured." + }, + { + "Name": "Compacting hammer", + "Description": "The force imparted by it is multiplied, but is spread around the surface of a struck object facing inward." + }, + { + "Name": "Cymbal of Symbols", + "Description": "This musical instrument enables the user to comprehend dead languages, but only while they are deafened by noise." + }, + { + "Name": "Dagger of Told Secrets", + "Description": "A simple-looking dagger. If used to backstab someone to death, it will whisper your most embarrassing secret to that person." + }, + { + "Name": "Dagger of Untold Secrets", + "Description": "A simple looking dagger. If used to backstab someone to death, it will whisper the most embarrassing secret of that person to you." + }, + { + "Name": "Decanter of Endless Sorrow", + "Description": "A pewter flask that produces limitless alcohol when held to their lips by someone who is troubled. It gets them drunk but they never feel any better." + }, + { + "Name": "Diadem of Brothaurity", + "Description": "When wearing this headpiece, you are as elegant and well-spoken as a famous diplomat or regent, but you can't stop calling everyone bro." + }, + { + "Name": "Enchanted Book of Collected Stories", + "Description": "Opening this will cause miniature creatures/people to pour out and preform a chapter from the book much like a theater." + }, + { + "Name": "Fade to Black Belt", + "Description": "The wearer of this belt will be unable to remember any sexual encounter begun while they were wearing the belt." + }, + { + "Name": "Focusing Ring", + "Description": "The digit on which this ring is worn can be viewed in extremely high definition from a great distance." + }, + { + "Name": "Gloves of Tinkering", + "Description": "Wearing the gloves will make you able to almost repair any broken item. However, you will always end up with pieces from the item that don't seem to fit anywhere." + }, + { + "Name": "Greater Staff of Random Summoning", + "Description": "Summons a random creature at a random place. You could be summoning a giant Ogre on the other side of the globe for all you know." + }, + { + "Name": "Hoarder's Wand", + "Description": "Does nothing but for some reason you think it might be important later in your quest." + }, + { + "Name": "Hood of Offensive Facades", + "Description": "This hood will change your identity in the eyes of others to the appearance of the person they most personally dislike." + }, + { + "Name": "Hood Of Worrisome Facades", + "Description": "This hood will change your identity in the eyes of others, however the identity used will be random." + }, + { + "Name": "Indestructible Notebook of Memories", + "Description": "This otherwise normal notepad of normal notepad size cannot be damaged or destroyed, and anything written in it cannot be obscured or defaced. It also has unlimited pages despite its finite size. However, the data it holds only lasts as long as the writer independently remembers it, and decays in exact proportion to the relevant memories. Remember who and when, but not where? Then the words describing the location in that particular entry are the only ones gone." + }, + { + "Name": "Intransigent Rod", + "Description": "When the button on this artifact is pressed in, the holder's opinions solidify and they become impossible to convince." + }, + { + "Name": "Lunchbox of Delicious Unfulfillment", + "Description": "This lunchbox will hold whatever food you desire. However you will never get full and the food will deliver no nourishment." + }, + { + "Name": "The Mattress of Poverty", + "Description": "No matter how you fluff this gorgeous, thick, mattress, you will always sleep on the thin part of it." + }, + { + "Name": "Mug O' Dissatisfaction", + "Description": "A mug that always produces a steaming hot cup of coffee or tea when tapped on the bottom. It conjures the opposite of what the tapper prefers, so if you like tea you get coffee and vice versa. Handing the full mug to another person will make the drink in it transform to the opposite of that persons preferences." + }, + { + "Name": "Murder Dagger", + "Description": "All damage it would deal is instead replaced by the target being harassed by crows for that many hours." + }, + { + "Name": "Needle Of Learned Compromise", + "Description": "This needle will create beautiful tattoos of any design, however they hurt a tiny bit more. When used to sew it is entirely normal." + }, + { + "Name": "Portable Dark Tavern Corner", + "Description": "Consisting of two wooden boards connected by a hinge, this artifact draws those nearby into assuming it is a perfect spot to conduct seedy business." + }, + { + "Name": "Ring of First Impression", + "Description": "Wearing the ring will make you able to perform a perfect handshake with the hand wearing it." + }, + { + "Name": "Sack of Hive Eggs", + "Description": "Crushing one of the numerous tiny eggs will cause the thoughts of everybody in the proximity to merge. Everybody can hear what you think and you can hear everybody." + }, + { + "Name": "Shoes of the Restless Traveler", + "Description": "These shoes allow their user to run for miles without feeling fatigue, but if they try to do anything else with it (walk, sit down, jump), they will instantly trip" + }, + { + "Name": "Sword of Parrying", + "Description": "Parries every attack, swinging it yourself will force it to \"parry\" your opponents weapon/attack even though he/she/it is defenseless." + }, + { + "Name": "Vorpal Grindstone", + "Description": "It can \"sharpen\" any object to become vorpal. Any object." + }, + { + "Name": "The Water Hat", + "Description": "A small red hat, when worn, causes water to pour from the wearer's fingers at the speed " + } +] \ No newline at end of file diff --git a/src/EllieBot/data/patron.yml b/src/EllieBot/data/patron.yml new file mode 100644 index 0000000..6485e1c --- /dev/null +++ b/src/EllieBot/data/patron.yml @@ -0,0 +1,69 @@ +# DO NOT CHANGE +version: 2 +# Whether the patronage feature is enabled +isEnabled: false +# List of patron only features and relevant quota data +quotas: +# Dictionary of feature names with their respective limits. Set to null for unlimited + features: + timely:extra_percent: + V: 10 + X: 22 + XX: 50 + L: 150 + C: 350 + rero:max_count: + V: 25 + X: 50 + cleverbot:response: + V: -20 + X: 5000 + XX: 12000 + L: 35000 + C: 100000 + # Dictionary of commands with their respective quota data + commands: + cleverbot: + V: + prune: + X: + PerHour: 1 + XX: + PerHour: 3 + google: + V: + PerDay: 15 + X: + PerDay: 30 + XX: + PerDay: 60 + L: + PerDay: 150 + C: + PerDay: 300 + image: + V: + PerDay: 15 + X: + PerDay: 30 + XX: + PerDay: 60 + L: + PerDay: 150 + C: + PerDay: 300 + youtube: + V: + PerDay: 25 + X: + PerDay: 50 + XX: + PerDay: 100 + L: + PerDay: 250 + C: + PerDay: 500 + # Dictionary of groups with their respective quota data + groups: {} + # Dictionary of modules with their respective quota data + modules: {} diff --git a/src/EllieBot/data/pokemon/LICENSE b/src/EllieBot/data/pokemon/LICENSE new file mode 100644 index 0000000..283bf7a --- /dev/null +++ b/src/EllieBot/data/pokemon/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2011-2016 Guangcong Luo and other contributors +http://pokemonshowdown.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/EllieBot/data/pokemon/name-id_map.json b/src/EllieBot/data/pokemon/name-id_map.json new file mode 100644 index 0000000..239e74a --- /dev/null +++ b/src/EllieBot/data/pokemon/name-id_map.json @@ -0,0 +1,3622 @@ +[ + { + "Id": 1, + "Name": "bulbasaur" + }, + { + "Id": 2, + "Name": "ivysaur" + }, + { + "Id": 3, + "Name": "venusaur" + }, + { + "Id": 4, + "Name": "charmander" + }, + { + "Id": 5, + "Name": "charmeleon" + }, + { + "Id": 6, + "Name": "charizard" + }, + { + "Id": 7, + "Name": "squirtle" + }, + { + "Id": 8, + "Name": "wartortle" + }, + { + "Id": 9, + "Name": "blastoise" + }, + { + "Id": 10, + "Name": "caterpie" + }, + { + "Id": 11, + "Name": "metapod" + }, + { + "Id": 12, + "Name": "butterfree" + }, + { + "Id": 13, + "Name": "weedle" + }, + { + "Id": 14, + "Name": "kakuna" + }, + { + "Id": 15, + "Name": "beedrill" + }, + { + "Id": 16, + "Name": "pidgey" + }, + { + "Id": 17, + "Name": "pidgeotto" + }, + { + "Id": 18, + "Name": "pidgeot" + }, + { + "Id": 19, + "Name": "rattata" + }, + { + "Id": 20, + "Name": "raticate" + }, + { + "Id": 21, + "Name": "spearow" + }, + { + "Id": 22, + "Name": "fearow" + }, + { + "Id": 23, + "Name": "ekans" + }, + { + "Id": 24, + "Name": "arbok" + }, + { + "Id": 25, + "Name": "pikachu" + }, + { + "Id": 26, + "Name": "raichu" + }, + { + "Id": 27, + "Name": "sandshrew" + }, + { + "Id": 28, + "Name": "sandslash" + }, + { + "Id": 29, + "Name": "nidoran" + }, + { + "Id": 30, + "Name": "nidorina" + }, + { + "Id": 31, + "Name": "nidoqueen" + }, + { + "Id": 32, + "Name": "nidoran" + }, + { + "Id": 33, + "Name": "nidorino" + }, + { + "Id": 34, + "Name": "nidoking" + }, + { + "Id": 35, + "Name": "clefairy" + }, + { + "Id": 36, + "Name": "clefable" + }, + { + "Id": 37, + "Name": "vulpix" + }, + { + "Id": 38, + "Name": "ninetales" + }, + { + "Id": 39, + "Name": "jigglypuff" + }, + { + "Id": 40, + "Name": "wigglytuff" + }, + { + "Id": 41, + "Name": "zubat" + }, + { + "Id": 42, + "Name": "golbat" + }, + { + "Id": 43, + "Name": "oddish" + }, + { + "Id": 44, + "Name": "gloom" + }, + { + "Id": 45, + "Name": "vileplume" + }, + { + "Id": 46, + "Name": "paras" + }, + { + "Id": 47, + "Name": "parasect" + }, + { + "Id": 48, + "Name": "venonat" + }, + { + "Id": 49, + "Name": "venomoth" + }, + { + "Id": 50, + "Name": "diglett" + }, + { + "Id": 51, + "Name": "dugtrio" + }, + { + "Id": 52, + "Name": "meowth" + }, + { + "Id": 53, + "Name": "persian" + }, + { + "Id": 54, + "Name": "psyduck" + }, + { + "Id": 55, + "Name": "golduck" + }, + { + "Id": 56, + "Name": "mankey" + }, + { + "Id": 57, + "Name": "primeape" + }, + { + "Id": 58, + "Name": "growlithe" + }, + { + "Id": 59, + "Name": "arcanine" + }, + { + "Id": 60, + "Name": "poliwag" + }, + { + "Id": 61, + "Name": "poliwhirl" + }, + { + "Id": 62, + "Name": "poliwrath" + }, + { + "Id": 63, + "Name": "abra" + }, + { + "Id": 64, + "Name": "kadabra" + }, + { + "Id": 65, + "Name": "alakazam" + }, + { + "Id": 66, + "Name": "machop" + }, + { + "Id": 67, + "Name": "machoke" + }, + { + "Id": 68, + "Name": "machamp" + }, + { + "Id": 69, + "Name": "bellsprout" + }, + { + "Id": 70, + "Name": "weepinbell" + }, + { + "Id": 71, + "Name": "victreebel" + }, + { + "Id": 72, + "Name": "tentacool" + }, + { + "Id": 73, + "Name": "tentacruel" + }, + { + "Id": 74, + "Name": "geodude" + }, + { + "Id": 75, + "Name": "graveler" + }, + { + "Id": 76, + "Name": "golem" + }, + { + "Id": 77, + "Name": "ponyta" + }, + { + "Id": 78, + "Name": "rapidash" + }, + { + "Id": 79, + "Name": "slowpoke" + }, + { + "Id": 80, + "Name": "slowbro" + }, + { + "Id": 81, + "Name": "magnemite" + }, + { + "Id": 82, + "Name": "magneton" + }, + { + "Id": 83, + "Name": "farfetchd" + }, + { + "Id": 84, + "Name": "doduo" + }, + { + "Id": 85, + "Name": "dodrio" + }, + { + "Id": 86, + "Name": "seel" + }, + { + "Id": 87, + "Name": "dewgong" + }, + { + "Id": 88, + "Name": "grimer" + }, + { + "Id": 89, + "Name": "muk" + }, + { + "Id": 90, + "Name": "shellder" + }, + { + "Id": 91, + "Name": "cloyster" + }, + { + "Id": 92, + "Name": "gastly" + }, + { + "Id": 93, + "Name": "haunter" + }, + { + "Id": 94, + "Name": "gengar" + }, + { + "Id": 95, + "Name": "onix" + }, + { + "Id": 96, + "Name": "drowzee" + }, + { + "Id": 97, + "Name": "hypno" + }, + { + "Id": 98, + "Name": "krabby" + }, + { + "Id": 99, + "Name": "kingler" + }, + { + "Id": 100, + "Name": "voltorb" + }, + { + "Id": 101, + "Name": "electrode" + }, + { + "Id": 102, + "Name": "exeggcute" + }, + { + "Id": 103, + "Name": "exeggutor" + }, + { + "Id": 104, + "Name": "cubone" + }, + { + "Id": 105, + "Name": "marowak" + }, + { + "Id": 106, + "Name": "hitmonlee" + }, + { + "Id": 107, + "Name": "hitmonchan" + }, + { + "Id": 108, + "Name": "lickitung" + }, + { + "Id": 109, + "Name": "koffing" + }, + { + "Id": 110, + "Name": "weezing" + }, + { + "Id": 111, + "Name": "rhyhorn" + }, + { + "Id": 112, + "Name": "rhydon" + }, + { + "Id": 113, + "Name": "chansey" + }, + { + "Id": 114, + "Name": "tangela" + }, + { + "Id": 115, + "Name": "kangaskhan" + }, + { + "Id": 116, + "Name": "horsea" + }, + { + "Id": 117, + "Name": "seadra" + }, + { + "Id": 118, + "Name": "goldeen" + }, + { + "Id": 119, + "Name": "seaking" + }, + { + "Id": 120, + "Name": "staryu" + }, + { + "Id": 121, + "Name": "starmie" + }, + { + "Id": 122, + "Name": "mr mime" + }, + { + "Id": 123, + "Name": "scyther" + }, + { + "Id": 124, + "Name": "jynx" + }, + { + "Id": 125, + "Name": "electabuzz" + }, + { + "Id": 126, + "Name": "magmar" + }, + { + "Id": 127, + "Name": "pinsir" + }, + { + "Id": 128, + "Name": "tauros" + }, + { + "Id": 129, + "Name": "magikarp" + }, + { + "Id": 130, + "Name": "gyarados" + }, + { + "Id": 131, + "Name": "lapras" + }, + { + "Id": 132, + "Name": "ditto" + }, + { + "Id": 133, + "Name": "eevee" + }, + { + "Id": 134, + "Name": "vaporeon" + }, + { + "Id": 135, + "Name": "jolteon" + }, + { + "Id": 136, + "Name": "flareon" + }, + { + "Id": 137, + "Name": "porygon" + }, + { + "Id": 138, + "Name": "omanyte" + }, + { + "Id": 139, + "Name": "omastar" + }, + { + "Id": 140, + "Name": "kabuto" + }, + { + "Id": 141, + "Name": "kabutops" + }, + { + "Id": 142, + "Name": "aerodactyl" + }, + { + "Id": 143, + "Name": "snorlax" + }, + { + "Id": 144, + "Name": "articuno" + }, + { + "Id": 145, + "Name": "zapdos" + }, + { + "Id": 146, + "Name": "moltres" + }, + { + "Id": 147, + "Name": "dratini" + }, + { + "Id": 148, + "Name": "dragonair" + }, + { + "Id": 149, + "Name": "dragonite" + }, + { + "Id": 150, + "Name": "mewtwo" + }, + { + "Id": 151, + "Name": "mew" + }, + { + "Id": 152, + "Name": "chikorita" + }, + { + "Id": 153, + "Name": "bayleef" + }, + { + "Id": 154, + "Name": "meganium" + }, + { + "Id": 155, + "Name": "cyndaquil" + }, + { + "Id": 156, + "Name": "quilava" + }, + { + "Id": 157, + "Name": "typhlosion" + }, + { + "Id": 158, + "Name": "totodile" + }, + { + "Id": 159, + "Name": "croconaw" + }, + { + "Id": 160, + "Name": "feraligatr" + }, + { + "Id": 161, + "Name": "sentret" + }, + { + "Id": 162, + "Name": "furret" + }, + { + "Id": 163, + "Name": "hoothoot" + }, + { + "Id": 164, + "Name": "noctowl" + }, + { + "Id": 165, + "Name": "ledyba" + }, + { + "Id": 166, + "Name": "ledian" + }, + { + "Id": 167, + "Name": "spinarak" + }, + { + "Id": 168, + "Name": "ariados" + }, + { + "Id": 169, + "Name": "crobat" + }, + { + "Id": 170, + "Name": "chinchou" + }, + { + "Id": 171, + "Name": "lanturn" + }, + { + "Id": 172, + "Name": "pichu" + }, + { + "Id": 173, + "Name": "cleffa" + }, + { + "Id": 174, + "Name": "igglybuff" + }, + { + "Id": 175, + "Name": "togepi" + }, + { + "Id": 176, + "Name": "togetic" + }, + { + "Id": 177, + "Name": "natu" + }, + { + "Id": 178, + "Name": "xatu" + }, + { + "Id": 179, + "Name": "mareep" + }, + { + "Id": 180, + "Name": "flaaffy" + }, + { + "Id": 181, + "Name": "ampharos" + }, + { + "Id": 182, + "Name": "bellossom" + }, + { + "Id": 183, + "Name": "marill" + }, + { + "Id": 184, + "Name": "azumarill" + }, + { + "Id": 185, + "Name": "sudowoodo" + }, + { + "Id": 186, + "Name": "politoed" + }, + { + "Id": 187, + "Name": "hoppip" + }, + { + "Id": 188, + "Name": "skiploom" + }, + { + "Id": 189, + "Name": "jumpluff" + }, + { + "Id": 190, + "Name": "aipom" + }, + { + "Id": 191, + "Name": "sunkern" + }, + { + "Id": 192, + "Name": "sunflora" + }, + { + "Id": 193, + "Name": "yanma" + }, + { + "Id": 194, + "Name": "wooper" + }, + { + "Id": 195, + "Name": "quagsire" + }, + { + "Id": 196, + "Name": "espeon" + }, + { + "Id": 197, + "Name": "umbreon" + }, + { + "Id": 198, + "Name": "murkrow" + }, + { + "Id": 199, + "Name": "slowking" + }, + { + "Id": 200, + "Name": "misdreavus" + }, + { + "Id": 201, + "Name": "unown" + }, + { + "Id": 202, + "Name": "wobbuffet" + }, + { + "Id": 203, + "Name": "girafarig" + }, + { + "Id": 204, + "Name": "pineco" + }, + { + "Id": 205, + "Name": "forretress" + }, + { + "Id": 206, + "Name": "dunsparce" + }, + { + "Id": 207, + "Name": "gligar" + }, + { + "Id": 208, + "Name": "steelix" + }, + { + "Id": 209, + "Name": "snubbull" + }, + { + "Id": 210, + "Name": "granbull" + }, + { + "Id": 211, + "Name": "qwilfish" + }, + { + "Id": 212, + "Name": "scizor" + }, + { + "Id": 213, + "Name": "shuckle" + }, + { + "Id": 214, + "Name": "heracross" + }, + { + "Id": 215, + "Name": "sneasel" + }, + { + "Id": 216, + "Name": "teddiursa" + }, + { + "Id": 217, + "Name": "ursaring" + }, + { + "Id": 218, + "Name": "slugma" + }, + { + "Id": 219, + "Name": "magcargo" + }, + { + "Id": 220, + "Name": "swinub" + }, + { + "Id": 221, + "Name": "piloswine" + }, + { + "Id": 222, + "Name": "corsola" + }, + { + "Id": 223, + "Name": "remoraid" + }, + { + "Id": 224, + "Name": "octillery" + }, + { + "Id": 225, + "Name": "delibird" + }, + { + "Id": 226, + "Name": "mantine" + }, + { + "Id": 227, + "Name": "skarmory" + }, + { + "Id": 228, + "Name": "houndour" + }, + { + "Id": 229, + "Name": "houndoom" + }, + { + "Id": 230, + "Name": "kingdra" + }, + { + "Id": 231, + "Name": "phanpy" + }, + { + "Id": 232, + "Name": "donphan" + }, + { + "Id": 233, + "Name": "porygon2" + }, + { + "Id": 234, + "Name": "stantler" + }, + { + "Id": 235, + "Name": "smeargle" + }, + { + "Id": 236, + "Name": "tyrogue" + }, + { + "Id": 237, + "Name": "hitmontop" + }, + { + "Id": 238, + "Name": "smoochum" + }, + { + "Id": 239, + "Name": "elekid" + }, + { + "Id": 240, + "Name": "magby" + }, + { + "Id": 241, + "Name": "miltank" + }, + { + "Id": 242, + "Name": "blissey" + }, + { + "Id": 243, + "Name": "raikou" + }, + { + "Id": 244, + "Name": "entei" + }, + { + "Id": 245, + "Name": "suicune" + }, + { + "Id": 246, + "Name": "larvitar" + }, + { + "Id": 247, + "Name": "pupitar" + }, + { + "Id": 248, + "Name": "tyranitar" + }, + { + "Id": 249, + "Name": "lugia" + }, + { + "Id": 250, + "Name": "ho-oh" + }, + { + "Id": 251, + "Name": "celebi" + }, + { + "Id": 252, + "Name": "treecko" + }, + { + "Id": 253, + "Name": "grovyle" + }, + { + "Id": 254, + "Name": "sceptile" + }, + { + "Id": 255, + "Name": "torchic" + }, + { + "Id": 256, + "Name": "combusken" + }, + { + "Id": 257, + "Name": "blaziken" + }, + { + "Id": 258, + "Name": "mudkip" + }, + { + "Id": 259, + "Name": "marshtomp" + }, + { + "Id": 260, + "Name": "swampert" + }, + { + "Id": 261, + "Name": "poochyena" + }, + { + "Id": 262, + "Name": "mightyena" + }, + { + "Id": 263, + "Name": "zigzagoon" + }, + { + "Id": 264, + "Name": "linoone" + }, + { + "Id": 265, + "Name": "wurmple" + }, + { + "Id": 266, + "Name": "silcoon" + }, + { + "Id": 267, + "Name": "beautifly" + }, + { + "Id": 268, + "Name": "cascoon" + }, + { + "Id": 269, + "Name": "dustox" + }, + { + "Id": 270, + "Name": "lotad" + }, + { + "Id": 271, + "Name": "lombre" + }, + { + "Id": 272, + "Name": "ludicolo" + }, + { + "Id": 273, + "Name": "seedot" + }, + { + "Id": 274, + "Name": "nuzleaf" + }, + { + "Id": 275, + "Name": "shiftry" + }, + { + "Id": 276, + "Name": "taillow" + }, + { + "Id": 277, + "Name": "swellow" + }, + { + "Id": 278, + "Name": "wingull" + }, + { + "Id": 279, + "Name": "pelipper" + }, + { + "Id": 280, + "Name": "ralts" + }, + { + "Id": 281, + "Name": "kirlia" + }, + { + "Id": 282, + "Name": "gardevoir" + }, + { + "Id": 283, + "Name": "surskit" + }, + { + "Id": 284, + "Name": "masquerain" + }, + { + "Id": 285, + "Name": "shroomish" + }, + { + "Id": 286, + "Name": "breloom" + }, + { + "Id": 287, + "Name": "slakoth" + }, + { + "Id": 288, + "Name": "vigoroth" + }, + { + "Id": 289, + "Name": "slaking" + }, + { + "Id": 290, + "Name": "nincada" + }, + { + "Id": 291, + "Name": "ninjask" + }, + { + "Id": 292, + "Name": "shedinja" + }, + { + "Id": 293, + "Name": "whismur" + }, + { + "Id": 294, + "Name": "loudred" + }, + { + "Id": 295, + "Name": "exploud" + }, + { + "Id": 296, + "Name": "makuhita" + }, + { + "Id": 297, + "Name": "hariyama" + }, + { + "Id": 298, + "Name": "azurill" + }, + { + "Id": 299, + "Name": "nosepass" + }, + { + "Id": 300, + "Name": "skitty" + }, + { + "Id": 301, + "Name": "delcatty" + }, + { + "Id": 302, + "Name": "sableye" + }, + { + "Id": 303, + "Name": "mawile" + }, + { + "Id": 304, + "Name": "aron" + }, + { + "Id": 305, + "Name": "lairon" + }, + { + "Id": 306, + "Name": "aggron" + }, + { + "Id": 307, + "Name": "meditite" + }, + { + "Id": 308, + "Name": "medicham" + }, + { + "Id": 309, + "Name": "electrike" + }, + { + "Id": 310, + "Name": "manectric" + }, + { + "Id": 311, + "Name": "plusle" + }, + { + "Id": 312, + "Name": "minun" + }, + { + "Id": 313, + "Name": "volbeat" + }, + { + "Id": 314, + "Name": "illumise" + }, + { + "Id": 315, + "Name": "roselia" + }, + { + "Id": 316, + "Name": "gulpin" + }, + { + "Id": 317, + "Name": "swalot" + }, + { + "Id": 318, + "Name": "carvanha" + }, + { + "Id": 319, + "Name": "sharpedo" + }, + { + "Id": 320, + "Name": "wailmer" + }, + { + "Id": 321, + "Name": "wailord" + }, + { + "Id": 322, + "Name": "numel" + }, + { + "Id": 323, + "Name": "camerupt" + }, + { + "Id": 324, + "Name": "torkoal" + }, + { + "Id": 325, + "Name": "spoink" + }, + { + "Id": 326, + "Name": "grumpig" + }, + { + "Id": 327, + "Name": "spinda" + }, + { + "Id": 328, + "Name": "trapinch" + }, + { + "Id": 329, + "Name": "vibrava" + }, + { + "Id": 330, + "Name": "flygon" + }, + { + "Id": 331, + "Name": "cacnea" + }, + { + "Id": 332, + "Name": "cacturne" + }, + { + "Id": 333, + "Name": "swablu" + }, + { + "Id": 334, + "Name": "altaria" + }, + { + "Id": 335, + "Name": "zangoose" + }, + { + "Id": 336, + "Name": "seviper" + }, + { + "Id": 337, + "Name": "lunatone" + }, + { + "Id": 338, + "Name": "solrock" + }, + { + "Id": 339, + "Name": "barboach" + }, + { + "Id": 340, + "Name": "whiscash" + }, + { + "Id": 341, + "Name": "corphish" + }, + { + "Id": 342, + "Name": "crawdaunt" + }, + { + "Id": 343, + "Name": "baltoy" + }, + { + "Id": 344, + "Name": "claydol" + }, + { + "Id": 345, + "Name": "lileep" + }, + { + "Id": 346, + "Name": "cradily" + }, + { + "Id": 347, + "Name": "anorith" + }, + { + "Id": 348, + "Name": "armaldo" + }, + { + "Id": 349, + "Name": "feebas" + }, + { + "Id": 350, + "Name": "milotic" + }, + { + "Id": 351, + "Name": "castform" + }, + { + "Id": 352, + "Name": "kecleon" + }, + { + "Id": 353, + "Name": "shuppet" + }, + { + "Id": 354, + "Name": "banette" + }, + { + "Id": 355, + "Name": "duskull" + }, + { + "Id": 356, + "Name": "dusclops" + }, + { + "Id": 357, + "Name": "tropius" + }, + { + "Id": 358, + "Name": "chimecho" + }, + { + "Id": 359, + "Name": "absol" + }, + { + "Id": 360, + "Name": "wynaut" + }, + { + "Id": 361, + "Name": "snorunt" + }, + { + "Id": 362, + "Name": "glalie" + }, + { + "Id": 363, + "Name": "spheal" + }, + { + "Id": 364, + "Name": "sealeo" + }, + { + "Id": 365, + "Name": "walrein" + }, + { + "Id": 366, + "Name": "clamperl" + }, + { + "Id": 367, + "Name": "huntail" + }, + { + "Id": 368, + "Name": "gorebyss" + }, + { + "Id": 369, + "Name": "relicanth" + }, + { + "Id": 370, + "Name": "luvdisc" + }, + { + "Id": 371, + "Name": "bagon" + }, + { + "Id": 372, + "Name": "shelgon" + }, + { + "Id": 373, + "Name": "salamence" + }, + { + "Id": 374, + "Name": "beldum" + }, + { + "Id": 375, + "Name": "metang" + }, + { + "Id": 376, + "Name": "metagross" + }, + { + "Id": 377, + "Name": "regirock" + }, + { + "Id": 378, + "Name": "regice" + }, + { + "Id": 379, + "Name": "registeel" + }, + { + "Id": 380, + "Name": "latias" + }, + { + "Id": 381, + "Name": "latios" + }, + { + "Id": 382, + "Name": "kyogre" + }, + { + "Id": 383, + "Name": "groudon" + }, + { + "Id": 384, + "Name": "rayquaza" + }, + { + "Id": 385, + "Name": "jirachi" + }, + { + "Id": 386, + "Name": "deoxys" + }, + { + "Id": 387, + "Name": "turtwig" + }, + { + "Id": 388, + "Name": "grotle" + }, + { + "Id": 389, + "Name": "torterra" + }, + { + "Id": 390, + "Name": "chimchar" + }, + { + "Id": 391, + "Name": "monferno" + }, + { + "Id": 392, + "Name": "infernape" + }, + { + "Id": 393, + "Name": "piplup" + }, + { + "Id": 394, + "Name": "prinplup" + }, + { + "Id": 395, + "Name": "empoleon" + }, + { + "Id": 396, + "Name": "starly" + }, + { + "Id": 397, + "Name": "staravia" + }, + { + "Id": 398, + "Name": "staraptor" + }, + { + "Id": 399, + "Name": "bidoof" + }, + { + "Id": 400, + "Name": "bibarel" + }, + { + "Id": 401, + "Name": "kricketot" + }, + { + "Id": 402, + "Name": "kricketune" + }, + { + "Id": 403, + "Name": "shinx" + }, + { + "Id": 404, + "Name": "luxio" + }, + { + "Id": 405, + "Name": "luxray" + }, + { + "Id": 406, + "Name": "budew" + }, + { + "Id": 407, + "Name": "roserade" + }, + { + "Id": 408, + "Name": "cranidos" + }, + { + "Id": 409, + "Name": "rampardos" + }, + { + "Id": 410, + "Name": "shieldon" + }, + { + "Id": 411, + "Name": "bastiodon" + }, + { + "Id": 412, + "Name": "burmy" + }, + { + "Id": 413, + "Name": "wormadam" + }, + { + "Id": 414, + "Name": "mothim" + }, + { + "Id": 415, + "Name": "combee" + }, + { + "Id": 416, + "Name": "vespiquen" + }, + { + "Id": 417, + "Name": "pachirisu" + }, + { + "Id": 418, + "Name": "buizel" + }, + { + "Id": 419, + "Name": "floatzel" + }, + { + "Id": 420, + "Name": "cherubi" + }, + { + "Id": 421, + "Name": "cherrim" + }, + { + "Id": 422, + "Name": "shellos" + }, + { + "Id": 423, + "Name": "gastrodon" + }, + { + "Id": 424, + "Name": "ambipom" + }, + { + "Id": 425, + "Name": "drifloon" + }, + { + "Id": 426, + "Name": "drifblim" + }, + { + "Id": 427, + "Name": "buneary" + }, + { + "Id": 428, + "Name": "lopunny" + }, + { + "Id": 429, + "Name": "mismagius" + }, + { + "Id": 430, + "Name": "honchkrow" + }, + { + "Id": 431, + "Name": "glameow" + }, + { + "Id": 432, + "Name": "purugly" + }, + { + "Id": 433, + "Name": "chingling" + }, + { + "Id": 434, + "Name": "stunky" + }, + { + "Id": 435, + "Name": "skuntank" + }, + { + "Id": 436, + "Name": "bronzor" + }, + { + "Id": 437, + "Name": "bronzong" + }, + { + "Id": 438, + "Name": "bonsly" + }, + { + "Id": 439, + "Name": "mime jr" + }, + { + "Id": 440, + "Name": "happiny" + }, + { + "Id": 441, + "Name": "chatot" + }, + { + "Id": 442, + "Name": "spiritomb" + }, + { + "Id": 443, + "Name": "gible" + }, + { + "Id": 444, + "Name": "gabite" + }, + { + "Id": 445, + "Name": "garchomp" + }, + { + "Id": 446, + "Name": "munchlax" + }, + { + "Id": 447, + "Name": "riolu" + }, + { + "Id": 448, + "Name": "lucario" + }, + { + "Id": 449, + "Name": "hippopotas" + }, + { + "Id": 450, + "Name": "hippowdon" + }, + { + "Id": 451, + "Name": "skorupi" + }, + { + "Id": 452, + "Name": "drapion" + }, + { + "Id": 453, + "Name": "croagunk" + }, + { + "Id": 454, + "Name": "toxicroak" + }, + { + "Id": 455, + "Name": "carnivine" + }, + { + "Id": 456, + "Name": "finneon" + }, + { + "Id": 457, + "Name": "lumineon" + }, + { + "Id": 458, + "Name": "mantyke" + }, + { + "Id": 459, + "Name": "snover" + }, + { + "Id": 460, + "Name": "abomasnow" + }, + { + "Id": 461, + "Name": "weavile" + }, + { + "Id": 462, + "Name": "magnezone" + }, + { + "Id": 463, + "Name": "lickilicky" + }, + { + "Id": 464, + "Name": "rhyperior" + }, + { + "Id": 465, + "Name": "tangrowth" + }, + { + "Id": 466, + "Name": "electivire" + }, + { + "Id": 467, + "Name": "magmortar" + }, + { + "Id": 468, + "Name": "togekiss" + }, + { + "Id": 469, + "Name": "yanmega" + }, + { + "Id": 470, + "Name": "leafeon" + }, + { + "Id": 471, + "Name": "glaceon" + }, + { + "Id": 472, + "Name": "gliscor" + }, + { + "Id": 473, + "Name": "mamoswine" + }, + { + "Id": 474, + "Name": "porygon z" + }, + { + "Id": 475, + "Name": "gallade" + }, + { + "Id": 476, + "Name": "probopass" + }, + { + "Id": 477, + "Name": "dusknoir" + }, + { + "Id": 478, + "Name": "froslass" + }, + { + "Id": 479, + "Name": "rotom" + }, + { + "Id": 480, + "Name": "uxie" + }, + { + "Id": 481, + "Name": "mesprit" + }, + { + "Id": 482, + "Name": "azelf" + }, + { + "Id": 483, + "Name": "dialga" + }, + { + "Id": 484, + "Name": "palkia" + }, + { + "Id": 485, + "Name": "heatran" + }, + { + "Id": 486, + "Name": "regigigas" + }, + { + "Id": 487, + "Name": "giratina" + }, + { + "Id": 488, + "Name": "cresselia" + }, + { + "Id": 489, + "Name": "phione" + }, + { + "Id": 490, + "Name": "manaphy" + }, + { + "Id": 491, + "Name": "darkrai" + }, + { + "Id": 492, + "Name": "shaymin" + }, + { + "Id": 493, + "Name": "arceus" + }, + { + "Id": 494, + "Name": "victini" + }, + { + "Id": 495, + "Name": "snivy" + }, + { + "Id": 496, + "Name": "servine" + }, + { + "Id": 497, + "Name": "serperior" + }, + { + "Id": 498, + "Name": "tepig" + }, + { + "Id": 499, + "Name": "pignite" + }, + { + "Id": 500, + "Name": "emboar" + }, + { + "Id": 501, + "Name": "oshawott" + }, + { + "Id": 502, + "Name": "dewott" + }, + { + "Id": 503, + "Name": "samurott" + }, + { + "Id": 504, + "Name": "patrat" + }, + { + "Id": 505, + "Name": "watchog" + }, + { + "Id": 506, + "Name": "lillipup" + }, + { + "Id": 507, + "Name": "herdier" + }, + { + "Id": 508, + "Name": "stoutland" + }, + { + "Id": 509, + "Name": "purrloin" + }, + { + "Id": 510, + "Name": "liepard" + }, + { + "Id": 511, + "Name": "pansage" + }, + { + "Id": 512, + "Name": "simisage" + }, + { + "Id": 513, + "Name": "pansear" + }, + { + "Id": 514, + "Name": "simisear" + }, + { + "Id": 515, + "Name": "panpour" + }, + { + "Id": 516, + "Name": "simipour" + }, + { + "Id": 517, + "Name": "munna" + }, + { + "Id": 518, + "Name": "musharna" + }, + { + "Id": 519, + "Name": "pidove" + }, + { + "Id": 520, + "Name": "tranquill" + }, + { + "Id": 521, + "Name": "unfezant" + }, + { + "Id": 522, + "Name": "blitzle" + }, + { + "Id": 523, + "Name": "zebstrika" + }, + { + "Id": 524, + "Name": "roggenrola" + }, + { + "Id": 525, + "Name": "boldore" + }, + { + "Id": 526, + "Name": "gigalith" + }, + { + "Id": 527, + "Name": "woobat" + }, + { + "Id": 528, + "Name": "swoobat" + }, + { + "Id": 529, + "Name": "drilbur" + }, + { + "Id": 530, + "Name": "excadrill" + }, + { + "Id": 531, + "Name": "audino" + }, + { + "Id": 532, + "Name": "timburr" + }, + { + "Id": 533, + "Name": "gurdurr" + }, + { + "Id": 534, + "Name": "conkeldurr" + }, + { + "Id": 535, + "Name": "tympole" + }, + { + "Id": 536, + "Name": "palpitoad" + }, + { + "Id": 537, + "Name": "seismitoad" + }, + { + "Id": 538, + "Name": "throh" + }, + { + "Id": 539, + "Name": "sawk" + }, + { + "Id": 540, + "Name": "sewaddle" + }, + { + "Id": 541, + "Name": "swadloon" + }, + { + "Id": 542, + "Name": "leavanny" + }, + { + "Id": 543, + "Name": "venipede" + }, + { + "Id": 544, + "Name": "whirlipede" + }, + { + "Id": 545, + "Name": "scolipede" + }, + { + "Id": 546, + "Name": "cottonee" + }, + { + "Id": 547, + "Name": "whimsicott" + }, + { + "Id": 548, + "Name": "petilil" + }, + { + "Id": 549, + "Name": "lilligant" + }, + { + "Id": 550, + "Name": "basculin" + }, + { + "Id": 551, + "Name": "sandile" + }, + { + "Id": 552, + "Name": "krokorok" + }, + { + "Id": 553, + "Name": "krookodile" + }, + { + "Id": 554, + "Name": "darumaka" + }, + { + "Id": 555, + "Name": "darmanitan" + }, + { + "Id": 556, + "Name": "maractus" + }, + { + "Id": 557, + "Name": "dwebble" + }, + { + "Id": 558, + "Name": "crustle" + }, + { + "Id": 559, + "Name": "scraggy" + }, + { + "Id": 560, + "Name": "scrafty" + }, + { + "Id": 561, + "Name": "sigilyph" + }, + { + "Id": 562, + "Name": "yamask" + }, + { + "Id": 563, + "Name": "cofagrigus" + }, + { + "Id": 564, + "Name": "tirtouga" + }, + { + "Id": 565, + "Name": "carracosta" + }, + { + "Id": 566, + "Name": "archen" + }, + { + "Id": 567, + "Name": "archeops" + }, + { + "Id": 568, + "Name": "trubbish" + }, + { + "Id": 569, + "Name": "garbodor" + }, + { + "Id": 570, + "Name": "zorua" + }, + { + "Id": 571, + "Name": "zoroark" + }, + { + "Id": 572, + "Name": "minccino" + }, + { + "Id": 573, + "Name": "cinccino" + }, + { + "Id": 574, + "Name": "gothita" + }, + { + "Id": 575, + "Name": "gothorita" + }, + { + "Id": 576, + "Name": "gothitelle" + }, + { + "Id": 577, + "Name": "solosis" + }, + { + "Id": 578, + "Name": "duosion" + }, + { + "Id": 579, + "Name": "reuniclus" + }, + { + "Id": 580, + "Name": "ducklett" + }, + { + "Id": 581, + "Name": "swanna" + }, + { + "Id": 582, + "Name": "vanillite" + }, + { + "Id": 583, + "Name": "vanillish" + }, + { + "Id": 584, + "Name": "vanilluxe" + }, + { + "Id": 585, + "Name": "deerling" + }, + { + "Id": 586, + "Name": "sawsbuck" + }, + { + "Id": 587, + "Name": "emolga" + }, + { + "Id": 588, + "Name": "karrablast" + }, + { + "Id": 589, + "Name": "escavalier" + }, + { + "Id": 590, + "Name": "foongus" + }, + { + "Id": 591, + "Name": "amoonguss" + }, + { + "Id": 592, + "Name": "frillish" + }, + { + "Id": 593, + "Name": "jellicent" + }, + { + "Id": 594, + "Name": "alomomola" + }, + { + "Id": 595, + "Name": "joltik" + }, + { + "Id": 596, + "Name": "galvantula" + }, + { + "Id": 597, + "Name": "ferroseed" + }, + { + "Id": 598, + "Name": "ferrothorn" + }, + { + "Id": 599, + "Name": "klink" + }, + { + "Id": 600, + "Name": "klang" + }, + { + "Id": 601, + "Name": "klinklang" + }, + { + "Id": 602, + "Name": "tynamo" + }, + { + "Id": 603, + "Name": "eelektrik" + }, + { + "Id": 604, + "Name": "eelektross" + }, + { + "Id": 605, + "Name": "elgyem" + }, + { + "Id": 606, + "Name": "beheeyem" + }, + { + "Id": 607, + "Name": "litwick" + }, + { + "Id": 608, + "Name": "lampent" + }, + { + "Id": 609, + "Name": "chandelure" + }, + { + "Id": 610, + "Name": "axew" + }, + { + "Id": 611, + "Name": "fraxure" + }, + { + "Id": 612, + "Name": "haxorus" + }, + { + "Id": 613, + "Name": "cubchoo" + }, + { + "Id": 614, + "Name": "beartic" + }, + { + "Id": 615, + "Name": "cryogonal" + }, + { + "Id": 616, + "Name": "shelmet" + }, + { + "Id": 617, + "Name": "accelgor" + }, + { + "Id": 618, + "Name": "stunfisk" + }, + { + "Id": 619, + "Name": "mienfoo" + }, + { + "Id": 620, + "Name": "mienshao" + }, + { + "Id": 621, + "Name": "druddigon" + }, + { + "Id": 622, + "Name": "golett" + }, + { + "Id": 623, + "Name": "golurk" + }, + { + "Id": 624, + "Name": "pawniard" + }, + { + "Id": 625, + "Name": "bisharp" + }, + { + "Id": 626, + "Name": "bouffalant" + }, + { + "Id": 627, + "Name": "rufflet" + }, + { + "Id": 628, + "Name": "braviary" + }, + { + "Id": 629, + "Name": "vullaby" + }, + { + "Id": 630, + "Name": "mandibuzz" + }, + { + "Id": 631, + "Name": "heatmor" + }, + { + "Id": 632, + "Name": "durant" + }, + { + "Id": 633, + "Name": "deino" + }, + { + "Id": 634, + "Name": "zweilous" + }, + { + "Id": 635, + "Name": "hydreigon" + }, + { + "Id": 636, + "Name": "larvesta" + }, + { + "Id": 637, + "Name": "volcarona" + }, + { + "Id": 638, + "Name": "cobalion" + }, + { + "Id": 639, + "Name": "terrakion" + }, + { + "Id": 640, + "Name": "virizion" + }, + { + "Id": 641, + "Name": "tornadus" + }, + { + "Id": 642, + "Name": "thundurus" + }, + { + "Id": 643, + "Name": "reshiram" + }, + { + "Id": 644, + "Name": "zekrom" + }, + { + "Id": 645, + "Name": "landorus" + }, + { + "Id": 646, + "Name": "kyurem" + }, + { + "Id": 647, + "Name": "keldeo" + }, + { + "Id": 648, + "Name": "meloetta" + }, + { + "Id": 649, + "Name": "genesect" + }, + { + "Id": 650, + "Name": "chespin" + }, + { + "Id": 651, + "Name": "quilladin" + }, + { + "Id": 652, + "Name": "chesnaught" + }, + { + "Id": 653, + "Name": "fennekin" + }, + { + "Id": 654, + "Name": "braixen" + }, + { + "Id": 655, + "Name": "delphox" + }, + { + "Id": 656, + "Name": "froakie" + }, + { + "Id": 657, + "Name": "frogadier" + }, + { + "Id": 658, + "Name": "greninja" + }, + { + "Id": 659, + "Name": "bunnelby" + }, + { + "Id": 660, + "Name": "diggersby" + }, + { + "Id": 661, + "Name": "fletchling" + }, + { + "Id": 662, + "Name": "fletchinder" + }, + { + "Id": 663, + "Name": "talonflame" + }, + { + "Id": 664, + "Name": "scatterbug" + }, + { + "Id": 665, + "Name": "spewpa" + }, + { + "Id": 666, + "Name": "vivillon" + }, + { + "Id": 667, + "Name": "litleo" + }, + { + "Id": 668, + "Name": "pyroar" + }, + { + "Id": 669, + "Name": "flabebe" + }, + { + "Id": 670, + "Name": "floette" + }, + { + "Id": 671, + "Name": "florges" + }, + { + "Id": 672, + "Name": "skiddo" + }, + { + "Id": 673, + "Name": "gogoat" + }, + { + "Id": 674, + "Name": "pancham" + }, + { + "Id": 675, + "Name": "pangoro" + }, + { + "Id": 676, + "Name": "furfrou" + }, + { + "Id": 677, + "Name": "espurr" + }, + { + "Id": 678, + "Name": "meowstic" + }, + { + "Id": 679, + "Name": "honedge" + }, + { + "Id": 680, + "Name": "doublade" + }, + { + "Id": 681, + "Name": "aegislash" + }, + { + "Id": 682, + "Name": "spritzee" + }, + { + "Id": 683, + "Name": "aromatisse" + }, + { + "Id": 684, + "Name": "swirlix" + }, + { + "Id": 685, + "Name": "slurpuff" + }, + { + "Id": 686, + "Name": "inkay" + }, + { + "Id": 687, + "Name": "malamar" + }, + { + "Id": 688, + "Name": "binacle" + }, + { + "Id": 689, + "Name": "barbaracle" + }, + { + "Id": 690, + "Name": "skrelp" + }, + { + "Id": 691, + "Name": "dragalge" + }, + { + "Id": 692, + "Name": "clauncher" + }, + { + "Id": 693, + "Name": "clawitzer" + }, + { + "Id": 694, + "Name": "helioptile" + }, + { + "Id": 695, + "Name": "heliolisk" + }, + { + "Id": 696, + "Name": "tyrunt" + }, + { + "Id": 697, + "Name": "tyrantrum" + }, + { + "Id": 698, + "Name": "amaura" + }, + { + "Id": 699, + "Name": "aurorus" + }, + { + "Id": 700, + "Name": "sylveon" + }, + { + "Id": 701, + "Name": "hawlucha" + }, + { + "Id": 702, + "Name": "dedenne" + }, + { + "Id": 703, + "Name": "carbink" + }, + { + "Id": 704, + "Name": "goomy" + }, + { + "Id": 705, + "Name": "sliggoo" + }, + { + "Id": 706, + "Name": "goodra" + }, + { + "Id": 707, + "Name": "klefki" + }, + { + "Id": 708, + "Name": "phantump" + }, + { + "Id": 709, + "Name": "trevenant" + }, + { + "Id": 710, + "Name": "pumpkaboo" + }, + { + "Id": 711, + "Name": "gourgeist" + }, + { + "Id": 712, + "Name": "bergmite" + }, + { + "Id": 713, + "Name": "avalugg" + }, + { + "Id": 714, + "Name": "noibat" + }, + { + "Id": 715, + "Name": "noivern" + }, + { + "Id": 716, + "Name": "xerneas" + }, + { + "Id": 717, + "Name": "yveltal" + }, + { + "Id": 718, + "Name": "zygarde" + }, + { + "Id": 719, + "Name": "diancie" + }, + { + "Id": 720, + "Name": "hoopa" + }, + { + "Id": 721, + "Name": "volcanion" + }, + { + "Id": 722, + "Name": "Rowlet" + }, + { + "Id": 723, + "Name": "Dartrix" + }, + { + "Id": 724, + "Name": "Decidueye" + }, + { + "Id": 725, + "Name": "Litten" + }, + { + "Id": 726, + "Name": "Torracat" + }, + { + "Id": 727, + "Name": "Incineroar" + }, + { + "Id": 728, + "Name": "Popplio" + }, + { + "Id": 729, + "Name": "Brionne" + }, + { + "Id": 730, + "Name": "Primarina" + }, + { + "Id": 731, + "Name": "Pikipek" + }, + { + "Id": 732, + "Name": "Trumbeak" + }, + { + "Id": 733, + "Name": "Toucannon" + }, + { + "Id": 734, + "Name": "Yungoos" + }, + { + "Id": 735, + "Name": "Gumshoos" + }, + { + "Id": 736, + "Name": "Grubbin" + }, + { + "Id": 737, + "Name": "Charjabug" + }, + { + "Id": 738, + "Name": "Vikavolt" + }, + { + "Id": 739, + "Name": "Crabrawler" + }, + { + "Id": 740, + "Name": "Crabominable" + }, + { + "Id": 741, + "Name": "Oricorio" + }, + { + "Id": 742, + "Name": "Cutiefly" + }, + { + "Id": 743, + "Name": "Ribombee" + }, + { + "Id": 744, + "Name": "Rockruff" + }, + { + "Id": 745, + "Name": "Lycanroc" + }, + { + "Id": 746, + "Name": "Wishiwashi" + }, + { + "Id": 747, + "Name": "Mareanie" + }, + { + "Id": 748, + "Name": "Toxapex" + }, + { + "Id": 749, + "Name": "Mudbray" + }, + { + "Id": 750, + "Name": "Mudsdale" + }, + { + "Id": 751, + "Name": "Dewpider" + }, + { + "Id": 752, + "Name": "Araquanid" + }, + { + "Id": 753, + "Name": "Fomantis" + }, + { + "Id": 754, + "Name": "Lurantis" + }, + { + "Id": 755, + "Name": "Morelull" + }, + { + "Id": 756, + "Name": "Shiinotic" + }, + { + "Id": 757, + "Name": "Salandit" + }, + { + "Id": 758, + "Name": "Salazzle" + }, + { + "Id": 759, + "Name": "Stufful" + }, + { + "Id": 760, + "Name": "Bewear" + }, + { + "Id": 761, + "Name": "Bounsweet" + }, + { + "Id": 762, + "Name": "Steenee" + }, + { + "Id": 763, + "Name": "Tsareena" + }, + { + "Id": 764, + "Name": "Comfey" + }, + { + "Id": 765, + "Name": "Oranguru" + }, + { + "Id": 766, + "Name": "Passimian" + }, + { + "Id": 767, + "Name": "Wimpod" + }, + { + "Id": 768, + "Name": "Golisopod" + }, + { + "Id": 769, + "Name": "Sandygast" + }, + { + "Id": 770, + "Name": "Palossand" + }, + { + "Id": 771, + "Name": "Pyukumuku" + }, + { + "Id": 772, + "Name": "Type Null" + }, + { + "Id": 773, + "Name": "Silvally" + }, + { + "Id": 774, + "Name": "Minior" + }, + { + "Id": 775, + "Name": "Komala" + }, + { + "Id": 776, + "Name": "Turtonator" + }, + { + "Id": 777, + "Name": "Togedemaru" + }, + { + "Id": 778, + "Name": "Mimikyu" + }, + { + "Id": 779, + "Name": "Bruxish" + }, + { + "Id": 780, + "Name": "Drampa" + }, + { + "Id": 781, + "Name": "Dhelmise" + }, + { + "Id": 782, + "Name": "Jangmo O" + }, + { + "Id": 783, + "Name": "Hakamo O" + }, + { + "Id": 784, + "Name": "Kommo O" + }, + { + "Id": 785, + "Name": "Tapu Koko" + }, + { + "Id": 786, + "Name": "Tapu Lele" + }, + { + "Id": 787, + "Name": "Tapu Bulu" + }, + { + "Id": 788, + "Name": "Tapu Fini" + }, + { + "Id": 789, + "Name": "Cosmog" + }, + { + "Id": 790, + "Name": "Cosmoem" + }, + { + "Id": 791, + "Name": "Solgaleo" + }, + { + "Id": 792, + "Name": "Lunala" + }, + { + "Id": 793, + "Name": "Nihilego" + }, + { + "Id": 794, + "Name": "Buzzwole" + }, + { + "Id": 795, + "Name": "Pheromosa" + }, + { + "Id": 796, + "Name": "Xurkitree" + }, + { + "Id": 797, + "Name": "Celesteela" + }, + { + "Id": 798, + "Name": "Kartana" + }, + { + "Id": 799, + "Name": "Guzzlord" + }, + { + "Id": 800, + "Name": "Necrozma" + }, + { + "Id": 801, + "Name": "Magearna" + }, + { + "Id": 802, + "Name": "Marshadow" + }, + { + "Id": 803, + "Name": "Poipole" + }, + { + "Id": 804, + "Name": "Naganadel" + }, + { + "Id": 805, + "Name": "Stakataka" + }, + { + "Id": 806, + "Name": "Blacephalon" + }, + { + "Id": 807, + "Name": "Zeraora" + }, + { + "Id": 808, + "Name": "Meltan" + }, + { + "Id": 809, + "Name": "Melmetal" + }, + { + "Id": 810, + "Name": "Grookey" + }, + { + "Id": 811, + "Name": "Thwackey" + }, + { + "Id": 812, + "Name": "Rillaboom" + }, + { + "Id": 813, + "Name": "Scorbunny" + }, + { + "Id": 814, + "Name": "Raboot" + }, + { + "Id": 815, + "Name": "Cinderace" + }, + { + "Id": 816, + "Name": "Sobble" + }, + { + "Id": 817, + "Name": "Drizzile" + }, + { + "Id": 818, + "Name": "Inteleon" + }, + { + "Id": 819, + "Name": "Skwovet" + }, + { + "Id": 820, + "Name": "Greedent" + }, + { + "Id": 821, + "Name": "Rookidee" + }, + { + "Id": 822, + "Name": "Corvisquire" + }, + { + "Id": 823, + "Name": "Corviknight" + }, + { + "Id": 824, + "Name": "Blipbug" + }, + { + "Id": 825, + "Name": "Dottler" + }, + { + "Id": 826, + "Name": "Orbeetle" + }, + { + "Id": 827, + "Name": "Nickit" + }, + { + "Id": 828, + "Name": "Thievul" + }, + { + "Id": 829, + "Name": "Gossifleur" + }, + { + "Id": 830, + "Name": "Eldegoss" + }, + { + "Id": 831, + "Name": "Wooloo" + }, + { + "Id": 832, + "Name": "Dubwool" + }, + { + "Id": 833, + "Name": "Chewtle" + }, + { + "Id": 834, + "Name": "Drednaw" + }, + { + "Id": 835, + "Name": "Yamper" + }, + { + "Id": 836, + "Name": "Boltund" + }, + { + "Id": 837, + "Name": "Rolycoly" + }, + { + "Id": 838, + "Name": "Carkol" + }, + { + "Id": 839, + "Name": "Coalossal" + }, + { + "Id": 840, + "Name": "Applin" + }, + { + "Id": 841, + "Name": "Flapple" + }, + { + "Id": 842, + "Name": "Appletun" + }, + { + "Id": 843, + "Name": "Silicobra" + }, + { + "Id": 844, + "Name": "Sandaconda" + }, + { + "Id": 845, + "Name": "Cramorant" + }, + { + "Id": 846, + "Name": "Arrokuda" + }, + { + "Id": 847, + "Name": "Barraskewda" + }, + { + "Id": 848, + "Name": "Toxel" + }, + { + "Id": 849, + "Name": "Toxtricity" + }, + { + "Id": 850, + "Name": "Sizzlipede" + }, + { + "Id": 851, + "Name": "Centiskorch" + }, + { + "Id": 852, + "Name": "Clobbopus" + }, + { + "Id": 853, + "Name": "Grapploct" + }, + { + "Id": 854, + "Name": "Sinistea" + }, + { + "Id": 855, + "Name": "Polteageist" + }, + { + "Id": 856, + "Name": "Hatenna" + }, + { + "Id": 857, + "Name": "Hattrem" + }, + { + "Id": 858, + "Name": "Hatterene" + }, + { + "Id": 859, + "Name": "Impidimp" + }, + { + "Id": 860, + "Name": "Morgrem" + }, + { + "Id": 861, + "Name": "Grimmsnarl" + }, + { + "Id": 862, + "Name": "Obstagoon" + }, + { + "Id": 863, + "Name": "Perrserker" + }, + { + "Id": 864, + "Name": "Cursola" + }, + { + "Id": 865, + "Name": "Sirfetchd" + }, + { + "Id": 866, + "Name": "Mr Rime" + }, + { + "Id": 867, + "Name": "Runerigus" + }, + { + "Id": 868, + "Name": "Milcery" + }, + { + "Id": 869, + "Name": "Alcremie" + }, + { + "Id": 870, + "Name": "Falinks" + }, + { + "Id": 871, + "Name": "Pincurchin" + }, + { + "Id": 872, + "Name": "Snom" + }, + { + "Id": 873, + "Name": "Frosmoth" + }, + { + "Id": 874, + "Name": "Stonjourner" + }, + { + "Id": 875, + "Name": "Eiscue" + }, + { + "Id": 876, + "Name": "Indeedee" + }, + { + "Id": 877, + "Name": "Morpeko" + }, + { + "Id": 878, + "Name": "Cufant" + }, + { + "Id": 879, + "Name": "Copperajah" + }, + { + "Id": 880, + "Name": "Dracozolt" + }, + { + "Id": 881, + "Name": "Arctozolt" + }, + { + "Id": 882, + "Name": "Dracovish" + }, + { + "Id": 883, + "Name": "Arctovish" + }, + { + "Id": 884, + "Name": "Duraludon" + }, + { + "Id": 885, + "Name": "Dreepy" + }, + { + "Id": 886, + "Name": "Drakloak" + }, + { + "Id": 887, + "Name": "Dragapult" + }, + { + "Id": 888, + "Name": "Zacian" + }, + { + "Id": 889, + "Name": "Zamazenta" + }, + { + "Id": 890, + "Name": "Eternatus" + }, + { + "Id": 891, + "Name": "Kubfu" + }, + { + "Id": 892, + "Name": "Urshifu Single Strike" + }, + { + "Id": 893, + "Name": "Zarude" + }, + { + "Id": 894, + "Name": "Regieleki" + }, + { + "Id": 895, + "Name": "Regidrago" + }, + { + "Id": 896, + "Name": "Glastrier" + }, + { + "Id": 897, + "Name": "Spectrier" + }, + { + "Id": 898, + "Name": "Calyrex" + }, + { + "Id": 899, + "Name": "Wyrdeer" + }, + { + "Id": 900, + "Name": "Kleavor" + }, + { + "Id": 901, + "Name": "Ursaluna" + }, + { + "Id": 902, + "Name": "Basculegion" + }, + { + "Id": 903, + "Name": "Sneasler" + }, + { + "Id": 904, + "Name": "Overqwil" + }, + { + "Id": 905, + "Name": "Enamorus" + } +] \ No newline at end of file diff --git a/src/EllieBot/data/pokemon/pokemon_abilities.json b/src/EllieBot/data/pokemon/pokemon_abilities.json new file mode 100644 index 0000000..7cbd029 --- /dev/null +++ b/src/EllieBot/data/pokemon/pokemon_abilities.json @@ -0,0 +1,1930 @@ +{ + "adaptability": { + "desc": "This Pokemon's moves that match one of its types have a same-type attack bonus (STAB) of 2 instead of 1.5.", + "shortDesc": "This Pokemon's same-type attack bonus (STAB) is 2 instead of 1.5.", + "id": "adaptability", + "name": "Adaptability", + "rating": 3.5, + "num": 91 + }, + "aftermath": { + "desc": "If this Pokemon is knocked out with a contact move, that move's user loses 1/4 of its maximum HP, rounded down. If any active Pokemon has the Ability Damp, this effect is prevented.", + "shortDesc": "If this Pokemon is KOed with a contact move, that move's user loses 1/4 its max HP.", + "id": "aftermath", + "name": "Aftermath", + "onAfterDamageOrder": 1, + "rating": 2.5, + "num": 106 + }, + "aerilate": { + "desc": "This Pokemon's Normal-type moves become Flying-type moves and have their power multiplied by 1.2. This effect comes after other effects that change a move's type, but before Ion Deluge and Electrify's effects.", + "shortDesc": "This Pokemon's Normal-type moves become Flying type and have 1.2x power.", + "onModifyMovePriority": -1, + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "aerilate", + "name": "Aerilate", + "rating": 4, + "num": 185 + }, + "airlock": { + "shortDesc": "While this Pokemon is active, the effects of weather conditions are disabled.", + "suppressWeather": true, + "id": "airlock", + "name": "Air Lock", + "rating": 3, + "num": 76 + }, + "analytic": { + "desc": "The power of this Pokemon's move is multiplied by 1.3 if it is the last to move in a turn. Does not affect Doom Desire and Future Sight.", + "shortDesc": "This Pokemon's attacks have 1.3x power if it is the last to move in a turn.", + "onBasePowerPriority": 8, + "id": "analytic", + "name": "Analytic", + "rating": 2, + "num": 148 + }, + "angerpoint": { + "desc": "If this Pokemon, but not its substitute, is struck by a critical hit, its Attack is raised by 12 stages.", + "shortDesc": "If this Pokemon (not its substitute) takes a critical hit, its Attack is raised 12 stages.", + "id": "angerpoint", + "name": "Anger Point", + "rating": 2, + "num": 83 + }, + "anticipation": { + "desc": "On switch-in, this Pokemon is alerted if any opposing Pokemon has an attack that is super effective on this Pokemon, or an OHKO move. Counter, Metal Burst, and Mirror Coat count as attacking moves of their respective types, while Hidden Power, Judgment, Natural Gift, Techno Blast, and Weather Ball are considered Normal-type moves.", + "shortDesc": "On switch-in, this Pokemon shudders if any foe has a supereffective or OHKO move.", + "id": "anticipation", + "name": "Anticipation", + "rating": 1, + "num": 107 + }, + "arenatrap": { + "desc": "Prevents adjacent opposing Pokemon from choosing to switch out unless they are immune to trapping or are airborne.", + "shortDesc": "Prevents adjacent foes from choosing to switch unless they are airborne.", + "id": "arenatrap", + "name": "Arena Trap", + "rating": 4.5, + "num": 71 + }, + "aromaveil": { + "desc": "This Pokemon and its allies cannot be affected by Attract, Disable, Encore, Heal Block, Taunt, or Torment.", + "shortDesc": "Protects user/allies from Attract, Disable, Encore, Heal Block, Taunt, and Torment.", + "id": "aromaveil", + "name": "Aroma Veil", + "rating": 1.5, + "num": 165 + }, + "aurabreak": { + "desc": "While this Pokemon is active, the effects of the Abilities Dark Aura and Fairy Aura are reversed, multiplying the power of Dark- and Fairy-type moves, respectively, by 3/4 instead of 1.33.", + "shortDesc": "While this Pokemon is active, the Dark Aura and Fairy Aura power modifier is 0.75x.", + "effect": { + "duration": 1 + }, + "id": "aurabreak", + "name": "Aura Break", + "rating": 1.5, + "num": 188 + }, + "baddreams": { + "desc": "Causes adjacent opposing Pokemon to lose 1/8 of their maximum HP, rounded down, at the end of each turn if they are asleep.", + "shortDesc": "Causes sleeping adjacent foes to lose 1/8 of their max HP at the end of each turn.", + "onResidualOrder": 26, + "onResidualSubOrder": 1, + "id": "baddreams", + "name": "Bad Dreams", + "rating": 2, + "num": 123 + }, + "battery": { + "shortDesc": "This Pokemon's allies have the power of their special attacks multiplied by 1.3.", + "onBasePowerPriority": 8, + "id": "battery", + "name": "Battery", + "rating": 0, + "num": 217 + }, + "battlearmor": { + "shortDesc": "This Pokemon cannot be struck by a critical hit.", + "onCriticalHit": false, + "id": "battlearmor", + "name": "Battle Armor", + "rating": 1, + "num": 4 + }, + "battlebond": { + "desc": "If this Pokemon is a Greninja, it transforms into Ash-Greninja after knocking out a Pokemon. As Ash-Greninja, its Water Shuriken has 20 base power and always hits 3 times.", + "shortDesc": "After KOing a Pokemon: becomes Ash-Greninja, Water Shuriken: 20 power, hits 3x.", + "id": "battlebond", + "name": "Battle Bond", + "rating": 3, + "num": 210 + }, + "beastboost": { + "desc": "This Pokemon's highest stat is raised by 1 stage if it attacks and knocks out another Pokemon.", + "shortDesc": "This Pokemon's highest stat is raised by 1 if it attacks and KOes another Pokemon.", + "id": "beastboost", + "name": "Beast Boost", + "rating": 3.5, + "num": 224 + }, + "berserk": { + "desc": "This Pokemon's Special Attack is raised by 1 stage when it reaches 1/2 or less of its maximum HP.", + "shortDesc": "This Pokemon's Sp. Atk is raised by 1 when it reaches 1/2 or less of its max HP.", + "id": "berserk", + "name": "Berserk", + "rating": 2.5, + "num": 201 + }, + "bigpecks": { + "shortDesc": "Prevents other Pokemon from lowering this Pokemon's Defense stat stage.", + "id": "bigpecks", + "name": "Big Pecks", + "rating": 0.5, + "num": 145 + }, + "blaze": { + "desc": "When this Pokemon has 1/3 or less of its maximum HP, rounded down, its attacking stat is multiplied by 1.5 while using a Fire-type attack.", + "shortDesc": "When this Pokemon has 1/3 or less of its max HP, its Fire attacks do 1.5x damage.", + "onModifyAtkPriority": 5, + "onModifySpAPriority": 5, + "id": "blaze", + "name": "Blaze", + "rating": 2, + "num": 66 + }, + "bulletproof": { + "desc": "This Pokemon is immune to ballistic moves. Ballistic moves include Bullet Seed, Octazooka, Barrage, Rock Wrecker, Zap Cannon, Acid Spray, Aura Sphere, Focus Blast, and all moves with Ball or Bomb in their name.", + "shortDesc": "Makes user immune to ballistic moves (Shadow Ball, Sludge Bomb, Focus Blast, etc).", + "id": "bulletproof", + "name": "Bulletproof", + "rating": 3, + "num": 171 + }, + "cheekpouch": { + "desc": "If this Pokemon eats a Berry, it restores 1/3 of its maximum HP, rounded down, in addition to the Berry's effect.", + "shortDesc": "If this Pokemon eats a Berry, it restores 1/3 of its max HP after the Berry's effect.", + "id": "cheekpouch", + "name": "Cheek Pouch", + "rating": 2, + "num": 167 + }, + "chlorophyll": { + "shortDesc": "If Sunny Day is active, this Pokemon's Speed is doubled.", + "id": "chlorophyll", + "name": "Chlorophyll", + "rating": 2.5, + "num": 34 + }, + "clearbody": { + "shortDesc": "Prevents other Pokemon from lowering this Pokemon's stat stages.", + "id": "clearbody", + "name": "Clear Body", + "rating": 2, + "num": 29 + }, + "cloudnine": { + "shortDesc": "While this Pokemon is active, the effects of weather conditions are disabled.", + "suppressWeather": true, + "id": "cloudnine", + "name": "Cloud Nine", + "rating": 3, + "num": 13 + }, + "colorchange": { + "desc": "This Pokemon's type changes to match the type of the last move that hit it, unless that type is already one of its types. This effect applies after all hits from a multi-hit move; Sheer Force prevents it from activating if the move has a secondary effect.", + "shortDesc": "This Pokemon's type changes to the type of a move it's hit by, unless it has the type.", + "id": "colorchange", + "name": "Color Change", + "rating": 1, + "num": 16 + }, + "comatose": { + "shortDesc": "This Pokemon cannot be statused, and is considered to be asleep.", + "isUnbreakable": true, + "id": "comatose", + "name": "Comatose", + "rating": 3, + "num": 213 + }, + "competitive": { + "desc": "This Pokemon's Special Attack is raised by 2 stages for each of its stat stages that is lowered by an opposing Pokemon.", + "shortDesc": "This Pokemon's Sp. Atk is raised by 2 for each of its stats that is lowered by a foe.", + "id": "competitive", + "name": "Competitive", + "rating": 2.5, + "num": 172 + }, + "compoundeyes": { + "shortDesc": "This Pokemon's moves have their accuracy multiplied by 1.3.", + "id": "compoundeyes", + "name": "Compound Eyes", + "rating": 3.5, + "num": 14 + }, + "contrary": { + "shortDesc": "If this Pokemon has a stat stage raised it is lowered instead, and vice versa.", + "id": "contrary", + "name": "Contrary", + "rating": 4, + "num": 126 + }, + "corrosion": { + "shortDesc": "This Pokemon can poison or badly poison other Pokemon regardless of their typing.", + "id": "corrosion", + "name": "Corrosion", + "rating": 2.5, + "num": 212 + }, + "cursedbody": { + "desc": "If this Pokemon is hit by an attack, there is a 30% chance that move gets disabled unless one of the attacker's moves is already disabled.", + "shortDesc": "If this Pokemon is hit by an attack, there is a 30% chance that move gets disabled.", + "id": "cursedbody", + "name": "Cursed Body", + "rating": 2, + "num": 130 + }, + "cutecharm": { + "desc": "There is a 30% chance a Pokemon making contact with this Pokemon will become infatuated if it is of the opposite gender.", + "shortDesc": "30% chance of infatuating Pokemon of the opposite gender if they make contact.", + "id": "cutecharm", + "name": "Cute Charm", + "rating": 1, + "num": 56 + }, + "damp": { + "desc": "While this Pokemon is active, Self-Destruct, Explosion, and the Ability Aftermath are prevented from having an effect.", + "shortDesc": "While this Pokemon is active, Self-Destruct, Explosion, and Aftermath have no effect.", + "id": "damp", + "name": "Damp", + "rating": 1, + "num": 6 + }, + "dancer": { + "desc": "After another Pokemon uses a dance move, this Pokemon uses the same move. Moves used by this Ability cannot be copied again.", + "shortDesc": "After another Pokemon uses a dance move, this Pokemon uses the same move.", + "id": "dancer", + "name": "Dancer", + "rating": 2.5, + "num": 216 + }, + "darkaura": { + "desc": "While this Pokemon is active, the power of Dark-type moves used by active Pokemon is multiplied by 1.33.", + "shortDesc": "While this Pokemon is active, a Dark move used by any Pokemon has 1.33x power.", + "id": "darkaura", + "name": "Dark Aura", + "rating": 3, + "num": 186 + }, + "dazzling": { + "desc": "While this Pokemon is active, priority moves from opposing Pokemon targeted at allies are prevented from having an effect.", + "shortDesc": "While this Pokemon is active, allies are protected from opposing priority moves.", + "id": "dazzling", + "name": "Dazzling", + "rating": 3.5, + "num": 219 + }, + "defeatist": { + "desc": "While this Pokemon has 1/2 or less of its maximum HP, its Attack and Special Attack are halved.", + "shortDesc": "While this Pokemon has 1/2 or less of its max HP, its Attack and Sp. Atk are halved.", + "onModifyAtkPriority": 5, + "onModifySpAPriority": 5, + "id": "defeatist", + "name": "Defeatist", + "rating": -1, + "num": 129 + }, + "defiant": { + "desc": "This Pokemon's Attack is raised by 2 stages for each of its stat stages that is lowered by an opposing Pokemon.", + "shortDesc": "This Pokemon's Attack is raised by 2 for each of its stats that is lowered by a foe.", + "id": "defiant", + "name": "Defiant", + "rating": 2.5, + "num": 128 + }, + "deltastream": { + "desc": "On switch-in, the weather becomes strong winds that remove the weaknesses of the Flying type from Flying-type Pokemon. This weather remains in effect until this Ability is no longer active for any Pokemon, or the weather is changed by Desolate Land or Primordial Sea.", + "shortDesc": "On switch-in, strong winds begin until this Ability is not active in battle.", + "id": "deltastream", + "name": "Delta Stream", + "rating": 5, + "num": 191 + }, + "desolateland": { + "desc": "On switch-in, the weather becomes extremely harsh sunlight that prevents damaging Water-type moves from executing, in addition to all the effects of Sunny Day. This weather remains in effect until this Ability is no longer active for any Pokemon, or the weather is changed by Delta Stream or Primordial Sea.", + "shortDesc": "On switch-in, extremely harsh sunlight begins until this Ability is not active in battle.", + "id": "desolateland", + "name": "Desolate Land", + "rating": 5, + "num": 190 + }, + "disguise": { + "desc": "If this Pokemon is a Mimikyu, it will take 0 damage the first time it is attacked in battle. It then changes to Busted Form.", + "shortDesc": "If this Pokemon is a Mimikyu, it takes 0 damage the first time it is attacked in battle.", + "onDamagePriority": 1, + "id": "disguise", + "name": "Disguise", + "rating": 4, + "num": 209 + }, + "download": { + "desc": "On switch-in, this Pokemon's Attack or Special Attack is raised by 1 stage based on the weaker combined defensive stat of all opposing Pokemon. Attack is raised if their Defense is lower, and Special Attack is raised if their Special Defense is the same or lower.", + "shortDesc": "On switch-in, Attack or Sp. Atk is raised 1 stage based on the foes' weaker Defense.", + "id": "download", + "name": "Download", + "rating": 4, + "num": 88 + }, + "drizzle": { + "shortDesc": "On switch-in, this Pokemon summons Rain Dance.", + "id": "drizzle", + "name": "Drizzle", + "rating": 4.5, + "num": 2 + }, + "drought": { + "shortDesc": "On switch-in, this Pokemon summons Sunny Day.", + "id": "drought", + "name": "Drought", + "rating": 4.5, + "num": 70 + }, + "dryskin": { + "desc": "This Pokemon is immune to Water-type moves and restores 1/4 of its maximum HP, rounded down, when hit by a Water-type move. The power of Fire-type moves is multiplied by 1.25 when used on this Pokemon. At the end of each turn, this Pokemon restores 1/8 of its maximum HP, rounded down, if the weather is Rain Dance, and loses 1/8 of its maximum HP, rounded down, if the weather is Sunny Day.", + "shortDesc": "This Pokemon is healed 1/4 by Water, 1/8 by Rain; is hurt 1.25x by Fire, 1/8 by Sun.", + "onBasePowerPriority": 7, + "id": "dryskin", + "name": "Dry Skin", + "rating": 3, + "num": 87 + }, + "earlybird": { + "shortDesc": "This Pokemon's sleep counter drops by 2 instead of 1.", + "id": "earlybird", + "name": "Early Bird", + "rating": 2.5, + "num": 48 + }, + "effectspore": { + "desc": "30% chance a Pokemon making contact with this Pokemon will be poisoned, paralyzed, or fall asleep.", + "shortDesc": "30% chance of poison/paralysis/sleep on others making contact with this Pokemon.", + "id": "effectspore", + "name": "Effect Spore", + "rating": 2, + "num": 27 + }, + "electricsurge": { + "shortDesc": "On switch-in, this Pokemon summons Electric Terrain.", + "id": "electricsurge", + "name": "Electric Surge", + "rating": 4, + "num": 226 + }, + "emergencyexit": { + "shortDesc": "This Pokemon switches out when it reaches 1/2 or less of its maximum HP.", + "id": "emergencyexit", + "name": "Emergency Exit", + "rating": 2, + "num": 194 + }, + "fairyaura": { + "desc": "While this Pokemon is active, the power of Fairy-type moves used by active Pokemon is multiplied by 1.33.", + "shortDesc": "While this Pokemon is active, a Fairy move used by any Pokemon has 1.33x power.", + "id": "fairyaura", + "name": "Fairy Aura", + "rating": 3, + "num": 187 + }, + "filter": { + "shortDesc": "This Pokemon receives 3/4 damage from supereffective attacks.", + "id": "filter", + "name": "Filter", + "rating": 3, + "num": 111 + }, + "flamebody": { + "shortDesc": "30% chance a Pokemon making contact with this Pokemon will be burned.", + "id": "flamebody", + "name": "Flame Body", + "rating": 2, + "num": 49 + }, + "flareboost": { + "desc": "While this Pokemon is burned, the power of its special attacks is multiplied by 1.5.", + "shortDesc": "While this Pokemon is burned, its special attacks have 1.5x power.", + "onBasePowerPriority": 8, + "id": "flareboost", + "name": "Flare Boost", + "rating": 2.5, + "num": 138 + }, + "flashfire": { + "desc": "This Pokemon is immune to Fire-type moves. The first time it is hit by a Fire-type move, its attacking stat is multiplied by 1.5 while using a Fire-type attack as long as it remains active and has this Ability. If this Pokemon is frozen, it cannot be defrosted by Fire-type attacks.", + "shortDesc": "This Pokemon's Fire attacks do 1.5x damage if hit by one Fire move; Fire immunity.", + "effect": { + "noCopy": true, + "onModifyAtkPriority": 5, + "onModifySpAPriority": 5 + }, + "id": "flashfire", + "name": "Flash Fire", + "rating": 3, + "num": 18 + }, + "flowergift": { + "desc": "If this Pokemon is a Cherrim and Sunny Day is active, it changes to Sunshine Form and the Attack and Special Defense of it and its allies are multiplied by 1.5.", + "shortDesc": "If user is Cherrim and Sunny Day is active, it and allies' Attack and Sp. Def are 1.5x.", + "onModifyAtkPriority": 3, + "onModifySpDPriority": 4, + "id": "flowergift", + "name": "Flower Gift", + "rating": 2.5, + "num": 122 + }, + "flowerveil": { + "desc": "Grass-type Pokemon on this Pokemon's side cannot have their stat stages lowered by other Pokemon or have a major status condition inflicted on them by other Pokemon.", + "shortDesc": "This side's Grass types can't have stats lowered or status inflicted by other Pokemon.", + "id": "flowerveil", + "name": "Flower Veil", + "rating": 0, + "num": 166 + }, + "fluffy": { + "desc": "This Pokemon receives 1/2 damage from contact moves, but double damage from Fire moves.", + "shortDesc": "This Pokemon takes 1/2 damage from contact moves, 2x damage from Fire moves.", + "id": "fluffy", + "name": "Fluffy", + "rating": 2.5, + "num": 218 + }, + "forecast": { + "desc": "If this Pokemon is a Castform, its type changes to the current weather condition's type, except Sandstorm.", + "shortDesc": "Castform's type changes to the current weather condition's type, except Sandstorm.", + "id": "forecast", + "name": "Forecast", + "rating": 3, + "num": 59 + }, + "forewarn": { + "desc": "On switch-in, this Pokemon is alerted to the move with the highest power, at random, known by an opposing Pokemon.", + "shortDesc": "On switch-in, this Pokemon is alerted to the foes' move with the highest power.", + "id": "forewarn", + "name": "Forewarn", + "rating": 1, + "num": 108 + }, + "friendguard": { + "shortDesc": "This Pokemon's allies receive 3/4 damage from other Pokemon's attacks.", + "id": "friendguard", + "name": "Friend Guard", + "rating": 0, + "num": 132 + }, + "frisk": { + "shortDesc": "On switch-in, this Pokemon identifies the held items of all opposing Pokemon.", + "id": "frisk", + "name": "Frisk", + "rating": 1.5, + "num": 119 + }, + "fullmetalbody": { + "shortDesc": "Prevents other Pokemon from lowering this Pokemon's stat stages.", + "isUnbreakable": true, + "id": "fullmetalbody", + "name": "Full Metal Body", + "rating": 2, + "num": 230 + }, + "furcoat": { + "shortDesc": "This Pokemon's Defense is doubled.", + "onModifyDefPriority": 6, + "id": "furcoat", + "name": "Fur Coat", + "rating": 3.5, + "num": 169 + }, + "galewings": { + "shortDesc": "If this Pokemon is at full HP, its Flying-type moves have their priority increased by 1.", + "id": "galewings", + "name": "Gale Wings", + "rating": 3, + "num": 177 + }, + "galvanize": { + "desc": "This Pokemon's Normal-type moves become Electric-type moves and have their power multiplied by 1.2. This effect comes after other effects that change a move's type, but before Ion Deluge and Electrify's effects.", + "shortDesc": "This Pokemon's Normal-type moves become Electric type and have 1.2x power.", + "onModifyMovePriority": -1, + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "galvanize", + "name": "Galvanize", + "rating": 4, + "num": 206 + }, + "gluttony": { + "shortDesc": "When this Pokemon has 1/2 or less of its maximum HP, it uses certain Berries early.", + "id": "gluttony", + "name": "Gluttony", + "rating": 1, + "num": 82 + }, + "gooey": { + "shortDesc": "Pokemon making contact with this Pokemon have their Speed lowered by 1 stage.", + "id": "gooey", + "name": "Gooey", + "rating": 2.5, + "num": 183 + }, + "grasspelt": { + "shortDesc": "If Grassy Terrain is active, this Pokemon's Defense is multiplied by 1.5.", + "onModifyDefPriority": 6, + "id": "grasspelt", + "name": "Grass Pelt", + "rating": 0.5, + "num": 179 + }, + "grassysurge": { + "shortDesc": "On switch-in, this Pokemon summons Grassy Terrain.", + "id": "grassysurge", + "name": "Grassy Surge", + "rating": 4, + "num": 229 + }, + "guts": { + "desc": "If this Pokemon has a major status condition, its Attack is multiplied by 1.5; burn's physical damage halving is ignored.", + "shortDesc": "If this Pokemon is statused, its Attack is 1.5x; ignores burn halving physical damage.", + "onModifyAtkPriority": 5, + "id": "guts", + "name": "Guts", + "rating": 3, + "num": 62 + }, + "harvest": { + "desc": "If the last item this Pokemon used is a Berry, there is a 50% chance it gets restored at the end of each turn. If Sunny Day is active, this chance is 100%.", + "shortDesc": "If last item used is a Berry, 50% chance to restore it each end of turn. 100% in Sun.", + "id": "harvest", + "name": "Harvest", + "onResidualOrder": 26, + "onResidualSubOrder": 1, + "rating": 2.5, + "num": 139 + }, + "healer": { + "desc": "There is a 30% chance of curing an adjacent ally's major status condition at the end of each turn.", + "shortDesc": "30% chance of curing an adjacent ally's status at the end of each turn.", + "id": "healer", + "name": "Healer", + "onResidualOrder": 5, + "onResidualSubOrder": 1, + "rating": 0, + "num": 131 + }, + "heatproof": { + "desc": "The power of Fire-type attacks against this Pokemon is halved, and burn damage taken is halved.", + "shortDesc": "The power of Fire-type attacks against this Pokemon is halved; burn damage halved.", + "onBasePowerPriority": 7, + "id": "heatproof", + "name": "Heatproof", + "rating": 2.5, + "num": 85 + }, + "heavymetal": { + "shortDesc": "This Pokemon's weight is doubled.", + "id": "heavymetal", + "name": "Heavy Metal", + "rating": -1, + "num": 134 + }, + "honeygather": { + "shortDesc": "No competitive use.", + "id": "honeygather", + "name": "Honey Gather", + "rating": 0, + "num": 118 + }, + "hugepower": { + "shortDesc": "This Pokemon's Attack is doubled.", + "onModifyAtkPriority": 5, + "id": "hugepower", + "name": "Huge Power", + "rating": 5, + "num": 37 + }, + "hustle": { + "desc": "This Pokemon's Attack is multiplied by 1.5 and the accuracy of its physical attacks is multiplied by 0.8.", + "shortDesc": "This Pokemon's Attack is 1.5x and accuracy of its physical attacks is 0.8x.", + "onModifyAtkPriority": 5, + "id": "hustle", + "name": "Hustle", + "rating": 3, + "num": 55 + }, + "hydration": { + "desc": "This Pokemon has its major status condition cured at the end of each turn if Rain Dance is active.", + "shortDesc": "This Pokemon has its status cured at the end of each turn if Rain Dance is active.", + "onResidualOrder": 5, + "onResidualSubOrder": 1, + "id": "hydration", + "name": "Hydration", + "rating": 2, + "num": 93 + }, + "hypercutter": { + "shortDesc": "Prevents other Pokemon from lowering this Pokemon's Attack stat stage.", + "id": "hypercutter", + "name": "Hyper Cutter", + "rating": 1.5, + "num": 52 + }, + "icebody": { + "desc": "If Hail is active, this Pokemon restores 1/16 of its maximum HP, rounded down, at the end of each turn. This Pokemon takes no damage from Hail.", + "shortDesc": "If Hail is active, this Pokemon heals 1/16 of its max HP each turn; immunity to Hail.", + "id": "icebody", + "name": "Ice Body", + "rating": 1.5, + "num": 115 + }, + "illuminate": { + "shortDesc": "No competitive use.", + "id": "illuminate", + "name": "Illuminate", + "rating": 0, + "num": 35 + }, + "illusion": { + "desc": "When this Pokemon switches in, it appears as the last unfainted Pokemon in its party until it takes direct damage from another Pokemon's attack. This Pokemon's actual level and HP are displayed instead of those of the mimicked Pokemon.", + "shortDesc": "This Pokemon appears as the last Pokemon in the party until it takes direct damage.", + "id": "illusion", + "name": "Illusion", + "rating": 4, + "num": 149 + }, + "immunity": { + "shortDesc": "This Pokemon cannot be poisoned. Gaining this Ability while poisoned cures it.", + "id": "immunity", + "name": "Immunity", + "rating": 2, + "num": 17 + }, + "imposter": { + "desc": "On switch-in, this Pokemon Transforms into the opposing Pokemon that is facing it. If there is no Pokemon at that position, this Pokemon does not Transform.", + "shortDesc": "On switch-in, this Pokemon Transforms into the opposing Pokemon that is facing it.", + "id": "imposter", + "name": "Imposter", + "rating": 4.5, + "num": 150 + }, + "infiltrator": { + "desc": "This Pokemon's moves ignore substitutes and the opposing side's Reflect, Light Screen, Safeguard, and Mist.", + "shortDesc": "Moves ignore substitutes and opposing Reflect, Light Screen, Safeguard, and Mist.", + "id": "infiltrator", + "name": "Infiltrator", + "rating": 3, + "num": 151 + }, + "innardsout": { + "desc": "If this Pokemon is knocked out with a move, that move's user loses HP equal to the amount of damage inflicted on this Pokemon.", + "shortDesc": "If this Pokemon is KOed with a move, that move's user loses an equal amount of HP.", + "id": "innardsout", + "name": "Innards Out", + "onAfterDamageOrder": 1, + "rating": 2.5, + "num": 215 + }, + "innerfocus": { + "shortDesc": "This Pokemon cannot be made to flinch.", + "onFlinch": false, + "id": "innerfocus", + "name": "Inner Focus", + "rating": 1.5, + "num": 39 + }, + "insomnia": { + "shortDesc": "This Pokemon cannot fall asleep. Gaining this Ability while asleep cures it.", + "id": "insomnia", + "name": "Insomnia", + "rating": 2, + "num": 15 + }, + "intimidate": { + "desc": "On switch-in, this Pokemon lowers the Attack of adjacent opposing Pokemon by 1 stage. Pokemon behind a substitute are immune.", + "shortDesc": "On switch-in, this Pokemon lowers the Attack of adjacent opponents by 1 stage.", + "id": "intimidate", + "name": "Intimidate", + "rating": 3.5, + "num": 22 + }, + "ironbarbs": { + "desc": "Pokemon making contact with this Pokemon lose 1/8 of their maximum HP, rounded down.", + "shortDesc": "Pokemon making contact with this Pokemon lose 1/8 of their max HP.", + "onAfterDamageOrder": 1, + "id": "ironbarbs", + "name": "Iron Barbs", + "rating": 3, + "num": 160 + }, + "ironfist": { + "desc": "This Pokemon's punch-based attacks have their power multiplied by 1.2.", + "shortDesc": "This Pokemon's punch-based attacks have 1.2x power. Sucker Punch is not boosted.", + "onBasePowerPriority": 8, + "id": "ironfist", + "name": "Iron Fist", + "rating": 3, + "num": 89 + }, + "justified": { + "shortDesc": "This Pokemon's Attack is raised by 1 stage after it is damaged by a Dark-type move.", + "id": "justified", + "name": "Justified", + "rating": 2, + "num": 154 + }, + "keeneye": { + "desc": "Prevents other Pokemon from lowering this Pokemon's accuracy stat stage. This Pokemon ignores a target's evasiveness stat stage.", + "shortDesc": "This Pokemon's accuracy can't be lowered by others; ignores their evasiveness stat.", + "id": "keeneye", + "name": "Keen Eye", + "rating": 1, + "num": 51 + }, + "klutz": { + "desc": "This Pokemon's held item has no effect. This Pokemon cannot use Fling successfully. Macho Brace, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, and Power Weight still have their effects.", + "shortDesc": "This Pokemon's held item has no effect, except Macho Brace. Fling cannot be used.", + "id": "klutz", + "name": "Klutz", + "rating": -1, + "num": 103 + }, + "leafguard": { + "desc": "If Sunny Day is active, this Pokemon cannot gain a major status condition and Rest will fail for it.", + "shortDesc": "If Sunny Day is active, this Pokemon cannot be statused and Rest will fail for it.", + "id": "leafguard", + "name": "Leaf Guard", + "rating": 1, + "num": 102 + }, + "levitate": { + "desc": "This Pokemon is immune to Ground. Gravity, Ingrain, Smack Down, Thousand Arrows, and Iron Ball nullify the immunity.", + "shortDesc": "This Pokemon is immune to Ground; Gravity/Ingrain/Smack Down/Iron Ball nullify it.", + "id": "levitate", + "name": "Levitate", + "rating": 3.5, + "num": 26 + }, + "lightmetal": { + "shortDesc": "This Pokemon's weight is halved.", + "id": "lightmetal", + "name": "Light Metal", + "rating": 1, + "num": 135 + }, + "lightningrod": { + "desc": "This Pokemon is immune to Electric-type moves and raises its Special Attack by 1 stage when hit by an Electric-type move. If this Pokemon is not the target of a single-target Electric-type move used by another Pokemon, this Pokemon redirects that move to itself if it is within the range of that move.", + "shortDesc": "This Pokemon draws Electric moves to itself to raise Sp. Atk by 1; Electric immunity.", + "id": "lightningrod", + "name": "Lightning Rod", + "rating": 3.5, + "num": 32 + }, + "limber": { + "shortDesc": "This Pokemon cannot be paralyzed. Gaining this Ability while paralyzed cures it.", + "id": "limber", + "name": "Limber", + "rating": 1.5, + "num": 7 + }, + "liquidooze": { + "shortDesc": "This Pokemon damages those draining HP from it for as much as they would heal.", + "id": "liquidooze", + "name": "Liquid Ooze", + "rating": 1.5, + "num": 64 + }, + "liquidvoice": { + "desc": "This Pokemon's sound-based moves become Water-type moves. This effect comes after other effects that change a move's type, but before Ion Deluge and Electrify's effects.", + "shortDesc": "This Pokemon's sound-based moves become Water type.", + "onModifyMovePriority": -1, + "id": "liquidvoice", + "name": "Liquid Voice", + "rating": 2.5, + "num": 204 + }, + "longreach": { + "shortDesc": "This Pokemon's attacks do not make contact with the target.", + "id": "longreach", + "name": "Long Reach", + "rating": 1.5, + "num": 203 + }, + "magicbounce": { + "desc": "This Pokemon blocks certain status moves and instead uses the move against the original user.", + "shortDesc": "This Pokemon blocks certain status moves and bounces them back to the user.", + "id": "magicbounce", + "name": "Magic Bounce", + "onTryHitPriority": 1, + "effect": { + "duration": 1 + }, + "rating": 4.5, + "num": 156 + }, + "magicguard": { + "desc": "This Pokemon can only be damaged by direct attacks. Curse and Substitute on use, Belly Drum, Pain Split, Struggle recoil, and confusion damage are considered direct damage.", + "shortDesc": "This Pokemon can only be damaged by direct attacks.", + "id": "magicguard", + "name": "Magic Guard", + "rating": 4.5, + "num": 98 + }, + "magician": { + "desc": "If this Pokemon has no item, it steals the item off a Pokemon it hits with an attack. Does not affect Doom Desire and Future Sight.", + "shortDesc": "If this Pokemon has no item, it steals the item off a Pokemon it hits with an attack.", + "id": "magician", + "name": "Magician", + "rating": 1.5, + "num": 170 + }, + "magmaarmor": { + "shortDesc": "This Pokemon cannot be frozen. Gaining this Ability while frozen cures it.", + "id": "magmaarmor", + "name": "Magma Armor", + "rating": 0.5, + "num": 40 + }, + "magnetpull": { + "desc": "Prevents adjacent opposing Steel-type Pokemon from choosing to switch out unless they are immune to trapping.", + "shortDesc": "Prevents adjacent Steel-type foes from choosing to switch.", + "id": "magnetpull", + "name": "Magnet Pull", + "rating": 4.5, + "num": 42 + }, + "marvelscale": { + "desc": "If this Pokemon has a major status condition, its Defense is multiplied by 1.5.", + "shortDesc": "If this Pokemon is statused, its Defense is 1.5x.", + "onModifyDefPriority": 6, + "id": "marvelscale", + "name": "Marvel Scale", + "rating": 2.5, + "num": 63 + }, + "megalauncher": { + "desc": "This Pokemon's pulse moves have their power multiplied by 1.5. Heal Pulse restores 3/4 of a target's maximum HP, rounded half down.", + "shortDesc": "This Pokemon's pulse moves have 1.5x power. Heal Pulse heals 3/4 target's max HP.", + "onBasePowerPriority": 8, + "id": "megalauncher", + "name": "Mega Launcher", + "rating": 3.5, + "num": 178 + }, + "merciless": { + "shortDesc": "This Pokemon's attacks are critical hits if the target is poisoned.", + "id": "merciless", + "name": "Merciless", + "rating": 2, + "num": 196 + }, + "minus": { + "desc": "If an active ally has this Ability or the Ability Plus, this Pokemon's Special Attack is multiplied by 1.5.", + "shortDesc": "If an active ally has this Ability or the Ability Plus, this Pokemon's Sp. Atk is 1.5x.", + "onModifySpAPriority": 5, + "id": "minus", + "name": "Minus", + "rating": 0, + "num": 58 + }, + "mistysurge": { + "shortDesc": "On switch-in, this Pokemon summons Misty Terrain.", + "id": "mistysurge", + "name": "Misty Surge", + "rating": 4, + "num": 228 + }, + "moldbreaker": { + "shortDesc": "This Pokemon's moves and their effects ignore the Abilities of other Pokemon.", + "id": "moldbreaker", + "name": "Mold Breaker", + "rating": 3.5, + "num": 104 + }, + "moody": { + "desc": "This Pokemon has a random stat raised by 2 stages and another stat lowered by 1 stage at the end of each turn.", + "shortDesc": "Raises a random stat by 2 and lowers another stat by 1 at the end of each turn.", + "onResidualOrder": 26, + "onResidualSubOrder": 1, + "id": "moody", + "name": "Moody", + "rating": 5, + "num": 141 + }, + "motordrive": { + "desc": "This Pokemon is immune to Electric-type moves and raises its Speed by 1 stage when hit by an Electric-type move.", + "shortDesc": "This Pokemon's Speed is raised 1 stage if hit by an Electric move; Electric immunity.", + "id": "motordrive", + "name": "Motor Drive", + "rating": 3, + "num": 78 + }, + "moxie": { + "desc": "This Pokemon's Attack is raised by 1 stage if it attacks and knocks out another Pokemon.", + "shortDesc": "This Pokemon's Attack is raised by 1 stage if it attacks and KOes another Pokemon.", + "id": "moxie", + "name": "Moxie", + "rating": 3.5, + "num": 153 + }, + "multiscale": { + "shortDesc": "If this Pokemon is at full HP, damage taken from attacks is halved.", + "id": "multiscale", + "name": "Multiscale", + "rating": 4, + "num": 136 + }, + "multitype": { + "shortDesc": "If this Pokemon is an Arceus, its type changes to match its held Plate or Z-Crystal.", + "id": "multitype", + "name": "Multitype", + "rating": 4, + "num": 121 + }, + "mummy": { + "desc": "Pokemon making contact with this Pokemon have their Ability changed to Mummy. Does not affect the Abilities Multitype or Stance Change.", + "shortDesc": "Pokemon making contact with this Pokemon have their Ability changed to Mummy.", + "id": "mummy", + "name": "Mummy", + "rating": 2, + "num": 152 + }, + "naturalcure": { + "shortDesc": "This Pokemon has its major status condition cured when it switches out.", + "id": "naturalcure", + "name": "Natural Cure", + "rating": 3.5, + "num": 30 + }, + "neuroforce": { + "shortDesc": "Multiplies the power of super effective moves by 1.25.", + "id": "neuroforce", + "name": "Neuroforce", + "rating": 3.5, + "num": 233 + }, + "noguard": { + "shortDesc": "Every move used by or against this Pokemon will always hit.", + "id": "noguard", + "name": "No Guard", + "rating": 4, + "num": 99 + }, + "normalize": { + "desc": "This Pokemon's moves are changed to be Normal type and have their power multiplied by 1.2. This effect comes before other effects that change a move's type.", + "shortDesc": "This Pokemon's moves are changed to be Normal type and have 1.2x power.", + "onModifyMovePriority": 1, + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "normalize", + "name": "Normalize", + "rating": -1, + "num": 96 + }, + "oblivious": { + "desc": "This Pokemon cannot be infatuated or taunted. Gaining this Ability while affected cures it.", + "shortDesc": "This Pokemon cannot be infatuated or taunted. Gaining this Ability cures it.", + "id": "oblivious", + "name": "Oblivious", + "rating": 1, + "num": 12 + }, + "overcoat": { + "shortDesc": "This Pokemon is immune to powder moves and damage from Sandstorm or Hail.", + "onTryHitPriority": 1, + "id": "overcoat", + "name": "Overcoat", + "rating": 2.5, + "num": 142 + }, + "overgrow": { + "desc": "When this Pokemon has 1/3 or less of its maximum HP, its attacking stat is multiplied by 1.5 while using a Grass-type attack.", + "shortDesc": "When this Pokemon has 1/3 or less of its max HP, its Grass attacks do 1.5x damage.", + "onModifyAtkPriority": 5, + "onModifySpAPriority": 5, + "id": "overgrow", + "name": "Overgrow", + "rating": 2, + "num": 65 + }, + "owntempo": { + "shortDesc": "This Pokemon cannot be confused. Gaining this Ability while confused cures it.", + "id": "owntempo", + "name": "Own Tempo", + "rating": 1, + "num": 20 + }, + "parentalbond": { + "desc": "This Pokemon's damaging moves become multi-hit moves that hit twice. The second hit has its damage quartered. Does not affect multi-hit moves or moves that have multiple targets.", + "shortDesc": "This Pokemon's damaging moves hit twice. The second hit has its damage quartered.", + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "parentalbond", + "name": "Parental Bond", + "rating": 5, + "num": 184 + }, + "pickup": { + "shortDesc": "If this Pokemon has no item, it finds one used by an adjacent Pokemon this turn.", + "onResidualOrder": 26, + "onResidualSubOrder": 1, + "id": "pickup", + "name": "Pickup", + "rating": 0.5, + "num": 53 + }, + "pickpocket": { + "desc": "If this Pokemon has no item, it steals the item off a Pokemon that makes contact with it. This effect applies after all hits from a multi-hit move; Sheer Force prevents it from activating if the move has a secondary effect.", + "shortDesc": "If this Pokemon has no item, it steals the item off a Pokemon making contact with it.", + "id": "pickpocket", + "name": "Pickpocket", + "rating": 1, + "num": 124 + }, + "pixilate": { + "desc": "This Pokemon's Normal-type moves become Fairy-type moves and have their power multiplied by 1.2. This effect comes after other effects that change a move's type, but before Ion Deluge and Electrify's effects.", + "shortDesc": "This Pokemon's Normal-type moves become Fairy type and have 1.2x power.", + "onModifyMovePriority": -1, + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "pixilate", + "name": "Pixilate", + "rating": 4, + "num": 182 + }, + "plus": { + "desc": "If an active ally has this Ability or the Ability Minus, this Pokemon's Special Attack is multiplied by 1.5.", + "shortDesc": "If an active ally has this Ability or the Ability Minus, this Pokemon's Sp. Atk is 1.5x.", + "onModifySpAPriority": 5, + "id": "plus", + "name": "Plus", + "rating": 0, + "num": 57 + }, + "poisonheal": { + "desc": "If this Pokemon is poisoned, it restores 1/8 of its maximum HP, rounded down, at the end of each turn instead of losing HP.", + "shortDesc": "This Pokemon is healed by 1/8 of its max HP each turn when poisoned; no HP loss.", + "id": "poisonheal", + "name": "Poison Heal", + "rating": 4, + "num": 90 + }, + "poisonpoint": { + "shortDesc": "30% chance a Pokemon making contact with this Pokemon will be poisoned.", + "id": "poisonpoint", + "name": "Poison Point", + "rating": 2, + "num": 38 + }, + "poisontouch": { + "shortDesc": "This Pokemon's contact moves have a 30% chance of poisoning.", + "id": "poisontouch", + "name": "Poison Touch", + "rating": 2, + "num": 143 + }, + "powerconstruct": { + "desc": "If this Pokemon is a Zygarde in its 10% or 50% Forme, it changes to Complete Forme when it has 1/2 or less of its maximum HP at the end of the turn.", + "shortDesc": "If Zygarde 10%/50%, changes to Complete if at 1/2 max HP or less at end of turn.", + "onResidualOrder": 27, + "id": "powerconstruct", + "name": "Power Construct", + "rating": 4, + "num": 211 + }, + "powerofalchemy": { + "desc": "This Pokemon copies the Ability of an ally that faints. Abilities that cannot be copied are Flower Gift, Forecast, Illusion, Imposter, Multitype, Stance Change, Trace, Wonder Guard, and Zen Mode.", + "shortDesc": "This Pokemon copies the Ability of an ally that faints.", + "id": "powerofalchemy", + "name": "Power of Alchemy", + "rating": 0, + "num": 223 + }, + "prankster": { + "shortDesc": "This Pokemon's Status moves have priority raised by 1, but Dark types are immune.", + "id": "prankster", + "name": "Prankster", + "rating": 4, + "num": 158 + }, + "pressure": { + "desc": "If this Pokemon is the target of an opposing Pokemon's move, that move loses one additional PP.", + "shortDesc": "If this Pokemon is the target of a foe's move, that move loses one additional PP.", + "id": "pressure", + "name": "Pressure", + "rating": 1.5, + "num": 46 + }, + "primordialsea": { + "desc": "On switch-in, the weather becomes heavy rain that prevents damaging Fire-type moves from executing, in addition to all the effects of Rain Dance. This weather remains in effect until this Ability is no longer active for any Pokemon, or the weather is changed by Delta Stream or Desolate Land.", + "shortDesc": "On switch-in, heavy rain begins until this Ability is not active in battle.", + "id": "primordialsea", + "name": "Primordial Sea", + "rating": 5, + "num": 189 + }, + "prismarmor": { + "shortDesc": "This Pokemon receives 3/4 damage from supereffective attacks.", + "isUnbreakable": true, + "id": "prismarmor", + "name": "Prism Armor", + "rating": 3, + "num": 232 + }, + "protean": { + "desc": "This Pokemon's type changes to match the type of the move it is about to use. This effect comes after all effects that change a move's type.", + "shortDesc": "This Pokemon's type changes to match the type of the move it is about to use.", + "id": "protean", + "name": "Protean", + "rating": 4, + "num": 168 + }, + "psychicsurge": { + "shortDesc": "On switch-in, this Pokemon summons Psychic Terrain.", + "id": "psychicsurge", + "name": "Psychic Surge", + "rating": 4, + "num": 227 + }, + "purepower": { + "shortDesc": "This Pokemon's Attack is doubled.", + "onModifyAtkPriority": 5, + "id": "purepower", + "name": "Pure Power", + "rating": 5, + "num": 74 + }, + "queenlymajesty": { + "desc": "While this Pokemon is active, priority moves from opposing Pokemon targeted at allies are prevented from having an effect.", + "shortDesc": "While this Pokemon is active, allies are protected from opposing priority moves.", + "id": "queenlymajesty", + "name": "Queenly Majesty", + "rating": 3.5, + "num": 214 + }, + "quickfeet": { + "desc": "If this Pokemon has a major status condition, its Speed is multiplied by 1.5; the Speed drop from paralysis is ignored.", + "shortDesc": "If this Pokemon is statused, its Speed is 1.5x; ignores Speed drop from paralysis.", + "id": "quickfeet", + "name": "Quick Feet", + "rating": 2.5, + "num": 95 + }, + "raindish": { + "desc": "If Rain Dance is active, this Pokemon restores 1/16 of its maximum HP, rounded down, at the end of each turn.", + "shortDesc": "If Rain Dance is active, this Pokemon heals 1/16 of its max HP each turn.", + "id": "raindish", + "name": "Rain Dish", + "rating": 1.5, + "num": 44 + }, + "rattled": { + "desc": "This Pokemon's Speed is raised by 1 stage if hit by a Bug-, Dark-, or Ghost-type attack.", + "shortDesc": "This Pokemon's Speed is raised 1 stage if hit by a Bug-, Dark-, or Ghost-type attack.", + "id": "rattled", + "name": "Rattled", + "rating": 1.5, + "num": 155 + }, + "receiver": { + "desc": "This Pokemon copies the Ability of an ally that faints. Abilities that cannot be copied are Flower Gift, Forecast, Illusion, Imposter, Multitype, Stance Change, Trace, Wonder Guard, and Zen Mode.", + "shortDesc": "This Pokemon copies the Ability of an ally that faints.", + "id": "receiver", + "name": "Receiver", + "rating": 0, + "num": 222 + }, + "reckless": { + "desc": "This Pokemon's attacks with recoil or crash damage have their power multiplied by 1.2. Does not affect Struggle.", + "shortDesc": "This Pokemon's attacks with recoil or crash damage have 1.2x power; not Struggle.", + "onBasePowerPriority": 8, + "id": "reckless", + "name": "Reckless", + "rating": 3, + "num": 120 + }, + "refrigerate": { + "desc": "This Pokemon's Normal-type moves become Ice-type moves and have their power multiplied by 1.2. This effect comes after other effects that change a move's type, but before Ion Deluge and Electrify's effects.", + "shortDesc": "This Pokemon's Normal-type moves become Ice type and have 1.2x power.", + "onModifyMovePriority": -1, + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "refrigerate", + "name": "Refrigerate", + "rating": 4, + "num": 174 + }, + "regenerator": { + "shortDesc": "This Pokemon restores 1/3 of its maximum HP, rounded down, when it switches out.", + "id": "regenerator", + "name": "Regenerator", + "rating": 4, + "num": 144 + }, + "rivalry": { + "desc": "This Pokemon's attacks have their power multiplied by 1.25 against targets of the same gender or multiplied by 0.75 against targets of the opposite gender. There is no modifier if either this Pokemon or the target is genderless.", + "shortDesc": "This Pokemon's attacks do 1.25x on same gender targets; 0.75x on opposite gender.", + "onBasePowerPriority": 8, + "id": "rivalry", + "name": "Rivalry", + "rating": 0.5, + "num": 79 + }, + "rkssystem": { + "shortDesc": "If this Pokemon is a Silvally, its type changes to match its held Memory.", + "id": "rkssystem", + "name": "RKS System", + "rating": 4, + "num": 225 + }, + "rockhead": { + "desc": "This Pokemon does not take recoil damage besides Struggle, Life Orb, and crash damage.", + "shortDesc": "This Pokemon does not take recoil damage besides Struggle/Life Orb/crash damage.", + "id": "rockhead", + "name": "Rock Head", + "rating": 3, + "num": 69 + }, + "roughskin": { + "desc": "Pokemon making contact with this Pokemon lose 1/8 of their maximum HP, rounded down.", + "shortDesc": "Pokemon making contact with this Pokemon lose 1/8 of their max HP.", + "onAfterDamageOrder": 1, + "id": "roughskin", + "name": "Rough Skin", + "rating": 3, + "num": 24 + }, + "runaway": { + "shortDesc": "No competitive use.", + "id": "runaway", + "name": "Run Away", + "rating": 0, + "num": 50 + }, + "sandforce": { + "desc": "If Sandstorm is active, this Pokemon's Ground-, Rock-, and Steel-type attacks have their power multiplied by 1.3. This Pokemon takes no damage from Sandstorm.", + "shortDesc": "This Pokemon's Ground/Rock/Steel attacks do 1.3x in Sandstorm; immunity to it.", + "onBasePowerPriority": 8, + "id": "sandforce", + "name": "Sand Force", + "rating": 2, + "num": 159 + }, + "sandrush": { + "desc": "If Sandstorm is active, this Pokemon's Speed is doubled. This Pokemon takes no damage from Sandstorm.", + "shortDesc": "If Sandstorm is active, this Pokemon's Speed is doubled; immunity to Sandstorm.", + "id": "sandrush", + "name": "Sand Rush", + "rating": 2.5, + "num": 146 + }, + "sandstream": { + "shortDesc": "On switch-in, this Pokemon summons Sandstorm.", + "id": "sandstream", + "name": "Sand Stream", + "rating": 4.5, + "num": 45 + }, + "sandveil": { + "desc": "If Sandstorm is active, this Pokemon's evasiveness is multiplied by 1.25. This Pokemon takes no damage from Sandstorm.", + "shortDesc": "If Sandstorm is active, this Pokemon's evasiveness is 1.25x; immunity to Sandstorm.", + "id": "sandveil", + "name": "Sand Veil", + "rating": 1.5, + "num": 8 + }, + "sapsipper": { + "desc": "This Pokemon is immune to Grass-type moves and raises its Attack by 1 stage when hit by a Grass-type move.", + "shortDesc": "This Pokemon's Attack is raised 1 stage if hit by a Grass move; Grass immunity.", + "onTryHitPriority": 1, + "id": "sapsipper", + "name": "Sap Sipper", + "rating": 3.5, + "num": 157 + }, + "schooling": { + "desc": "On switch-in, if this Pokemon is a Wishiwashi that is level 20 or above and has more than 1/4 of its maximum HP left, it changes to School Form. If it is in School Form and its HP drops to 1/4 of its maximum HP or less, it changes to Solo Form at the end of the turn. If it is in Solo Form and its HP is greater than 1/4 its maximum HP at the end of the turn, it changes to School Form.", + "shortDesc": "If user is Wishiwashi, changes to School Form if it has > 1/4 max HP, else Solo Form.", + "onResidualOrder": 27, + "id": "schooling", + "name": "Schooling", + "rating": 2.5, + "num": 208 + }, + "scrappy": { + "shortDesc": "This Pokemon can hit Ghost types with Normal- and Fighting-type moves.", + "onModifyMovePriority": -5, + "id": "scrappy", + "name": "Scrappy", + "rating": 3, + "num": 113 + }, + "serenegrace": { + "shortDesc": "This Pokemon's moves have their secondary effect chance doubled.", + "onModifyMovePriority": -2, + "id": "serenegrace", + "name": "Serene Grace", + "rating": 4, + "num": 32 + }, + "shadowshield": { + "shortDesc": "If this Pokemon is at full HP, damage taken from attacks is halved.", + "isUnbreakable": true, + "id": "shadowshield", + "name": "Shadow Shield", + "rating": 4, + "num": 231 + }, + "shadowtag": { + "desc": "Prevents adjacent opposing Pokemon from choosing to switch out unless they are immune to trapping or also have this Ability.", + "shortDesc": "Prevents adjacent foes from choosing to switch unless they also have this Ability.", + "id": "shadowtag", + "name": "Shadow Tag", + "rating": 5, + "num": 23 + }, + "shedskin": { + "desc": "This Pokemon has a 33% chance to have its major status condition cured at the end of each turn.", + "shortDesc": "This Pokemon has a 33% chance to have its status cured at the end of each turn.", + "onResidualOrder": 5, + "onResidualSubOrder": 1, + "id": "shedskin", + "name": "Shed Skin", + "rating": 3.5, + "num": 61 + }, + "sheerforce": { + "desc": "This Pokemon's attacks with secondary effects have their power multiplied by 1.3, but the secondary effects are removed.", + "shortDesc": "This Pokemon's attacks with secondary effects have 1.3x power; nullifies the effects.", + "effect": { + "duration": 1, + "onBasePowerPriority": 8 + }, + "id": "sheerforce", + "name": "Sheer Force", + "rating": 4, + "num": 125 + }, + "shellarmor": { + "shortDesc": "This Pokemon cannot be struck by a critical hit.", + "onCriticalHit": false, + "id": "shellarmor", + "name": "Shell Armor", + "rating": 1, + "num": 75 + }, + "shielddust": { + "shortDesc": "This Pokemon is not affected by the secondary effect of another Pokemon's attack.", + "id": "shielddust", + "name": "Shield Dust", + "rating": 2.5, + "num": 19 + }, + "shieldsdown": { + "desc": "If this Pokemon is a Minior, it changes to its Core forme if it has 1/2 or less of its maximum HP, and changes to Meteor Form if it has more than 1/2 its maximum HP. This check is done on switch-in and at the end of each turn. While in its Meteor Form, it cannot become affected by major status conditions.", + "shortDesc": "If Minior, switch-in/end of turn it changes to Core at 1/2 max HP or less, else Meteor.", + "onResidualOrder": 27, + "id": "shieldsdown", + "name": "Shields Down", + "rating": 2.5, + "num": 197 + }, + "simple": { + "shortDesc": "If this Pokemon's stat stages are raised or lowered, the effect is doubled instead.", + "id": "simple", + "name": "Simple", + "rating": 4, + "num": 86 + }, + "skilllink": { + "shortDesc": "This Pokemon's multi-hit attacks always hit the maximum number of times.", + "id": "skilllink", + "name": "Skill Link", + "rating": 4, + "num": 92 + }, + "slowstart": { + "shortDesc": "On switch-in, this Pokemon's Attack and Speed are halved for 5 turns.", + "effect": { + "duration": 5, + "onModifyAtkPriority": 5 + }, + "id": "slowstart", + "name": "Slow Start", + "rating": -2, + "num": 112 + }, + "slushrush": { + "desc": "If Hail is active, this Pokemon's Speed is doubled. This Pokemon takes no damage from Hail.", + "shortDesc": "If Hail is active, this Pokemon's Speed is doubled; immunity to Hail.", + "id": "slushrush", + "name": "Slush Rush", + "rating": 2.5, + "num": 202 + }, + "sniper": { + "shortDesc": "If this Pokemon strikes with a critical hit, the damage is multiplied by 1.5.", + "id": "sniper", + "name": "Sniper", + "rating": 1, + "num": 97 + }, + "snowcloak": { + "desc": "If Hail is active, this Pokemon's evasiveness is multiplied by 1.25. This Pokemon takes no damage from Hail.", + "shortDesc": "If Hail is active, this Pokemon's evasiveness is 1.25x; immunity to Hail.", + "id": "snowcloak", + "name": "Snow Cloak", + "rating": 1.5, + "num": 81 + }, + "snowwarning": { + "shortDesc": "On switch-in, this Pokemon summons Hail.", + "id": "snowwarning", + "name": "Snow Warning", + "rating": 4, + "num": 117 + }, + "solarpower": { + "desc": "If Sunny Day is active, this Pokemon's Special Attack is multiplied by 1.5 and it loses 1/8 of its maximum HP, rounded down, at the end of each turn.", + "shortDesc": "If Sunny Day is active, this Pokemon's Sp. Atk is 1.5x; loses 1/8 max HP per turn.", + "onModifySpAPriority": 5, + "id": "solarpower", + "name": "Solar Power", + "rating": 1.5, + "num": 94 + }, + "solidrock": { + "shortDesc": "This Pokemon receives 3/4 damage from supereffective attacks.", + "id": "solidrock", + "name": "Solid Rock", + "rating": 3, + "num": 116 + }, + "soulheart": { + "desc": "This Pokemon's Special Attack is raised by 1 stage when another Pokemon faints.", + "shortDesc": "This Pokemon's Sp. Atk is raised by 1 stage when another Pokemon faints.", + "id": "soulheart", + "name": "Soul-Heart", + "rating": 3.5, + "num": 220 + }, + "soundproof": { + "shortDesc": "This Pokemon is immune to sound-based moves, including Heal Bell.", + "id": "soundproof", + "name": "Soundproof", + "rating": 2, + "num": 43 + }, + "speedboost": { + "desc": "This Pokemon's Speed is raised by 1 stage at the end of each full turn it has been on the field.", + "shortDesc": "This Pokemon's Speed is raised 1 stage at the end of each full turn on the field.", + "onResidualOrder": 26, + "onResidualSubOrder": 1, + "id": "speedboost", + "name": "Speed Boost", + "rating": 4.5, + "num": 3 + }, + "stakeout": { + "shortDesc": "This Pokemon's attacks deal double damage if the target switched in this turn.", + "id": "stakeout", + "name": "Stakeout", + "rating": 2.5, + "num": 198 + }, + "stall": { + "shortDesc": "This Pokemon moves last among Pokemon using the same or greater priority moves.", + "id": "stall", + "name": "Stall", + "rating": -1, + "num": 100 + }, + "stamina": { + "shortDesc": "This Pokemon's Defense is raised by 1 stage after it is damaged by a move.", + "id": "stamina", + "name": "Stamina", + "rating": 1.5, + "num": 192 + }, + "stancechange": { + "desc": "If this Pokemon is an Aegislash, it changes to Blade Forme before attempting to use an attacking move, and changes to Shield Forme before attempting to use King's Shield.", + "shortDesc": "If Aegislash, changes Forme to Blade before attacks and Shield before King's Shield.", + "onBeforeMovePriority": 0.5, + "id": "stancechange", + "name": "Stance Change", + "rating": 5, + "num": 176 + }, + "static": { + "shortDesc": "30% chance a Pokemon making contact with this Pokemon will be paralyzed.", + "id": "static", + "name": "Static", + "rating": 2, + "num": 9 + }, + "steadfast": { + "shortDesc": "If this Pokemon flinches, its Speed is raised by 1 stage.", + "id": "steadfast", + "name": "Steadfast", + "rating": 1, + "num": 80 + }, + "steelworker": { + "shortDesc": "This Pokemon's Steel-type attacks have their power multiplied by 1.5.", + "onBasePowerPriority": 8, + "id": "steelworker", + "name": "Steelworker", + "rating": 3, + "num": 200 + }, + "stench": { + "shortDesc": "This Pokemon's attacks without a chance to flinch have a 10% chance to flinch.", + "id": "stench", + "name": "Stench", + "rating": 0.5, + "num": 1 + }, + "stickyhold": { + "shortDesc": "This Pokemon cannot lose its held item due to another Pokemon's attack.", + "id": "stickyhold", + "name": "Sticky Hold", + "rating": 1.5, + "num": 60 + }, + "stormdrain": { + "desc": "This Pokemon is immune to Water-type moves and raises its Special Attack by 1 stage when hit by a Water-type move. If this Pokemon is not the target of a single-target Water-type move used by another Pokemon, this Pokemon redirects that move to itself if it is within the range of that move.", + "shortDesc": "This Pokemon draws Water moves to itself to raise Sp. Atk by 1; Water immunity.", + "id": "stormdrain", + "name": "Storm Drain", + "rating": 3.5, + "num": 114 + }, + "strongjaw": { + "desc": "This Pokemon's bite-based attacks have their power multiplied by 1.5.", + "shortDesc": "This Pokemon's bite-based attacks have 1.5x power. Bug Bite is not boosted.", + "onBasePowerPriority": 8, + "id": "strongjaw", + "name": "Strong Jaw", + "rating": 3, + "num": 173 + }, + "sturdy": { + "desc": "If this Pokemon is at full HP, it survives one hit with at least 1 HP. OHKO moves fail when used against this Pokemon.", + "shortDesc": "If this Pokemon is at full HP, it survives one hit with at least 1 HP. Immune to OHKO.", + "onDamagePriority": -100, + "id": "sturdy", + "name": "Sturdy", + "rating": 3, + "num": 5 + }, + "suctioncups": { + "shortDesc": "This Pokemon cannot be forced to switch out by another Pokemon's attack or item.", + "onDragOutPriority": 1, + "id": "suctioncups", + "name": "Suction Cups", + "rating": 2, + "num": 21 + }, + "superluck": { + "shortDesc": "This Pokemon's critical hit ratio is raised by 1 stage.", + "id": "superluck", + "name": "Super Luck", + "rating": 1.5, + "num": 105 + }, + "surgesurfer": { + "shortDesc": "If Electric Terrain is active, this Pokemon's Speed is doubled.", + "id": "surgesurfer", + "name": "Surge Surfer", + "rating": 2, + "num": 207 + }, + "swarm": { + "desc": "When this Pokemon has 1/3 or less of its maximum HP, rounded down, its attacking stat is multiplied by 1.5 while using a Bug-type attack.", + "shortDesc": "When this Pokemon has 1/3 or less of its max HP, its Bug attacks do 1.5x damage.", + "onModifyAtkPriority": 5, + "onModifySpAPriority": 5, + "id": "swarm", + "name": "Swarm", + "rating": 2, + "num": 68 + }, + "sweetveil": { + "shortDesc": "This Pokemon and its allies cannot fall asleep.", + "id": "sweetveil", + "name": "Sweet Veil", + "rating": 2, + "num": 175 + }, + "swiftswim": { + "shortDesc": "If Rain Dance is active, this Pokemon's Speed is doubled.", + "id": "swiftswim", + "name": "Swift Swim", + "rating": 2.5, + "num": 33 + }, + "symbiosis": { + "desc": "If an ally uses its item, this Pokemon gives its item to that ally immediately. Does not activate if the ally's item was stolen or knocked off.", + "shortDesc": "If an ally uses its item, this Pokemon gives its item to that ally immediately.", + "id": "symbiosis", + "name": "Symbiosis", + "rating": 0, + "num": 180 + }, + "synchronize": { + "desc": "If another Pokemon burns, paralyzes, poisons, or badly poisons this Pokemon, that Pokemon receives the same major status condition.", + "shortDesc": "If another Pokemon burns/poisons/paralyzes this Pokemon, it also gets that status.", + "id": "synchronize", + "name": "Synchronize", + "rating": 2.5, + "num": 28 + }, + "tangledfeet": { + "shortDesc": "This Pokemon's evasiveness is doubled as long as it is confused.", + "id": "tangledfeet", + "name": "Tangled Feet", + "rating": 1, + "num": 77 + }, + "tanglinghair": { + "shortDesc": "Pokemon making contact with this Pokemon have their Speed lowered by 1 stage.", + "id": "tanglinghair", + "name": "Tangling Hair", + "rating": 2.5, + "num": 221 + }, + "technician": { + "desc": "This Pokemon's moves of 60 power or less have their power multiplied by 1.5. Does affect Struggle.", + "shortDesc": "This Pokemon's moves of 60 power or less have 1.5x power. Includes Struggle.", + "onBasePowerPriority": 8, + "id": "technician", + "name": "Technician", + "rating": 4, + "num": 101 + }, + "telepathy": { + "shortDesc": "This Pokemon does not take damage from attacks made by its allies.", + "id": "telepathy", + "name": "Telepathy", + "rating": 0, + "num": 140 + }, + "teravolt": { + "shortDesc": "This Pokemon's moves and their effects ignore the Abilities of other Pokemon.", + "id": "teravolt", + "name": "Teravolt", + "rating": 3.5, + "num": 164 + }, + "thickfat": { + "desc": "If a Pokemon uses a Fire- or Ice-type attack against this Pokemon, that Pokemon's attacking stat is halved when calculating the damage to this Pokemon.", + "shortDesc": "Fire/Ice-type moves against this Pokemon deal damage with a halved attacking stat.", + "onModifyAtkPriority": 6, + "onModifySpAPriority": 5, + "id": "thickfat", + "name": "Thick Fat", + "rating": 3.5, + "num": 47 + }, + "tintedlens": { + "shortDesc": "This Pokemon's attacks that are not very effective on a target deal double damage.", + "id": "tintedlens", + "name": "Tinted Lens", + "rating": 3.5, + "num": 110 + }, + "torrent": { + "desc": "When this Pokemon has 1/3 or less of its maximum HP, rounded down, its attacking stat is multiplied by 1.5 while using a Water-type attack.", + "shortDesc": "When this Pokemon has 1/3 or less of its max HP, its Water attacks do 1.5x damage.", + "onModifyAtkPriority": 5, + "onModifySpAPriority": 5, + "id": "torrent", + "name": "Torrent", + "rating": 2, + "num": 67 + }, + "toxicboost": { + "desc": "While this Pokemon is poisoned, the power of its physical attacks is multiplied by 1.5.", + "shortDesc": "While this Pokemon is poisoned, its physical attacks have 1.5x power.", + "onBasePowerPriority": 8, + "id": "toxicboost", + "name": "Toxic Boost", + "rating": 3, + "num": 137 + }, + "toughclaws": { + "shortDesc": "This Pokemon's contact moves have their power multiplied by 1.3.", + "onBasePowerPriority": 8, + "id": "toughclaws", + "name": "Tough Claws", + "rating": 3.5, + "num": 181 + }, + "trace": { + "desc": "On switch-in, this Pokemon copies a random adjacent opposing Pokemon's Ability. If there is no Ability that can be copied at that time, this Ability will activate as soon as an Ability can be copied. Abilities that cannot be copied are Comatose, Disguise, Flower Gift, Forecast, Illusion, Imposter, Multitype, Schooling, Stance Change, Trace, and Zen Mode.", + "shortDesc": "On switch-in, or when it can, this Pokemon copies a random adjacent foe's Ability.", + "id": "trace", + "name": "Trace", + "rating": 3, + "num": 36 + }, + "triage": { + "shortDesc": "This Pokemon's healing moves have their priority increased by 3.", + "id": "triage", + "name": "Triage", + "rating": 3.5, + "num": 205 + }, + "truant": { + "shortDesc": "This Pokemon skips every other turn instead of using a move.", + "onBeforeMovePriority": 9, + "effect": { + "duration": 2 + }, + "id": "truant", + "name": "Truant", + "rating": -2, + "num": 54 + }, + "turboblaze": { + "shortDesc": "This Pokemon's moves and their effects ignore the Abilities of other Pokemon.", + "id": "turboblaze", + "name": "Turboblaze", + "rating": 3.5, + "num": 163 + }, + "unaware": { + "desc": "This Pokemon ignores other Pokemon's Attack, Special Attack, and accuracy stat stages when taking damage, and ignores other Pokemon's Defense, Special Defense, and evasiveness stat stages when dealing damage.", + "shortDesc": "This Pokemon ignores other Pokemon's stat stages when taking or doing damage.", + "id": "unaware", + "name": "Unaware", + "rating": 3, + "num": 109 + }, + "unburden": { + "desc": "If this Pokemon loses its held item for any reason, its Speed is doubled. This boost is lost if it switches out or gains a new item or Ability.", + "shortDesc": "Speed is doubled on held item loss; boost is lost if it switches, gets new item/Ability.", + "effect": {}, + "id": "unburden", + "name": "Unburden", + "rating": 3.5, + "num": 84 + }, + "unnerve": { + "shortDesc": "While this Pokemon is active, it prevents opposing Pokemon from using their Berries.", + "onFoeTryEatItem": false, + "id": "unnerve", + "name": "Unnerve", + "rating": 1.5, + "num": 127 + }, + "victorystar": { + "shortDesc": "This Pokemon and its allies' moves have their accuracy multiplied by 1.1.", + "id": "victorystar", + "name": "Victory Star", + "rating": 2.5, + "num": 162 + }, + "vitalspirit": { + "shortDesc": "This Pokemon cannot fall asleep. Gaining this Ability while asleep cures it.", + "id": "vitalspirit", + "name": "Vital Spirit", + "rating": 2, + "num": 72 + }, + "voltabsorb": { + "desc": "This Pokemon is immune to Electric-type moves and restores 1/4 of its maximum HP, rounded down, when hit by an Electric-type move.", + "shortDesc": "This Pokemon heals 1/4 of its max HP when hit by Electric moves; Electric immunity.", + "id": "voltabsorb", + "name": "Volt Absorb", + "rating": 3.5, + "num": 10 + }, + "waterabsorb": { + "desc": "This Pokemon is immune to Water-type moves and restores 1/4 of its maximum HP, rounded down, when hit by a Water-type move.", + "shortDesc": "This Pokemon heals 1/4 of its max HP when hit by Water moves; Water immunity.", + "id": "waterabsorb", + "name": "Water Absorb", + "rating": 3.5, + "num": 11 + }, + "waterbubble": { + "desc": "This Pokemon's Water-type attacks have their power doubled, the power of Fire-type attacks against this Pokemon is halved, and this Pokemon cannot be burned. Gaining this Ability while burned cures it.", + "shortDesc": "This Pokemon's Water power is 2x; it can't be burned; Fire power against it is halved.", + "onBasePowerPriority": 7, + "id": "waterbubble", + "name": "Water Bubble", + "rating": 4, + "num": 199 + }, + "watercompaction": { + "shortDesc": "This Pokemon's Defense is raised 2 stages after it is damaged by a Water-type move.", + "id": "watercompaction", + "name": "Water Compaction", + "rating": 2, + "num": 195 + }, + "waterveil": { + "shortDesc": "This Pokemon cannot be burned. Gaining this Ability while burned cures it.", + "id": "waterveil", + "name": "Water Veil", + "rating": 2, + "num": 41 + }, + "weakarmor": { + "desc": "If a physical attack hits this Pokemon, its Defense is lowered by 1 stage and its Speed is raised by 2 stages.", + "shortDesc": "If a physical attack hits this Pokemon, Defense is lowered by 1, Speed is raised by 2.", + "id": "weakarmor", + "name": "Weak Armor", + "rating": 1, + "num": 133 + }, + "whitesmoke": { + "shortDesc": "Prevents other Pokemon from lowering this Pokemon's stat stages.", + "id": "whitesmoke", + "name": "White Smoke", + "rating": 2, + "num": 73 + }, + "wimpout": { + "shortDesc": "This Pokemon switches out when it reaches 1/2 or less of its maximum HP.", + "id": "wimpout", + "name": "Wimp Out", + "rating": 2, + "num": 193 + }, + "wonderguard": { + "shortDesc": "This Pokemon can only be damaged by supereffective moves and indirect damage.", + "id": "wonderguard", + "name": "Wonder Guard", + "rating": 5, + "num": 25 + }, + "wonderskin": { + "desc": "All non-damaging moves that check accuracy have their accuracy changed to 50% when used on this Pokemon. This change is done before any other accuracy modifying effects.", + "shortDesc": "Status moves with accuracy checks are 50% accurate when used on this Pokemon.", + "onModifyAccuracyPriority": 10, + "id": "wonderskin", + "name": "Wonder Skin", + "rating": 2, + "num": 147 + }, + "zenmode": { + "desc": "If this Pokemon is a Darmanitan, it changes to Zen Mode if it has 1/2 or less of its maximum HP at the end of a turn. If Darmanitan's HP is above 1/2 of its maximum HP at the end of a turn, it changes back to Standard Mode. If Darmanitan loses this Ability while in Zen Mode it reverts to Standard Mode immediately.", + "shortDesc": "If Darmanitan, at end of turn changes Mode to Standard if > 1/2 max HP, else Zen.", + "onResidualOrder": 27, + "effect": {}, + "id": "zenmode", + "name": "Zen Mode", + "rating": -1, + "num": 161 + }, + "mountaineer": { + "shortDesc": "On switch-in, this Pokemon avoids all Rock-type attacks and Stealth Rock.", + "id": "mountaineer", + "isNonstandard": true, + "name": "Mountaineer", + "rating": 3.5, + "num": -2 + }, + "rebound": { + "desc": "On switch-in, this Pokemon blocks certain status moves and instead uses the move against the original user.", + "shortDesc": "On switch-in, blocks certain status moves and bounces them back to the user.", + "id": "rebound", + "isNonstandard": true, + "name": "Rebound", + "onTryHitPriority": 1, + "effect": { + "duration": 1 + }, + "rating": 3.5, + "num": -3 + }, + "persistent": { + "shortDesc": "The duration of certain field effects is increased by 2 turns if used by this Pokemon.", + "id": "persistent", + "isNonstandard": true, + "name": "Persistent", + "rating": 3.5, + "num": -4 + } +} \ No newline at end of file diff --git a/src/EllieBot/data/pokemon/pokemon_list.json b/src/EllieBot/data/pokemon/pokemon_list.json new file mode 100644 index 0000000..ae632eb --- /dev/null +++ b/src/EllieBot/data/pokemon/pokemon_list.json @@ -0,0 +1,29770 @@ +{ + "bulbasaur": { + "num": 1, + "species": "Bulbasaur", + "types": [ + "Grass", + "Poison" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 45, + "atk": 49, + "def": 49, + "spa": 65, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Overgrow", + "H": "Chlorophyll" + }, + "heightm": 0.7, + "weightkg": 6.9, + "color": "Green", + "evos": [ + "ivysaur" + ], + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "ivysaur": { + "num": 2, + "species": "Ivysaur", + "types": [ + "Grass", + "Poison" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 62, + "def": 63, + "spa": 80, + "spd": 80, + "spe": 60 + }, + "abilities": { + "0": "Overgrow", + "H": "Chlorophyll" + }, + "heightm": 1, + "weightkg": 13, + "color": "Green", + "prevo": "bulbasaur", + "evos": [ + "venusaur" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "venusaur": { + "num": 3, + "species": "Venusaur", + "types": [ + "Grass", + "Poison" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 82, + "def": 83, + "spa": 100, + "spd": 100, + "spe": 80 + }, + "abilities": { + "0": "Overgrow", + "H": "Chlorophyll" + }, + "heightm": 2, + "weightkg": 100, + "color": "Green", + "prevo": "ivysaur", + "evoLevel": 32, + "eggGroups": [ + "Monster", + "Grass" + ], + "otherFormes": [ + "venusaurmega" + ] + }, + "venusaurmega": { + "num": 3, + "species": "Venusaur-Mega", + "baseSpecies": "Venusaur", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Grass", + "Poison" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 100, + "def": 123, + "spa": 122, + "spd": 120, + "spe": 80 + }, + "abilities": { + "0": "Thick Fat" + }, + "heightm": 2.4, + "weightkg": 155.5, + "color": "Green", + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "charmander": { + "num": 4, + "species": "Charmander", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 39, + "atk": 52, + "def": 43, + "spa": 60, + "spd": 50, + "spe": 65 + }, + "abilities": { + "0": "Blaze", + "H": "Solar Power" + }, + "heightm": 0.6, + "weightkg": 8.5, + "color": "Red", + "evos": [ + "charmeleon" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "charmeleon": { + "num": 5, + "species": "Charmeleon", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 58, + "atk": 64, + "def": 58, + "spa": 80, + "spd": 65, + "spe": 80 + }, + "abilities": { + "0": "Blaze", + "H": "Solar Power" + }, + "heightm": 1.1, + "weightkg": 19, + "color": "Red", + "prevo": "charmander", + "evos": [ + "charizard" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "charizard": { + "num": 6, + "species": "Charizard", + "types": [ + "Fire", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 78, + "atk": 84, + "def": 78, + "spa": 109, + "spd": 85, + "spe": 100 + }, + "abilities": { + "0": "Blaze", + "H": "Solar Power" + }, + "heightm": 1.7, + "weightkg": 90.5, + "color": "Red", + "prevo": "charmeleon", + "evoLevel": 36, + "eggGroups": [ + "Monster", + "Dragon" + ], + "otherFormes": [ + "charizardmegax", + "charizardmegay" + ] + }, + "charizardmegax": { + "num": 6, + "species": "Charizard-Mega-X", + "baseSpecies": "Charizard", + "forme": "Mega-X", + "formeLetter": "M", + "types": [ + "Fire", + "Dragon" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 78, + "atk": 130, + "def": 111, + "spa": 130, + "spd": 85, + "spe": 100 + }, + "abilities": { + "0": "Tough Claws" + }, + "heightm": 1.7, + "weightkg": 110.5, + "color": "Red", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "charizardmegay": { + "num": 6, + "species": "Charizard-Mega-Y", + "baseSpecies": "Charizard", + "forme": "Mega-Y", + "formeLetter": "M", + "types": [ + "Fire", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 78, + "atk": 104, + "def": 78, + "spa": 159, + "spd": 115, + "spe": 100 + }, + "abilities": { + "0": "Drought" + }, + "heightm": 1.7, + "weightkg": 100.5, + "color": "Red", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "squirtle": { + "num": 7, + "species": "Squirtle", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 44, + "atk": 48, + "def": 65, + "spa": 50, + "spd": 64, + "spe": 43 + }, + "abilities": { + "0": "Torrent", + "H": "Rain Dish" + }, + "heightm": 0.5, + "weightkg": 9, + "color": "Blue", + "evos": [ + "wartortle" + ], + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "wartortle": { + "num": 8, + "species": "Wartortle", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 59, + "atk": 63, + "def": 80, + "spa": 65, + "spd": 80, + "spe": 58 + }, + "abilities": { + "0": "Torrent", + "H": "Rain Dish" + }, + "heightm": 1, + "weightkg": 22.5, + "color": "Blue", + "prevo": "squirtle", + "evos": [ + "blastoise" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "blastoise": { + "num": 9, + "species": "Blastoise", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 79, + "atk": 83, + "def": 100, + "spa": 85, + "spd": 105, + "spe": 78 + }, + "abilities": { + "0": "Torrent", + "H": "Rain Dish" + }, + "heightm": 1.6, + "weightkg": 85.5, + "color": "Blue", + "prevo": "wartortle", + "evoLevel": 36, + "eggGroups": [ + "Monster", + "Water 1" + ], + "otherFormes": [ + "blastoisemega" + ] + }, + "blastoisemega": { + "num": 9, + "species": "Blastoise-Mega", + "baseSpecies": "Blastoise", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 79, + "atk": 103, + "def": 120, + "spa": 135, + "spd": 115, + "spe": 78 + }, + "abilities": { + "0": "Mega Launcher" + }, + "heightm": 1.6, + "weightkg": 101.1, + "color": "Blue", + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "caterpie": { + "num": 10, + "species": "Caterpie", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 45, + "atk": 30, + "def": 35, + "spa": 20, + "spd": 20, + "spe": 45 + }, + "abilities": { + "0": "Shield Dust", + "H": "Run Away" + }, + "heightm": 0.3, + "weightkg": 2.9, + "color": "Green", + "evos": [ + "metapod" + ], + "eggGroups": [ + "Bug" + ] + }, + "metapod": { + "num": 11, + "species": "Metapod", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 50, + "atk": 20, + "def": 55, + "spa": 25, + "spd": 25, + "spe": 30 + }, + "abilities": { + "0": "Shed Skin" + }, + "heightm": 0.7, + "weightkg": 9.9, + "color": "Green", + "prevo": "caterpie", + "evos": [ + "butterfree" + ], + "evoLevel": 7, + "eggGroups": [ + "Bug" + ] + }, + "butterfree": { + "num": 12, + "species": "Butterfree", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 45, + "def": 50, + "spa": 90, + "spd": 80, + "spe": 70 + }, + "abilities": { + "0": "Compound Eyes", + "H": "Tinted Lens" + }, + "heightm": 1.1, + "weightkg": 32, + "color": "White", + "prevo": "metapod", + "evoLevel": 10, + "eggGroups": [ + "Bug" + ] + }, + "weedle": { + "num": 13, + "species": "Weedle", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 40, + "atk": 35, + "def": 30, + "spa": 20, + "spd": 20, + "spe": 50 + }, + "abilities": { + "0": "Shield Dust", + "H": "Run Away" + }, + "heightm": 0.3, + "weightkg": 3.2, + "color": "Brown", + "evos": [ + "kakuna" + ], + "eggGroups": [ + "Bug" + ] + }, + "kakuna": { + "num": 14, + "species": "Kakuna", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 45, + "atk": 25, + "def": 50, + "spa": 25, + "spd": 25, + "spe": 35 + }, + "abilities": { + "0": "Shed Skin" + }, + "heightm": 0.6, + "weightkg": 10, + "color": "Yellow", + "prevo": "weedle", + "evos": [ + "beedrill" + ], + "evoLevel": 7, + "eggGroups": [ + "Bug" + ] + }, + "beedrill": { + "num": 15, + "species": "Beedrill", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 65, + "atk": 90, + "def": 40, + "spa": 45, + "spd": 80, + "spe": 75 + }, + "abilities": { + "0": "Swarm", + "H": "Sniper" + }, + "heightm": 1, + "weightkg": 29.5, + "color": "Yellow", + "prevo": "kakuna", + "evoLevel": 10, + "eggGroups": [ + "Bug" + ], + "otherFormes": [ + "beedrillmega" + ] + }, + "beedrillmega": { + "num": 15, + "species": "Beedrill-Mega", + "baseSpecies": "Beedrill", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 65, + "atk": 150, + "def": 40, + "spa": 15, + "spd": 80, + "spe": 145 + }, + "abilities": { + "0": "Adaptability" + }, + "heightm": 1.4, + "weightkg": 40.5, + "color": "Yellow", + "eggGroups": [ + "Bug" + ] + }, + "pidgey": { + "num": 16, + "species": "Pidgey", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 45, + "def": 40, + "spa": 35, + "spd": 35, + "spe": 56 + }, + "abilities": { + "0": "Keen Eye", + "1": "Tangled Feet", + "H": "Big Pecks" + }, + "heightm": 0.3, + "weightkg": 1.8, + "color": "Brown", + "evos": [ + "pidgeotto" + ], + "eggGroups": [ + "Flying" + ] + }, + "pidgeotto": { + "num": 17, + "species": "Pidgeotto", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 63, + "atk": 60, + "def": 55, + "spa": 50, + "spd": 50, + "spe": 71 + }, + "abilities": { + "0": "Keen Eye", + "1": "Tangled Feet", + "H": "Big Pecks" + }, + "heightm": 1.1, + "weightkg": 30, + "color": "Brown", + "prevo": "pidgey", + "evos": [ + "pidgeot" + ], + "evoLevel": 18, + "eggGroups": [ + "Flying" + ] + }, + "pidgeot": { + "num": 18, + "species": "Pidgeot", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 83, + "atk": 80, + "def": 75, + "spa": 70, + "spd": 70, + "spe": 101 + }, + "abilities": { + "0": "Keen Eye", + "1": "Tangled Feet", + "H": "Big Pecks" + }, + "heightm": 1.5, + "weightkg": 39.5, + "color": "Brown", + "prevo": "pidgeotto", + "evoLevel": 36, + "eggGroups": [ + "Flying" + ], + "otherFormes": [ + "pidgeotmega" + ] + }, + "pidgeotmega": { + "num": 18, + "species": "Pidgeot-Mega", + "baseSpecies": "Pidgeot", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 83, + "atk": 80, + "def": 80, + "spa": 135, + "spd": 80, + "spe": 121 + }, + "abilities": { + "0": "No Guard" + }, + "heightm": 2.2, + "weightkg": 50.5, + "color": "Brown", + "eggGroups": [ + "Flying" + ] + }, + "rattata": { + "num": 19, + "species": "Rattata", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 30, + "atk": 56, + "def": 35, + "spa": 25, + "spd": 35, + "spe": 72 + }, + "abilities": { + "0": "Run Away", + "1": "Guts", + "H": "Hustle" + }, + "heightm": 0.3, + "weightkg": 3.5, + "color": "Purple", + "evos": [ + "raticate" + ], + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "rattataalola" + ] + }, + "rattataalola": { + "num": 19, + "species": "Rattata-Alola", + "baseSpecies": "Rattata", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Dark", + "Normal" + ], + "baseStats": { + "hp": 30, + "atk": 56, + "def": 35, + "spa": 25, + "spd": 35, + "spe": 72 + }, + "abilities": { + "0": "Gluttony", + "1": "Hustle", + "H": "Thick Fat" + }, + "heightm": 0.3, + "weightkg": 3.8, + "color": "Black", + "evos": [ + "raticatealola" + ], + "eggGroups": [ + "Field" + ] + }, + "raticate": { + "num": 20, + "species": "Raticate", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 55, + "atk": 81, + "def": 60, + "spa": 50, + "spd": 70, + "spe": 97 + }, + "abilities": { + "0": "Run Away", + "1": "Guts", + "H": "Hustle" + }, + "heightm": 0.7, + "weightkg": 18.5, + "color": "Brown", + "prevo": "rattata", + "evoLevel": 20, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "raticatealola" + ] + }, + "raticatealola": { + "num": 20, + "species": "Raticate-Alola", + "baseSpecies": "Raticate", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Dark", + "Normal" + ], + "baseStats": { + "hp": 75, + "atk": 71, + "def": 70, + "spa": 40, + "spd": 80, + "spe": 77 + }, + "abilities": { + "0": "Gluttony", + "1": "Hustle", + "H": "Thick Fat" + }, + "heightm": 0.7, + "weightkg": 25.5, + "color": "Black", + "prevo": "rattataalola", + "evoLevel": 20, + "eggGroups": [ + "Field" + ] + }, + "spearow": { + "num": 21, + "species": "Spearow", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 60, + "def": 30, + "spa": 31, + "spd": 31, + "spe": 70 + }, + "abilities": { + "0": "Keen Eye", + "H": "Sniper" + }, + "heightm": 0.3, + "weightkg": 2, + "color": "Brown", + "evos": [ + "fearow" + ], + "eggGroups": [ + "Flying" + ] + }, + "fearow": { + "num": 22, + "species": "Fearow", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 90, + "def": 65, + "spa": 61, + "spd": 61, + "spe": 100 + }, + "abilities": { + "0": "Keen Eye", + "H": "Sniper" + }, + "heightm": 1.2, + "weightkg": 38, + "color": "Brown", + "prevo": "spearow", + "evoLevel": 20, + "eggGroups": [ + "Flying" + ] + }, + "ekans": { + "num": 23, + "species": "Ekans", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 35, + "atk": 60, + "def": 44, + "spa": 40, + "spd": 54, + "spe": 55 + }, + "abilities": { + "0": "Intimidate", + "1": "Shed Skin", + "H": "Unnerve" + }, + "heightm": 2, + "weightkg": 6.9, + "color": "Purple", + "evos": [ + "arbok" + ], + "eggGroups": [ + "Field", + "Dragon" + ] + }, + "arbok": { + "num": 24, + "species": "Arbok", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 95, + "def": 69, + "spa": 65, + "spd": 79, + "spe": 80 + }, + "abilities": { + "0": "Intimidate", + "1": "Shed Skin", + "H": "Unnerve" + }, + "heightm": 3.5, + "weightkg": 65, + "color": "Purple", + "prevo": "ekans", + "evoLevel": 22, + "eggGroups": [ + "Field", + "Dragon" + ] + }, + "pikachu": { + "num": 25, + "species": "Pikachu", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Static", + "H": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "prevo": "pichu", + "evos": [ + "raichu", + "raichualola" + ], + "evoLevel": 1, + "eggGroups": [ + "Field", + "Fairy" + ], + "otherFormes": [ + "pikachucosplay", + "pikachurockstar", + "pikachubelle", + "pikachupopstar", + "pikachuphd", + "pikachulibre" + ] + }, + "pikachucosplay": { + "num": 25, + "species": "Pikachu-Cosplay", + "baseSpecies": "Pikachu", + "forme": "Cosplay", + "formeLetter": "C", + "types": [ + "Electric" + ], + "gender": "F", + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "pikachurockstar": { + "num": 25, + "species": "Pikachu-Rock-Star", + "baseSpecies": "Pikachu", + "forme": "Rock-Star", + "formeLetter": "R", + "types": [ + "Electric" + ], + "gender": "F", + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "pikachubelle": { + "num": 25, + "species": "Pikachu-Belle", + "baseSpecies": "Pikachu", + "forme": "Belle", + "formeLetter": "B", + "types": [ + "Electric" + ], + "gender": "F", + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "pikachupopstar": { + "num": 25, + "species": "Pikachu-Pop-Star", + "baseSpecies": "Pikachu", + "forme": "Pop-Star", + "formeLetter": "P", + "types": [ + "Electric" + ], + "gender": "F", + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "pikachuphd": { + "num": 25, + "species": "Pikachu-PhD", + "baseSpecies": "Pikachu", + "forme": "PhD", + "formeLetter": "D", + "types": [ + "Electric" + ], + "gender": "F", + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "pikachulibre": { + "num": 25, + "species": "Pikachu-Libre", + "baseSpecies": "Pikachu", + "forme": "Libre", + "formeLetter": "L", + "types": [ + "Electric" + ], + "gender": "F", + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "raichu": { + "num": 26, + "species": "Raichu", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 60, + "atk": 90, + "def": 55, + "spa": 90, + "spd": 80, + "spe": 110 + }, + "abilities": { + "0": "Static", + "H": "Lightning Rod" + }, + "heightm": 0.8, + "weightkg": 30, + "color": "Yellow", + "prevo": "pikachu", + "evoLevel": 1, + "eggGroups": [ + "Field", + "Fairy" + ], + "otherFormes": [ + "raichualola" + ] + }, + "raichualola": { + "num": 26, + "species": "Raichu-Alola", + "baseSpecies": "Raichu", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Electric", + "Psychic" + ], + "baseStats": { + "hp": 60, + "atk": 85, + "def": 50, + "spa": 95, + "spd": 85, + "spe": 110 + }, + "abilities": { + "0": "Surge Surfer" + }, + "heightm": 0.7, + "weightkg": 21, + "color": "Brown", + "prevo": "pikachu", + "evoLevel": 1, + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "sandshrew": { + "num": 27, + "species": "Sandshrew", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 50, + "atk": 75, + "def": 85, + "spa": 20, + "spd": 30, + "spe": 40 + }, + "abilities": { + "0": "Sand Veil", + "H": "Sand Rush" + }, + "heightm": 0.6, + "weightkg": 12, + "color": "Yellow", + "evos": [ + "sandslash" + ], + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "sandshrewalola" + ] + }, + "sandshrewalola": { + "num": 27, + "species": "Sandshrew-Alola", + "baseSpecies": "Sandshrew", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Ice", + "Steel" + ], + "baseStats": { + "hp": 50, + "atk": 75, + "def": 90, + "spa": 10, + "spd": 35, + "spe": 40 + }, + "abilities": { + "0": "Snow Cloak", + "H": "Slush Rush" + }, + "heightm": 0.7, + "weightkg": 40, + "color": "White", + "evos": [ + "sandslashalola" + ], + "eggGroups": [ + "Field" + ] + }, + "sandslash": { + "num": 28, + "species": "Sandslash", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 75, + "atk": 100, + "def": 110, + "spa": 45, + "spd": 55, + "spe": 65 + }, + "abilities": { + "0": "Sand Veil", + "H": "Sand Rush" + }, + "heightm": 1, + "weightkg": 29.5, + "color": "Yellow", + "prevo": "sandshrew", + "evoLevel": 22, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "sandslashalola" + ] + }, + "sandslashalola": { + "num": 28, + "species": "Sandslash-Alola", + "baseSpecies": "Sandslash", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Ice", + "Steel" + ], + "baseStats": { + "hp": 75, + "atk": 100, + "def": 120, + "spa": 25, + "spd": 65, + "spe": 65 + }, + "abilities": { + "0": "Snow Cloak", + "H": "Slush Rush" + }, + "heightm": 1.2, + "weightkg": 55, + "color": "Blue", + "prevo": "sandshrewalola", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "nidoranf": { + "num": 29, + "species": "Nidoran-F", + "types": [ + "Poison" + ], + "gender": "F", + "baseStats": { + "hp": 55, + "atk": 47, + "def": 52, + "spa": 40, + "spd": 40, + "spe": 41 + }, + "abilities": { + "0": "Poison Point", + "1": "Rivalry", + "H": "Hustle" + }, + "heightm": 0.4, + "weightkg": 7, + "color": "Blue", + "evos": [ + "nidorina" + ], + "eggGroups": [ + "Monster", + "Field" + ] + }, + "nidorina": { + "num": 30, + "species": "Nidorina", + "types": [ + "Poison" + ], + "gender": "F", + "baseStats": { + "hp": 70, + "atk": 62, + "def": 67, + "spa": 55, + "spd": 55, + "spe": 56 + }, + "abilities": { + "0": "Poison Point", + "1": "Rivalry", + "H": "Hustle" + }, + "heightm": 0.8, + "weightkg": 20, + "color": "Blue", + "prevo": "nidoranf", + "evos": [ + "nidoqueen" + ], + "evoLevel": 16, + "eggGroups": [ + "Undiscovered" + ] + }, + "nidoqueen": { + "num": 31, + "species": "Nidoqueen", + "types": [ + "Poison", + "Ground" + ], + "gender": "F", + "baseStats": { + "hp": 90, + "atk": 92, + "def": 87, + "spa": 75, + "spd": 85, + "spe": 76 + }, + "abilities": { + "0": "Poison Point", + "1": "Rivalry", + "H": "Sheer Force" + }, + "heightm": 1.3, + "weightkg": 60, + "color": "Blue", + "prevo": "nidorina", + "evoLevel": 16, + "eggGroups": [ + "Undiscovered" + ] + }, + "nidoranm": { + "num": 32, + "species": "Nidoran-M", + "types": [ + "Poison" + ], + "gender": "M", + "baseStats": { + "hp": 46, + "atk": 57, + "def": 40, + "spa": 40, + "spd": 40, + "spe": 50 + }, + "abilities": { + "0": "Poison Point", + "1": "Rivalry", + "H": "Hustle" + }, + "heightm": 0.5, + "weightkg": 9, + "color": "Purple", + "evos": [ + "nidorino" + ], + "eggGroups": [ + "Monster", + "Field" + ] + }, + "nidorino": { + "num": 33, + "species": "Nidorino", + "types": [ + "Poison" + ], + "gender": "M", + "baseStats": { + "hp": 61, + "atk": 72, + "def": 57, + "spa": 55, + "spd": 55, + "spe": 65 + }, + "abilities": { + "0": "Poison Point", + "1": "Rivalry", + "H": "Hustle" + }, + "heightm": 0.9, + "weightkg": 19.5, + "color": "Purple", + "prevo": "nidoranm", + "evos": [ + "nidoking" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "nidoking": { + "num": 34, + "species": "Nidoking", + "types": [ + "Poison", + "Ground" + ], + "gender": "M", + "baseStats": { + "hp": 81, + "atk": 102, + "def": 77, + "spa": 85, + "spd": 75, + "spe": 85 + }, + "abilities": { + "0": "Poison Point", + "1": "Rivalry", + "H": "Sheer Force" + }, + "heightm": 1.4, + "weightkg": 62, + "color": "Purple", + "prevo": "nidorino", + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "clefairy": { + "num": 35, + "species": "Clefairy", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 70, + "atk": 45, + "def": 48, + "spa": 60, + "spd": 65, + "spe": 35 + }, + "abilities": { + "0": "Cute Charm", + "1": "Magic Guard", + "H": "Friend Guard" + }, + "heightm": 0.6, + "weightkg": 7.5, + "color": "Pink", + "prevo": "cleffa", + "evos": [ + "clefable" + ], + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "clefable": { + "num": 36, + "species": "Clefable", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 95, + "atk": 70, + "def": 73, + "spa": 95, + "spd": 90, + "spe": 60 + }, + "abilities": { + "0": "Cute Charm", + "1": "Magic Guard", + "H": "Unaware" + }, + "heightm": 1.3, + "weightkg": 40, + "color": "Pink", + "prevo": "clefairy", + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "vulpix": { + "num": 37, + "species": "Vulpix", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 38, + "atk": 41, + "def": 40, + "spa": 50, + "spd": 65, + "spe": 65 + }, + "abilities": { + "0": "Flash Fire", + "H": "Drought" + }, + "heightm": 0.6, + "weightkg": 9.9, + "color": "Brown", + "evos": [ + "ninetales" + ], + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "vulpixalola" + ] + }, + "vulpixalola": { + "num": 37, + "species": "Vulpix-Alola", + "baseSpecies": "Vulpix", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Ice" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 38, + "atk": 41, + "def": 40, + "spa": 50, + "spd": 65, + "spe": 65 + }, + "abilities": { + "0": "Snow Cloak", + "H": "Snow Warning" + }, + "heightm": 0.6, + "weightkg": 9.9, + "color": "White", + "evos": [ + "ninetalesalola" + ], + "eggGroups": [ + "Field" + ] + }, + "ninetales": { + "num": 38, + "species": "Ninetales", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 73, + "atk": 76, + "def": 75, + "spa": 81, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Flash Fire", + "H": "Drought" + }, + "heightm": 1.1, + "weightkg": 19.9, + "color": "Yellow", + "prevo": "vulpix", + "evoLevel": 1, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "ninetalesalola" + ] + }, + "ninetalesalola": { + "num": 38, + "species": "Ninetales-Alola", + "baseSpecies": "Ninetales", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Ice", + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 73, + "atk": 67, + "def": 75, + "spa": 81, + "spd": 100, + "spe": 109 + }, + "abilities": { + "0": "Snow Cloak", + "H": "Snow Warning" + }, + "heightm": 1.1, + "weightkg": 19.9, + "color": "Blue", + "prevo": "vulpixalola", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "jigglypuff": { + "num": 39, + "species": "Jigglypuff", + "types": [ + "Normal", + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 115, + "atk": 45, + "def": 20, + "spa": 45, + "spd": 25, + "spe": 20 + }, + "abilities": { + "0": "Cute Charm", + "1": "Competitive", + "H": "Friend Guard" + }, + "heightm": 0.5, + "weightkg": 5.5, + "color": "Pink", + "prevo": "igglybuff", + "evos": [ + "wigglytuff" + ], + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "wigglytuff": { + "num": 40, + "species": "Wigglytuff", + "types": [ + "Normal", + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 140, + "atk": 70, + "def": 45, + "spa": 85, + "spd": 50, + "spe": 45 + }, + "abilities": { + "0": "Cute Charm", + "1": "Competitive", + "H": "Frisk" + }, + "heightm": 1, + "weightkg": 12, + "color": "Pink", + "prevo": "jigglypuff", + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "zubat": { + "num": 41, + "species": "Zubat", + "types": [ + "Poison", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 45, + "def": 35, + "spa": 30, + "spd": 40, + "spe": 55 + }, + "abilities": { + "0": "Inner Focus", + "H": "Infiltrator" + }, + "heightm": 0.8, + "weightkg": 7.5, + "color": "Purple", + "evos": [ + "golbat" + ], + "eggGroups": [ + "Flying" + ] + }, + "golbat": { + "num": 42, + "species": "Golbat", + "types": [ + "Poison", + "Flying" + ], + "baseStats": { + "hp": 75, + "atk": 80, + "def": 70, + "spa": 65, + "spd": 75, + "spe": 90 + }, + "abilities": { + "0": "Inner Focus", + "H": "Infiltrator" + }, + "heightm": 1.6, + "weightkg": 55, + "color": "Purple", + "prevo": "zubat", + "evos": [ + "crobat" + ], + "evoLevel": 22, + "eggGroups": [ + "Flying" + ] + }, + "oddish": { + "num": 43, + "species": "Oddish", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 45, + "atk": 50, + "def": 55, + "spa": 75, + "spd": 65, + "spe": 30 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Run Away" + }, + "heightm": 0.5, + "weightkg": 5.4, + "color": "Blue", + "evos": [ + "gloom" + ], + "eggGroups": [ + "Grass" + ] + }, + "gloom": { + "num": 44, + "species": "Gloom", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 65, + "def": 70, + "spa": 85, + "spd": 75, + "spe": 40 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Stench" + }, + "heightm": 0.8, + "weightkg": 8.6, + "color": "Blue", + "prevo": "oddish", + "evos": [ + "vileplume", + "bellossom" + ], + "evoLevel": 21, + "eggGroups": [ + "Grass" + ] + }, + "vileplume": { + "num": 45, + "species": "Vileplume", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 75, + "atk": 80, + "def": 85, + "spa": 110, + "spd": 90, + "spe": 50 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Effect Spore" + }, + "heightm": 1.2, + "weightkg": 18.6, + "color": "Red", + "prevo": "gloom", + "evoLevel": 21, + "eggGroups": [ + "Grass" + ] + }, + "paras": { + "num": 46, + "species": "Paras", + "types": [ + "Bug", + "Grass" + ], + "baseStats": { + "hp": 35, + "atk": 70, + "def": 55, + "spa": 45, + "spd": 55, + "spe": 25 + }, + "abilities": { + "0": "Effect Spore", + "1": "Dry Skin", + "H": "Damp" + }, + "heightm": 0.3, + "weightkg": 5.4, + "color": "Red", + "evos": [ + "parasect" + ], + "eggGroups": [ + "Bug", + "Grass" + ] + }, + "parasect": { + "num": 47, + "species": "Parasect", + "types": [ + "Bug", + "Grass" + ], + "baseStats": { + "hp": 60, + "atk": 95, + "def": 80, + "spa": 60, + "spd": 80, + "spe": 30 + }, + "abilities": { + "0": "Effect Spore", + "1": "Dry Skin", + "H": "Damp" + }, + "heightm": 1, + "weightkg": 29.5, + "color": "Red", + "prevo": "paras", + "evoLevel": 24, + "eggGroups": [ + "Bug", + "Grass" + ] + }, + "venonat": { + "num": 48, + "species": "Venonat", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 55, + "def": 50, + "spa": 40, + "spd": 55, + "spe": 45 + }, + "abilities": { + "0": "Compound Eyes", + "1": "Tinted Lens", + "H": "Run Away" + }, + "heightm": 1, + "weightkg": 30, + "color": "Purple", + "evos": [ + "venomoth" + ], + "eggGroups": [ + "Bug" + ] + }, + "venomoth": { + "num": 49, + "species": "Venomoth", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 70, + "atk": 65, + "def": 60, + "spa": 90, + "spd": 75, + "spe": 90 + }, + "abilities": { + "0": "Shield Dust", + "1": "Tinted Lens", + "H": "Wonder Skin" + }, + "heightm": 1.5, + "weightkg": 12.5, + "color": "Purple", + "prevo": "venonat", + "evoLevel": 31, + "eggGroups": [ + "Bug" + ] + }, + "diglett": { + "num": 50, + "species": "Diglett", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 10, + "atk": 55, + "def": 25, + "spa": 35, + "spd": 45, + "spe": 95 + }, + "abilities": { + "0": "Sand Veil", + "1": "Arena Trap", + "H": "Sand Force" + }, + "heightm": 0.2, + "weightkg": 0.8, + "color": "Brown", + "evos": [ + "dugtrio" + ], + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "diglettalola" + ] + }, + "diglettalola": { + "num": 50, + "species": "Diglett-Alola", + "baseSpecies": "Diglett", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Ground", + "Steel" + ], + "baseStats": { + "hp": 10, + "atk": 55, + "def": 30, + "spa": 35, + "spd": 45, + "spe": 90 + }, + "abilities": { + "0": "Sand Veil", + "1": "Tangling Hair", + "H": "Sand Force" + }, + "heightm": 0.2, + "weightkg": 1, + "color": "Brown", + "evos": [ + "dugtrioalola" + ], + "eggGroups": [ + "Field" + ] + }, + "dugtrio": { + "num": 51, + "species": "Dugtrio", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 35, + "atk": 100, + "def": 50, + "spa": 50, + "spd": 70, + "spe": 120 + }, + "abilities": { + "0": "Sand Veil", + "1": "Arena Trap", + "H": "Sand Force" + }, + "heightm": 0.7, + "weightkg": 33.3, + "color": "Brown", + "prevo": "diglett", + "evoLevel": 26, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "dugtrioalola" + ] + }, + "dugtrioalola": { + "num": 51, + "species": "Dugtrio-Alola", + "baseSpecies": "Dugtrio", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Ground", + "Steel" + ], + "baseStats": { + "hp": 35, + "atk": 100, + "def": 60, + "spa": 50, + "spd": 70, + "spe": 110 + }, + "abilities": { + "0": "Sand Veil", + "1": "Tangling Hair", + "H": "Sand Force" + }, + "heightm": 0.7, + "weightkg": 66.6, + "color": "Brown", + "prevo": "diglettalola", + "evoLevel": 26, + "eggGroups": [ + "Field" + ] + }, + "meowth": { + "num": 52, + "species": "Meowth", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 40, + "atk": 45, + "def": 35, + "spa": 40, + "spd": 40, + "spe": 90 + }, + "abilities": { + "0": "Pickup", + "1": "Technician", + "H": "Unnerve" + }, + "heightm": 0.4, + "weightkg": 4.2, + "color": "Yellow", + "evos": [ + "persian" + ], + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "meowthalola" + ] + }, + "meowthalola": { + "num": 52, + "species": "Meowth-Alola", + "baseSpecies": "Meowth", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 40, + "atk": 35, + "def": 35, + "spa": 50, + "spd": 40, + "spe": 90 + }, + "abilities": { + "0": "Pickup", + "1": "Technician", + "H": "Rattled" + }, + "heightm": 0.4, + "weightkg": 4.2, + "color": "Blue", + "evos": [ + "persianalola" + ], + "eggGroups": [ + "Field" + ] + }, + "persian": { + "num": 53, + "species": "Persian", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 65, + "atk": 70, + "def": 60, + "spa": 65, + "spd": 65, + "spe": 115 + }, + "abilities": { + "0": "Limber", + "1": "Technician", + "H": "Unnerve" + }, + "heightm": 1, + "weightkg": 32, + "color": "Yellow", + "prevo": "meowth", + "evoLevel": 28, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "persianalola" + ] + }, + "persianalola": { + "num": 53, + "species": "Persian-Alola", + "baseSpecies": "Persian", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 65, + "atk": 60, + "def": 60, + "spa": 75, + "spd": 65, + "spe": 115 + }, + "abilities": { + "0": "Fur Coat", + "1": "Technician", + "H": "Rattled" + }, + "heightm": 1.1, + "weightkg": 33, + "color": "Blue", + "prevo": "meowthalola", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "psyduck": { + "num": 54, + "species": "Psyduck", + "types": [ + "Water" + ], + "baseStats": { + "hp": 50, + "atk": 52, + "def": 48, + "spa": 65, + "spd": 50, + "spe": 55 + }, + "abilities": { + "0": "Damp", + "1": "Cloud Nine", + "H": "Swift Swim" + }, + "heightm": 0.8, + "weightkg": 19.6, + "color": "Yellow", + "evos": [ + "golduck" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "golduck": { + "num": 55, + "species": "Golduck", + "types": [ + "Water" + ], + "baseStats": { + "hp": 80, + "atk": 82, + "def": 78, + "spa": 95, + "spd": 80, + "spe": 85 + }, + "abilities": { + "0": "Damp", + "1": "Cloud Nine", + "H": "Swift Swim" + }, + "heightm": 1.7, + "weightkg": 76.6, + "color": "Blue", + "prevo": "psyduck", + "evoLevel": 33, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "mankey": { + "num": 56, + "species": "Mankey", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 40, + "atk": 80, + "def": 35, + "spa": 35, + "spd": 45, + "spe": 70 + }, + "abilities": { + "0": "Vital Spirit", + "1": "Anger Point", + "H": "Defiant" + }, + "heightm": 0.5, + "weightkg": 28, + "color": "Brown", + "evos": [ + "primeape" + ], + "eggGroups": [ + "Field" + ] + }, + "primeape": { + "num": 57, + "species": "Primeape", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 65, + "atk": 105, + "def": 60, + "spa": 60, + "spd": 70, + "spe": 95 + }, + "abilities": { + "0": "Vital Spirit", + "1": "Anger Point", + "H": "Defiant" + }, + "heightm": 1, + "weightkg": 32, + "color": "Brown", + "prevo": "mankey", + "evoLevel": 28, + "eggGroups": [ + "Field" + ] + }, + "growlithe": { + "num": 58, + "species": "Growlithe", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 55, + "atk": 70, + "def": 45, + "spa": 70, + "spd": 50, + "spe": 60 + }, + "abilities": { + "0": "Intimidate", + "1": "Flash Fire", + "H": "Justified" + }, + "heightm": 0.7, + "weightkg": 19, + "color": "Brown", + "evos": [ + "arcanine" + ], + "eggGroups": [ + "Field" + ] + }, + "arcanine": { + "num": 59, + "species": "Arcanine", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 90, + "atk": 110, + "def": 80, + "spa": 100, + "spd": 80, + "spe": 95 + }, + "abilities": { + "0": "Intimidate", + "1": "Flash Fire", + "H": "Justified" + }, + "heightm": 1.9, + "weightkg": 155, + "color": "Brown", + "prevo": "growlithe", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "poliwag": { + "num": 60, + "species": "Poliwag", + "types": [ + "Water" + ], + "baseStats": { + "hp": 40, + "atk": 50, + "def": 40, + "spa": 40, + "spd": 40, + "spe": 90 + }, + "abilities": { + "0": "Water Absorb", + "1": "Damp", + "H": "Swift Swim" + }, + "heightm": 0.6, + "weightkg": 12.4, + "color": "Blue", + "evos": [ + "poliwhirl" + ], + "eggGroups": [ + "Water 1" + ] + }, + "poliwhirl": { + "num": 61, + "species": "Poliwhirl", + "types": [ + "Water" + ], + "baseStats": { + "hp": 65, + "atk": 65, + "def": 65, + "spa": 50, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Water Absorb", + "1": "Damp", + "H": "Swift Swim" + }, + "heightm": 1, + "weightkg": 20, + "color": "Blue", + "prevo": "poliwag", + "evos": [ + "poliwrath", + "politoed" + ], + "evoLevel": 25, + "eggGroups": [ + "Water 1" + ] + }, + "poliwrath": { + "num": 62, + "species": "Poliwrath", + "types": [ + "Water", + "Fighting" + ], + "baseStats": { + "hp": 90, + "atk": 95, + "def": 95, + "spa": 70, + "spd": 90, + "spe": 70 + }, + "abilities": { + "0": "Water Absorb", + "1": "Damp", + "H": "Swift Swim" + }, + "heightm": 1.3, + "weightkg": 54, + "color": "Blue", + "prevo": "poliwhirl", + "evoLevel": 25, + "eggGroups": [ + "Water 1" + ] + }, + "abra": { + "num": 63, + "species": "Abra", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 25, + "atk": 20, + "def": 15, + "spa": 105, + "spd": 55, + "spe": 90 + }, + "abilities": { + "0": "Synchronize", + "1": "Inner Focus", + "H": "Magic Guard" + }, + "heightm": 0.9, + "weightkg": 19.5, + "color": "Brown", + "evos": [ + "kadabra" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "kadabra": { + "num": 64, + "species": "Kadabra", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 40, + "atk": 35, + "def": 30, + "spa": 120, + "spd": 70, + "spe": 105 + }, + "abilities": { + "0": "Synchronize", + "1": "Inner Focus", + "H": "Magic Guard" + }, + "heightm": 1.3, + "weightkg": 56.5, + "color": "Brown", + "prevo": "abra", + "evos": [ + "alakazam" + ], + "evoLevel": 16, + "eggGroups": [ + "Human-Like" + ] + }, + "alakazam": { + "num": 65, + "species": "Alakazam", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 55, + "atk": 50, + "def": 45, + "spa": 135, + "spd": 95, + "spe": 120 + }, + "abilities": { + "0": "Synchronize", + "1": "Inner Focus", + "H": "Magic Guard" + }, + "heightm": 1.5, + "weightkg": 48, + "color": "Brown", + "prevo": "kadabra", + "evoLevel": 16, + "eggGroups": [ + "Human-Like" + ], + "otherFormes": [ + "alakazammega" + ] + }, + "alakazammega": { + "num": 65, + "species": "Alakazam-Mega", + "baseSpecies": "Alakazam", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 55, + "atk": 50, + "def": 65, + "spa": 175, + "spd": 105, + "spe": 150 + }, + "abilities": { + "0": "Trace" + }, + "heightm": 1.2, + "weightkg": 48, + "color": "Brown", + "eggGroups": [ + "Human-Like" + ] + }, + "machop": { + "num": 66, + "species": "Machop", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 70, + "atk": 80, + "def": 50, + "spa": 35, + "spd": 35, + "spe": 35 + }, + "abilities": { + "0": "Guts", + "1": "No Guard", + "H": "Steadfast" + }, + "heightm": 0.8, + "weightkg": 19.5, + "color": "Gray", + "evos": [ + "machoke" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "machoke": { + "num": 67, + "species": "Machoke", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 80, + "atk": 100, + "def": 70, + "spa": 50, + "spd": 60, + "spe": 45 + }, + "abilities": { + "0": "Guts", + "1": "No Guard", + "H": "Steadfast" + }, + "heightm": 1.5, + "weightkg": 70.5, + "color": "Gray", + "prevo": "machop", + "evos": [ + "machamp" + ], + "evoLevel": 28, + "eggGroups": [ + "Human-Like" + ] + }, + "machamp": { + "num": 68, + "species": "Machamp", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 90, + "atk": 130, + "def": 80, + "spa": 65, + "spd": 85, + "spe": 55 + }, + "abilities": { + "0": "Guts", + "1": "No Guard", + "H": "Steadfast" + }, + "heightm": 1.6, + "weightkg": 130, + "color": "Gray", + "prevo": "machoke", + "evoLevel": 28, + "eggGroups": [ + "Human-Like" + ] + }, + "bellsprout": { + "num": 69, + "species": "Bellsprout", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 50, + "atk": 75, + "def": 35, + "spa": 70, + "spd": 30, + "spe": 40 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Gluttony" + }, + "heightm": 0.7, + "weightkg": 4, + "color": "Green", + "evos": [ + "weepinbell" + ], + "eggGroups": [ + "Grass" + ] + }, + "weepinbell": { + "num": 70, + "species": "Weepinbell", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 65, + "atk": 90, + "def": 50, + "spa": 85, + "spd": 45, + "spe": 55 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Gluttony" + }, + "heightm": 1, + "weightkg": 6.4, + "color": "Green", + "prevo": "bellsprout", + "evos": [ + "victreebel" + ], + "evoLevel": 21, + "eggGroups": [ + "Grass" + ] + }, + "victreebel": { + "num": 71, + "species": "Victreebel", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 80, + "atk": 105, + "def": 65, + "spa": 100, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Gluttony" + }, + "heightm": 1.7, + "weightkg": 15.5, + "color": "Green", + "prevo": "weepinbell", + "evoLevel": 21, + "eggGroups": [ + "Grass" + ] + }, + "tentacool": { + "num": 72, + "species": "Tentacool", + "types": [ + "Water", + "Poison" + ], + "baseStats": { + "hp": 40, + "atk": 40, + "def": 35, + "spa": 50, + "spd": 100, + "spe": 70 + }, + "abilities": { + "0": "Clear Body", + "1": "Liquid Ooze", + "H": "Rain Dish" + }, + "heightm": 0.9, + "weightkg": 45.5, + "color": "Blue", + "evos": [ + "tentacruel" + ], + "eggGroups": [ + "Water 3" + ] + }, + "tentacruel": { + "num": 73, + "species": "Tentacruel", + "types": [ + "Water", + "Poison" + ], + "baseStats": { + "hp": 80, + "atk": 70, + "def": 65, + "spa": 80, + "spd": 120, + "spe": 100 + }, + "abilities": { + "0": "Clear Body", + "1": "Liquid Ooze", + "H": "Rain Dish" + }, + "heightm": 1.6, + "weightkg": 55, + "color": "Blue", + "prevo": "tentacool", + "evoLevel": 30, + "eggGroups": [ + "Water 3" + ] + }, + "geodude": { + "num": 74, + "species": "Geodude", + "types": [ + "Rock", + "Ground" + ], + "baseStats": { + "hp": 40, + "atk": 80, + "def": 100, + "spa": 30, + "spd": 30, + "spe": 20 + }, + "abilities": { + "0": "Rock Head", + "1": "Sturdy", + "H": "Sand Veil" + }, + "heightm": 0.4, + "weightkg": 20, + "color": "Brown", + "evos": [ + "graveler" + ], + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "geodudealola" + ] + }, + "geodudealola": { + "num": 74, + "species": "Geodude-Alola", + "baseSpecies": "Geodude", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Rock", + "Electric" + ], + "baseStats": { + "hp": 40, + "atk": 80, + "def": 100, + "spa": 30, + "spd": 30, + "spe": 20 + }, + "abilities": { + "0": "Magnet Pull", + "1": "Sturdy", + "H": "Galvanize" + }, + "heightm": 0.4, + "weightkg": 20.3, + "color": "Gray", + "evos": [ + "graveleralola" + ], + "eggGroups": [ + "Mineral" + ] + }, + "graveler": { + "num": 75, + "species": "Graveler", + "types": [ + "Rock", + "Ground" + ], + "baseStats": { + "hp": 55, + "atk": 95, + "def": 115, + "spa": 45, + "spd": 45, + "spe": 35 + }, + "abilities": { + "0": "Rock Head", + "1": "Sturdy", + "H": "Sand Veil" + }, + "heightm": 1, + "weightkg": 105, + "color": "Brown", + "prevo": "geodude", + "evos": [ + "golem" + ], + "evoLevel": 25, + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "graveleralola" + ] + }, + "graveleralola": { + "num": 75, + "species": "Graveler-Alola", + "baseSpecies": "Graveler", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Rock", + "Electric" + ], + "baseStats": { + "hp": 55, + "atk": 95, + "def": 115, + "spa": 45, + "spd": 45, + "spe": 35 + }, + "abilities": { + "0": "Magnet Pull", + "1": "Sturdy", + "H": "Galvanize" + }, + "heightm": 1, + "weightkg": 110, + "color": "Gray", + "prevo": "geodudealola", + "evos": [ + "golemalola" + ], + "evoLevel": 25, + "eggGroups": [ + "Mineral" + ] + }, + "golem": { + "num": 76, + "species": "Golem", + "types": [ + "Rock", + "Ground" + ], + "baseStats": { + "hp": 80, + "atk": 120, + "def": 130, + "spa": 55, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Rock Head", + "1": "Sturdy", + "H": "Sand Veil" + }, + "heightm": 1.4, + "weightkg": 300, + "color": "Brown", + "prevo": "graveler", + "evoLevel": 25, + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "golemalola" + ] + }, + "golemalola": { + "num": 76, + "species": "Golem-Alola", + "baseSpecies": "Golem", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Rock", + "Electric" + ], + "baseStats": { + "hp": 80, + "atk": 120, + "def": 130, + "spa": 55, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Magnet Pull", + "1": "Sturdy", + "H": "Galvanize" + }, + "heightm": 1.7, + "weightkg": 316, + "color": "Gray", + "prevo": "graveleralola", + "evoLevel": 25, + "eggGroups": [ + "Mineral" + ] + }, + "ponyta": { + "num": 77, + "species": "Ponyta", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 50, + "atk": 85, + "def": 55, + "spa": 65, + "spd": 65, + "spe": 90 + }, + "abilities": { + "0": "Run Away", + "1": "Flash Fire", + "H": "Flame Body" + }, + "heightm": 1, + "weightkg": 30, + "color": "Yellow", + "evos": [ + "rapidash" + ], + "eggGroups": [ + "Field" + ] + }, + "rapidash": { + "num": 78, + "species": "Rapidash", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 65, + "atk": 100, + "def": 70, + "spa": 80, + "spd": 80, + "spe": 105 + }, + "abilities": { + "0": "Run Away", + "1": "Flash Fire", + "H": "Flame Body" + }, + "heightm": 1.7, + "weightkg": 95, + "color": "Yellow", + "prevo": "ponyta", + "evoLevel": 40, + "eggGroups": [ + "Field" + ] + }, + "slowpoke": { + "num": 79, + "species": "Slowpoke", + "types": [ + "Water", + "Psychic" + ], + "baseStats": { + "hp": 90, + "atk": 65, + "def": 65, + "spa": 40, + "spd": 40, + "spe": 15 + }, + "abilities": { + "0": "Oblivious", + "1": "Own Tempo", + "H": "Regenerator" + }, + "heightm": 1.2, + "weightkg": 36, + "color": "Pink", + "evos": [ + "slowbro", + "slowking" + ], + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "slowbro": { + "num": 80, + "species": "Slowbro", + "types": [ + "Water", + "Psychic" + ], + "baseStats": { + "hp": 95, + "atk": 75, + "def": 110, + "spa": 100, + "spd": 80, + "spe": 30 + }, + "abilities": { + "0": "Oblivious", + "1": "Own Tempo", + "H": "Regenerator" + }, + "heightm": 1.6, + "weightkg": 78.5, + "color": "Pink", + "prevo": "slowpoke", + "evoLevel": 37, + "eggGroups": [ + "Monster", + "Water 1" + ], + "otherFormes": [ + "slowbromega" + ] + }, + "slowbromega": { + "num": 80, + "species": "Slowbro-Mega", + "baseSpecies": "Slowbro", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Water", + "Psychic" + ], + "baseStats": { + "hp": 95, + "atk": 75, + "def": 180, + "spa": 130, + "spd": 80, + "spe": 30 + }, + "abilities": { + "0": "Shell Armor" + }, + "heightm": 2, + "weightkg": 120, + "color": "Pink", + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "magnemite": { + "num": 81, + "species": "Magnemite", + "types": [ + "Electric", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 25, + "atk": 35, + "def": 70, + "spa": 95, + "spd": 55, + "spe": 45 + }, + "abilities": { + "0": "Magnet Pull", + "1": "Sturdy", + "H": "Analytic" + }, + "heightm": 0.3, + "weightkg": 6, + "color": "Gray", + "evos": [ + "magneton" + ], + "eggGroups": [ + "Mineral" + ] + }, + "magneton": { + "num": 82, + "species": "Magneton", + "types": [ + "Electric", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 60, + "def": 95, + "spa": 120, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Magnet Pull", + "1": "Sturdy", + "H": "Analytic" + }, + "heightm": 1, + "weightkg": 60, + "color": "Gray", + "prevo": "magnemite", + "evos": [ + "magnezone" + ], + "evoLevel": 30, + "eggGroups": [ + "Mineral" + ] + }, + "farfetchd": { + "num": 83, + "species": "Farfetch'd", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 52, + "atk": 90, + "def": 55, + "spa": 58, + "spd": 62, + "spe": 60 + }, + "abilities": { + "0": "Keen Eye", + "1": "Inner Focus", + "H": "Defiant" + }, + "heightm": 0.8, + "weightkg": 15, + "color": "Brown", + "eggGroups": [ + "Flying", + "Field" + ] + }, + "doduo": { + "num": 84, + "species": "Doduo", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 35, + "atk": 85, + "def": 45, + "spa": 35, + "spd": 35, + "spe": 75 + }, + "abilities": { + "0": "Run Away", + "1": "Early Bird", + "H": "Tangled Feet" + }, + "heightm": 1.4, + "weightkg": 39.2, + "color": "Brown", + "evos": [ + "dodrio" + ], + "eggGroups": [ + "Flying" + ] + }, + "dodrio": { + "num": 85, + "species": "Dodrio", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 110, + "def": 70, + "spa": 60, + "spd": 60, + "spe": 110 + }, + "abilities": { + "0": "Run Away", + "1": "Early Bird", + "H": "Tangled Feet" + }, + "heightm": 1.8, + "weightkg": 85.2, + "color": "Brown", + "prevo": "doduo", + "evoLevel": 31, + "eggGroups": [ + "Flying" + ] + }, + "seel": { + "num": 86, + "species": "Seel", + "types": [ + "Water" + ], + "baseStats": { + "hp": 65, + "atk": 45, + "def": 55, + "spa": 45, + "spd": 70, + "spe": 45 + }, + "abilities": { + "0": "Thick Fat", + "1": "Hydration", + "H": "Ice Body" + }, + "heightm": 1.1, + "weightkg": 90, + "color": "White", + "evos": [ + "dewgong" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "dewgong": { + "num": 87, + "species": "Dewgong", + "types": [ + "Water", + "Ice" + ], + "baseStats": { + "hp": 90, + "atk": 70, + "def": 80, + "spa": 70, + "spd": 95, + "spe": 70 + }, + "abilities": { + "0": "Thick Fat", + "1": "Hydration", + "H": "Ice Body" + }, + "heightm": 1.7, + "weightkg": 120, + "color": "White", + "prevo": "seel", + "evoLevel": 34, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "grimer": { + "num": 88, + "species": "Grimer", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 80, + "atk": 80, + "def": 50, + "spa": 40, + "spd": 50, + "spe": 25 + }, + "abilities": { + "0": "Stench", + "1": "Sticky Hold", + "H": "Poison Touch" + }, + "heightm": 0.9, + "weightkg": 30, + "color": "Purple", + "evos": [ + "muk" + ], + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "grimeralola" + ] + }, + "grimeralola": { + "num": 88, + "species": "Grimer-Alola", + "baseSpecies": "Grimer", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Poison", + "Dark" + ], + "baseStats": { + "hp": 80, + "atk": 80, + "def": 50, + "spa": 40, + "spd": 50, + "spe": 25 + }, + "abilities": { + "0": "Poison Touch", + "1": "Gluttony", + "H": "Power of Alchemy" + }, + "heightm": 0.7, + "weightkg": 42, + "color": "Green", + "evos": [ + "mukalola" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "muk": { + "num": 89, + "species": "Muk", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 105, + "atk": 105, + "def": 75, + "spa": 65, + "spd": 100, + "spe": 50 + }, + "abilities": { + "0": "Stench", + "1": "Sticky Hold", + "H": "Poison Touch" + }, + "heightm": 1.2, + "weightkg": 30, + "color": "Purple", + "prevo": "grimer", + "evoLevel": 38, + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "mukalola" + ] + }, + "mukalola": { + "num": 89, + "species": "Muk-Alola", + "baseSpecies": "Muk", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Poison", + "Dark" + ], + "baseStats": { + "hp": 105, + "atk": 105, + "def": 75, + "spa": 65, + "spd": 100, + "spe": 50 + }, + "abilities": { + "0": "Poison Touch", + "1": "Gluttony", + "H": "Power of Alchemy" + }, + "heightm": 1, + "weightkg": 52, + "color": "Green", + "prevo": "grimeralola", + "evoLevel": 38, + "eggGroups": [ + "Amorphous" + ] + }, + "shellder": { + "num": 90, + "species": "Shellder", + "types": [ + "Water" + ], + "baseStats": { + "hp": 30, + "atk": 65, + "def": 100, + "spa": 45, + "spd": 25, + "spe": 40 + }, + "abilities": { + "0": "Shell Armor", + "1": "Skill Link", + "H": "Overcoat" + }, + "heightm": 0.3, + "weightkg": 4, + "color": "Purple", + "evos": [ + "cloyster" + ], + "eggGroups": [ + "Water 3" + ] + }, + "cloyster": { + "num": 91, + "species": "Cloyster", + "types": [ + "Water", + "Ice" + ], + "baseStats": { + "hp": 50, + "atk": 95, + "def": 180, + "spa": 85, + "spd": 45, + "spe": 70 + }, + "abilities": { + "0": "Shell Armor", + "1": "Skill Link", + "H": "Overcoat" + }, + "heightm": 1.5, + "weightkg": 132.5, + "color": "Purple", + "prevo": "shellder", + "evoLevel": 1, + "eggGroups": [ + "Water 3" + ] + }, + "gastly": { + "num": 92, + "species": "Gastly", + "types": [ + "Ghost", + "Poison" + ], + "baseStats": { + "hp": 30, + "atk": 35, + "def": 30, + "spa": 100, + "spd": 35, + "spe": 80 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.3, + "weightkg": 0.1, + "color": "Purple", + "evos": [ + "haunter" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "haunter": { + "num": 93, + "species": "Haunter", + "types": [ + "Ghost", + "Poison" + ], + "baseStats": { + "hp": 45, + "atk": 50, + "def": 45, + "spa": 115, + "spd": 55, + "spe": 95 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.6, + "weightkg": 0.1, + "color": "Purple", + "prevo": "gastly", + "evos": [ + "gengar" + ], + "evoLevel": 25, + "eggGroups": [ + "Amorphous" + ] + }, + "gengar": { + "num": 94, + "species": "Gengar", + "types": [ + "Ghost", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 65, + "def": 60, + "spa": 130, + "spd": 75, + "spe": 110 + }, + "abilities": { + "0": "Cursed Body" + }, + "heightm": 1.5, + "weightkg": 40.5, + "color": "Purple", + "prevo": "haunter", + "evoLevel": 25, + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "gengarmega" + ] + }, + "gengarmega": { + "num": 94, + "species": "Gengar-Mega", + "baseSpecies": "Gengar", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Ghost", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 65, + "def": 80, + "spa": 170, + "spd": 95, + "spe": 130 + }, + "abilities": { + "0": "Shadow Tag" + }, + "heightm": 1.4, + "weightkg": 40.5, + "color": "Purple", + "eggGroups": [ + "Amorphous" + ] + }, + "onix": { + "num": 95, + "species": "Onix", + "types": [ + "Rock", + "Ground" + ], + "baseStats": { + "hp": 35, + "atk": 45, + "def": 160, + "spa": 30, + "spd": 45, + "spe": 70 + }, + "abilities": { + "0": "Rock Head", + "1": "Sturdy", + "H": "Weak Armor" + }, + "heightm": 8.8, + "weightkg": 210, + "color": "Gray", + "evos": [ + "steelix" + ], + "eggGroups": [ + "Mineral" + ] + }, + "drowzee": { + "num": 96, + "species": "Drowzee", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 60, + "atk": 48, + "def": 45, + "spa": 43, + "spd": 90, + "spe": 42 + }, + "abilities": { + "0": "Insomnia", + "1": "Forewarn", + "H": "Inner Focus" + }, + "heightm": 1, + "weightkg": 32.4, + "color": "Yellow", + "evos": [ + "hypno" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "hypno": { + "num": 97, + "species": "Hypno", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 85, + "atk": 73, + "def": 70, + "spa": 73, + "spd": 115, + "spe": 67 + }, + "abilities": { + "0": "Insomnia", + "1": "Forewarn", + "H": "Inner Focus" + }, + "heightm": 1.6, + "weightkg": 75.6, + "color": "Yellow", + "prevo": "drowzee", + "evoLevel": 26, + "eggGroups": [ + "Human-Like" + ] + }, + "krabby": { + "num": 98, + "species": "Krabby", + "types": [ + "Water" + ], + "baseStats": { + "hp": 30, + "atk": 105, + "def": 90, + "spa": 25, + "spd": 25, + "spe": 50 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Shell Armor", + "H": "Sheer Force" + }, + "heightm": 0.4, + "weightkg": 6.5, + "color": "Red", + "evos": [ + "kingler" + ], + "eggGroups": [ + "Water 3" + ] + }, + "kingler": { + "num": 99, + "species": "Kingler", + "types": [ + "Water" + ], + "baseStats": { + "hp": 55, + "atk": 130, + "def": 115, + "spa": 50, + "spd": 50, + "spe": 75 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Shell Armor", + "H": "Sheer Force" + }, + "heightm": 1.3, + "weightkg": 60, + "color": "Red", + "prevo": "krabby", + "evoLevel": 28, + "eggGroups": [ + "Water 3" + ] + }, + "voltorb": { + "num": 100, + "species": "Voltorb", + "types": [ + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 40, + "atk": 30, + "def": 50, + "spa": 55, + "spd": 55, + "spe": 100 + }, + "abilities": { + "0": "Soundproof", + "1": "Static", + "H": "Aftermath" + }, + "heightm": 0.5, + "weightkg": 10.4, + "color": "Red", + "evos": [ + "electrode" + ], + "eggGroups": [ + "Mineral" + ] + }, + "electrode": { + "num": 101, + "species": "Electrode", + "types": [ + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 50, + "def": 70, + "spa": 80, + "spd": 80, + "spe": 150 + }, + "abilities": { + "0": "Soundproof", + "1": "Static", + "H": "Aftermath" + }, + "heightm": 1.2, + "weightkg": 66.6, + "color": "Red", + "prevo": "voltorb", + "evoLevel": 30, + "eggGroups": [ + "Mineral" + ] + }, + "exeggcute": { + "num": 102, + "species": "Exeggcute", + "types": [ + "Grass", + "Psychic" + ], + "baseStats": { + "hp": 60, + "atk": 40, + "def": 80, + "spa": 60, + "spd": 45, + "spe": 40 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Harvest" + }, + "heightm": 0.4, + "weightkg": 2.5, + "color": "Pink", + "evos": [ + "exeggutor", + "exeggutoralola" + ], + "eggGroups": [ + "Grass" + ] + }, + "exeggutor": { + "num": 103, + "species": "Exeggutor", + "types": [ + "Grass", + "Psychic" + ], + "baseStats": { + "hp": 95, + "atk": 95, + "def": 85, + "spa": 125, + "spd": 75, + "spe": 55 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Harvest" + }, + "heightm": 2, + "weightkg": 120, + "color": "Yellow", + "prevo": "exeggcute", + "evoLevel": 1, + "eggGroups": [ + "Grass" + ], + "otherFormes": [ + "exeggutoralola" + ] + }, + "exeggutoralola": { + "num": 103, + "species": "Exeggutor-Alola", + "baseSpecies": "Exeggutor", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Grass", + "Dragon" + ], + "baseStats": { + "hp": 95, + "atk": 105, + "def": 85, + "spa": 125, + "spd": 75, + "spe": 45 + }, + "abilities": { + "0": "Frisk", + "H": "Harvest" + }, + "heightm": 10.9, + "weightkg": 415.6, + "color": "Yellow", + "prevo": "exeggcute", + "evoLevel": 1, + "eggGroups": [ + "Grass" + ] + }, + "cubone": { + "num": 104, + "species": "Cubone", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 50, + "atk": 50, + "def": 95, + "spa": 40, + "spd": 50, + "spe": 35 + }, + "abilities": { + "0": "Rock Head", + "1": "Lightning Rod", + "H": "Battle Armor" + }, + "heightm": 0.4, + "weightkg": 6.5, + "color": "Brown", + "evos": [ + "marowak", + "marowakalola" + ], + "eggGroups": [ + "Monster" + ] + }, + "marowak": { + "num": 105, + "species": "Marowak", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 60, + "atk": 80, + "def": 110, + "spa": 50, + "spd": 80, + "spe": 45 + }, + "abilities": { + "0": "Rock Head", + "1": "Lightning Rod", + "H": "Battle Armor" + }, + "heightm": 1, + "weightkg": 45, + "color": "Brown", + "prevo": "cubone", + "evoLevel": 28, + "eggGroups": [ + "Monster" + ], + "otherFormes": [ + "marowakalola" + ] + }, + "marowakalola": { + "num": 105, + "species": "Marowak-Alola", + "baseSpecies": "Marowak", + "forme": "Alola", + "formeLetter": "A", + "types": [ + "Fire", + "Ghost" + ], + "baseStats": { + "hp": 60, + "atk": 80, + "def": 110, + "spa": 50, + "spd": 80, + "spe": 45 + }, + "abilities": { + "0": "Cursed Body", + "1": "Lightning Rod", + "H": "Rock Head" + }, + "heightm": 1, + "weightkg": 34, + "color": "Purple", + "prevo": "cubone", + "evoLevel": 28, + "eggGroups": [ + "Monster" + ] + }, + "hitmonlee": { + "num": 106, + "species": "Hitmonlee", + "types": [ + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 50, + "atk": 120, + "def": 53, + "spa": 35, + "spd": 110, + "spe": 87 + }, + "abilities": { + "0": "Limber", + "1": "Reckless", + "H": "Unburden" + }, + "heightm": 1.5, + "weightkg": 49.8, + "color": "Brown", + "prevo": "tyrogue", + "evoLevel": 20, + "eggGroups": [ + "Human-Like" + ] + }, + "hitmonchan": { + "num": 107, + "species": "Hitmonchan", + "types": [ + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 50, + "atk": 105, + "def": 79, + "spa": 35, + "spd": 110, + "spe": 76 + }, + "abilities": { + "0": "Keen Eye", + "1": "Iron Fist", + "H": "Inner Focus" + }, + "heightm": 1.4, + "weightkg": 50.2, + "color": "Brown", + "prevo": "tyrogue", + "evoLevel": 20, + "eggGroups": [ + "Human-Like" + ] + }, + "lickitung": { + "num": 108, + "species": "Lickitung", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 90, + "atk": 55, + "def": 75, + "spa": 60, + "spd": 75, + "spe": 30 + }, + "abilities": { + "0": "Own Tempo", + "1": "Oblivious", + "H": "Cloud Nine" + }, + "heightm": 1.2, + "weightkg": 65.5, + "color": "Pink", + "evos": [ + "lickilicky" + ], + "eggGroups": [ + "Monster" + ] + }, + "koffing": { + "num": 109, + "species": "Koffing", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 40, + "atk": 65, + "def": 95, + "spa": 60, + "spd": 45, + "spe": 35 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.6, + "weightkg": 1, + "color": "Purple", + "evos": [ + "weezing" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "weezing": { + "num": 110, + "species": "Weezing", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 65, + "atk": 90, + "def": 120, + "spa": 85, + "spd": 70, + "spe": 60 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.2, + "weightkg": 9.5, + "color": "Purple", + "prevo": "koffing", + "evoLevel": 35, + "eggGroups": [ + "Amorphous" + ] + }, + "rhyhorn": { + "num": 111, + "species": "Rhyhorn", + "types": [ + "Ground", + "Rock" + ], + "baseStats": { + "hp": 80, + "atk": 85, + "def": 95, + "spa": 30, + "spd": 30, + "spe": 25 + }, + "abilities": { + "0": "Lightning Rod", + "1": "Rock Head", + "H": "Reckless" + }, + "heightm": 1, + "weightkg": 115, + "color": "Gray", + "evos": [ + "rhydon" + ], + "eggGroups": [ + "Monster", + "Field" + ] + }, + "rhydon": { + "num": 112, + "species": "Rhydon", + "types": [ + "Ground", + "Rock" + ], + "baseStats": { + "hp": 105, + "atk": 130, + "def": 120, + "spa": 45, + "spd": 45, + "spe": 40 + }, + "abilities": { + "0": "Lightning Rod", + "1": "Rock Head", + "H": "Reckless" + }, + "heightm": 1.9, + "weightkg": 120, + "color": "Gray", + "prevo": "rhyhorn", + "evos": [ + "rhyperior" + ], + "evoLevel": 42, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "chansey": { + "num": 113, + "species": "Chansey", + "types": [ + "Normal" + ], + "gender": "F", + "baseStats": { + "hp": 250, + "atk": 5, + "def": 5, + "spa": 35, + "spd": 105, + "spe": 50 + }, + "abilities": { + "0": "Natural Cure", + "1": "Serene Grace", + "H": "Healer" + }, + "heightm": 1.1, + "weightkg": 34.6, + "color": "Pink", + "prevo": "happiny", + "evos": [ + "blissey" + ], + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "tangela": { + "num": 114, + "species": "Tangela", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 65, + "atk": 55, + "def": 115, + "spa": 100, + "spd": 40, + "spe": 60 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Leaf Guard", + "H": "Regenerator" + }, + "heightm": 1, + "weightkg": 35, + "color": "Blue", + "evos": [ + "tangrowth" + ], + "eggGroups": [ + "Grass" + ] + }, + "kangaskhan": { + "num": 115, + "species": "Kangaskhan", + "types": [ + "Normal" + ], + "gender": "F", + "baseStats": { + "hp": 105, + "atk": 95, + "def": 80, + "spa": 40, + "spd": 80, + "spe": 90 + }, + "abilities": { + "0": "Early Bird", + "1": "Scrappy", + "H": "Inner Focus" + }, + "heightm": 2.2, + "weightkg": 80, + "color": "Brown", + "eggGroups": [ + "Monster" + ], + "otherFormes": [ + "kangaskhanmega" + ] + }, + "kangaskhanmega": { + "num": 115, + "species": "Kangaskhan-Mega", + "baseSpecies": "Kangaskhan", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Normal" + ], + "gender": "F", + "baseStats": { + "hp": 105, + "atk": 125, + "def": 100, + "spa": 60, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Parental Bond" + }, + "heightm": 2.2, + "weightkg": 100, + "color": "Brown", + "eggGroups": [ + "Monster" + ] + }, + "horsea": { + "num": 116, + "species": "Horsea", + "types": [ + "Water" + ], + "baseStats": { + "hp": 30, + "atk": 40, + "def": 70, + "spa": 70, + "spd": 25, + "spe": 60 + }, + "abilities": { + "0": "Swift Swim", + "1": "Sniper", + "H": "Damp" + }, + "heightm": 0.4, + "weightkg": 8, + "color": "Blue", + "evos": [ + "seadra" + ], + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "seadra": { + "num": 117, + "species": "Seadra", + "types": [ + "Water" + ], + "baseStats": { + "hp": 55, + "atk": 65, + "def": 95, + "spa": 95, + "spd": 45, + "spe": 85 + }, + "abilities": { + "0": "Poison Point", + "1": "Sniper", + "H": "Damp" + }, + "heightm": 1.2, + "weightkg": 25, + "color": "Blue", + "prevo": "horsea", + "evos": [ + "kingdra" + ], + "evoLevel": 32, + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "goldeen": { + "num": 118, + "species": "Goldeen", + "types": [ + "Water" + ], + "baseStats": { + "hp": 45, + "atk": 67, + "def": 60, + "spa": 35, + "spd": 50, + "spe": 63 + }, + "abilities": { + "0": "Swift Swim", + "1": "Water Veil", + "H": "Lightning Rod" + }, + "heightm": 0.6, + "weightkg": 15, + "color": "Red", + "evos": [ + "seaking" + ], + "eggGroups": [ + "Water 2" + ] + }, + "seaking": { + "num": 119, + "species": "Seaking", + "types": [ + "Water" + ], + "baseStats": { + "hp": 80, + "atk": 92, + "def": 65, + "spa": 65, + "spd": 80, + "spe": 68 + }, + "abilities": { + "0": "Swift Swim", + "1": "Water Veil", + "H": "Lightning Rod" + }, + "heightm": 1.3, + "weightkg": 39, + "color": "Red", + "prevo": "goldeen", + "evoLevel": 33, + "eggGroups": [ + "Water 2" + ] + }, + "staryu": { + "num": 120, + "species": "Staryu", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 30, + "atk": 45, + "def": 55, + "spa": 70, + "spd": 55, + "spe": 85 + }, + "abilities": { + "0": "Illuminate", + "1": "Natural Cure", + "H": "Analytic" + }, + "heightm": 0.8, + "weightkg": 34.5, + "color": "Brown", + "evos": [ + "starmie" + ], + "eggGroups": [ + "Water 3" + ] + }, + "starmie": { + "num": 121, + "species": "Starmie", + "types": [ + "Water", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 75, + "def": 85, + "spa": 100, + "spd": 85, + "spe": 115 + }, + "abilities": { + "0": "Illuminate", + "1": "Natural Cure", + "H": "Analytic" + }, + "heightm": 1.1, + "weightkg": 80, + "color": "Purple", + "prevo": "staryu", + "evoLevel": 1, + "eggGroups": [ + "Water 3" + ] + }, + "mrmime": { + "num": 122, + "species": "Mr. Mime", + "types": [ + "Psychic", + "Fairy" + ], + "baseStats": { + "hp": 40, + "atk": 45, + "def": 65, + "spa": 100, + "spd": 120, + "spe": 90 + }, + "abilities": { + "0": "Soundproof", + "1": "Filter", + "H": "Technician" + }, + "heightm": 1.3, + "weightkg": 54.5, + "color": "Pink", + "prevo": "mimejr", + "evoLevel": 1, + "evoMove": "Mimic", + "eggGroups": [ + "Human-Like" + ] + }, + "scyther": { + "num": 123, + "species": "Scyther", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 70, + "atk": 110, + "def": 80, + "spa": 55, + "spd": 80, + "spe": 105 + }, + "abilities": { + "0": "Swarm", + "1": "Technician", + "H": "Steadfast" + }, + "heightm": 1.5, + "weightkg": 56, + "color": "Green", + "evos": [ + "scizor" + ], + "eggGroups": [ + "Bug" + ] + }, + "jynx": { + "num": 124, + "species": "Jynx", + "types": [ + "Ice", + "Psychic" + ], + "gender": "F", + "baseStats": { + "hp": 65, + "atk": 50, + "def": 35, + "spa": 115, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "Oblivious", + "1": "Forewarn", + "H": "Dry Skin" + }, + "heightm": 1.4, + "weightkg": 40.6, + "color": "Red", + "prevo": "smoochum", + "evoLevel": 30, + "eggGroups": [ + "Human-Like" + ] + }, + "electabuzz": { + "num": 125, + "species": "Electabuzz", + "types": [ + "Electric" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 65, + "atk": 83, + "def": 57, + "spa": 95, + "spd": 85, + "spe": 105 + }, + "abilities": { + "0": "Static", + "H": "Vital Spirit" + }, + "heightm": 1.1, + "weightkg": 30, + "color": "Yellow", + "prevo": "elekid", + "evos": [ + "electivire" + ], + "evoLevel": 30, + "eggGroups": [ + "Human-Like" + ] + }, + "magmar": { + "num": 126, + "species": "Magmar", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 65, + "atk": 95, + "def": 57, + "spa": 100, + "spd": 85, + "spe": 93 + }, + "abilities": { + "0": "Flame Body", + "H": "Vital Spirit" + }, + "heightm": 1.3, + "weightkg": 44.5, + "color": "Red", + "prevo": "magby", + "evos": [ + "magmortar" + ], + "evoLevel": 30, + "eggGroups": [ + "Human-Like" + ] + }, + "pinsir": { + "num": 127, + "species": "Pinsir", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 65, + "atk": 125, + "def": 100, + "spa": 55, + "spd": 70, + "spe": 85 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Mold Breaker", + "H": "Moxie" + }, + "heightm": 1.5, + "weightkg": 55, + "color": "Brown", + "eggGroups": [ + "Bug" + ], + "otherFormes": [ + "pinsirmega" + ] + }, + "pinsirmega": { + "num": 127, + "species": "Pinsir-Mega", + "baseSpecies": "Pinsir", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 155, + "def": 120, + "spa": 65, + "spd": 90, + "spe": 105 + }, + "abilities": { + "0": "Aerilate" + }, + "heightm": 1.7, + "weightkg": 59, + "color": "Brown", + "eggGroups": [ + "Bug" + ] + }, + "tauros": { + "num": 128, + "species": "Tauros", + "types": [ + "Normal" + ], + "gender": "M", + "baseStats": { + "hp": 75, + "atk": 100, + "def": 95, + "spa": 40, + "spd": 70, + "spe": 110 + }, + "abilities": { + "0": "Intimidate", + "1": "Anger Point", + "H": "Sheer Force" + }, + "heightm": 1.4, + "weightkg": 88.4, + "color": "Brown", + "eggGroups": [ + "Field" + ] + }, + "magikarp": { + "num": 129, + "species": "Magikarp", + "types": [ + "Water" + ], + "baseStats": { + "hp": 20, + "atk": 10, + "def": 55, + "spa": 15, + "spd": 20, + "spe": 80 + }, + "abilities": { + "0": "Swift Swim", + "H": "Rattled" + }, + "heightm": 0.9, + "weightkg": 10, + "color": "Red", + "evos": [ + "gyarados" + ], + "eggGroups": [ + "Water 2", + "Dragon" + ] + }, + "gyarados": { + "num": 130, + "species": "Gyarados", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 95, + "atk": 125, + "def": 79, + "spa": 60, + "spd": 100, + "spe": 81 + }, + "abilities": { + "0": "Intimidate", + "H": "Moxie" + }, + "heightm": 6.5, + "weightkg": 235, + "color": "Blue", + "prevo": "magikarp", + "evoLevel": 20, + "eggGroups": [ + "Water 2", + "Dragon" + ], + "otherFormes": [ + "gyaradosmega" + ] + }, + "gyaradosmega": { + "num": 130, + "species": "Gyarados-Mega", + "baseSpecies": "Gyarados", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Water", + "Dark" + ], + "baseStats": { + "hp": 95, + "atk": 155, + "def": 109, + "spa": 70, + "spd": 130, + "spe": 81 + }, + "abilities": { + "0": "Mold Breaker" + }, + "heightm": 6.5, + "weightkg": 305, + "color": "Blue", + "eggGroups": [ + "Water 2", + "Dragon" + ] + }, + "lapras": { + "num": 131, + "species": "Lapras", + "types": [ + "Water", + "Ice" + ], + "baseStats": { + "hp": 130, + "atk": 85, + "def": 80, + "spa": 85, + "spd": 95, + "spe": 60 + }, + "abilities": { + "0": "Water Absorb", + "1": "Shell Armor", + "H": "Hydration" + }, + "heightm": 2.5, + "weightkg": 220, + "color": "Blue", + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "ditto": { + "num": 132, + "species": "Ditto", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 48, + "atk": 48, + "def": 48, + "spa": 48, + "spd": 48, + "spe": 48 + }, + "abilities": { + "0": "Limber", + "H": "Imposter" + }, + "heightm": 0.3, + "weightkg": 4, + "color": "Purple", + "eggGroups": [ + "Ditto" + ] + }, + "eevee": { + "num": 133, + "species": "Eevee", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 55, + "atk": 55, + "def": 50, + "spa": 45, + "spd": 65, + "spe": 55 + }, + "abilities": { + "0": "Run Away", + "1": "Adaptability", + "H": "Anticipation" + }, + "heightm": 0.3, + "weightkg": 6.5, + "color": "Brown", + "evos": [ + "vaporeon", + "jolteon", + "flareon", + "espeon", + "umbreon", + "leafeon", + "glaceon", + "sylveon" + ], + "eggGroups": [ + "Field" + ] + }, + "vaporeon": { + "num": 134, + "species": "Vaporeon", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 130, + "atk": 65, + "def": 60, + "spa": 110, + "spd": 95, + "spe": 65 + }, + "abilities": { + "0": "Water Absorb", + "H": "Hydration" + }, + "heightm": 1, + "weightkg": 29, + "color": "Blue", + "prevo": "eevee", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "jolteon": { + "num": 135, + "species": "Jolteon", + "types": [ + "Electric" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 65, + "def": 60, + "spa": 110, + "spd": 95, + "spe": 130 + }, + "abilities": { + "0": "Volt Absorb", + "H": "Quick Feet" + }, + "heightm": 0.8, + "weightkg": 24.5, + "color": "Yellow", + "prevo": "eevee", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "flareon": { + "num": 136, + "species": "Flareon", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 130, + "def": 60, + "spa": 95, + "spd": 110, + "spe": 65 + }, + "abilities": { + "0": "Flash Fire", + "H": "Guts" + }, + "heightm": 0.9, + "weightkg": 25, + "color": "Red", + "prevo": "eevee", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "porygon": { + "num": 137, + "species": "Porygon", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 65, + "atk": 60, + "def": 70, + "spa": 85, + "spd": 75, + "spe": 40 + }, + "abilities": { + "0": "Trace", + "1": "Download", + "H": "Analytic" + }, + "heightm": 0.8, + "weightkg": 36.5, + "color": "Pink", + "evos": [ + "porygon2" + ], + "eggGroups": [ + "Mineral" + ] + }, + "omanyte": { + "num": 138, + "species": "Omanyte", + "types": [ + "Rock", + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 35, + "atk": 40, + "def": 100, + "spa": 90, + "spd": 55, + "spe": 35 + }, + "abilities": { + "0": "Swift Swim", + "1": "Shell Armor", + "H": "Weak Armor" + }, + "heightm": 0.4, + "weightkg": 7.5, + "color": "Blue", + "evos": [ + "omastar" + ], + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "omastar": { + "num": 139, + "species": "Omastar", + "types": [ + "Rock", + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 70, + "atk": 60, + "def": 125, + "spa": 115, + "spd": 70, + "spe": 55 + }, + "abilities": { + "0": "Swift Swim", + "1": "Shell Armor", + "H": "Weak Armor" + }, + "heightm": 1, + "weightkg": 35, + "color": "Blue", + "prevo": "omanyte", + "evoLevel": 40, + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "kabuto": { + "num": 140, + "species": "Kabuto", + "types": [ + "Rock", + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 30, + "atk": 80, + "def": 90, + "spa": 55, + "spd": 45, + "spe": 55 + }, + "abilities": { + "0": "Swift Swim", + "1": "Battle Armor", + "H": "Weak Armor" + }, + "heightm": 0.5, + "weightkg": 11.5, + "color": "Brown", + "evos": [ + "kabutops" + ], + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "kabutops": { + "num": 141, + "species": "Kabutops", + "types": [ + "Rock", + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 115, + "def": 105, + "spa": 65, + "spd": 70, + "spe": 80 + }, + "abilities": { + "0": "Swift Swim", + "1": "Battle Armor", + "H": "Weak Armor" + }, + "heightm": 1.3, + "weightkg": 40.5, + "color": "Brown", + "prevo": "kabuto", + "evoLevel": 40, + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "aerodactyl": { + "num": 142, + "species": "Aerodactyl", + "types": [ + "Rock", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 105, + "def": 65, + "spa": 60, + "spd": 75, + "spe": 130 + }, + "abilities": { + "0": "Rock Head", + "1": "Pressure", + "H": "Unnerve" + }, + "heightm": 1.8, + "weightkg": 59, + "color": "Purple", + "eggGroups": [ + "Flying" + ], + "otherFormes": [ + "aerodactylmega" + ] + }, + "aerodactylmega": { + "num": 142, + "species": "Aerodactyl-Mega", + "baseSpecies": "Aerodactyl", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Rock", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 135, + "def": 85, + "spa": 70, + "spd": 95, + "spe": 150 + }, + "abilities": { + "0": "Tough Claws" + }, + "heightm": 2.1, + "weightkg": 79, + "color": "Purple", + "eggGroups": [ + "Flying" + ] + }, + "snorlax": { + "num": 143, + "species": "Snorlax", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 160, + "atk": 110, + "def": 65, + "spa": 65, + "spd": 110, + "spe": 30 + }, + "abilities": { + "0": "Immunity", + "1": "Thick Fat", + "H": "Gluttony" + }, + "heightm": 2.1, + "weightkg": 460, + "color": "Black", + "prevo": "munchlax", + "evoLevel": 1, + "eggGroups": [ + "Monster" + ] + }, + "articuno": { + "num": 144, + "species": "Articuno", + "types": [ + "Ice", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 85, + "def": 100, + "spa": 95, + "spd": 125, + "spe": 85 + }, + "abilities": { + "0": "Pressure", + "H": "Snow Cloak" + }, + "heightm": 1.7, + "weightkg": 55.4, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "zapdos": { + "num": 145, + "species": "Zapdos", + "types": [ + "Electric", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 90, + "def": 85, + "spa": 125, + "spd": 90, + "spe": 100 + }, + "abilities": { + "0": "Pressure", + "H": "Static" + }, + "heightm": 1.6, + "weightkg": 52.6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "moltres": { + "num": 146, + "species": "Moltres", + "types": [ + "Fire", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 100, + "def": 90, + "spa": 125, + "spd": 85, + "spe": 90 + }, + "abilities": { + "0": "Pressure", + "H": "Flame Body" + }, + "heightm": 2, + "weightkg": 60, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "dratini": { + "num": 147, + "species": "Dratini", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 41, + "atk": 64, + "def": 45, + "spa": 50, + "spd": 50, + "spe": 50 + }, + "abilities": { + "0": "Shed Skin", + "H": "Marvel Scale" + }, + "heightm": 1.8, + "weightkg": 3.3, + "color": "Blue", + "evos": [ + "dragonair" + ], + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "dragonair": { + "num": 148, + "species": "Dragonair", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 61, + "atk": 84, + "def": 65, + "spa": 70, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Shed Skin", + "H": "Marvel Scale" + }, + "heightm": 4, + "weightkg": 16.5, + "color": "Blue", + "prevo": "dratini", + "evos": [ + "dragonite" + ], + "evoLevel": 30, + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "dragonite": { + "num": 149, + "species": "Dragonite", + "types": [ + "Dragon", + "Flying" + ], + "baseStats": { + "hp": 91, + "atk": 134, + "def": 95, + "spa": 100, + "spd": 100, + "spe": 80 + }, + "abilities": { + "0": "Inner Focus", + "H": "Multiscale" + }, + "heightm": 2.2, + "weightkg": 210, + "color": "Brown", + "prevo": "dragonair", + "evoLevel": 55, + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "mewtwo": { + "num": 150, + "species": "Mewtwo", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 106, + "atk": 110, + "def": 90, + "spa": 154, + "spd": 90, + "spe": 130 + }, + "abilities": { + "0": "Pressure", + "H": "Unnerve" + }, + "heightm": 2, + "weightkg": 122, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "mewtwomegax", + "mewtwomegay" + ] + }, + "mewtwomegax": { + "num": 150, + "species": "Mewtwo-Mega-X", + "baseSpecies": "Mewtwo", + "forme": "Mega-X", + "formeLetter": "M", + "types": [ + "Psychic", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 106, + "atk": 190, + "def": 100, + "spa": 154, + "spd": 100, + "spe": 130 + }, + "abilities": { + "0": "Steadfast" + }, + "heightm": 2.3, + "weightkg": 127, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "mewtwomegay": { + "num": 150, + "species": "Mewtwo-Mega-Y", + "baseSpecies": "Mewtwo", + "forme": "Mega-Y", + "formeLetter": "M", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 106, + "atk": 150, + "def": 70, + "spa": 194, + "spd": 120, + "spe": 140 + }, + "abilities": { + "0": "Insomnia" + }, + "heightm": 1.5, + "weightkg": 33, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "mew": { + "num": 151, + "species": "Mew", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 100, + "spa": 100, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Synchronize" + }, + "heightm": 0.4, + "weightkg": 4, + "color": "Pink", + "eggGroups": [ + "Undiscovered" + ] + }, + "chikorita": { + "num": 152, + "species": "Chikorita", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 45, + "atk": 49, + "def": 65, + "spa": 49, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Overgrow", + "H": "Leaf Guard" + }, + "heightm": 0.9, + "weightkg": 6.4, + "color": "Green", + "evos": [ + "bayleef" + ], + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "bayleef": { + "num": 153, + "species": "Bayleef", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 62, + "def": 80, + "spa": 63, + "spd": 80, + "spe": 60 + }, + "abilities": { + "0": "Overgrow", + "H": "Leaf Guard" + }, + "heightm": 1.2, + "weightkg": 15.8, + "color": "Green", + "prevo": "chikorita", + "evos": [ + "meganium" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "meganium": { + "num": 154, + "species": "Meganium", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 82, + "def": 100, + "spa": 83, + "spd": 100, + "spe": 80 + }, + "abilities": { + "0": "Overgrow", + "H": "Leaf Guard" + }, + "heightm": 1.8, + "weightkg": 100.5, + "color": "Green", + "prevo": "bayleef", + "evoLevel": 32, + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "cyndaquil": { + "num": 155, + "species": "Cyndaquil", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 39, + "atk": 52, + "def": 43, + "spa": 60, + "spd": 50, + "spe": 65 + }, + "abilities": { + "0": "Blaze", + "H": "Flash Fire" + }, + "heightm": 0.5, + "weightkg": 7.9, + "color": "Yellow", + "evos": [ + "quilava" + ], + "eggGroups": [ + "Field" + ] + }, + "quilava": { + "num": 156, + "species": "Quilava", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 58, + "atk": 64, + "def": 58, + "spa": 80, + "spd": 65, + "spe": 80 + }, + "abilities": { + "0": "Blaze", + "H": "Flash Fire" + }, + "heightm": 0.9, + "weightkg": 19, + "color": "Yellow", + "prevo": "cyndaquil", + "evos": [ + "typhlosion" + ], + "evoLevel": 14, + "eggGroups": [ + "Field" + ] + }, + "typhlosion": { + "num": 157, + "species": "Typhlosion", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 78, + "atk": 84, + "def": 78, + "spa": 109, + "spd": 85, + "spe": 100 + }, + "abilities": { + "0": "Blaze", + "H": "Flash Fire" + }, + "heightm": 1.7, + "weightkg": 79.5, + "color": "Yellow", + "prevo": "quilava", + "evoLevel": 36, + "eggGroups": [ + "Field" + ] + }, + "totodile": { + "num": 158, + "species": "Totodile", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 65, + "def": 64, + "spa": 44, + "spd": 48, + "spe": 43 + }, + "abilities": { + "0": "Torrent", + "H": "Sheer Force" + }, + "heightm": 0.6, + "weightkg": 9.5, + "color": "Blue", + "evos": [ + "croconaw" + ], + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "croconaw": { + "num": 159, + "species": "Croconaw", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 80, + "def": 80, + "spa": 59, + "spd": 63, + "spe": 58 + }, + "abilities": { + "0": "Torrent", + "H": "Sheer Force" + }, + "heightm": 1.1, + "weightkg": 25, + "color": "Blue", + "prevo": "totodile", + "evos": [ + "feraligatr" + ], + "evoLevel": 18, + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "feraligatr": { + "num": 160, + "species": "Feraligatr", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 85, + "atk": 105, + "def": 100, + "spa": 79, + "spd": 83, + "spe": 78 + }, + "abilities": { + "0": "Torrent", + "H": "Sheer Force" + }, + "heightm": 2.3, + "weightkg": 88.8, + "color": "Blue", + "prevo": "croconaw", + "evoLevel": 30, + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "sentret": { + "num": 161, + "species": "Sentret", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 35, + "atk": 46, + "def": 34, + "spa": 35, + "spd": 45, + "spe": 20 + }, + "abilities": { + "0": "Run Away", + "1": "Keen Eye", + "H": "Frisk" + }, + "heightm": 0.8, + "weightkg": 6, + "color": "Brown", + "evos": [ + "furret" + ], + "eggGroups": [ + "Field" + ] + }, + "furret": { + "num": 162, + "species": "Furret", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 85, + "atk": 76, + "def": 64, + "spa": 45, + "spd": 55, + "spe": 90 + }, + "abilities": { + "0": "Run Away", + "1": "Keen Eye", + "H": "Frisk" + }, + "heightm": 1.8, + "weightkg": 32.5, + "color": "Brown", + "prevo": "sentret", + "evoLevel": 15, + "eggGroups": [ + "Field" + ] + }, + "hoothoot": { + "num": 163, + "species": "Hoothoot", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 30, + "def": 30, + "spa": 36, + "spd": 56, + "spe": 50 + }, + "abilities": { + "0": "Insomnia", + "1": "Keen Eye", + "H": "Tinted Lens" + }, + "heightm": 0.7, + "weightkg": 21.2, + "color": "Brown", + "evos": [ + "noctowl" + ], + "eggGroups": [ + "Flying" + ] + }, + "noctowl": { + "num": 164, + "species": "Noctowl", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 100, + "atk": 50, + "def": 50, + "spa": 86, + "spd": 96, + "spe": 70 + }, + "abilities": { + "0": "Insomnia", + "1": "Keen Eye", + "H": "Tinted Lens" + }, + "heightm": 1.6, + "weightkg": 40.8, + "color": "Brown", + "prevo": "hoothoot", + "evoLevel": 20, + "eggGroups": [ + "Flying" + ] + }, + "ledyba": { + "num": 165, + "species": "Ledyba", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 20, + "def": 30, + "spa": 40, + "spd": 80, + "spe": 55 + }, + "abilities": { + "0": "Swarm", + "1": "Early Bird", + "H": "Rattled" + }, + "heightm": 1, + "weightkg": 10.8, + "color": "Red", + "evos": [ + "ledian" + ], + "eggGroups": [ + "Bug" + ] + }, + "ledian": { + "num": 166, + "species": "Ledian", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 55, + "atk": 35, + "def": 50, + "spa": 55, + "spd": 110, + "spe": 85 + }, + "abilities": { + "0": "Swarm", + "1": "Early Bird", + "H": "Iron Fist" + }, + "heightm": 1.4, + "weightkg": 35.6, + "color": "Red", + "prevo": "ledyba", + "evoLevel": 18, + "eggGroups": [ + "Bug" + ] + }, + "spinarak": { + "num": 167, + "species": "Spinarak", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 40, + "atk": 60, + "def": 40, + "spa": 40, + "spd": 40, + "spe": 30 + }, + "abilities": { + "0": "Swarm", + "1": "Insomnia", + "H": "Sniper" + }, + "heightm": 0.5, + "weightkg": 8.5, + "color": "Green", + "evos": [ + "ariados" + ], + "eggGroups": [ + "Bug" + ] + }, + "ariados": { + "num": 168, + "species": "Ariados", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 70, + "atk": 90, + "def": 70, + "spa": 60, + "spd": 70, + "spe": 40 + }, + "abilities": { + "0": "Swarm", + "1": "Insomnia", + "H": "Sniper" + }, + "heightm": 1.1, + "weightkg": 33.5, + "color": "Red", + "prevo": "spinarak", + "evoLevel": 22, + "eggGroups": [ + "Bug" + ] + }, + "crobat": { + "num": 169, + "species": "Crobat", + "types": [ + "Poison", + "Flying" + ], + "baseStats": { + "hp": 85, + "atk": 90, + "def": 80, + "spa": 70, + "spd": 80, + "spe": 130 + }, + "abilities": { + "0": "Inner Focus", + "H": "Infiltrator" + }, + "heightm": 1.8, + "weightkg": 75, + "color": "Purple", + "prevo": "golbat", + "evoLevel": 23, + "eggGroups": [ + "Flying" + ] + }, + "chinchou": { + "num": 170, + "species": "Chinchou", + "types": [ + "Water", + "Electric" + ], + "baseStats": { + "hp": 75, + "atk": 38, + "def": 38, + "spa": 56, + "spd": 56, + "spe": 67 + }, + "abilities": { + "0": "Volt Absorb", + "1": "Illuminate", + "H": "Water Absorb" + }, + "heightm": 0.5, + "weightkg": 12, + "color": "Blue", + "evos": [ + "lanturn" + ], + "eggGroups": [ + "Water 2" + ] + }, + "lanturn": { + "num": 171, + "species": "Lanturn", + "types": [ + "Water", + "Electric" + ], + "baseStats": { + "hp": 125, + "atk": 58, + "def": 58, + "spa": 76, + "spd": 76, + "spe": 67 + }, + "abilities": { + "0": "Volt Absorb", + "1": "Illuminate", + "H": "Water Absorb" + }, + "heightm": 1.2, + "weightkg": 22.5, + "color": "Blue", + "prevo": "chinchou", + "evoLevel": 27, + "eggGroups": [ + "Water 2" + ] + }, + "pichu": { + "num": 172, + "species": "Pichu", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 20, + "atk": 40, + "def": 15, + "spa": 35, + "spd": 35, + "spe": 60 + }, + "abilities": { + "0": "Static", + "H": "Lightning Rod" + }, + "heightm": 0.3, + "weightkg": 2, + "color": "Yellow", + "evos": [ + "pikachu" + ], + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "pichuspikyeared" + ] + }, + "pichuspikyeared": { + "num": 172, + "species": "Pichu-Spiky-eared", + "baseSpecies": "Pichu", + "forme": "Spiky-eared", + "formeLetter": "S", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 20, + "atk": 40, + "def": 15, + "spa": 35, + "spd": 35, + "spe": 60 + }, + "abilities": { + "0": "Static" + }, + "heightm": 0.3, + "weightkg": 2, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "cleffa": { + "num": 173, + "species": "Cleffa", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 50, + "atk": 25, + "def": 28, + "spa": 45, + "spd": 55, + "spe": 15 + }, + "abilities": { + "0": "Cute Charm", + "1": "Magic Guard", + "H": "Friend Guard" + }, + "heightm": 0.3, + "weightkg": 3, + "color": "Pink", + "evos": [ + "clefairy" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "igglybuff": { + "num": 174, + "species": "Igglybuff", + "types": [ + "Normal", + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 90, + "atk": 30, + "def": 15, + "spa": 40, + "spd": 20, + "spe": 15 + }, + "abilities": { + "0": "Cute Charm", + "1": "Competitive", + "H": "Friend Guard" + }, + "heightm": 0.3, + "weightkg": 1, + "color": "Pink", + "evos": [ + "jigglypuff" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "togepi": { + "num": 175, + "species": "Togepi", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 35, + "atk": 20, + "def": 65, + "spa": 40, + "spd": 65, + "spe": 20 + }, + "abilities": { + "0": "Hustle", + "1": "Serene Grace", + "H": "Super Luck" + }, + "heightm": 0.3, + "weightkg": 1.5, + "color": "White", + "evos": [ + "togetic" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "togetic": { + "num": 176, + "species": "Togetic", + "types": [ + "Fairy", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 55, + "atk": 40, + "def": 85, + "spa": 80, + "spd": 105, + "spe": 40 + }, + "abilities": { + "0": "Hustle", + "1": "Serene Grace", + "H": "Super Luck" + }, + "heightm": 0.6, + "weightkg": 3.2, + "color": "White", + "prevo": "togepi", + "evos": [ + "togekiss" + ], + "evoLevel": 2, + "eggGroups": [ + "Flying", + "Fairy" + ] + }, + "natu": { + "num": 177, + "species": "Natu", + "types": [ + "Psychic", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 50, + "def": 45, + "spa": 70, + "spd": 45, + "spe": 70 + }, + "abilities": { + "0": "Synchronize", + "1": "Early Bird", + "H": "Magic Bounce" + }, + "heightm": 0.2, + "weightkg": 2, + "color": "Green", + "evos": [ + "xatu" + ], + "eggGroups": [ + "Flying" + ] + }, + "xatu": { + "num": 178, + "species": "Xatu", + "types": [ + "Psychic", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 75, + "def": 70, + "spa": 95, + "spd": 70, + "spe": 95 + }, + "abilities": { + "0": "Synchronize", + "1": "Early Bird", + "H": "Magic Bounce" + }, + "heightm": 1.5, + "weightkg": 15, + "color": "Green", + "prevo": "natu", + "evoLevel": 25, + "eggGroups": [ + "Flying" + ] + }, + "mareep": { + "num": 179, + "species": "Mareep", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 55, + "atk": 40, + "def": 40, + "spa": 65, + "spd": 45, + "spe": 35 + }, + "abilities": { + "0": "Static", + "H": "Plus" + }, + "heightm": 0.6, + "weightkg": 7.8, + "color": "White", + "evos": [ + "flaaffy" + ], + "eggGroups": [ + "Monster", + "Field" + ] + }, + "flaaffy": { + "num": 180, + "species": "Flaaffy", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 70, + "atk": 55, + "def": 55, + "spa": 80, + "spd": 60, + "spe": 45 + }, + "abilities": { + "0": "Static", + "H": "Plus" + }, + "heightm": 0.8, + "weightkg": 13.3, + "color": "Pink", + "prevo": "mareep", + "evos": [ + "ampharos" + ], + "evoLevel": 15, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "ampharos": { + "num": 181, + "species": "Ampharos", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 90, + "atk": 75, + "def": 85, + "spa": 115, + "spd": 90, + "spe": 55 + }, + "abilities": { + "0": "Static", + "H": "Plus" + }, + "heightm": 1.4, + "weightkg": 61.5, + "color": "Yellow", + "prevo": "flaaffy", + "evoLevel": 30, + "eggGroups": [ + "Monster", + "Field" + ], + "otherFormes": [ + "ampharosmega" + ] + }, + "ampharosmega": { + "num": 181, + "species": "Ampharos-Mega", + "baseSpecies": "Ampharos", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Electric", + "Dragon" + ], + "baseStats": { + "hp": 90, + "atk": 95, + "def": 105, + "spa": 165, + "spd": 110, + "spe": 45 + }, + "abilities": { + "0": "Mold Breaker" + }, + "heightm": 1.4, + "weightkg": 61.5, + "color": "Yellow", + "eggGroups": [ + "Monster", + "Field" + ] + }, + "bellossom": { + "num": 182, + "species": "Bellossom", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 75, + "atk": 80, + "def": 95, + "spa": 90, + "spd": 100, + "spe": 50 + }, + "abilities": { + "0": "Chlorophyll", + "H": "Healer" + }, + "heightm": 0.4, + "weightkg": 5.8, + "color": "Green", + "prevo": "gloom", + "evoLevel": 21, + "eggGroups": [ + "Grass" + ] + }, + "marill": { + "num": 183, + "species": "Marill", + "types": [ + "Water", + "Fairy" + ], + "baseStats": { + "hp": 70, + "atk": 20, + "def": 50, + "spa": 20, + "spd": 50, + "spe": 40 + }, + "abilities": { + "0": "Thick Fat", + "1": "Huge Power", + "H": "Sap Sipper" + }, + "heightm": 0.4, + "weightkg": 8.5, + "color": "Blue", + "prevo": "azurill", + "evos": [ + "azumarill" + ], + "evoLevel": 1, + "eggGroups": [ + "Water 1", + "Fairy" + ] + }, + "azumarill": { + "num": 184, + "species": "Azumarill", + "types": [ + "Water", + "Fairy" + ], + "baseStats": { + "hp": 100, + "atk": 50, + "def": 80, + "spa": 60, + "spd": 80, + "spe": 50 + }, + "abilities": { + "0": "Thick Fat", + "1": "Huge Power", + "H": "Sap Sipper" + }, + "heightm": 0.8, + "weightkg": 28.5, + "color": "Blue", + "prevo": "marill", + "evoLevel": 18, + "eggGroups": [ + "Water 1", + "Fairy" + ] + }, + "sudowoodo": { + "num": 185, + "species": "Sudowoodo", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 70, + "atk": 100, + "def": 115, + "spa": 30, + "spd": 65, + "spe": 30 + }, + "abilities": { + "0": "Sturdy", + "1": "Rock Head", + "H": "Rattled" + }, + "heightm": 1.2, + "weightkg": 38, + "color": "Brown", + "prevo": "bonsly", + "evoLevel": 1, + "evoMove": "Mimic", + "eggGroups": [ + "Mineral" + ] + }, + "politoed": { + "num": 186, + "species": "Politoed", + "types": [ + "Water" + ], + "baseStats": { + "hp": 90, + "atk": 75, + "def": 75, + "spa": 90, + "spd": 100, + "spe": 70 + }, + "abilities": { + "0": "Water Absorb", + "1": "Damp", + "H": "Drizzle" + }, + "heightm": 1.1, + "weightkg": 33.9, + "color": "Green", + "prevo": "poliwhirl", + "evoLevel": 25, + "eggGroups": [ + "Water 1" + ] + }, + "hoppip": { + "num": 187, + "species": "Hoppip", + "types": [ + "Grass", + "Flying" + ], + "baseStats": { + "hp": 35, + "atk": 35, + "def": 40, + "spa": 35, + "spd": 55, + "spe": 50 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Leaf Guard", + "H": "Infiltrator" + }, + "heightm": 0.4, + "weightkg": 0.5, + "color": "Pink", + "evos": [ + "skiploom" + ], + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "skiploom": { + "num": 188, + "species": "Skiploom", + "types": [ + "Grass", + "Flying" + ], + "baseStats": { + "hp": 55, + "atk": 45, + "def": 50, + "spa": 45, + "spd": 65, + "spe": 80 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Leaf Guard", + "H": "Infiltrator" + }, + "heightm": 0.6, + "weightkg": 1, + "color": "Green", + "prevo": "hoppip", + "evos": [ + "jumpluff" + ], + "evoLevel": 18, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "jumpluff": { + "num": 189, + "species": "Jumpluff", + "types": [ + "Grass", + "Flying" + ], + "baseStats": { + "hp": 75, + "atk": 55, + "def": 70, + "spa": 55, + "spd": 95, + "spe": 110 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Leaf Guard", + "H": "Infiltrator" + }, + "heightm": 0.8, + "weightkg": 3, + "color": "Blue", + "prevo": "skiploom", + "evoLevel": 27, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "aipom": { + "num": 190, + "species": "Aipom", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 55, + "atk": 70, + "def": 55, + "spa": 40, + "spd": 55, + "spe": 85 + }, + "abilities": { + "0": "Run Away", + "1": "Pickup", + "H": "Skill Link" + }, + "heightm": 0.8, + "weightkg": 11.5, + "color": "Purple", + "evos": [ + "ambipom" + ], + "eggGroups": [ + "Field" + ] + }, + "sunkern": { + "num": 191, + "species": "Sunkern", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 30, + "atk": 30, + "def": 30, + "spa": 30, + "spd": 30, + "spe": 30 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Solar Power", + "H": "Early Bird" + }, + "heightm": 0.3, + "weightkg": 1.8, + "color": "Yellow", + "evos": [ + "sunflora" + ], + "eggGroups": [ + "Grass" + ] + }, + "sunflora": { + "num": 192, + "species": "Sunflora", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 75, + "atk": 75, + "def": 55, + "spa": 105, + "spd": 85, + "spe": 30 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Solar Power", + "H": "Early Bird" + }, + "heightm": 0.8, + "weightkg": 8.5, + "color": "Yellow", + "prevo": "sunkern", + "evoLevel": 1, + "eggGroups": [ + "Grass" + ] + }, + "yanma": { + "num": 193, + "species": "Yanma", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 65, + "def": 45, + "spa": 75, + "spd": 45, + "spe": 95 + }, + "abilities": { + "0": "Speed Boost", + "1": "Compound Eyes", + "H": "Frisk" + }, + "heightm": 1.2, + "weightkg": 38, + "color": "Red", + "evos": [ + "yanmega" + ], + "eggGroups": [ + "Bug" + ] + }, + "wooper": { + "num": 194, + "species": "Wooper", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 55, + "atk": 45, + "def": 45, + "spa": 25, + "spd": 25, + "spe": 15 + }, + "abilities": { + "0": "Damp", + "1": "Water Absorb", + "H": "Unaware" + }, + "heightm": 0.4, + "weightkg": 8.5, + "color": "Blue", + "evos": [ + "quagsire" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "quagsire": { + "num": 195, + "species": "Quagsire", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 95, + "atk": 85, + "def": 85, + "spa": 65, + "spd": 65, + "spe": 35 + }, + "abilities": { + "0": "Damp", + "1": "Water Absorb", + "H": "Unaware" + }, + "heightm": 1.4, + "weightkg": 75, + "color": "Blue", + "prevo": "wooper", + "evoLevel": 20, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "espeon": { + "num": 196, + "species": "Espeon", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 65, + "def": 60, + "spa": 130, + "spd": 95, + "spe": 110 + }, + "abilities": { + "0": "Synchronize", + "H": "Magic Bounce" + }, + "heightm": 0.9, + "weightkg": 26.5, + "color": "Purple", + "prevo": "eevee", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "umbreon": { + "num": 197, + "species": "Umbreon", + "types": [ + "Dark" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 95, + "atk": 65, + "def": 110, + "spa": 60, + "spd": 130, + "spe": 65 + }, + "abilities": { + "0": "Synchronize", + "H": "Inner Focus" + }, + "heightm": 1, + "weightkg": 27, + "color": "Black", + "prevo": "eevee", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "murkrow": { + "num": 198, + "species": "Murkrow", + "types": [ + "Dark", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 85, + "def": 42, + "spa": 85, + "spd": 42, + "spe": 91 + }, + "abilities": { + "0": "Insomnia", + "1": "Super Luck", + "H": "Prankster" + }, + "heightm": 0.5, + "weightkg": 2.1, + "color": "Black", + "evos": [ + "honchkrow" + ], + "eggGroups": [ + "Flying" + ] + }, + "slowking": { + "num": 199, + "species": "Slowking", + "types": [ + "Water", + "Psychic" + ], + "baseStats": { + "hp": 95, + "atk": 75, + "def": 80, + "spa": 100, + "spd": 110, + "spe": 30 + }, + "abilities": { + "0": "Oblivious", + "1": "Own Tempo", + "H": "Regenerator" + }, + "heightm": 2, + "weightkg": 79.5, + "color": "Pink", + "prevo": "slowpoke", + "evoLevel": 1, + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "misdreavus": { + "num": 200, + "species": "Misdreavus", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 60, + "spa": 85, + "spd": 85, + "spe": 85 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.7, + "weightkg": 1, + "color": "Gray", + "evos": [ + "mismagius" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "unown": { + "num": 201, + "species": "Unown", + "baseForme": "A", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 48, + "atk": 72, + "def": 48, + "spa": 72, + "spd": 48, + "spe": 48 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.5, + "weightkg": 5, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ], + "otherForms": [ + "unownb", + "unownc", + "unownd", + "unowne", + "unownf", + "unowng", + "unownh", + "unowni", + "unownj", + "unownk", + "unownl", + "unownm", + "unownn", + "unowno", + "unownp", + "unownq", + "unownr", + "unowns", + "unownt", + "unownu", + "unownv", + "unownw", + "unownx", + "unowny", + "unownz", + "unownexclamation", + "unownquestion" + ] + }, + "wobbuffet": { + "num": 202, + "species": "Wobbuffet", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 190, + "atk": 33, + "def": 58, + "spa": 33, + "spd": 58, + "spe": 33 + }, + "abilities": { + "0": "Shadow Tag", + "H": "Telepathy" + }, + "heightm": 1.3, + "weightkg": 28.5, + "color": "Blue", + "prevo": "wynaut", + "evoLevel": 15, + "eggGroups": [ + "Amorphous" + ] + }, + "girafarig": { + "num": 203, + "species": "Girafarig", + "types": [ + "Normal", + "Psychic" + ], + "baseStats": { + "hp": 70, + "atk": 80, + "def": 65, + "spa": 90, + "spd": 65, + "spe": 85 + }, + "abilities": { + "0": "Inner Focus", + "1": "Early Bird", + "H": "Sap Sipper" + }, + "heightm": 1.5, + "weightkg": 41.5, + "color": "Yellow", + "eggGroups": [ + "Field" + ] + }, + "pineco": { + "num": 204, + "species": "Pineco", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 50, + "atk": 65, + "def": 90, + "spa": 35, + "spd": 35, + "spe": 15 + }, + "abilities": { + "0": "Sturdy", + "H": "Overcoat" + }, + "heightm": 0.6, + "weightkg": 7.2, + "color": "Gray", + "evos": [ + "forretress" + ], + "eggGroups": [ + "Bug" + ] + }, + "forretress": { + "num": 205, + "species": "Forretress", + "types": [ + "Bug", + "Steel" + ], + "baseStats": { + "hp": 75, + "atk": 90, + "def": 140, + "spa": 60, + "spd": 60, + "spe": 40 + }, + "abilities": { + "0": "Sturdy", + "H": "Overcoat" + }, + "heightm": 1.2, + "weightkg": 125.8, + "color": "Purple", + "prevo": "pineco", + "evoLevel": 31, + "eggGroups": [ + "Bug" + ] + }, + "dunsparce": { + "num": 206, + "species": "Dunsparce", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 100, + "atk": 70, + "def": 70, + "spa": 65, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Serene Grace", + "1": "Run Away", + "H": "Rattled" + }, + "heightm": 1.5, + "weightkg": 14, + "color": "Yellow", + "eggGroups": [ + "Field" + ] + }, + "gligar": { + "num": 207, + "species": "Gligar", + "types": [ + "Ground", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 75, + "def": 105, + "spa": 35, + "spd": 65, + "spe": 85 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Sand Veil", + "H": "Immunity" + }, + "heightm": 1.1, + "weightkg": 64.8, + "color": "Purple", + "evos": [ + "gliscor" + ], + "eggGroups": [ + "Bug" + ] + }, + "steelix": { + "num": 208, + "species": "Steelix", + "types": [ + "Steel", + "Ground" + ], + "baseStats": { + "hp": 75, + "atk": 85, + "def": 200, + "spa": 55, + "spd": 65, + "spe": 30 + }, + "abilities": { + "0": "Rock Head", + "1": "Sturdy", + "H": "Sheer Force" + }, + "heightm": 9.2, + "weightkg": 400, + "color": "Gray", + "prevo": "onix", + "evoLevel": 1, + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "steelixmega" + ] + }, + "steelixmega": { + "num": 208, + "species": "Steelix-Mega", + "baseSpecies": "Steelix", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Steel", + "Ground" + ], + "baseStats": { + "hp": 75, + "atk": 125, + "def": 230, + "spa": 55, + "spd": 95, + "spe": 30 + }, + "abilities": { + "0": "Sand Force" + }, + "heightm": 10.5, + "weightkg": 740, + "color": "Gray", + "eggGroups": [ + "Mineral" + ] + }, + "snubbull": { + "num": 209, + "species": "Snubbull", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 60, + "atk": 80, + "def": 50, + "spa": 40, + "spd": 40, + "spe": 30 + }, + "abilities": { + "0": "Intimidate", + "1": "Run Away", + "H": "Rattled" + }, + "heightm": 0.6, + "weightkg": 7.8, + "color": "Pink", + "evos": [ + "granbull" + ], + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "granbull": { + "num": 210, + "species": "Granbull", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 90, + "atk": 120, + "def": 75, + "spa": 60, + "spd": 60, + "spe": 45 + }, + "abilities": { + "0": "Intimidate", + "1": "Quick Feet", + "H": "Rattled" + }, + "heightm": 1.4, + "weightkg": 48.7, + "color": "Purple", + "prevo": "snubbull", + "evoLevel": 23, + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "qwilfish": { + "num": 211, + "species": "Qwilfish", + "types": [ + "Water", + "Poison" + ], + "baseStats": { + "hp": 65, + "atk": 95, + "def": 85, + "spa": 55, + "spd": 55, + "spe": 85 + }, + "abilities": { + "0": "Poison Point", + "1": "Swift Swim", + "H": "Intimidate" + }, + "heightm": 0.5, + "weightkg": 3.9, + "color": "Gray", + "eggGroups": [ + "Water 2" + ] + }, + "scizor": { + "num": 212, + "species": "Scizor", + "types": [ + "Bug", + "Steel" + ], + "baseStats": { + "hp": 70, + "atk": 130, + "def": 100, + "spa": 55, + "spd": 80, + "spe": 65 + }, + "abilities": { + "0": "Swarm", + "1": "Technician", + "H": "Light Metal" + }, + "heightm": 1.8, + "weightkg": 118, + "color": "Red", + "prevo": "scyther", + "evoLevel": 1, + "eggGroups": [ + "Bug" + ], + "otherFormes": [ + "scizormega" + ] + }, + "scizormega": { + "num": 212, + "species": "Scizor-Mega", + "baseSpecies": "Scizor", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Bug", + "Steel" + ], + "baseStats": { + "hp": 70, + "atk": 150, + "def": 140, + "spa": 65, + "spd": 100, + "spe": 75 + }, + "abilities": { + "0": "Technician" + }, + "heightm": 2, + "weightkg": 125, + "color": "Red", + "eggGroups": [ + "Bug" + ] + }, + "shuckle": { + "num": 213, + "species": "Shuckle", + "types": [ + "Bug", + "Rock" + ], + "baseStats": { + "hp": 20, + "atk": 10, + "def": 230, + "spa": 10, + "spd": 230, + "spe": 5 + }, + "abilities": { + "0": "Sturdy", + "1": "Gluttony", + "H": "Contrary" + }, + "heightm": 0.6, + "weightkg": 20.5, + "color": "Yellow", + "eggGroups": [ + "Bug" + ] + }, + "heracross": { + "num": 214, + "species": "Heracross", + "types": [ + "Bug", + "Fighting" + ], + "baseStats": { + "hp": 80, + "atk": 125, + "def": 75, + "spa": 40, + "spd": 95, + "spe": 85 + }, + "abilities": { + "0": "Swarm", + "1": "Guts", + "H": "Moxie" + }, + "heightm": 1.5, + "weightkg": 54, + "color": "Blue", + "eggGroups": [ + "Bug" + ], + "otherFormes": [ + "heracrossmega" + ] + }, + "heracrossmega": { + "num": 214, + "species": "Heracross-Mega", + "baseSpecies": "Heracross", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Bug", + "Fighting" + ], + "baseStats": { + "hp": 80, + "atk": 185, + "def": 115, + "spa": 40, + "spd": 105, + "spe": 75 + }, + "abilities": { + "0": "Skill Link" + }, + "heightm": 1.7, + "weightkg": 62.5, + "color": "Blue", + "eggGroups": [ + "Bug" + ] + }, + "sneasel": { + "num": 215, + "species": "Sneasel", + "types": [ + "Dark", + "Ice" + ], + "baseStats": { + "hp": 55, + "atk": 95, + "def": 55, + "spa": 35, + "spd": 75, + "spe": 115 + }, + "abilities": { + "0": "Inner Focus", + "1": "Keen Eye", + "H": "Pickpocket" + }, + "heightm": 0.9, + "weightkg": 28, + "color": "Black", + "evos": [ + "weavile" + ], + "eggGroups": [ + "Field" + ] + }, + "teddiursa": { + "num": 216, + "species": "Teddiursa", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 60, + "atk": 80, + "def": 50, + "spa": 50, + "spd": 50, + "spe": 40 + }, + "abilities": { + "0": "Pickup", + "1": "Quick Feet", + "H": "Honey Gather" + }, + "heightm": 0.6, + "weightkg": 8.8, + "color": "Brown", + "evos": [ + "ursaring" + ], + "eggGroups": [ + "Field" + ] + }, + "ursaring": { + "num": 217, + "species": "Ursaring", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 90, + "atk": 130, + "def": 75, + "spa": 75, + "spd": 75, + "spe": 55 + }, + "abilities": { + "0": "Guts", + "1": "Quick Feet", + "H": "Unnerve" + }, + "heightm": 1.8, + "weightkg": 125.8, + "color": "Brown", + "prevo": "teddiursa", + "evoLevel": 30, + "eggGroups": [ + "Field" + ] + }, + "slugma": { + "num": 218, + "species": "Slugma", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 40, + "atk": 40, + "def": 40, + "spa": 70, + "spd": 40, + "spe": 20 + }, + "abilities": { + "0": "Magma Armor", + "1": "Flame Body", + "H": "Weak Armor" + }, + "heightm": 0.7, + "weightkg": 35, + "color": "Red", + "evos": [ + "magcargo" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "magcargo": { + "num": 219, + "species": "Magcargo", + "types": [ + "Fire", + "Rock" + ], + "baseStats": { + "hp": 60, + "atk": 50, + "def": 120, + "spa": 90, + "spd": 80, + "spe": 30 + }, + "abilities": { + "0": "Magma Armor", + "1": "Flame Body", + "H": "Weak Armor" + }, + "heightm": 0.8, + "weightkg": 55, + "color": "Red", + "prevo": "slugma", + "evoLevel": 38, + "eggGroups": [ + "Amorphous" + ] + }, + "swinub": { + "num": 220, + "species": "Swinub", + "types": [ + "Ice", + "Ground" + ], + "baseStats": { + "hp": 50, + "atk": 50, + "def": 40, + "spa": 30, + "spd": 30, + "spe": 50 + }, + "abilities": { + "0": "Oblivious", + "1": "Snow Cloak", + "H": "Thick Fat" + }, + "heightm": 0.4, + "weightkg": 6.5, + "color": "Brown", + "evos": [ + "piloswine" + ], + "eggGroups": [ + "Field" + ] + }, + "piloswine": { + "num": 221, + "species": "Piloswine", + "types": [ + "Ice", + "Ground" + ], + "baseStats": { + "hp": 100, + "atk": 100, + "def": 80, + "spa": 60, + "spd": 60, + "spe": 50 + }, + "abilities": { + "0": "Oblivious", + "1": "Snow Cloak", + "H": "Thick Fat" + }, + "heightm": 1.1, + "weightkg": 55.8, + "color": "Brown", + "prevo": "swinub", + "evos": [ + "mamoswine" + ], + "evoLevel": 33, + "eggGroups": [ + "Field" + ] + }, + "corsola": { + "num": 222, + "species": "Corsola", + "types": [ + "Water", + "Rock" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 65, + "atk": 55, + "def": 95, + "spa": 65, + "spd": 95, + "spe": 35 + }, + "abilities": { + "0": "Hustle", + "1": "Natural Cure", + "H": "Regenerator" + }, + "heightm": 0.6, + "weightkg": 5, + "color": "Pink", + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "remoraid": { + "num": 223, + "species": "Remoraid", + "types": [ + "Water" + ], + "baseStats": { + "hp": 35, + "atk": 65, + "def": 35, + "spa": 65, + "spd": 35, + "spe": 65 + }, + "abilities": { + "0": "Hustle", + "1": "Sniper", + "H": "Moody" + }, + "heightm": 0.6, + "weightkg": 12, + "color": "Gray", + "evos": [ + "octillery" + ], + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "octillery": { + "num": 224, + "species": "Octillery", + "types": [ + "Water" + ], + "baseStats": { + "hp": 75, + "atk": 105, + "def": 75, + "spa": 105, + "spd": 75, + "spe": 45 + }, + "abilities": { + "0": "Suction Cups", + "1": "Sniper", + "H": "Moody" + }, + "heightm": 0.9, + "weightkg": 28.5, + "color": "Red", + "prevo": "remoraid", + "evoLevel": 25, + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "delibird": { + "num": 225, + "species": "Delibird", + "types": [ + "Ice", + "Flying" + ], + "baseStats": { + "hp": 45, + "atk": 55, + "def": 45, + "spa": 65, + "spd": 45, + "spe": 75 + }, + "abilities": { + "0": "Vital Spirit", + "1": "Hustle", + "H": "Insomnia" + }, + "heightm": 0.9, + "weightkg": 16, + "color": "Red", + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "mantine": { + "num": 226, + "species": "Mantine", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 85, + "atk": 40, + "def": 70, + "spa": 80, + "spd": 140, + "spe": 70 + }, + "abilities": { + "0": "Swift Swim", + "1": "Water Absorb", + "H": "Water Veil" + }, + "heightm": 2.1, + "weightkg": 220, + "color": "Purple", + "prevo": "mantyke", + "evoLevel": 1, + "eggGroups": [ + "Water 1" + ] + }, + "skarmory": { + "num": 227, + "species": "Skarmory", + "types": [ + "Steel", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 80, + "def": 140, + "spa": 40, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Keen Eye", + "1": "Sturdy", + "H": "Weak Armor" + }, + "heightm": 1.7, + "weightkg": 50.5, + "color": "Gray", + "eggGroups": [ + "Flying" + ] + }, + "houndour": { + "num": 228, + "species": "Houndour", + "types": [ + "Dark", + "Fire" + ], + "baseStats": { + "hp": 45, + "atk": 60, + "def": 30, + "spa": 80, + "spd": 50, + "spe": 65 + }, + "abilities": { + "0": "Early Bird", + "1": "Flash Fire", + "H": "Unnerve" + }, + "heightm": 0.6, + "weightkg": 10.8, + "color": "Black", + "evos": [ + "houndoom" + ], + "eggGroups": [ + "Field" + ] + }, + "houndoom": { + "num": 229, + "species": "Houndoom", + "types": [ + "Dark", + "Fire" + ], + "baseStats": { + "hp": 75, + "atk": 90, + "def": 50, + "spa": 110, + "spd": 80, + "spe": 95 + }, + "abilities": { + "0": "Early Bird", + "1": "Flash Fire", + "H": "Unnerve" + }, + "heightm": 1.4, + "weightkg": 35, + "color": "Black", + "prevo": "houndour", + "evoLevel": 24, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "houndoommega" + ] + }, + "houndoommega": { + "num": 229, + "species": "Houndoom-Mega", + "baseSpecies": "Houndoom", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dark", + "Fire" + ], + "baseStats": { + "hp": 75, + "atk": 90, + "def": 90, + "spa": 140, + "spd": 90, + "spe": 115 + }, + "abilities": { + "0": "Solar Power" + }, + "heightm": 1.9, + "weightkg": 49.5, + "color": "Black", + "eggGroups": [ + "Field" + ] + }, + "kingdra": { + "num": 230, + "species": "Kingdra", + "types": [ + "Water", + "Dragon" + ], + "baseStats": { + "hp": 75, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 85 + }, + "abilities": { + "0": "Swift Swim", + "1": "Sniper", + "H": "Damp" + }, + "heightm": 1.8, + "weightkg": 152, + "color": "Blue", + "prevo": "seadra", + "evoLevel": 32, + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "phanpy": { + "num": 231, + "species": "Phanpy", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 90, + "atk": 60, + "def": 60, + "spa": 40, + "spd": 40, + "spe": 40 + }, + "abilities": { + "0": "Pickup", + "H": "Sand Veil" + }, + "heightm": 0.5, + "weightkg": 33.5, + "color": "Blue", + "evos": [ + "donphan" + ], + "eggGroups": [ + "Field" + ] + }, + "donphan": { + "num": 232, + "species": "Donphan", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 90, + "atk": 120, + "def": 120, + "spa": 60, + "spd": 60, + "spe": 50 + }, + "abilities": { + "0": "Sturdy", + "H": "Sand Veil" + }, + "heightm": 1.1, + "weightkg": 120, + "color": "Gray", + "prevo": "phanpy", + "evoLevel": 25, + "eggGroups": [ + "Field" + ] + }, + "porygon2": { + "num": 233, + "species": "Porygon2", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 85, + "atk": 80, + "def": 90, + "spa": 105, + "spd": 95, + "spe": 60 + }, + "abilities": { + "0": "Trace", + "1": "Download", + "H": "Analytic" + }, + "heightm": 0.6, + "weightkg": 32.5, + "color": "Red", + "prevo": "porygon", + "evos": [ + "porygonz" + ], + "evoLevel": 1, + "eggGroups": [ + "Mineral" + ] + }, + "stantler": { + "num": 234, + "species": "Stantler", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 73, + "atk": 95, + "def": 62, + "spa": 85, + "spd": 65, + "spe": 85 + }, + "abilities": { + "0": "Intimidate", + "1": "Frisk", + "H": "Sap Sipper" + }, + "heightm": 1.4, + "weightkg": 71.2, + "color": "Brown", + "eggGroups": [ + "Field" + ] + }, + "smeargle": { + "num": 235, + "species": "Smeargle", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 55, + "atk": 20, + "def": 35, + "spa": 20, + "spd": 45, + "spe": 75 + }, + "abilities": { + "0": "Own Tempo", + "1": "Technician", + "H": "Moody" + }, + "heightm": 1.2, + "weightkg": 58, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "tyrogue": { + "num": 236, + "species": "Tyrogue", + "types": [ + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 35, + "atk": 35, + "def": 35, + "spa": 35, + "spd": 35, + "spe": 35 + }, + "abilities": { + "0": "Guts", + "1": "Steadfast", + "H": "Vital Spirit" + }, + "heightm": 0.7, + "weightkg": 21, + "color": "Purple", + "evos": [ + "hitmonlee", + "hitmonchan", + "hitmontop" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "hitmontop": { + "num": 237, + "species": "Hitmontop", + "types": [ + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 50, + "atk": 95, + "def": 95, + "spa": 35, + "spd": 110, + "spe": 70 + }, + "abilities": { + "0": "Intimidate", + "1": "Technician", + "H": "Steadfast" + }, + "heightm": 1.4, + "weightkg": 48, + "color": "Brown", + "prevo": "tyrogue", + "evoLevel": 20, + "eggGroups": [ + "Human-Like" + ] + }, + "smoochum": { + "num": 238, + "species": "Smoochum", + "types": [ + "Ice", + "Psychic" + ], + "gender": "F", + "baseStats": { + "hp": 45, + "atk": 30, + "def": 15, + "spa": 85, + "spd": 65, + "spe": 65 + }, + "abilities": { + "0": "Oblivious", + "1": "Forewarn", + "H": "Hydration" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Pink", + "evos": [ + "jynx" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "elekid": { + "num": 239, + "species": "Elekid", + "types": [ + "Electric" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 45, + "atk": 63, + "def": 37, + "spa": 65, + "spd": 55, + "spe": 95 + }, + "abilities": { + "0": "Static", + "H": "Vital Spirit" + }, + "heightm": 0.6, + "weightkg": 23.5, + "color": "Yellow", + "evos": [ + "electabuzz" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "magby": { + "num": 240, + "species": "Magby", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 45, + "atk": 75, + "def": 37, + "spa": 70, + "spd": 55, + "spe": 83 + }, + "abilities": { + "0": "Flame Body", + "H": "Vital Spirit" + }, + "heightm": 0.7, + "weightkg": 21.4, + "color": "Red", + "evos": [ + "magmar" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "miltank": { + "num": 241, + "species": "Miltank", + "types": [ + "Normal" + ], + "gender": "F", + "baseStats": { + "hp": 95, + "atk": 80, + "def": 105, + "spa": 40, + "spd": 70, + "spe": 100 + }, + "abilities": { + "0": "Thick Fat", + "1": "Scrappy", + "H": "Sap Sipper" + }, + "heightm": 1.2, + "weightkg": 75.5, + "color": "Pink", + "eggGroups": [ + "Field" + ] + }, + "blissey": { + "num": 242, + "species": "Blissey", + "types": [ + "Normal" + ], + "gender": "F", + "baseStats": { + "hp": 255, + "atk": 10, + "def": 10, + "spa": 75, + "spd": 135, + "spe": 55 + }, + "abilities": { + "0": "Natural Cure", + "1": "Serene Grace", + "H": "Healer" + }, + "heightm": 1.5, + "weightkg": 46.8, + "color": "Pink", + "prevo": "chansey", + "evoLevel": 2, + "eggGroups": [ + "Fairy" + ] + }, + "raikou": { + "num": 243, + "species": "Raikou", + "types": [ + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 85, + "def": 75, + "spa": 115, + "spd": 100, + "spe": 115 + }, + "abilities": { + "0": "Pressure", + "H": "Inner Focus" + }, + "heightm": 1.9, + "weightkg": 178, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "entei": { + "num": 244, + "species": "Entei", + "types": [ + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 115, + "atk": 115, + "def": 85, + "spa": 90, + "spd": 75, + "spe": 100 + }, + "abilities": { + "0": "Pressure", + "H": "Inner Focus" + }, + "heightm": 2.1, + "weightkg": 198, + "color": "Brown", + "eggGroups": [ + "Undiscovered" + ] + }, + "suicune": { + "num": 245, + "species": "Suicune", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 75, + "def": 115, + "spa": 90, + "spd": 115, + "spe": 85 + }, + "abilities": { + "0": "Pressure", + "H": "Inner Focus" + }, + "heightm": 2, + "weightkg": 187, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "larvitar": { + "num": 246, + "species": "Larvitar", + "types": [ + "Rock", + "Ground" + ], + "baseStats": { + "hp": 50, + "atk": 64, + "def": 50, + "spa": 45, + "spd": 50, + "spe": 41 + }, + "abilities": { + "0": "Guts", + "H": "Sand Veil" + }, + "heightm": 0.6, + "weightkg": 72, + "color": "Green", + "evos": [ + "pupitar" + ], + "eggGroups": [ + "Monster" + ] + }, + "pupitar": { + "num": 247, + "species": "Pupitar", + "types": [ + "Rock", + "Ground" + ], + "baseStats": { + "hp": 70, + "atk": 84, + "def": 70, + "spa": 65, + "spd": 70, + "spe": 51 + }, + "abilities": { + "0": "Shed Skin" + }, + "heightm": 1.2, + "weightkg": 152, + "color": "Gray", + "prevo": "larvitar", + "evos": [ + "tyranitar" + ], + "evoLevel": 30, + "eggGroups": [ + "Monster" + ] + }, + "tyranitar": { + "num": 248, + "species": "Tyranitar", + "types": [ + "Rock", + "Dark" + ], + "baseStats": { + "hp": 100, + "atk": 134, + "def": 110, + "spa": 95, + "spd": 100, + "spe": 61 + }, + "abilities": { + "0": "Sand Stream", + "H": "Unnerve" + }, + "heightm": 2, + "weightkg": 202, + "color": "Green", + "prevo": "pupitar", + "evoLevel": 55, + "eggGroups": [ + "Monster" + ], + "otherFormes": [ + "tyranitarmega" + ] + }, + "tyranitarmega": { + "num": 248, + "species": "Tyranitar-Mega", + "baseSpecies": "Tyranitar", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Rock", + "Dark" + ], + "baseStats": { + "hp": 100, + "atk": 164, + "def": 150, + "spa": 95, + "spd": 120, + "spe": 71 + }, + "abilities": { + "0": "Sand Stream" + }, + "heightm": 2.5, + "weightkg": 255, + "color": "Green", + "eggGroups": [ + "Monster" + ] + }, + "lugia": { + "num": 249, + "species": "Lugia", + "types": [ + "Psychic", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 106, + "atk": 90, + "def": 130, + "spa": 90, + "spd": 154, + "spe": 110 + }, + "abilities": { + "0": "Pressure", + "H": "Multiscale" + }, + "heightm": 5.2, + "weightkg": 216, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "hooh": { + "num": 250, + "species": "Ho-Oh", + "types": [ + "Fire", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 106, + "atk": 130, + "def": 90, + "spa": 110, + "spd": 154, + "spe": 90 + }, + "abilities": { + "0": "Pressure", + "H": "Regenerator" + }, + "heightm": 3.8, + "weightkg": 199, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "celebi": { + "num": 251, + "species": "Celebi", + "types": [ + "Psychic", + "Grass" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 100, + "spa": 100, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Natural Cure" + }, + "heightm": 0.6, + "weightkg": 5, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "treecko": { + "num": 252, + "species": "Treecko", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 40, + "atk": 45, + "def": 35, + "spa": 65, + "spd": 55, + "spe": 70 + }, + "abilities": { + "0": "Overgrow", + "H": "Unburden" + }, + "heightm": 0.5, + "weightkg": 5, + "color": "Green", + "evos": [ + "grovyle" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "grovyle": { + "num": 253, + "species": "Grovyle", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 65, + "def": 45, + "spa": 85, + "spd": 65, + "spe": 95 + }, + "abilities": { + "0": "Overgrow", + "H": "Unburden" + }, + "heightm": 0.9, + "weightkg": 21.6, + "color": "Green", + "prevo": "treecko", + "evos": [ + "sceptile" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "sceptile": { + "num": 254, + "species": "Sceptile", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 70, + "atk": 85, + "def": 65, + "spa": 105, + "spd": 85, + "spe": 120 + }, + "abilities": { + "0": "Overgrow", + "H": "Unburden" + }, + "heightm": 1.7, + "weightkg": 52.2, + "color": "Green", + "prevo": "grovyle", + "evoLevel": 36, + "eggGroups": [ + "Monster", + "Dragon" + ], + "otherFormes": [ + "sceptilemega" + ] + }, + "sceptilemega": { + "num": 254, + "species": "Sceptile-Mega", + "baseSpecies": "Sceptile", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Grass", + "Dragon" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 70, + "atk": 110, + "def": 75, + "spa": 145, + "spd": 85, + "spe": 145 + }, + "abilities": { + "0": "Lightning Rod" + }, + "heightm": 1.9, + "weightkg": 55.2, + "color": "Green", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "torchic": { + "num": 255, + "species": "Torchic", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 45, + "atk": 60, + "def": 40, + "spa": 70, + "spd": 50, + "spe": 45 + }, + "abilities": { + "0": "Blaze", + "H": "Speed Boost" + }, + "heightm": 0.4, + "weightkg": 2.5, + "color": "Red", + "evos": [ + "combusken" + ], + "eggGroups": [ + "Field" + ] + }, + "combusken": { + "num": 256, + "species": "Combusken", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 85, + "def": 60, + "spa": 85, + "spd": 60, + "spe": 55 + }, + "abilities": { + "0": "Blaze", + "H": "Speed Boost" + }, + "heightm": 0.9, + "weightkg": 19.5, + "color": "Red", + "prevo": "torchic", + "evos": [ + "blaziken" + ], + "evoLevel": 16, + "eggGroups": [ + "Field" + ] + }, + "blaziken": { + "num": 257, + "species": "Blaziken", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 120, + "def": 70, + "spa": 110, + "spd": 70, + "spe": 80 + }, + "abilities": { + "0": "Blaze", + "H": "Speed Boost" + }, + "heightm": 1.9, + "weightkg": 52, + "color": "Red", + "prevo": "combusken", + "evoLevel": 36, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "blazikenmega" + ] + }, + "blazikenmega": { + "num": 257, + "species": "Blaziken-Mega", + "baseSpecies": "Blaziken", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 160, + "def": 80, + "spa": 130, + "spd": 80, + "spe": 100 + }, + "abilities": { + "0": "Speed Boost" + }, + "heightm": 1.9, + "weightkg": 52, + "color": "Red", + "eggGroups": [ + "Field" + ] + }, + "mudkip": { + "num": 258, + "species": "Mudkip", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 70, + "def": 50, + "spa": 50, + "spd": 50, + "spe": 40 + }, + "abilities": { + "0": "Torrent", + "H": "Damp" + }, + "heightm": 0.4, + "weightkg": 7.6, + "color": "Blue", + "evos": [ + "marshtomp" + ], + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "marshtomp": { + "num": 259, + "species": "Marshtomp", + "types": [ + "Water", + "Ground" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 70, + "atk": 85, + "def": 70, + "spa": 60, + "spd": 70, + "spe": 50 + }, + "abilities": { + "0": "Torrent", + "H": "Damp" + }, + "heightm": 0.7, + "weightkg": 28, + "color": "Blue", + "prevo": "mudkip", + "evos": [ + "swampert" + ], + "evoLevel": 16, + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "swampert": { + "num": 260, + "species": "Swampert", + "types": [ + "Water", + "Ground" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 100, + "atk": 110, + "def": 90, + "spa": 85, + "spd": 90, + "spe": 60 + }, + "abilities": { + "0": "Torrent", + "H": "Damp" + }, + "heightm": 1.5, + "weightkg": 81.9, + "color": "Blue", + "prevo": "marshtomp", + "evoLevel": 36, + "eggGroups": [ + "Monster", + "Water 1" + ], + "otherFormes": [ + "swampertmega" + ] + }, + "swampertmega": { + "num": 260, + "species": "Swampert-Mega", + "baseSpecies": "Swampert", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Water", + "Ground" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 100, + "atk": 150, + "def": 110, + "spa": 95, + "spd": 110, + "spe": 70 + }, + "abilities": { + "0": "Swift Swim" + }, + "heightm": 1.9, + "weightkg": 102, + "color": "Blue", + "eggGroups": [ + "Monster", + "Water 1" + ] + }, + "poochyena": { + "num": 261, + "species": "Poochyena", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 35, + "atk": 55, + "def": 35, + "spa": 30, + "spd": 30, + "spe": 35 + }, + "abilities": { + "0": "Run Away", + "1": "Quick Feet", + "H": "Rattled" + }, + "heightm": 0.5, + "weightkg": 13.6, + "color": "Gray", + "evos": [ + "mightyena" + ], + "eggGroups": [ + "Field" + ] + }, + "mightyena": { + "num": 262, + "species": "Mightyena", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 70, + "atk": 90, + "def": 70, + "spa": 60, + "spd": 60, + "spe": 70 + }, + "abilities": { + "0": "Intimidate", + "1": "Quick Feet", + "H": "Moxie" + }, + "heightm": 1, + "weightkg": 37, + "color": "Gray", + "prevo": "poochyena", + "evoLevel": 18, + "eggGroups": [ + "Field" + ] + }, + "zigzagoon": { + "num": 263, + "species": "Zigzagoon", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 38, + "atk": 30, + "def": 41, + "spa": 30, + "spd": 41, + "spe": 60 + }, + "abilities": { + "0": "Pickup", + "1": "Gluttony", + "H": "Quick Feet" + }, + "heightm": 0.4, + "weightkg": 17.5, + "color": "Brown", + "evos": [ + "linoone" + ], + "eggGroups": [ + "Field" + ] + }, + "linoone": { + "num": 264, + "species": "Linoone", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 78, + "atk": 70, + "def": 61, + "spa": 50, + "spd": 61, + "spe": 100 + }, + "abilities": { + "0": "Pickup", + "1": "Gluttony", + "H": "Quick Feet" + }, + "heightm": 0.5, + "weightkg": 32.5, + "color": "White", + "prevo": "zigzagoon", + "evoLevel": 20, + "eggGroups": [ + "Field" + ] + }, + "wurmple": { + "num": 265, + "species": "Wurmple", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 45, + "atk": 45, + "def": 35, + "spa": 20, + "spd": 30, + "spe": 20 + }, + "abilities": { + "0": "Shield Dust", + "H": "Run Away" + }, + "heightm": 0.3, + "weightkg": 3.6, + "color": "Red", + "evos": [ + "silcoon", + "cascoon" + ], + "eggGroups": [ + "Bug" + ] + }, + "silcoon": { + "num": 266, + "species": "Silcoon", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 50, + "atk": 35, + "def": 55, + "spa": 25, + "spd": 25, + "spe": 15 + }, + "abilities": { + "0": "Shed Skin" + }, + "heightm": 0.6, + "weightkg": 10, + "color": "White", + "prevo": "wurmple", + "evos": [ + "beautifly" + ], + "evoLevel": 7, + "eggGroups": [ + "Bug" + ] + }, + "beautifly": { + "num": 267, + "species": "Beautifly", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 70, + "def": 50, + "spa": 100, + "spd": 50, + "spe": 65 + }, + "abilities": { + "0": "Swarm", + "H": "Rivalry" + }, + "heightm": 1, + "weightkg": 28.4, + "color": "Yellow", + "prevo": "silcoon", + "evoLevel": 10, + "eggGroups": [ + "Bug" + ] + }, + "cascoon": { + "num": 268, + "species": "Cascoon", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 50, + "atk": 35, + "def": 55, + "spa": 25, + "spd": 25, + "spe": 15 + }, + "abilities": { + "0": "Shed Skin" + }, + "heightm": 0.7, + "weightkg": 11.5, + "color": "Purple", + "prevo": "wurmple", + "evos": [ + "dustox" + ], + "evoLevel": 7, + "eggGroups": [ + "Bug" + ] + }, + "dustox": { + "num": 269, + "species": "Dustox", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 50, + "def": 70, + "spa": 50, + "spd": 90, + "spe": 65 + }, + "abilities": { + "0": "Shield Dust", + "H": "Compound Eyes" + }, + "heightm": 1.2, + "weightkg": 31.6, + "color": "Green", + "prevo": "cascoon", + "evoLevel": 10, + "eggGroups": [ + "Bug" + ] + }, + "lotad": { + "num": 270, + "species": "Lotad", + "types": [ + "Water", + "Grass" + ], + "baseStats": { + "hp": 40, + "atk": 30, + "def": 30, + "spa": 40, + "spd": 50, + "spe": 30 + }, + "abilities": { + "0": "Swift Swim", + "1": "Rain Dish", + "H": "Own Tempo" + }, + "heightm": 0.5, + "weightkg": 2.6, + "color": "Green", + "evos": [ + "lombre" + ], + "eggGroups": [ + "Water 1", + "Grass" + ] + }, + "lombre": { + "num": 271, + "species": "Lombre", + "types": [ + "Water", + "Grass" + ], + "baseStats": { + "hp": 60, + "atk": 50, + "def": 50, + "spa": 60, + "spd": 70, + "spe": 50 + }, + "abilities": { + "0": "Swift Swim", + "1": "Rain Dish", + "H": "Own Tempo" + }, + "heightm": 1.2, + "weightkg": 32.5, + "color": "Green", + "prevo": "lotad", + "evos": [ + "ludicolo" + ], + "evoLevel": 14, + "eggGroups": [ + "Water 1", + "Grass" + ] + }, + "ludicolo": { + "num": 272, + "species": "Ludicolo", + "types": [ + "Water", + "Grass" + ], + "baseStats": { + "hp": 80, + "atk": 70, + "def": 70, + "spa": 90, + "spd": 100, + "spe": 70 + }, + "abilities": { + "0": "Swift Swim", + "1": "Rain Dish", + "H": "Own Tempo" + }, + "heightm": 1.5, + "weightkg": 55, + "color": "Green", + "prevo": "lombre", + "evoLevel": 14, + "eggGroups": [ + "Water 1", + "Grass" + ] + }, + "seedot": { + "num": 273, + "species": "Seedot", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 40, + "atk": 40, + "def": 50, + "spa": 30, + "spd": 30, + "spe": 30 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Early Bird", + "H": "Pickpocket" + }, + "heightm": 0.5, + "weightkg": 4, + "color": "Brown", + "evos": [ + "nuzleaf" + ], + "eggGroups": [ + "Field", + "Grass" + ] + }, + "nuzleaf": { + "num": 274, + "species": "Nuzleaf", + "types": [ + "Grass", + "Dark" + ], + "baseStats": { + "hp": 70, + "atk": 70, + "def": 40, + "spa": 60, + "spd": 40, + "spe": 60 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Early Bird", + "H": "Pickpocket" + }, + "heightm": 1, + "weightkg": 28, + "color": "Brown", + "prevo": "seedot", + "evos": [ + "shiftry" + ], + "evoLevel": 14, + "eggGroups": [ + "Field", + "Grass" + ] + }, + "shiftry": { + "num": 275, + "species": "Shiftry", + "types": [ + "Grass", + "Dark" + ], + "baseStats": { + "hp": 90, + "atk": 100, + "def": 60, + "spa": 90, + "spd": 60, + "spe": 80 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Early Bird", + "H": "Pickpocket" + }, + "heightm": 1.3, + "weightkg": 59.6, + "color": "Brown", + "prevo": "nuzleaf", + "evoLevel": 14, + "eggGroups": [ + "Field", + "Grass" + ] + }, + "taillow": { + "num": 276, + "species": "Taillow", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 55, + "def": 30, + "spa": 30, + "spd": 30, + "spe": 85 + }, + "abilities": { + "0": "Guts", + "H": "Scrappy" + }, + "heightm": 0.3, + "weightkg": 2.3, + "color": "Blue", + "evos": [ + "swellow" + ], + "eggGroups": [ + "Flying" + ] + }, + "swellow": { + "num": 277, + "species": "Swellow", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 85, + "def": 60, + "spa": 75, + "spd": 50, + "spe": 125 + }, + "abilities": { + "0": "Guts", + "H": "Scrappy" + }, + "heightm": 0.7, + "weightkg": 19.8, + "color": "Blue", + "prevo": "taillow", + "evoLevel": 22, + "eggGroups": [ + "Flying" + ] + }, + "wingull": { + "num": 278, + "species": "Wingull", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 30, + "def": 30, + "spa": 55, + "spd": 30, + "spe": 85 + }, + "abilities": { + "0": "Keen Eye", + "1": "Hydration", + "H": "Rain Dish" + }, + "heightm": 0.6, + "weightkg": 9.5, + "color": "White", + "evos": [ + "pelipper" + ], + "eggGroups": [ + "Water 1", + "Flying" + ] + }, + "pelipper": { + "num": 279, + "species": "Pelipper", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 60, + "atk": 50, + "def": 100, + "spa": 95, + "spd": 70, + "spe": 65 + }, + "abilities": { + "0": "Keen Eye", + "1": "Drizzle", + "H": "Rain Dish" + }, + "heightm": 1.2, + "weightkg": 28, + "color": "Yellow", + "prevo": "wingull", + "evoLevel": 25, + "eggGroups": [ + "Water 1", + "Flying" + ] + }, + "ralts": { + "num": 280, + "species": "Ralts", + "types": [ + "Psychic", + "Fairy" + ], + "baseStats": { + "hp": 28, + "atk": 25, + "def": 25, + "spa": 45, + "spd": 35, + "spe": 40 + }, + "abilities": { + "0": "Synchronize", + "1": "Trace", + "H": "Telepathy" + }, + "heightm": 0.4, + "weightkg": 6.6, + "color": "White", + "evos": [ + "kirlia" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "kirlia": { + "num": 281, + "species": "Kirlia", + "types": [ + "Psychic", + "Fairy" + ], + "baseStats": { + "hp": 38, + "atk": 35, + "def": 35, + "spa": 65, + "spd": 55, + "spe": 50 + }, + "abilities": { + "0": "Synchronize", + "1": "Trace", + "H": "Telepathy" + }, + "heightm": 0.8, + "weightkg": 20.2, + "color": "White", + "prevo": "ralts", + "evos": [ + "gardevoir", + "gallade" + ], + "evoLevel": 20, + "eggGroups": [ + "Amorphous" + ] + }, + "gardevoir": { + "num": 282, + "species": "Gardevoir", + "types": [ + "Psychic", + "Fairy" + ], + "baseStats": { + "hp": 68, + "atk": 65, + "def": 65, + "spa": 125, + "spd": 115, + "spe": 80 + }, + "abilities": { + "0": "Synchronize", + "1": "Trace", + "H": "Telepathy" + }, + "heightm": 1.6, + "weightkg": 48.4, + "color": "White", + "prevo": "kirlia", + "evoLevel": 30, + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "gardevoirmega" + ] + }, + "gardevoirmega": { + "num": 282, + "species": "Gardevoir-Mega", + "baseSpecies": "Gardevoir", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Psychic", + "Fairy" + ], + "baseStats": { + "hp": 68, + "atk": 85, + "def": 65, + "spa": 165, + "spd": 135, + "spe": 100 + }, + "abilities": { + "0": "Pixilate" + }, + "heightm": 1.6, + "weightkg": 48.4, + "color": "White", + "eggGroups": [ + "Amorphous" + ] + }, + "surskit": { + "num": 283, + "species": "Surskit", + "types": [ + "Bug", + "Water" + ], + "baseStats": { + "hp": 40, + "atk": 30, + "def": 32, + "spa": 50, + "spd": 52, + "spe": 65 + }, + "abilities": { + "0": "Swift Swim", + "H": "Rain Dish" + }, + "heightm": 0.5, + "weightkg": 1.7, + "color": "Blue", + "evos": [ + "masquerain" + ], + "eggGroups": [ + "Water 1", + "Bug" + ] + }, + "masquerain": { + "num": 284, + "species": "Masquerain", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 70, + "atk": 60, + "def": 62, + "spa": 100, + "spd": 82, + "spe": 80 + }, + "abilities": { + "0": "Intimidate", + "H": "Unnerve" + }, + "heightm": 0.8, + "weightkg": 3.6, + "color": "Blue", + "prevo": "surskit", + "evoLevel": 22, + "eggGroups": [ + "Water 1", + "Bug" + ] + }, + "shroomish": { + "num": 285, + "species": "Shroomish", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 60, + "atk": 40, + "def": 60, + "spa": 40, + "spd": 60, + "spe": 35 + }, + "abilities": { + "0": "Effect Spore", + "1": "Poison Heal", + "H": "Quick Feet" + }, + "heightm": 0.4, + "weightkg": 4.5, + "color": "Brown", + "evos": [ + "breloom" + ], + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "breloom": { + "num": 286, + "species": "Breloom", + "types": [ + "Grass", + "Fighting" + ], + "baseStats": { + "hp": 60, + "atk": 130, + "def": 80, + "spa": 60, + "spd": 60, + "spe": 70 + }, + "abilities": { + "0": "Effect Spore", + "1": "Poison Heal", + "H": "Technician" + }, + "heightm": 1.2, + "weightkg": 39.2, + "color": "Green", + "prevo": "shroomish", + "evoLevel": 23, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "slakoth": { + "num": 287, + "species": "Slakoth", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 60, + "spa": 35, + "spd": 35, + "spe": 30 + }, + "abilities": { + "0": "Truant" + }, + "heightm": 0.8, + "weightkg": 24, + "color": "Brown", + "evos": [ + "vigoroth" + ], + "eggGroups": [ + "Field" + ] + }, + "vigoroth": { + "num": 288, + "species": "Vigoroth", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 80, + "atk": 80, + "def": 80, + "spa": 55, + "spd": 55, + "spe": 90 + }, + "abilities": { + "0": "Vital Spirit" + }, + "heightm": 1.4, + "weightkg": 46.5, + "color": "White", + "prevo": "slakoth", + "evos": [ + "slaking" + ], + "evoLevel": 18, + "eggGroups": [ + "Field" + ] + }, + "slaking": { + "num": 289, + "species": "Slaking", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 150, + "atk": 160, + "def": 100, + "spa": 95, + "spd": 65, + "spe": 100 + }, + "abilities": { + "0": "Truant" + }, + "heightm": 2, + "weightkg": 130.5, + "color": "Brown", + "prevo": "vigoroth", + "evoLevel": 36, + "eggGroups": [ + "Field" + ] + }, + "nincada": { + "num": 290, + "species": "Nincada", + "types": [ + "Bug", + "Ground" + ], + "baseStats": { + "hp": 31, + "atk": 45, + "def": 90, + "spa": 30, + "spd": 30, + "spe": 40 + }, + "abilities": { + "0": "Compound Eyes", + "H": "Run Away" + }, + "heightm": 0.5, + "weightkg": 5.5, + "color": "Gray", + "evos": [ + "ninjask", + "shedinja" + ], + "eggGroups": [ + "Bug" + ] + }, + "ninjask": { + "num": 291, + "species": "Ninjask", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 61, + "atk": 90, + "def": 45, + "spa": 50, + "spd": 50, + "spe": 160 + }, + "abilities": { + "0": "Speed Boost", + "H": "Infiltrator" + }, + "heightm": 0.8, + "weightkg": 12, + "color": "Yellow", + "prevo": "nincada", + "evoLevel": 20, + "eggGroups": [ + "Bug" + ] + }, + "shedinja": { + "num": 292, + "species": "Shedinja", + "types": [ + "Bug", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 1, + "atk": 90, + "def": 45, + "spa": 30, + "spd": 30, + "spe": 40 + }, + "maxHP": 1, + "abilities": { + "0": "Wonder Guard" + }, + "heightm": 0.8, + "weightkg": 1.2, + "color": "Brown", + "prevo": "nincada", + "evoLevel": 20, + "eggGroups": [ + "Mineral" + ] + }, + "whismur": { + "num": 293, + "species": "Whismur", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 64, + "atk": 51, + "def": 23, + "spa": 51, + "spd": 23, + "spe": 28 + }, + "abilities": { + "0": "Soundproof", + "H": "Rattled" + }, + "heightm": 0.6, + "weightkg": 16.3, + "color": "Pink", + "evos": [ + "loudred" + ], + "eggGroups": [ + "Monster", + "Field" + ] + }, + "loudred": { + "num": 294, + "species": "Loudred", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 84, + "atk": 71, + "def": 43, + "spa": 71, + "spd": 43, + "spe": 48 + }, + "abilities": { + "0": "Soundproof", + "H": "Scrappy" + }, + "heightm": 1, + "weightkg": 40.5, + "color": "Blue", + "prevo": "whismur", + "evos": [ + "exploud" + ], + "evoLevel": 20, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "exploud": { + "num": 295, + "species": "Exploud", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 104, + "atk": 91, + "def": 63, + "spa": 91, + "spd": 73, + "spe": 68 + }, + "abilities": { + "0": "Soundproof", + "H": "Scrappy" + }, + "heightm": 1.5, + "weightkg": 84, + "color": "Blue", + "prevo": "loudred", + "evoLevel": 40, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "makuhita": { + "num": 296, + "species": "Makuhita", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 72, + "atk": 60, + "def": 30, + "spa": 20, + "spd": 30, + "spe": 25 + }, + "abilities": { + "0": "Thick Fat", + "1": "Guts", + "H": "Sheer Force" + }, + "heightm": 1, + "weightkg": 86.4, + "color": "Yellow", + "evos": [ + "hariyama" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "hariyama": { + "num": 297, + "species": "Hariyama", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 144, + "atk": 120, + "def": 60, + "spa": 40, + "spd": 60, + "spe": 50 + }, + "abilities": { + "0": "Thick Fat", + "1": "Guts", + "H": "Sheer Force" + }, + "heightm": 2.3, + "weightkg": 253.8, + "color": "Brown", + "prevo": "makuhita", + "evoLevel": 24, + "eggGroups": [ + "Human-Like" + ] + }, + "azurill": { + "num": 298, + "species": "Azurill", + "types": [ + "Normal", + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 50, + "atk": 20, + "def": 40, + "spa": 20, + "spd": 40, + "spe": 20 + }, + "abilities": { + "0": "Thick Fat", + "1": "Huge Power", + "H": "Sap Sipper" + }, + "heightm": 0.2, + "weightkg": 2, + "color": "Blue", + "evos": [ + "marill" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "nosepass": { + "num": 299, + "species": "Nosepass", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 30, + "atk": 45, + "def": 135, + "spa": 45, + "spd": 90, + "spe": 30 + }, + "abilities": { + "0": "Sturdy", + "1": "Magnet Pull", + "H": "Sand Force" + }, + "heightm": 1, + "weightkg": 97, + "color": "Gray", + "evos": [ + "probopass" + ], + "eggGroups": [ + "Mineral" + ] + }, + "skitty": { + "num": 300, + "species": "Skitty", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 50, + "atk": 45, + "def": 45, + "spa": 35, + "spd": 35, + "spe": 50 + }, + "abilities": { + "0": "Cute Charm", + "1": "Normalize", + "H": "Wonder Skin" + }, + "heightm": 0.6, + "weightkg": 11, + "color": "Pink", + "evos": [ + "delcatty" + ], + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "delcatty": { + "num": 301, + "species": "Delcatty", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 70, + "atk": 65, + "def": 65, + "spa": 55, + "spd": 55, + "spe": 90 + }, + "abilities": { + "0": "Cute Charm", + "1": "Normalize", + "H": "Wonder Skin" + }, + "heightm": 1.1, + "weightkg": 32.6, + "color": "Purple", + "prevo": "skitty", + "evoLevel": 1, + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "sableye": { + "num": 302, + "species": "Sableye", + "types": [ + "Dark", + "Ghost" + ], + "baseStats": { + "hp": 50, + "atk": 75, + "def": 75, + "spa": 65, + "spd": 65, + "spe": 50 + }, + "abilities": { + "0": "Keen Eye", + "1": "Stall", + "H": "Prankster" + }, + "heightm": 0.5, + "weightkg": 11, + "color": "Purple", + "eggGroups": [ + "Human-Like" + ], + "otherFormes": [ + "sableyemega" + ] + }, + "sableyemega": { + "num": 302, + "species": "Sableye-Mega", + "baseSpecies": "Sableye", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dark", + "Ghost" + ], + "baseStats": { + "hp": 50, + "atk": 85, + "def": 125, + "spa": 85, + "spd": 115, + "spe": 20 + }, + "abilities": { + "0": "Magic Bounce" + }, + "heightm": 0.5, + "weightkg": 161, + "color": "Purple", + "eggGroups": [ + "Human-Like" + ] + }, + "mawile": { + "num": 303, + "species": "Mawile", + "types": [ + "Steel", + "Fairy" + ], + "baseStats": { + "hp": 50, + "atk": 85, + "def": 85, + "spa": 55, + "spd": 55, + "spe": 50 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Intimidate", + "H": "Sheer Force" + }, + "heightm": 0.6, + "weightkg": 11.5, + "color": "Black", + "eggGroups": [ + "Field", + "Fairy" + ], + "otherFormes": [ + "mawilemega" + ] + }, + "mawilemega": { + "num": 303, + "species": "Mawile-Mega", + "baseSpecies": "Mawile", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Steel", + "Fairy" + ], + "baseStats": { + "hp": 50, + "atk": 105, + "def": 125, + "spa": 55, + "spd": 95, + "spe": 50 + }, + "abilities": { + "0": "Huge Power" + }, + "heightm": 1, + "weightkg": 23.5, + "color": "Black", + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "aron": { + "num": 304, + "species": "Aron", + "types": [ + "Steel", + "Rock" + ], + "baseStats": { + "hp": 50, + "atk": 70, + "def": 100, + "spa": 40, + "spd": 40, + "spe": 30 + }, + "abilities": { + "0": "Sturdy", + "1": "Rock Head", + "H": "Heavy Metal" + }, + "heightm": 0.4, + "weightkg": 60, + "color": "Gray", + "evos": [ + "lairon" + ], + "eggGroups": [ + "Monster" + ] + }, + "lairon": { + "num": 305, + "species": "Lairon", + "types": [ + "Steel", + "Rock" + ], + "baseStats": { + "hp": 60, + "atk": 90, + "def": 140, + "spa": 50, + "spd": 50, + "spe": 40 + }, + "abilities": { + "0": "Sturdy", + "1": "Rock Head", + "H": "Heavy Metal" + }, + "heightm": 0.9, + "weightkg": 120, + "color": "Gray", + "prevo": "aron", + "evos": [ + "aggron" + ], + "evoLevel": 32, + "eggGroups": [ + "Monster" + ] + }, + "aggron": { + "num": 306, + "species": "Aggron", + "types": [ + "Steel", + "Rock" + ], + "baseStats": { + "hp": 70, + "atk": 110, + "def": 180, + "spa": 60, + "spd": 60, + "spe": 50 + }, + "abilities": { + "0": "Sturdy", + "1": "Rock Head", + "H": "Heavy Metal" + }, + "heightm": 2.1, + "weightkg": 360, + "color": "Gray", + "prevo": "lairon", + "evoLevel": 42, + "eggGroups": [ + "Monster" + ], + "otherFormes": [ + "aggronmega" + ] + }, + "aggronmega": { + "num": 306, + "species": "Aggron-Mega", + "baseSpecies": "Aggron", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Steel" + ], + "baseStats": { + "hp": 70, + "atk": 140, + "def": 230, + "spa": 60, + "spd": 80, + "spe": 50 + }, + "abilities": { + "0": "Filter" + }, + "heightm": 2.2, + "weightkg": 395, + "color": "Gray", + "eggGroups": [ + "Monster" + ] + }, + "meditite": { + "num": 307, + "species": "Meditite", + "types": [ + "Fighting", + "Psychic" + ], + "baseStats": { + "hp": 30, + "atk": 40, + "def": 55, + "spa": 40, + "spd": 55, + "spe": 60 + }, + "abilities": { + "0": "Pure Power", + "H": "Telepathy" + }, + "heightm": 0.6, + "weightkg": 11.2, + "color": "Blue", + "evos": [ + "medicham" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "medicham": { + "num": 308, + "species": "Medicham", + "types": [ + "Fighting", + "Psychic" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 75, + "spa": 60, + "spd": 75, + "spe": 80 + }, + "abilities": { + "0": "Pure Power", + "H": "Telepathy" + }, + "heightm": 1.3, + "weightkg": 31.5, + "color": "Red", + "prevo": "meditite", + "evoLevel": 37, + "eggGroups": [ + "Human-Like" + ], + "otherFormes": [ + "medichammega" + ] + }, + "medichammega": { + "num": 308, + "species": "Medicham-Mega", + "baseSpecies": "Medicham", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Fighting", + "Psychic" + ], + "baseStats": { + "hp": 60, + "atk": 100, + "def": 85, + "spa": 80, + "spd": 85, + "spe": 100 + }, + "abilities": { + "0": "Pure Power" + }, + "heightm": 1.3, + "weightkg": 31.5, + "color": "Red", + "eggGroups": [ + "Human-Like" + ] + }, + "electrike": { + "num": 309, + "species": "Electrike", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 40, + "atk": 45, + "def": 40, + "spa": 65, + "spd": 40, + "spe": 65 + }, + "abilities": { + "0": "Static", + "1": "Lightning Rod", + "H": "Minus" + }, + "heightm": 0.6, + "weightkg": 15.2, + "color": "Green", + "evos": [ + "manectric" + ], + "eggGroups": [ + "Field" + ] + }, + "manectric": { + "num": 310, + "species": "Manectric", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 70, + "atk": 75, + "def": 60, + "spa": 105, + "spd": 60, + "spe": 105 + }, + "abilities": { + "0": "Static", + "1": "Lightning Rod", + "H": "Minus" + }, + "heightm": 1.5, + "weightkg": 40.2, + "color": "Yellow", + "prevo": "electrike", + "evoLevel": 26, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "manectricmega" + ] + }, + "manectricmega": { + "num": 310, + "species": "Manectric-Mega", + "baseSpecies": "Manectric", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 70, + "atk": 75, + "def": 80, + "spa": 135, + "spd": 80, + "spe": 135 + }, + "abilities": { + "0": "Intimidate" + }, + "heightm": 1.8, + "weightkg": 44, + "color": "Yellow", + "eggGroups": [ + "Field" + ] + }, + "plusle": { + "num": 311, + "species": "Plusle", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 60, + "atk": 50, + "def": 40, + "spa": 85, + "spd": 75, + "spe": 95 + }, + "abilities": { + "0": "Plus", + "H": "Lightning Rod" + }, + "heightm": 0.4, + "weightkg": 4.2, + "color": "Yellow", + "eggGroups": [ + "Fairy" + ] + }, + "minun": { + "num": 312, + "species": "Minun", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 60, + "atk": 40, + "def": 50, + "spa": 75, + "spd": 85, + "spe": 95 + }, + "abilities": { + "0": "Minus", + "H": "Volt Absorb" + }, + "heightm": 0.4, + "weightkg": 4.2, + "color": "Yellow", + "eggGroups": [ + "Fairy" + ] + }, + "volbeat": { + "num": 313, + "species": "Volbeat", + "types": [ + "Bug" + ], + "gender": "M", + "baseStats": { + "hp": 65, + "atk": 73, + "def": 75, + "spa": 47, + "spd": 85, + "spe": 85 + }, + "abilities": { + "0": "Illuminate", + "1": "Swarm", + "H": "Prankster" + }, + "heightm": 0.7, + "weightkg": 17.7, + "color": "Gray", + "eggGroups": [ + "Bug", + "Human-Like" + ] + }, + "illumise": { + "num": 314, + "species": "Illumise", + "types": [ + "Bug" + ], + "gender": "F", + "baseStats": { + "hp": 65, + "atk": 47, + "def": 75, + "spa": 73, + "spd": 85, + "spe": 85 + }, + "abilities": { + "0": "Oblivious", + "1": "Tinted Lens", + "H": "Prankster" + }, + "heightm": 0.6, + "weightkg": 17.7, + "color": "Purple", + "eggGroups": [ + "Bug", + "Human-Like" + ] + }, + "roselia": { + "num": 315, + "species": "Roselia", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 50, + "atk": 60, + "def": 45, + "spa": 100, + "spd": 80, + "spe": 65 + }, + "abilities": { + "0": "Natural Cure", + "1": "Poison Point", + "H": "Leaf Guard" + }, + "heightm": 0.3, + "weightkg": 2, + "color": "Green", + "prevo": "budew", + "evos": [ + "roserade" + ], + "evoLevel": 1, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "gulpin": { + "num": 316, + "species": "Gulpin", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 70, + "atk": 43, + "def": 53, + "spa": 43, + "spd": 53, + "spe": 40 + }, + "abilities": { + "0": "Liquid Ooze", + "1": "Sticky Hold", + "H": "Gluttony" + }, + "heightm": 0.4, + "weightkg": 10.3, + "color": "Green", + "evos": [ + "swalot" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "swalot": { + "num": 317, + "species": "Swalot", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 100, + "atk": 73, + "def": 83, + "spa": 73, + "spd": 83, + "spe": 55 + }, + "abilities": { + "0": "Liquid Ooze", + "1": "Sticky Hold", + "H": "Gluttony" + }, + "heightm": 1.7, + "weightkg": 80, + "color": "Purple", + "prevo": "gulpin", + "evoLevel": 26, + "eggGroups": [ + "Amorphous" + ] + }, + "carvanha": { + "num": 318, + "species": "Carvanha", + "types": [ + "Water", + "Dark" + ], + "baseStats": { + "hp": 45, + "atk": 90, + "def": 20, + "spa": 65, + "spd": 20, + "spe": 65 + }, + "abilities": { + "0": "Rough Skin", + "H": "Speed Boost" + }, + "heightm": 0.8, + "weightkg": 20.8, + "color": "Red", + "evos": [ + "sharpedo" + ], + "eggGroups": [ + "Water 2" + ] + }, + "sharpedo": { + "num": 319, + "species": "Sharpedo", + "types": [ + "Water", + "Dark" + ], + "baseStats": { + "hp": 70, + "atk": 120, + "def": 40, + "spa": 95, + "spd": 40, + "spe": 95 + }, + "abilities": { + "0": "Rough Skin", + "H": "Speed Boost" + }, + "heightm": 1.8, + "weightkg": 88.8, + "color": "Blue", + "prevo": "carvanha", + "evoLevel": 30, + "eggGroups": [ + "Water 2" + ], + "otherFormes": [ + "sharpedomega" + ] + }, + "sharpedomega": { + "num": 319, + "species": "Sharpedo-Mega", + "baseSpecies": "Sharpedo", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Water", + "Dark" + ], + "baseStats": { + "hp": 70, + "atk": 140, + "def": 70, + "spa": 110, + "spd": 65, + "spe": 105 + }, + "abilities": { + "0": "Strong Jaw" + }, + "heightm": 2.5, + "weightkg": 130.3, + "color": "Blue", + "eggGroups": [ + "Water 2" + ] + }, + "wailmer": { + "num": 320, + "species": "Wailmer", + "types": [ + "Water" + ], + "baseStats": { + "hp": 130, + "atk": 70, + "def": 35, + "spa": 70, + "spd": 35, + "spe": 60 + }, + "abilities": { + "0": "Water Veil", + "1": "Oblivious", + "H": "Pressure" + }, + "heightm": 2, + "weightkg": 130, + "color": "Blue", + "evos": [ + "wailord" + ], + "eggGroups": [ + "Field", + "Water 2" + ] + }, + "wailord": { + "num": 321, + "species": "Wailord", + "types": [ + "Water" + ], + "baseStats": { + "hp": 170, + "atk": 90, + "def": 45, + "spa": 90, + "spd": 45, + "spe": 60 + }, + "abilities": { + "0": "Water Veil", + "1": "Oblivious", + "H": "Pressure" + }, + "heightm": 14.5, + "weightkg": 398, + "color": "Blue", + "prevo": "wailmer", + "evoLevel": 40, + "eggGroups": [ + "Field", + "Water 2" + ] + }, + "numel": { + "num": 322, + "species": "Numel", + "types": [ + "Fire", + "Ground" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 40, + "spa": 65, + "spd": 45, + "spe": 35 + }, + "abilities": { + "0": "Oblivious", + "1": "Simple", + "H": "Own Tempo" + }, + "heightm": 0.7, + "weightkg": 24, + "color": "Yellow", + "evos": [ + "camerupt" + ], + "eggGroups": [ + "Field" + ] + }, + "camerupt": { + "num": 323, + "species": "Camerupt", + "types": [ + "Fire", + "Ground" + ], + "baseStats": { + "hp": 70, + "atk": 100, + "def": 70, + "spa": 105, + "spd": 75, + "spe": 40 + }, + "abilities": { + "0": "Magma Armor", + "1": "Solid Rock", + "H": "Anger Point" + }, + "heightm": 1.9, + "weightkg": 220, + "color": "Red", + "prevo": "numel", + "evoLevel": 33, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "cameruptmega" + ] + }, + "cameruptmega": { + "num": 323, + "species": "Camerupt-Mega", + "baseSpecies": "Camerupt", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Fire", + "Ground" + ], + "baseStats": { + "hp": 70, + "atk": 120, + "def": 100, + "spa": 145, + "spd": 105, + "spe": 20 + }, + "abilities": { + "0": "Sheer Force" + }, + "heightm": 2.5, + "weightkg": 320.5, + "color": "Red", + "eggGroups": [ + "Field" + ] + }, + "torkoal": { + "num": 324, + "species": "Torkoal", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 70, + "atk": 85, + "def": 140, + "spa": 85, + "spd": 70, + "spe": 20 + }, + "abilities": { + "0": "White Smoke", + "1": "Drought", + "H": "Shell Armor" + }, + "heightm": 0.5, + "weightkg": 80.4, + "color": "Brown", + "eggGroups": [ + "Field" + ] + }, + "spoink": { + "num": 325, + "species": "Spoink", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 60, + "atk": 25, + "def": 35, + "spa": 70, + "spd": 80, + "spe": 60 + }, + "abilities": { + "0": "Thick Fat", + "1": "Own Tempo", + "H": "Gluttony" + }, + "heightm": 0.7, + "weightkg": 30.6, + "color": "Black", + "evos": [ + "grumpig" + ], + "eggGroups": [ + "Field" + ] + }, + "grumpig": { + "num": 326, + "species": "Grumpig", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 80, + "atk": 45, + "def": 65, + "spa": 90, + "spd": 110, + "spe": 80 + }, + "abilities": { + "0": "Thick Fat", + "1": "Own Tempo", + "H": "Gluttony" + }, + "heightm": 0.9, + "weightkg": 71.5, + "color": "Purple", + "prevo": "spoink", + "evoLevel": 32, + "eggGroups": [ + "Field" + ] + }, + "spinda": { + "num": 327, + "species": "Spinda", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 60, + "spa": 60, + "spd": 60, + "spe": 60 + }, + "abilities": { + "0": "Own Tempo", + "1": "Tangled Feet", + "H": "Contrary" + }, + "heightm": 1.1, + "weightkg": 5, + "color": "Brown", + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "trapinch": { + "num": 328, + "species": "Trapinch", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 45, + "atk": 100, + "def": 45, + "spa": 45, + "spd": 45, + "spe": 10 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Arena Trap", + "H": "Sheer Force" + }, + "heightm": 0.7, + "weightkg": 15, + "color": "Brown", + "evos": [ + "vibrava" + ], + "eggGroups": [ + "Bug" + ] + }, + "vibrava": { + "num": 329, + "species": "Vibrava", + "types": [ + "Ground", + "Dragon" + ], + "baseStats": { + "hp": 50, + "atk": 70, + "def": 50, + "spa": 50, + "spd": 50, + "spe": 70 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.1, + "weightkg": 15.3, + "color": "Green", + "prevo": "trapinch", + "evos": [ + "flygon" + ], + "evoLevel": 35, + "eggGroups": [ + "Bug" + ] + }, + "flygon": { + "num": 330, + "species": "Flygon", + "types": [ + "Ground", + "Dragon" + ], + "baseStats": { + "hp": 80, + "atk": 100, + "def": 80, + "spa": 80, + "spd": 80, + "spe": 100 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 2, + "weightkg": 82, + "color": "Green", + "prevo": "vibrava", + "evoLevel": 45, + "eggGroups": [ + "Bug" + ] + }, + "cacnea": { + "num": 331, + "species": "Cacnea", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 50, + "atk": 85, + "def": 40, + "spa": 85, + "spd": 40, + "spe": 35 + }, + "abilities": { + "0": "Sand Veil", + "H": "Water Absorb" + }, + "heightm": 0.4, + "weightkg": 51.3, + "color": "Green", + "evos": [ + "cacturne" + ], + "eggGroups": [ + "Grass", + "Human-Like" + ] + }, + "cacturne": { + "num": 332, + "species": "Cacturne", + "types": [ + "Grass", + "Dark" + ], + "baseStats": { + "hp": 70, + "atk": 115, + "def": 60, + "spa": 115, + "spd": 60, + "spe": 55 + }, + "abilities": { + "0": "Sand Veil", + "H": "Water Absorb" + }, + "heightm": 1.3, + "weightkg": 77.4, + "color": "Green", + "prevo": "cacnea", + "evoLevel": 32, + "eggGroups": [ + "Grass", + "Human-Like" + ] + }, + "swablu": { + "num": 333, + "species": "Swablu", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 45, + "atk": 40, + "def": 60, + "spa": 40, + "spd": 75, + "spe": 50 + }, + "abilities": { + "0": "Natural Cure", + "H": "Cloud Nine" + }, + "heightm": 0.4, + "weightkg": 1.2, + "color": "Blue", + "evos": [ + "altaria" + ], + "eggGroups": [ + "Flying", + "Dragon" + ] + }, + "altaria": { + "num": 334, + "species": "Altaria", + "types": [ + "Dragon", + "Flying" + ], + "baseStats": { + "hp": 75, + "atk": 70, + "def": 90, + "spa": 70, + "spd": 105, + "spe": 80 + }, + "abilities": { + "0": "Natural Cure", + "H": "Cloud Nine" + }, + "heightm": 1.1, + "weightkg": 20.6, + "color": "Blue", + "prevo": "swablu", + "evoLevel": 35, + "eggGroups": [ + "Flying", + "Dragon" + ], + "otherFormes": [ + "altariamega" + ] + }, + "altariamega": { + "num": 334, + "species": "Altaria-Mega", + "baseSpecies": "Altaria", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dragon", + "Fairy" + ], + "baseStats": { + "hp": 75, + "atk": 110, + "def": 110, + "spa": 110, + "spd": 105, + "spe": 80 + }, + "abilities": { + "0": "Pixilate" + }, + "heightm": 1.5, + "weightkg": 20.6, + "color": "Blue", + "eggGroups": [ + "Flying", + "Dragon" + ] + }, + "zangoose": { + "num": 335, + "species": "Zangoose", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 73, + "atk": 115, + "def": 60, + "spa": 60, + "spd": 60, + "spe": 90 + }, + "abilities": { + "0": "Immunity", + "H": "Toxic Boost" + }, + "heightm": 1.3, + "weightkg": 40.3, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "seviper": { + "num": 336, + "species": "Seviper", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 73, + "atk": 100, + "def": 60, + "spa": 100, + "spd": 60, + "spe": 65 + }, + "abilities": { + "0": "Shed Skin", + "H": "Infiltrator" + }, + "heightm": 2.7, + "weightkg": 52.5, + "color": "Black", + "eggGroups": [ + "Field", + "Dragon" + ] + }, + "lunatone": { + "num": 337, + "species": "Lunatone", + "types": [ + "Rock", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 55, + "def": 65, + "spa": 95, + "spd": 85, + "spe": 70 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1, + "weightkg": 168, + "color": "Yellow", + "eggGroups": [ + "Mineral" + ] + }, + "solrock": { + "num": 338, + "species": "Solrock", + "types": [ + "Rock", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 95, + "def": 85, + "spa": 55, + "spd": 65, + "spe": 70 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.2, + "weightkg": 154, + "color": "Red", + "eggGroups": [ + "Mineral" + ] + }, + "barboach": { + "num": 339, + "species": "Barboach", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 50, + "atk": 48, + "def": 43, + "spa": 46, + "spd": 41, + "spe": 60 + }, + "abilities": { + "0": "Oblivious", + "1": "Anticipation", + "H": "Hydration" + }, + "heightm": 0.4, + "weightkg": 1.9, + "color": "Gray", + "evos": [ + "whiscash" + ], + "eggGroups": [ + "Water 2" + ] + }, + "whiscash": { + "num": 340, + "species": "Whiscash", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 110, + "atk": 78, + "def": 73, + "spa": 76, + "spd": 71, + "spe": 60 + }, + "abilities": { + "0": "Oblivious", + "1": "Anticipation", + "H": "Hydration" + }, + "heightm": 0.9, + "weightkg": 23.6, + "color": "Blue", + "prevo": "barboach", + "evoLevel": 30, + "eggGroups": [ + "Water 2" + ] + }, + "corphish": { + "num": 341, + "species": "Corphish", + "types": [ + "Water" + ], + "baseStats": { + "hp": 43, + "atk": 80, + "def": 65, + "spa": 50, + "spd": 35, + "spe": 35 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Shell Armor", + "H": "Adaptability" + }, + "heightm": 0.6, + "weightkg": 11.5, + "color": "Red", + "evos": [ + "crawdaunt" + ], + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "crawdaunt": { + "num": 342, + "species": "Crawdaunt", + "types": [ + "Water", + "Dark" + ], + "baseStats": { + "hp": 63, + "atk": 120, + "def": 85, + "spa": 90, + "spd": 55, + "spe": 55 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Shell Armor", + "H": "Adaptability" + }, + "heightm": 1.1, + "weightkg": 32.8, + "color": "Red", + "prevo": "corphish", + "evoLevel": 30, + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "baltoy": { + "num": 343, + "species": "Baltoy", + "types": [ + "Ground", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 40, + "atk": 40, + "def": 55, + "spa": 40, + "spd": 70, + "spe": 55 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.5, + "weightkg": 21.5, + "color": "Brown", + "evos": [ + "claydol" + ], + "eggGroups": [ + "Mineral" + ] + }, + "claydol": { + "num": 344, + "species": "Claydol", + "types": [ + "Ground", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 70, + "def": 105, + "spa": 70, + "spd": 120, + "spe": 75 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.5, + "weightkg": 108, + "color": "Black", + "prevo": "baltoy", + "evoLevel": 36, + "eggGroups": [ + "Mineral" + ] + }, + "lileep": { + "num": 345, + "species": "Lileep", + "types": [ + "Rock", + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 66, + "atk": 41, + "def": 77, + "spa": 61, + "spd": 87, + "spe": 23 + }, + "abilities": { + "0": "Suction Cups", + "H": "Storm Drain" + }, + "heightm": 1, + "weightkg": 23.8, + "color": "Purple", + "evos": [ + "cradily" + ], + "eggGroups": [ + "Water 3" + ] + }, + "cradily": { + "num": 346, + "species": "Cradily", + "types": [ + "Rock", + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 86, + "atk": 81, + "def": 97, + "spa": 81, + "spd": 107, + "spe": 43 + }, + "abilities": { + "0": "Suction Cups", + "H": "Storm Drain" + }, + "heightm": 1.5, + "weightkg": 60.4, + "color": "Green", + "prevo": "lileep", + "evoLevel": 40, + "eggGroups": [ + "Water 3" + ] + }, + "anorith": { + "num": 347, + "species": "Anorith", + "types": [ + "Rock", + "Bug" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 45, + "atk": 95, + "def": 50, + "spa": 40, + "spd": 50, + "spe": 75 + }, + "abilities": { + "0": "Battle Armor", + "H": "Swift Swim" + }, + "heightm": 0.7, + "weightkg": 12.5, + "color": "Gray", + "evos": [ + "armaldo" + ], + "eggGroups": [ + "Water 3" + ] + }, + "armaldo": { + "num": 348, + "species": "Armaldo", + "types": [ + "Rock", + "Bug" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 125, + "def": 100, + "spa": 70, + "spd": 80, + "spe": 45 + }, + "abilities": { + "0": "Battle Armor", + "H": "Swift Swim" + }, + "heightm": 1.5, + "weightkg": 68.2, + "color": "Gray", + "prevo": "anorith", + "evoLevel": 40, + "eggGroups": [ + "Water 3" + ] + }, + "feebas": { + "num": 349, + "species": "Feebas", + "types": [ + "Water" + ], + "baseStats": { + "hp": 20, + "atk": 15, + "def": 20, + "spa": 10, + "spd": 55, + "spe": 80 + }, + "abilities": { + "0": "Swift Swim", + "1": "Oblivious", + "H": "Adaptability" + }, + "heightm": 0.6, + "weightkg": 7.4, + "color": "Brown", + "evos": [ + "milotic" + ], + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "milotic": { + "num": 350, + "species": "Milotic", + "types": [ + "Water" + ], + "baseStats": { + "hp": 95, + "atk": 60, + "def": 79, + "spa": 100, + "spd": 125, + "spe": 81 + }, + "abilities": { + "0": "Marvel Scale", + "1": "Competitive", + "H": "Cute Charm" + }, + "heightm": 6.2, + "weightkg": 162, + "color": "Pink", + "prevo": "feebas", + "evoLevel": 1, + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "castform": { + "num": 351, + "species": "Castform", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 70, + "atk": 70, + "def": 70, + "spa": 70, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Forecast" + }, + "heightm": 0.3, + "weightkg": 0.8, + "color": "White", + "eggGroups": [ + "Fairy", + "Amorphous" + ], + "otherFormes": [ + "castformsunny", + "castformrainy", + "castformsnowy" + ] + }, + "castformsunny": { + "num": 351, + "species": "Castform-Sunny", + "baseSpecies": "Castform", + "forme": "Sunny", + "formeLetter": "S", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 70, + "atk": 70, + "def": 70, + "spa": 70, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Forecast" + }, + "heightm": 0.3, + "weightkg": 0.8, + "color": "White", + "eggGroups": [ + "Fairy", + "Amorphous" + ] + }, + "castformrainy": { + "num": 351, + "species": "Castform-Rainy", + "baseSpecies": "Castform", + "forme": "Rainy", + "formeLetter": "R", + "types": [ + "Water" + ], + "baseStats": { + "hp": 70, + "atk": 70, + "def": 70, + "spa": 70, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Forecast" + }, + "heightm": 0.3, + "weightkg": 0.8, + "color": "White", + "eggGroups": [ + "Fairy", + "Amorphous" + ] + }, + "castformsnowy": { + "num": 351, + "species": "Castform-Snowy", + "baseSpecies": "Castform", + "forme": "Snowy", + "formeLetter": "S", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 70, + "atk": 70, + "def": 70, + "spa": 70, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Forecast" + }, + "heightm": 0.3, + "weightkg": 0.8, + "color": "White", + "eggGroups": [ + "Fairy", + "Amorphous" + ] + }, + "kecleon": { + "num": 352, + "species": "Kecleon", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 60, + "atk": 90, + "def": 70, + "spa": 60, + "spd": 120, + "spe": 40 + }, + "abilities": { + "0": "Color Change", + "H": "Protean" + }, + "heightm": 1, + "weightkg": 22, + "color": "Green", + "eggGroups": [ + "Field" + ] + }, + "shuppet": { + "num": 353, + "species": "Shuppet", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 44, + "atk": 75, + "def": 35, + "spa": 63, + "spd": 33, + "spe": 45 + }, + "abilities": { + "0": "Insomnia", + "1": "Frisk", + "H": "Cursed Body" + }, + "heightm": 0.6, + "weightkg": 2.3, + "color": "Black", + "evos": [ + "banette" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "banette": { + "num": 354, + "species": "Banette", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 64, + "atk": 115, + "def": 65, + "spa": 83, + "spd": 63, + "spe": 65 + }, + "abilities": { + "0": "Insomnia", + "1": "Frisk", + "H": "Cursed Body" + }, + "heightm": 1.1, + "weightkg": 12.5, + "color": "Black", + "prevo": "shuppet", + "evoLevel": 37, + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "banettemega" + ] + }, + "banettemega": { + "num": 354, + "species": "Banette-Mega", + "baseSpecies": "Banette", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 64, + "atk": 165, + "def": 75, + "spa": 93, + "spd": 83, + "spe": 75 + }, + "abilities": { + "0": "Prankster" + }, + "heightm": 1.2, + "weightkg": 13, + "color": "Black", + "eggGroups": [ + "Amorphous" + ] + }, + "duskull": { + "num": 355, + "species": "Duskull", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 20, + "atk": 40, + "def": 90, + "spa": 30, + "spd": 90, + "spe": 25 + }, + "abilities": { + "0": "Levitate", + "H": "Frisk" + }, + "heightm": 0.8, + "weightkg": 15, + "color": "Black", + "evos": [ + "dusclops" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "dusclops": { + "num": 356, + "species": "Dusclops", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 40, + "atk": 70, + "def": 130, + "spa": 60, + "spd": 130, + "spe": 25 + }, + "abilities": { + "0": "Pressure", + "H": "Frisk" + }, + "heightm": 1.6, + "weightkg": 30.6, + "color": "Black", + "prevo": "duskull", + "evos": [ + "dusknoir" + ], + "evoLevel": 37, + "eggGroups": [ + "Amorphous" + ] + }, + "tropius": { + "num": 357, + "species": "Tropius", + "types": [ + "Grass", + "Flying" + ], + "baseStats": { + "hp": 99, + "atk": 68, + "def": 83, + "spa": 72, + "spd": 87, + "spe": 51 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Solar Power", + "H": "Harvest" + }, + "heightm": 2, + "weightkg": 100, + "color": "Green", + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "chimecho": { + "num": 358, + "species": "Chimecho", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 75, + "atk": 50, + "def": 80, + "spa": 95, + "spd": 90, + "spe": 65 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.6, + "weightkg": 1, + "color": "Blue", + "prevo": "chingling", + "evoLevel": 1, + "eggGroups": [ + "Amorphous" + ] + }, + "absol": { + "num": 359, + "species": "Absol", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 65, + "atk": 130, + "def": 60, + "spa": 75, + "spd": 60, + "spe": 75 + }, + "abilities": { + "0": "Pressure", + "1": "Super Luck", + "H": "Justified" + }, + "heightm": 1.2, + "weightkg": 47, + "color": "White", + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "absolmega" + ] + }, + "absolmega": { + "num": 359, + "species": "Absol-Mega", + "baseSpecies": "Absol", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 65, + "atk": 150, + "def": 60, + "spa": 115, + "spd": 60, + "spe": 115 + }, + "abilities": { + "0": "Magic Bounce" + }, + "heightm": 1.2, + "weightkg": 49, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "wynaut": { + "num": 360, + "species": "Wynaut", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 95, + "atk": 23, + "def": 48, + "spa": 23, + "spd": 48, + "spe": 23 + }, + "abilities": { + "0": "Shadow Tag", + "H": "Telepathy" + }, + "heightm": 0.6, + "weightkg": 14, + "color": "Blue", + "evos": [ + "wobbuffet" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "snorunt": { + "num": 361, + "species": "Snorunt", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 50, + "atk": 50, + "def": 50, + "spa": 50, + "spd": 50, + "spe": 50 + }, + "abilities": { + "0": "Inner Focus", + "1": "Ice Body", + "H": "Moody" + }, + "heightm": 0.7, + "weightkg": 16.8, + "color": "Gray", + "evos": [ + "glalie", + "froslass" + ], + "eggGroups": [ + "Fairy", + "Mineral" + ] + }, + "glalie": { + "num": 362, + "species": "Glalie", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 80, + "atk": 80, + "def": 80, + "spa": 80, + "spd": 80, + "spe": 80 + }, + "abilities": { + "0": "Inner Focus", + "1": "Ice Body", + "H": "Moody" + }, + "heightm": 1.5, + "weightkg": 256.5, + "color": "Gray", + "prevo": "snorunt", + "evoLevel": 42, + "eggGroups": [ + "Fairy", + "Mineral" + ], + "otherFormes": [ + "glaliemega" + ] + }, + "glaliemega": { + "num": 362, + "species": "Glalie-Mega", + "baseSpecies": "Glalie", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 80, + "atk": 120, + "def": 80, + "spa": 120, + "spd": 80, + "spe": 100 + }, + "abilities": { + "0": "Refrigerate" + }, + "heightm": 2.1, + "weightkg": 350.2, + "color": "Gray", + "eggGroups": [ + "Fairy", + "Mineral" + ] + }, + "spheal": { + "num": 363, + "species": "Spheal", + "types": [ + "Ice", + "Water" + ], + "baseStats": { + "hp": 70, + "atk": 40, + "def": 50, + "spa": 55, + "spd": 50, + "spe": 25 + }, + "abilities": { + "0": "Thick Fat", + "1": "Ice Body", + "H": "Oblivious" + }, + "heightm": 0.8, + "weightkg": 39.5, + "color": "Blue", + "evos": [ + "sealeo" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "sealeo": { + "num": 364, + "species": "Sealeo", + "types": [ + "Ice", + "Water" + ], + "baseStats": { + "hp": 90, + "atk": 60, + "def": 70, + "spa": 75, + "spd": 70, + "spe": 45 + }, + "abilities": { + "0": "Thick Fat", + "1": "Ice Body", + "H": "Oblivious" + }, + "heightm": 1.1, + "weightkg": 87.6, + "color": "Blue", + "prevo": "spheal", + "evos": [ + "walrein" + ], + "evoLevel": 32, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "walrein": { + "num": 365, + "species": "Walrein", + "types": [ + "Ice", + "Water" + ], + "baseStats": { + "hp": 110, + "atk": 80, + "def": 90, + "spa": 95, + "spd": 90, + "spe": 65 + }, + "abilities": { + "0": "Thick Fat", + "1": "Ice Body", + "H": "Oblivious" + }, + "heightm": 1.4, + "weightkg": 150.6, + "color": "Blue", + "prevo": "sealeo", + "evoLevel": 44, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "clamperl": { + "num": 366, + "species": "Clamperl", + "types": [ + "Water" + ], + "baseStats": { + "hp": 35, + "atk": 64, + "def": 85, + "spa": 74, + "spd": 55, + "spe": 32 + }, + "abilities": { + "0": "Shell Armor", + "H": "Rattled" + }, + "heightm": 0.4, + "weightkg": 52.5, + "color": "Blue", + "evos": [ + "huntail", + "gorebyss" + ], + "eggGroups": [ + "Water 1" + ] + }, + "huntail": { + "num": 367, + "species": "Huntail", + "types": [ + "Water" + ], + "baseStats": { + "hp": 55, + "atk": 104, + "def": 105, + "spa": 94, + "spd": 75, + "spe": 52 + }, + "abilities": { + "0": "Swift Swim", + "H": "Water Veil" + }, + "heightm": 1.7, + "weightkg": 27, + "color": "Blue", + "prevo": "clamperl", + "evoLevel": 1, + "eggGroups": [ + "Water 1" + ] + }, + "gorebyss": { + "num": 368, + "species": "Gorebyss", + "types": [ + "Water" + ], + "baseStats": { + "hp": 55, + "atk": 84, + "def": 105, + "spa": 114, + "spd": 75, + "spe": 52 + }, + "abilities": { + "0": "Swift Swim", + "H": "Hydration" + }, + "heightm": 1.8, + "weightkg": 22.6, + "color": "Pink", + "prevo": "clamperl", + "evoLevel": 1, + "eggGroups": [ + "Water 1" + ] + }, + "relicanth": { + "num": 369, + "species": "Relicanth", + "types": [ + "Water", + "Rock" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 100, + "atk": 90, + "def": 130, + "spa": 45, + "spd": 65, + "spe": 55 + }, + "abilities": { + "0": "Swift Swim", + "1": "Rock Head", + "H": "Sturdy" + }, + "heightm": 1, + "weightkg": 23.4, + "color": "Gray", + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "luvdisc": { + "num": 370, + "species": "Luvdisc", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 43, + "atk": 30, + "def": 55, + "spa": 40, + "spd": 65, + "spe": 97 + }, + "abilities": { + "0": "Swift Swim", + "H": "Hydration" + }, + "heightm": 0.6, + "weightkg": 8.7, + "color": "Pink", + "eggGroups": [ + "Water 2" + ] + }, + "bagon": { + "num": 371, + "species": "Bagon", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 45, + "atk": 75, + "def": 60, + "spa": 40, + "spd": 30, + "spe": 50 + }, + "abilities": { + "0": "Rock Head", + "H": "Sheer Force" + }, + "heightm": 0.6, + "weightkg": 42.1, + "color": "Blue", + "evos": [ + "shelgon" + ], + "eggGroups": [ + "Dragon" + ] + }, + "shelgon": { + "num": 372, + "species": "Shelgon", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 65, + "atk": 95, + "def": 100, + "spa": 60, + "spd": 50, + "spe": 50 + }, + "abilities": { + "0": "Rock Head", + "H": "Overcoat" + }, + "heightm": 1.1, + "weightkg": 110.5, + "color": "White", + "prevo": "bagon", + "evos": [ + "salamence" + ], + "evoLevel": 30, + "eggGroups": [ + "Dragon" + ] + }, + "salamence": { + "num": 373, + "species": "Salamence", + "types": [ + "Dragon", + "Flying" + ], + "baseStats": { + "hp": 95, + "atk": 135, + "def": 80, + "spa": 110, + "spd": 80, + "spe": 100 + }, + "abilities": { + "0": "Intimidate", + "H": "Moxie" + }, + "heightm": 1.5, + "weightkg": 102.6, + "color": "Blue", + "prevo": "shelgon", + "evoLevel": 50, + "eggGroups": [ + "Dragon" + ], + "otherFormes": [ + "salamencemega" + ] + }, + "salamencemega": { + "num": 373, + "species": "Salamence-Mega", + "baseSpecies": "Salamence", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dragon", + "Flying" + ], + "baseStats": { + "hp": 95, + "atk": 145, + "def": 130, + "spa": 120, + "spd": 90, + "spe": 120 + }, + "abilities": { + "0": "Aerilate" + }, + "heightm": 1.8, + "weightkg": 112.6, + "color": "Blue", + "eggGroups": [ + "Dragon" + ] + }, + "beldum": { + "num": 374, + "species": "Beldum", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 40, + "atk": 55, + "def": 80, + "spa": 35, + "spd": 60, + "spe": 30 + }, + "abilities": { + "0": "Clear Body", + "H": "Light Metal" + }, + "heightm": 0.6, + "weightkg": 95.2, + "color": "Blue", + "evos": [ + "metang" + ], + "eggGroups": [ + "Mineral" + ] + }, + "metang": { + "num": 375, + "species": "Metang", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 75, + "def": 100, + "spa": 55, + "spd": 80, + "spe": 50 + }, + "abilities": { + "0": "Clear Body", + "H": "Light Metal" + }, + "heightm": 1.2, + "weightkg": 202.5, + "color": "Blue", + "prevo": "beldum", + "evos": [ + "metagross" + ], + "evoLevel": 20, + "eggGroups": [ + "Mineral" + ] + }, + "metagross": { + "num": 376, + "species": "Metagross", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 135, + "def": 130, + "spa": 95, + "spd": 90, + "spe": 70 + }, + "abilities": { + "0": "Clear Body", + "H": "Light Metal" + }, + "heightm": 1.6, + "weightkg": 550, + "color": "Blue", + "prevo": "metang", + "evoLevel": 45, + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "metagrossmega" + ] + }, + "metagrossmega": { + "num": 376, + "species": "Metagross-Mega", + "baseSpecies": "Metagross", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 145, + "def": 150, + "spa": 105, + "spd": 110, + "spe": 110 + }, + "abilities": { + "0": "Tough Claws" + }, + "heightm": 2.5, + "weightkg": 942.9, + "color": "Blue", + "eggGroups": [ + "Mineral" + ] + }, + "regirock": { + "num": 377, + "species": "Regirock", + "types": [ + "Rock" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 100, + "def": 200, + "spa": 50, + "spd": 100, + "spe": 50 + }, + "abilities": { + "0": "Clear Body", + "H": "Sturdy" + }, + "heightm": 1.7, + "weightkg": 230, + "color": "Brown", + "eggGroups": [ + "Undiscovered" + ] + }, + "regice": { + "num": 378, + "species": "Regice", + "types": [ + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 50, + "def": 100, + "spa": 100, + "spd": 200, + "spe": 50 + }, + "abilities": { + "0": "Clear Body", + "H": "Ice Body" + }, + "heightm": 1.8, + "weightkg": 175, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "registeel": { + "num": 379, + "species": "Registeel", + "types": [ + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 75, + "def": 150, + "spa": 75, + "spd": 150, + "spe": 50 + }, + "abilities": { + "0": "Clear Body", + "H": "Light Metal" + }, + "heightm": 1.9, + "weightkg": 205, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "latias": { + "num": 380, + "species": "Latias", + "types": [ + "Dragon", + "Psychic" + ], + "gender": "F", + "baseStats": { + "hp": 80, + "atk": 80, + "def": 90, + "spa": 110, + "spd": 130, + "spe": 110 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.4, + "weightkg": 40, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "latiasmega" + ] + }, + "latiasmega": { + "num": 380, + "species": "Latias-Mega", + "baseSpecies": "Latias", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dragon", + "Psychic" + ], + "gender": "F", + "baseStats": { + "hp": 80, + "atk": 100, + "def": 120, + "spa": 140, + "spd": 150, + "spe": 110 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.8, + "weightkg": 52, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "latios": { + "num": 381, + "species": "Latios", + "types": [ + "Dragon", + "Psychic" + ], + "gender": "M", + "baseStats": { + "hp": 80, + "atk": 90, + "def": 80, + "spa": 130, + "spd": 110, + "spe": 110 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 2, + "weightkg": 60, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "latiosmega" + ] + }, + "latiosmega": { + "num": 381, + "species": "Latios-Mega", + "baseSpecies": "Latios", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dragon", + "Psychic" + ], + "gender": "M", + "baseStats": { + "hp": 80, + "atk": 130, + "def": 100, + "spa": 160, + "spd": 120, + "spe": 110 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 2.3, + "weightkg": 70, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "kyogre": { + "num": 382, + "species": "Kyogre", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 90, + "spa": 150, + "spd": 140, + "spe": 90 + }, + "abilities": { + "0": "Drizzle" + }, + "heightm": 4.5, + "weightkg": 352, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "kyogreprimal" + ] + }, + "kyogreprimal": { + "num": 382, + "species": "Kyogre-Primal", + "baseSpecies": "Kyogre", + "forme": "Primal", + "formeLetter": "P", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 150, + "def": 90, + "spa": 180, + "spd": 160, + "spe": 90 + }, + "abilities": { + "0": "Primordial Sea" + }, + "heightm": 9.8, + "weightkg": 430, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "groudon": { + "num": 383, + "species": "Groudon", + "types": [ + "Ground" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 150, + "def": 140, + "spa": 100, + "spd": 90, + "spe": 90 + }, + "abilities": { + "0": "Drought" + }, + "heightm": 3.5, + "weightkg": 950, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "groudonprimal" + ] + }, + "groudonprimal": { + "num": 383, + "species": "Groudon-Primal", + "baseSpecies": "Groudon", + "forme": "Primal", + "formeLetter": "P", + "types": [ + "Ground", + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 180, + "def": 160, + "spa": 150, + "spd": 90, + "spe": 90 + }, + "abilities": { + "0": "Desolate Land" + }, + "heightm": 5, + "weightkg": 999.7, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "rayquaza": { + "num": 384, + "species": "Rayquaza", + "types": [ + "Dragon", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 105, + "atk": 150, + "def": 90, + "spa": 150, + "spd": 90, + "spe": 95 + }, + "abilities": { + "0": "Air Lock" + }, + "heightm": 7, + "weightkg": 206.5, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "rayquazamega" + ] + }, + "rayquazamega": { + "num": 384, + "species": "Rayquaza-Mega", + "baseSpecies": "Rayquaza", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dragon", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 105, + "atk": 180, + "def": 100, + "spa": 180, + "spd": 100, + "spe": 115 + }, + "abilities": { + "0": "Delta Stream" + }, + "heightm": 10.8, + "weightkg": 392, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "jirachi": { + "num": 385, + "species": "Jirachi", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 100, + "spa": 100, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Serene Grace" + }, + "heightm": 0.3, + "weightkg": 1.1, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "deoxys": { + "num": 386, + "species": "Deoxys", + "baseForme": "Normal", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 150, + "def": 50, + "spa": 150, + "spd": 50, + "spe": 150 + }, + "abilities": { + "0": "Pressure" + }, + "heightm": 1.7, + "weightkg": 60.8, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "deoxysattack", + "deoxysdefense", + "deoxysspeed" + ] + }, + "deoxysattack": { + "num": 386, + "species": "Deoxys-Attack", + "baseSpecies": "Deoxys", + "forme": "Attack", + "formeLetter": "A", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 180, + "def": 20, + "spa": 180, + "spd": 20, + "spe": 150 + }, + "abilities": { + "0": "Pressure" + }, + "heightm": 1.7, + "weightkg": 60.8, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "deoxysdefense": { + "num": 386, + "species": "Deoxys-Defense", + "baseSpecies": "Deoxys", + "forme": "Defense", + "formeLetter": "D", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 70, + "def": 160, + "spa": 70, + "spd": 160, + "spe": 90 + }, + "abilities": { + "0": "Pressure" + }, + "heightm": 1.7, + "weightkg": 60.8, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "deoxysspeed": { + "num": 386, + "species": "Deoxys-Speed", + "baseSpecies": "Deoxys", + "forme": "Speed", + "formeLetter": "S", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 95, + "def": 90, + "spa": 95, + "spd": 90, + "spe": 180 + }, + "abilities": { + "0": "Pressure" + }, + "heightm": 1.7, + "weightkg": 60.8, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "turtwig": { + "num": 387, + "species": "Turtwig", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 55, + "atk": 68, + "def": 64, + "spa": 45, + "spd": 55, + "spe": 31 + }, + "abilities": { + "0": "Overgrow", + "H": "Shell Armor" + }, + "heightm": 0.4, + "weightkg": 10.2, + "color": "Green", + "evos": [ + "grotle" + ], + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "grotle": { + "num": 388, + "species": "Grotle", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 89, + "def": 85, + "spa": 55, + "spd": 65, + "spe": 36 + }, + "abilities": { + "0": "Overgrow", + "H": "Shell Armor" + }, + "heightm": 1.1, + "weightkg": 97, + "color": "Green", + "prevo": "turtwig", + "evos": [ + "torterra" + ], + "evoLevel": 18, + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "torterra": { + "num": 389, + "species": "Torterra", + "types": [ + "Grass", + "Ground" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 95, + "atk": 109, + "def": 105, + "spa": 75, + "spd": 85, + "spe": 56 + }, + "abilities": { + "0": "Overgrow", + "H": "Shell Armor" + }, + "heightm": 2.2, + "weightkg": 310, + "color": "Green", + "prevo": "grotle", + "evoLevel": 32, + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "chimchar": { + "num": 390, + "species": "Chimchar", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 44, + "atk": 58, + "def": 44, + "spa": 58, + "spd": 44, + "spe": 61 + }, + "abilities": { + "0": "Blaze", + "H": "Iron Fist" + }, + "heightm": 0.5, + "weightkg": 6.2, + "color": "Brown", + "evos": [ + "monferno" + ], + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "monferno": { + "num": 391, + "species": "Monferno", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 64, + "atk": 78, + "def": 52, + "spa": 78, + "spd": 52, + "spe": 81 + }, + "abilities": { + "0": "Blaze", + "H": "Iron Fist" + }, + "heightm": 0.9, + "weightkg": 22, + "color": "Brown", + "prevo": "chimchar", + "evos": [ + "infernape" + ], + "evoLevel": 14, + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "infernape": { + "num": 392, + "species": "Infernape", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 76, + "atk": 104, + "def": 71, + "spa": 104, + "spd": 71, + "spe": 108 + }, + "abilities": { + "0": "Blaze", + "H": "Iron Fist" + }, + "heightm": 1.2, + "weightkg": 55, + "color": "Brown", + "prevo": "monferno", + "evoLevel": 36, + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "piplup": { + "num": 393, + "species": "Piplup", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 53, + "atk": 51, + "def": 53, + "spa": 61, + "spd": 56, + "spe": 40 + }, + "abilities": { + "0": "Torrent", + "H": "Defiant" + }, + "heightm": 0.4, + "weightkg": 5.2, + "color": "Blue", + "evos": [ + "prinplup" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "prinplup": { + "num": 394, + "species": "Prinplup", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 64, + "atk": 66, + "def": 68, + "spa": 81, + "spd": 76, + "spe": 50 + }, + "abilities": { + "0": "Torrent", + "H": "Defiant" + }, + "heightm": 0.8, + "weightkg": 23, + "color": "Blue", + "prevo": "piplup", + "evos": [ + "empoleon" + ], + "evoLevel": 16, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "empoleon": { + "num": 395, + "species": "Empoleon", + "types": [ + "Water", + "Steel" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 84, + "atk": 86, + "def": 88, + "spa": 111, + "spd": 101, + "spe": 60 + }, + "abilities": { + "0": "Torrent", + "H": "Defiant" + }, + "heightm": 1.7, + "weightkg": 84.5, + "color": "Blue", + "prevo": "prinplup", + "evoLevel": 36, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "starly": { + "num": 396, + "species": "Starly", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 40, + "atk": 55, + "def": 30, + "spa": 30, + "spd": 30, + "spe": 60 + }, + "abilities": { + "0": "Keen Eye", + "H": "Reckless" + }, + "heightm": 0.3, + "weightkg": 2, + "color": "Brown", + "evos": [ + "staravia" + ], + "eggGroups": [ + "Flying" + ] + }, + "staravia": { + "num": 397, + "species": "Staravia", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 55, + "atk": 75, + "def": 50, + "spa": 40, + "spd": 40, + "spe": 80 + }, + "abilities": { + "0": "Intimidate", + "H": "Reckless" + }, + "heightm": 0.6, + "weightkg": 15.5, + "color": "Brown", + "prevo": "starly", + "evos": [ + "staraptor" + ], + "evoLevel": 14, + "eggGroups": [ + "Flying" + ] + }, + "staraptor": { + "num": 398, + "species": "Staraptor", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 85, + "atk": 120, + "def": 70, + "spa": 50, + "spd": 60, + "spe": 100 + }, + "abilities": { + "0": "Intimidate", + "H": "Reckless" + }, + "heightm": 1.2, + "weightkg": 24.9, + "color": "Brown", + "prevo": "staravia", + "evoLevel": 34, + "eggGroups": [ + "Flying" + ] + }, + "bidoof": { + "num": 399, + "species": "Bidoof", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 59, + "atk": 45, + "def": 40, + "spa": 35, + "spd": 40, + "spe": 31 + }, + "abilities": { + "0": "Simple", + "1": "Unaware", + "H": "Moody" + }, + "heightm": 0.5, + "weightkg": 20, + "color": "Brown", + "evos": [ + "bibarel" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "bibarel": { + "num": 400, + "species": "Bibarel", + "types": [ + "Normal", + "Water" + ], + "baseStats": { + "hp": 79, + "atk": 85, + "def": 60, + "spa": 55, + "spd": 60, + "spe": 71 + }, + "abilities": { + "0": "Simple", + "1": "Unaware", + "H": "Moody" + }, + "heightm": 1, + "weightkg": 31.5, + "color": "Brown", + "prevo": "bidoof", + "evoLevel": 15, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "kricketot": { + "num": 401, + "species": "Kricketot", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 37, + "atk": 25, + "def": 41, + "spa": 25, + "spd": 41, + "spe": 25 + }, + "abilities": { + "0": "Shed Skin", + "H": "Run Away" + }, + "heightm": 0.3, + "weightkg": 2.2, + "color": "Red", + "evos": [ + "kricketune" + ], + "eggGroups": [ + "Bug" + ] + }, + "kricketune": { + "num": 402, + "species": "Kricketune", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 77, + "atk": 85, + "def": 51, + "spa": 55, + "spd": 51, + "spe": 65 + }, + "abilities": { + "0": "Swarm", + "H": "Technician" + }, + "heightm": 1, + "weightkg": 25.5, + "color": "Red", + "prevo": "kricketot", + "evoLevel": 10, + "eggGroups": [ + "Bug" + ] + }, + "shinx": { + "num": 403, + "species": "Shinx", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 45, + "atk": 65, + "def": 34, + "spa": 40, + "spd": 34, + "spe": 45 + }, + "abilities": { + "0": "Rivalry", + "1": "Intimidate", + "H": "Guts" + }, + "heightm": 0.5, + "weightkg": 9.5, + "color": "Blue", + "evos": [ + "luxio" + ], + "eggGroups": [ + "Field" + ] + }, + "luxio": { + "num": 404, + "species": "Luxio", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 60, + "atk": 85, + "def": 49, + "spa": 60, + "spd": 49, + "spe": 60 + }, + "abilities": { + "0": "Rivalry", + "1": "Intimidate", + "H": "Guts" + }, + "heightm": 0.9, + "weightkg": 30.5, + "color": "Blue", + "prevo": "shinx", + "evos": [ + "luxray" + ], + "evoLevel": 15, + "eggGroups": [ + "Field" + ] + }, + "luxray": { + "num": 405, + "species": "Luxray", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 80, + "atk": 120, + "def": 79, + "spa": 95, + "spd": 79, + "spe": 70 + }, + "abilities": { + "0": "Rivalry", + "1": "Intimidate", + "H": "Guts" + }, + "heightm": 1.4, + "weightkg": 42, + "color": "Blue", + "prevo": "luxio", + "evoLevel": 30, + "eggGroups": [ + "Field" + ] + }, + "budew": { + "num": 406, + "species": "Budew", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 40, + "atk": 30, + "def": 35, + "spa": 50, + "spd": 70, + "spe": 55 + }, + "abilities": { + "0": "Natural Cure", + "1": "Poison Point", + "H": "Leaf Guard" + }, + "heightm": 0.2, + "weightkg": 1.2, + "color": "Green", + "evos": [ + "roselia" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "roserade": { + "num": 407, + "species": "Roserade", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 70, + "def": 65, + "spa": 125, + "spd": 105, + "spe": 90 + }, + "abilities": { + "0": "Natural Cure", + "1": "Poison Point", + "H": "Technician" + }, + "heightm": 0.9, + "weightkg": 14.5, + "color": "Green", + "prevo": "roselia", + "evoLevel": 1, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "cranidos": { + "num": 408, + "species": "Cranidos", + "types": [ + "Rock" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 67, + "atk": 125, + "def": 40, + "spa": 30, + "spd": 30, + "spe": 58 + }, + "abilities": { + "0": "Mold Breaker", + "H": "Sheer Force" + }, + "heightm": 0.9, + "weightkg": 31.5, + "color": "Blue", + "evos": [ + "rampardos" + ], + "eggGroups": [ + "Monster" + ] + }, + "rampardos": { + "num": 409, + "species": "Rampardos", + "types": [ + "Rock" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 97, + "atk": 165, + "def": 60, + "spa": 65, + "spd": 50, + "spe": 58 + }, + "abilities": { + "0": "Mold Breaker", + "H": "Sheer Force" + }, + "heightm": 1.6, + "weightkg": 102.5, + "color": "Blue", + "prevo": "cranidos", + "evoLevel": 30, + "eggGroups": [ + "Monster" + ] + }, + "shieldon": { + "num": 410, + "species": "Shieldon", + "types": [ + "Rock", + "Steel" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 30, + "atk": 42, + "def": 118, + "spa": 42, + "spd": 88, + "spe": 30 + }, + "abilities": { + "0": "Sturdy", + "H": "Soundproof" + }, + "heightm": 0.5, + "weightkg": 57, + "color": "Gray", + "evos": [ + "bastiodon" + ], + "eggGroups": [ + "Monster" + ] + }, + "bastiodon": { + "num": 411, + "species": "Bastiodon", + "types": [ + "Rock", + "Steel" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 52, + "def": 168, + "spa": 47, + "spd": 138, + "spe": 30 + }, + "abilities": { + "0": "Sturdy", + "H": "Soundproof" + }, + "heightm": 1.3, + "weightkg": 149.5, + "color": "Gray", + "prevo": "shieldon", + "evoLevel": 30, + "eggGroups": [ + "Monster" + ] + }, + "burmy": { + "num": 412, + "species": "Burmy", + "baseForme": "Grass", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 40, + "atk": 29, + "def": 45, + "spa": 29, + "spd": 45, + "spe": 36 + }, + "abilities": { + "0": "Shed Skin", + "H": "Overcoat" + }, + "heightm": 0.2, + "weightkg": 3.4, + "color": "Gray", + "evos": [ + "wormadam", + "wormadamsandy", + "wormadamtrash", + "mothim" + ], + "eggGroups": [ + "Bug" + ], + "otherForms": [ + "burmysandy", + "burmytrash" + ] + }, + "wormadam": { + "num": 413, + "species": "Wormadam", + "baseForme": "Grass", + "types": [ + "Bug", + "Grass" + ], + "gender": "F", + "baseStats": { + "hp": 60, + "atk": 59, + "def": 85, + "spa": 79, + "spd": 105, + "spe": 36 + }, + "abilities": { + "0": "Anticipation", + "H": "Overcoat" + }, + "heightm": 0.5, + "weightkg": 6.5, + "color": "Gray", + "prevo": "burmy", + "evoLevel": 20, + "eggGroups": [ + "Bug" + ], + "otherFormes": [ + "wormadamsandy", + "wormadamtrash" + ] + }, + "wormadamsandy": { + "num": 413, + "species": "Wormadam-Sandy", + "baseSpecies": "Wormadam", + "forme": "Sandy", + "formeLetter": "G", + "types": [ + "Bug", + "Ground" + ], + "gender": "F", + "baseStats": { + "hp": 60, + "atk": 79, + "def": 105, + "spa": 59, + "spd": 85, + "spe": 36 + }, + "abilities": { + "0": "Anticipation", + "H": "Overcoat" + }, + "heightm": 0.5, + "weightkg": 6.5, + "color": "Gray", + "prevo": "burmy", + "evoLevel": 20, + "eggGroups": [ + "Bug" + ] + }, + "wormadamtrash": { + "num": 413, + "species": "Wormadam-Trash", + "baseSpecies": "Wormadam", + "forme": "Trash", + "formeLetter": "S", + "types": [ + "Bug", + "Steel" + ], + "gender": "F", + "baseStats": { + "hp": 60, + "atk": 69, + "def": 95, + "spa": 69, + "spd": 95, + "spe": 36 + }, + "abilities": { + "0": "Anticipation", + "H": "Overcoat" + }, + "heightm": 0.5, + "weightkg": 6.5, + "color": "Gray", + "prevo": "burmy", + "evoLevel": 20, + "eggGroups": [ + "Bug" + ] + }, + "mothim": { + "num": 414, + "species": "Mothim", + "types": [ + "Bug", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 70, + "atk": 94, + "def": 50, + "spa": 94, + "spd": 50, + "spe": 66 + }, + "abilities": { + "0": "Swarm", + "H": "Tinted Lens" + }, + "heightm": 0.9, + "weightkg": 23.3, + "color": "Yellow", + "prevo": "burmy", + "evoLevel": 20, + "eggGroups": [ + "Bug" + ] + }, + "combee": { + "num": 415, + "species": "Combee", + "types": [ + "Bug", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 30, + "atk": 30, + "def": 42, + "spa": 30, + "spd": 42, + "spe": 70 + }, + "abilities": { + "0": "Honey Gather", + "H": "Hustle" + }, + "heightm": 0.3, + "weightkg": 5.5, + "color": "Yellow", + "evos": [ + "vespiquen" + ], + "eggGroups": [ + "Bug" + ] + }, + "vespiquen": { + "num": 416, + "species": "Vespiquen", + "types": [ + "Bug", + "Flying" + ], + "gender": "F", + "baseStats": { + "hp": 70, + "atk": 80, + "def": 102, + "spa": 80, + "spd": 102, + "spe": 40 + }, + "abilities": { + "0": "Pressure", + "H": "Unnerve" + }, + "heightm": 1.2, + "weightkg": 38.5, + "color": "Yellow", + "prevo": "combee", + "evoLevel": 21, + "eggGroups": [ + "Bug" + ] + }, + "pachirisu": { + "num": 417, + "species": "Pachirisu", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 60, + "atk": 45, + "def": 70, + "spa": 45, + "spd": 90, + "spe": 95 + }, + "abilities": { + "0": "Run Away", + "1": "Pickup", + "H": "Volt Absorb" + }, + "heightm": 0.4, + "weightkg": 3.9, + "color": "White", + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "buizel": { + "num": 418, + "species": "Buizel", + "types": [ + "Water" + ], + "baseStats": { + "hp": 55, + "atk": 65, + "def": 35, + "spa": 60, + "spd": 30, + "spe": 85 + }, + "abilities": { + "0": "Swift Swim", + "H": "Water Veil" + }, + "heightm": 0.7, + "weightkg": 29.5, + "color": "Brown", + "evos": [ + "floatzel" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "floatzel": { + "num": 419, + "species": "Floatzel", + "types": [ + "Water" + ], + "baseStats": { + "hp": 85, + "atk": 105, + "def": 55, + "spa": 85, + "spd": 50, + "spe": 115 + }, + "abilities": { + "0": "Swift Swim", + "H": "Water Veil" + }, + "heightm": 1.1, + "weightkg": 33.5, + "color": "Brown", + "prevo": "buizel", + "evoLevel": 26, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "cherubi": { + "num": 420, + "species": "Cherubi", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 45, + "atk": 35, + "def": 45, + "spa": 62, + "spd": 53, + "spe": 35 + }, + "abilities": { + "0": "Chlorophyll" + }, + "heightm": 0.4, + "weightkg": 3.3, + "color": "Pink", + "evos": [ + "cherrim" + ], + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "cherrim": { + "num": 421, + "species": "Cherrim", + "baseForme": "Overcast", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 70, + "atk": 60, + "def": 70, + "spa": 87, + "spd": 78, + "spe": 85 + }, + "abilities": { + "0": "Flower Gift" + }, + "heightm": 0.5, + "weightkg": 9.3, + "color": "Pink", + "prevo": "cherubi", + "evoLevel": 25, + "eggGroups": [ + "Fairy", + "Grass" + ], + "otherFormes": [ + "cherrimsunshine" + ] + }, + "cherrimsunshine": { + "num": 421, + "species": "Cherrim-Sunshine", + "baseSpecies": "Cherrim", + "forme": "Sunshine", + "formeLetter": "S", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 70, + "atk": 60, + "def": 70, + "spa": 87, + "spd": 78, + "spe": 85 + }, + "abilities": { + "0": "Flower Gift" + }, + "heightm": 0.5, + "weightkg": 9.3, + "color": "Pink", + "prevo": "cherubi", + "evoLevel": 25, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "shellos": { + "num": 422, + "species": "Shellos", + "baseForme": "West", + "types": [ + "Water" + ], + "baseStats": { + "hp": 76, + "atk": 48, + "def": 48, + "spa": 57, + "spd": 62, + "spe": 34 + }, + "abilities": { + "0": "Sticky Hold", + "1": "Storm Drain", + "H": "Sand Force" + }, + "heightm": 0.3, + "weightkg": 6.3, + "color": "Purple", + "evos": [ + "gastrodon" + ], + "eggGroups": [ + "Water 1", + "Amorphous" + ], + "otherForms": [ + "shelloseast" + ] + }, + "gastrodon": { + "num": 423, + "species": "Gastrodon", + "baseForme": "West", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 111, + "atk": 83, + "def": 68, + "spa": 92, + "spd": 82, + "spe": 39 + }, + "abilities": { + "0": "Sticky Hold", + "1": "Storm Drain", + "H": "Sand Force" + }, + "heightm": 0.9, + "weightkg": 29.9, + "color": "Purple", + "prevo": "shellos", + "evoLevel": 30, + "eggGroups": [ + "Water 1", + "Amorphous" + ], + "otherForms": [ + "gastrodoneast" + ] + }, + "ambipom": { + "num": 424, + "species": "Ambipom", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 75, + "atk": 100, + "def": 66, + "spa": 60, + "spd": 66, + "spe": 115 + }, + "abilities": { + "0": "Technician", + "1": "Pickup", + "H": "Skill Link" + }, + "heightm": 1.2, + "weightkg": 20.3, + "color": "Purple", + "prevo": "aipom", + "evoLevel": 2, + "evoMove": "Double Hit", + "eggGroups": [ + "Field" + ] + }, + "drifloon": { + "num": 425, + "species": "Drifloon", + "types": [ + "Ghost", + "Flying" + ], + "baseStats": { + "hp": 90, + "atk": 50, + "def": 34, + "spa": 60, + "spd": 44, + "spe": 70 + }, + "abilities": { + "0": "Aftermath", + "1": "Unburden", + "H": "Flare Boost" + }, + "heightm": 0.4, + "weightkg": 1.2, + "color": "Purple", + "evos": [ + "drifblim" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "drifblim": { + "num": 426, + "species": "Drifblim", + "types": [ + "Ghost", + "Flying" + ], + "baseStats": { + "hp": 150, + "atk": 80, + "def": 44, + "spa": 90, + "spd": 54, + "spe": 80 + }, + "abilities": { + "0": "Aftermath", + "1": "Unburden", + "H": "Flare Boost" + }, + "heightm": 1.2, + "weightkg": 15, + "color": "Purple", + "prevo": "drifloon", + "evoLevel": 28, + "eggGroups": [ + "Amorphous" + ] + }, + "buneary": { + "num": 427, + "species": "Buneary", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 55, + "atk": 66, + "def": 44, + "spa": 44, + "spd": 56, + "spe": 85 + }, + "abilities": { + "0": "Run Away", + "1": "Klutz", + "H": "Limber" + }, + "heightm": 0.4, + "weightkg": 5.5, + "color": "Brown", + "evos": [ + "lopunny" + ], + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "lopunny": { + "num": 428, + "species": "Lopunny", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 65, + "atk": 76, + "def": 84, + "spa": 54, + "spd": 96, + "spe": 105 + }, + "abilities": { + "0": "Cute Charm", + "1": "Klutz", + "H": "Limber" + }, + "heightm": 1.2, + "weightkg": 33.3, + "color": "Brown", + "prevo": "buneary", + "evoLevel": 2, + "eggGroups": [ + "Field", + "Human-Like" + ], + "otherFormes": [ + "lopunnymega" + ] + }, + "lopunnymega": { + "num": 428, + "species": "Lopunny-Mega", + "baseSpecies": "Lopunny", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Normal", + "Fighting" + ], + "baseStats": { + "hp": 65, + "atk": 136, + "def": 94, + "spa": 54, + "spd": 96, + "spe": 135 + }, + "abilities": { + "0": "Scrappy" + }, + "heightm": 1.3, + "weightkg": 28.3, + "color": "Brown", + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "mismagius": { + "num": 429, + "species": "Mismagius", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 60, + "spa": 105, + "spd": 105, + "spe": 105 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.9, + "weightkg": 4.4, + "color": "Purple", + "prevo": "misdreavus", + "evoLevel": 1, + "eggGroups": [ + "Amorphous" + ] + }, + "honchkrow": { + "num": 430, + "species": "Honchkrow", + "types": [ + "Dark", + "Flying" + ], + "baseStats": { + "hp": 100, + "atk": 125, + "def": 52, + "spa": 105, + "spd": 52, + "spe": 71 + }, + "abilities": { + "0": "Insomnia", + "1": "Super Luck", + "H": "Moxie" + }, + "heightm": 0.9, + "weightkg": 27.3, + "color": "Black", + "prevo": "murkrow", + "evoLevel": 1, + "eggGroups": [ + "Flying" + ] + }, + "glameow": { + "num": 431, + "species": "Glameow", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 49, + "atk": 55, + "def": 42, + "spa": 42, + "spd": 37, + "spe": 85 + }, + "abilities": { + "0": "Limber", + "1": "Own Tempo", + "H": "Keen Eye" + }, + "heightm": 0.5, + "weightkg": 3.9, + "color": "Gray", + "evos": [ + "purugly" + ], + "eggGroups": [ + "Field" + ] + }, + "purugly": { + "num": 432, + "species": "Purugly", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 71, + "atk": 82, + "def": 64, + "spa": 64, + "spd": 59, + "spe": 112 + }, + "abilities": { + "0": "Thick Fat", + "1": "Own Tempo", + "H": "Defiant" + }, + "heightm": 1, + "weightkg": 43.8, + "color": "Gray", + "prevo": "glameow", + "evoLevel": 38, + "eggGroups": [ + "Field" + ] + }, + "chingling": { + "num": 433, + "species": "Chingling", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 45, + "atk": 30, + "def": 50, + "spa": 65, + "spd": 50, + "spe": 45 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.2, + "weightkg": 0.6, + "color": "Yellow", + "evos": [ + "chimecho" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "stunky": { + "num": 434, + "species": "Stunky", + "types": [ + "Poison", + "Dark" + ], + "baseStats": { + "hp": 63, + "atk": 63, + "def": 47, + "spa": 41, + "spd": 41, + "spe": 74 + }, + "abilities": { + "0": "Stench", + "1": "Aftermath", + "H": "Keen Eye" + }, + "heightm": 0.4, + "weightkg": 19.2, + "color": "Purple", + "evos": [ + "skuntank" + ], + "eggGroups": [ + "Field" + ] + }, + "skuntank": { + "num": 435, + "species": "Skuntank", + "types": [ + "Poison", + "Dark" + ], + "baseStats": { + "hp": 103, + "atk": 93, + "def": 67, + "spa": 71, + "spd": 61, + "spe": 84 + }, + "abilities": { + "0": "Stench", + "1": "Aftermath", + "H": "Keen Eye" + }, + "heightm": 1, + "weightkg": 38, + "color": "Purple", + "prevo": "stunky", + "evoLevel": 34, + "eggGroups": [ + "Field" + ] + }, + "bronzor": { + "num": 436, + "species": "Bronzor", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 57, + "atk": 24, + "def": 86, + "spa": 24, + "spd": 86, + "spe": 23 + }, + "abilities": { + "0": "Levitate", + "1": "Heatproof", + "H": "Heavy Metal" + }, + "heightm": 0.5, + "weightkg": 60.5, + "color": "Green", + "evos": [ + "bronzong" + ], + "eggGroups": [ + "Mineral" + ] + }, + "bronzong": { + "num": 437, + "species": "Bronzong", + "types": [ + "Steel", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 67, + "atk": 89, + "def": 116, + "spa": 79, + "spd": 116, + "spe": 33 + }, + "abilities": { + "0": "Levitate", + "1": "Heatproof", + "H": "Heavy Metal" + }, + "heightm": 1.3, + "weightkg": 187, + "color": "Green", + "prevo": "bronzor", + "evoLevel": 33, + "eggGroups": [ + "Mineral" + ] + }, + "bonsly": { + "num": 438, + "species": "Bonsly", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 50, + "atk": 80, + "def": 95, + "spa": 10, + "spd": 45, + "spe": 10 + }, + "abilities": { + "0": "Sturdy", + "1": "Rock Head", + "H": "Rattled" + }, + "heightm": 0.5, + "weightkg": 15, + "color": "Brown", + "evos": [ + "sudowoodo" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "mimejr": { + "num": 439, + "species": "Mime Jr.", + "types": [ + "Psychic", + "Fairy" + ], + "baseStats": { + "hp": 20, + "atk": 25, + "def": 45, + "spa": 70, + "spd": 90, + "spe": 60 + }, + "abilities": { + "0": "Soundproof", + "1": "Filter", + "H": "Technician" + }, + "heightm": 0.6, + "weightkg": 13, + "color": "Pink", + "evos": [ + "mrmime" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "happiny": { + "num": 440, + "species": "Happiny", + "types": [ + "Normal" + ], + "gender": "F", + "baseStats": { + "hp": 100, + "atk": 5, + "def": 5, + "spa": 15, + "spd": 65, + "spe": 30 + }, + "abilities": { + "0": "Natural Cure", + "1": "Serene Grace", + "H": "Friend Guard" + }, + "heightm": 0.6, + "weightkg": 24.4, + "color": "Pink", + "evos": [ + "chansey" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "chatot": { + "num": 441, + "species": "Chatot", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 76, + "atk": 65, + "def": 45, + "spa": 92, + "spd": 42, + "spe": 91 + }, + "abilities": { + "0": "Keen Eye", + "1": "Tangled Feet", + "H": "Big Pecks" + }, + "heightm": 0.5, + "weightkg": 1.9, + "color": "Black", + "eggGroups": [ + "Flying" + ] + }, + "spiritomb": { + "num": 442, + "species": "Spiritomb", + "types": [ + "Ghost", + "Dark" + ], + "baseStats": { + "hp": 50, + "atk": 92, + "def": 108, + "spa": 92, + "spd": 108, + "spe": 35 + }, + "abilities": { + "0": "Pressure", + "H": "Infiltrator" + }, + "heightm": 1, + "weightkg": 108, + "color": "Purple", + "eggGroups": [ + "Amorphous" + ] + }, + "gible": { + "num": 443, + "species": "Gible", + "types": [ + "Dragon", + "Ground" + ], + "baseStats": { + "hp": 58, + "atk": 70, + "def": 45, + "spa": 40, + "spd": 45, + "spe": 42 + }, + "abilities": { + "0": "Sand Veil", + "H": "Rough Skin" + }, + "heightm": 0.7, + "weightkg": 20.5, + "color": "Blue", + "evos": [ + "gabite" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "gabite": { + "num": 444, + "species": "Gabite", + "types": [ + "Dragon", + "Ground" + ], + "baseStats": { + "hp": 68, + "atk": 90, + "def": 65, + "spa": 50, + "spd": 55, + "spe": 82 + }, + "abilities": { + "0": "Sand Veil", + "H": "Rough Skin" + }, + "heightm": 1.4, + "weightkg": 56, + "color": "Blue", + "prevo": "gible", + "evos": [ + "garchomp" + ], + "evoLevel": 24, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "garchomp": { + "num": 445, + "species": "Garchomp", + "types": [ + "Dragon", + "Ground" + ], + "baseStats": { + "hp": 108, + "atk": 130, + "def": 95, + "spa": 80, + "spd": 85, + "spe": 102 + }, + "abilities": { + "0": "Sand Veil", + "H": "Rough Skin" + }, + "heightm": 1.9, + "weightkg": 95, + "color": "Blue", + "prevo": "gabite", + "evoLevel": 48, + "eggGroups": [ + "Monster", + "Dragon" + ], + "otherFormes": [ + "garchompmega" + ] + }, + "garchompmega": { + "num": 445, + "species": "Garchomp-Mega", + "baseSpecies": "Garchomp", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Dragon", + "Ground" + ], + "baseStats": { + "hp": 108, + "atk": 170, + "def": 115, + "spa": 120, + "spd": 95, + "spe": 92 + }, + "abilities": { + "0": "Sand Force" + }, + "heightm": 1.9, + "weightkg": 95, + "color": "Blue", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "munchlax": { + "num": 446, + "species": "Munchlax", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 135, + "atk": 85, + "def": 40, + "spa": 40, + "spd": 85, + "spe": 5 + }, + "abilities": { + "0": "Pickup", + "1": "Thick Fat", + "H": "Gluttony" + }, + "heightm": 0.6, + "weightkg": 105, + "color": "Black", + "evos": [ + "snorlax" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "riolu": { + "num": 447, + "species": "Riolu", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 40, + "atk": 70, + "def": 40, + "spa": 35, + "spd": 40, + "spe": 60 + }, + "abilities": { + "0": "Steadfast", + "1": "Inner Focus", + "H": "Prankster" + }, + "heightm": 0.7, + "weightkg": 20.2, + "color": "Blue", + "evos": [ + "lucario" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "lucario": { + "num": 448, + "species": "Lucario", + "types": [ + "Fighting", + "Steel" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 70, + "atk": 110, + "def": 70, + "spa": 115, + "spd": 70, + "spe": 90 + }, + "abilities": { + "0": "Steadfast", + "1": "Inner Focus", + "H": "Justified" + }, + "heightm": 1.2, + "weightkg": 54, + "color": "Blue", + "prevo": "riolu", + "evoLevel": 2, + "eggGroups": [ + "Field", + "Human-Like" + ], + "otherFormes": [ + "lucariomega" + ] + }, + "lucariomega": { + "num": 448, + "species": "Lucario-Mega", + "baseSpecies": "Lucario", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Fighting", + "Steel" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 70, + "atk": 145, + "def": 88, + "spa": 140, + "spd": 70, + "spe": 112 + }, + "abilities": { + "0": "Adaptability" + }, + "heightm": 1.3, + "weightkg": 57.5, + "color": "Blue", + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "hippopotas": { + "num": 449, + "species": "Hippopotas", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 68, + "atk": 72, + "def": 78, + "spa": 38, + "spd": 42, + "spe": 32 + }, + "abilities": { + "0": "Sand Stream", + "H": "Sand Force" + }, + "heightm": 0.8, + "weightkg": 49.5, + "color": "Brown", + "evos": [ + "hippowdon" + ], + "eggGroups": [ + "Field" + ] + }, + "hippowdon": { + "num": 450, + "species": "Hippowdon", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 108, + "atk": 112, + "def": 118, + "spa": 68, + "spd": 72, + "spe": 47 + }, + "abilities": { + "0": "Sand Stream", + "H": "Sand Force" + }, + "heightm": 2, + "weightkg": 300, + "color": "Brown", + "prevo": "hippopotas", + "evoLevel": 34, + "eggGroups": [ + "Field" + ] + }, + "skorupi": { + "num": 451, + "species": "Skorupi", + "types": [ + "Poison", + "Bug" + ], + "baseStats": { + "hp": 40, + "atk": 50, + "def": 90, + "spa": 30, + "spd": 55, + "spe": 65 + }, + "abilities": { + "0": "Battle Armor", + "1": "Sniper", + "H": "Keen Eye" + }, + "heightm": 0.8, + "weightkg": 12, + "color": "Purple", + "evos": [ + "drapion" + ], + "eggGroups": [ + "Bug", + "Water 3" + ] + }, + "drapion": { + "num": 452, + "species": "Drapion", + "types": [ + "Poison", + "Dark" + ], + "baseStats": { + "hp": 70, + "atk": 90, + "def": 110, + "spa": 60, + "spd": 75, + "spe": 95 + }, + "abilities": { + "0": "Battle Armor", + "1": "Sniper", + "H": "Keen Eye" + }, + "heightm": 1.3, + "weightkg": 61.5, + "color": "Purple", + "prevo": "skorupi", + "evoLevel": 40, + "eggGroups": [ + "Bug", + "Water 3" + ] + }, + "croagunk": { + "num": 453, + "species": "Croagunk", + "types": [ + "Poison", + "Fighting" + ], + "baseStats": { + "hp": 48, + "atk": 61, + "def": 40, + "spa": 61, + "spd": 40, + "spe": 50 + }, + "abilities": { + "0": "Anticipation", + "1": "Dry Skin", + "H": "Poison Touch" + }, + "heightm": 0.7, + "weightkg": 23, + "color": "Blue", + "evos": [ + "toxicroak" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "toxicroak": { + "num": 454, + "species": "Toxicroak", + "types": [ + "Poison", + "Fighting" + ], + "baseStats": { + "hp": 83, + "atk": 106, + "def": 65, + "spa": 86, + "spd": 65, + "spe": 85 + }, + "abilities": { + "0": "Anticipation", + "1": "Dry Skin", + "H": "Poison Touch" + }, + "heightm": 1.3, + "weightkg": 44.4, + "color": "Blue", + "prevo": "croagunk", + "evoLevel": 37, + "eggGroups": [ + "Human-Like" + ] + }, + "carnivine": { + "num": 455, + "species": "Carnivine", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 74, + "atk": 100, + "def": 72, + "spa": 90, + "spd": 72, + "spe": 46 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.4, + "weightkg": 27, + "color": "Green", + "eggGroups": [ + "Grass" + ] + }, + "finneon": { + "num": 456, + "species": "Finneon", + "types": [ + "Water" + ], + "baseStats": { + "hp": 49, + "atk": 49, + "def": 56, + "spa": 49, + "spd": 61, + "spe": 66 + }, + "abilities": { + "0": "Swift Swim", + "1": "Storm Drain", + "H": "Water Veil" + }, + "heightm": 0.4, + "weightkg": 7, + "color": "Blue", + "evos": [ + "lumineon" + ], + "eggGroups": [ + "Water 2" + ] + }, + "lumineon": { + "num": 457, + "species": "Lumineon", + "types": [ + "Water" + ], + "baseStats": { + "hp": 69, + "atk": 69, + "def": 76, + "spa": 69, + "spd": 86, + "spe": 91 + }, + "abilities": { + "0": "Swift Swim", + "1": "Storm Drain", + "H": "Water Veil" + }, + "heightm": 1.2, + "weightkg": 24, + "color": "Blue", + "prevo": "finneon", + "evoLevel": 31, + "eggGroups": [ + "Water 2" + ] + }, + "mantyke": { + "num": 458, + "species": "Mantyke", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 45, + "atk": 20, + "def": 50, + "spa": 60, + "spd": 120, + "spe": 50 + }, + "abilities": { + "0": "Swift Swim", + "1": "Water Absorb", + "H": "Water Veil" + }, + "heightm": 1, + "weightkg": 65, + "color": "Blue", + "evos": [ + "mantine" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "snover": { + "num": 459, + "species": "Snover", + "types": [ + "Grass", + "Ice" + ], + "baseStats": { + "hp": 60, + "atk": 62, + "def": 50, + "spa": 62, + "spd": 60, + "spe": 40 + }, + "abilities": { + "0": "Snow Warning", + "H": "Soundproof" + }, + "heightm": 1, + "weightkg": 50.5, + "color": "White", + "evos": [ + "abomasnow" + ], + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "abomasnow": { + "num": 460, + "species": "Abomasnow", + "types": [ + "Grass", + "Ice" + ], + "baseStats": { + "hp": 90, + "atk": 92, + "def": 75, + "spa": 92, + "spd": 85, + "spe": 60 + }, + "abilities": { + "0": "Snow Warning", + "H": "Soundproof" + }, + "heightm": 2.2, + "weightkg": 135.5, + "color": "White", + "prevo": "snover", + "evoLevel": 40, + "eggGroups": [ + "Monster", + "Grass" + ], + "otherFormes": [ + "abomasnowmega" + ] + }, + "abomasnowmega": { + "num": 460, + "species": "Abomasnow-Mega", + "baseSpecies": "Abomasnow", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Grass", + "Ice" + ], + "baseStats": { + "hp": 90, + "atk": 132, + "def": 105, + "spa": 132, + "spd": 105, + "spe": 30 + }, + "abilities": { + "0": "Snow Warning" + }, + "heightm": 2.7, + "weightkg": 185, + "color": "White", + "eggGroups": [ + "Monster", + "Grass" + ] + }, + "weavile": { + "num": 461, + "species": "Weavile", + "types": [ + "Dark", + "Ice" + ], + "baseStats": { + "hp": 70, + "atk": 120, + "def": 65, + "spa": 45, + "spd": 85, + "spe": 125 + }, + "abilities": { + "0": "Pressure", + "H": "Pickpocket" + }, + "heightm": 1.1, + "weightkg": 34, + "color": "Black", + "prevo": "sneasel", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "magnezone": { + "num": 462, + "species": "Magnezone", + "types": [ + "Electric", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 70, + "def": 115, + "spa": 130, + "spd": 90, + "spe": 60 + }, + "abilities": { + "0": "Magnet Pull", + "1": "Sturdy", + "H": "Analytic" + }, + "heightm": 1.2, + "weightkg": 180, + "color": "Gray", + "prevo": "magneton", + "evoLevel": 31, + "eggGroups": [ + "Mineral" + ] + }, + "lickilicky": { + "num": 463, + "species": "Lickilicky", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 110, + "atk": 85, + "def": 95, + "spa": 80, + "spd": 95, + "spe": 50 + }, + "abilities": { + "0": "Own Tempo", + "1": "Oblivious", + "H": "Cloud Nine" + }, + "heightm": 1.7, + "weightkg": 140, + "color": "Pink", + "prevo": "lickitung", + "evoLevel": 2, + "evoMove": "Rollout", + "eggGroups": [ + "Monster" + ] + }, + "rhyperior": { + "num": 464, + "species": "Rhyperior", + "types": [ + "Ground", + "Rock" + ], + "baseStats": { + "hp": 115, + "atk": 140, + "def": 130, + "spa": 55, + "spd": 55, + "spe": 40 + }, + "abilities": { + "0": "Lightning Rod", + "1": "Solid Rock", + "H": "Reckless" + }, + "heightm": 2.4, + "weightkg": 282.8, + "color": "Gray", + "prevo": "rhydon", + "evoLevel": 42, + "eggGroups": [ + "Monster", + "Field" + ] + }, + "tangrowth": { + "num": 465, + "species": "Tangrowth", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 100, + "atk": 100, + "def": 125, + "spa": 110, + "spd": 50, + "spe": 50 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Leaf Guard", + "H": "Regenerator" + }, + "heightm": 2, + "weightkg": 128.6, + "color": "Blue", + "prevo": "tangela", + "evoLevel": 2, + "evoMove": "AncientPower", + "eggGroups": [ + "Grass" + ] + }, + "electivire": { + "num": 466, + "species": "Electivire", + "types": [ + "Electric" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 75, + "atk": 123, + "def": 67, + "spa": 95, + "spd": 85, + "spe": 95 + }, + "abilities": { + "0": "Motor Drive", + "H": "Vital Spirit" + }, + "heightm": 1.8, + "weightkg": 138.6, + "color": "Yellow", + "prevo": "electabuzz", + "evoLevel": 30, + "eggGroups": [ + "Human-Like" + ] + }, + "magmortar": { + "num": 467, + "species": "Magmortar", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 75, + "atk": 95, + "def": 67, + "spa": 125, + "spd": 95, + "spe": 83 + }, + "abilities": { + "0": "Flame Body", + "H": "Vital Spirit" + }, + "heightm": 1.6, + "weightkg": 68, + "color": "Red", + "prevo": "magmar", + "evoLevel": 30, + "eggGroups": [ + "Human-Like" + ] + }, + "togekiss": { + "num": 468, + "species": "Togekiss", + "types": [ + "Fairy", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 85, + "atk": 50, + "def": 95, + "spa": 120, + "spd": 115, + "spe": 80 + }, + "abilities": { + "0": "Hustle", + "1": "Serene Grace", + "H": "Super Luck" + }, + "heightm": 1.5, + "weightkg": 38, + "color": "White", + "prevo": "togetic", + "evoLevel": 2, + "eggGroups": [ + "Flying", + "Fairy" + ] + }, + "yanmega": { + "num": 469, + "species": "Yanmega", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 86, + "atk": 76, + "def": 86, + "spa": 116, + "spd": 56, + "spe": 95 + }, + "abilities": { + "0": "Speed Boost", + "1": "Tinted Lens", + "H": "Frisk" + }, + "heightm": 1.9, + "weightkg": 51.5, + "color": "Green", + "prevo": "yanma", + "evoLevel": 2, + "evoMove": "AncientPower", + "eggGroups": [ + "Bug" + ] + }, + "leafeon": { + "num": 470, + "species": "Leafeon", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 110, + "def": 130, + "spa": 60, + "spd": 65, + "spe": 95 + }, + "abilities": { + "0": "Leaf Guard", + "H": "Chlorophyll" + }, + "heightm": 1, + "weightkg": 25.5, + "color": "Green", + "prevo": "eevee", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "glaceon": { + "num": 471, + "species": "Glaceon", + "types": [ + "Ice" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 60, + "def": 110, + "spa": 130, + "spd": 95, + "spe": 65 + }, + "abilities": { + "0": "Snow Cloak", + "H": "Ice Body" + }, + "heightm": 0.8, + "weightkg": 25.9, + "color": "Blue", + "prevo": "eevee", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "gliscor": { + "num": 472, + "species": "Gliscor", + "types": [ + "Ground", + "Flying" + ], + "baseStats": { + "hp": 75, + "atk": 95, + "def": 125, + "spa": 45, + "spd": 75, + "spe": 95 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Sand Veil", + "H": "Poison Heal" + }, + "heightm": 2, + "weightkg": 42.5, + "color": "Purple", + "prevo": "gligar", + "evoLevel": 2, + "eggGroups": [ + "Bug" + ] + }, + "mamoswine": { + "num": 473, + "species": "Mamoswine", + "types": [ + "Ice", + "Ground" + ], + "baseStats": { + "hp": 110, + "atk": 130, + "def": 80, + "spa": 70, + "spd": 60, + "spe": 80 + }, + "abilities": { + "0": "Oblivious", + "1": "Snow Cloak", + "H": "Thick Fat" + }, + "heightm": 2.5, + "weightkg": 291, + "color": "Brown", + "prevo": "piloswine", + "evoLevel": 34, + "evoMove": "AncientPower", + "eggGroups": [ + "Field" + ] + }, + "porygonz": { + "num": 474, + "species": "Porygon-Z", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 85, + "atk": 80, + "def": 70, + "spa": 135, + "spd": 75, + "spe": 90 + }, + "abilities": { + "0": "Adaptability", + "1": "Download", + "H": "Analytic" + }, + "heightm": 0.9, + "weightkg": 34, + "color": "Red", + "prevo": "porygon2", + "evoLevel": 1, + "eggGroups": [ + "Mineral" + ] + }, + "gallade": { + "num": 475, + "species": "Gallade", + "types": [ + "Psychic", + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 68, + "atk": 125, + "def": 65, + "spa": 65, + "spd": 115, + "spe": 80 + }, + "abilities": { + "0": "Steadfast", + "H": "Justified" + }, + "heightm": 1.6, + "weightkg": 52, + "color": "White", + "prevo": "kirlia", + "evoLevel": 20, + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "gallademega" + ] + }, + "gallademega": { + "num": 475, + "species": "Gallade-Mega", + "baseSpecies": "Gallade", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Psychic", + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 68, + "atk": 165, + "def": 95, + "spa": 65, + "spd": 115, + "spe": 110 + }, + "abilities": { + "0": "Inner Focus" + }, + "heightm": 1.6, + "weightkg": 56.4, + "color": "White", + "eggGroups": [ + "Amorphous" + ] + }, + "probopass": { + "num": 476, + "species": "Probopass", + "types": [ + "Rock", + "Steel" + ], + "baseStats": { + "hp": 60, + "atk": 55, + "def": 145, + "spa": 75, + "spd": 150, + "spe": 40 + }, + "abilities": { + "0": "Sturdy", + "1": "Magnet Pull", + "H": "Sand Force" + }, + "heightm": 1.4, + "weightkg": 340, + "color": "Gray", + "prevo": "nosepass", + "evoLevel": 2, + "eggGroups": [ + "Mineral" + ] + }, + "dusknoir": { + "num": 477, + "species": "Dusknoir", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 45, + "atk": 100, + "def": 135, + "spa": 65, + "spd": 135, + "spe": 45 + }, + "abilities": { + "0": "Pressure", + "H": "Frisk" + }, + "heightm": 2.2, + "weightkg": 106.6, + "color": "Black", + "prevo": "dusclops", + "evoLevel": 37, + "eggGroups": [ + "Amorphous" + ] + }, + "froslass": { + "num": 478, + "species": "Froslass", + "types": [ + "Ice", + "Ghost" + ], + "gender": "F", + "baseStats": { + "hp": 70, + "atk": 80, + "def": 70, + "spa": 80, + "spd": 70, + "spe": 110 + }, + "abilities": { + "0": "Snow Cloak", + "H": "Cursed Body" + }, + "heightm": 1.3, + "weightkg": 26.6, + "color": "White", + "prevo": "snorunt", + "evoLevel": 1, + "eggGroups": [ + "Fairy", + "Mineral" + ] + }, + "rotom": { + "num": 479, + "species": "Rotom", + "types": [ + "Electric", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 50, + "def": 77, + "spa": 95, + "spd": 77, + "spe": 91 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "rotomheat", + "rotomwash", + "rotomfrost", + "rotomfan", + "rotommow" + ] + }, + "rotomheat": { + "num": 479, + "species": "Rotom-Heat", + "baseSpecies": "Rotom", + "forme": "Heat", + "formeLetter": "H", + "types": [ + "Electric", + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 65, + "def": 107, + "spa": 105, + "spd": 107, + "spe": 86 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Amorphous" + ] + }, + "rotomwash": { + "num": 479, + "species": "Rotom-Wash", + "baseSpecies": "Rotom", + "forme": "Wash", + "formeLetter": "W", + "types": [ + "Electric", + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 65, + "def": 107, + "spa": 105, + "spd": 107, + "spe": 86 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Amorphous" + ] + }, + "rotomfrost": { + "num": 479, + "species": "Rotom-Frost", + "baseSpecies": "Rotom", + "forme": "Frost", + "formeLetter": "F", + "types": [ + "Electric", + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 65, + "def": 107, + "spa": 105, + "spd": 107, + "spe": 86 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Amorphous" + ] + }, + "rotomfan": { + "num": 479, + "species": "Rotom-Fan", + "baseSpecies": "Rotom", + "forme": "Fan", + "formeLetter": "S", + "types": [ + "Electric", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 65, + "def": 107, + "spa": 105, + "spd": 107, + "spe": 86 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Amorphous" + ] + }, + "rotommow": { + "num": 479, + "species": "Rotom-Mow", + "baseSpecies": "Rotom", + "forme": "Mow", + "formeLetter": "C", + "types": [ + "Electric", + "Grass" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 65, + "def": 107, + "spa": 105, + "spd": 107, + "spe": 86 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Amorphous" + ] + }, + "uxie": { + "num": 480, + "species": "Uxie", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 75, + "atk": 75, + "def": 130, + "spa": 75, + "spd": 130, + "spe": 95 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "mesprit": { + "num": 481, + "species": "Mesprit", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 105, + "def": 105, + "spa": 105, + "spd": 105, + "spe": 80 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Pink", + "eggGroups": [ + "Undiscovered" + ] + }, + "azelf": { + "num": 482, + "species": "Azelf", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 75, + "atk": 125, + "def": 70, + "spa": 125, + "spd": 70, + "spe": 115 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "dialga": { + "num": 483, + "species": "Dialga", + "types": [ + "Steel", + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 120, + "def": 120, + "spa": 150, + "spd": 100, + "spe": 90 + }, + "abilities": { + "0": "Pressure", + "H": "Telepathy" + }, + "heightm": 5.4, + "weightkg": 683, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "palkia": { + "num": 484, + "species": "Palkia", + "types": [ + "Water", + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 120, + "def": 100, + "spa": 150, + "spd": 120, + "spe": 100 + }, + "abilities": { + "0": "Pressure", + "H": "Telepathy" + }, + "heightm": 4.2, + "weightkg": 336, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "heatran": { + "num": 485, + "species": "Heatran", + "types": [ + "Fire", + "Steel" + ], + "baseStats": { + "hp": 91, + "atk": 90, + "def": 106, + "spa": 130, + "spd": 106, + "spe": 77 + }, + "abilities": { + "0": "Flash Fire", + "H": "Flame Body" + }, + "heightm": 1.7, + "weightkg": 430, + "color": "Brown", + "eggGroups": [ + "Undiscovered" + ] + }, + "regigigas": { + "num": 486, + "species": "Regigigas", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 110, + "atk": 160, + "def": 110, + "spa": 80, + "spd": 110, + "spe": 100 + }, + "abilities": { + "0": "Slow Start" + }, + "heightm": 3.7, + "weightkg": 420, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "giratina": { + "num": 487, + "species": "Giratina", + "baseForme": "Altered", + "types": [ + "Ghost", + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 150, + "atk": 100, + "def": 120, + "spa": 100, + "spd": 120, + "spe": 90 + }, + "abilities": { + "0": "Pressure", + "H": "Telepathy" + }, + "heightm": 4.5, + "weightkg": 750, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "giratinaorigin" + ] + }, + "giratinaorigin": { + "num": 487, + "species": "Giratina-Origin", + "baseSpecies": "Giratina", + "forme": "Origin", + "formeLetter": "O", + "types": [ + "Ghost", + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 150, + "atk": 120, + "def": 100, + "spa": 120, + "spd": 100, + "spe": 90 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 6.9, + "weightkg": 650, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "cresselia": { + "num": 488, + "species": "Cresselia", + "types": [ + "Psychic" + ], + "gender": "F", + "baseStats": { + "hp": 120, + "atk": 70, + "def": 120, + "spa": 75, + "spd": 130, + "spe": 85 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.5, + "weightkg": 85.6, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "phione": { + "num": 489, + "species": "Phione", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 80, + "def": 80, + "spa": 80, + "spd": 80, + "spe": 80 + }, + "abilities": { + "0": "Hydration" + }, + "heightm": 0.4, + "weightkg": 3.1, + "color": "Blue", + "eggGroups": [ + "Water 1", + "Fairy" + ] + }, + "manaphy": { + "num": 490, + "species": "Manaphy", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 100, + "spa": 100, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Hydration" + }, + "heightm": 0.3, + "weightkg": 1.4, + "color": "Blue", + "eggGroups": [ + "Water 1", + "Fairy" + ] + }, + "darkrai": { + "num": 491, + "species": "Darkrai", + "types": [ + "Dark" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 90, + "def": 90, + "spa": 135, + "spd": 90, + "spe": 125 + }, + "abilities": { + "0": "Bad Dreams" + }, + "heightm": 1.5, + "weightkg": 50.5, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "shaymin": { + "num": 492, + "species": "Shaymin", + "baseForme": "Land", + "types": [ + "Grass" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 100, + "spa": 100, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Natural Cure" + }, + "heightm": 0.2, + "weightkg": 2.1, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "shayminsky" + ] + }, + "shayminsky": { + "num": 492, + "species": "Shaymin-Sky", + "baseSpecies": "Shaymin", + "forme": "Sky", + "formeLetter": "S", + "types": [ + "Grass", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 103, + "def": 75, + "spa": 120, + "spd": 75, + "spe": 127 + }, + "abilities": { + "0": "Serene Grace" + }, + "heightm": 0.4, + "weightkg": 5.2, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceus": { + "num": 493, + "species": "Arceus", + "baseForme": "Normal", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "arceusbug", + "arceusdark", + "arceusdragon", + "arceuselectric", + "arceusfairy", + "arceusfighting", + "arceusfire", + "arceusflying", + "arceusghost", + "arceusgrass", + "arceusground", + "arceusice", + "arceuspoison", + "arceuspsychic", + "arceusrock", + "arceussteel", + "arceuswater" + ] + }, + "arceusbug": { + "num": 493, + "species": "Arceus-Bug", + "baseSpecies": "Arceus", + "forme": "Bug", + "formeLetter": "B", + "types": [ + "Bug" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusdark": { + "num": 493, + "species": "Arceus-Dark", + "baseSpecies": "Arceus", + "forme": "Dark", + "formeLetter": "D", + "types": [ + "Dark" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusdragon": { + "num": 493, + "species": "Arceus-Dragon", + "baseSpecies": "Arceus", + "forme": "Dragon", + "formeLetter": "D", + "types": [ + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceuselectric": { + "num": 493, + "species": "Arceus-Electric", + "baseSpecies": "Arceus", + "forme": "Electric", + "formeLetter": "E", + "types": [ + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusfairy": { + "num": 493, + "species": "Arceus-Fairy", + "baseSpecies": "Arceus", + "forme": "Fairy", + "formeLetter": "F", + "types": [ + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusfighting": { + "num": 493, + "species": "Arceus-Fighting", + "baseSpecies": "Arceus", + "forme": "Fighting", + "formeLetter": "F", + "types": [ + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusfire": { + "num": 493, + "species": "Arceus-Fire", + "baseSpecies": "Arceus", + "forme": "Fire", + "formeLetter": "F", + "types": [ + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusflying": { + "num": 493, + "species": "Arceus-Flying", + "baseSpecies": "Arceus", + "forme": "Flying", + "formeLetter": "F", + "types": [ + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusghost": { + "num": 493, + "species": "Arceus-Ghost", + "baseSpecies": "Arceus", + "forme": "Ghost", + "formeLetter": "G", + "types": [ + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusgrass": { + "num": 493, + "species": "Arceus-Grass", + "baseSpecies": "Arceus", + "forme": "Grass", + "formeLetter": "G", + "types": [ + "Grass" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusground": { + "num": 493, + "species": "Arceus-Ground", + "baseSpecies": "Arceus", + "forme": "Ground", + "formeLetter": "G", + "types": [ + "Ground" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusice": { + "num": 493, + "species": "Arceus-Ice", + "baseSpecies": "Arceus", + "forme": "Ice", + "formeLetter": "I", + "types": [ + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceuspoison": { + "num": 493, + "species": "Arceus-Poison", + "baseSpecies": "Arceus", + "forme": "Poison", + "formeLetter": "P", + "types": [ + "Poison" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceuspsychic": { + "num": 493, + "species": "Arceus-Psychic", + "baseSpecies": "Arceus", + "forme": "Psychic", + "formeLetter": "P", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceusrock": { + "num": 493, + "species": "Arceus-Rock", + "baseSpecies": "Arceus", + "forme": "Rock", + "formeLetter": "R", + "types": [ + "Rock" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceussteel": { + "num": 493, + "species": "Arceus-Steel", + "baseSpecies": "Arceus", + "forme": "Steel", + "formeLetter": "S", + "types": [ + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arceuswater": { + "num": 493, + "species": "Arceus-Water", + "baseSpecies": "Arceus", + "forme": "Water", + "formeLetter": "W", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 120, + "atk": 120, + "def": 120, + "spa": 120, + "spd": 120, + "spe": 120 + }, + "abilities": { + "0": "Multitype" + }, + "heightm": 3.2, + "weightkg": 320, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "victini": { + "num": 494, + "species": "Victini", + "types": [ + "Psychic", + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 100, + "def": 100, + "spa": 100, + "spd": 100, + "spe": 100 + }, + "abilities": { + "0": "Victory Star" + }, + "heightm": 0.4, + "weightkg": 4, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "snivy": { + "num": 495, + "species": "Snivy", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 45, + "atk": 45, + "def": 55, + "spa": 45, + "spd": 55, + "spe": 63 + }, + "abilities": { + "0": "Overgrow", + "H": "Contrary" + }, + "heightm": 0.6, + "weightkg": 8.1, + "color": "Green", + "evos": [ + "servine" + ], + "eggGroups": [ + "Field", + "Grass" + ] + }, + "servine": { + "num": 496, + "species": "Servine", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 60, + "def": 75, + "spa": 60, + "spd": 75, + "spe": 83 + }, + "abilities": { + "0": "Overgrow", + "H": "Contrary" + }, + "heightm": 0.8, + "weightkg": 16, + "color": "Green", + "prevo": "snivy", + "evos": [ + "serperior" + ], + "evoLevel": 17, + "eggGroups": [ + "Field", + "Grass" + ] + }, + "serperior": { + "num": 497, + "species": "Serperior", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 75, + "def": 95, + "spa": 75, + "spd": 95, + "spe": 113 + }, + "abilities": { + "0": "Overgrow", + "H": "Contrary" + }, + "heightm": 3.3, + "weightkg": 63, + "color": "Green", + "prevo": "servine", + "evoLevel": 36, + "eggGroups": [ + "Field", + "Grass" + ] + }, + "tepig": { + "num": 498, + "species": "Tepig", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 63, + "def": 45, + "spa": 45, + "spd": 45, + "spe": 45 + }, + "abilities": { + "0": "Blaze", + "H": "Thick Fat" + }, + "heightm": 0.5, + "weightkg": 9.9, + "color": "Red", + "evos": [ + "pignite" + ], + "eggGroups": [ + "Field" + ] + }, + "pignite": { + "num": 499, + "species": "Pignite", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 90, + "atk": 93, + "def": 55, + "spa": 70, + "spd": 55, + "spe": 55 + }, + "abilities": { + "0": "Blaze", + "H": "Thick Fat" + }, + "heightm": 1, + "weightkg": 55.5, + "color": "Red", + "prevo": "tepig", + "evos": [ + "emboar" + ], + "evoLevel": 17, + "eggGroups": [ + "Field" + ] + }, + "emboar": { + "num": 500, + "species": "Emboar", + "types": [ + "Fire", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 110, + "atk": 123, + "def": 65, + "spa": 100, + "spd": 65, + "spe": 65 + }, + "abilities": { + "0": "Blaze", + "H": "Reckless" + }, + "heightm": 1.6, + "weightkg": 150, + "color": "Red", + "prevo": "pignite", + "evoLevel": 36, + "eggGroups": [ + "Field" + ] + }, + "oshawott": { + "num": 501, + "species": "Oshawott", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 55, + "atk": 55, + "def": 45, + "spa": 63, + "spd": 45, + "spe": 45 + }, + "abilities": { + "0": "Torrent", + "H": "Shell Armor" + }, + "heightm": 0.5, + "weightkg": 5.9, + "color": "Blue", + "evos": [ + "dewott" + ], + "eggGroups": [ + "Field" + ] + }, + "dewott": { + "num": 502, + "species": "Dewott", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 75, + "def": 60, + "spa": 83, + "spd": 60, + "spe": 60 + }, + "abilities": { + "0": "Torrent", + "H": "Shell Armor" + }, + "heightm": 0.8, + "weightkg": 24.5, + "color": "Blue", + "prevo": "oshawott", + "evos": [ + "samurott" + ], + "evoLevel": 17, + "eggGroups": [ + "Field" + ] + }, + "samurott": { + "num": 503, + "species": "Samurott", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 95, + "atk": 100, + "def": 85, + "spa": 108, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Torrent", + "H": "Shell Armor" + }, + "heightm": 1.5, + "weightkg": 94.6, + "color": "Blue", + "prevo": "dewott", + "evoLevel": 36, + "eggGroups": [ + "Field" + ] + }, + "patrat": { + "num": 504, + "species": "Patrat", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 45, + "atk": 55, + "def": 39, + "spa": 35, + "spd": 39, + "spe": 42 + }, + "abilities": { + "0": "Run Away", + "1": "Keen Eye", + "H": "Analytic" + }, + "heightm": 0.5, + "weightkg": 11.6, + "color": "Brown", + "evos": [ + "watchog" + ], + "eggGroups": [ + "Field" + ] + }, + "watchog": { + "num": 505, + "species": "Watchog", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 60, + "atk": 85, + "def": 69, + "spa": 60, + "spd": 69, + "spe": 77 + }, + "abilities": { + "0": "Illuminate", + "1": "Keen Eye", + "H": "Analytic" + }, + "heightm": 1.1, + "weightkg": 27, + "color": "Brown", + "prevo": "patrat", + "evoLevel": 20, + "eggGroups": [ + "Field" + ] + }, + "lillipup": { + "num": 506, + "species": "Lillipup", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 45, + "atk": 60, + "def": 45, + "spa": 25, + "spd": 45, + "spe": 55 + }, + "abilities": { + "0": "Vital Spirit", + "1": "Pickup", + "H": "Run Away" + }, + "heightm": 0.4, + "weightkg": 4.1, + "color": "Brown", + "evos": [ + "herdier" + ], + "eggGroups": [ + "Field" + ] + }, + "herdier": { + "num": 507, + "species": "Herdier", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 65, + "atk": 80, + "def": 65, + "spa": 35, + "spd": 65, + "spe": 60 + }, + "abilities": { + "0": "Intimidate", + "1": "Sand Rush", + "H": "Scrappy" + }, + "heightm": 0.9, + "weightkg": 14.7, + "color": "Gray", + "prevo": "lillipup", + "evos": [ + "stoutland" + ], + "evoLevel": 16, + "eggGroups": [ + "Field" + ] + }, + "stoutland": { + "num": 508, + "species": "Stoutland", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 85, + "atk": 110, + "def": 90, + "spa": 45, + "spd": 90, + "spe": 80 + }, + "abilities": { + "0": "Intimidate", + "1": "Sand Rush", + "H": "Scrappy" + }, + "heightm": 1.2, + "weightkg": 61, + "color": "Gray", + "prevo": "herdier", + "evoLevel": 32, + "eggGroups": [ + "Field" + ] + }, + "purrloin": { + "num": 509, + "species": "Purrloin", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 41, + "atk": 50, + "def": 37, + "spa": 50, + "spd": 37, + "spe": 66 + }, + "abilities": { + "0": "Limber", + "1": "Unburden", + "H": "Prankster" + }, + "heightm": 0.4, + "weightkg": 10.1, + "color": "Purple", + "evos": [ + "liepard" + ], + "eggGroups": [ + "Field" + ] + }, + "liepard": { + "num": 510, + "species": "Liepard", + "types": [ + "Dark" + ], + "baseStats": { + "hp": 64, + "atk": 88, + "def": 50, + "spa": 88, + "spd": 50, + "spe": 106 + }, + "abilities": { + "0": "Limber", + "1": "Unburden", + "H": "Prankster" + }, + "heightm": 1.1, + "weightkg": 37.5, + "color": "Purple", + "prevo": "purrloin", + "evoLevel": 20, + "eggGroups": [ + "Field" + ] + }, + "pansage": { + "num": 511, + "species": "Pansage", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 53, + "def": 48, + "spa": 53, + "spd": 48, + "spe": 64 + }, + "abilities": { + "0": "Gluttony", + "H": "Overgrow" + }, + "heightm": 0.6, + "weightkg": 10.5, + "color": "Green", + "evos": [ + "simisage" + ], + "eggGroups": [ + "Field" + ] + }, + "simisage": { + "num": 512, + "species": "Simisage", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 98, + "def": 63, + "spa": 98, + "spd": 63, + "spe": 101 + }, + "abilities": { + "0": "Gluttony", + "H": "Overgrow" + }, + "heightm": 1.1, + "weightkg": 30.5, + "color": "Green", + "prevo": "pansage", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "pansear": { + "num": 513, + "species": "Pansear", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 53, + "def": 48, + "spa": 53, + "spd": 48, + "spe": 64 + }, + "abilities": { + "0": "Gluttony", + "H": "Blaze" + }, + "heightm": 0.6, + "weightkg": 11, + "color": "Red", + "evos": [ + "simisear" + ], + "eggGroups": [ + "Field" + ] + }, + "simisear": { + "num": 514, + "species": "Simisear", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 98, + "def": 63, + "spa": 98, + "spd": 63, + "spe": 101 + }, + "abilities": { + "0": "Gluttony", + "H": "Blaze" + }, + "heightm": 1, + "weightkg": 28, + "color": "Red", + "prevo": "pansear", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "panpour": { + "num": 515, + "species": "Panpour", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 53, + "def": 48, + "spa": 53, + "spd": 48, + "spe": 64 + }, + "abilities": { + "0": "Gluttony", + "H": "Torrent" + }, + "heightm": 0.6, + "weightkg": 13.5, + "color": "Blue", + "evos": [ + "simipour" + ], + "eggGroups": [ + "Field" + ] + }, + "simipour": { + "num": 516, + "species": "Simipour", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 98, + "def": 63, + "spa": 98, + "spd": 63, + "spe": 101 + }, + "abilities": { + "0": "Gluttony", + "H": "Torrent" + }, + "heightm": 1, + "weightkg": 29, + "color": "Blue", + "prevo": "panpour", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "munna": { + "num": 517, + "species": "Munna", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 76, + "atk": 25, + "def": 45, + "spa": 67, + "spd": 55, + "spe": 24 + }, + "abilities": { + "0": "Forewarn", + "1": "Synchronize", + "H": "Telepathy" + }, + "heightm": 0.6, + "weightkg": 23.3, + "color": "Pink", + "evos": [ + "musharna" + ], + "eggGroups": [ + "Field" + ] + }, + "musharna": { + "num": 518, + "species": "Musharna", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 116, + "atk": 55, + "def": 85, + "spa": 107, + "spd": 95, + "spe": 29 + }, + "abilities": { + "0": "Forewarn", + "1": "Synchronize", + "H": "Telepathy" + }, + "heightm": 1.1, + "weightkg": 60.5, + "color": "Pink", + "prevo": "munna", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "pidove": { + "num": 519, + "species": "Pidove", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 50, + "atk": 55, + "def": 50, + "spa": 36, + "spd": 30, + "spe": 43 + }, + "abilities": { + "0": "Big Pecks", + "1": "Super Luck", + "H": "Rivalry" + }, + "heightm": 0.3, + "weightkg": 2.1, + "color": "Gray", + "evos": [ + "tranquill" + ], + "eggGroups": [ + "Flying" + ] + }, + "tranquill": { + "num": 520, + "species": "Tranquill", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 62, + "atk": 77, + "def": 62, + "spa": 50, + "spd": 42, + "spe": 65 + }, + "abilities": { + "0": "Big Pecks", + "1": "Super Luck", + "H": "Rivalry" + }, + "heightm": 0.6, + "weightkg": 15, + "color": "Gray", + "prevo": "pidove", + "evos": [ + "unfezant" + ], + "evoLevel": 21, + "eggGroups": [ + "Flying" + ] + }, + "unfezant": { + "num": 521, + "species": "Unfezant", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 80, + "atk": 115, + "def": 80, + "spa": 65, + "spd": 55, + "spe": 93 + }, + "abilities": { + "0": "Big Pecks", + "1": "Super Luck", + "H": "Rivalry" + }, + "heightm": 1.2, + "weightkg": 29, + "color": "Gray", + "prevo": "tranquill", + "evoLevel": 32, + "eggGroups": [ + "Flying" + ] + }, + "blitzle": { + "num": 522, + "species": "Blitzle", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 45, + "atk": 60, + "def": 32, + "spa": 50, + "spd": 32, + "spe": 76 + }, + "abilities": { + "0": "Lightning Rod", + "1": "Motor Drive", + "H": "Sap Sipper" + }, + "heightm": 0.8, + "weightkg": 29.8, + "color": "Black", + "evos": [ + "zebstrika" + ], + "eggGroups": [ + "Field" + ] + }, + "zebstrika": { + "num": 523, + "species": "Zebstrika", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 75, + "atk": 100, + "def": 63, + "spa": 80, + "spd": 63, + "spe": 116 + }, + "abilities": { + "0": "Lightning Rod", + "1": "Motor Drive", + "H": "Sap Sipper" + }, + "heightm": 1.6, + "weightkg": 79.5, + "color": "Black", + "prevo": "blitzle", + "evoLevel": 27, + "eggGroups": [ + "Field" + ] + }, + "roggenrola": { + "num": 524, + "species": "Roggenrola", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 55, + "atk": 75, + "def": 85, + "spa": 25, + "spd": 25, + "spe": 15 + }, + "abilities": { + "0": "Sturdy", + "1": "Weak Armor", + "H": "Sand Force" + }, + "heightm": 0.4, + "weightkg": 18, + "color": "Blue", + "evos": [ + "boldore" + ], + "eggGroups": [ + "Mineral" + ] + }, + "boldore": { + "num": 525, + "species": "Boldore", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 70, + "atk": 105, + "def": 105, + "spa": 50, + "spd": 40, + "spe": 20 + }, + "abilities": { + "0": "Sturdy", + "1": "Weak Armor", + "H": "Sand Force" + }, + "heightm": 0.9, + "weightkg": 102, + "color": "Blue", + "prevo": "roggenrola", + "evos": [ + "gigalith" + ], + "evoLevel": 25, + "eggGroups": [ + "Mineral" + ] + }, + "gigalith": { + "num": 526, + "species": "Gigalith", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 85, + "atk": 135, + "def": 130, + "spa": 60, + "spd": 80, + "spe": 25 + }, + "abilities": { + "0": "Sturdy", + "1": "Sand Stream", + "H": "Sand Force" + }, + "heightm": 1.7, + "weightkg": 260, + "color": "Blue", + "prevo": "boldore", + "evoLevel": 25, + "eggGroups": [ + "Mineral" + ] + }, + "woobat": { + "num": 527, + "species": "Woobat", + "types": [ + "Psychic", + "Flying" + ], + "baseStats": { + "hp": 65, + "atk": 45, + "def": 43, + "spa": 55, + "spd": 43, + "spe": 72 + }, + "abilities": { + "0": "Unaware", + "1": "Klutz", + "H": "Simple" + }, + "heightm": 0.4, + "weightkg": 2.1, + "color": "Blue", + "evos": [ + "swoobat" + ], + "eggGroups": [ + "Flying", + "Field" + ] + }, + "swoobat": { + "num": 528, + "species": "Swoobat", + "types": [ + "Psychic", + "Flying" + ], + "baseStats": { + "hp": 67, + "atk": 57, + "def": 55, + "spa": 77, + "spd": 55, + "spe": 114 + }, + "abilities": { + "0": "Unaware", + "1": "Klutz", + "H": "Simple" + }, + "heightm": 0.9, + "weightkg": 10.5, + "color": "Blue", + "prevo": "woobat", + "evoLevel": 2, + "eggGroups": [ + "Flying", + "Field" + ] + }, + "drilbur": { + "num": 529, + "species": "Drilbur", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 60, + "atk": 85, + "def": 40, + "spa": 30, + "spd": 45, + "spe": 68 + }, + "abilities": { + "0": "Sand Rush", + "1": "Sand Force", + "H": "Mold Breaker" + }, + "heightm": 0.3, + "weightkg": 8.5, + "color": "Gray", + "evos": [ + "excadrill" + ], + "eggGroups": [ + "Field" + ] + }, + "excadrill": { + "num": 530, + "species": "Excadrill", + "types": [ + "Ground", + "Steel" + ], + "baseStats": { + "hp": 110, + "atk": 135, + "def": 60, + "spa": 50, + "spd": 65, + "spe": 88 + }, + "abilities": { + "0": "Sand Rush", + "1": "Sand Force", + "H": "Mold Breaker" + }, + "heightm": 0.7, + "weightkg": 40.4, + "color": "Gray", + "prevo": "drilbur", + "evoLevel": 31, + "eggGroups": [ + "Field" + ] + }, + "audino": { + "num": 531, + "species": "Audino", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 103, + "atk": 60, + "def": 86, + "spa": 60, + "spd": 86, + "spe": 50 + }, + "abilities": { + "0": "Healer", + "1": "Regenerator", + "H": "Klutz" + }, + "heightm": 1.1, + "weightkg": 31, + "color": "Pink", + "eggGroups": [ + "Fairy" + ], + "otherFormes": [ + "audinomega" + ] + }, + "audinomega": { + "num": 531, + "species": "Audino-Mega", + "baseSpecies": "Audino", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Normal", + "Fairy" + ], + "baseStats": { + "hp": 103, + "atk": 60, + "def": 126, + "spa": 80, + "spd": 126, + "spe": 50 + }, + "abilities": { + "0": "Healer" + }, + "heightm": 1.5, + "weightkg": 32, + "color": "Pink", + "eggGroups": [ + "Fairy" + ] + }, + "timburr": { + "num": 532, + "species": "Timburr", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 75, + "atk": 80, + "def": 55, + "spa": 25, + "spd": 35, + "spe": 35 + }, + "abilities": { + "0": "Guts", + "1": "Sheer Force", + "H": "Iron Fist" + }, + "heightm": 0.6, + "weightkg": 12.5, + "color": "Gray", + "evos": [ + "gurdurr" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "gurdurr": { + "num": 533, + "species": "Gurdurr", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 85, + "atk": 105, + "def": 85, + "spa": 40, + "spd": 50, + "spe": 40 + }, + "abilities": { + "0": "Guts", + "1": "Sheer Force", + "H": "Iron Fist" + }, + "heightm": 1.2, + "weightkg": 40, + "color": "Gray", + "prevo": "timburr", + "evos": [ + "conkeldurr" + ], + "evoLevel": 25, + "eggGroups": [ + "Human-Like" + ] + }, + "conkeldurr": { + "num": 534, + "species": "Conkeldurr", + "types": [ + "Fighting" + ], + "genderRatio": { + "M": 0.75, + "F": 0.25 + }, + "baseStats": { + "hp": 105, + "atk": 140, + "def": 95, + "spa": 55, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Guts", + "1": "Sheer Force", + "H": "Iron Fist" + }, + "heightm": 1.4, + "weightkg": 87, + "color": "Brown", + "prevo": "gurdurr", + "evoLevel": 25, + "eggGroups": [ + "Human-Like" + ] + }, + "tympole": { + "num": 535, + "species": "Tympole", + "types": [ + "Water" + ], + "baseStats": { + "hp": 50, + "atk": 50, + "def": 40, + "spa": 50, + "spd": 40, + "spe": 64 + }, + "abilities": { + "0": "Swift Swim", + "1": "Hydration", + "H": "Water Absorb" + }, + "heightm": 0.5, + "weightkg": 4.5, + "color": "Blue", + "evos": [ + "palpitoad" + ], + "eggGroups": [ + "Water 1" + ] + }, + "palpitoad": { + "num": 536, + "species": "Palpitoad", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 75, + "atk": 65, + "def": 55, + "spa": 65, + "spd": 55, + "spe": 69 + }, + "abilities": { + "0": "Swift Swim", + "1": "Hydration", + "H": "Water Absorb" + }, + "heightm": 0.8, + "weightkg": 17, + "color": "Blue", + "prevo": "tympole", + "evos": [ + "seismitoad" + ], + "evoLevel": 25, + "eggGroups": [ + "Water 1" + ] + }, + "seismitoad": { + "num": 537, + "species": "Seismitoad", + "types": [ + "Water", + "Ground" + ], + "baseStats": { + "hp": 105, + "atk": 95, + "def": 75, + "spa": 85, + "spd": 75, + "spe": 74 + }, + "abilities": { + "0": "Swift Swim", + "1": "Poison Touch", + "H": "Water Absorb" + }, + "heightm": 1.5, + "weightkg": 62, + "color": "Blue", + "prevo": "palpitoad", + "evoLevel": 36, + "eggGroups": [ + "Water 1" + ] + }, + "throh": { + "num": 538, + "species": "Throh", + "types": [ + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 120, + "atk": 100, + "def": 85, + "spa": 30, + "spd": 85, + "spe": 45 + }, + "abilities": { + "0": "Guts", + "1": "Inner Focus", + "H": "Mold Breaker" + }, + "heightm": 1.3, + "weightkg": 55.5, + "color": "Red", + "eggGroups": [ + "Human-Like" + ] + }, + "sawk": { + "num": 539, + "species": "Sawk", + "types": [ + "Fighting" + ], + "gender": "M", + "baseStats": { + "hp": 75, + "atk": 125, + "def": 75, + "spa": 30, + "spd": 75, + "spe": 85 + }, + "abilities": { + "0": "Sturdy", + "1": "Inner Focus", + "H": "Mold Breaker" + }, + "heightm": 1.4, + "weightkg": 51, + "color": "Blue", + "eggGroups": [ + "Human-Like" + ] + }, + "sewaddle": { + "num": 540, + "species": "Sewaddle", + "types": [ + "Bug", + "Grass" + ], + "baseStats": { + "hp": 45, + "atk": 53, + "def": 70, + "spa": 40, + "spd": 60, + "spe": 42 + }, + "abilities": { + "0": "Swarm", + "1": "Chlorophyll", + "H": "Overcoat" + }, + "heightm": 0.3, + "weightkg": 2.5, + "color": "Yellow", + "evos": [ + "swadloon" + ], + "eggGroups": [ + "Bug" + ] + }, + "swadloon": { + "num": 541, + "species": "Swadloon", + "types": [ + "Bug", + "Grass" + ], + "baseStats": { + "hp": 55, + "atk": 63, + "def": 90, + "spa": 50, + "spd": 80, + "spe": 42 + }, + "abilities": { + "0": "Leaf Guard", + "1": "Chlorophyll", + "H": "Overcoat" + }, + "heightm": 0.5, + "weightkg": 7.3, + "color": "Green", + "prevo": "sewaddle", + "evos": [ + "leavanny" + ], + "evoLevel": 20, + "eggGroups": [ + "Bug" + ] + }, + "leavanny": { + "num": 542, + "species": "Leavanny", + "types": [ + "Bug", + "Grass" + ], + "baseStats": { + "hp": 75, + "atk": 103, + "def": 80, + "spa": 70, + "spd": 80, + "spe": 92 + }, + "abilities": { + "0": "Swarm", + "1": "Chlorophyll", + "H": "Overcoat" + }, + "heightm": 1.2, + "weightkg": 20.5, + "color": "Yellow", + "prevo": "swadloon", + "evoLevel": 21, + "eggGroups": [ + "Bug" + ] + }, + "venipede": { + "num": 543, + "species": "Venipede", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 30, + "atk": 45, + "def": 59, + "spa": 30, + "spd": 39, + "spe": 57 + }, + "abilities": { + "0": "Poison Point", + "1": "Swarm", + "H": "Speed Boost" + }, + "heightm": 0.4, + "weightkg": 5.3, + "color": "Red", + "evos": [ + "whirlipede" + ], + "eggGroups": [ + "Bug" + ] + }, + "whirlipede": { + "num": 544, + "species": "Whirlipede", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 40, + "atk": 55, + "def": 99, + "spa": 40, + "spd": 79, + "spe": 47 + }, + "abilities": { + "0": "Poison Point", + "1": "Swarm", + "H": "Speed Boost" + }, + "heightm": 1.2, + "weightkg": 58.5, + "color": "Gray", + "prevo": "venipede", + "evos": [ + "scolipede" + ], + "evoLevel": 22, + "eggGroups": [ + "Bug" + ] + }, + "scolipede": { + "num": 545, + "species": "Scolipede", + "types": [ + "Bug", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 100, + "def": 89, + "spa": 55, + "spd": 69, + "spe": 112 + }, + "abilities": { + "0": "Poison Point", + "1": "Swarm", + "H": "Speed Boost" + }, + "heightm": 2.5, + "weightkg": 200.5, + "color": "Red", + "prevo": "whirlipede", + "evoLevel": 30, + "eggGroups": [ + "Bug" + ] + }, + "cottonee": { + "num": 546, + "species": "Cottonee", + "types": [ + "Grass", + "Fairy" + ], + "baseStats": { + "hp": 40, + "atk": 27, + "def": 60, + "spa": 37, + "spd": 50, + "spe": 66 + }, + "abilities": { + "0": "Prankster", + "1": "Infiltrator", + "H": "Chlorophyll" + }, + "heightm": 0.3, + "weightkg": 0.6, + "color": "Green", + "evos": [ + "whimsicott" + ], + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "whimsicott": { + "num": 547, + "species": "Whimsicott", + "types": [ + "Grass", + "Fairy" + ], + "baseStats": { + "hp": 60, + "atk": 67, + "def": 85, + "spa": 77, + "spd": 75, + "spe": 116 + }, + "abilities": { + "0": "Prankster", + "1": "Infiltrator", + "H": "Chlorophyll" + }, + "heightm": 0.7, + "weightkg": 6.6, + "color": "Green", + "prevo": "cottonee", + "evoLevel": 1, + "eggGroups": [ + "Fairy", + "Grass" + ] + }, + "petilil": { + "num": 548, + "species": "Petilil", + "types": [ + "Grass" + ], + "gender": "F", + "baseStats": { + "hp": 45, + "atk": 35, + "def": 50, + "spa": 70, + "spd": 50, + "spe": 30 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Own Tempo", + "H": "Leaf Guard" + }, + "heightm": 0.5, + "weightkg": 6.6, + "color": "Green", + "evos": [ + "lilligant" + ], + "eggGroups": [ + "Grass" + ] + }, + "lilligant": { + "num": 549, + "species": "Lilligant", + "types": [ + "Grass" + ], + "gender": "F", + "baseStats": { + "hp": 70, + "atk": 60, + "def": 75, + "spa": 110, + "spd": 75, + "spe": 90 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Own Tempo", + "H": "Leaf Guard" + }, + "heightm": 1.1, + "weightkg": 16.3, + "color": "Green", + "prevo": "petilil", + "evoLevel": 1, + "eggGroups": [ + "Grass" + ] + }, + "basculin": { + "num": 550, + "species": "Basculin", + "baseForme": "Red-Striped", + "types": [ + "Water" + ], + "baseStats": { + "hp": 70, + "atk": 92, + "def": 65, + "spa": 80, + "spd": 55, + "spe": 98 + }, + "abilities": { + "0": "Reckless", + "1": "Adaptability", + "H": "Mold Breaker" + }, + "heightm": 1, + "weightkg": 18, + "color": "Green", + "eggGroups": [ + "Water 2" + ], + "otherFormes": [ + "basculinbluestriped" + ] + }, + "basculinbluestriped": { + "num": 550, + "species": "Basculin-Blue-Striped", + "baseSpecies": "Basculin", + "forme": "Blue-Striped", + "formeLetter": "B", + "types": [ + "Water" + ], + "baseStats": { + "hp": 70, + "atk": 92, + "def": 65, + "spa": 80, + "spd": 55, + "spe": 98 + }, + "abilities": { + "0": "Rock Head", + "1": "Adaptability", + "H": "Mold Breaker" + }, + "heightm": 1, + "weightkg": 18, + "color": "Green", + "eggGroups": [ + "Water 2" + ] + }, + "sandile": { + "num": 551, + "species": "Sandile", + "types": [ + "Ground", + "Dark" + ], + "baseStats": { + "hp": 50, + "atk": 72, + "def": 35, + "spa": 35, + "spd": 35, + "spe": 65 + }, + "abilities": { + "0": "Intimidate", + "1": "Moxie", + "H": "Anger Point" + }, + "heightm": 0.7, + "weightkg": 15.2, + "color": "Brown", + "evos": [ + "krokorok" + ], + "eggGroups": [ + "Field" + ] + }, + "krokorok": { + "num": 552, + "species": "Krokorok", + "types": [ + "Ground", + "Dark" + ], + "baseStats": { + "hp": 60, + "atk": 82, + "def": 45, + "spa": 45, + "spd": 45, + "spe": 74 + }, + "abilities": { + "0": "Intimidate", + "1": "Moxie", + "H": "Anger Point" + }, + "heightm": 1, + "weightkg": 33.4, + "color": "Brown", + "prevo": "sandile", + "evos": [ + "krookodile" + ], + "evoLevel": 29, + "eggGroups": [ + "Field" + ] + }, + "krookodile": { + "num": 553, + "species": "Krookodile", + "types": [ + "Ground", + "Dark" + ], + "baseStats": { + "hp": 95, + "atk": 117, + "def": 80, + "spa": 65, + "spd": 70, + "spe": 92 + }, + "abilities": { + "0": "Intimidate", + "1": "Moxie", + "H": "Anger Point" + }, + "heightm": 1.5, + "weightkg": 96.3, + "color": "Red", + "prevo": "krokorok", + "evoLevel": 40, + "eggGroups": [ + "Field" + ] + }, + "darumaka": { + "num": 554, + "species": "Darumaka", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 70, + "atk": 90, + "def": 45, + "spa": 15, + "spd": 45, + "spe": 50 + }, + "abilities": { + "0": "Hustle", + "H": "Inner Focus" + }, + "heightm": 0.6, + "weightkg": 37.5, + "color": "Red", + "evos": [ + "darmanitan" + ], + "eggGroups": [ + "Field" + ] + }, + "darmanitan": { + "num": 555, + "species": "Darmanitan", + "baseForme": "Standard", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 105, + "atk": 140, + "def": 55, + "spa": 30, + "spd": 55, + "spe": 95 + }, + "abilities": { + "0": "Sheer Force", + "H": "Zen Mode" + }, + "heightm": 1.3, + "weightkg": 92.9, + "color": "Red", + "prevo": "darumaka", + "evoLevel": 35, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "darmanitanzen" + ] + }, + "darmanitanzen": { + "num": 555, + "species": "Darmanitan-Zen", + "baseSpecies": "Darmanitan", + "forme": "Zen", + "formeLetter": "Z", + "types": [ + "Fire", + "Psychic" + ], + "baseStats": { + "hp": 105, + "atk": 30, + "def": 105, + "spa": 140, + "spd": 105, + "spe": 55 + }, + "abilities": { + "0": "Zen Mode" + }, + "heightm": 1.3, + "weightkg": 92.9, + "color": "Red", + "prevo": "darumaka", + "evoLevel": 35, + "eggGroups": [ + "Field" + ] + }, + "maractus": { + "num": 556, + "species": "Maractus", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 75, + "atk": 86, + "def": 67, + "spa": 106, + "spd": 67, + "spe": 60 + }, + "abilities": { + "0": "Water Absorb", + "1": "Chlorophyll", + "H": "Storm Drain" + }, + "heightm": 1, + "weightkg": 28, + "color": "Green", + "eggGroups": [ + "Grass" + ] + }, + "dwebble": { + "num": 557, + "species": "Dwebble", + "types": [ + "Bug", + "Rock" + ], + "baseStats": { + "hp": 50, + "atk": 65, + "def": 85, + "spa": 35, + "spd": 35, + "spe": 55 + }, + "abilities": { + "0": "Sturdy", + "1": "Shell Armor", + "H": "Weak Armor" + }, + "heightm": 0.3, + "weightkg": 14.5, + "color": "Red", + "evos": [ + "crustle" + ], + "eggGroups": [ + "Bug", + "Mineral" + ] + }, + "crustle": { + "num": 558, + "species": "Crustle", + "types": [ + "Bug", + "Rock" + ], + "baseStats": { + "hp": 70, + "atk": 105, + "def": 125, + "spa": 65, + "spd": 75, + "spe": 45 + }, + "abilities": { + "0": "Sturdy", + "1": "Shell Armor", + "H": "Weak Armor" + }, + "heightm": 1.4, + "weightkg": 200, + "color": "Red", + "prevo": "dwebble", + "evoLevel": 34, + "eggGroups": [ + "Bug", + "Mineral" + ] + }, + "scraggy": { + "num": 559, + "species": "Scraggy", + "types": [ + "Dark", + "Fighting" + ], + "baseStats": { + "hp": 50, + "atk": 75, + "def": 70, + "spa": 35, + "spd": 70, + "spe": 48 + }, + "abilities": { + "0": "Shed Skin", + "1": "Moxie", + "H": "Intimidate" + }, + "heightm": 0.6, + "weightkg": 11.8, + "color": "Yellow", + "evos": [ + "scrafty" + ], + "eggGroups": [ + "Field", + "Dragon" + ] + }, + "scrafty": { + "num": 560, + "species": "Scrafty", + "types": [ + "Dark", + "Fighting" + ], + "baseStats": { + "hp": 65, + "atk": 90, + "def": 115, + "spa": 45, + "spd": 115, + "spe": 58 + }, + "abilities": { + "0": "Shed Skin", + "1": "Moxie", + "H": "Intimidate" + }, + "heightm": 1.1, + "weightkg": 30, + "color": "Red", + "prevo": "scraggy", + "evoLevel": 39, + "eggGroups": [ + "Field", + "Dragon" + ] + }, + "sigilyph": { + "num": 561, + "species": "Sigilyph", + "types": [ + "Psychic", + "Flying" + ], + "baseStats": { + "hp": 72, + "atk": 58, + "def": 80, + "spa": 103, + "spd": 80, + "spe": 97 + }, + "abilities": { + "0": "Wonder Skin", + "1": "Magic Guard", + "H": "Tinted Lens" + }, + "heightm": 1.4, + "weightkg": 14, + "color": "Black", + "eggGroups": [ + "Flying" + ] + }, + "yamask": { + "num": 562, + "species": "Yamask", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 38, + "atk": 30, + "def": 85, + "spa": 55, + "spd": 65, + "spe": 30 + }, + "abilities": { + "0": "Mummy" + }, + "heightm": 0.5, + "weightkg": 1.5, + "color": "Black", + "evos": [ + "cofagrigus" + ], + "eggGroups": [ + "Mineral", + "Amorphous" + ] + }, + "cofagrigus": { + "num": 563, + "species": "Cofagrigus", + "types": [ + "Ghost" + ], + "baseStats": { + "hp": 58, + "atk": 50, + "def": 145, + "spa": 95, + "spd": 105, + "spe": 30 + }, + "abilities": { + "0": "Mummy" + }, + "heightm": 1.7, + "weightkg": 76.5, + "color": "Yellow", + "prevo": "yamask", + "evoLevel": 34, + "eggGroups": [ + "Mineral", + "Amorphous" + ] + }, + "tirtouga": { + "num": 564, + "species": "Tirtouga", + "types": [ + "Water", + "Rock" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 54, + "atk": 78, + "def": 103, + "spa": 53, + "spd": 45, + "spe": 22 + }, + "abilities": { + "0": "Solid Rock", + "1": "Sturdy", + "H": "Swift Swim" + }, + "heightm": 0.7, + "weightkg": 16.5, + "color": "Blue", + "evos": [ + "carracosta" + ], + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "carracosta": { + "num": 565, + "species": "Carracosta", + "types": [ + "Water", + "Rock" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 74, + "atk": 108, + "def": 133, + "spa": 83, + "spd": 65, + "spe": 32 + }, + "abilities": { + "0": "Solid Rock", + "1": "Sturdy", + "H": "Swift Swim" + }, + "heightm": 1.2, + "weightkg": 81, + "color": "Blue", + "prevo": "tirtouga", + "evoLevel": 37, + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "archen": { + "num": 566, + "species": "Archen", + "types": [ + "Rock", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 55, + "atk": 112, + "def": 45, + "spa": 74, + "spd": 45, + "spe": 70 + }, + "abilities": { + "0": "Defeatist" + }, + "heightm": 0.5, + "weightkg": 9.5, + "color": "Yellow", + "evos": [ + "archeops" + ], + "eggGroups": [ + "Flying", + "Water 3" + ] + }, + "archeops": { + "num": 567, + "species": "Archeops", + "types": [ + "Rock", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 140, + "def": 65, + "spa": 112, + "spd": 65, + "spe": 110 + }, + "abilities": { + "0": "Defeatist" + }, + "heightm": 1.4, + "weightkg": 32, + "color": "Yellow", + "prevo": "archen", + "evoLevel": 37, + "eggGroups": [ + "Flying", + "Water 3" + ] + }, + "trubbish": { + "num": 568, + "species": "Trubbish", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 50, + "atk": 50, + "def": 62, + "spa": 40, + "spd": 62, + "spe": 65 + }, + "abilities": { + "0": "Stench", + "1": "Sticky Hold", + "H": "Aftermath" + }, + "heightm": 0.6, + "weightkg": 31, + "color": "Green", + "evos": [ + "garbodor" + ], + "eggGroups": [ + "Mineral" + ] + }, + "garbodor": { + "num": 569, + "species": "Garbodor", + "types": [ + "Poison" + ], + "baseStats": { + "hp": 80, + "atk": 95, + "def": 82, + "spa": 60, + "spd": 82, + "spe": 75 + }, + "abilities": { + "0": "Stench", + "1": "Weak Armor", + "H": "Aftermath" + }, + "heightm": 1.9, + "weightkg": 107.3, + "color": "Green", + "prevo": "trubbish", + "evoLevel": 36, + "eggGroups": [ + "Mineral" + ] + }, + "zorua": { + "num": 570, + "species": "Zorua", + "types": [ + "Dark" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 40, + "atk": 65, + "def": 40, + "spa": 80, + "spd": 40, + "spe": 65 + }, + "abilities": { + "0": "Illusion" + }, + "heightm": 0.7, + "weightkg": 12.5, + "color": "Gray", + "evos": [ + "zoroark" + ], + "eggGroups": [ + "Field" + ] + }, + "zoroark": { + "num": 571, + "species": "Zoroark", + "types": [ + "Dark" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 105, + "def": 60, + "spa": 120, + "spd": 60, + "spe": 105 + }, + "abilities": { + "0": "Illusion" + }, + "heightm": 1.6, + "weightkg": 81.1, + "color": "Gray", + "prevo": "zorua", + "evoLevel": 30, + "eggGroups": [ + "Field" + ] + }, + "minccino": { + "num": 572, + "species": "Minccino", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 55, + "atk": 50, + "def": 40, + "spa": 40, + "spd": 40, + "spe": 75 + }, + "abilities": { + "0": "Cute Charm", + "1": "Technician", + "H": "Skill Link" + }, + "heightm": 0.4, + "weightkg": 5.8, + "color": "Gray", + "evos": [ + "cinccino" + ], + "eggGroups": [ + "Field" + ] + }, + "cinccino": { + "num": 573, + "species": "Cinccino", + "types": [ + "Normal" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 75, + "atk": 95, + "def": 60, + "spa": 65, + "spd": 60, + "spe": 115 + }, + "abilities": { + "0": "Cute Charm", + "1": "Technician", + "H": "Skill Link" + }, + "heightm": 0.5, + "weightkg": 7.5, + "color": "Gray", + "prevo": "minccino", + "evoLevel": 1, + "eggGroups": [ + "Field" + ] + }, + "gothita": { + "num": 574, + "species": "Gothita", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 45, + "atk": 30, + "def": 50, + "spa": 55, + "spd": 65, + "spe": 45 + }, + "abilities": { + "0": "Frisk", + "1": "Competitive", + "H": "Shadow Tag" + }, + "heightm": 0.4, + "weightkg": 5.8, + "color": "Purple", + "evos": [ + "gothorita" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "gothorita": { + "num": 575, + "species": "Gothorita", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 60, + "atk": 45, + "def": 70, + "spa": 75, + "spd": 85, + "spe": 55 + }, + "abilities": { + "0": "Frisk", + "1": "Competitive", + "H": "Shadow Tag" + }, + "heightm": 0.7, + "weightkg": 18, + "color": "Purple", + "prevo": "gothita", + "evos": [ + "gothitelle" + ], + "evoLevel": 32, + "eggGroups": [ + "Human-Like" + ] + }, + "gothitelle": { + "num": 576, + "species": "Gothitelle", + "types": [ + "Psychic" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 70, + "atk": 55, + "def": 95, + "spa": 95, + "spd": 110, + "spe": 65 + }, + "abilities": { + "0": "Frisk", + "1": "Competitive", + "H": "Shadow Tag" + }, + "heightm": 1.5, + "weightkg": 44, + "color": "Purple", + "prevo": "gothorita", + "evoLevel": 41, + "eggGroups": [ + "Human-Like" + ] + }, + "solosis": { + "num": 577, + "species": "Solosis", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 45, + "atk": 30, + "def": 40, + "spa": 105, + "spd": 50, + "spe": 20 + }, + "abilities": { + "0": "Overcoat", + "1": "Magic Guard", + "H": "Regenerator" + }, + "heightm": 0.3, + "weightkg": 1, + "color": "Green", + "evos": [ + "duosion" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "duosion": { + "num": 578, + "species": "Duosion", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 65, + "atk": 40, + "def": 50, + "spa": 125, + "spd": 60, + "spe": 30 + }, + "abilities": { + "0": "Overcoat", + "1": "Magic Guard", + "H": "Regenerator" + }, + "heightm": 0.6, + "weightkg": 8, + "color": "Green", + "prevo": "solosis", + "evos": [ + "reuniclus" + ], + "evoLevel": 32, + "eggGroups": [ + "Amorphous" + ] + }, + "reuniclus": { + "num": 579, + "species": "Reuniclus", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 110, + "atk": 65, + "def": 75, + "spa": 125, + "spd": 85, + "spe": 30 + }, + "abilities": { + "0": "Overcoat", + "1": "Magic Guard", + "H": "Regenerator" + }, + "heightm": 1, + "weightkg": 20.1, + "color": "Green", + "prevo": "duosion", + "evoLevel": 41, + "eggGroups": [ + "Amorphous" + ] + }, + "ducklett": { + "num": 580, + "species": "Ducklett", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 62, + "atk": 44, + "def": 50, + "spa": 44, + "spd": 50, + "spe": 55 + }, + "abilities": { + "0": "Keen Eye", + "1": "Big Pecks", + "H": "Hydration" + }, + "heightm": 0.5, + "weightkg": 5.5, + "color": "Blue", + "evos": [ + "swanna" + ], + "eggGroups": [ + "Water 1", + "Flying" + ] + }, + "swanna": { + "num": 581, + "species": "Swanna", + "types": [ + "Water", + "Flying" + ], + "baseStats": { + "hp": 75, + "atk": 87, + "def": 63, + "spa": 87, + "spd": 63, + "spe": 98 + }, + "abilities": { + "0": "Keen Eye", + "1": "Big Pecks", + "H": "Hydration" + }, + "heightm": 1.3, + "weightkg": 24.2, + "color": "White", + "prevo": "ducklett", + "evoLevel": 35, + "eggGroups": [ + "Water 1", + "Flying" + ] + }, + "vanillite": { + "num": 582, + "species": "Vanillite", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 36, + "atk": 50, + "def": 50, + "spa": 65, + "spd": 60, + "spe": 44 + }, + "abilities": { + "0": "Ice Body", + "1": "Snow Cloak", + "H": "Weak Armor" + }, + "heightm": 0.4, + "weightkg": 5.7, + "color": "White", + "evos": [ + "vanillish" + ], + "eggGroups": [ + "Mineral" + ] + }, + "vanillish": { + "num": 583, + "species": "Vanillish", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 51, + "atk": 65, + "def": 65, + "spa": 80, + "spd": 75, + "spe": 59 + }, + "abilities": { + "0": "Ice Body", + "1": "Snow Cloak", + "H": "Weak Armor" + }, + "heightm": 1.1, + "weightkg": 41, + "color": "White", + "prevo": "vanillite", + "evos": [ + "vanilluxe" + ], + "evoLevel": 35, + "eggGroups": [ + "Mineral" + ] + }, + "vanilluxe": { + "num": 584, + "species": "Vanilluxe", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 71, + "atk": 95, + "def": 85, + "spa": 110, + "spd": 95, + "spe": 79 + }, + "abilities": { + "0": "Ice Body", + "1": "Snow Warning", + "H": "Weak Armor" + }, + "heightm": 1.3, + "weightkg": 57.5, + "color": "White", + "prevo": "vanillish", + "evoLevel": 47, + "eggGroups": [ + "Mineral" + ] + }, + "deerling": { + "num": 585, + "species": "Deerling", + "baseForme": "Spring", + "types": [ + "Normal", + "Grass" + ], + "baseStats": { + "hp": 60, + "atk": 60, + "def": 50, + "spa": 40, + "spd": 50, + "spe": 75 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Sap Sipper", + "H": "Serene Grace" + }, + "heightm": 0.6, + "weightkg": 19.5, + "color": "Yellow", + "evos": [ + "sawsbuck" + ], + "eggGroups": [ + "Field" + ], + "otherForms": [ + "deerlingsummer", + "deerlingautumn", + "deerlingwinter" + ] + }, + "sawsbuck": { + "num": 586, + "species": "Sawsbuck", + "baseForme": "Spring", + "types": [ + "Normal", + "Grass" + ], + "baseStats": { + "hp": 80, + "atk": 100, + "def": 70, + "spa": 60, + "spd": 70, + "spe": 95 + }, + "abilities": { + "0": "Chlorophyll", + "1": "Sap Sipper", + "H": "Serene Grace" + }, + "heightm": 1.9, + "weightkg": 92.5, + "color": "Brown", + "prevo": "deerling", + "evoLevel": 34, + "eggGroups": [ + "Field" + ], + "otherForms": [ + "sawsbucksummer", + "sawsbuckautumn", + "sawsbuckwinter" + ] + }, + "emolga": { + "num": 587, + "species": "Emolga", + "types": [ + "Electric", + "Flying" + ], + "baseStats": { + "hp": 55, + "atk": 75, + "def": 60, + "spa": 75, + "spd": 60, + "spe": 103 + }, + "abilities": { + "0": "Static", + "H": "Motor Drive" + }, + "heightm": 0.4, + "weightkg": 5, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "karrablast": { + "num": 588, + "species": "Karrablast", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 50, + "atk": 75, + "def": 45, + "spa": 40, + "spd": 45, + "spe": 60 + }, + "abilities": { + "0": "Swarm", + "1": "Shed Skin", + "H": "No Guard" + }, + "heightm": 0.5, + "weightkg": 5.9, + "color": "Blue", + "evos": [ + "escavalier" + ], + "eggGroups": [ + "Bug" + ] + }, + "escavalier": { + "num": 589, + "species": "Escavalier", + "types": [ + "Bug", + "Steel" + ], + "baseStats": { + "hp": 70, + "atk": 135, + "def": 105, + "spa": 60, + "spd": 105, + "spe": 20 + }, + "abilities": { + "0": "Swarm", + "1": "Shell Armor", + "H": "Overcoat" + }, + "heightm": 1, + "weightkg": 33, + "color": "Gray", + "prevo": "karrablast", + "evoLevel": 1, + "eggGroups": [ + "Bug" + ] + }, + "foongus": { + "num": 590, + "species": "Foongus", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 69, + "atk": 55, + "def": 45, + "spa": 55, + "spd": 55, + "spe": 15 + }, + "abilities": { + "0": "Effect Spore", + "H": "Regenerator" + }, + "heightm": 0.2, + "weightkg": 1, + "color": "White", + "evos": [ + "amoonguss" + ], + "eggGroups": [ + "Grass" + ] + }, + "amoonguss": { + "num": 591, + "species": "Amoonguss", + "types": [ + "Grass", + "Poison" + ], + "baseStats": { + "hp": 114, + "atk": 85, + "def": 70, + "spa": 85, + "spd": 80, + "spe": 30 + }, + "abilities": { + "0": "Effect Spore", + "H": "Regenerator" + }, + "heightm": 0.6, + "weightkg": 10.5, + "color": "White", + "prevo": "foongus", + "evoLevel": 39, + "eggGroups": [ + "Grass" + ] + }, + "frillish": { + "num": 592, + "species": "Frillish", + "types": [ + "Water", + "Ghost" + ], + "baseStats": { + "hp": 55, + "atk": 40, + "def": 50, + "spa": 65, + "spd": 85, + "spe": 40 + }, + "abilities": { + "0": "Water Absorb", + "1": "Cursed Body", + "H": "Damp" + }, + "heightm": 1.2, + "weightkg": 33, + "color": "White", + "evos": [ + "jellicent" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "jellicent": { + "num": 593, + "species": "Jellicent", + "types": [ + "Water", + "Ghost" + ], + "baseStats": { + "hp": 100, + "atk": 60, + "def": 70, + "spa": 85, + "spd": 105, + "spe": 60 + }, + "abilities": { + "0": "Water Absorb", + "1": "Cursed Body", + "H": "Damp" + }, + "heightm": 2.2, + "weightkg": 135, + "color": "White", + "prevo": "frillish", + "evoLevel": 40, + "eggGroups": [ + "Amorphous" + ] + }, + "alomomola": { + "num": 594, + "species": "Alomomola", + "types": [ + "Water" + ], + "baseStats": { + "hp": 165, + "atk": 75, + "def": 80, + "spa": 40, + "spd": 45, + "spe": 65 + }, + "abilities": { + "0": "Healer", + "1": "Hydration", + "H": "Regenerator" + }, + "heightm": 1.2, + "weightkg": 31.6, + "color": "Pink", + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "joltik": { + "num": 595, + "species": "Joltik", + "types": [ + "Bug", + "Electric" + ], + "baseStats": { + "hp": 50, + "atk": 47, + "def": 50, + "spa": 57, + "spd": 50, + "spe": 65 + }, + "abilities": { + "0": "Compound Eyes", + "1": "Unnerve", + "H": "Swarm" + }, + "heightm": 0.1, + "weightkg": 0.6, + "color": "Yellow", + "evos": [ + "galvantula" + ], + "eggGroups": [ + "Bug" + ] + }, + "galvantula": { + "num": 596, + "species": "Galvantula", + "types": [ + "Bug", + "Electric" + ], + "baseStats": { + "hp": 70, + "atk": 77, + "def": 60, + "spa": 97, + "spd": 60, + "spe": 108 + }, + "abilities": { + "0": "Compound Eyes", + "1": "Unnerve", + "H": "Swarm" + }, + "heightm": 0.8, + "weightkg": 14.3, + "color": "Yellow", + "prevo": "joltik", + "evoLevel": 36, + "eggGroups": [ + "Bug" + ] + }, + "ferroseed": { + "num": 597, + "species": "Ferroseed", + "types": [ + "Grass", + "Steel" + ], + "baseStats": { + "hp": 44, + "atk": 50, + "def": 91, + "spa": 24, + "spd": 86, + "spe": 10 + }, + "abilities": { + "0": "Iron Barbs" + }, + "heightm": 0.6, + "weightkg": 18.8, + "color": "Gray", + "evos": [ + "ferrothorn" + ], + "eggGroups": [ + "Grass", + "Mineral" + ] + }, + "ferrothorn": { + "num": 598, + "species": "Ferrothorn", + "types": [ + "Grass", + "Steel" + ], + "baseStats": { + "hp": 74, + "atk": 94, + "def": 131, + "spa": 54, + "spd": 116, + "spe": 20 + }, + "abilities": { + "0": "Iron Barbs", + "H": "Anticipation" + }, + "heightm": 1, + "weightkg": 110, + "color": "Gray", + "prevo": "ferroseed", + "evoLevel": 40, + "eggGroups": [ + "Grass", + "Mineral" + ] + }, + "klink": { + "num": 599, + "species": "Klink", + "types": [ + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 40, + "atk": 55, + "def": 70, + "spa": 45, + "spd": 60, + "spe": 30 + }, + "abilities": { + "0": "Plus", + "1": "Minus", + "H": "Clear Body" + }, + "heightm": 0.3, + "weightkg": 21, + "color": "Gray", + "evos": [ + "klang" + ], + "eggGroups": [ + "Mineral" + ] + }, + "klang": { + "num": 600, + "species": "Klang", + "types": [ + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 80, + "def": 95, + "spa": 70, + "spd": 85, + "spe": 50 + }, + "abilities": { + "0": "Plus", + "1": "Minus", + "H": "Clear Body" + }, + "heightm": 0.6, + "weightkg": 51, + "color": "Gray", + "prevo": "klink", + "evos": [ + "klinklang" + ], + "evoLevel": 38, + "eggGroups": [ + "Mineral" + ] + }, + "klinklang": { + "num": 601, + "species": "Klinklang", + "types": [ + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 100, + "def": 115, + "spa": 70, + "spd": 85, + "spe": 90 + }, + "abilities": { + "0": "Plus", + "1": "Minus", + "H": "Clear Body" + }, + "heightm": 0.6, + "weightkg": 81, + "color": "Gray", + "prevo": "klang", + "evoLevel": 49, + "eggGroups": [ + "Mineral" + ] + }, + "tynamo": { + "num": 602, + "species": "Tynamo", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 35, + "atk": 55, + "def": 40, + "spa": 45, + "spd": 40, + "spe": 60 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 0.2, + "weightkg": 0.3, + "color": "White", + "evos": [ + "eelektrik" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "eelektrik": { + "num": 603, + "species": "Eelektrik", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 65, + "atk": 85, + "def": 70, + "spa": 75, + "spd": 70, + "spe": 40 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.2, + "weightkg": 22, + "color": "Blue", + "prevo": "tynamo", + "evos": [ + "eelektross" + ], + "evoLevel": 39, + "eggGroups": [ + "Amorphous" + ] + }, + "eelektross": { + "num": 604, + "species": "Eelektross", + "types": [ + "Electric" + ], + "baseStats": { + "hp": 85, + "atk": 115, + "def": 80, + "spa": 105, + "spd": 80, + "spe": 50 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 2.1, + "weightkg": 80.5, + "color": "Blue", + "prevo": "eelektrik", + "evoLevel": 39, + "eggGroups": [ + "Amorphous" + ] + }, + "elgyem": { + "num": 605, + "species": "Elgyem", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 55, + "atk": 55, + "def": 55, + "spa": 85, + "spd": 55, + "spe": 30 + }, + "abilities": { + "0": "Telepathy", + "1": "Synchronize", + "H": "Analytic" + }, + "heightm": 0.5, + "weightkg": 9, + "color": "Blue", + "evos": [ + "beheeyem" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "beheeyem": { + "num": 606, + "species": "Beheeyem", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 75, + "atk": 75, + "def": 75, + "spa": 125, + "spd": 95, + "spe": 40 + }, + "abilities": { + "0": "Telepathy", + "1": "Synchronize", + "H": "Analytic" + }, + "heightm": 1, + "weightkg": 34.5, + "color": "Brown", + "prevo": "elgyem", + "evoLevel": 42, + "eggGroups": [ + "Human-Like" + ] + }, + "litwick": { + "num": 607, + "species": "Litwick", + "types": [ + "Ghost", + "Fire" + ], + "baseStats": { + "hp": 50, + "atk": 30, + "def": 55, + "spa": 65, + "spd": 55, + "spe": 20 + }, + "abilities": { + "0": "Flash Fire", + "1": "Flame Body", + "H": "Infiltrator" + }, + "heightm": 0.3, + "weightkg": 3.1, + "color": "White", + "evos": [ + "lampent" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "lampent": { + "num": 608, + "species": "Lampent", + "types": [ + "Ghost", + "Fire" + ], + "baseStats": { + "hp": 60, + "atk": 40, + "def": 60, + "spa": 95, + "spd": 60, + "spe": 55 + }, + "abilities": { + "0": "Flash Fire", + "1": "Flame Body", + "H": "Infiltrator" + }, + "heightm": 0.6, + "weightkg": 13, + "color": "Black", + "prevo": "litwick", + "evos": [ + "chandelure" + ], + "evoLevel": 41, + "eggGroups": [ + "Amorphous" + ] + }, + "chandelure": { + "num": 609, + "species": "Chandelure", + "types": [ + "Ghost", + "Fire" + ], + "baseStats": { + "hp": 60, + "atk": 55, + "def": 90, + "spa": 145, + "spd": 90, + "spe": 80 + }, + "abilities": { + "0": "Flash Fire", + "1": "Flame Body", + "H": "Infiltrator" + }, + "heightm": 1, + "weightkg": 34.3, + "color": "Black", + "prevo": "lampent", + "evoLevel": 41, + "eggGroups": [ + "Amorphous" + ] + }, + "axew": { + "num": 610, + "species": "Axew", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 46, + "atk": 87, + "def": 60, + "spa": 30, + "spd": 40, + "spe": 57 + }, + "abilities": { + "0": "Rivalry", + "1": "Mold Breaker", + "H": "Unnerve" + }, + "heightm": 0.6, + "weightkg": 18, + "color": "Green", + "evos": [ + "fraxure" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "fraxure": { + "num": 611, + "species": "Fraxure", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 66, + "atk": 117, + "def": 70, + "spa": 40, + "spd": 50, + "spe": 67 + }, + "abilities": { + "0": "Rivalry", + "1": "Mold Breaker", + "H": "Unnerve" + }, + "heightm": 1, + "weightkg": 36, + "color": "Green", + "prevo": "axew", + "evos": [ + "haxorus" + ], + "evoLevel": 38, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "haxorus": { + "num": 612, + "species": "Haxorus", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 76, + "atk": 147, + "def": 90, + "spa": 60, + "spd": 70, + "spe": 97 + }, + "abilities": { + "0": "Rivalry", + "1": "Mold Breaker", + "H": "Unnerve" + }, + "heightm": 1.8, + "weightkg": 105.5, + "color": "Yellow", + "prevo": "fraxure", + "evoLevel": 48, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "cubchoo": { + "num": 613, + "species": "Cubchoo", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 55, + "atk": 70, + "def": 40, + "spa": 60, + "spd": 40, + "spe": 40 + }, + "abilities": { + "0": "Snow Cloak", + "1": "Slush Rush", + "H": "Rattled" + }, + "heightm": 0.5, + "weightkg": 8.5, + "color": "White", + "evos": [ + "beartic" + ], + "eggGroups": [ + "Field" + ] + }, + "beartic": { + "num": 614, + "species": "Beartic", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 95, + "atk": 130, + "def": 80, + "spa": 70, + "spd": 80, + "spe": 50 + }, + "abilities": { + "0": "Snow Cloak", + "1": "Slush Rush", + "H": "Swift Swim" + }, + "heightm": 2.6, + "weightkg": 260, + "color": "White", + "prevo": "cubchoo", + "evoLevel": 37, + "eggGroups": [ + "Field" + ] + }, + "cryogonal": { + "num": 615, + "species": "Cryogonal", + "types": [ + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 50, + "def": 50, + "spa": 95, + "spd": 135, + "spe": 105 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.1, + "weightkg": 148, + "color": "Blue", + "eggGroups": [ + "Mineral" + ] + }, + "shelmet": { + "num": 616, + "species": "Shelmet", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 50, + "atk": 40, + "def": 85, + "spa": 40, + "spd": 65, + "spe": 25 + }, + "abilities": { + "0": "Hydration", + "1": "Shell Armor", + "H": "Overcoat" + }, + "heightm": 0.4, + "weightkg": 7.7, + "color": "Red", + "evos": [ + "accelgor" + ], + "eggGroups": [ + "Bug" + ] + }, + "accelgor": { + "num": 617, + "species": "Accelgor", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 80, + "atk": 70, + "def": 40, + "spa": 100, + "spd": 60, + "spe": 145 + }, + "abilities": { + "0": "Hydration", + "1": "Sticky Hold", + "H": "Unburden" + }, + "heightm": 0.8, + "weightkg": 25.3, + "color": "Red", + "prevo": "shelmet", + "evoLevel": 1, + "eggGroups": [ + "Bug" + ] + }, + "stunfisk": { + "num": 618, + "species": "Stunfisk", + "types": [ + "Ground", + "Electric" + ], + "baseStats": { + "hp": 109, + "atk": 66, + "def": 84, + "spa": 81, + "spd": 99, + "spe": 32 + }, + "abilities": { + "0": "Static", + "1": "Limber", + "H": "Sand Veil" + }, + "heightm": 0.7, + "weightkg": 11, + "color": "Brown", + "eggGroups": [ + "Water 1", + "Amorphous" + ] + }, + "mienfoo": { + "num": 619, + "species": "Mienfoo", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 45, + "atk": 85, + "def": 50, + "spa": 55, + "spd": 50, + "spe": 65 + }, + "abilities": { + "0": "Inner Focus", + "1": "Regenerator", + "H": "Reckless" + }, + "heightm": 0.9, + "weightkg": 20, + "color": "Yellow", + "evos": [ + "mienshao" + ], + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "mienshao": { + "num": 620, + "species": "Mienshao", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 65, + "atk": 125, + "def": 60, + "spa": 95, + "spd": 60, + "spe": 105 + }, + "abilities": { + "0": "Inner Focus", + "1": "Regenerator", + "H": "Reckless" + }, + "heightm": 1.4, + "weightkg": 35.5, + "color": "Purple", + "prevo": "mienfoo", + "evoLevel": 50, + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "druddigon": { + "num": 621, + "species": "Druddigon", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 77, + "atk": 120, + "def": 90, + "spa": 60, + "spd": 90, + "spe": 48 + }, + "abilities": { + "0": "Rough Skin", + "1": "Sheer Force", + "H": "Mold Breaker" + }, + "heightm": 1.6, + "weightkg": 139, + "color": "Red", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "golett": { + "num": 622, + "species": "Golett", + "types": [ + "Ground", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 59, + "atk": 74, + "def": 50, + "spa": 35, + "spd": 50, + "spe": 35 + }, + "abilities": { + "0": "Iron Fist", + "1": "Klutz", + "H": "No Guard" + }, + "heightm": 1, + "weightkg": 92, + "color": "Green", + "evos": [ + "golurk" + ], + "eggGroups": [ + "Mineral" + ] + }, + "golurk": { + "num": 623, + "species": "Golurk", + "types": [ + "Ground", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 89, + "atk": 124, + "def": 80, + "spa": 55, + "spd": 80, + "spe": 55 + }, + "abilities": { + "0": "Iron Fist", + "1": "Klutz", + "H": "No Guard" + }, + "heightm": 2.8, + "weightkg": 330, + "color": "Green", + "prevo": "golett", + "evoLevel": 43, + "eggGroups": [ + "Mineral" + ] + }, + "pawniard": { + "num": 624, + "species": "Pawniard", + "types": [ + "Dark", + "Steel" + ], + "baseStats": { + "hp": 45, + "atk": 85, + "def": 70, + "spa": 40, + "spd": 40, + "spe": 60 + }, + "abilities": { + "0": "Defiant", + "1": "Inner Focus", + "H": "Pressure" + }, + "heightm": 0.5, + "weightkg": 10.2, + "color": "Red", + "evos": [ + "bisharp" + ], + "eggGroups": [ + "Human-Like" + ] + }, + "bisharp": { + "num": 625, + "species": "Bisharp", + "types": [ + "Dark", + "Steel" + ], + "baseStats": { + "hp": 65, + "atk": 125, + "def": 100, + "spa": 60, + "spd": 70, + "spe": 70 + }, + "abilities": { + "0": "Defiant", + "1": "Inner Focus", + "H": "Pressure" + }, + "heightm": 1.6, + "weightkg": 70, + "color": "Red", + "prevo": "pawniard", + "evoLevel": 52, + "eggGroups": [ + "Human-Like" + ] + }, + "bouffalant": { + "num": 626, + "species": "Bouffalant", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 95, + "atk": 110, + "def": 95, + "spa": 40, + "spd": 95, + "spe": 55 + }, + "abilities": { + "0": "Reckless", + "1": "Sap Sipper", + "H": "Soundproof" + }, + "heightm": 1.6, + "weightkg": 94.6, + "color": "Brown", + "eggGroups": [ + "Field" + ] + }, + "rufflet": { + "num": 627, + "species": "Rufflet", + "types": [ + "Normal", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 70, + "atk": 83, + "def": 50, + "spa": 37, + "spd": 50, + "spe": 60 + }, + "abilities": { + "0": "Keen Eye", + "1": "Sheer Force", + "H": "Hustle" + }, + "heightm": 0.5, + "weightkg": 10.5, + "color": "White", + "evos": [ + "braviary" + ], + "eggGroups": [ + "Flying" + ] + }, + "braviary": { + "num": 628, + "species": "Braviary", + "types": [ + "Normal", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 100, + "atk": 123, + "def": 75, + "spa": 57, + "spd": 75, + "spe": 80 + }, + "abilities": { + "0": "Keen Eye", + "1": "Sheer Force", + "H": "Defiant" + }, + "heightm": 1.5, + "weightkg": 41, + "color": "Red", + "prevo": "rufflet", + "evoLevel": 54, + "eggGroups": [ + "Flying" + ] + }, + "vullaby": { + "num": 629, + "species": "Vullaby", + "types": [ + "Dark", + "Flying" + ], + "gender": "F", + "baseStats": { + "hp": 70, + "atk": 55, + "def": 75, + "spa": 45, + "spd": 65, + "spe": 60 + }, + "abilities": { + "0": "Big Pecks", + "1": "Overcoat", + "H": "Weak Armor" + }, + "heightm": 0.5, + "weightkg": 9, + "color": "Brown", + "evos": [ + "mandibuzz" + ], + "eggGroups": [ + "Flying" + ] + }, + "mandibuzz": { + "num": 630, + "species": "Mandibuzz", + "types": [ + "Dark", + "Flying" + ], + "gender": "F", + "baseStats": { + "hp": 110, + "atk": 65, + "def": 105, + "spa": 55, + "spd": 95, + "spe": 80 + }, + "abilities": { + "0": "Big Pecks", + "1": "Overcoat", + "H": "Weak Armor" + }, + "heightm": 1.2, + "weightkg": 39.5, + "color": "Brown", + "prevo": "vullaby", + "evoLevel": 54, + "eggGroups": [ + "Flying" + ] + }, + "heatmor": { + "num": 631, + "species": "Heatmor", + "types": [ + "Fire" + ], + "baseStats": { + "hp": 85, + "atk": 97, + "def": 66, + "spa": 105, + "spd": 66, + "spe": 65 + }, + "abilities": { + "0": "Gluttony", + "1": "Flash Fire", + "H": "White Smoke" + }, + "heightm": 1.4, + "weightkg": 58, + "color": "Red", + "eggGroups": [ + "Field" + ] + }, + "durant": { + "num": 632, + "species": "Durant", + "types": [ + "Bug", + "Steel" + ], + "baseStats": { + "hp": 58, + "atk": 109, + "def": 112, + "spa": 48, + "spd": 48, + "spe": 109 + }, + "abilities": { + "0": "Swarm", + "1": "Hustle", + "H": "Truant" + }, + "heightm": 0.3, + "weightkg": 33, + "color": "Gray", + "eggGroups": [ + "Bug" + ] + }, + "deino": { + "num": 633, + "species": "Deino", + "types": [ + "Dark", + "Dragon" + ], + "baseStats": { + "hp": 52, + "atk": 65, + "def": 50, + "spa": 45, + "spd": 50, + "spe": 38 + }, + "abilities": { + "0": "Hustle" + }, + "heightm": 0.8, + "weightkg": 17.3, + "color": "Blue", + "evos": [ + "zweilous" + ], + "eggGroups": [ + "Dragon" + ] + }, + "zweilous": { + "num": 634, + "species": "Zweilous", + "types": [ + "Dark", + "Dragon" + ], + "baseStats": { + "hp": 72, + "atk": 85, + "def": 70, + "spa": 65, + "spd": 70, + "spe": 58 + }, + "abilities": { + "0": "Hustle" + }, + "heightm": 1.4, + "weightkg": 50, + "color": "Blue", + "prevo": "deino", + "evos": [ + "hydreigon" + ], + "evoLevel": 50, + "eggGroups": [ + "Dragon" + ] + }, + "hydreigon": { + "num": 635, + "species": "Hydreigon", + "types": [ + "Dark", + "Dragon" + ], + "baseStats": { + "hp": 92, + "atk": 105, + "def": 90, + "spa": 125, + "spd": 90, + "spe": 98 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.8, + "weightkg": 160, + "color": "Blue", + "prevo": "zweilous", + "evoLevel": 64, + "eggGroups": [ + "Dragon" + ] + }, + "larvesta": { + "num": 636, + "species": "Larvesta", + "types": [ + "Bug", + "Fire" + ], + "baseStats": { + "hp": 55, + "atk": 85, + "def": 55, + "spa": 50, + "spd": 55, + "spe": 60 + }, + "abilities": { + "0": "Flame Body", + "H": "Swarm" + }, + "heightm": 1.1, + "weightkg": 28.8, + "color": "White", + "evos": [ + "volcarona" + ], + "eggGroups": [ + "Bug" + ] + }, + "volcarona": { + "num": 637, + "species": "Volcarona", + "types": [ + "Bug", + "Fire" + ], + "baseStats": { + "hp": 85, + "atk": 60, + "def": 65, + "spa": 135, + "spd": 105, + "spe": 100 + }, + "abilities": { + "0": "Flame Body", + "H": "Swarm" + }, + "heightm": 1.6, + "weightkg": 46, + "color": "White", + "prevo": "larvesta", + "evoLevel": 59, + "eggGroups": [ + "Bug" + ] + }, + "cobalion": { + "num": 638, + "species": "Cobalion", + "types": [ + "Steel", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 91, + "atk": 90, + "def": 129, + "spa": 90, + "spd": 72, + "spe": 108 + }, + "abilities": { + "0": "Justified" + }, + "heightm": 2.1, + "weightkg": 250, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "terrakion": { + "num": 639, + "species": "Terrakion", + "types": [ + "Rock", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 91, + "atk": 129, + "def": 90, + "spa": 72, + "spd": 90, + "spe": 108 + }, + "abilities": { + "0": "Justified" + }, + "heightm": 1.9, + "weightkg": 260, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "virizion": { + "num": 640, + "species": "Virizion", + "types": [ + "Grass", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 91, + "atk": 90, + "def": 72, + "spa": 90, + "spd": 129, + "spe": 108 + }, + "abilities": { + "0": "Justified" + }, + "heightm": 2, + "weightkg": 200, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "tornadus": { + "num": 641, + "species": "Tornadus", + "baseForme": "Incarnate", + "types": [ + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 79, + "atk": 115, + "def": 70, + "spa": 125, + "spd": 80, + "spe": 111 + }, + "abilities": { + "0": "Prankster", + "H": "Defiant" + }, + "heightm": 1.5, + "weightkg": 63, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "tornadustherian" + ] + }, + "tornadustherian": { + "num": 641, + "species": "Tornadus-Therian", + "baseSpecies": "Tornadus", + "forme": "Therian", + "formeLetter": "T", + "types": [ + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 79, + "atk": 100, + "def": 80, + "spa": 110, + "spd": 90, + "spe": 121 + }, + "abilities": { + "0": "Regenerator" + }, + "heightm": 1.4, + "weightkg": 63, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "thundurus": { + "num": 642, + "species": "Thundurus", + "baseForme": "Incarnate", + "types": [ + "Electric", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 79, + "atk": 115, + "def": 70, + "spa": 125, + "spd": 80, + "spe": 111 + }, + "abilities": { + "0": "Prankster", + "H": "Defiant" + }, + "heightm": 1.5, + "weightkg": 61, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "thundurustherian" + ] + }, + "thundurustherian": { + "num": 642, + "species": "Thundurus-Therian", + "baseSpecies": "Thundurus", + "forme": "Therian", + "formeLetter": "T", + "types": [ + "Electric", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 79, + "atk": 105, + "def": 70, + "spa": 145, + "spd": 80, + "spe": 101 + }, + "abilities": { + "0": "Volt Absorb" + }, + "heightm": 3, + "weightkg": 61, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "reshiram": { + "num": 643, + "species": "Reshiram", + "types": [ + "Dragon", + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 120, + "def": 100, + "spa": 150, + "spd": 120, + "spe": 90 + }, + "abilities": { + "0": "Turboblaze" + }, + "heightm": 3.2, + "weightkg": 330, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "zekrom": { + "num": 644, + "species": "Zekrom", + "types": [ + "Dragon", + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 150, + "def": 120, + "spa": 120, + "spd": 100, + "spe": 90 + }, + "abilities": { + "0": "Teravolt" + }, + "heightm": 2.9, + "weightkg": 345, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "landorus": { + "num": 645, + "species": "Landorus", + "baseForme": "Incarnate", + "types": [ + "Ground", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 89, + "atk": 125, + "def": 90, + "spa": 115, + "spd": 80, + "spe": 101 + }, + "abilities": { + "0": "Sand Force", + "H": "Sheer Force" + }, + "heightm": 1.5, + "weightkg": 68, + "color": "Brown", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "landorustherian" + ] + }, + "landorustherian": { + "num": 645, + "species": "Landorus-Therian", + "baseSpecies": "Landorus", + "forme": "Therian", + "formeLetter": "T", + "types": [ + "Ground", + "Flying" + ], + "gender": "M", + "baseStats": { + "hp": 89, + "atk": 145, + "def": 90, + "spa": 105, + "spd": 80, + "spe": 91 + }, + "abilities": { + "0": "Intimidate" + }, + "heightm": 1.3, + "weightkg": 68, + "color": "Brown", + "eggGroups": [ + "Undiscovered" + ] + }, + "kyurem": { + "num": 646, + "species": "Kyurem", + "types": [ + "Dragon", + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 125, + "atk": 130, + "def": 90, + "spa": 130, + "spd": 90, + "spe": 95 + }, + "abilities": { + "0": "Pressure" + }, + "heightm": 3, + "weightkg": 325, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "kyuremblack", + "kyuremwhite" + ] + }, + "kyuremblack": { + "num": 646, + "species": "Kyurem-Black", + "baseSpecies": "Kyurem", + "forme": "Black", + "formeLetter": "B", + "types": [ + "Dragon", + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 125, + "atk": 170, + "def": 100, + "spa": 120, + "spd": 90, + "spe": 95 + }, + "abilities": { + "0": "Teravolt" + }, + "heightm": 3.3, + "weightkg": 325, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "kyuremwhite": { + "num": 646, + "species": "Kyurem-White", + "baseSpecies": "Kyurem", + "forme": "White", + "formeLetter": "W", + "types": [ + "Dragon", + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 125, + "atk": 120, + "def": 90, + "spa": 170, + "spd": 100, + "spe": 95 + }, + "abilities": { + "0": "Turboblaze" + }, + "heightm": 3.6, + "weightkg": 325, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "keldeo": { + "num": 647, + "species": "Keldeo", + "baseForme": "Ordinary", + "types": [ + "Water", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 91, + "atk": 72, + "def": 90, + "spa": 129, + "spd": 90, + "spe": 108 + }, + "abilities": { + "0": "Justified" + }, + "heightm": 1.4, + "weightkg": 48.5, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "keldeoresolute" + ] + }, + "keldeoresolute": { + "num": 647, + "species": "Keldeo-Resolute", + "baseSpecies": "Keldeo", + "forme": "Resolute", + "formeLetter": "R", + "types": [ + "Water", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 91, + "atk": 72, + "def": 90, + "spa": 129, + "spd": 90, + "spe": 108 + }, + "abilities": { + "0": "Justified" + }, + "heightm": 1.4, + "weightkg": 48.5, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "meloetta": { + "num": 648, + "species": "Meloetta", + "baseForme": "Aria", + "types": [ + "Normal", + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 77, + "def": 77, + "spa": 128, + "spd": 128, + "spe": 90 + }, + "abilities": { + "0": "Serene Grace" + }, + "heightm": 0.6, + "weightkg": 6.5, + "color": "White", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "meloettapirouette" + ] + }, + "meloettapirouette": { + "num": 648, + "species": "Meloetta-Pirouette", + "baseSpecies": "Meloetta", + "forme": "Pirouette", + "formeLetter": "P", + "types": [ + "Normal", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 100, + "atk": 128, + "def": 90, + "spa": 77, + "spd": 77, + "spe": 128 + }, + "abilities": { + "0": "Serene Grace" + }, + "heightm": 0.6, + "weightkg": 6.5, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "genesect": { + "num": 649, + "species": "Genesect", + "types": [ + "Bug", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 71, + "atk": 120, + "def": 95, + "spa": 120, + "spd": 95, + "spe": 99 + }, + "abilities": { + "0": "Download" + }, + "heightm": 1.5, + "weightkg": 82.5, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "genesectdouse", + "genesectshock", + "genesectburn", + "genesectchill" + ] + }, + "genesectdouse": { + "num": 649, + "species": "Genesect-Douse", + "baseSpecies": "Genesect", + "forme": "Douse", + "formeLetter": "D", + "types": [ + "Bug", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 71, + "atk": 120, + "def": 95, + "spa": 120, + "spd": 95, + "spe": 99 + }, + "abilities": { + "0": "Download" + }, + "heightm": 1.5, + "weightkg": 82.5, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "genesectshock": { + "num": 649, + "species": "Genesect-Shock", + "baseSpecies": "Genesect", + "forme": "Shock", + "formeLetter": "S", + "types": [ + "Bug", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 71, + "atk": 120, + "def": 95, + "spa": 120, + "spd": 95, + "spe": 99 + }, + "abilities": { + "0": "Download" + }, + "heightm": 1.5, + "weightkg": 82.5, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "genesectburn": { + "num": 649, + "species": "Genesect-Burn", + "baseSpecies": "Genesect", + "forme": "Burn", + "formeLetter": "B", + "types": [ + "Bug", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 71, + "atk": 120, + "def": 95, + "spa": 120, + "spd": 95, + "spe": 99 + }, + "abilities": { + "0": "Download" + }, + "heightm": 1.5, + "weightkg": 82.5, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "genesectchill": { + "num": 649, + "species": "Genesect-Chill", + "baseSpecies": "Genesect", + "forme": "Chill", + "formeLetter": "C", + "types": [ + "Bug", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 71, + "atk": 120, + "def": 95, + "spa": 120, + "spd": 95, + "spe": 99 + }, + "abilities": { + "0": "Download" + }, + "heightm": 1.5, + "weightkg": 82.5, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "chespin": { + "num": 650, + "species": "Chespin", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 56, + "atk": 61, + "def": 65, + "spa": 48, + "spd": 45, + "spe": 38 + }, + "abilities": { + "0": "Overgrow", + "H": "Bulletproof" + }, + "heightm": 0.4, + "weightkg": 9, + "color": "Green", + "evos": [ + "quilladin" + ], + "eggGroups": [ + "Field" + ] + }, + "quilladin": { + "num": 651, + "species": "Quilladin", + "types": [ + "Grass" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 61, + "atk": 78, + "def": 95, + "spa": 56, + "spd": 58, + "spe": 57 + }, + "abilities": { + "0": "Overgrow", + "H": "Bulletproof" + }, + "heightm": 0.7, + "weightkg": 29, + "color": "Green", + "prevo": "chespin", + "evos": [ + "chesnaught" + ], + "evoLevel": 16, + "eggGroups": [ + "Field" + ] + }, + "chesnaught": { + "num": 652, + "species": "Chesnaught", + "types": [ + "Grass", + "Fighting" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 88, + "atk": 107, + "def": 122, + "spa": 74, + "spd": 75, + "spe": 64 + }, + "abilities": { + "0": "Overgrow", + "H": "Bulletproof" + }, + "heightm": 1.6, + "weightkg": 90, + "color": "Green", + "prevo": "quilladin", + "evoLevel": 36, + "eggGroups": [ + "Field" + ] + }, + "fennekin": { + "num": 653, + "species": "Fennekin", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 40, + "atk": 45, + "def": 40, + "spa": 62, + "spd": 60, + "spe": 60 + }, + "abilities": { + "0": "Blaze", + "H": "Magician" + }, + "heightm": 0.4, + "weightkg": 9.4, + "color": "Red", + "evos": [ + "braixen" + ], + "eggGroups": [ + "Field" + ] + }, + "braixen": { + "num": 654, + "species": "Braixen", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 59, + "atk": 59, + "def": 58, + "spa": 90, + "spd": 70, + "spe": 73 + }, + "abilities": { + "0": "Blaze", + "H": "Magician" + }, + "heightm": 1, + "weightkg": 14.5, + "color": "Red", + "prevo": "fennekin", + "evos": [ + "delphox" + ], + "evoLevel": 16, + "eggGroups": [ + "Field" + ] + }, + "delphox": { + "num": 655, + "species": "Delphox", + "types": [ + "Fire", + "Psychic" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 75, + "atk": 69, + "def": 72, + "spa": 114, + "spd": 100, + "spe": 104 + }, + "abilities": { + "0": "Blaze", + "H": "Magician" + }, + "heightm": 1.5, + "weightkg": 39, + "color": "Red", + "prevo": "braixen", + "evoLevel": 36, + "eggGroups": [ + "Field" + ] + }, + "froakie": { + "num": 656, + "species": "Froakie", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 41, + "atk": 56, + "def": 40, + "spa": 62, + "spd": 44, + "spe": 71 + }, + "abilities": { + "0": "Torrent", + "H": "Protean" + }, + "heightm": 0.3, + "weightkg": 7, + "color": "Blue", + "evos": [ + "frogadier" + ], + "eggGroups": [ + "Water 1" + ] + }, + "frogadier": { + "num": 657, + "species": "Frogadier", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 54, + "atk": 63, + "def": 52, + "spa": 83, + "spd": 56, + "spe": 97 + }, + "abilities": { + "0": "Torrent", + "H": "Protean" + }, + "heightm": 0.6, + "weightkg": 10.9, + "color": "Blue", + "prevo": "froakie", + "evos": [ + "greninja" + ], + "evoLevel": 16, + "eggGroups": [ + "Water 1" + ] + }, + "greninja": { + "num": 658, + "species": "Greninja", + "types": [ + "Water", + "Dark" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 72, + "atk": 95, + "def": 67, + "spa": 103, + "spd": 71, + "spe": 122 + }, + "abilities": { + "0": "Torrent", + "H": "Protean", + "S": "Battle Bond" + }, + "heightm": 1.5, + "weightkg": 40, + "color": "Blue", + "prevo": "frogadier", + "evoLevel": 36, + "eggGroups": [ + "Water 1" + ], + "otherFormes": [ + "greninjaash" + ] + }, + "greninjaash": { + "num": 658, + "species": "Greninja-Ash", + "baseSpecies": "Greninja", + "forme": "Ash", + "formeLetter": "A", + "types": [ + "Water", + "Dark" + ], + "gender": "M", + "baseStats": { + "hp": 72, + "atk": 145, + "def": 67, + "spa": 153, + "spd": 71, + "spe": 132 + }, + "abilities": { + "0": "Battle Bond" + }, + "heightm": 1.5, + "weightkg": 40, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "bunnelby": { + "num": 659, + "species": "Bunnelby", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 38, + "atk": 36, + "def": 38, + "spa": 32, + "spd": 36, + "spe": 57 + }, + "abilities": { + "0": "Pickup", + "1": "Cheek Pouch", + "H": "Huge Power" + }, + "heightm": 0.4, + "weightkg": 5, + "color": "Brown", + "evos": [ + "diggersby" + ], + "eggGroups": [ + "Field" + ] + }, + "diggersby": { + "num": 660, + "species": "Diggersby", + "types": [ + "Normal", + "Ground" + ], + "baseStats": { + "hp": 85, + "atk": 56, + "def": 77, + "spa": 50, + "spd": 77, + "spe": 78 + }, + "abilities": { + "0": "Pickup", + "1": "Cheek Pouch", + "H": "Huge Power" + }, + "heightm": 1, + "weightkg": 42.4, + "color": "Brown", + "prevo": "bunnelby", + "evoLevel": 20, + "eggGroups": [ + "Field" + ] + }, + "fletchling": { + "num": 661, + "species": "Fletchling", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 45, + "atk": 50, + "def": 43, + "spa": 40, + "spd": 38, + "spe": 62 + }, + "abilities": { + "0": "Big Pecks", + "H": "Gale Wings" + }, + "heightm": 0.3, + "weightkg": 1.7, + "color": "Red", + "evos": [ + "fletchinder" + ], + "eggGroups": [ + "Flying" + ] + }, + "fletchinder": { + "num": 662, + "species": "Fletchinder", + "types": [ + "Fire", + "Flying" + ], + "baseStats": { + "hp": 62, + "atk": 73, + "def": 55, + "spa": 56, + "spd": 52, + "spe": 84 + }, + "abilities": { + "0": "Flame Body", + "H": "Gale Wings" + }, + "heightm": 0.7, + "weightkg": 16, + "color": "Red", + "prevo": "fletchling", + "evos": [ + "talonflame" + ], + "evoLevel": 17, + "eggGroups": [ + "Flying" + ] + }, + "talonflame": { + "num": 663, + "species": "Talonflame", + "types": [ + "Fire", + "Flying" + ], + "baseStats": { + "hp": 78, + "atk": 81, + "def": 71, + "spa": 74, + "spd": 69, + "spe": 126 + }, + "abilities": { + "0": "Flame Body", + "H": "Gale Wings" + }, + "heightm": 1.2, + "weightkg": 24.5, + "color": "Red", + "prevo": "fletchinder", + "evoLevel": 35, + "eggGroups": [ + "Flying" + ] + }, + "scatterbug": { + "num": 664, + "species": "Scatterbug", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 38, + "atk": 35, + "def": 40, + "spa": 27, + "spd": 25, + "spe": 35 + }, + "abilities": { + "0": "Shield Dust", + "1": "Compound Eyes", + "H": "Friend Guard" + }, + "heightm": 0.3, + "weightkg": 2.5, + "color": "Black", + "evos": [ + "spewpa" + ], + "eggGroups": [ + "Bug" + ] + }, + "spewpa": { + "num": 665, + "species": "Spewpa", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 45, + "atk": 22, + "def": 60, + "spa": 27, + "spd": 30, + "spe": 29 + }, + "abilities": { + "0": "Shed Skin", + "H": "Friend Guard" + }, + "heightm": 0.3, + "weightkg": 8.4, + "color": "Black", + "prevo": "scatterbug", + "evos": [ + "vivillon" + ], + "evoLevel": 9, + "eggGroups": [ + "Bug" + ] + }, + "vivillon": { + "num": 666, + "species": "Vivillon", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 80, + "atk": 52, + "def": 50, + "spa": 90, + "spd": 50, + "spe": 89 + }, + "abilities": { + "0": "Shield Dust", + "1": "Compound Eyes", + "H": "Friend Guard" + }, + "heightm": 1.2, + "weightkg": 17, + "color": "Black", + "prevo": "spewpa", + "evoLevel": 12, + "eggGroups": [ + "Bug" + ], + "otherForms": [ + "vivillonarchipelago", + "vivilloncontinental", + "vivillonelegant", + "vivillongarden", + "vivillonhighplains", + "vivillonicysnow", + "vivillonjungle", + "vivillonmarine", + "vivillonmodern", + "vivillonmonsoon", + "vivillonocean", + "vivillonpolar", + "vivillonriver", + "vivillonsandstorm", + "vivillonsavanna", + "vivillonsun", + "vivillontundra" + ], + "otherFormes": [ + "vivillonfancy", + "vivillonpokeball" + ] + }, + "vivillonfancy": { + "num": 666, + "species": "Vivillon-Fancy", + "baseSpecies": "Vivillon", + "forme": "Fancy", + "formeLetter": "F", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 80, + "atk": 52, + "def": 50, + "spa": 90, + "spd": 50, + "spe": 89 + }, + "abilities": { + "0": "Shield Dust", + "1": "Compound Eyes" + }, + "heightm": 1.2, + "weightkg": 17, + "color": "Black", + "eggGroups": [ + "Bug" + ] + }, + "vivillonpokeball": { + "num": 666, + "species": "Vivillon-Pokeball", + "baseSpecies": "Vivillon", + "forme": "Pokeball", + "formeLetter": "P", + "types": [ + "Bug", + "Flying" + ], + "baseStats": { + "hp": 80, + "atk": 52, + "def": 50, + "spa": 90, + "spd": 50, + "spe": 89 + }, + "abilities": { + "0": "Shield Dust", + "1": "Compound Eyes" + }, + "heightm": 1.2, + "weightkg": 17, + "color": "Black", + "eggGroups": [ + "Bug" + ] + }, + "litleo": { + "num": 667, + "species": "Litleo", + "types": [ + "Fire", + "Normal" + ], + "genderRatio": { + "M": 0.125, + "F": 0.875 + }, + "baseStats": { + "hp": 62, + "atk": 50, + "def": 58, + "spa": 73, + "spd": 54, + "spe": 72 + }, + "abilities": { + "0": "Rivalry", + "1": "Unnerve", + "H": "Moxie" + }, + "heightm": 0.6, + "weightkg": 13.5, + "color": "Brown", + "evos": [ + "pyroar" + ], + "eggGroups": [ + "Field" + ] + }, + "pyroar": { + "num": 668, + "species": "Pyroar", + "types": [ + "Fire", + "Normal" + ], + "genderRatio": { + "M": 0.125, + "F": 0.875 + }, + "baseStats": { + "hp": 86, + "atk": 68, + "def": 72, + "spa": 109, + "spd": 66, + "spe": 106 + }, + "abilities": { + "0": "Rivalry", + "1": "Unnerve", + "H": "Moxie" + }, + "heightm": 1.5, + "weightkg": 81.5, + "color": "Brown", + "prevo": "litleo", + "evoLevel": 35, + "eggGroups": [ + "Field" + ] + }, + "flabebe": { + "num": 669, + "species": "Flabebe", + "types": [ + "Fairy" + ], + "gender": "F", + "baseStats": { + "hp": 44, + "atk": 38, + "def": 39, + "spa": 61, + "spd": 79, + "spe": 42 + }, + "abilities": { + "0": "Flower Veil", + "H": "Symbiosis" + }, + "heightm": 0.1, + "weightkg": 0.1, + "color": "White", + "evos": [ + "floette" + ], + "eggGroups": [ + "Fairy" + ], + "otherForms": [ + "flabebeblue", + "flabebeorange", + "flabebewhite", + "flabebeyellow" + ] + }, + "floette": { + "num": 670, + "species": "Floette", + "baseForme": "Red-Flower", + "types": [ + "Fairy" + ], + "gender": "F", + "baseStats": { + "hp": 54, + "atk": 45, + "def": 47, + "spa": 75, + "spd": 98, + "spe": 52 + }, + "abilities": { + "0": "Flower Veil", + "H": "Symbiosis" + }, + "heightm": 0.2, + "weightkg": 0.9, + "color": "White", + "prevo": "flabebe", + "evos": [ + "florges" + ], + "evoLevel": 19, + "eggGroups": [ + "Fairy" + ], + "otherForms": [ + "floetteblue", + "floetteorange", + "floettewhite", + "floetteyellow" + ], + "otherFormes": [ + "floetteeternal" + ] + }, + "floetteeternal": { + "num": 670, + "species": "Floette-Eternal", + "baseSpecies": "Floette", + "forme": "Eternal", + "formeLetter": "E", + "types": [ + "Fairy" + ], + "gender": "F", + "baseStats": { + "hp": 74, + "atk": 65, + "def": 67, + "spa": 125, + "spd": 128, + "spe": 92 + }, + "abilities": { + "0": "Flower Veil" + }, + "heightm": 0.2, + "weightkg": 0.9, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "florges": { + "num": 671, + "species": "Florges", + "types": [ + "Fairy" + ], + "gender": "F", + "baseStats": { + "hp": 78, + "atk": 65, + "def": 68, + "spa": 112, + "spd": 154, + "spe": 75 + }, + "abilities": { + "0": "Flower Veil", + "H": "Symbiosis" + }, + "heightm": 1.1, + "weightkg": 10, + "color": "White", + "prevo": "floette", + "evoLevel": 19, + "eggGroups": [ + "Fairy" + ], + "otherForms": [ + "florgesblue", + "florgesorange", + "florgeswhite", + "florgesyellow" + ] + }, + "skiddo": { + "num": 672, + "species": "Skiddo", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 66, + "atk": 65, + "def": 48, + "spa": 62, + "spd": 57, + "spe": 52 + }, + "abilities": { + "0": "Sap Sipper", + "H": "Grass Pelt" + }, + "heightm": 0.9, + "weightkg": 31, + "color": "Brown", + "evos": [ + "gogoat" + ], + "eggGroups": [ + "Field" + ] + }, + "gogoat": { + "num": 673, + "species": "Gogoat", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 123, + "atk": 100, + "def": 62, + "spa": 97, + "spd": 81, + "spe": 68 + }, + "abilities": { + "0": "Sap Sipper", + "H": "Grass Pelt" + }, + "heightm": 1.7, + "weightkg": 91, + "color": "Brown", + "prevo": "skiddo", + "evoLevel": 32, + "eggGroups": [ + "Field" + ] + }, + "pancham": { + "num": 674, + "species": "Pancham", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 67, + "atk": 82, + "def": 62, + "spa": 46, + "spd": 48, + "spe": 43 + }, + "abilities": { + "0": "Iron Fist", + "1": "Mold Breaker", + "H": "Scrappy" + }, + "heightm": 0.6, + "weightkg": 8, + "color": "White", + "evos": [ + "pangoro" + ], + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "pangoro": { + "num": 675, + "species": "Pangoro", + "types": [ + "Fighting", + "Dark" + ], + "baseStats": { + "hp": 95, + "atk": 124, + "def": 78, + "spa": 69, + "spd": 71, + "spe": 58 + }, + "abilities": { + "0": "Iron Fist", + "1": "Mold Breaker", + "H": "Scrappy" + }, + "heightm": 2.1, + "weightkg": 136, + "color": "White", + "prevo": "pancham", + "evoLevel": 32, + "eggGroups": [ + "Field", + "Human-Like" + ] + }, + "furfrou": { + "num": 676, + "species": "Furfrou", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 75, + "atk": 80, + "def": 60, + "spa": 65, + "spd": 90, + "spe": 102 + }, + "abilities": { + "0": "Fur Coat" + }, + "heightm": 1.2, + "weightkg": 28, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "espurr": { + "num": 677, + "species": "Espurr", + "types": [ + "Psychic" + ], + "baseStats": { + "hp": 62, + "atk": 48, + "def": 54, + "spa": 63, + "spd": 60, + "spe": 68 + }, + "abilities": { + "0": "Keen Eye", + "1": "Infiltrator", + "H": "Own Tempo" + }, + "heightm": 0.3, + "weightkg": 3.5, + "color": "Gray", + "evos": [ + "meowstic" + ], + "eggGroups": [ + "Field" + ] + }, + "meowstic": { + "num": 678, + "species": "Meowstic", + "baseForme": "M", + "types": [ + "Psychic" + ], + "gender": "M", + "baseStats": { + "hp": 74, + "atk": 48, + "def": 76, + "spa": 83, + "spd": 81, + "spe": 104 + }, + "abilities": { + "0": "Keen Eye", + "1": "Infiltrator", + "H": "Prankster" + }, + "heightm": 0.6, + "weightkg": 8.5, + "color": "White", + "prevo": "espurr", + "evoLevel": 25, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "meowsticf" + ] + }, + "meowsticf": { + "num": 678, + "species": "Meowstic-F", + "baseSpecies": "Meowstic", + "forme": "F", + "formeLetter": "F", + "types": [ + "Psychic" + ], + "gender": "F", + "baseStats": { + "hp": 74, + "atk": 48, + "def": 76, + "spa": 83, + "spd": 81, + "spe": 104 + }, + "abilities": { + "0": "Keen Eye", + "1": "Infiltrator", + "H": "Competitive" + }, + "heightm": 0.6, + "weightkg": 8.5, + "color": "White", + "prevo": "espurr", + "evoLevel": 25, + "eggGroups": [ + "Field" + ] + }, + "honedge": { + "num": 679, + "species": "Honedge", + "types": [ + "Steel", + "Ghost" + ], + "baseStats": { + "hp": 45, + "atk": 80, + "def": 100, + "spa": 35, + "spd": 37, + "spe": 28 + }, + "abilities": { + "0": "No Guard" + }, + "heightm": 0.8, + "weightkg": 2, + "color": "Brown", + "evos": [ + "doublade" + ], + "eggGroups": [ + "Mineral" + ] + }, + "doublade": { + "num": 680, + "species": "Doublade", + "types": [ + "Steel", + "Ghost" + ], + "baseStats": { + "hp": 59, + "atk": 110, + "def": 150, + "spa": 45, + "spd": 49, + "spe": 35 + }, + "abilities": { + "0": "No Guard" + }, + "heightm": 0.8, + "weightkg": 4.5, + "color": "Brown", + "prevo": "honedge", + "evos": [ + "aegislash" + ], + "evoLevel": 35, + "eggGroups": [ + "Mineral" + ] + }, + "aegislash": { + "num": 681, + "species": "Aegislash", + "baseForme": "Shield", + "types": [ + "Steel", + "Ghost" + ], + "baseStats": { + "hp": 60, + "atk": 50, + "def": 150, + "spa": 50, + "spd": 150, + "spe": 60 + }, + "abilities": { + "0": "Stance Change" + }, + "heightm": 1.7, + "weightkg": 53, + "color": "Brown", + "prevo": "doublade", + "evoLevel": 35, + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "aegislashblade" + ] + }, + "aegislashblade": { + "num": 681, + "species": "Aegislash-Blade", + "baseSpecies": "Aegislash", + "forme": "Blade", + "formeLetter": "B", + "types": [ + "Steel", + "Ghost" + ], + "baseStats": { + "hp": 60, + "atk": 150, + "def": 50, + "spa": 150, + "spd": 50, + "spe": 60 + }, + "abilities": { + "0": "Stance Change" + }, + "heightm": 1.7, + "weightkg": 53, + "color": "Brown", + "prevo": "doublade", + "evoLevel": 35, + "eggGroups": [ + "Mineral" + ] + }, + "spritzee": { + "num": 682, + "species": "Spritzee", + "types": [ + "Fairy" + ], + "baseStats": { + "hp": 78, + "atk": 52, + "def": 60, + "spa": 63, + "spd": 65, + "spe": 23 + }, + "abilities": { + "0": "Healer", + "H": "Aroma Veil" + }, + "heightm": 0.2, + "weightkg": 0.5, + "color": "Pink", + "evos": [ + "aromatisse" + ], + "eggGroups": [ + "Fairy" + ] + }, + "aromatisse": { + "num": 683, + "species": "Aromatisse", + "types": [ + "Fairy" + ], + "baseStats": { + "hp": 101, + "atk": 72, + "def": 72, + "spa": 99, + "spd": 89, + "spe": 29 + }, + "abilities": { + "0": "Healer", + "H": "Aroma Veil" + }, + "heightm": 0.8, + "weightkg": 15.5, + "color": "Pink", + "prevo": "spritzee", + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "swirlix": { + "num": 684, + "species": "Swirlix", + "types": [ + "Fairy" + ], + "baseStats": { + "hp": 62, + "atk": 48, + "def": 66, + "spa": 59, + "spd": 57, + "spe": 49 + }, + "abilities": { + "0": "Sweet Veil", + "H": "Unburden" + }, + "heightm": 0.4, + "weightkg": 3.5, + "color": "White", + "evos": [ + "slurpuff" + ], + "eggGroups": [ + "Fairy" + ] + }, + "slurpuff": { + "num": 685, + "species": "Slurpuff", + "types": [ + "Fairy" + ], + "baseStats": { + "hp": 82, + "atk": 80, + "def": 86, + "spa": 85, + "spd": 75, + "spe": 72 + }, + "abilities": { + "0": "Sweet Veil", + "H": "Unburden" + }, + "heightm": 0.8, + "weightkg": 5, + "color": "White", + "prevo": "swirlix", + "evoLevel": 1, + "eggGroups": [ + "Fairy" + ] + }, + "inkay": { + "num": 686, + "species": "Inkay", + "types": [ + "Dark", + "Psychic" + ], + "baseStats": { + "hp": 53, + "atk": 54, + "def": 53, + "spa": 37, + "spd": 46, + "spe": 45 + }, + "abilities": { + "0": "Contrary", + "1": "Suction Cups", + "H": "Infiltrator" + }, + "heightm": 0.4, + "weightkg": 3.5, + "color": "Blue", + "evos": [ + "malamar" + ], + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "malamar": { + "num": 687, + "species": "Malamar", + "types": [ + "Dark", + "Psychic" + ], + "baseStats": { + "hp": 86, + "atk": 92, + "def": 88, + "spa": 68, + "spd": 75, + "spe": 73 + }, + "abilities": { + "0": "Contrary", + "1": "Suction Cups", + "H": "Infiltrator" + }, + "heightm": 1.5, + "weightkg": 47, + "color": "Blue", + "prevo": "inkay", + "evoLevel": 30, + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "binacle": { + "num": 688, + "species": "Binacle", + "types": [ + "Rock", + "Water" + ], + "baseStats": { + "hp": 42, + "atk": 52, + "def": 67, + "spa": 39, + "spd": 56, + "spe": 50 + }, + "abilities": { + "0": "Tough Claws", + "1": "Sniper", + "H": "Pickpocket" + }, + "heightm": 0.5, + "weightkg": 31, + "color": "Brown", + "evos": [ + "barbaracle" + ], + "eggGroups": [ + "Water 3" + ] + }, + "barbaracle": { + "num": 689, + "species": "Barbaracle", + "types": [ + "Rock", + "Water" + ], + "baseStats": { + "hp": 72, + "atk": 105, + "def": 115, + "spa": 54, + "spd": 86, + "spe": 68 + }, + "abilities": { + "0": "Tough Claws", + "1": "Sniper", + "H": "Pickpocket" + }, + "heightm": 1.3, + "weightkg": 96, + "color": "Brown", + "prevo": "binacle", + "evoLevel": 39, + "eggGroups": [ + "Water 3" + ] + }, + "skrelp": { + "num": 690, + "species": "Skrelp", + "types": [ + "Poison", + "Water" + ], + "baseStats": { + "hp": 50, + "atk": 60, + "def": 60, + "spa": 60, + "spd": 60, + "spe": 30 + }, + "abilities": { + "0": "Poison Point", + "1": "Poison Touch", + "H": "Adaptability" + }, + "heightm": 0.5, + "weightkg": 7.3, + "color": "Brown", + "evos": [ + "dragalge" + ], + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "dragalge": { + "num": 691, + "species": "Dragalge", + "types": [ + "Poison", + "Dragon" + ], + "baseStats": { + "hp": 65, + "atk": 75, + "def": 90, + "spa": 97, + "spd": 123, + "spe": 44 + }, + "abilities": { + "0": "Poison Point", + "1": "Poison Touch", + "H": "Adaptability" + }, + "heightm": 1.8, + "weightkg": 81.5, + "color": "Brown", + "prevo": "skrelp", + "evoLevel": 48, + "eggGroups": [ + "Water 1", + "Dragon" + ] + }, + "clauncher": { + "num": 692, + "species": "Clauncher", + "types": [ + "Water" + ], + "baseStats": { + "hp": 50, + "atk": 53, + "def": 62, + "spa": 58, + "spd": 63, + "spe": 44 + }, + "abilities": { + "0": "Mega Launcher" + }, + "heightm": 0.5, + "weightkg": 8.3, + "color": "Blue", + "evos": [ + "clawitzer" + ], + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "clawitzer": { + "num": 693, + "species": "Clawitzer", + "types": [ + "Water" + ], + "baseStats": { + "hp": 71, + "atk": 73, + "def": 88, + "spa": 120, + "spd": 89, + "spe": 59 + }, + "abilities": { + "0": "Mega Launcher" + }, + "heightm": 1.3, + "weightkg": 35.3, + "color": "Blue", + "prevo": "clauncher", + "evoLevel": 37, + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "helioptile": { + "num": 694, + "species": "Helioptile", + "types": [ + "Electric", + "Normal" + ], + "baseStats": { + "hp": 44, + "atk": 38, + "def": 33, + "spa": 61, + "spd": 43, + "spe": 70 + }, + "abilities": { + "0": "Dry Skin", + "1": "Sand Veil", + "H": "Solar Power" + }, + "heightm": 0.5, + "weightkg": 6, + "color": "Yellow", + "evos": [ + "heliolisk" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "heliolisk": { + "num": 695, + "species": "Heliolisk", + "types": [ + "Electric", + "Normal" + ], + "baseStats": { + "hp": 62, + "atk": 55, + "def": 52, + "spa": 109, + "spd": 94, + "spe": 109 + }, + "abilities": { + "0": "Dry Skin", + "1": "Sand Veil", + "H": "Solar Power" + }, + "heightm": 1, + "weightkg": 21, + "color": "Yellow", + "prevo": "helioptile", + "evoLevel": 1, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "tyrunt": { + "num": 696, + "species": "Tyrunt", + "types": [ + "Rock", + "Dragon" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 58, + "atk": 89, + "def": 77, + "spa": 45, + "spd": 45, + "spe": 48 + }, + "abilities": { + "0": "Strong Jaw", + "H": "Sturdy" + }, + "heightm": 0.8, + "weightkg": 26, + "color": "Brown", + "evos": [ + "tyrantrum" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "tyrantrum": { + "num": 697, + "species": "Tyrantrum", + "types": [ + "Rock", + "Dragon" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 82, + "atk": 121, + "def": 119, + "spa": 69, + "spd": 59, + "spe": 71 + }, + "abilities": { + "0": "Strong Jaw", + "H": "Rock Head" + }, + "heightm": 2.5, + "weightkg": 270, + "color": "Red", + "prevo": "tyrunt", + "evoLevel": 39, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "amaura": { + "num": 698, + "species": "Amaura", + "types": [ + "Rock", + "Ice" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 77, + "atk": 59, + "def": 50, + "spa": 67, + "spd": 63, + "spe": 46 + }, + "abilities": { + "0": "Refrigerate", + "H": "Snow Warning" + }, + "heightm": 1.3, + "weightkg": 25.2, + "color": "Blue", + "evos": [ + "aurorus" + ], + "eggGroups": [ + "Monster" + ] + }, + "aurorus": { + "num": 699, + "species": "Aurorus", + "types": [ + "Rock", + "Ice" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 123, + "atk": 77, + "def": 72, + "spa": 99, + "spd": 92, + "spe": 58 + }, + "abilities": { + "0": "Refrigerate", + "H": "Snow Warning" + }, + "heightm": 2.7, + "weightkg": 225, + "color": "Blue", + "prevo": "amaura", + "evoLevel": 39, + "eggGroups": [ + "Monster" + ] + }, + "sylveon": { + "num": 700, + "species": "Sylveon", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 95, + "atk": 65, + "def": 65, + "spa": 110, + "spd": 130, + "spe": 60 + }, + "abilities": { + "0": "Cute Charm", + "H": "Pixilate" + }, + "heightm": 1, + "weightkg": 23.5, + "color": "Pink", + "prevo": "eevee", + "evoLevel": 2, + "eggGroups": [ + "Field" + ] + }, + "hawlucha": { + "num": 701, + "species": "Hawlucha", + "types": [ + "Fighting", + "Flying" + ], + "baseStats": { + "hp": 78, + "atk": 92, + "def": 75, + "spa": 74, + "spd": 63, + "spe": 118 + }, + "abilities": { + "0": "Limber", + "1": "Unburden", + "H": "Mold Breaker" + }, + "heightm": 0.8, + "weightkg": 21.5, + "color": "Green", + "eggGroups": [ + "Human-Like" + ] + }, + "dedenne": { + "num": 702, + "species": "Dedenne", + "types": [ + "Electric", + "Fairy" + ], + "baseStats": { + "hp": 67, + "atk": 58, + "def": 57, + "spa": 81, + "spd": 67, + "spe": 101 + }, + "abilities": { + "0": "Cheek Pouch", + "1": "Pickup", + "H": "Plus" + }, + "heightm": 0.2, + "weightkg": 2.2, + "color": "Yellow", + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "carbink": { + "num": 703, + "species": "Carbink", + "types": [ + "Rock", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 50, + "def": 150, + "spa": 50, + "spd": 150, + "spe": 50 + }, + "abilities": { + "0": "Clear Body", + "H": "Sturdy" + }, + "heightm": 0.3, + "weightkg": 5.7, + "color": "Gray", + "eggGroups": [ + "Fairy", + "Mineral" + ] + }, + "goomy": { + "num": 704, + "species": "Goomy", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 45, + "atk": 50, + "def": 35, + "spa": 55, + "spd": 75, + "spe": 40 + }, + "abilities": { + "0": "Sap Sipper", + "1": "Hydration", + "H": "Gooey" + }, + "heightm": 0.3, + "weightkg": 2.8, + "color": "Purple", + "evos": [ + "sliggoo" + ], + "eggGroups": [ + "Dragon" + ] + }, + "sliggoo": { + "num": 705, + "species": "Sliggoo", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 68, + "atk": 75, + "def": 53, + "spa": 83, + "spd": 113, + "spe": 60 + }, + "abilities": { + "0": "Sap Sipper", + "1": "Hydration", + "H": "Gooey" + }, + "heightm": 0.8, + "weightkg": 17.5, + "color": "Purple", + "prevo": "goomy", + "evos": [ + "goodra" + ], + "evoLevel": 40, + "eggGroups": [ + "Dragon" + ] + }, + "goodra": { + "num": 706, + "species": "Goodra", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 90, + "atk": 100, + "def": 70, + "spa": 110, + "spd": 150, + "spe": 80 + }, + "abilities": { + "0": "Sap Sipper", + "1": "Hydration", + "H": "Gooey" + }, + "heightm": 2, + "weightkg": 150.5, + "color": "Purple", + "prevo": "sliggoo", + "evoLevel": 50, + "eggGroups": [ + "Dragon" + ] + }, + "klefki": { + "num": 707, + "species": "Klefki", + "types": [ + "Steel", + "Fairy" + ], + "baseStats": { + "hp": 57, + "atk": 80, + "def": 91, + "spa": 80, + "spd": 87, + "spe": 75 + }, + "abilities": { + "0": "Prankster", + "H": "Magician" + }, + "heightm": 0.2, + "weightkg": 3, + "color": "Gray", + "eggGroups": [ + "Mineral" + ] + }, + "phantump": { + "num": 708, + "species": "Phantump", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 43, + "atk": 70, + "def": 48, + "spa": 50, + "spd": 60, + "spe": 38 + }, + "abilities": { + "0": "Natural Cure", + "1": "Frisk", + "H": "Harvest" + }, + "heightm": 0.4, + "weightkg": 7, + "color": "Brown", + "evos": [ + "trevenant" + ], + "eggGroups": [ + "Grass", + "Amorphous" + ] + }, + "trevenant": { + "num": 709, + "species": "Trevenant", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 85, + "atk": 110, + "def": 76, + "spa": 65, + "spd": 82, + "spe": 56 + }, + "abilities": { + "0": "Natural Cure", + "1": "Frisk", + "H": "Harvest" + }, + "heightm": 1.5, + "weightkg": 71, + "color": "Brown", + "prevo": "phantump", + "evoLevel": 1, + "eggGroups": [ + "Grass", + "Amorphous" + ] + }, + "pumpkaboo": { + "num": 710, + "species": "Pumpkaboo", + "baseForme": "Average", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 49, + "atk": 66, + "def": 70, + "spa": 44, + "spd": 55, + "spe": 51 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 0.4, + "weightkg": 5, + "color": "Brown", + "evos": [ + "gourgeist" + ], + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "pumpkaboosmall", + "pumpkaboolarge", + "pumpkaboosuper" + ] + }, + "pumpkaboosmall": { + "num": 710, + "species": "Pumpkaboo-Small", + "baseSpecies": "Pumpkaboo", + "forme": "Small", + "formeLetter": "S", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 44, + "atk": 66, + "def": 70, + "spa": 44, + "spd": 55, + "spe": 56 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 0.3, + "weightkg": 3.5, + "color": "Brown", + "evos": [ + "gourgeistsmall" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "pumpkaboolarge": { + "num": 710, + "species": "Pumpkaboo-Large", + "baseSpecies": "Pumpkaboo", + "forme": "Large", + "formeLetter": "L", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 54, + "atk": 66, + "def": 70, + "spa": 44, + "spd": 55, + "spe": 46 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 0.5, + "weightkg": 7.5, + "color": "Brown", + "evos": [ + "gourgeistlarge" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "pumpkaboosuper": { + "num": 710, + "species": "Pumpkaboo-Super", + "baseSpecies": "Pumpkaboo", + "forme": "Super", + "formeLetter": "S", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 59, + "atk": 66, + "def": 70, + "spa": 44, + "spd": 55, + "spe": 41 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 0.8, + "weightkg": 15, + "color": "Brown", + "evos": [ + "gourgeistsuper" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "gourgeist": { + "num": 711, + "species": "Gourgeist", + "baseForme": "Average", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 65, + "atk": 90, + "def": 122, + "spa": 58, + "spd": 75, + "spe": 84 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 0.9, + "weightkg": 12.5, + "color": "Brown", + "prevo": "pumpkaboo", + "evoLevel": 1, + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "gourgeistsmall", + "gourgeistlarge", + "gourgeistsuper" + ] + }, + "gourgeistsmall": { + "num": 711, + "species": "Gourgeist-Small", + "baseSpecies": "Gourgeist", + "forme": "Small", + "formeLetter": "S", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 55, + "atk": 85, + "def": 122, + "spa": 58, + "spd": 75, + "spe": 99 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 0.7, + "weightkg": 9.5, + "color": "Brown", + "prevo": "pumpkaboosmall", + "evoLevel": 1, + "eggGroups": [ + "Amorphous" + ] + }, + "gourgeistlarge": { + "num": 711, + "species": "Gourgeist-Large", + "baseSpecies": "Gourgeist", + "forme": "Large", + "formeLetter": "L", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 75, + "atk": 95, + "def": 122, + "spa": 58, + "spd": 75, + "spe": 69 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 1.1, + "weightkg": 14, + "color": "Brown", + "prevo": "pumpkaboolarge", + "evoLevel": 1, + "eggGroups": [ + "Amorphous" + ] + }, + "gourgeistsuper": { + "num": 711, + "species": "Gourgeist-Super", + "baseSpecies": "Gourgeist", + "forme": "Super", + "formeLetter": "S", + "types": [ + "Ghost", + "Grass" + ], + "baseStats": { + "hp": 85, + "atk": 100, + "def": 122, + "spa": 58, + "spd": 75, + "spe": 54 + }, + "abilities": { + "0": "Pickup", + "1": "Frisk", + "H": "Insomnia" + }, + "heightm": 1.7, + "weightkg": 39, + "color": "Brown", + "prevo": "pumpkaboosuper", + "evoLevel": 1, + "eggGroups": [ + "Amorphous" + ] + }, + "bergmite": { + "num": 712, + "species": "Bergmite", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 55, + "atk": 69, + "def": 85, + "spa": 32, + "spd": 35, + "spe": 28 + }, + "abilities": { + "0": "Own Tempo", + "1": "Ice Body", + "H": "Sturdy" + }, + "heightm": 1, + "weightkg": 99.5, + "color": "Blue", + "evos": [ + "avalugg" + ], + "eggGroups": [ + "Monster" + ] + }, + "avalugg": { + "num": 713, + "species": "Avalugg", + "types": [ + "Ice" + ], + "baseStats": { + "hp": 95, + "atk": 117, + "def": 184, + "spa": 44, + "spd": 46, + "spe": 28 + }, + "abilities": { + "0": "Own Tempo", + "1": "Ice Body", + "H": "Sturdy" + }, + "heightm": 2, + "weightkg": 505, + "color": "Blue", + "prevo": "bergmite", + "evoLevel": 37, + "eggGroups": [ + "Monster" + ] + }, + "noibat": { + "num": 714, + "species": "Noibat", + "types": [ + "Flying", + "Dragon" + ], + "baseStats": { + "hp": 40, + "atk": 30, + "def": 35, + "spa": 45, + "spd": 40, + "spe": 55 + }, + "abilities": { + "0": "Frisk", + "1": "Infiltrator", + "H": "Telepathy" + }, + "heightm": 0.5, + "weightkg": 8, + "color": "Purple", + "evos": [ + "noivern" + ], + "eggGroups": [ + "Flying" + ] + }, + "noivern": { + "num": 715, + "species": "Noivern", + "types": [ + "Flying", + "Dragon" + ], + "baseStats": { + "hp": 85, + "atk": 70, + "def": 80, + "spa": 97, + "spd": 80, + "spe": 123 + }, + "abilities": { + "0": "Frisk", + "1": "Infiltrator", + "H": "Telepathy" + }, + "heightm": 1.5, + "weightkg": 85, + "color": "Purple", + "prevo": "noibat", + "evoLevel": 48, + "eggGroups": [ + "Flying" + ] + }, + "xerneas": { + "num": 716, + "species": "Xerneas", + "types": [ + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 126, + "atk": 131, + "def": 95, + "spa": 131, + "spd": 98, + "spe": 99 + }, + "abilities": { + "0": "Fairy Aura" + }, + "heightm": 3, + "weightkg": 215, + "color": "Blue", + "eggGroups": [ + "Undiscovered" + ] + }, + "yveltal": { + "num": 717, + "species": "Yveltal", + "types": [ + "Dark", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 126, + "atk": 131, + "def": 95, + "spa": 131, + "spd": 98, + "spe": 99 + }, + "abilities": { + "0": "Dark Aura" + }, + "heightm": 5.8, + "weightkg": 203, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "zygarde": { + "num": 718, + "species": "Zygarde", + "baseForme": "50%", + "types": [ + "Dragon", + "Ground" + ], + "gender": "N", + "baseStats": { + "hp": 108, + "atk": 100, + "def": 121, + "spa": 81, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "Aura Break", + "H": "Power Construct" + }, + "heightm": 5, + "weightkg": 305, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "zygarde10", + "zygardecomplete" + ] + }, + "zygarde10": { + "num": 718, + "species": "Zygarde-10%", + "baseSpecies": "Zygarde", + "forme": "10%", + "formeLetter": "T", + "types": [ + "Dragon", + "Ground" + ], + "gender": "N", + "baseStats": { + "hp": 54, + "atk": 100, + "def": 71, + "spa": 61, + "spd": 85, + "spe": 115 + }, + "abilities": { + "0": "Aura Break", + "H": "Power Construct" + }, + "heightm": 1.2, + "weightkg": 33.5, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "zygardecomplete": { + "num": 718, + "species": "Zygarde-Complete", + "baseSpecies": "Zygarde", + "forme": "Complete", + "formeLetter": "C", + "types": [ + "Dragon", + "Ground" + ], + "gender": "N", + "baseStats": { + "hp": 216, + "atk": 100, + "def": 121, + "spa": 91, + "spd": 95, + "spe": 85 + }, + "abilities": { + "0": "Power Construct" + }, + "heightm": 4.5, + "weightkg": 610, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "diancie": { + "num": 719, + "species": "Diancie", + "types": [ + "Rock", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 100, + "def": 150, + "spa": 100, + "spd": 150, + "spe": 50 + }, + "abilities": { + "0": "Clear Body" + }, + "heightm": 0.7, + "weightkg": 8.8, + "color": "Pink", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "dianciemega" + ] + }, + "dianciemega": { + "num": 719, + "species": "Diancie-Mega", + "baseSpecies": "Diancie", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Rock", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 50, + "atk": 160, + "def": 110, + "spa": 160, + "spd": 110, + "spe": 110 + }, + "abilities": { + "0": "Magic Bounce" + }, + "heightm": 1.1, + "weightkg": 27.8, + "color": "Pink", + "eggGroups": [ + "Undiscovered" + ] + }, + "hoopa": { + "num": 720, + "species": "Hoopa", + "baseForme": "Confined", + "types": [ + "Psychic", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 110, + "def": 60, + "spa": 150, + "spd": 130, + "spe": 70 + }, + "abilities": { + "0": "Magician" + }, + "heightm": 0.5, + "weightkg": 9, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "hoopaunbound" + ] + }, + "hoopaunbound": { + "num": 720, + "species": "Hoopa-Unbound", + "baseSpecies": "Hoopa", + "forme": "Unbound", + "formeLetter": "U", + "types": [ + "Psychic", + "Dark" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 160, + "def": 60, + "spa": 170, + "spd": 130, + "spe": 80 + }, + "abilities": { + "0": "Magician" + }, + "heightm": 6.5, + "weightkg": 490, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "volcanion": { + "num": 721, + "species": "Volcanion", + "types": [ + "Fire", + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 110, + "def": 120, + "spa": 130, + "spd": 90, + "spe": 70 + }, + "abilities": { + "0": "Water Absorb" + }, + "heightm": 1.7, + "weightkg": 195, + "color": "Brown", + "eggGroups": [ + "Undiscovered" + ] + }, + "rowlet": { + "num": 722, + "species": "Rowlet", + "types": [ + "Grass", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 68, + "atk": 55, + "def": 55, + "spa": 50, + "spd": 50, + "spe": 42 + }, + "abilities": { + "0": "Overgrow", + "H": "Long Reach" + }, + "heightm": 0.3, + "weightkg": 1.5, + "color": "Brown", + "evos": [ + "dartrix" + ], + "eggGroups": [ + "Flying" + ] + }, + "dartrix": { + "num": 723, + "species": "Dartrix", + "types": [ + "Grass", + "Flying" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 78, + "atk": 75, + "def": 75, + "spa": 70, + "spd": 70, + "spe": 52 + }, + "abilities": { + "0": "Overgrow", + "H": "Long Reach" + }, + "heightm": 0.7, + "weightkg": 16, + "color": "Brown", + "prevo": "rowlet", + "evos": [ + "decidueye" + ], + "evoLevel": 17, + "eggGroups": [ + "Flying" + ] + }, + "decidueye": { + "num": 724, + "species": "Decidueye", + "types": [ + "Grass", + "Ghost" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 78, + "atk": 107, + "def": 75, + "spa": 100, + "spd": 100, + "spe": 70 + }, + "abilities": { + "0": "Overgrow", + "H": "Long Reach" + }, + "heightm": 1.6, + "weightkg": 36.6, + "color": "Brown", + "prevo": "dartrix", + "evoLevel": 34, + "eggGroups": [ + "Flying" + ] + }, + "litten": { + "num": 725, + "species": "Litten", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 45, + "atk": 65, + "def": 40, + "spa": 60, + "spd": 40, + "spe": 70 + }, + "abilities": { + "0": "Blaze", + "H": "Intimidate" + }, + "heightm": 0.4, + "weightkg": 4.3, + "color": "Red", + "evos": [ + "torracat" + ], + "eggGroups": [ + "Field" + ] + }, + "torracat": { + "num": 726, + "species": "Torracat", + "types": [ + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 65, + "atk": 85, + "def": 50, + "spa": 80, + "spd": 50, + "spe": 90 + }, + "abilities": { + "0": "Blaze", + "H": "Intimidate" + }, + "heightm": 0.7, + "weightkg": 25, + "color": "Red", + "prevo": "litten", + "evos": [ + "incineroar" + ], + "evoLevel": 17, + "eggGroups": [ + "Field" + ] + }, + "incineroar": { + "num": 727, + "species": "Incineroar", + "types": [ + "Fire", + "Dark" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 95, + "atk": 115, + "def": 90, + "spa": 80, + "spd": 90, + "spe": 60 + }, + "abilities": { + "0": "Blaze", + "H": "Intimidate" + }, + "heightm": 1.8, + "weightkg": 83, + "color": "Red", + "prevo": "torracat", + "evoLevel": 34, + "eggGroups": [ + "Field" + ] + }, + "popplio": { + "num": 728, + "species": "Popplio", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 50, + "atk": 54, + "def": 54, + "spa": 66, + "spd": 56, + "spe": 40 + }, + "abilities": { + "0": "Torrent", + "H": "Liquid Voice" + }, + "heightm": 0.4, + "weightkg": 7.5, + "color": "Blue", + "evos": [ + "brionne" + ], + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "brionne": { + "num": 729, + "species": "Brionne", + "types": [ + "Water" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 60, + "atk": 69, + "def": 69, + "spa": 91, + "spd": 81, + "spe": 50 + }, + "abilities": { + "0": "Torrent", + "H": "Liquid Voice" + }, + "heightm": 0.6, + "weightkg": 17.5, + "color": "Blue", + "prevo": "popplio", + "evos": [ + "primarina" + ], + "evoLevel": 17, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "primarina": { + "num": 730, + "species": "Primarina", + "types": [ + "Water", + "Fairy" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 80, + "atk": 74, + "def": 74, + "spa": 126, + "spd": 116, + "spe": 60 + }, + "abilities": { + "0": "Torrent", + "H": "Liquid Voice" + }, + "heightm": 1.8, + "weightkg": 44, + "color": "Blue", + "prevo": "brionne", + "evoLevel": 34, + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "pikipek": { + "num": 731, + "species": "Pikipek", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 35, + "atk": 75, + "def": 30, + "spa": 30, + "spd": 30, + "spe": 65 + }, + "abilities": { + "0": "Keen Eye", + "1": "Skill Link", + "H": "Pickup" + }, + "heightm": 0.3, + "weightkg": 1.2, + "color": "Black", + "evos": [ + "trumbeak" + ], + "eggGroups": [ + "Flying" + ] + }, + "trumbeak": { + "num": 732, + "species": "Trumbeak", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 55, + "atk": 85, + "def": 50, + "spa": 40, + "spd": 50, + "spe": 75 + }, + "abilities": { + "0": "Keen Eye", + "1": "Skill Link", + "H": "Pickup" + }, + "heightm": 0.6, + "weightkg": 14.8, + "color": "Black", + "prevo": "pikipek", + "evos": [ + "toucannon" + ], + "evoLevel": 14, + "eggGroups": [ + "Flying" + ] + }, + "toucannon": { + "num": 733, + "species": "Toucannon", + "types": [ + "Normal", + "Flying" + ], + "baseStats": { + "hp": 80, + "atk": 120, + "def": 75, + "spa": 75, + "spd": 75, + "spe": 60 + }, + "abilities": { + "0": "Keen Eye", + "1": "Skill Link", + "H": "Sheer Force" + }, + "heightm": 1.1, + "weightkg": 26, + "color": "Black", + "prevo": "trumbeak", + "evoLevel": 28, + "eggGroups": [ + "Flying" + ] + }, + "yungoos": { + "num": 734, + "species": "Yungoos", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 48, + "atk": 70, + "def": 30, + "spa": 30, + "spd": 30, + "spe": 45 + }, + "abilities": { + "0": "Stakeout", + "1": "Strong Jaw", + "H": "Adaptability" + }, + "heightm": 0.4, + "weightkg": 6, + "color": "Brown", + "evos": [ + "gumshoos" + ], + "eggGroups": [ + "Field" + ] + }, + "gumshoos": { + "num": 735, + "species": "Gumshoos", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 88, + "atk": 110, + "def": 60, + "spa": 55, + "spd": 60, + "spe": 45 + }, + "abilities": { + "0": "Stakeout", + "1": "Strong Jaw", + "H": "Adaptability" + }, + "heightm": 0.7, + "weightkg": 14.2, + "color": "Brown", + "prevo": "yungoos", + "evoLevel": 20, + "eggGroups": [ + "Field" + ] + }, + "grubbin": { + "num": 736, + "species": "Grubbin", + "types": [ + "Bug" + ], + "baseStats": { + "hp": 47, + "atk": 62, + "def": 45, + "spa": 55, + "spd": 45, + "spe": 46 + }, + "abilities": { + "0": "Swarm" + }, + "heightm": 0.4, + "weightkg": 4.4, + "color": "Gray", + "evos": [ + "charjabug" + ], + "eggGroups": [ + "Bug" + ] + }, + "charjabug": { + "num": 737, + "species": "Charjabug", + "types": [ + "Bug", + "Electric" + ], + "baseStats": { + "hp": 57, + "atk": 82, + "def": 95, + "spa": 55, + "spd": 75, + "spe": 36 + }, + "abilities": { + "0": "Battery" + }, + "heightm": 0.5, + "weightkg": 10.5, + "color": "Green", + "prevo": "grubbin", + "evos": [ + "vikavolt" + ], + "evoLevel": 20, + "eggGroups": [ + "Bug" + ] + }, + "vikavolt": { + "num": 738, + "species": "Vikavolt", + "types": [ + "Bug", + "Electric" + ], + "baseStats": { + "hp": 77, + "atk": 70, + "def": 90, + "spa": 145, + "spd": 75, + "spe": 43 + }, + "abilities": { + "0": "Levitate" + }, + "heightm": 1.5, + "weightkg": 45, + "color": "Blue", + "prevo": "charjabug", + "evoLevel": 21, + "eggGroups": [ + "Bug" + ] + }, + "crabrawler": { + "num": 739, + "species": "Crabrawler", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 47, + "atk": 82, + "def": 57, + "spa": 42, + "spd": 47, + "spe": 63 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Iron Fist", + "H": "Anger Point" + }, + "heightm": 0.6, + "weightkg": 7, + "color": "Purple", + "evos": [ + "crabominable" + ], + "eggGroups": [ + "Water 3" + ] + }, + "crabominable": { + "num": 740, + "species": "Crabominable", + "types": [ + "Fighting", + "Ice" + ], + "baseStats": { + "hp": 97, + "atk": 132, + "def": 77, + "spa": 62, + "spd": 67, + "spe": 43 + }, + "abilities": { + "0": "Hyper Cutter", + "1": "Iron Fist", + "H": "Anger Point" + }, + "heightm": 1.7, + "weightkg": 180, + "color": "White", + "prevo": "crabrawler", + "evoLevel": 2, + "eggGroups": [ + "Water 3" + ] + }, + "oricorio": { + "num": 741, + "species": "Oricorio", + "baseForme": "Baile", + "types": [ + "Fire", + "Flying" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 75, + "atk": 70, + "def": 70, + "spa": 98, + "spd": 70, + "spe": 93 + }, + "abilities": { + "0": "Dancer" + }, + "heightm": 0.6, + "weightkg": 3.4, + "color": "Red", + "eggGroups": [ + "Flying" + ], + "otherFormes": [ + "oricoriopompom", + "oricoriopau", + "oricoriosensu" + ] + }, + "oricoriopompom": { + "num": 741, + "species": "Oricorio-Pom-Pom", + "baseSpecies": "Oricorio", + "forme": "Pom-Pom", + "formeLetter": "P", + "types": [ + "Electric", + "Flying" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 75, + "atk": 70, + "def": 70, + "spa": 98, + "spd": 70, + "spe": 93 + }, + "abilities": { + "0": "Dancer" + }, + "heightm": 0.6, + "weightkg": 3.4, + "color": "Yellow", + "eggGroups": [ + "Flying" + ] + }, + "oricoriopau": { + "num": 741, + "species": "Oricorio-Pa'u", + "baseSpecies": "Oricorio", + "forme": "Pa'u", + "formeLetter": "P", + "types": [ + "Psychic", + "Flying" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 75, + "atk": 70, + "def": 70, + "spa": 98, + "spd": 70, + "spe": 93 + }, + "abilities": { + "0": "Dancer" + }, + "heightm": 0.6, + "weightkg": 3.4, + "color": "Pink", + "eggGroups": [ + "Flying" + ] + }, + "oricoriosensu": { + "num": 741, + "species": "Oricorio-Sensu", + "baseSpecies": "Oricorio", + "forme": "Sensu", + "formeLetter": "S", + "types": [ + "Ghost", + "Flying" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 75, + "atk": 70, + "def": 70, + "spa": 98, + "spd": 70, + "spe": 93 + }, + "abilities": { + "0": "Dancer" + }, + "heightm": 0.6, + "weightkg": 3.4, + "color": "Purple", + "eggGroups": [ + "Flying" + ] + }, + "cutiefly": { + "num": 742, + "species": "Cutiefly", + "types": [ + "Bug", + "Fairy" + ], + "baseStats": { + "hp": 40, + "atk": 45, + "def": 40, + "spa": 55, + "spd": 40, + "spe": 84 + }, + "abilities": { + "0": "Honey Gather", + "1": "Shield Dust", + "H": "Sweet Veil" + }, + "heightm": 0.1, + "weightkg": 0.2, + "color": "Yellow", + "evos": [ + "ribombee" + ], + "eggGroups": [ + "Bug", + "Fairy" + ] + }, + "ribombee": { + "num": 743, + "species": "Ribombee", + "types": [ + "Bug", + "Fairy" + ], + "baseStats": { + "hp": 60, + "atk": 55, + "def": 60, + "spa": 95, + "spd": 70, + "spe": 124 + }, + "abilities": { + "0": "Honey Gather", + "1": "Shield Dust", + "H": "Sweet Veil" + }, + "heightm": 0.2, + "weightkg": 0.5, + "color": "Yellow", + "prevo": "cutiefly", + "evoLevel": 25, + "eggGroups": [ + "Bug", + "Fairy" + ] + }, + "rockruff": { + "num": 744, + "species": "Rockruff", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 45, + "atk": 65, + "def": 40, + "spa": 30, + "spd": 40, + "spe": 60 + }, + "abilities": { + "0": "Keen Eye", + "1": "Vital Spirit", + "H": "Steadfast" + }, + "heightm": 0.5, + "weightkg": 9.2, + "color": "Brown", + "evos": [ + "lycanroc", + "lycanrocmidnight" + ], + "eggGroups": [ + "Field" + ] + }, + "lycanroc": { + "num": 745, + "species": "Lycanroc", + "baseForme": "Midday", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 75, + "atk": 115, + "def": 65, + "spa": 55, + "spd": 65, + "spe": 112 + }, + "abilities": { + "0": "Keen Eye", + "1": "Sand Rush", + "H": "Steadfast" + }, + "heightm": 0.8, + "weightkg": 25, + "color": "Brown", + "prevo": "rockruff", + "evoLevel": 25, + "eggGroups": [ + "Field" + ], + "otherFormes": [ + "lycanrocmidnight" + ] + }, + "lycanrocmidnight": { + "num": 745, + "species": "Lycanroc-Midnight", + "baseSpecies": "Lycanroc", + "forme": "Midnight", + "formeLetter": "M", + "types": [ + "Rock" + ], + "baseStats": { + "hp": 85, + "atk": 115, + "def": 75, + "spa": 55, + "spd": 75, + "spe": 82 + }, + "abilities": { + "0": "Keen Eye", + "1": "Vital Spirit", + "H": "No Guard" + }, + "heightm": 1.1, + "weightkg": 25, + "color": "Red", + "prevo": "rockruff", + "evoLevel": 25, + "eggGroups": [ + "Field" + ] + }, + "wishiwashi": { + "num": 746, + "species": "Wishiwashi", + "baseForme": "Solo", + "types": [ + "Water" + ], + "baseStats": { + "hp": 45, + "atk": 20, + "def": 20, + "spa": 25, + "spd": 25, + "spe": 40 + }, + "abilities": { + "0": "Schooling" + }, + "heightm": 0.2, + "weightkg": 0.3, + "color": "Blue", + "eggGroups": [ + "Water 2" + ], + "otherFormes": [ + "wishiwashischool" + ] + }, + "wishiwashischool": { + "num": 746, + "species": "Wishiwashi-School", + "baseSpecies": "Wishiwashi", + "forme": "School", + "formeLetter": "S", + "types": [ + "Water" + ], + "baseStats": { + "hp": 45, + "atk": 140, + "def": 130, + "spa": 140, + "spd": 135, + "spe": 30 + }, + "abilities": { + "0": "Schooling" + }, + "heightm": 8.2, + "weightkg": 78.6, + "color": "Blue", + "eggGroups": [ + "Water 2" + ] + }, + "mareanie": { + "num": 747, + "species": "Mareanie", + "types": [ + "Poison", + "Water" + ], + "baseStats": { + "hp": 50, + "atk": 53, + "def": 62, + "spa": 43, + "spd": 52, + "spe": 45 + }, + "abilities": { + "0": "Merciless", + "1": "Limber", + "H": "Regenerator" + }, + "heightm": 0.4, + "weightkg": 8, + "color": "Blue", + "evos": [ + "toxapex" + ], + "eggGroups": [ + "Water 1" + ] + }, + "toxapex": { + "num": 748, + "species": "Toxapex", + "types": [ + "Poison", + "Water" + ], + "baseStats": { + "hp": 50, + "atk": 63, + "def": 152, + "spa": 53, + "spd": 142, + "spe": 35 + }, + "abilities": { + "0": "Merciless", + "1": "Limber", + "H": "Regenerator" + }, + "heightm": 0.7, + "weightkg": 14.5, + "color": "Blue", + "prevo": "mareanie", + "evoLevel": 38, + "eggGroups": [ + "Water 1" + ] + }, + "mudbray": { + "num": 749, + "species": "Mudbray", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 70, + "atk": 100, + "def": 70, + "spa": 45, + "spd": 55, + "spe": 45 + }, + "abilities": { + "0": "Own Tempo", + "1": "Stamina", + "H": "Inner Focus" + }, + "heightm": 1, + "weightkg": 110, + "color": "Brown", + "evos": [ + "mudsdale" + ], + "eggGroups": [ + "Field" + ] + }, + "mudsdale": { + "num": 750, + "species": "Mudsdale", + "types": [ + "Ground" + ], + "baseStats": { + "hp": 100, + "atk": 125, + "def": 100, + "spa": 55, + "spd": 85, + "spe": 35 + }, + "abilities": { + "0": "Own Tempo", + "1": "Stamina", + "H": "Inner Focus" + }, + "heightm": 2.5, + "weightkg": 920, + "color": "Brown", + "prevo": "mudbray", + "evoLevel": 30, + "eggGroups": [ + "Field" + ] + }, + "dewpider": { + "num": 751, + "species": "Dewpider", + "types": [ + "Water", + "Bug" + ], + "baseStats": { + "hp": 38, + "atk": 40, + "def": 52, + "spa": 40, + "spd": 72, + "spe": 27 + }, + "abilities": { + "0": "Water Bubble", + "H": "Water Absorb" + }, + "heightm": 0.3, + "weightkg": 4, + "color": "Green", + "evos": [ + "araquanid" + ], + "eggGroups": [ + "Water 1", + "Bug" + ] + }, + "araquanid": { + "num": 752, + "species": "Araquanid", + "types": [ + "Water", + "Bug" + ], + "baseStats": { + "hp": 68, + "atk": 70, + "def": 92, + "spa": 50, + "spd": 132, + "spe": 42 + }, + "abilities": { + "0": "Water Bubble", + "H": "Water Absorb" + }, + "heightm": 1.8, + "weightkg": 82, + "color": "Green", + "prevo": "dewpider", + "evoLevel": 22, + "eggGroups": [ + "Water 1", + "Bug" + ] + }, + "fomantis": { + "num": 753, + "species": "Fomantis", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 40, + "atk": 55, + "def": 35, + "spa": 50, + "spd": 35, + "spe": 35 + }, + "abilities": { + "0": "Leaf Guard", + "H": "Contrary" + }, + "heightm": 0.3, + "weightkg": 1.5, + "color": "Pink", + "evos": [ + "lurantis" + ], + "eggGroups": [ + "Grass" + ] + }, + "lurantis": { + "num": 754, + "species": "Lurantis", + "types": [ + "Grass" + ], + "baseStats": { + "hp": 70, + "atk": 105, + "def": 90, + "spa": 80, + "spd": 90, + "spe": 45 + }, + "abilities": { + "0": "Leaf Guard", + "H": "Contrary" + }, + "heightm": 0.9, + "weightkg": 18.5, + "color": "Green", + "prevo": "fomantis", + "evoLevel": 34, + "eggGroups": [ + "Grass" + ] + }, + "morelull": { + "num": 755, + "species": "Morelull", + "types": [ + "Grass", + "Fairy" + ], + "baseStats": { + "hp": 40, + "atk": 35, + "def": 55, + "spa": 65, + "spd": 75, + "spe": 15 + }, + "abilities": { + "0": "Illuminate", + "1": "Effect Spore", + "H": "Rain Dish" + }, + "heightm": 0.2, + "weightkg": 1.5, + "color": "Purple", + "evos": [ + "shiinotic" + ], + "eggGroups": [ + "Grass" + ] + }, + "shiinotic": { + "num": 756, + "species": "Shiinotic", + "types": [ + "Grass", + "Fairy" + ], + "baseStats": { + "hp": 60, + "atk": 45, + "def": 80, + "spa": 90, + "spd": 100, + "spe": 30 + }, + "abilities": { + "0": "Illuminate", + "1": "Effect Spore", + "H": "Rain Dish" + }, + "heightm": 1, + "weightkg": 11.5, + "color": "Purple", + "prevo": "morelull", + "evoLevel": 24, + "eggGroups": [ + "Grass" + ] + }, + "salandit": { + "num": 757, + "species": "Salandit", + "types": [ + "Poison", + "Fire" + ], + "genderRatio": { + "M": 0.875, + "F": 0.125 + }, + "baseStats": { + "hp": 48, + "atk": 44, + "def": 40, + "spa": 71, + "spd": 40, + "spe": 77 + }, + "abilities": { + "0": "Corrosion", + "H": "Oblivious" + }, + "heightm": 0.6, + "weightkg": 4.8, + "color": "Black", + "evos": [ + "salazzle" + ], + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "salazzle": { + "num": 758, + "species": "Salazzle", + "types": [ + "Poison", + "Fire" + ], + "gender": "F", + "baseStats": { + "hp": 68, + "atk": 64, + "def": 60, + "spa": 111, + "spd": 60, + "spe": 117 + }, + "abilities": { + "0": "Corrosion", + "H": "Oblivious" + }, + "heightm": 1.2, + "weightkg": 22.2, + "color": "Black", + "prevo": "salandit", + "evoLevel": 33, + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "stufful": { + "num": 759, + "species": "Stufful", + "types": [ + "Normal", + "Fighting" + ], + "baseStats": { + "hp": 70, + "atk": 75, + "def": 50, + "spa": 45, + "spd": 50, + "spe": 50 + }, + "abilities": { + "0": "Fluffy", + "1": "Klutz", + "H": "Cute Charm" + }, + "heightm": 0.5, + "weightkg": 6.8, + "color": "Pink", + "evos": [ + "bewear" + ], + "eggGroups": [ + "Field" + ] + }, + "bewear": { + "num": 760, + "species": "Bewear", + "types": [ + "Normal", + "Fighting" + ], + "baseStats": { + "hp": 120, + "atk": 125, + "def": 80, + "spa": 55, + "spd": 60, + "spe": 60 + }, + "abilities": { + "0": "Fluffy", + "1": "Klutz", + "H": "Unnerve" + }, + "heightm": 2.1, + "weightkg": 135, + "color": "Pink", + "prevo": "stufful", + "evoLevel": 27, + "eggGroups": [ + "Field" + ] + }, + "bounsweet": { + "num": 761, + "species": "Bounsweet", + "types": [ + "Grass" + ], + "gender": "F", + "baseStats": { + "hp": 42, + "atk": 30, + "def": 38, + "spa": 30, + "spd": 38, + "spe": 32 + }, + "abilities": { + "0": "Leaf Guard", + "1": "Oblivious", + "H": "Sweet Veil" + }, + "heightm": 0.3, + "weightkg": 3.2, + "color": "Purple", + "evos": [ + "steenee" + ], + "eggGroups": [ + "Grass" + ] + }, + "steenee": { + "num": 762, + "species": "Steenee", + "types": [ + "Grass" + ], + "gender": "F", + "baseStats": { + "hp": 52, + "atk": 40, + "def": 48, + "spa": 40, + "spd": 48, + "spe": 62 + }, + "abilities": { + "0": "Leaf Guard", + "1": "Oblivious", + "H": "Sweet Veil" + }, + "heightm": 0.7, + "weightkg": 8.2, + "color": "Purple", + "prevo": "bounsweet", + "evos": [ + "tsareena" + ], + "evoLevel": 18, + "eggGroups": [ + "Grass" + ] + }, + "tsareena": { + "num": 763, + "species": "Tsareena", + "types": [ + "Grass" + ], + "gender": "F", + "baseStats": { + "hp": 72, + "atk": 120, + "def": 98, + "spa": 50, + "spd": 98, + "spe": 72 + }, + "abilities": { + "0": "Leaf Guard", + "1": "Queenly Majesty", + "H": "Sweet Veil" + }, + "heightm": 1.2, + "weightkg": 21.4, + "color": "Purple", + "prevo": "steenee", + "evoLevel": 29, + "eggGroups": [ + "Grass" + ] + }, + "comfey": { + "num": 764, + "species": "Comfey", + "types": [ + "Fairy" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 51, + "atk": 52, + "def": 90, + "spa": 82, + "spd": 110, + "spe": 100 + }, + "abilities": { + "0": "Flower Veil", + "1": "Triage", + "H": "Natural Cure" + }, + "heightm": 0.1, + "weightkg": 0.3, + "color": "Green", + "eggGroups": [ + "Grass" + ] + }, + "oranguru": { + "num": 765, + "species": "Oranguru", + "types": [ + "Normal", + "Psychic" + ], + "baseStats": { + "hp": 90, + "atk": 60, + "def": 80, + "spa": 90, + "spd": 110, + "spe": 60 + }, + "abilities": { + "0": "Inner Focus", + "1": "Telepathy", + "H": "Symbiosis" + }, + "heightm": 1.5, + "weightkg": 76, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "passimian": { + "num": 766, + "species": "Passimian", + "types": [ + "Fighting" + ], + "baseStats": { + "hp": 100, + "atk": 120, + "def": 90, + "spa": 40, + "spd": 60, + "spe": 80 + }, + "abilities": { + "0": "Receiver", + "H": "Defiant" + }, + "heightm": 2, + "weightkg": 82.8, + "color": "White", + "eggGroups": [ + "Field" + ] + }, + "wimpod": { + "num": 767, + "species": "Wimpod", + "types": [ + "Bug", + "Water" + ], + "baseStats": { + "hp": 25, + "atk": 35, + "def": 40, + "spa": 20, + "spd": 30, + "spe": 80 + }, + "abilities": { + "0": "Wimp Out" + }, + "heightm": 0.5, + "weightkg": 12, + "color": "Gray", + "evos": [ + "golisopod" + ], + "eggGroups": [ + "Bug", + "Water 3" + ] + }, + "golisopod": { + "num": 768, + "species": "Golisopod", + "types": [ + "Bug", + "Water" + ], + "baseStats": { + "hp": 75, + "atk": 125, + "def": 140, + "spa": 60, + "spd": 90, + "spe": 40 + }, + "abilities": { + "0": "Emergency Exit" + }, + "heightm": 2, + "weightkg": 108, + "color": "Gray", + "prevo": "wimpod", + "evoLevel": 30, + "eggGroups": [ + "Bug", + "Water 3" + ] + }, + "sandygast": { + "num": 769, + "species": "Sandygast", + "types": [ + "Ghost", + "Ground" + ], + "baseStats": { + "hp": 55, + "atk": 55, + "def": 80, + "spa": 70, + "spd": 45, + "spe": 15 + }, + "abilities": { + "0": "Water Compaction", + "H": "Sand Veil" + }, + "heightm": 0.5, + "weightkg": 70, + "color": "Brown", + "evos": [ + "palossand" + ], + "eggGroups": [ + "Amorphous" + ] + }, + "palossand": { + "num": 770, + "species": "Palossand", + "types": [ + "Ghost", + "Ground" + ], + "baseStats": { + "hp": 85, + "atk": 75, + "def": 110, + "spa": 100, + "spd": 75, + "spe": 35 + }, + "abilities": { + "0": "Water Compaction", + "H": "Sand Veil" + }, + "heightm": 1.3, + "weightkg": 250, + "color": "Brown", + "prevo": "sandygast", + "evoLevel": 42, + "eggGroups": [ + "Amorphous" + ] + }, + "pyukumuku": { + "num": 771, + "species": "Pyukumuku", + "types": [ + "Water" + ], + "baseStats": { + "hp": 55, + "atk": 60, + "def": 130, + "spa": 30, + "spd": 130, + "spe": 5 + }, + "abilities": { + "0": "Innards Out", + "H": "Unaware" + }, + "heightm": 0.3, + "weightkg": 1.2, + "color": "Black", + "eggGroups": [ + "Water 1" + ] + }, + "typenull": { + "num": 772, + "species": "Type: Null", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 59 + }, + "abilities": { + "0": "Battle Armor" + }, + "heightm": 1.9, + "weightkg": 120.5, + "color": "Gray", + "evos": [ + "silvally" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "silvally": { + "num": 773, + "species": "Silvally", + "types": [ + "Normal" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 41, + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "silvallybug", + "silvallydark", + "silvallydragon", + "silvallyelectric", + "silvallyfairy", + "silvallyfighting", + "silvallyfire", + "silvallyflying", + "silvallyghost", + "silvallygrass", + "silvallyground", + "silvallyice", + "silvallypoison", + "silvallypsychic", + "silvallyrock", + "silvallysteel", + "silvallywater" + ] + }, + "silvallybug": { + "num": 773, + "species": "Silvally-Bug", + "baseSpecies": "Silvally", + "forme": "Bug", + "formeLetter": "B", + "types": [ + "Bug" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallydark": { + "num": 773, + "species": "Silvally-Dark", + "baseSpecies": "Silvally", + "forme": "Dark", + "formeLetter": "D", + "types": [ + "Dark" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallydragon": { + "num": 773, + "species": "Silvally-Dragon", + "baseSpecies": "Silvally", + "forme": "Dragon", + "formeLetter": "D", + "types": [ + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyelectric": { + "num": 773, + "species": "Silvally-Electric", + "baseSpecies": "Silvally", + "forme": "Electric", + "formeLetter": "E", + "types": [ + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyfairy": { + "num": 773, + "species": "Silvally-Fairy", + "baseSpecies": "Silvally", + "forme": "Fairy", + "formeLetter": "F", + "types": [ + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyfighting": { + "num": 773, + "species": "Silvally-Fighting", + "baseSpecies": "Silvally", + "forme": "Fighting", + "formeLetter": "F", + "types": [ + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyfire": { + "num": 773, + "species": "Silvally-Fire", + "baseSpecies": "Silvally", + "forme": "Fire", + "formeLetter": "F", + "types": [ + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyflying": { + "num": 773, + "species": "Silvally-Flying", + "baseSpecies": "Silvally", + "forme": "Flying", + "formeLetter": "F", + "types": [ + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyghost": { + "num": 773, + "species": "Silvally-Ghost", + "baseSpecies": "Silvally", + "forme": "Ghost", + "formeLetter": "G", + "types": [ + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallygrass": { + "num": 773, + "species": "Silvally-Grass", + "baseSpecies": "Silvally", + "forme": "Grass", + "formeLetter": "G", + "types": [ + "Grass" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyground": { + "num": 773, + "species": "Silvally-Ground", + "baseSpecies": "Silvally", + "forme": "Ground", + "formeLetter": "G", + "types": [ + "Ground" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyice": { + "num": 773, + "species": "Silvally-Ice", + "baseSpecies": "Silvally", + "forme": "Ice", + "formeLetter": "I", + "types": [ + "Ice" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallypoison": { + "num": 773, + "species": "Silvally-Poison", + "baseSpecies": "Silvally", + "forme": "Poison", + "formeLetter": "P", + "types": [ + "Poison" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallypsychic": { + "num": 773, + "species": "Silvally-Psychic", + "baseSpecies": "Silvally", + "forme": "Psychic", + "formeLetter": "P", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallyrock": { + "num": 773, + "species": "Silvally-Rock", + "baseSpecies": "Silvally", + "forme": "Rock", + "formeLetter": "R", + "types": [ + "Rock" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallysteel": { + "num": 773, + "species": "Silvally-Steel", + "baseSpecies": "Silvally", + "forme": "Steel", + "formeLetter": "S", + "types": [ + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "silvallywater": { + "num": 773, + "species": "Silvally-Water", + "baseSpecies": "Silvally", + "forme": "Water", + "formeLetter": "W", + "types": [ + "Water" + ], + "gender": "N", + "baseStats": { + "hp": 95, + "atk": 95, + "def": 95, + "spa": 95, + "spd": 95, + "spe": 95 + }, + "abilities": { + "0": "RKS System" + }, + "heightm": 2.3, + "weightkg": 100.5, + "color": "Gray", + "prevo": "typenull", + "evoLevel": 2, + "eggGroups": [ + "Undiscovered" + ] + }, + "minior": { + "num": 774, + "species": "Minior", + "baseForme": "Red", + "types": [ + "Rock", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 100, + "def": 60, + "spa": 100, + "spd": 60, + "spe": 120 + }, + "abilities": { + "0": "Shields Down" + }, + "heightm": 0.3, + "weightkg": 0.3, + "color": "Red", + "eggGroups": [ + "Mineral" + ], + "otherFormes": [ + "miniormeteor" + ], + "otherForms": [ + "miniororange", + "minioryellow", + "miniorgreen", + "miniorblue", + "miniorindigo", + "miniorviolet" + ] + }, + "miniormeteor": { + "num": 774, + "species": "Minior-Meteor", + "baseSpecies": "Minior", + "forme": "Meteor", + "formeLetter": "M", + "types": [ + "Rock", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 60, + "atk": 60, + "def": 100, + "spa": 60, + "spd": 100, + "spe": 60 + }, + "abilities": { + "0": "Shields Down" + }, + "heightm": 0.3, + "weightkg": 40, + "color": "Brown", + "eggGroups": [ + "Mineral" + ] + }, + "komala": { + "num": 775, + "species": "Komala", + "types": [ + "Normal" + ], + "baseStats": { + "hp": 65, + "atk": 115, + "def": 65, + "spa": 75, + "spd": 95, + "spe": 65 + }, + "abilities": { + "0": "Comatose" + }, + "heightm": 0.4, + "weightkg": 19.9, + "color": "Blue", + "eggGroups": [ + "Field" + ] + }, + "turtonator": { + "num": 776, + "species": "Turtonator", + "types": [ + "Fire", + "Dragon" + ], + "baseStats": { + "hp": 60, + "atk": 78, + "def": 135, + "spa": 91, + "spd": 85, + "spe": 36 + }, + "abilities": { + "0": "Shell Armor" + }, + "heightm": 2, + "weightkg": 212, + "color": "Red", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "togedemaru": { + "num": 777, + "species": "Togedemaru", + "types": [ + "Electric", + "Steel" + ], + "baseStats": { + "hp": 65, + "atk": 98, + "def": 63, + "spa": 40, + "spd": 73, + "spe": 96 + }, + "abilities": { + "0": "Iron Barbs", + "1": "Lightning Rod", + "H": "Sturdy" + }, + "heightm": 0.3, + "weightkg": 3.3, + "color": "Gray", + "eggGroups": [ + "Field", + "Fairy" + ] + }, + "mimikyu": { + "num": 778, + "species": "Mimikyu", + "types": [ + "Ghost", + "Fairy" + ], + "baseStats": { + "hp": 55, + "atk": 90, + "def": 80, + "spa": 50, + "spd": 105, + "spe": 96 + }, + "abilities": { + "0": "Disguise" + }, + "heightm": 0.2, + "weightkg": 0.7, + "color": "Yellow", + "eggGroups": [ + "Amorphous" + ], + "otherFormes": [ + "mimikyubusted" + ] + }, + "mimikyubusted": { + "num": 778, + "species": "Mimikyu-Busted", + "baseSpecies": "Mimikyu", + "forme": "Busted", + "formeLetter": "B", + "types": [ + "Ghost", + "Fairy" + ], + "baseStats": { + "hp": 55, + "atk": 90, + "def": 80, + "spa": 50, + "spd": 105, + "spe": 96 + }, + "abilities": { + "0": "Disguise" + }, + "heightm": 0.2, + "weightkg": 0.7, + "color": "Yellow", + "eggGroups": [ + "Amorphous" + ] + }, + "bruxish": { + "num": 779, + "species": "Bruxish", + "types": [ + "Water", + "Psychic" + ], + "baseStats": { + "hp": 68, + "atk": 105, + "def": 70, + "spa": 70, + "spd": 70, + "spe": 92 + }, + "abilities": { + "0": "Dazzling", + "1": "Strong Jaw", + "H": "Wonder Skin" + }, + "heightm": 0.9, + "weightkg": 19, + "color": "Pink", + "eggGroups": [ + "Water 2" + ] + }, + "drampa": { + "num": 780, + "species": "Drampa", + "types": [ + "Normal", + "Dragon" + ], + "baseStats": { + "hp": 78, + "atk": 60, + "def": 85, + "spa": 135, + "spd": 91, + "spe": 36 + }, + "abilities": { + "0": "Berserk", + "1": "Sap Sipper", + "H": "Cloud Nine" + }, + "heightm": 3, + "weightkg": 185, + "color": "White", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "dhelmise": { + "num": 781, + "species": "Dhelmise", + "types": [ + "Ghost", + "Grass" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 131, + "def": 100, + "spa": 86, + "spd": 90, + "spe": 40 + }, + "abilities": { + "0": "Steelworker" + }, + "heightm": 3.9, + "weightkg": 210, + "color": "Green", + "eggGroups": [ + "Mineral" + ] + }, + "jangmoo": { + "num": 782, + "species": "Jangmo-o", + "types": [ + "Dragon" + ], + "baseStats": { + "hp": 45, + "atk": 55, + "def": 65, + "spa": 45, + "spd": 45, + "spe": 45 + }, + "abilities": { + "0": "Bulletproof", + "1": "Soundproof", + "H": "Overcoat" + }, + "heightm": 0.6, + "weightkg": 29.7, + "color": "Gray", + "evos": [ + "hakamoo" + ], + "eggGroups": [ + "Dragon" + ] + }, + "hakamoo": { + "num": 783, + "species": "Hakamo-o", + "types": [ + "Dragon", + "Fighting" + ], + "baseStats": { + "hp": 55, + "atk": 75, + "def": 90, + "spa": 65, + "spd": 70, + "spe": 65 + }, + "abilities": { + "0": "Bulletproof", + "1": "Soundproof", + "H": "Overcoat" + }, + "heightm": 1.2, + "weightkg": 47, + "color": "Gray", + "prevo": "jangmoo", + "evos": [ + "kommoo" + ], + "evoLevel": 35, + "eggGroups": [ + "Dragon" + ] + }, + "kommoo": { + "num": 784, + "species": "Kommo-o", + "types": [ + "Dragon", + "Fighting" + ], + "baseStats": { + "hp": 75, + "atk": 110, + "def": 125, + "spa": 100, + "spd": 105, + "spe": 85 + }, + "abilities": { + "0": "Bulletproof", + "1": "Soundproof", + "H": "Overcoat" + }, + "heightm": 1.6, + "weightkg": 78.2, + "color": "Gray", + "prevo": "hakamoo", + "evoLevel": 45, + "eggGroups": [ + "Dragon" + ] + }, + "tapukoko": { + "num": 785, + "species": "Tapu Koko", + "types": [ + "Electric", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 115, + "def": 85, + "spa": 95, + "spd": 75, + "spe": 130 + }, + "abilities": { + "0": "Electric Surge", + "H": "Telepathy" + }, + "heightm": 1.8, + "weightkg": 20.5, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "tapulele": { + "num": 786, + "species": "Tapu Lele", + "types": [ + "Psychic", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 85, + "def": 75, + "spa": 130, + "spd": 115, + "spe": 95 + }, + "abilities": { + "0": "Psychic Surge", + "H": "Telepathy" + }, + "heightm": 1.2, + "weightkg": 18.6, + "color": "Pink", + "eggGroups": [ + "Undiscovered" + ] + }, + "tapubulu": { + "num": 787, + "species": "Tapu Bulu", + "types": [ + "Grass", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 130, + "def": 115, + "spa": 85, + "spd": 95, + "spe": 75 + }, + "abilities": { + "0": "Grassy Surge", + "H": "Telepathy" + }, + "heightm": 1.9, + "weightkg": 45.5, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "tapufini": { + "num": 788, + "species": "Tapu Fini", + "types": [ + "Water", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 70, + "atk": 75, + "def": 115, + "spa": 95, + "spd": 130, + "spe": 85 + }, + "abilities": { + "0": "Misty Surge", + "H": "Telepathy" + }, + "heightm": 1.3, + "weightkg": 21.2, + "color": "Purple", + "eggGroups": [ + "Undiscovered" + ] + }, + "cosmog": { + "num": 789, + "species": "Cosmog", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 43, + "atk": 29, + "def": 31, + "spa": 29, + "spd": 31, + "spe": 37 + }, + "abilities": { + "0": "Unaware" + }, + "heightm": 0.2, + "weightkg": 0.1, + "color": "Blue", + "evos": [ + "cosmoem" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "cosmoem": { + "num": 790, + "species": "Cosmoem", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 43, + "atk": 29, + "def": 131, + "spa": 29, + "spd": 131, + "spe": 37 + }, + "abilities": { + "0": "Sturdy" + }, + "heightm": 0.1, + "weightkg": 999.9, + "color": "Blue", + "prevo": "cosmog", + "evos": [ + "solgaleo", + "lunala" + ], + "evoLevel": 43, + "eggGroups": [ + "Undiscovered" + ] + }, + "solgaleo": { + "num": 791, + "species": "Solgaleo", + "types": [ + "Psychic", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 137, + "atk": 137, + "def": 107, + "spa": 113, + "spd": 89, + "spe": 97 + }, + "abilities": { + "0": "Full Metal Body" + }, + "heightm": 3.4, + "weightkg": 230, + "color": "White", + "prevo": "cosmoem", + "evoLevel": 53, + "eggGroups": [ + "Undiscovered" + ] + }, + "lunala": { + "num": 792, + "species": "Lunala", + "types": [ + "Psychic", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 137, + "atk": 113, + "def": 89, + "spa": 137, + "spd": 107, + "spe": 97 + }, + "abilities": { + "0": "Shadow Shield" + }, + "heightm": 4, + "weightkg": 120, + "color": "Purple", + "prevo": "cosmoem", + "evoLevel": 53, + "eggGroups": [ + "Undiscovered" + ] + }, + "nihilego": { + "num": 793, + "species": "Nihilego", + "types": [ + "Rock", + "Poison" + ], + "gender": "N", + "baseStats": { + "hp": 109, + "atk": 53, + "def": 47, + "spa": 127, + "spd": 131, + "spe": 103 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 1.2, + "weightkg": 55.5, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "buzzwole": { + "num": 794, + "species": "Buzzwole", + "types": [ + "Bug", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 107, + "atk": 139, + "def": 139, + "spa": 53, + "spd": 53, + "spe": 79 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 2.4, + "weightkg": 333.6, + "color": "Red", + "eggGroups": [ + "Undiscovered" + ] + }, + "pheromosa": { + "num": 795, + "species": "Pheromosa", + "types": [ + "Bug", + "Fighting" + ], + "gender": "N", + "baseStats": { + "hp": 71, + "atk": 137, + "def": 37, + "spa": 137, + "spd": 37, + "spe": 151 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 1.8, + "weightkg": 25, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "xurkitree": { + "num": 796, + "species": "Xurkitree", + "types": [ + "Electric" + ], + "gender": "N", + "baseStats": { + "hp": 83, + "atk": 89, + "def": 71, + "spa": 173, + "spd": 71, + "spe": 83 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 3.8, + "weightkg": 100, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "celesteela": { + "num": 797, + "species": "Celesteela", + "types": [ + "Steel", + "Flying" + ], + "gender": "N", + "baseStats": { + "hp": 97, + "atk": 101, + "def": 103, + "spa": 107, + "spd": 101, + "spe": 61 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 9.2, + "weightkg": 999.9, + "color": "Green", + "eggGroups": [ + "Undiscovered" + ] + }, + "kartana": { + "num": 798, + "species": "Kartana", + "types": [ + "Grass", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 59, + "atk": 181, + "def": 131, + "spa": 59, + "spd": 31, + "spe": 109 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 0.3, + "weightkg": 0.1, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "guzzlord": { + "num": 799, + "species": "Guzzlord", + "types": [ + "Dark", + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 223, + "atk": 101, + "def": 53, + "spa": 97, + "spd": 53, + "spe": 43 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 5.5, + "weightkg": 888, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "necrozma": { + "num": 800, + "species": "Necrozma", + "types": [ + "Psychic" + ], + "gender": "N", + "baseStats": { + "hp": 97, + "atk": 107, + "def": 101, + "spa": 127, + "spd": 89, + "spe": 79 + }, + "abilities": { + "0": "Prism Armor" + }, + "heightm": 2.4, + "weightkg": 230, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ], + "otherFormes": [ + "necrozmaduskmane", + "necrozmadawnwings", + "necrozmaultra" + ] + }, + "necrozmaduskmane": { + "num": 800, + "species": "Dusk Mane Necrozma", + "baseSpecies": "Necrozma", + "forme": "Dusk Mane", + "formeLetter": "M", + "types": [ + "Psychic", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 97, + "atk": 157, + "def": 127, + "spa": 113, + "spd": 109, + "spe": 77 + }, + "abilities": { + "0": "Prism Armor" + }, + "heightm": 3.8, + "weightkg": 460, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "necrozmadawnwings": { + "num": 800, + "species": "Dawn Wings Necrozma", + "baseSpecies": "Necrozma", + "forme": "Dawn Wings", + "formeLetter": "W", + "types": [ + "Psychic", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 97, + "atk": 113, + "def": 109, + "spa": 157, + "spd": 127, + "spe": 77 + }, + "abilities": { + "0": "Prism Armor" + }, + "heightm": 4.2, + "weightkg": 350, + "color": "Black", + "eggGroups": [ + "Undiscovered" + ] + }, + "necrozmaultra": { + "num": 800, + "species": "Ultra Necrozma", + "baseSpecies": "Necrozma", + "forme": "Ultra", + "formeLetter": "U", + "types": [ + "Psychic", + "Dragon" + ], + "gender": "N", + "baseStats": { + "hp": 97, + "atk": 167, + "def": 97, + "spa": 167, + "spd": 97, + "spe": 129 + }, + "abilities": { + "0": "Neuroforce" + }, + "heightm": 7.5, + "weightkg": 230, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "magearna": { + "num": 801, + "species": "Magearna", + "types": [ + "Steel", + "Fairy" + ], + "gender": "N", + "baseStats": { + "hp": 80, + "atk": 95, + "def": 115, + "spa": 130, + "spd": 115, + "spe": 65 + }, + "abilities": { + "0": "Soul-Heart" + }, + "heightm": 1, + "weightkg": 80.5, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ], + "otherForms": [ + "magearnaoriginal" + ] + }, + "marshadow": { + "num": 802, + "species": "Marshadow", + "types": [ + "Fighting", + "Ghost" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 125, + "def": 80, + "spa": 90, + "spd": 90, + "spe": 125 + }, + "abilities": { + "0": "Technician" + }, + "heightm": 0.7, + "weightkg": 22.2, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "poipole": { + "num": 803, + "species": "Poipole", + "types": [ + "Dragon", + "Poison" + ], + "gender": "N", + "baseStats": { + "hp": 67, + "atk": 73, + "def": 67, + "spa": 73, + "spd": 67, + "spe": 73 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 0.6, + "weightkg": 1.8, + "color": "Purple", + "evos": [ + "Naganadel" + ], + "eggGroups": [ + "Undiscovered" + ] + }, + "naganadel": { + "num": 804, + "species": "Naganadel", + "types": [ + "Dragon", + "Poison" + ], + "gender": "N", + "baseStats": { + "hp": 73, + "atk": 73, + "def": 73, + "spa": 127, + "spd": 73, + "spe": 121 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 3.6, + "weightkg": 150, + "color": "Purple", + "prevo": "Poipole", + "evoLevel": 2, + "evoMove": "Dragon Pulse", + "eggGroups": [ + "Undiscovered" + ] + }, + "stakataka": { + "num": 805, + "species": "Stakataka", + "types": [ + "Rock", + "Steel" + ], + "gender": "N", + "baseStats": { + "hp": 61, + "atk": 131, + "def": 211, + "spa": 53, + "spd": 101, + "spe": 13 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 5.5, + "weightkg": 820.0, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "blacephalon": { + "num": 806, + "species": "Blacephalon", + "types": [ + "Ghost", + "Fire" + ], + "gender": "N", + "baseStats": { + "hp": 53, + "atk": 127, + "def": 53, + "spa": 151, + "spd": 79, + "spe": 107 + }, + "abilities": { + "0": "Beast Boost" + }, + "heightm": 1.8, + "weightkg": 13.0, + "color": "White", + "eggGroups": [ + "Undiscovered" + ] + }, + "zeraora": { + "num": 807, + "species": "Zeraora", + "types": [ + "Electric", + ], + "gender": "N", + "baseStats": { + "hp": 88, + "atk": 112, + "def": 75, + "spa": 102, + "spd": 80, + "spe": 143 + }, + "abilities": { + "0": "Volt Absorb" + }, + "heightm": 1.5, + "weightkg": 44.5, + "color": "Yellow", + "eggGroups": [ + "Undiscovered" + ] + }, + "missingno": { + "num": 0, + "species": "Missingno.", + "types": [ + "Bird", + "Normal" + ], + "baseStats": { + "hp": 33, + "atk": 136, + "def": 0, + "spa": 6, + "spd": 6, + "spe": 29 + }, + "abilities": { + "0": "" + }, + "heightm": 3, + "weightkg": 1590.8, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "tomohawk": { + "num": -1, + "species": "Tomohawk", + "types": [ + "Flying", + "Fighting" + ], + "baseStats": { + "hp": 105, + "atk": 60, + "def": 90, + "spa": 115, + "spd": 80, + "spe": 85 + }, + "abilities": { + "0": "Intimidate", + "1": "Prankster", + "H": "Justified" + }, + "heightm": 1.27, + "weightkg": 37.2, + "color": "Red", + "eggGroups": [ + "Field", + "Flying" + ] + }, + "necturna": { + "num": -2, + "species": "Necturna", + "types": [ + "Grass", + "Ghost" + ], + "gender": "F", + "baseStats": { + "hp": 64, + "atk": 120, + "def": 100, + "spa": 85, + "spd": 120, + "spe": 81 + }, + "abilities": { + "0": "Forewarn", + "H": "Telepathy" + }, + "heightm": 1.65, + "weightkg": 49.6, + "color": "Black", + "eggGroups": [ + "Grass", + "Field" + ] + }, + "mollux": { + "num": -3, + "species": "Mollux", + "types": [ + "Fire", + "Poison" + ], + "baseStats": { + "hp": 95, + "atk": 45, + "def": 83, + "spa": 131, + "spd": 105, + "spe": 76 + }, + "abilities": { + "0": "Dry Skin", + "H": "Illuminate" + }, + "heightm": 1.2, + "weightkg": 41, + "color": "Pink", + "eggGroups": [ + "Fairy", + "Field" + ] + }, + "aurumoth": { + "num": -4, + "species": "Aurumoth", + "types": [ + "Bug", + "Psychic" + ], + "baseStats": { + "hp": 110, + "atk": 120, + "def": 99, + "spa": 117, + "spd": 60, + "spe": 94 + }, + "abilities": { + "0": "Weak Armor", + "1": "No Guard", + "H": "Illusion" + }, + "heightm": 2.1, + "weightkg": 193, + "color": "Purple", + "eggGroups": [ + "Bug" + ] + }, + "malaconda": { + "num": -5, + "species": "Malaconda", + "types": [ + "Dark", + "Grass" + ], + "baseStats": { + "hp": 115, + "atk": 100, + "def": 60, + "spa": 40, + "spd": 130, + "spe": 55 + }, + "abilities": { + "0": "Harvest", + "1": "Infiltrator" + }, + "heightm": 5.5, + "weightkg": 108.8, + "color": "Brown", + "eggGroups": [ + "Grass", + "Dragon" + ] + }, + "cawmodore": { + "num": -6, + "species": "Cawmodore", + "types": [ + "Steel", + "Flying" + ], + "baseStats": { + "hp": 50, + "atk": 92, + "def": 130, + "spa": 65, + "spd": 75, + "spe": 118 + }, + "abilities": { + "0": "Intimidate", + "1": "Volt Absorb", + "H": "Big Pecks" + }, + "heightm": 1.7, + "weightkg": 37, + "color": "Black", + "eggGroups": [ + "Flying" + ] + }, + "volkraken": { + "num": -7, + "species": "Volkraken", + "types": [ + "Water", + "Fire" + ], + "baseStats": { + "hp": 100, + "atk": 45, + "def": 80, + "spa": 135, + "spd": 100, + "spe": 95 + }, + "abilities": { + "0": "Analytic", + "1": "Infiltrator", + "H": "Pressure" + }, + "heightm": 1.3, + "weightkg": 44.5, + "color": "Red", + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "plasmanta": { + "num": -8, + "species": "Plasmanta", + "types": [ + "Electric", + "Poison" + ], + "baseStats": { + "hp": 60, + "atk": 57, + "def": 119, + "spa": 131, + "spd": 98, + "spe": 100 + }, + "abilities": { + "0": "Storm Drain", + "1": "Vital Spirit", + "H": "Telepathy" + }, + "heightm": 7, + "weightkg": 460, + "color": "Purple", + "eggGroups": [ + "Water 1", + "Water 2" + ] + }, + "naviathan": { + "num": -9, + "species": "Naviathan", + "types": [ + "Water", + "Steel" + ], + "baseStats": { + "hp": 103, + "atk": 110, + "def": 90, + "spa": 95, + "spd": 65, + "spe": 97 + }, + "abilities": { + "0": "Water Veil", + "1": "Heatproof", + "H": "Light Metal" + }, + "heightm": 3, + "weightkg": 510, + "color": "Gray", + "eggGroups": [ + "Water 1", + "Field" + ] + }, + "crucibelle": { + "num": -10, + "species": "Crucibelle", + "types": [ + "Rock", + "Poison" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 106, + "atk": 105, + "def": 65, + "spa": 75, + "spd": 85, + "spe": 104 + }, + "abilities": { + "0": "Regenerator", + "1": "Mold Breaker", + "H": "Liquid Ooze" + }, + "heightm": 1.3, + "weightkg": 23.6, + "color": "Purple", + "eggGroups": [ + "Amorphous", + "Mineral" + ], + "otherFormes": [ + "crucibellemega" + ] + }, + "crucibellemega": { + "num": -10, + "species": "Crucibelle-Mega", + "baseSpecies": "Crucibelle", + "forme": "Mega", + "formeLetter": "M", + "types": [ + "Rock", + "Poison" + ], + "genderRatio": { + "M": 0.25, + "F": 0.75 + }, + "baseStats": { + "hp": 106, + "atk": 135, + "def": 75, + "spa": 85, + "spd": 125, + "spe": 114 + }, + "abilities": { + "0": "Magic Guard" + }, + "heightm": 1.4, + "weightkg": 22.5, + "color": "Purple", + "eggGroups": [ + "Amorphous", + "Mineral" + ] + }, + "kerfluffle": { + "num": -11, + "species": "Kerfluffle", + "types": [ + "Fairy", + "Fighting" + ], + "baseStats": { + "hp": 84, + "atk": 78, + "def": 86, + "spa": 115, + "spd": 88, + "spe": 119 + }, + "abilities": { + "0": "Natural Cure", + "1": "Aroma Veil", + "H": "Friend Guard" + }, + "heightm": 2.1, + "weightkg": 24.2, + "color": "Pink", + "eggGroups": [ + "Fairy", + "Human-Like" + ] + }, + "syclant": { + "num": -51, + "species": "Syclant", + "types": [ + "Ice", + "Bug" + ], + "baseStats": { + "hp": 70, + "atk": 116, + "def": 70, + "spa": 114, + "spd": 64, + "spe": 121 + }, + "abilities": { + "0": "Compound Eyes", + "1": "Mountaineer" + }, + "heightm": 1.7, + "weightkg": 52, + "color": "Blue", + "eggGroups": [ + "Bug" + ] + }, + "revenankh": { + "num": -52, + "species": "Revenankh", + "types": [ + "Ghost", + "Fighting" + ], + "baseStats": { + "hp": 90, + "atk": 105, + "def": 90, + "spa": 65, + "spd": 110, + "spe": 65 + }, + "abilities": { + "0": "Shed Skin", + "1": "Air Lock" + }, + "heightm": 1.8, + "weightkg": 44, + "color": "White", + "eggGroups": [ + "Amorphous", + "Human-Like" + ] + }, + "pyroak": { + "num": -53, + "species": "Pyroak", + "types": [ + "Fire", + "Grass" + ], + "baseStats": { + "hp": 120, + "atk": 70, + "def": 105, + "spa": 95, + "spd": 90, + "spe": 60 + }, + "abilities": { + "0": "Rock Head", + "1": "Battle Armor" + }, + "heightm": 2.1, + "weightkg": 168, + "color": "Brown", + "eggGroups": [ + "Monster", + "Dragon" + ] + }, + "fidgit": { + "num": -54, + "species": "Fidgit", + "types": [ + "Poison", + "Ground" + ], + "baseStats": { + "hp": 95, + "atk": 76, + "def": 109, + "spa": 90, + "spd": 80, + "spe": 105 + }, + "abilities": { + "0": "Persistent", + "1": "Vital Spirit" + }, + "heightm": 0.9, + "weightkg": 53, + "color": "Purple", + "eggGroups": [ + "Field" + ] + }, + "stratagem": { + "num": -55, + "species": "Stratagem", + "types": [ + "Rock" + ], + "gender": "N", + "baseStats": { + "hp": 90, + "atk": 60, + "def": 65, + "spa": 120, + "spd": 70, + "spe": 130 + }, + "abilities": { + "0": "Levitate", + "1": "Technician" + }, + "heightm": 0.9, + "weightkg": 45, + "color": "Gray", + "eggGroups": [ + "Undiscovered" + ] + }, + "arghonaut": { + "num": -56, + "species": "Arghonaut", + "types": [ + "Water", + "Fighting" + ], + "baseStats": { + "hp": 105, + "atk": 110, + "def": 95, + "spa": 70, + "spd": 100, + "spe": 75 + }, + "abilities": { + "0": "Unaware" + }, + "heightm": 1.7, + "weightkg": 151, + "color": "Green", + "eggGroups": [ + "Water 1", + "Water 3" + ] + }, + "kitsunoh": { + "num": -57, + "species": "Kitsunoh", + "types": [ + "Steel", + "Ghost" + ], + "baseStats": { + "hp": 80, + "atk": 103, + "def": 85, + "spa": 55, + "spd": 80, + "spe": 110 + }, + "abilities": { + "0": "Frisk", + "1": "Limber" + }, + "heightm": 1.1, + "weightkg": 51, + "color": "Gray", + "eggGroups": [ + "Field" + ] + }, + "cyclohm": { + "num": -58, + "species": "Cyclohm", + "types": [ + "Electric", + "Dragon" + ], + "baseStats": { + "hp": 108, + "atk": 60, + "def": 118, + "spa": 112, + "spd": 70, + "spe": 80 + }, + "abilities": { + "0": "Shield Dust", + "1": "Static" + }, + "heightm": 1.6, + "weightkg": 59, + "color": "Yellow", + "eggGroups": [ + "Dragon", + "Monster" + ] + }, + "colossoil": { + "num": -59, + "species": "Colossoil", + "types": [ + "Dark", + "Ground" + ], + "baseStats": { + "hp": 133, + "atk": 122, + "def": 72, + "spa": 71, + "spd": 72, + "spe": 95 + }, + "abilities": { + "0": "Rebound", + "1": "Guts" + }, + "heightm": 2.6, + "weightkg": 683.6, + "color": "Brown", + "eggGroups": [ + "Water 2", + "Field" + ] + }, + "krilowatt": { + "num": -60, + "species": "Krilowatt", + "types": [ + "Electric", + "Water" + ], + "baseStats": { + "hp": 151, + "atk": 84, + "def": 73, + "spa": 83, + "spd": 74, + "spe": 105 + }, + "abilities": { + "0": "Trace", + "1": "Magic Guard" + }, + "heightm": 0.7, + "weightkg": 10.6, + "color": "Red", + "eggGroups": [ + "Water 1", + "Fairy" + ] + }, + "voodoom": { + "num": -61, + "species": "Voodoom", + "types": [ + "Fighting", + "Dark" + ], + "baseStats": { + "hp": 90, + "atk": 85, + "def": 80, + "spa": 105, + "spd": 80, + "spe": 110 + }, + "abilities": { + "0": "Volt Absorb", + "1": "Lightning Rod" + }, + "heightm": 2, + "weightkg": 75.5, + "color": "Brown", + "eggGroups": [ + "Human-Like", + "Ground" + ] + } +} \ No newline at end of file diff --git a/src/EllieBot/data/searches.yml b/src/EllieBot/data/searches.yml new file mode 100644 index 0000000..a4a2309 --- /dev/null +++ b/src/EllieBot/data/searches.yml @@ -0,0 +1,47 @@ +# DO NOT CHANGE +version: 2 +# Which engine should .search command +# 'google_scrape' - default. Scrapes the webpage for results. May break. Requires no api keys. +# 'google' - official google api. Requires googleApiKey and google.searchId set in creds.yml +# 'searx' - requires at least one searx instance specified in the 'searxInstances' property below +webSearchEngine: Google_Scrape +# Which engine should .image command use +# 'google'- official google api. googleApiKey and google.imageSearchId set in creds.yml +# 'searx' requires at least one searx instance specified in the 'searxInstances' property below +imgSearchEngine: Google +# Which search provider will be used for the `.youtube` command. +# +# - `ytDataApiv3` - uses google's official youtube data api. Requires `GoogleApiKey` set in creds and youtube data api enabled in developers console +# +# - `ytdl` - default, uses youtube-dl. Requires `youtube-dl` to be installed and it's path added to env variables. Slow. +# +# - `ytdlp` - recommended easy, uses `yt-dlp`. Requires `yt-dlp` to be installed and it's path added to env variables +# +# - `invidious` - recommended advanced, uses invidious api. Requires at least one invidious instance specified in the `invidiousInstances` property +ytProvider: Ytdlp +# Set the searx instance urls in case you want to use 'searx' for either img or web search. +# Nadeko will use a random one for each request. +# Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com` +# Instances specified must support 'format=json' query parameter. +# - In case you're running your own searx instance, set +# +# search: +# formats: +# - json +# +# in 'searxng/settings.yml' on your server +# +# - If you're using a public instance, make sure that the instance you're using supports it (they usually don't) +searxInstances: [] +# Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search +# Nadeko will use a random one for each request. +# These instances may be used for music queue functionality in the future. +# Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com +# +# Instances specified must have api available. +# You check that by opening an api endpoint in your browser. For example: https://my-invidious-instance.mydomain.com/api/v1/trending +invidiousInstances: [] +# Maximum number of followed streams per server +followedStreams: + # Maximum number of streams that each server can follow. -1 for infinite + maxCount: 10 diff --git a/src/EllieBot/data/strings/commands/commands.en-US.yml b/src/EllieBot/data/strings/commands/commands.en-US.yml new file mode 100644 index 0000000..4b1996d --- /dev/null +++ b/src/EllieBot/data/strings/commands/commands.en-US.yml @@ -0,0 +1,2371 @@ +h: + desc: "Either shows a help for a single command, or DMs you help link if no parameters are specified." + args: + - "{0}cmds" + - "" +gencmdlist: + desc: "Generates the command list and sends it to the chat. Optionally also uploads it to DO spaces (not supported)." + args: + - "" +donate: + desc: "Instructions for helping the project financially." + args: + - "" +modules: + desc: "Lists all bot modules." + args: + - "" +commands: + desc: "List all of the bot's commands from the specified module. You can either specify the full name or only the first few letters of the module name. Specifying no module will show the list of modules instead." + args: + - "Admin" + - "Admin --view 1" + - "" +greetdel: + desc: "Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion." + args: + - "0" + - "30" +greet: + desc: "Toggles announcements on the current channel when someone joins the server." + args: + - "" +greetmsg: + desc: |- + Sets a new join announcement message which will be shown in the server's channel. + Type `%user.mention%` if you want to mention the new member. + Full list of placeholders can be found here + Using it with no message will show the current greet message. + You can use embed json from instead of a regular text, if you want the message to be embedded. + args: + - "Welcome, %user.mention%." +bye: + desc: "Toggles announcements on the current channel when someone leaves the server." + args: + - "" +byemsg: + desc: |- + Sets a new leave announcement message. + Type `%user.mention%` if you want to show the name the user who left. + Full list of placeholders can be found here + Using this command with no message will show the current bye message. + You can use embed json from instead of a regular text, if you want the message to be embedded. + args: + - "%user.mention% has left." +byedel: + desc: "Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion." + args: + - "0" + - "30" +greetdm: + desc: "Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled)." + args: + - "" +greettest: + desc: "Sends the greet message in the current channel as if you just joined the server. You can optionally specify a different user." + args: + - "" + - "@SomeoneElse" +greetdmtest: + desc: "Sends the greet direct message to you as if you just joined the server. You can optionally specify a different user." + args: + - "" + - "@SomeoneElse" +byetest: + desc: "Sends the bye message in the current channel as if you just left the server. You can optionally specify a different user." + args: + - "" + - "@SomeoneElse" +boost: + desc: "Toggles announcements on the current channel when someone boosts the server." + args: + - "" +boostmsg: + desc: |- + Sets a new boost announcement message. + Type `%user.mention%` if you want to show the name the user who left. + Full list of placeholders can be found here + Using this command with no message will show the current boost message. + You can use embed json from instead of a regular text, if you want the message to be embedded. + args: + - "%user.mention% has boosted the server!!!" +boostdel: + desc: "Sets the time it takes (in seconds) for boost messages to be auto-deleted. Set it to `0` to disable automatic deletion." + args: + - "0" + - "30" +logserver: + desc: "Enables or Disables ALL log events. If enabled, all log events will log to this channel." + args: + - "enable" + - "disable" +logignore: + desc: "Toggles whether the `{0}logserver` command ignores the specified channel or user. Provide no arguments to see the list of currently ignored users and channels" + args: + - "" + - "@SomeUser" + - "#some-channel" +repeatlist: + desc: "Shows currently repeating messages and their indexes." + args: + - "" +repeatremove: + desc: "Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes." + args: + - "2" +repeatinvoke: + desc: "Immediately shows the repeat message on a certain index and restarts its timer." + args: + - "1" +repeat: + desc: "Repeat a message once every specified amount of time in the current channel. You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). If you've specified time of day, you can still override the default daily interval with your own interval. You can have up to 5 repeating messages on the server in total." + args: + - "Hello there" + - "1h5m Hello @erryone" + - "10:00 Daily have a nice day! This will execute once every 24h." + - "21:00 30m Starting at 21 and every 30 minutes after that i will send this message!" +repeatredundant: + desc: "Specify repeater's index (use `{0}repli` to find it) to toggle whether that repeater's message should be reposted if the last message in the channel is the same repeater's message. This is useful if you want to remind everyone to be nice in the channel every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone." + args: + - "1" +repeatskip: + desc: "Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. This setting is not stored in the database and will get reset if the bot is restarted." + args: + - "3" +rotateplaying: + desc: "Toggles rotation of playing status of the dynamic strings you previously specified." + args: + - "" +addplaying: + desc: "Adds a specified string to the list of playing strings to rotate. You have to pick either 'Playing', 'Watching' or 'Listening' as the first parameter." + args: + - "Playing with you" + - "Watching you sleep" +listplaying: + desc: "Lists all playing statuses with their corresponding number." + args: + - "" +removeplaying: + desc: "Removes a playing string on a given number." + args: + - "" +vcrolelist: + desc: "Shows a list of currently set voice channel roles." + args: + - "" +vcrole: + desc: "Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command." + args: + - "SomeRole" + - "" +vcrolerm: + desc: "Removes vcrole associated with the specified voice channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted." + args: + - "123123123123123" +asar: + desc: "Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled, users will be able to pick one role per group." + args: + - "Gamer" + - "1 Alliance" + - "1 Horde" +rsar: + desc: "Removes a specified role from the list of self-assignable roles." + args: + - "Gamer" + - "Alliance" + - "Horde" +lsar: + desc: "Lists self-assignable roles. Shows 20 roles per page." + args: + - "" + - "2" +sargn: + desc: "Sets a self assignable role group name. Provide no name to remove." + args: + - "1 Faction" + - "2" +togglexclsar: + desc: "Toggles whether the self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group." + args: + - "" +iam: + desc: "Adds a role to you that you choose. Role must be on a list of self-assignable roles." + args: + - "Gamer" +iamnot: + desc: "Removes a specified role from you. Role must be on a list of self-assignable roles." + args: + - "Gamer" +expradd: + desc: "Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide here: " + args: + - '"hello" Hi there %user.mention%' +expraddserver: + desc: "Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. Guide here: " + args: + - '"hello" Hi there %user.mention%' +exprlist: + desc: |- + Lists global or server expressions (20 commands per page). + Running the command in DM will list global expressions, while running it in a server will list server expressions. + Shows enabled settings, followed by id, followed by the trigger. + **Settings:** + • 🗯️ Triggered if trigger matches any word (`{0}h {0}exca`) + • ✉️ Response will be DMed (`{0}h {0}exdm`) + • ❌ Trigger will be deleted (`{0}h {0}exad`) + args: + - "1" + - "all" +exprshow: + desc: "Shows an expression's response on a given ID." + args: + - "1" +exprdelete: + desc: "Deletes an expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression." + args: + - "5" +exprdeleteserver: + desc: "Deletes an expression on a specific index on this server." + args: + - "5c" +exprclear: + desc: "Deletes all expression on this server." + args: + - "" +fwclear: + desc: "Deletes all filtered words on this server." + args: + - "" +filterlist: + desc: "Lists invite and link filter channels and status." + args: + - "" +aliasesclear: + desc: "Deletes all aliases on this server." + args: + - "" +autoassignrole: + desc: |- + Toggles the role which will be assigned to every user who joins the server. + You can run this command multiple times to add multiple roles (up to 3). + Specifying the role that is already added will remove that role from the list. + Provide no parameters to list current roles. + args: + - "" + - "RoleName" +leave: + desc: "Makes Nadeko leave the server. Either server name or server ID is required." + args: + - "123123123331" +slowmode: + desc: "Toggles slowmode on the current channel with the specified amount of time. Provide no parameters to disable." + args: + - "" + - "27s" + - "3h15m5s" +delmsgoncmd: + desc: "Toggles the automatic deletion of the user's successful command message to prevent chat flood. You can use it either as a server toggle, channel whitelist, or channel blacklist, as channel option has 3 settings: Enable (always do it on this channel), Disable (never do it on this channel), and Inherit (respect server setting). Use `list` parameter to see the current states." + args: + - "" + - "channel enable" + - "ch inherit" + - "list" +restart: + desc: "Restarts the bot. Might not work." + args: + - "" +setrole: + desc: "Gives a role to a user. The role you specify has to be lower in the role hierarchy than your highest role." + args: + - "@User Guest" +removerole: + desc: "Removes a role from a user. The role you specify has to be lower in the role hierarchy than your highest role." + args: + - "@User Admin" +renamerole: + desc: "Renames a role. The role you specify has to be lower in the role hierarchy than your highest role." + args: + - '"First role" SecondRole' +removeallroles: + desc: "Removes all roles which are lower than your highest role in the role hierarchy from the user you specify." + args: + - "@User" +rolehoist: + desc: "Toggles whether this role is displayed in the sidebar or not. The role you specify has to be lower in the role hierarchy than your highest role." + args: + - "Guests" + - "Space Wizards" +createrole: + desc: "Creates a role with a given name." + args: + - "Awesome Role" +deleterole: + desc: "Deletes a role with a given name." + args: + - "Awesome Role" +rolecolor: + desc: "Set a role's color using its hex value. Provide no color in order to see the hex value of the color of the specified role. The role you specify has to be lower in the role hierarchy than your highest role." + args: + - "Admin" + - "ffba55 Admin" +ban: + desc: "Bans a user by ID or name with an optional message. You can specify a time string before the user name to ban the user temporarily." + args: + - "@Someone Get out!" + - '"Some Guy#1234" Your behaviour is toxic.' + - "1d12h @Someone Come back when u chill" +softban: + desc: "Bans and then unbans a user by ID or name with an optional message." + args: + - "@Someone Get out!" + - '"Some Guy#1234" Your behaviour is toxic.' +kick: + desc: "Kicks a mentioned user." + args: + - "@Someone Get out!" + - '"Some Guy#1234" Your behaviour is toxic.' +timeout: + desc: "Times the user out for the specified amount of time. You may optionally specify a reason, which will be sent to the user." + args: + - "@Someone 3h Shut up!" + - "@Someone 1h30m" +mute: + desc: "Mutes a mentioned user both from speaking and chatting. You can also specify time string for how long the user should be muted. You can optionally specify a reason." + args: + - "@Someone" + - "@Someone too noisy" + - "1h30m @Someone" + - "1h30m @Someone too noisy" +voiceunmute: + desc: "Gives a previously voice-muted user a permission to speak." + args: + - "@Someguy" +deafen: + desc: "Deafens mentioned user or users." + args: + - '"@Someguy"' + - '"@Someguy" "@Someguy"' +undeafen: + desc: "Undeafens mentioned user or users." + args: + - '"@Someguy"' + - '"@Someguy" "@Someguy"' +delvoichanl: + desc: "Deletes a voice channel with a given name." + args: + - "VoiceChannelName" +creatvoichanl: + desc: "Creates a new voice channel with a given name." + args: + - "VoiceChannelName" +deltxtchanl: + desc: "Deletes a text channel with a given name." + args: + - "TextChannelName" +creatxtchanl: + desc: "Creates a new text channel with a given name." + args: + - "TextChannelName" +settopic: + desc: "Sets a topic on the current channel." + args: + - "My new topic" +setchanlname: + desc: "Changes the name of the current channel." + args: + - "NewName" +prune: + desc: "`{0}prune` removes all Nadeko's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel." + args: + - "" + - "-s" + - "5" + - "5 --safe" + - "@Someone" + - "@Someone --safe" + - "@Someone X" + - "@Someone X -s" +die: + desc: "Shuts the bot down." + args: + - "" +setname: + desc: "Gives the bot a new name." + args: + - "BotName" +setnick: + desc: "Changes the nickname of the bot on this server. You can also target other users to change their nickname." + args: + - "BotNickname" + - "@SomeUser New Nickname" +setavatar: + desc: "Sets a new avatar image for the NadekoBot. Parameter is a direct link to an image." + args: + - "https://i.imgur.com/xTG3a1I.jpg" +setgame: + desc: "Sets the bots game status to either Playing, Listening, or Watching." + args: + - "Playing with snakes." + - "Watching anime." + - "Listening music." +send: + desc: "Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`." + args: + - "serverid|c:channelid message" + - "serverid|u:userid message" +savechat: + desc: "Saves a number of messages to a text file and sends it to you." + args: + - "150" +remind: + desc: "Sends a message to you or a channel after certain amount of time (max 2 months). First parameter is `me`/`here`/'channelname'. Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third parameter is a (multiword) message. Requires ManageMessages server permission if you're targeting a different channel." + args: + - "me 1d5h Do something" + - "#general 1m Start now!" +reminddelete: + desc: "Deletes a reminder on the specified index. You can specify 'server' option if you're an Administrator, and you want to delete a reminder on this server created by someone else. " + args: + - "3" + - "server 2" +remindlist: + desc: "Lists all reminders you created. You can specify 'server' option if you're an Administrator to list all reminders created on this server. Paginated." + args: + - "1" + - "server 2" +serverinfo: + desc: "Shows info about the server the bot is on. If no server is supplied, it defaults to current one." + args: + - "Some Server" +channelinfo: + desc: "Shows info about the channel. If no channel is supplied, it defaults to current one." + args: + - "#some-channel" +roleinfo: + desc: "Shows info about the specified role." + args: + - "Gamers" +userinfo: + desc: "Shows info about the user. If no user is supplied, it defaults a user running the command." + args: + - "@SomeUser" +whosplaying: + desc: "Shows a list of users who are playing the specified game." + args: + - "Overwatch" +inrole: + desc: "Lists every person from the specified role on this server. You can specify a page before the role to jump to that page. Provide no role to list users who have no roles" + args: + - "RoleName" + - "5 RoleName" + - "" +checkperms: + desc: "Checks yours or bot's user-specific permissions on this channel." + args: + - "me" + - "bot" +stats: + desc: "Shows some basic stats for Nadeko." + args: + - "" +userid: + desc: "Shows user ID." + args: + - "" + - "@Someone" +channelid: + desc: "Shows current channel ID." + args: + - "" +serverid: + desc: "Shows current server ID." + args: + - "" +roles: + desc: "List roles on this server or roles of a user if specified. Paginated, 20 roles per page." + args: + - "2" + - "@Someone" +channeltopic: + desc: "Sends current channel's topic as a message." + args: + - "" +chnlfilterinv: + desc: "Toggles automatic deletion of invites posted in the channel. Does not negate the `{0}srvrfilterinv` enabled setting. Does not affect users with the Administrator permission." + args: + - "" +srvrfilterinv: + desc: "Toggles automatic deletion of invites posted in the server. Does not affect users with the Administrator permission." + args: + - "" +chnlfilterlin: + desc: "Toggles automatic deletion of links posted in the channel. Does not negate the `{0}srvrfilterlin` enabled setting. Does not affect users with the Administrator permission." + args: + - "" +srvrfilterlin: + desc: "Toggles automatic deletion of links posted in the server. Does not affect users with the Administrator permission." + args: + - "" +chnlfilterwords: + desc: "Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `{0}srvrfilterwords` enabled setting. Does not affect users with the Administrator permission." + args: + - "" +filterword: + desc: "Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering." + args: + - "poop" +srvrfilterwords: + desc: "Toggles automatic deletion of messages containing filtered words on the server. Does not affect users with the Administrator permission." + args: + - "" +lstfilterwords: + desc: "Shows a list of filtered words." + args: + - "" +permrole: + desc: "Sets a role which can change permissions. Supply no parameters to see the current one. Type 'reset' instead of the role name to reset the currently set permission role. Users with the Administrator server permissions can use permission commands regardless of whether they have the specified role. There is no default permission role." + args: + - "Some Role" + - "reset" +verbose: + desc: "Toggles or sets whether to show when a command/module is blocked." + args: + - "" + - "true" +srvrmdl: + desc: "Sets a module's permission at the server level." + args: + - "ModuleName enable" +srvrcmd: + desc: "Sets a command's permission at the server level." + args: + - '"command name" disable' +rolemdl: + desc: "Sets a module's permission at the role level." + args: + - "ModuleName enable MyRole" +rolecmd: + desc: "Sets a command's permission at the role level." + args: + - '"command name" disable MyRole' +chnlmdl: + desc: "Sets a module's permission at the channel level." + args: + - "ModuleName enable SomeChannel" +chnlcmd: + desc: "Sets a command's permission at the channel level." + args: + - '"command name" enable SomeChannel' +usrmdl: + desc: "Sets a module's permission at the user level." + args: + - "ModuleName enable SomeUsername" +usrcmd: + desc: "Sets a command's permission at the user level." + args: + - '"command name" enable SomeUsername' +allsrvrmdls: + desc: "Enable or disable all modules for your server." + args: + - "[enable/disable]" +allchnlmdls: + desc: "Enable or disable all modules in a specified channel." + args: + - "enable #SomeChannel" +allrolemdls: + desc: "Enable or disable all modules for a specific role." + args: + - "[enable/disable] MyRole" +userblacklist: + desc: |- + Either [add]s or [rem]oves a user or users specified by a Mention or an ID from a blacklist. + Specify no argument or a page number to list blacklisted users. + args: + - "add @SomeUser @SomeUser2 @SomeUser3" + - "rem 12312312313" + - "" + - "4" +channelblacklist: + desc: |- + Either [add]s or [rem]oves a channel or channels specified an ID from a blacklist. + Specify no argument or a page number to list blacklisted channels. + args: + - "add 12312312312 66666666666" + - "rem 12312312312" + - "" + - "3" +serverblacklist: + desc: |- + Either [add]s or [rem]oves a server, or servers specified by an ID from a blacklist. + Specify no argument or a page number to list blacklisted servers. + args: + - "add 12312321312" + - "rem 12312321312" + - "" + - "2" +cmdcooldown: + desc: + "Sets a cooldown, in seconds, for a command or an expression which will be applied per user. + Set it to 0 to remove the cooldown. + Supports a special command `cleverbot:response` which can be used limit how often users can talk to cleverbot" + args: + - ".h 5" + - ".pat 30" +allcmdcooldowns: + desc: "Shows a list of all commands and their respective cooldowns." + args: + - "" +quoteadd: + desc: "Adds a new quote with the specified name and message." + args: + - "sayhi Hi" +quoteprint: + desc: "Prints a random quote with a specified name." + args: + - "abc" +quoteshow: + desc: "Shows information about a quote with the specified ID." + args: + - "123" +quotesearch: + desc: "Shows a random quote given a search query. Partially matches in several ways: 1) Only content of any quote, 2) only by author, 3) keyword and content, 3) or keyword and author" + args: + - '"find this long text"' + - "AuthorName" + - "keyword some text" + - "keyword AuthorName" +quoteid: + desc: "Displays the quote with the specified ID number. Quote ID numbers can be found by typing `{0}liqu [num]` where `[num]` is a number of a page which contains 15 quotes." + args: + - "123456" +quotedelete: + desc: "Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it." + args: + - "123456" +quotedeleteauthor: + desc: "Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required." + args: + - "@QuoteSpammer" +draw: + desc: "Draws a card from this server's deck. You can draw up to 10 cards by supplying a number of cards to draw." + args: + - "" + - "5" +drawnew: + desc: "Draws a card from the NEW deck of cards. You can draw up to 10 cards by supplying a number of cards to draw." + args: + - "" + - "5" +playlistshuffle: + desc: "Shuffles the current playlist." + args: + - "" +flip: + desc: "Flips coin(s) - heads or tails, and shows an image." + args: + - "" + - "3" +betflip: + desc: "Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner." + args: + - "5 heads" + - "3 t" +roll: + desc: "Rolls 0-100. If you supply a number `X` it rolls up to 30 normal dice. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. `Y` can be a letter 'F' if you want to roll fate dice instead of dnd." + args: + - "" + - "7" + - "3d5" + - "5dF" +rolluo: + desc: "Rolls `X` normal dice (up to 30) unordered. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`." + args: + - "" + - "7" + - "3d5" +nroll: + desc: "Rolls in a given range. If you specify just one number instead of the range, it will roll from 0 to that number." + args: + - "5" + - "5-15" +race: + desc: "Starts a new animal race." + args: + - "" +joinrace: + desc: "Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win." + args: + - "" + - "5" +nunchi: + desc: "Creates or joins an existing nunchi game. Users have to count up by 1 from the starting number shown by the bot. If someone makes a mistake (types an incorrect number, or repeats the same number) they are out of the game and a new round starts without them. Minimum 3 users required." + args: + - "" +connect4: + desc: "Creates or joins an existing connect4 game. 2 players are required for the game. Objective of the game is to get 4 of your pieces next to each other in a vertical, horizontal or diagonal line. You can specify a bet when you create a game and only users who bet the same amount will be able to join your game." + args: + - "" +raffle: + desc: "Prints a name and ID of a random online user from the server, or from the online user in the specified role." + args: + - "" + - "RoleName" +raffleany: + desc: "Prints a name and ID of a random user from the server, or from the specified role." + args: + - "" + - " RoleName" +give: + desc: "Give someone a certain amount of currency. You can specify the reason after the mention." + args: + - "1 @Someone" + - "5 @CootGurl Ur so pwetty" +award: + desc: "Awards someone a certain amount of currency. You can specify the reason after the Username. You can also specify a role name to award currency to all users in a role." + args: + - "100 @person" + - "5 Role Of Gamblers" +take: + desc: "Takes the specified amount of currency from someone. You can specify a role instead to take the specified amount of currency from all users in the role." + args: + - "1 @Someone" + - "50 SomeRole" +betroll: + desc: "Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10." + args: + - "5" +luckyladder: + desc: "Bets a certain amount of currency on the lucky ladder. You can stop on one of many different multipliers. Won amount is rounded down to the nearest whole number." + args: + - "10" +leaderboard: + desc: "Displays the bot's currency leaderboard." + args: + - "" +trivia: + desc: "Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question." + args: + - "" + - "--timeout 5 -p -w 3 -q 10" +tl: + desc: "Shows a current trivia leaderboard." + args: + - "" +tq: + desc: "Quits current trivia after current question." + args: + - "" +typestart: + desc: "Starts a typing contest." + args: + - "" +typestop: + desc: "Stops a typing contest on the current channel." + args: + - "" +typeadd: + desc: "Adds a new article to the typing contest." + args: + - "wordswords" +pollend: + desc: "Stops active poll on this server and prints the results in this channel." + args: + - "" +pick: + desc: "Picks the currency planted in this channel. If the plant has a password, you need to specify it." + args: + - "" + - "passwd" +plant: + desc: "Spend an amount of currency to plant it in this channel. Default is 1. You can specify the password after the amount. Password has to be alphanumeric and it will be trimmed down to 10 characters if it's longer." + args: + - "5" + - "10 meow" +gencurrency: + desc: "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%)" + args: + - "" +gencurlist: + desc: "Shows the list of server and channel ids where gc is enabled. Paginated with 9 per page." + args: + - "" +choose: + desc: "Chooses a thing from a list of things" + args: + - "Get up;Sleep;Sleep more" +rps: + desc: "Play a game of Rocket-Paperclip-Scissors with Nadeko. You can bet on it. Multiplier is the same as on betflip." + args: + - "r 100" + - "scissors" +linux: + desc: "Prints a customizable Linux interjection" + args: + - "Spyware Windows" +next: + desc: "Goes to the next song in the queue. You have to be in the same voice channel as the bot" + args: + - "" +play: + desc: "If no parameters are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command" + args: + - "" + - "5" + - "Dream Of Venice" +stop: + desc: "Stops the music and preserves the current song index. Stays in the channel." + args: + - "" +destroy: + desc: "Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour)" + args: + - "" +pause: + desc: "Pauses or Unpauses the song." + args: + - "" +queue: + desc: "Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**." + args: + - "Dream Of Venice" +queuenext: + desc: "Works the same as `{0}queue` command, except it enqueues the new song after the current one. **You must be in a voice channel**." + args: + - "Dream Of Venice" +queuesearch: + desc: "Search for top 5 youtube song result using keywords, and type the index of the song to play that song. Bot will join your voice channel. **You must be in a voice channel**." + args: + - "Dream Of Venice" +soundcloudqueue: + desc: "Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**." + args: + - "Dream Of Venice" +listqueue: + desc: "Lists 10 currently queued songs per page. Default page is 1." + args: + - "" + - "2" +nowplaying: + desc: "Shows the song that the bot is currently playing." + args: + - "" +volume: + desc: "Sets the music playback volume (0-100%). Persistent server setting. Default 100" + args: + - "50" +playlist: + desc: "Queues up to 500 songs from a youtube playlist specified by a link, or keywords." + args: + - "" +soundcloudpl: + desc: "Queue a Soundcloud playlist using a link." + args: + - "https://soundcloud.com/classical-music-playlist/sets/classical-music-essential-collection" + - "" +localplaylist: + desc: "Queues all songs from a directory." + args: + - "C:/music/classical" +radio: + desc: "Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: )" + args: + - "radio link here" +local: + desc: "Queues a local file by specifying a full path." + args: + - "C:/music/mysong.mp3" +join: + desc: "Makes the bot join your voice channel." + args: + - "" +trackremove: + desc: "Remove a song by its # in the queue, or 'all' (or provide no parameter) to remove all songs from the queue." + args: + - "5" + - "all" + - "" +trackmove: + desc: "Moves a song from one position to another." + args: + - "5 3" +setmaxqueue: + desc: "Sets a maximum queue size. Specify no parameters to have no limit." + args: + - "50" + - "" +queuerepeat: + desc: "Sets music player repeat strategy for this server.\n- `n` / `no` - player will stop once it reaches the end of the queue\n- `s` / `song` - player will repeat current song\n- `q` / `queue` or empty - player will repeat entire music queue" + args: + - "" + - "n" + - "song" +save: + desc: "Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes." + args: + - "classical1" +streamrole: + desc: "Sets a role which is monitored for streamers (FromRole), and a role to add if a user from 'FromRole' is streaming (AddRole). When a user from 'FromRole' starts streaming, they will receive an 'AddRole'. You can only have 1 Stream Role per server. Provide no parameters to disable" + args: + - '"Eligible Streamers" "Featured Streams"' +load: + desc: "Loads a saved playlist using its ID. Use `{0}pls` to list all saved playlists and `{0}save` to save new ones." + args: + - "5" +playlists: + desc: "Lists all playlists. Paginated, 20 per page." + args: + - "1" +playlistshow: + desc: "Lists all songs in a playlist specified by its id. Paginated, 20 per page." + args: + - "1" +deleteplaylist: + desc: "Deletes a saved playlist using its id. Works only if you made it or if you are the bot owner." + args: + - "5" +queueautoplay: + desc: "Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs)" + args: + - "" +streamadd: + desc: "Notifies this channel when the stream on the specified URL goes online or offline. Offline notifications will only show if you enable `{0}streamoff`. Maximum 10 per server." + args: + - "twitch.tv/someguy" +streamsclear: + desc: "Removes all followed streams on this server." + args: + - "" +streamremove: + desc: "Stops following the stream on the specified index. (use `{0}stl` to see indexes)" + args: + - "2" +streamlist: + desc: "Lists all streams you are following on this server and their respective indexes." + args: + - "" +streamoffline: + desc: "Toggles whether the bot will also notify when added streams go offline." + args: + - "" +streamonlinedelete: + desc: "Toggles whether the bot will delete stream online message when the stream goes offline." + args: + - "" +streammessage: + desc: "Sets the message which will show when the stream on the specified index comes online. You can use %user% and %platform% placeholders." + args: + - "1 Hey @erryone %user% is back online on %platform%!1!!" +streammessageall: + desc: "Sets the message which will show when any of the currently followed streams comes online. This does not apply to the streams which get added afterwards. You can use %user% and %platform% placeholders." + args: + - "Hey @erryone %user% is back online!1!!" +streamcheck: + desc: "Retrieves information about a stream." + args: + - "https://twitch.tv/somedude" +convert: + desc: "Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies." + args: + - "m km 1000" +convertlist: + desc: "List of the convertible dimensions and currencies." + args: + - "" +wowjoke: + desc: "Get one of penultimate WoW jokes." + args: + - "" +calculate: + desc: "Evaluate a mathematical expression." + args: + - "1+1" +osu: + desc: "Shows osu! stats for a player." + args: + - "Name" + - "Name taiko" +gatari: + desc: "Shows osu!gatari stats for a player." + args: + - "Name" + - "Name ctb" +osu5: + desc: "Displays a user's top 5 plays." + args: + - "Name" +pokemon: + desc: "Searches for a pokemon." + args: + - "Sylveon" +pokemonability: + desc: "Searches for a pokemon ability." + args: + - "overgrow" +memelist: + desc: "Shows a list of template keys (and their respective names) used for `{0}memegen`." + args: + - "" +memegen: + desc: "Generates a meme from memelist with specified text. Separate multiple text values with semicolons. Provide no meme text to see an example meme with that template." + args: + - "biw gets iced coffee;in the winter" + - "ntot" +weather: + desc: "Shows weather data for a specified city. You can also specify a country after a comma." + args: + - "Moscow, RU" +youtube: + desc: "Searches youtubes and shows the first result" + args: + - "query" +anime: + desc: "Queries anilist for an anime and shows the first result." + args: + - "aquarion evol" +steam: + desc: "Returns a store link for a steam game with the specified name. It doesn't work very well because bundles." + args: + - "Sakura Agent" +movie: + desc: "Queries omdb for movies or series, show first result." + args: + - "Batman vs Superman" +manga: + desc: "Queries anilist for a manga and shows the first result." + args: + - "Shingeki no kyojin" +randomcat: + desc: "Shows a random cat image." + args: + - "" +randomdog: + desc: "Shows a random dog image." + args: + - "" +randomfood: + desc: "Shows a random food image." + args: + - "" +randombird: + desc: "Shows a random bird image." + args: + - "" +image: + desc: "Pulls a random image using a search parameter." + args: + - "cute kitten" +lmgtfy: + desc: "Google something for an idiot." + args: + - "query" +google: + desc: "Get a Google search link for some terms." + args: + - "query" +duckduckgo: + desc: "Get duckduckgo search results." + args: + - "cat pictures" +hearthstone: + desc: "Searches for a Hearthstone card and shows its image. Takes a while to complete." + args: + - "Ysera" +urbandict: + desc: "Searches Urban Dictionary for a word." + args: + - "Pineapple" +catfact: + desc: "Shows a random catfact from " + args: + - "" +yomama: + desc: "Shows a random joke from " + args: + - "" +randjoke: + desc: "Shows a random joke." + args: + - "" +chucknorris: + desc: "Shows a random Chuck Norris joke." + args: + - "" +magicitem: + desc: "Shows a random magic item from " + args: + - "" +revav: + desc: "Returns a Google reverse image search for someone's avatar." + args: + - "@Someone" +revimg: + desc: "Returns a Google reverse image search for an image from a link." + args: + - "Image link" +wiki: + desc: "Gives you back a wikipedia link" + args: + - "query" +color: + desc: "Shows you pictures of colors which correspond to the inputted hex values. Max 10." + args: + - "00ff00" + - "f00 0f0 00f" +avatar: + desc: "Shows a mentioned person's avatar." + args: + - "@Someone" +hentai: + desc: "Shows a hentai image from a random website (gelbooru, danbooru, konachan or yandere) with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags. Only 1 tag allowed." + args: + - "yuri" +autohentai: + desc: "Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tag groups. Random group will be chosen every time the image is sent. Max 2 tags per group. 20 seconds minimum. Provide no parameters to disable." + args: + - "30 yuri kissing|tail long_hair" + - "" +hentaibomb: + desc: "Shows a total 5 images (from gelbooru, danbooru, konachan and yandere). Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri" +yandere: + desc: "Shows a random image from yandere with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +danbooru: + desc: "Shows a random hentai image from danbooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +derpibooru: + desc: "Shows a random image from derpibooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +gelbooru: + desc: "Shows a random hentai image from gelbooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +sankaku: + desc: "Shows a random hentai image from chan.sankakucomplex.com with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kiss" +rule34: + desc: "Shows a random image from rule34.xx with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +e621: + desc: "Shows a random hentai image from e621.net with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +safebooru: + desc: "Shows a random image from safebooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri kissing" +boobs: + desc: "Real adult content." + args: + - "" +butts: + desc: "Real adult content." + args: + - "" +translate: + desc: "Translates text from the given language to the destination language." + args: + - "en fr Hello" +translangs: + desc: "Lists the valid languages for translation." + args: + - "" +guide: + desc: "Sends a readme and a guide links to the channel." + args: + - "" +calcops: + desc: "Shows all available operations in the `{0}calc` command" + args: + - "" +delallquotes: + desc: "Deletes all quotes on a specified keyword." + args: + - "kek" +greetdmmsg: + desc: "Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from instead of a regular text, if you want the message to be embedded." + args: + - "Welcome to the server, %user.mention%" +cash: + desc: "Check how much currency a person has. (Defaults to yourself)" + args: + - "" + - "@Someone" +currencytransactions: + desc: "Shows your currency transactions on the specified page. Bot owner can see other people's transactions too." + args: + - "2" + - "@SomeUser 2" +currencytransaction: + desc: "Shows full details about a currency transaction with the specified ID. You can only check your own transactions." + args: + - "3yvd" +listperms: + desc: "Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions." + args: + - "" + - "3" +allusrmdls: + desc: "Enable or disable all modules for a specific user." + args: + - "enable @Someone" +moveperm: + desc: "Moves permission from one position to another in the Permissions list." + args: + - "2 4" +removeperm: + desc: "Removes a permission from a given position in the Permissions list." + args: + - "1" +showemojis: + desc: "Shows a name and a link to every SPECIAL emoji in the message." + args: + - "A message full of SPECIAL emojis" +emojiadd: + desc: |- + Adds the specified emoji to this server. + You can specify a name before the emoji to add it under a different name. + You can specify a name followed by an image link to add a new emoji from an image. + You can omit imageUrl and instead upload the image as an attachment. + Image size has to be below 256KB. + args: + - ":someonesCustomEmoji:" + - "MyEmojiName :someonesCustomEmoji:" + - "owoNice https://cdn.discordapp.com/emojis/587930873811173386.png?size=128" +emojiremove: + desc: "Removes the specified emoji or emojis from this server." + args: + - ":eagleWarrior: :plumedArcher:" +stickeradd: + desc: "Adds the sticker from your message to this server. Send the sticker along with this command (in the same message)." + args: + - "" + - 'name "description" tag1 tag2 tagN' +deckshuffle: + desc: "Reshuffles all cards back into the deck." + args: + - "" +forwardmessages: + desc: "Toggles forwarding of non-command messages sent to bot's DM to the bot owners" + args: + - "" +forwardtoall: + desc: "Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the creds.yml file" + args: + - "" +forwardtochannel: + desc: "Toggles forwarding of non-command messages sent to bot's DM to the current channel" + args: + - "" +resetperms: + desc: "Resets the bot's permissions module on this server to the default value." + args: + - "" +antiraid: + desc: "Sets an anti-raid protection on the server. Provide no parameters to disable. First parameter is number of people which will trigger the protection. Second parameter is a time interval in which that number of people needs to join in order to trigger the protection, and third parameter is punishment for those people. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, RemoveRoles, AddRole, Warn, TimeOut" + args: + - "5 20 Kick" + - "7 9 Ban" + - "10 10 Ban 6h30m" + - "" +antispam: + desc: "Stops people from repeating same message X times in a row. Provide no parameters to disable. You can specify to either mute, kick or ban the offenders. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Max message count is 10. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, AddRole, RemoveRoles, Warn, TimeOut" + args: + - "3 Mute" + - "5 Ban" + - "5 Ban 3h30m" + - "" +antialt: + desc: "Applies a punishment action to any user whose account is younger than the specified threshold. Specify time after the punishment to have a timed punishment (not all punishments support timers)." + args: + - "1h Ban" + - "3d Mute 1h" +chatmute: + desc: "Prevents a mentioned user from chatting in text channels. You can also specify time string for how long the user should be muted. You can optionally specify a reason." + args: + - "@Someone" + - "@Someone stop writing" + - "15m @Someone" + - "1h30m @Someone" + - "1h @Someone chill" +voicemute: + desc: "Prevents a mentioned user from speaking in voice channels. User has to be in a voice channel in order for the command to have an effect. You can also specify time string for how long the user should be muted. You can optionally specify a reason." + args: + - "@Someone" + - "@Someone stop talking" + - "15m @Someone" + - "1h30m @Someone" + - "1h @Someone silence" +konachan: + desc: "Shows a random hentai image from konachan with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." + args: + - "yuri" +muterole: + desc: "Sets a name of the role which will be assigned to people who should be muted. Provide no arguments to see currently set mute role. Default is ellie-mute." + args: + - "" + - "Silenced" +adsarm: + desc: "Toggles the automatic deletion of the user's message and Nadeko's confirmations for `{0}iam` and `{0}iamn` commands." + args: + - "" +setstream: + desc: "Sets the bots stream. First parameter is the twitch link, second parameter is stream name." + args: + - "TWITCHLINK Hello" +chatunmute: + desc: "Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels." + args: + - "@Someone" +unmute: + desc: "Unmutes a mentioned user previously muted with `{0}mute` command." + args: + - "@Someone" +xkcd: + desc: 'Shows a XKCD comic. Specify no parameters to retrieve a random one. Number parameter will retrieve a specific comic, and "latest" will get the latest one.' + args: + - "" + - "1400" + - "latest" +placelist: + desc: "Shows the list of available tags for the `{0}place` command." + args: + - "" +place: + desc: "Shows a placeholder image of a given tag. Use `{0}placelist` to see all available tags. You can specify the width and height of the image as the last two optional parameters." + args: + - "Cage" + - "steven 500 400" +poll: + desc: "Creates a public poll which requires users to type a number of the voting option in the channel command is ran in." + args: + - "Question?;Answer1;Answ 2;A_3" +autotranslang: + desc: "Sets your source and target language to be used with `{0}at`. Specify no parameters to remove previously set value." + args: + - "en fr" +autotranslate: + desc: 'Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" parameter to automatically delete all translated user messages.' + args: + - "" + - "del" +listquotes: + desc: "Lists all quotes on the server ordered alphabetically or by ID. 15 Per page." + args: + - "3" + - "3 id" +typedel: + desc: "Deletes a typing article given the ID." + args: + - "3" +typelist: + desc: "Lists added typing articles with their IDs. 15 per page." + args: + - "" + - "3" +listservers: + desc: "Lists servers the bot is on with some basic info. 15 per page." + args: + - "3" +cleverbot: + desc: "Toggles cleverbot/chatgpt session. When enabled, the bot will reply to messages starting with bot mention in the server. Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled." + args: + - "" +shorten: + desc: "Attempts to shorten an URL, if it fails, returns the input URL." + args: + - "https://google.com" +wikia: + desc: "Gives you back a fandom link" + args: + - "mtg Vigilance" + - "mlp Dashy" +magicthegathering: + desc: "Searches for a Magic The Gathering card." + args: + - "about face" +hangmanlist: + desc: "Shows a list of hangman question categories." + args: + - "" +hangman: + desc: "Starts a game of hangman in the channel. You can optionally select a category `{0}hangmanlist` to see a list of available categories." + args: + - "" + - "movies" +hangmanstop: + desc: "Stops the active hangman game on this channel if it exists." + args: + - "" +acrophobia: + desc: "Starts an Acrophobia game." + args: + - "" + - "-s 30" +logevents: + desc: "Shows a list of all events you can subscribe to with `{0}log`" + args: + - "" +log: + desc: "Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to." + args: + - "userpresence" + - "userbanned" +fairplay: + desc: "Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue." + args: + - "" +define: + desc: "Finds a definition of a word." + args: + - "heresy" +setmaxplaytime: + desc: "Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit." + args: + - "0" + - "270" +activity: + desc: "Checks for spammers." + args: + - "" +setstatus: + desc: "Sets the bot's status. (Online/Idle/Dnd/Invisible)" + args: + - "Idle" +invitecreate: + desc: "Creates a new invite which has infinite max uses and never expires." + args: + - "" +invitelist: + desc: "Lists all invites for this channel. Paginated with 9 per page." + args: + - "" + - "3" +invitedelete: + desc: "Deletes an invite on the specified index. Use `{0}invitelist` to see the list of invites." + args: + - "2" +pollstats: + desc: "Shows the poll results without stopping the poll on this server." + args: + - "" +antilist: + desc: "Shows currently enabled protection features." + args: + - "" +antispamignore: + desc: "Toggles whether antispam ignores current channel. Antispam must be enabled." + args: + - "" +eventstart: + desc: "Starts one of the events seen on public ellie. Events: `reaction`, `gamestatus`" + args: + - "reaction" + - "reaction -d 1 -a 50 --pot-size 1500" +betstats: + desc: "Shows the total stats of several gambling features. Updates once an hour." + args: + - "" +slottest: + desc: "Tests to see how much slots payout for X number of plays." + args: + - "1000" +slot: + desc: "Play Nadeko slots. 1 second cooldown per user." + args: + - "5" +affinity: + desc: "Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. Provide no parameters to clear your affinity. 30 minutes cooldown." + args: + - "@MyHusband" + - "" +waifuclaim: + desc: "Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `{0}affinity` towards you." + args: + - "50 @Himesama" +waifureset: + desc: "Resets your waifu stats, except current waifus." + args: + - "" +waifutransfer: + desc: "Transfer the ownership of one of your waifus to another user. You must pay 10% of your waifu's value unless that waifu has affinity towards you, in which case you must pay 60% fee. Transferred waifu's price will be reduced by the fee amount." + args: + - "@ExWaifu @NewOwner" +waifugift: + desc: -| + Gift an item to someone. This will increase their waifu value by a percentage of the gift's value. + Negative gifts will not show up in waifuinfo. + Provide no parameters to see a list of items that you can gift. + args: + - "" + - "Rose @Himesama" +waifulb: + desc: "Shows top 9 waifus. You can specify another page to show other waifus." + args: + - "" + - "3" +divorce: + desc: "Releases your claim on a specific waifu. You will get 50% of that waifu's value back, unless that waifu has an affinity towards you, in which case they will be reimbursed instead. 6 hours cooldown." + args: + - "@CheatingSloot" +waifuinfo: + desc: "Shows waifu stats for a target person. Defaults to you if no user is provided." + args: + - "@MyCrush" + - "" +mal: + desc: "Shows basic info from a MyAnimeList profile." + args: + - "straysocks" +setmusicchannel: + desc: "Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. Persistent server setting." + args: + - "" +unsetmusicchannel: + desc: "Bot will output playing, finished, paused and removed songs to the channel where the first song was queued in. Persistent server setting." + args: + - "" +musicquality: + desc: "Gets or sets the default music player quality. Available settings: Highest, High, Medium, Low. Default is **Highest**. Provide no argument to see current setting." + args: + - "" + - "High" + - "Low" +stringsreload: + desc: "Reloads localized bot strings." + args: + - "" +shardstats: + desc: |- + Stats for shards. Paginated with 25 shards per page. + Format: `[status] | # [shard_id] | [last_heartbeat] | [server_count]` + args: + - "" + - "2" +restartshard: + desc: "Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors." + args: + - "2" +tictactoe: + desc: "Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play." + args: + - "" +timezones: + desc: "Lists all timezones available on the system to be used with `{0}timezone`." + args: + - "" +timezone: + desc: "Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) **Setting timezone requires Administrator server permission.**" + args: + - "" + - "GMT Standard Time" +languagesetdefault: + desc: "Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no parameters to see currently set language." + args: + - "en-US" + - "default" +languageset: + desc: "Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no parameters to see currently set language." + args: + - "de-DE " + - "default" +languageslist: + desc: "List of languages for which translation (or part of it) exist atm." + args: + - "" +rategirl: + desc: "Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart." + args: + - "@SomeGurl" +exprtoggleglobal: + desc: "Toggles whether global expressions are usable on this server." + args: + - "" +exprreact: + desc: "Sets or resets reactions (up to 3) which will be added to the response message of the Expression with the specified ID. Provide no emojis to reset." + args: + - "59 \U0001F44D \U0001F44E " + - "59 " + - "59" +exprad: + desc: "Toggles whether the message triggering the expression will be automatically deleted." + args: + - "59" +exprat: + desc: "Toggles whether the expression will allow extra input after the trigger. For example, with this feature enabled, expression with trigger 'hi' will also be invoked when a user types 'hi there'. This feature is automatically enabled on expressions which have '%target%' in their response." + args: + - "59" +exprdm: + desc: "Toggles whether the response message of the expression will be sent as a direct message." + args: + - "44" +exprca: + desc: "Toggles whether the expression will trigger if the triggering message contains the keyword (instead of only starting with it)." + args: + - "44" +exprsreload: + desc: "Reloads all expressions on all shards. Use this if you've made changes to the database while the bot is running, or used `{0}deleteunusedcrnq`" + args: + - "" +exprsimport: + desc: "Upload the file or send the raw .yml data with this command to import all expressions from the specified string or file into the current server (or as global expressions in dm)" + args: + - "" +exprsexport: + desc: "Exports expressions from the current server (or global expressions in DMs) into a .yml file" + args: + - "" +quotesimport: + desc: "Upload the file or send the raw .yml data with this command to import all quotes from the specified string or file into the current server." + args: + - "" +quotesexport: + desc: "Exports quotes from the current server into a .yml file" + args: + - "" +aliaslist: + desc: "Shows the list of currently set aliases. Paginated." + args: + - "" + - "3" +alias: + desc: "Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one." + args: + - "allin {0}bf all h" + - '"linux thingy" >loonix Spyware Windows' +warnlog: + desc: "See a list of warnings of a certain user." + args: + - "@Someone" +warnlogall: + desc: "See a list of all warnings on the server. 15 users per page." + args: + - "" + - "2" +warn: + desc: |- + Warns a user with an optional reason. + You can specify a warning weight integer before the user. For example, 3 would mean that this warning counts as 3 warnings. + args: + - "@Someone Very rude person" + - "3 @Someone Very rude person" +startupcommandadd: + desc: "Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up." + args: + - "{0}stats" +autocommandadd: + desc: "Adds a command to the list of commands which will be executed automatically every X seconds." + args: + - "60 {0}prune 1000" +startupcommandremove: + desc: "Removes a startup command on the specified index." + args: + - "3" +autocommandremove: + desc: "Removes an auto command on the specified index." + args: + - "3" +startupcommandsclear: + desc: "Removes all startup commands." + args: + - "" +startupcommandslist: + desc: "Lists all startup commands in the order they will be executed in." + args: + - "" +autocommandslist: + desc: "Lists all auto commands and the intervals in which they execute." + args: + - "" +unban: + desc: "Unbans a user with the provided user#discrim or id." + args: + - "kwoth#1234" + - "123123123" +banmessage: + desc: "Sets a ban message template which will be used when a user is banned from this server. You can use embed strings and ban-specific placeholders: %ban.mod%, %ban.user%, %ban.duration% and %ban.reason%. You can disable ban message with `{0}banmsg -`" + args: + - "%ban.user%, you've been banned from %server.name%. Reason: %ban.reason%" + - '{{ "description": "%ban.user% you have been banned from %server.name% by %ban.mod%" }}' +banmessagetest: + desc: "If ban message is not disabled, bot will send you the message as if you were banned by yourself. Used for testing the ban message." + args: + - "No reason" + - "1h Test 1 hour ban message" +banmsgreset: + desc: "Resets ban message to default. If you want to completely disable ban messages, use `{0}banmsg -`" + args: + - "" +banprune: + desc: |- + Sets how many days of messages will be deleted when a user is banned. + Only works if the user is banned via the .ban command or punishment. + Allowed values: 0 - 7 + args: + - "3" +wait: + desc: "Used only as a startup command. Waits a certain number of milliseconds before continuing the execution of the following startup commands." + args: + - "3000" +warnexpire: + desc: "Gets or sets the number of days after which the warnings will be cleared automatically. This setting works retroactively. If you want to delete the warnings instead of clearing them, you can set the `--delete` optional parameter. Provide no parameter to see currently set expiry" + args: + - "" + - "3" + - "6 --delete" +warnclear: + desc: "Clears all warnings from a certain user. You can specify a number to clear a specific one." + args: + - "@PoorDude 3" + - "@PoorDude" +warnpunishlist: + desc: "Lists punishments for warnings." + args: + - "" +warnpunish: + desc: "Sets a punishment for a certain number of warnings. You can specify a time string after 'Ban' or *'Mute' punishments to make it a temporary mute/ban. Provide no punishment to remove. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, AddRole, RemoveRoles" + args: + - "3" + - "5 Ban" + - "5 Mute 2d12h" + - "4 AddRole toxic 1h" +ping: + desc: "Ping the bot to see if there are latency issues." + args: + - "" +time: + desc: "Shows the current time and timezone in the specified location." + args: + - "London, UK" +shop: + desc: "Lists this server's administrators' shop. Paginated." + args: + - "" + - "2" +shopadd: + desc: "Adds an item to the shop by specifying type price and name. Available types are role and list. 90% of currency from each purchase will be received by the user who added the item to the shop." + args: + - "role 1000 Rich" +shopremove: + desc: "Removes an item from the shop by its ID." + args: + - "1" +shopreq: + desc: "Sets a role which will be required to buy the item on the specified index. Specify only index to remove the requirement." + args: + - "2 Gamers" + - "2" +shopchangename: + desc: "Change the name of a shop entry at the specified index. Only works for non-role items" + args: + - "3 Cool stuff" +shopchangeprice: + desc: "Change the price of a shop entry at the specified index. Specify the index of the entry, followed by the price" + args: + - "1 500" +shopswap: + desc: "Swap the index of two shop entries" + args: + - "1 5" +shopmove: + desc: "Moves the shop entry from the current index to a new one" + args: + - "2 4" +buy: + desc: "Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you." + args: + - "2" +gamevoicechannel: + desc: "Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server." + args: + - "" +shoplistadd: + desc: "Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked." + args: + - "1 Uni-que-Steam-Key" +globalcommand: + desc: "Toggles whether a command can be used on any server." + args: + - "{0}stats" +globalmodule: + desc: "Toggles whether a module can be used on any server." + args: + - "nsfw" +globalpermlist: + desc: "Lists global permissions set by the bot owner." + args: + - "" +resetglobalperms: + desc: "Resets global permissions set by bot owner." + args: + - "" +prefix: + desc: "Sets this server's prefix for all bot commands. Provide no parameters to see the current server prefix. **Setting prefix requires Administrator server permission.**" + args: + - "+" +defprefix: + desc: "Sets bot's default prefix for all bot commands. Provide no parameters to see the current default prefix. This will not change this server's current prefix." + args: + - "+" +verboseerror: + desc: "Toggles or sets whether the bot should print command errors when a command is incorrectly used." + args: + - "" + - "false" +streamrolekeyword: + desc: "Sets keyword which is required in the stream's title in order for the streamrole to apply. Provide no keyword in order to reset." + args: + - "" + - "PUBG" +streamroleblacklist: + desc: "Adds or removes a blacklisted user. Blacklisted users will never receive the stream role." + args: + - "add @Someone#1234" + - "rem @Someone#1234" +streamrolewhitelist: + desc: "Adds or removes a whitelisted user. Whitelisted users will receive the stream role even if they don't have the specified keyword in their stream title." + args: + - "add @Someone#1234" + - "rem @Someone#1234" +config: + desc: |- + Gets or sets configuration values. + Provide no arguments to see the list of configs you can edit/view. + Provide config name to see all properties in that configuration and their values. + Provide config name and property name to see that property's description and value. + Provide config name, property name and value to set that property to the new value. + args: + - "" + - "bot" + - "bot color.ok" + - "bot color.ok ff0000" +configreload: + desc: "Reloads specified configuration" + args: + - "bot" + - "gambling" +nsfwtagblacklist: + desc: "Toggles whether the tag is blacklisted or not in nsfw searches. Provide no parameters to see the list of blacklisted tags." + args: + - "poop" +experience: + desc: "Shows your xp stats. Specify the user to show that user's stats instead." + args: + - "" + - "@someguy" +xptemplatereload: + desc: "Reloads the xp template file. Xp template file allows you to customize the position and color of elements on the `{0}xp` card." + args: + - "" +xpexclusionlist: + desc: "Shows the roles and channels excluded from the XP system on this server, as well as whether the whole server is excluded." + args: + - "" +xpexclude: + desc: "Exclude a channel, role or current server from the xp system." + args: + - "Role Excluded-Role" + - "Server" +xpnotify: + desc: "Sets how the bot should notify you when you get a `server` or `global` level. This is a personal setting and affects only how you receive Global or Server level-up notifications. You can set `dm` (for the bot to send you a direct message), `channel` (to get notified in the channel you sent the last message in) or `none` to disable." + args: + - "global dm" + - "server channel" +xpleveluprewards: + desc: "Shows currently set level up rewards." + args: + - "" +xprewsreset: + desc: "Resets all currently set xp level up rewards." + args: + - "" +xprolereward: + desc: |- + Add or remove a role from the user who reaches the specified level. + Provide no action and role name in order to remove the role reward. + args: + - "1 rm Newbie" + - "3 add Social" + - "5 add Member" + - "5" +xpcurrencyreward: + desc: "Sets a currency reward on a specified level. Provide no amount in order to remove the reward." + args: + - "3 50" +xpleaderboard: + desc: "Shows current server's xp leaderboard." + args: + - "" +xpgloballeaderboard: + desc: "Shows the global xp leaderboard." + args: + - "" +xpadd: + desc: "Adds server XP to a single user or all users role on this server. This does not affect their global ranking. You can use negative values." + args: + - "100 @Someone" + - "500 SomeRoleName" +clubcreate: + desc: "Creates a club. You must be at least level 5 and not be in the club already." + args: + - "My Brand New Club" +clubtransfer: + desc: "Transfers the ownership of the club to another member of the club." + args: + - "@Someone" +clubinformation: + desc: "Shows information about the club." + args: + - "My Brand New Club#23" +clubapply: + desc: "Apply to join a club. You must meet that club's minimum level requirement, and not be on its ban list." + args: + - "My Brand New Club#23" +clubaccept: + desc: "Accept a user who applied to your club." + args: + - "user#1337" +clubreject: + desc: "Reject a user who applied to your club." + args: + - "user#1337" +clubleave: + desc: "Leaves the club you're currently in." + args: + - "" +clubdisband: + desc: "Disbands the club you're the owner of. This action is irreversible." + args: + - "" +clubkick: + desc: "Kicks the user from the club. You must be the club owner. They will be able to apply again." + args: + - "user#1337" +clubban: + desc: "Bans the user from the club. You must be the club owner. They will not be able to apply again." + args: + - "user#1337" +clubunban: + desc: "Unbans the previously banned user from the club. You must be the club owner." + args: + - "user#1337" +clubdescription: + desc: "Sets the club description. Maximum 150 characters. Club owner only." + args: + - "This is the best club please join." +clubicon: + desc: "Sets the club icon." + args: + - "https://i.imgur.com/htfDMfU.png" +clubapps: + desc: "Shows the list of users who have applied to your club. Paginated. You must be club owner to use this command." + args: + - "2" +clubbans: + desc: "Shows the list of users who have banned from your club. Paginated. You must be club owner to use this command." + args: + - "2" +clubleaderboard: + desc: "Shows club rankings on the specified page." + args: + - "2" +clubadmin: + desc: "Assigns (or unassigns) staff role to the member of the club. Admins can ban, kick and accept applications." + args: + - "@Someone" +autoboobs: + desc: "Posts a boobs every X seconds. 20 seconds minimum. Provide no parameters to disable." + args: + - "30" + - "" +autobutts: + desc: "Posts a butt every X seconds. 20 seconds minimum. Provide no parameters to disable." + args: + - "30" + - "" +eightball: + desc: "Ask the 8ball a yes/no question." + args: + - "Is b1nzy a nice guy?" +ytuploadnotif: + desc: |- + Subscribe to a youtube channel's upload rss feed. + Shortcut for `.feed https://www.youtube.com/feeds/videos.xml?channel_id=%3Cyoutube_channel_id` + You can optionally specify a message which will be posted with an update. + args: + - "https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow" + - "https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow New video is posted" +feed: + desc: |- + Subscribes to a feed. + Bot will post an update up to once every 10 seconds. + You can have up to 10 feeds on one server. + All feeds must have unique URLs. + Set a channel as a second optional parameter to specify where to send the updates. + You can optionally specify a message after the channel name which will be posted with an update. + args: + - "https://blog.playstation.com/feed/" + - "https://blog.playstation.com/feed/ #updates" + - "https://blog.playstation.com/feed/ #updates New playstation rss feed post!" +feedremove: + desc: "Stops tracking a feed on the given index. Use `{0}feeds` command to see a list of feeds and their indexes." + args: + - "3" +feedlist: + desc: "Shows the list of feeds you've subscribed to on this server." + args: + - "" +expredit: + desc: "Edits the expression's response given its ID." + args: + - "123 I'm a magical girl" +say: + desc: "Bot will send the message you typed in the specified channel. If you omit the channel name, it will send the message in the current channel. Supports embeds." + args: + - "hi" + - "#chat hi" +sqlexec: + desc: "Executes provided sql command and returns the number of affected rows. Dangerous." + args: + - "UPDATE DiscordUser SET CurrencyAmount=CurrencyAmount+1234" +sqlselect: + desc: "Executes provided sql query and returns the results. Dangerous." + args: + - "SELECT * FROM DiscordUser LIMIT 5" +deletewaifus: + desc: "Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables." + args: + - "" +deletewaifu: + desc: "Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables for the specified user. Also makes specified user's waifus free." + args: + - "" +deletecurrency: + desc: "Deletes everything from Currency and CurrencyTransactions." + args: + - "" +deleteplaylists: + desc: "Deletes everything from MusicPlaylists." + args: + - "" +deletexp: + desc: "Deletes everything from UserXpStats, Clubs and sets users' TotalXP to 0." + args: + - "" +discordpermoverride: + desc: "Overrides required user permissions that the command has with the specified ones. You can only use server-level permissions. This action will make the bot ignore user permission requirements which command has by default. Provide no permissions to reset to default." + args: + - "{0}prune ManageMessages BanMembers" + - "{0}prune" +discordpermoverridelist: + desc: "Lists all discord permission overrides on this server." + args: + - "" +discordpermoverridereset: + desc: "Resets ALL currently set discord permission overrides on this server. This will make all commands have default discord permission requirements." + args: + - "" +rafflecur: + desc: "Starts or joins a currency raffle with a specified amount. Users who join the raffle will lose the amount of currency specified and add it to the pot. After 30 seconds, random winner will be selected who will receive the whole pot. There is also a `mixed` mode in which the users will be able to join the game with any amount of currency, and have their chances be proportional to the amount they've bet." + args: + - "20" + - "mixed 15" +rip: + desc: "Shows the inevitable fate of someone." + args: + - "@Someone" +autodisconnect: + desc: "Toggles whether the bot should disconnect from the voice channel once it's done playing all of the songs and queue repeat option is set to `none`." + args: + - "" +timelyset: + desc: "Sets the 'timely' currency allowance amount for users. Second parameter is period in hours, default is 24 hours." + args: + - "100" + - "50 12" +timely: + desc: "Use to claim your 'timely' currency. Bot owner has to specify the amount and the period on how often you can claim your currency." + args: + - "" +timelyreset: + desc: "Resets all user timeouts on `{0}timely` command." + args: + - "" +crypto: + desc: "Shows basic stats about a cryptocurrency from coinmarketcap.com. You can use either a name or an abbreviation of the currency." + args: + - "btc" + - "bitcoin" +stock: + desc: "Shows basic information about a stock. You can use a symbol or company name" + args: + - "tsla" + - "advanced micro devices" + - "amd" +rolelevelreq: + desc: "Set a level requirement on a self-assignable role." + args: + - "5 SomeRole" +massban: + desc: "Bans multiple users at once. Specify a space separated list of IDs of users who you wish to ban." + args: + - "123123123 3333333333 444444444" +masskill: + desc: "Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away." + args: + - "BadPerson#1234 Toxic person" +pathofexile: + desc: "Searches characters for a given Path of Exile account. May specify league name to filter results." + args: + - '"Zizaran"' +pathofexileleagues: + desc: "Returns a list of the main Path of Exile leagues." + args: + - "" +pathofexilecurrency: + desc: "Returns the chaos equivalent of a given currency or exchange rate between two currencies." + args: + - 'Standard "Mirror of Kalandra"' +rollduel: + desc: "Challenge someone to a roll duel by specifying the amount and the user you wish to challenge as the parameters. To accept the challenge, just specify the name of the user who challenged you, without the amount." + args: + - "50 @Someone" + - "@Challenger" +reactionroleadd: + desc: |- + Specify a message id, emote and a role name to have the bot assign the specified role to the user who reacts to the specified message (in this channel) with the specified emoji. + You can optionally specify an exclusivity group. Default is group 0 which is non-exclusive. Other groups are exclusive. Exclusive groups will let the user only have one of the roles specified in that group. + You can optionally specify a level requirement after a group. Users who don't meet the level requirement will not receive the role. + You can have up to 50 reaction roles per server in total. + args: + - 971276352684691466 😊 gamer + - 971276352684691466 😢 emo 1 + - 971276352684691466 🤔 philosopher 5 20 + - 971276352684691466 👨 normie 5 20 +reactionroleslist: + desc: "Lists all ReactionRole messages on this server with their message ids. Clicking/Tapping message ids will send you to that message." + args: + - "" +reactionrolesremove: + desc: "Remove all reaction roles from message specified by the id" + args: + - "971276352684691466" +reactionrolesdeleteall: + desc: "Deletes all reaction roles on the server. This action is irreversible." + args: + - "" +reactionrolestransfer: + desc: "Transfers reaction roles from one message to another by specifying their ids. If the target message has reaction roles specified already, the reaction roles will be MERGED, not overwritten." + args: + - "971276352684691466 971427748448964628" +blackjack: + desc: "Start or join a blackjack game. You must specify the amount you're betting. Use `{0}hit`, `{0}stand` and `{0}double` commands to play. Game is played with 4 decks. Dealer hits on soft 17 and wins draws." + args: + - "50" +hit: + desc: "In the blackjack game, ask the dealer for an extra card." + args: + - "" +stand: + desc: "Finish your turn in the blackjack game." + args: + - "" +double: + desc: "In the blackjack game, double your bet in order to receive exactly one more card, and your turn ends." + args: + - "" +xpreset: + desc: "Resets specified user's XP, or the XP of all users in the server. You can't reverse this action." + args: + - "@Someone" + - "" +xpshop: + desc: "Access the xp shop (if enabled). You can purchase either xp card frames or backgrounds. You can optionally provide a page number" + args: + - "bgs" + - "frames" + - "bgs 3" +xpshopbuy: + desc: "Buy an item from the xp shop by specifying the type and the key of the item." + args: + - "bg open_sea" + - "fr gold" +xpshopuse: + desc: "Use a previously purchased item from the xp shop by specifying the type and the key of the item." + args: + - "bg synth" + - "fr default" +bible: + desc: "Shows bible verse. You need to supply book name and chapter:verse" + args: + - "genesis 3:19" +edit: + desc: "Edits bot's message, you have to specify message ID and new text. You can optionally specify target channel. Supports embeds." + args: + - "7479498384 Hi :^)" + - "#other-channel 771562360594628608 New message!" + - '#other-channel 771562360594628608 {{"description":"hello"}}' +delete: + desc: "Deletes a single message given the channel and message ID. If channel is ommited, message will be searched for in the current channel. You can also specify time parameter after which the message will be deleted (up to 7 days). This timer won't persist through bot restarts." + args: + - "#chat 771562360594628608" + - "771562360594628608" + - "771562360594628608 5m" +roleid: + desc: "Shows the id of the specified role." + args: + - "Some Role" +nsfwtoggle: + desc: "Toggles the NSFW parameter of the current text channel." + args: + - "" +economy: + desc: "Breakdown of the current state of the bot's economy. Updates every 3 minutes." + args: + - "" +purgeuser: + desc: "Purge user from the database completely. This includes currency, xp, clubs that user owns, waifu info" + args: + - "@Oblivion" +imageonlychannel: + desc: |- + Toggles whether the channel only allows images. + Users who send more than a few non-image messages will be banned from using the channel. + args: + - "" +linkonlychannel: + desc: |- + Toggles whether the channel only allows links. + Users who send more than a few non-link messages will be banned from using the channel. + args: + - "" +coordreload: + desc: "Reloads coordinator config" + args: + - "" +showembed: + desc: "Prints the json equivalent of the embed of the message specified by its Id." + args: + - "820022733172121600" + - "#some-channel 820022733172121600" +deleteemptyservers: + desc: "Deletes all servers in which the bot is the only member." + args: + - "" +medusaload: + desc: |- + Loads a marmalade with the specified name from the data/marmalades/ folder. + Provide no name to see the list of loadable marmalades. + Read about the marmalade system [here](https://docs.elliebot.net/v4/) + args: + - "mycoolmedusa" + - "" +medusaunload: + desc: |- + Unloads the previously loaded marmalade. + Provide no name to see the list of unloadable marmalades. + Read about the marmalade system [here](https://docs.elliebot.net/v4/) + args: + - "mycoolmedusa" + - "" +medusainfo: + desc: |- + Shows information about the specified marmalade such as the author, name, description, list of sneks, number of commands etc. + Provide no name to see the basic information about all loaded marmalades. + Read about the marmalade system [here](https://docs.elliebot.net/v4/) + args: + - "mycoolmedusa" + - "" +medusalist: + desc: |- + Lists all loaded and unloaded marmalades. + Read about the marmalade system [here](https://docs.elliebot.net/v4/) + args: + - "" +bankdeposit: + desc: "Deposits the specified amount of currency into the bank for later use." + args: + - "50" +bankwithdraw: + desc: "Withdraws the specified amount of currency from the bank if available." + args: + - "49" +bankbalance: + desc: "Shows your current bank balance available for withdrawal." + args: + - "" +banktake: + desc: "Takes the specified amount of currency from a user's bank" + args: + - "500 @MoniLaunder" +bankaward: + desc: "Award the specified amount of currency to a user's bank" + args: + - "99999 @Bestie" +patron: + desc: "Check your patronage status and command usage quota. Bot owners can check targeted user's patronage status." + args: + - "" +patronmessage: + desc: "Sends a message to all patrons of the specified tier and higher. Supports embeds." + args: + - "x hello" +eval: + desc: |- + Execute arbitrary C# code and (optionally) return a result. Several namespaces are included by default. + Special variables available: + `self` - Instance of the command group executing the command (this) + `guild` - Server in which the command is executed + `channel` - Channel in which the command is executed + `user` - User executing the command + `ctx` - Discord.Net command context + `services` - Nadeko's IServiceProvider + args: + - "123 / 4.5f" + - "await ctx.OkAsync();" + - 'await ctx.SendConfirmAsync("uwu");' +betdraw: + desc: |- + Bet on the card value and/or color. Specify the amount followed by your guess. + You can specify `r` or `b` for red or black, and `h` or `l` for high or low. + You can specify only h/l or only r/b or both. + Returns are high but **7 always loses**. + args: + - "50 r" + - "200 b l" + - "1000 h" + - "38 hi black" +bettest: + desc: |- + Tests a betting command by specifying the name followed by the number of tests. Some have multiple variations. + See the list of all tests by specifying no parameters. + args: + - "" + - "betflip 1000" + - "slot 2000" +threadcreate: + desc: "Create a public thread with the specified title. You may optionally reply to a message to have it as a starting point." + args: + - "Q&A" +threaddelete: + desc: "Delete a thread with the specified name in this channel. Case insensitive." + args: + - "Q&A" +autopublish: + desc: "Make the bot automatically publish all messages posted in the news channel this command was executed in." + args: + - "" +doas: + desc: "Execute the command as if you were the target user. Requires bot ownership and server administrator permission." + args: + - "@Thief .give all @Admin" +cacheusers: + desc: Caches users of a Discord server and saves them to the database. + args: + - "" + - "serverId" diff --git a/src/EllieBot/data/strings/responses/responses.en-US.json b/src/EllieBot/data/strings/responses/responses.en-US.json new file mode 100644 index 0000000..be21798 --- /dev/null +++ b/src/EllieBot/data/strings/responses/responses.en-US.json @@ -0,0 +1,1064 @@ +{ + "expr_global_disabled": "Global expressions are now disabled on this server.", + "expr_global_enabled": "Global expressions are no longer disabled on this server.", + "expr_deleted": "Expression deleted", + "expr_insuff_perms": "Insufficient permissions. Requires Bot ownership for global expressions, and Administrator for server expressions.", + "expressions": "Expressions", + "expr_new": "New Expression", + "expr_no_found": "No expression found.", + "expr_no_found_id": "No expression found with that id.", + "exprs_cleared": "All {0} expressions on this server have been removed.", + "expr_reset": "Expression with id {0} will no longer add reactions.", + "expr_set": "Expression with id {0} will add following reactions to the response message: {1}", + "invalid_emojis": "All emojis you've specified are invalid.", + "invalid_emoji_link": "Specified link is either not an image or exceeds 256KB.", + "emoji_add_error": "Error adding emoji. You either ran out of emoji slots, or image size is inadequate.", + "emoji_added": "Added a new emoji: {0}", + "emoji_not_removed": "The following emojis were not removed: {0}", + "fw_cleared": "Removed all filtered words and filtered words channel settings.", + "aliases_cleared": "All {0} aliases on this server have been removed.", + "no_results": "No results found.", + "vcrole_not_found": "That voice channel doesn't have a VcRole.", + "aar_disabled": "**Auto assign role** on user join is now **disabled**.", + "aar_none": "Users don't receive any roles when they join this server.", + "aar_roles": "The following roles are applied to users that join this server: {0}", + "aar_role_removed": "Users will no longer receive {0} role when they join this server.", + "attachments": "Attachments", + "avatar_changed": "Avatar Changed", + "autopublish_enable": "All messages posted in this channel will be automatically published.", + "autopublish_disable": "Messages in this channel will no longer be automatically published.", + "req_announcement_channel": "This command must be executed in an Announcement channel.", + "bandm": "You have been banned from {0} server.\nReason: {1}", + "banmsg_disabled": "Ban messages are disabled. You can enable them by setting a banmsg to something other than '-'.", + "banmsg_default": "No ban message set. Default behavior will be used.", + "banned_pl": "banned", + "banned_user": "User Banned", + "ban_prune_disabled": "Banned user's messages will no longer be deleted.", + "ban_prune": "Bot will prune up to {0} day(s) worth of messages from banned user.", + "timeoutdm": "You have been timed out in {0} server.\nReason: {1}", + "timedout_user": "User Timed Out", + "remove_roles_pl": "have had their roles removed", + "bot_name": "Bot's name changed to {0}", + "bot_status": "Bot status changed to {0}", + "byedel_off": "Automatic deletion of bye messages has been disabled.", + "byedel_on": "Bye messages will be deleted after {0} seconds.", + "byemsg_cur": "Current bye message: {0}", + "byemsg_enable": "Enable bye messages by typing {0}", + "byemsg_new": "New bye message set.", + "bye_off": "Bye announcements disabled.", + "bye_on": "Bye announcements enabled on this channel.", + "ch_name_change": "Channel Name Changed", + "ch_old_name": "Old Name", + "ch_topic_change": "Channel Topic Changed", + "content": "Content", + "cr": "Successfully created role {0}", + "dr": "Role {0} has been deleted.", + "createtextchan": "Text channel {0} created.", + "createvoich": "Voice channel {0} created.", + "deafen": "Deafen successful.", + "delmsg_off": "I will no longer auto-delete messages which successfully execute commands on this server.", + "delmsg_on": "I will auto-delete messages which successfully execute commands on this server.", + "delmsg_channel_off": "I will never auto-delete messages which successfully execute commands on this channel.", + "delmsg_channel_on": "I will always auto-delete messages which successfully execute commands on this channel, regardless of the server setting.", + "delmsg_channel_inherit": "I will auto-delete messages which successfully execute commands on this channel only if this feature is enabled on the server.", + "server_delmsgoncmd": "Server Setting", + "channel_delmsgoncmd": "Channel-Specific Settings", + "deltextchan": "Text channel {0} deleted.", + "delvoich": "Voice channel {0} deleted.", + "dm_from": "DM from", + "fwall_start": "I will forward DMs to all owners.", + "fwall_stop": "I will forward DMs only to the first owner.", + "fwdm_start": "I will forward DMs from now on.", + "fwdm_stop": "I will stop forwarding DMs from now on.", + "fwch_start": "Any message sent to bot's DMs will be forwarded to this channel.", + "fwch_stop": "Messages sent to bot's DMs will no longer be forwarded to this channel.", + "greetdel_off": "Automatic deletion of greet messages has been disabled.", + "greetdel_on": "Greet messages will be deleted after {0} seconds.", + "greetdmmsg_cur": "Current DM greet message: {0}", + "greetdmmsg_enable": "Enable DM greet messages by typing {0}", + "greetdmmsg_new": "New DM greet message set.", + "greetdm_off": "DM greet announcements disabled.", + "greetdm_on": "DM greet announcements enabled.", + "greetmsg_cur": "Current greet message: {0}", + "greetmsg_enable": "Enable greet messages by typing {0}", + "greetmsg_new": "New greet message set.", + "greet_off": "Greet announcements disabled.", + "greet_on": "Greet announcements enabled on this channel.", + "boost_on": "Boost announcements enabled on this channel.", + "boost_off": "Boost announcements disabled.", + "boostmsg_cur": "Current boost message: {0}", + "boostmsg_enable": "Enable boost messages by typing {0}", + "boostmsg_new": "New boost message set.", + "boostdel_off": "Automatic deletion of boost messages has been disabled.", + "boostdel_on": "Boost messages will be deleted after {0} seconds.", + "hierarchy": "You can't use this command on users with a role higher or equal than yours (or mine) in the role hierarchy.", + "role_too_high": "You can't use this command with roles which are above your highest role, unless you're server administrator.", + "insuf_perms_i": "I have insufficient permissions.", + "insuf_perms_u": "You have insufficient permissions.", + "invalid_format": "Invalid input format.", + "kickdm": "You have been kicked from {0} server.\nReason: {1}", + "kicked_user": "User kicked", + "lang_list": "List of languages", + "lang_set": "Your server's locale is now {0} - {1}", + "lang_set_bot": "Bot's default locale is now {0} - {1}", + "lang_set_bot_show": "Bot's language is set to {0} - {1}", + "lang_set_fail": "Failed setting locale. Revisit this command's help.", + "lang_set_show": "This server's language is set to {0} - {1}", + "log": "Logging {0} event in this channel.", + "log_all": "Logging all events in this channel.", + "log_disabled": "Logging disabled.", + "log_events": "Log events you can subscribe to:", + "log_ignored_channels": "Ignored Channels", + "log_ignored_users": "Ignored Users", + "log_ignore_user": "Logging will ignore user {0}", + "log_not_ignore_user": "Logging will no longer ignore user {0}", + "log_ignore_chan": "Logging will ignore channel {0}", + "log_not_ignore_chan": "Logging will no longer ignore channel {0}", + "log_stop": "Stopped logging {0} event.", + "message_sent": "Message sent.", + "msg_not_found": "Message not found.", + "time_too_long": "Time you've specified is too long.", + "log_vc_moved": "{0} moved from {1} to {2} voice channel", + "log_vc_joined": "{0} joined {1} voice channel", + "log_vc_left": "{0} left {1} voice channel", + "msg_del": "Message deleted in #{0}", + "msg_update": "Message updated in #{0}", + "muted_pl": "Muted", + "muted_sn": "Muted", + "mute_error": "I don't have the permission necessary for that most likely.", + "mute_role_set": "New mute role set.", + "mute_role": "Current mute role is {0}", + "mute_perms": "You can't mute a user who has a role higher than your highest role in the role hierarchy unless you're the owner of the server.", + "new_msg": "New message", + "new_nick": "New nickname", + "new_topic": "New topic", + "nick_change": "Nickname changed", + "no_shard_id": "No shard with that ID found.", + "nsfw_set_true": "NSFW has been enabled on this channel.", + "nsfw_set_false": "NSFW has been disabled on this channel.", + "old_msg": "Old message", + "old_nick": "Old nickname", + "old_topic": "Old topic", + "prot_active": "Active protections", + "prot_disable": "{0} has been **disabled** on this server.", + "prot_enable": "{0} Enabled", + "prot_none": "No protection enabled.", + "prot_cant_use_time": "You can't specify duration for this punishment action.", + "protection_not_running": "{0} protection is not enabled.", + "raid_cnt": "User threshold must be between {0} and {1}.", + "raid_stats": "If {0} or more users join within {1} seconds, I will {2} them.", + "raid_time": "Time must be between {0} and {1} seconds.", + "anti_alt_status": "Any user joining the server with an account that is not older than {0} will have the following action applied to them: {1}\nPunished so far: {2}", + "rar": "Successfully removed all roles from user {0}", + "rar_err": "Failed to remove roles. I have insufficient permissions.", + "rc": "Color of {0} role has been changed.", + "rc_perms": "Error occurred due to invalid color or insufficient permissions.", + "color": "Color", + "hoisted": "Hoisted", + "mentionable": "Mentionable", + "remrole": "Successfully removed role {0} from user {1}", + "remrole_err": "Failed to remove role. I have insufficient permissions.", + "renrole": "Role renamed.", + "renrole_err": "Failed to rename role. I have insufficient permissions.", + "renrole_perms": "You can't edit roles higher than either your, or my highest role.", + "reprm": "Removed the playing message: {0}", + "role_added": "Role {0} has been added to the list in group {1}.", + "role_in_list": "Role {0} is already in the list.", + "ropl_added": "Added.", + "ropl_disabled": "Rotating playing status disabled.", + "ropl_enabled": "Rotating playing status enabled.", + "ropl_list": "Here is a list of rotating statuses:\n{0}", + "ropl_not_set": "No rotating playing statuses set.", + "self_assign_already": "You already have {0} role.", + "self_assign_excl": "Self assigned roles are now exclusive!", + "self_assign_list": "There are {0} self assignable roles", + "self_assign_not": "That role is not self-assignable.", + "self_assign_not_have": "You don't have {0} role.", + "self_assign_no_excl": "Self assigned roles are now not exclusive!", + "self_assign_perms": "I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.`", + "self_assign_rem": "{0} has been removed from the list of self-assignable roles.", + "self_assign_remove": "You no longer have {0} role.", + "self_assign_success": "You now have {0} role.", + "adsarm_enable": "Automatic deletion of `{0}iam` and `{0}iamn` responses has been enabled.", + "adsarm_disable": "Bot will no longer delete `{0}iam` and `{0}iamn` responses.", + "setrole": "Successfully added role {0} to user {1}", + "setrole_err": "Failed to add role. I have insufficient permissions.", + "set_avatar": "New avatar set!", + "set_channel_name": "New channel name set.", + "set_game": "New game set!", + "set_stream": "New stream set!", + "set_topic": "New channel topic set.", + "shard_reconnecting": "Shard {0} reconnecting.", + "shutting_down": "Shutting down", + "soft_banned_pl": "soft-banned", + "spam_ignore": "{0} will ignore this channel.", + "spam_not_ignore": "{0} will no longer ignore this channel.", + "spam_stats": "If a user posts {0} same messages in a row, I will {1} them.\n __IgnoredChannels__: {2}", + "text_chan_created": "Text channel created.", + "text_chan_destroyed": "Text channel destroyed.", + "duration": "Duration", + "undeafen": "Undeafen successful.", + "unmuted_sn": "Unmuted", + "unable_to_dm_user": "DMing user failed.", + "username": "Username", + "username_changed": "Username changed", + "user_banned": "User banned", + "user_chat_mute": "{0} has been **muted** from chatting.", + "user_chat_unmute": "{0} has been **unmuted** from chatting.", + "user_joined": "User joined", + "user_left": "User left", + "user_muted": "{0} has been **muted** from text and voice chat.", + "user_role_add": "User's role added", + "user_role_rem": "User's role removed", + "user_status_change": "{0} is now {1}", + "user_unmuted": "{0} has been **unmuted** from text and voice chat.", + "user_vjoined": "{0} has joined {1} voice channel.", + "user_vleft": "{0} has left {1} voice channel.", + "user_vmoved": "{0} moved from {1} to {2} voice channel.", + "user_voice_mute": "{0} has been **voice muted**.", + "user_voice_unmute": "{0} has been **voice unmuted**.", + "voice_chan_created": "Voice channel created", + "voice_chan_destroyed": "Voice channel destroyed", + "xmuted_text": "User {0} from text chat by {1}", + "xmuted_text_and_voice": "User {0} from text and voice chat by {1}", + "xmuted_voice": "User {0} from voice chat {1}", + "sbdm": "You have been soft-banned from {0} server.\nReason: {1}", + "user_unbanned": "User unbanned", + "presence_updates": "Presence updates", + "sb_user": "User soft-banned", + "awarded": "has awarded {0} to {1}", + "better_luck": "Better luck next time ^_^", + "br_win": "Congratulations! You won {0} for rolling above {1}", + "deck_reshuffled": "Deck reshuffled.", + "flipped": "Flipped {0}", + "flip_guess": "You guessed it! You won {0}", + "flip_invalid": "Invalid number specified. You can flip 1 to {0} coins.", + "flip_results": "Flipped {0} coins. {1} heads, {2} tails.", + "cards_left": "{0} cards left in the deck.", + "cards": "Cards", + "hand_value": "Hand value", + "gifted": "has gifted {0} to {1}", + "has": "{0} has {1}", + "heads": "Head", + "mass_award": "Awarded {0} to {1} users from {2} role.", + "mass_take": "Taken {0} from {1} users in {2} role.", + "max_bet_limit": "You can't bet more than {0}", + "min_bet_limit": "You can't bet less than {0}", + "not_enough": "You don't have enough {0}", + "no_more_cards": "No more cards in the deck.", + "raffled_user": "Raffled user", + "roll2": "Roll", + "rolls": "Rolls", + "slot_jackpot": "WOAAHHHHHH!!! Congratulations!!! x{0}", + "slot_single": "A single {0}, x{1}", + "slot_three": "Wow! Lucky! Three of a kind! x{0}", + "slot_two": "Good job! Two {0} - bet x{1}", + "available_tests": "Available Tests", + "test_results_for": "Test results for {0}", + "won": "Won", + "multiplier": "Multiplier", + "tails": "Tail", + "take": "successfully took {0} from {1}", + "take_fail": "was unable to take {0} from {1} because the user doesn't have that much {2}!", + "transactions": "Transactions of user {0}", + "transaction": "Currency Transaction", + "commandlist_regen": "Commandlist regenerated.", + "commands_instr": "Type `{0}h CommandName` to see the help for that specified command. e.g. `{0}h {0}8ball`", + "command_not_found": "I can't find that command. Please verify that the command exists before trying again.", + "desc": "Description", + "cant_dm": "I can't dm you. Make sure your DMs are open. Go to **options (cog button) -> Privacy & Safety -> Allow direct messages from server members**", + "guide": "**List of commands**: <{0}>\n**Hosting guides and docs can be found here**: <{1}>", + "list_of_modules": "List of modules", + "module_not_found": "That module does not exist.", + "module_not_found_or_cant_exec": "Either the module doesn't exist, or you can't run any of the commands in the specified module.", + "usage": "Usage", + "options": "Options", + "requires": "Requires", + "animal_race": "Animal race", + "animal_race_failed": "Failed to start since there was not enough participants.", + "animal_race_full": "Race is full! Starting immediately.", + "animal_race_join": "{0} joined as a {1}", + "animal_race_join_bet": "{0} joined as a {1} and bet {2}!", + "animal_race_join_instr": "Type {0}jr to join the race.", + "animal_race_starting": "Starting in {0} seconds or when the room is full.", + "animal_race_starting_with_x": "Starting with {0} participants.", + "animal_race_won": "{0} as {1} Won the race!", + "animal_race_won_money": "{0} as {1} Won the race and {2}!", + "dice_invalid_number": "Invalid number specified. You can roll {0}-{1} dice at once.", + "dice_rolled": "rolled {0}", + "dice_rolled_num": "Dice rolled: {0}", + "race_not_exist": "No race exists on this server", + "second_larger_than_first": "Second number must be larger than the first one.", + "changes_of_heart": "Changes of heart", + "claimed_by": "Claimed by", + "divorces": "Divorces", + "likes": "Likes", + "waifu": "Waifu", + "waifus_none": "No waifus have been claimed yet.", + "waifus_top_waifus": "Top Waifus", + "waifu_affinity_already": "your affinity is already set to that waifu or you're trying to remove your affinity while not having one.", + "waifu_affinity_changed": "changed their affinity from {0} to {1}.\n\n*This is morally questionable.*🤔", + "waifu_affinity_cooldown": "You must wait {0} hours and {1} minutes in order to change your affinity again.", + "waifu_affinity_reset": "Your affinity is reset. You no longer have a person you like.", + "waifu_affinity_set": "wants to be {0}'s waifu. Aww <3", + "waifu_claimed": "claimed {0} as their waifu for {1}!", + "waifu_divorced_like": "You have divorced a waifu who likes you. You heartless monster.\n{0} received {1} as a compensation.", + "waifu_egomaniac": "you can't set affinity to yourself, you egomaniac.", + "waifu_fulfilled": "🎉 Their love is fulfilled! 🎉\n{0}'s new value is {1}!", + "waifu_isnt_cheap": "No waifu is that cheap. You must pay at least {0} to get a waifu, even if their actual value is lower.", + "waifu_not_enough": "You must pay {0} or more to claim that waifu!", + "waifu_not_yours": "That waifu is not yours.", + "waifu_not_yourself": "You can't claim yourself.", + "waifu_recent_divorce": "You divorced recently. You must wait {0} hours and {1} minutes to divorce again.", + "waifu_transfer_fail": "You're either not the owner of that waifu, or you can't afford it. Alternatively your input is invalid.", + "waifu_transfer_success": "Claim on {0} has been transfered from {1} to {2}", + "nobody": "Nobody", + "waifu_divorced_notlike": "You have divorced a waifu who doesn't like you. You received {0} back.", + "waifu_reset": "Your waifu stats have been reset.", + "waifu_reset_fail": "Failed resetting waifu stats. Make sure you have enough currency.", + "waifu_reset_confirm": "This will reset your waifu stats", + "waifu_reset_price": "Price: {0}", + "_8ball": "8ball", + "acrophobia": "Acrophobia", + "acro_ended_no_sub": "Game ended with no submissions.", + "acro_no_votes_cast": "No votes cast. Game ended with no winner.", + "acro_nym_was": "Acronym was {0}.", + "acro_running": "Acrophobia game is already running in this channel.", + "acro_started": "Game started. Create a sentence with the following acronym: {0}.", + "acro_started_footer": "You have {0} seconds to make a submission.", + "acro_vote": "Vote by typing a number of the submission", + "acro_vote_cast": "{0} cast their vote!", + "acro_winner": "Winner is {0} with {1} points.", + "acro_winner_only": "{0} is the winner for being the only user who made a submission!", + "question": "Question", + "rps_draw": "It's a draw! Both picked {0}", + "rps_win": "{0} won! {1} beats {2}", + "submissions_closed": "Submissions closed", + "animal_race_already_started": "Animal Race is already running.", + "category": "Category", + "cleverbot_disabled": "Disabled cleverbot on this server.", + "cleverbot_enabled": "Enabled cleverbot on this server.", + "curgen_disabled": "Currency generation has been disabled on this channel.", + "curgen_enabled": "Currency generation has been enabled on this channel.", + "curgen_pl": "{0} random {1} appeared!", + "curgen_sn": "A random {0} appeared!", + "game_started": "Game started", + "hangman_game_started": "Hangman game started", + "hangman_running": "Hangman game already running on this channel.", + "hangman_types": "List of \"{0}hangman\" term types:", + "leaderboard": "Leaderboard", + "picked": "picked {0}", + "planted": "{0} planted {1}", + "trivia_already_running": "Trivia game is already running on this server.", + "trivia_game": "Trivia Game", + "trivia_guess": "{0} guessed it! The answer was: {1}", + "trivia_none": "No trivia is running on this server.", + "trivia_points": "{0} has {1} points", + "trivia_stopping": "Stopping after this question.", + "trivia_times_up": "Time's up! The correct answer was {0}", + "trivia_win": "{0} guessed it and WON the game! The answer was: {1}", + "trivia_quit": "You can stop trivia by typing {0}", + "trivia_ended": "Trivia game ended", + "ttt_against_yourself": "You can't play against yourself.", + "ttt_already_running": "TicTacToe Game is already running in this channel.", + "ttt_a_draw": "A draw!", + "ttt_created": "has created a game of TicTacToe.", + "ttt_has_won": "{0} has won!", + "ttt_matched_three": "Matched three", + "ttt_no_moves": "No moves left!", + "ttt_time_expired": "Time expired!", + "ttt_users_move": "{0}'s move", + "vs": "{0} vs {1}", + "attempting_to_queue": "Attempting to queue {0} tracks...", + "dir_queue_complete": "Directory queue complete.", + "finished_track": "Track Finished", + "from_position": "From position", + "id": "Id", + "now_playing": "Now playing", + "no_player": "No active music player.", + "no_search_results": "No search results.", + "player_queue": "Player queue - Page {0}/{1}", + "playing_track": "Playing track #{0}", + "playlists": "`#{0}` - **{1}** by *{2}* ({3} tracks)", + "playlists_page": "Page {0} of saved playlists", + "playlist_deleted": "Playlist deleted.", + "playlist_delete_fail": "Failed to delete that playlist. It either doesn't exist, or you are not its author.", + "playlist_id_not_found": "Playlist with that ID doesn't exist.", + "playlist_queue_complete": "Playlist queue complete.", + "playlist_saved": "Playlist saved", + "queue": "Queue", + "queued_track": "Queued track", + "queue_cleared": "Music queue cleared.", + "removed_track": "Removed track", + "repeating_none": "Player will stop once the end of queue is reached.", + "repeating_queue": "Player will repeat the queue.", + "repeating_track": "Player will keep repeating the same track.", + "autoplaying": "Automatically adds related tracks.", + "set_music_channel": "I will now output playing, finished, paused and removed tracks in this channel.", + "unset_music_channel": "I will now output playing, finished, paused and removed tracks of the newly created music players in the channel music was started from.", + "current_music_quality": "Currently set music quality is: {0}", + "music_quality_set": "Music quality has been set to {0}. You will have to destroy and restart music player for the change to take effect.", + "music_autoplay_on": "Music autoplay enabled. I will automatically queue related tracks after each track finishes playing.", + "music_autoplay_off": "Music autoplay disabled.", + "track_moved": "Track moved", + "to_position": "To position", + "volume_input_invalid": "Volume must be between 0 and 100", + "volume_set": "Volume set to {0}%", + "acm_disable": "Disabled usage of ALL MODULES on channel {0}.", + "acm_enable": "Enabled usage of ALL MODULES on channel {0}.", + "arm_disable": "Disabled usage of ALL MODULES for role {0}.", + "arm_enable": "Enabled usage of ALL MODULES for role {0}.", + "asm_disable": "Disabled usage of ALL MODULES on this server.", + "asm_enable": "Enabled usage of ALL MODULES on this server.", + "aum_disable": "Disabled usage of ALL MODULES for user {0}.", + "aum_enable": "Enabled usage of ALL MODULES for user {0}.", + "blacklisted": "Blacklisted {0} with ID {1}", + "blacklisted_users": "Blacklisted Users", + "blacklisted_channels": "Blacklisted Channels", + "blacklisted_servers": "Blacklisted Servers", + "cmdcd_add": "Command {0} now has a {1}s cooldown.", + "cmdcd_cleared": "Command {0} has no cooldown now and all existing cooldowns have been cleared.", + "cmdcd_none": "No command cooldowns set.", + "cx_disable": "Disabled usage of {0} {1} on channel {2}.", + "cx_enable": "Enabled usage of {0} {1} on channel {2}.", + "filter_word_add": "Added word {0} to the list of filtered words.", + "filter_word_list": "List of filtered words", + "filter_word_remove": "Removed word {0} from the list of filtered words.", + "invalid_second_param_between": "Invalid second parameter.(Must be a number between {0} and {1})", + "invite_filter_channel_off": "Invite filtering disabled on this channel.", + "invite_filter_channel_on": "Invite filtering enabled on this channel.", + "invite_filter_server_off": "Invite filtering disabled on this server.", + "invite_filter_server_on": "Invite filtering enabled on this server.", + "link_filter_channel_off": "Link filtering disabled on this channel.", + "link_filter_channel_on": "Link filtering enabled on this channel.", + "link_filter_server_off": "Link filtering disabled on this server.", + "link_filter_server_on": "Link filtering enabled on this server.", + "moved_permission": "Moved permission {0} from #{1} to #{2}", + "perm_not_found": "Can't find permission at index #{0}", + "of_command": "command", + "of_module": "module", + "permrole": "Current permissions role is {0}.", + "permrole_not_set": "Permission role is not set.", + "permrole_reset": "Permission role is reset.", + "permrole_changed": "Users now require {0} role in order to edit permissions.", + "perm_out_of_range": "No permission found on that index.", + "removed": "removed permission #{0} - {1}", + "rx_disable": "Disabled usage of {0} {1} for {2} role.", + "rx_enable": "Enabled usage of {0} {1} for {2} role.", + "sx_disable": "Disabled usage of {0} {1} on this server.", + "sx_enable": "Enabled usage of {0} {1} on this server.", + "unblacklisted": "Unblacklisted {0} with ID {1}", + "uneditable": "uneditable", + "ux_disable": "Disabled usage of {0} {1} for {2} user.", + "ux_enable": "Enabled usage of {0} {1} for {2} user.", + "verbose_false": "I will no longer show permission warnings.", + "verbose_true": "I will now show permission warnings.", + "word_filter_channel_off": "Word filtering disabled on this channel.", + "word_filter_channel_on": "Word filtering enabled on this channel.", + "word_filter_server_off": "Word filtering disabled on this server.", + "word_filter_server_on": "Word filtering enabled on this server.", + "abilities": "Abilities", + "anime_no_fav": "No favorite anime yet", + "atl_removed": "your auto-translate language has been removed.", + "atl_set": "Your auto-translate language has been set to {0}>{1}", + "atl_started": "Started automatic translation of messages on this channel.", + "atl_stopped": "Stopped automatic translation of messages on this channel.", + "atl_not_enabled": "Automatic translation is not enabled on this channel or you've provided an invalid language.", + "bad_input_format": "Bad input format, or something went wrong.", + "card_not_found": "Couldn't find that card.", + "card": "Card", + "guess": "Guess", + "catfact": "fact", + "chapters": "Chapters", + "comic_number": "Comic #", + "comic_not_found": "Comic not found.", + "completed": "Completed", + "condition": "Condition", + "cost": "Cost", + "date": "Date", + "word": "Word", + "_class": "Class", + "definition": "Definition", + "example": "Example", + "dropped": "Dropped", + "episodes": "Episodes", + "error_occured": "Error occurred.", + "api_key_missing": "Api key missing.", + "invalid_input": "Invalid input.", + "not_found": "Not found.", + "failed_finding_anime": "Failed finding that anime.", + "failed_finding_manga": "Failed finding that manga.", + "genres": "Genres", + "authors": "Authors", + "height_weight": "Height/Weight", + "height_weight_val": "{0}m/{1}kg", + "humidity": "Humidity", + "imdb_fail": "Failed to find that movie.", + "invalid_lang": "Invalid source or target language.", + "jokes_not_loaded": "Jokes not loaded.", + "latlong": "Lat/Long", + "list_of_place_tags": "List of {0}place tags", + "location": "Location", + "city_not_found": "City not found.", + "magicitems_not_loaded": "Magic Items not loaded.", + "mal_profile": "{0}'s MAL profile", + "mashape_api_missing": "Bot owner didn't specify MashapeApiKey. You can't use this functionality.", + "min_max": "Min/Max", + "no_channel_found": "No channel found.", + "on_hold": "On-hold", + "original_url": "Original url", + "osu_api_key": "An osu! API key is required.", + "osu_failed": "Failed retrieving osu! signature.", + "osu_user_not_found": "User not found.", + "plan_to_watch": "Plan to watch", + "pokemon_ability_none": "No ability found.", + "pokemon_none": "No pokemon found.", + "rating": "Rating", + "score": "Score:", + "short_url": "Short url", + "something_went_wrong": "Something went wrong.", + "specify_search_params": "Please specify search parameters.", + "status": "Status", + "store_url": "Store url", + "streamer_offline": "Streamer {0} is offline.", + "streamer_online": "Streamer {0} is online with {1} viewers.", + "streams_follow_title": "Streams you're following", + "streams_none": "You are not following any streams on this server.", + "streams_cleared": "All streams followed on this server have been removed.", + "stream_no": "No such stream.", + "stream_off_enabled": "Stream notifications will now show when a stream goes offline.", + "stream_off_disabled": "Stream notifications will no longer show when a stream goes offline.", + "stream_online_delete_enabled": "Online stream notifications will now be deleted when the stream goes offline.", + "stream_online_delete_disabled": "Online stream notifications will no longer be deleted when the stream goes offline.", + "stream_not_added": "Stream was not added. Either stream doesn't exist, that platform is unsupported, or you've reached the maximum number of streams allowed.", + "stream_message_reset": "Announcement message for {0} stream has been reset.", + "stream_message_set": "Announcement message when {0} stream goes online has been set.", + "stream_not_following": "You're not following that stream on this server.", + "stream_removed": "Removed {0}'s stream ({1}) from notifications.", + "stream_tracked": "I will notify this channel whenever this stream comes online.", + "stream_not_following_any": "You're not following any streams.", + "stream_message_set_all": "All {0} followed streams now have the specified announcement message.", + "sunrise": "Sunrise", + "sunset": "Sunset", + "temperature": "Temperature", + "title": "Title:", + "top_3_fav_anime": "Top 3 favorite anime:", + "translation": "Translation:", + "types": "Types", + "ud_error": "Failed finding definition for that term.", + "url": "Url", + "viewers": "Viewers", + "watching": "Watching", + "wikia_error": "Failed finding that term on the specified wikia.", + "wikia_input_error": "Please enter a target wikia, followed by search query.", + "wiki_page_not_found": "Page not found.", + "wind_speed": "Wind speed", + "activity_line": "`{0}.` {1} [{2:F2}/s] - {3} total", + "activity_page": "Activity page #{0}", + "activity_users_total": "{0} users total.", + "author": "Author", + "botid": "Bot ID", + "calcops": "List of functions in {0}calc command", + "channelid": "{0} of this channel is {1}", + "channel_topic": "Channel topic", + "commands_ran": "Commands ran", + "convert": "{0} {1} is equal to {2} {3}", + "convertlist": "Units which can be used by the converter", + "convert_not_found": "Cannot convert {0} to {1}: units not found", + "convert_type_error": "Cannot convert {0} to {1}: types of unit are not equal", + "created_at": "Created at", + "custom_emojis": "Custom emojis", + "error": "Error", + "features": "Features", + "index_out_of_range": "Index out of range.", + "inrole_list": "List of users in {0} role ({1})", + "joined_discord": "Joined Discord", + "joined_server": "Joined server", + "listservers": "ID: {0}\nMembers: {1}\nOwner ID: {2}", + "listservers_none": "No servers found on that page.", + "list_of_repeaters": "List of repeaters", + "members": "Members", + "memory": "Memory", + "messages": "Messages", + "repeater_created": "Repeater Created", + "repeater_removed": "Repeater #{0} Removed", + "repeater_exceed_limit": "You cannot have more than {0} repeaters per server.", + "repeater_remove_fail": "Failed removing repeater on that index. Either you've specified invalid index, or repeater was in executing state at that time, in which case, try again in a few seconds.", + "repeater_skip_next": "Next trigger of this repeater will be skipped.", + "repeater_dont_skip_next": "Next trigger of this repeater won't be skipped.", + "interval_colon": "Interval:", + "executes_in_colon": "Executes in:", + "message_colon": "Message:", + "no_redundant": "Won't post duplicate message.", + "name": "Name", + "nickname": "Nickname", + "nobody_playing_game": "Nobody is playing that game.", + "no_roles_on_page": "No roles on this page.", + "no_shards_on_page": "No shards on this page.", + "no_topic_set": "No topic set.", + "owner": "Owner", + "owner_ids": "Owner IDs", + "presence": "Presence", + "presence_txt": "{0} Servers\n{1} Text Channels\n{2} Voice Channels", + "quotes_deleted": "Deleted all quotes with {0} keyword.", + "quotes_deleted_count": "Deleted {0} quotes.", + "quotes_page": "Page {0} of quotes", + "quotes_page_none": "No quotes found on that page.", + "quotes_remove_none": "No quotes found which you can remove.", + "quote_added_new": "Quote #{0} added.", + "quote_deleted": "Quote #{0} deleted.", + "region": "Region", + "remind": "I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`", + "remind_timely": "I will remind you about your timely reward {0}", + "remind_invalid": "Not a valid remind format. Remind must have a target, timer and a reason. Check the command list.", + "remind_too_long": "Remind time has exceeded maximum.", + "repeater_redundant_no": "Repeater **#{0}** won't post redundant messages anymore.", + "repeater_redundant_yes": "Repeater **#{0}** will post redundant messages from now on.", + "repeaters_none": "No repeaters running on this server.", + "repeat_invoke_none": "No repeating messages found on this server.", + "result": "Result", + "roles": "Roles", + "roles_all_page": "Page #{0} of all roles on this server:", + "roles_page": "Page #{0} of roles for {1}", + "serverid": "{0} of this server is {1}", + "server_info": "Server info", + "shard": "Shard", + "showemojis": "**Name:** {0} **Link:** {1}", + "showemojis_none": "No special emojis found.", + "channels": "Channels", + "text_channels": "Text: {0}", + "voice_channels": "Voice: {0}", + "uptime": "Uptime", + "userid": "{0} of the user {1} is {2}", + "roleid": "{0} of the role {1} is {2}", + "users": "Users", + "current_poll_results": "Current poll results", + "poll_already_running": "Poll is already running on this server.", + "poll_created": "📃 {0} has created a poll", + "poll_result": "`{0}.` {1} with {2} votes.", + "poll_voted": "{0} voted.", + "poll_invalid_input": "Invalid input. You have to have a question and at least 2 answers, all separated by a `;`.", + "x_votes_cast": "{0} total votes cast.", + "pick_pl": "Pick them up by typing `{0}pick`", + "pick_sn": "Pick it up by typing `{0}pick`", + "no_user_on_this_page": "No users on this page.", + "sql_confirm_exec": "Confirm execution of the following SQL command", + "must_be_in_voice": "You need to be in a voice channel on this server.", + "no_vcroles": "There are no voice channel roles.", + "user_muted_time": "{0} has been **muted** from text and voice chat for {1} minutes.", + "user_voice_mute_time": "{0} has been **voice muted** for {1} minutes.", + "user_chat_mute_time": "{0} has been **chat muted** for {1} minutes.", + "vcrole_added": "Users who join {0} voice channel will get {1} role.", + "vcrole_removed": "Users who join {0} voice channel will no longer get a role.", + "vc_role_list": "Voice channel roles", + "option_disabled": "{0} option is now disabled for the expression with id {1}.", + "option_enabled": "{0} option is now enabled for the expression with id {1}.", + "aliases_none": "No alias found", + "alias_added": "Typing {0} will now be an alias of {1}.", + "alias_list": "List of aliases", + "alias_removed": "Trigger {0} no longer has an alias.", + "alias_remove_fail": "Trigger {0} didn't have an alias.", + "channel": "Channel", + "cant_apply_punishment": "Can't apply punishment. Please make sure I have sufficient permissions, and that my role is above any other role in the server settings.", + "punishment_unsupported": "You can't use {0} punishment action with this feature.", + "command_text": "Command Text", + "interval": "Interval", + "kicked_pl": "Kicked", + "moderator": "Moderator", + "page": "page {0}", + "reason": "Reason", + "scadd": "New startup command added.", + "scrm": "Startup command successfully removed.", + "scrm_fail": "Startup command not found.", + "acrm_fail": "Auto command not found on the specified index.", + "autocmd_add": "The command {0} will execute every {1}s in this channel.", + "server": "Server", + "startcmdlist_none": "No startup commands on this page.", + "autocmdlist_none": "No auto commands on this page.", + "startcmds_cleared": "Cleared all startup commands.", + "unbanned_user": "User {0} has been unbanned.", + "user_not_found": "User not found.", + "user_warned": "User {0} has been warned.", + "user_warned_and_punished": "User {0} has been warned and {1} punishment has been applied.", + "warned_on": "Warned on {0} server", + "warned_on_by": "On {0} at {1} by {2}", + "warnings_cleared": "All warnings have been cleared for {0}.", + "warning_clear_fail": "Warning not cleared. Either the warning at that index doesn't exist, or it has already been cleared.", + "warning_cleared": "Warning {0} has been cleared for {1}.", + "warnings_none": "No warning on this page.", + "warn_weight": "Weight: {0}", + "warn_count": "{0} current, {1} total", + "warnlog_for": "Warnlog for {0}", + "warnpl_none": "No punishments set.", + "warn_expire_set_delete": "Warnings will be deleted after {0} days.", + "warn_expire_set_clear": "Warnings will be cleared after {0} days.", + "warn_expire_reset": "Warnings will no longer expire.", + "warns_dont_expire": "Warnings have no expiry set.", + "warns_expire_in": "Warnings will expire in {0} days.", + "warn_cleared_by": "cleared by {0}", + "warn_punish_list": "Warning punishment list", + "warn_punish_rem": "Having {0} warnings will no longer trigger a punishment.", + "warn_punish_set": "I will apply {0} punishment to users with {1} warnings.", + "warn_punish_set_timed": "I will apply {0} punishment for {2} to users with {1} warnings.", + "time_new": "Time", + "timezone": "Timezone", + "timezone_db_api_key": "You need to activate your TimezoneDB API key. You can do so by clicking on the link you've received in the email with your API key.", + "rolehoist_enabled": "Role {0} is now displayed separately from online members.", + "rolehoist_disabled": "Role {0} is no longer displayed separately from online members.", + "shop": "Shop", + "shop_item_add": "Shop item added", + "shop_none": "No shop items found on this page.", + "shop_role": "You will get {0} role.", + "type": "Type", + "gvc_disabled": "Game Voice Channel feature has been disabled on this server.", + "gvc_enabled": "{0} is a Game Voice Channel now.", + "not_in_voice": "You are not in a voice channel on this server.", + "not_with_bot_in_voice": "You are not in the same voice channel as the bot.", + "item": "Item", + "out_of_stock": "Out of stock.", + "random_unique_item": "Random unique item.", + "shop_buy_error": "Error DMing item. You've been refunded.", + "shop_item_not_found": "No item on that index found.", + "shop_item_purchase": "Item purchase successful.", + "shop_item_rm": "Shop item removed", + "shop_item_wrong_type": "That shop entry does not support item adding.", + "shop_list_item_added": "Item successfully added.", + "shop_list_item_not_unique": "That item is already added.", + "shop_purchase": "Purchase on {0} server", + "shop_role_not_found": "Role which is being sold no longer exists.", + "shop_role_already_bought": "You already bought this role.", + "shop_role_purchase": "You've successfully purchased {0} role.", + "shop_role_purchase_error": "Error assigning role. Your purchase has been refunded.", + "shop_item_role_req": "Shop item #{0} will now require users to have a {1} role in order to purchase it.", + "shop_item_req_role_unfulfilled": "You don't have the required role '{0}' in order to buy this shop item.", + "shop_item_req_role_not_found": "The required role for this item doesn't exist anymore. Please contact server administrator.", + "shop_item_requires_role": "Requires {0} role to purchase", + "shop_item_role_no_req": "Shop item #{0} will no longer require a role.", + "unique_items_left": "{0} unique items left.", + "blocked_commands": "Blocked Commands", + "blocked_modules": "Blocked Modules", + "gcmd_add": "Command {0} has been disabled on all servers.", + "gcmd_remove": "Command {0} has been enabled on all servers.", + "gmod_add": "Module {0} has been disabled on all servers.", + "gmod_remove": "Module {0} has been enabled on all servers.", + "lgp_none": "No blocked commands or modules.", + "cant_read_or_send": "You can't read from or send messages to that channel.", + "quotes_notfound": "No quotes found matching the quote ID specified.", + "prefix_current": "Prefix on this server is {0}", + "prefix_new": "Changed prefix on this server from {0} to {1}", + "defprefix_current": "Default bot prefix is {0}", + "defprefix_new": "Changed Default bot prefix from {0} to {1}", + "bot_nick": "Bot's nickname changed to {0}", + "user_nick": "Nickname of the user {0} changed to {1}", + "timezone_guild": "Timezone for this guild is `{0}`", + "timezone_not_found": "Timezone not found. Use \"timezones\" command to see the list of available timezones.", + "timezones_available": "Available Timezones", + "perm_override": "Users will need {0} permission in order to run {1} command.", + "track_not_found": "No track found.", + "define_unknown": "Can't find the definition for that term.", + "verbose_errors_enabled": "Incorrectly used commands will now show errors.", + "verbose_errors_disabled": "Incorrectly used commands will no longer show errors.", + "perms_reset": "Permissions for this server are reset.", + "perm_prevent": "Permission number #{0} {1} is preventing this action.", + "global_perms_reset": "Global permissions have been reset.", + "module": "Module: {0}", + "hangman_stopped": "Hangman game stopped.", + "queue_stopped": "Player is stopped. Use {0} command to start playing.", + "removed_track_error": "Track on that index doesn't exist", + "queue_shuffled": "Music queue has been shuffled.", + "warnings_list": "List of all warned users on the server", + "redacted_too_long": "Redacted because it's too long.", + "blacklisted_tag_list": "List of blacklisted tags:", + "blacklisted_tag_add": "Nsfw tag {0} is now blacklisted.", + "blacklisted_tag_remove": "Nsfw tag {0} is no longer blacklisted.", + "waifu_gift": "Gifted {0} to {1}", + "waifu_gift_not_exist": "That waifu item doesn't exist", + "waifu_gift_shop": "Waifu gift shop", + "gifts": "Gifts", + "fans": "Fans ({0})", + "connect4_created": "Created a Connect4 game. Waiting for a player to join.", + "connect4_created_bet": "Created a Connect4 game and bet {0}. Waiting for a player to join with the same bet.", + "connect4_player_to_move": "Player to move: {0}", + "connect4_failed_to_start": "Connect4 game failed to start because nobody joined.", + "connect4_draw": "Connect4 game ended in a draw.", + "connect4_won": "{0} won the game of Connect4 against {1}.", + "nunchi_joined": "Joined nunchi game. {0} users joined so far.", + "nunchi_ended": "Nunchi game ended. {0} won", + "nunchi_ended_no_winner": "Nunchi game ended with no winner.", + "nunchi_started": "Nunchi game started with {0} participants.", + "nunchi_round_ended": "Nunchi round ended. {0} is out of the game.", + "nunchi_round_ended_boot": "Nunchi round ended due to timeout of some users. These users are still in the game: {0}", + "nunchi_round_started": "Nunchi round started with {0} users. Start counting from the number {1}.", + "nunchi_next_number": "Number registered. Last number was {0}.", + "nunchi_failed_to_start": "Nunchi failed to start because there were not enough participants.", + "nunchi_created": "Nunchi game created. Waiting for users to join.", + "stream_role_enabled": "When a user from {0} role starts streaming, I will give them {1} role.", + "stream_role_disabled": "Stream role feature has been disabled.", + "stream_role_kw_set": "Streamers now require {0} keyword in order to receive the role.", + "stream_role_kw_reset": "Stream role keyword reset.", + "stream_role_bl_add": "User {0} will never receive the stream role.", + "stream_role_bl_add_fail": "User {0} is already blacklisted.", + "stream_role_bl_rem": "User {0} is no longer blacklisted.", + "stream_role_bl_rem_fail": "User {0} is not blacklisted.", + "stream_role_wl_add": "User {0} will receive the stream role even if they don't have the keyword in the stream title.", + "stream_role_wl_add_fail": "User {0} is already whitelisted.", + "stream_role_wl_rem": "User {0} is no longer whitelisted.", + "stream_role_wl_rem_fail": "User {0} is not whitelisted.", + "config_edit_fail": "Failed setting {0} to the value {1}", + "config_not_found": "Configuration {0} not found", + "config_prop_not_found": "Property {0} not found on {1} configuration", + "config_list": "Config list", + "bot_strings_reloaded": "Bot strings have been reloaded.", + "xpn_setting_global": "Global Level-Up notifications", + "xpn_setting_server": "Server Level-Up notifications", + "xpn_notif_channel": "In the channel where you sent the last message.", + "xpn_notif_dm": "In a direct message channel.", + "xpn_notif_disabled": "Nowhere.", + "xprewsreset_confirm": "Are you sure you want to delete ALL xp level up rewards from this server? This action is irreversible.", + "excluded": "{0} has been excluded from the XP system on this server.", + "not_excluded": "{0} is no longer excluded from the XP system on this server.", + "exclusion_list": "Exclusion List", + "server_is_excluded": "This server is excluded.", + "server_is_not_excluded": "This server is not excluded.", + "level_up_channel": "Congratulations {0}, You've reached level {1}!", + "level_up_dm": "Congratulations {0}, You've reached level {1} on {2} server!", + "level_up_global": "Congratulations {0}, You've reached global level {1}!", + "xp_role_reward_cleared": "Reaching level {0} will no longer reward a role.", + "xp_role_reward_add_role": "Users who reach level {0} will receive {1} role.", + "xp_role_reward_remove_role": "Users who reach level {0} will lose {1} role.", + "xp_receive_role": "Receive {0} role.", + "xp_lose_role": "Lose {0} role.", + "xp_shop_disabled": "Xp shop is disabled by the owner, or there are no items for sale.", + "role_not_found": "Role not found: {0}", + "cur_reward_cleared": "Reaching level {0} will no longer reward any {1}.", + "cur_reward_added": "Users who reach level {0} will receive {1}.", + "level_up_rewards": "Level Up Rewards", + "level_x": "Level {0}", + "no_level_up_rewards": "No level up reward on this page.", + "server_leaderboard": "Server XP Leaderboard", + "global_leaderboard": "Global XP Leaderboard", + "modified": "Modified server XP of the user {0} by {1}", + "club_insuff_lvl": "You're insufficient level to join that club.", + "club_join_banned": "You're banned from that club.", + "club_already_in": "You are already a member of a club.", + "club_create_error_name": "Failed creating the club. A club with that name already exists.", + "club_name_too_long": "Club name is too long.", + "club_created": "Club {0} successfully created!", + "club_create_insuff_lvl": "You don't meet the minimum level requirements in order to create a club.", + "club_not_exists": "That club doesn't exist.", + "club_applied": "You've applied for membership in {0} club.", + "club_accepted": "Accepted user {0} to the club.", + "club_rejected": "The application by {0} has been rejected.", + "club_accept_invalid_applicant": "That user has not applied to your club.", + "club_left": "You've left the club.", + "club_not_in_a_club": "You are not in a club.", + "club_owner_cant_leave": "Club owner can't leave the club - you must either transfer ownership or disband the club.", + "club_user_kick": "User {0} kicked from {1} club.", + "club_user_not_in_club": "{0} is not in a club.", + "club_user_banned": "Banned user {0} from {1} club.", + "club_owner_only": "This action can only be performed by the club owner.", + "club_admin_invalid_target": "You can't target yourself or the club owner.", + "club_target_not_member": "Specified user is not a member of your club.", + "club_admin_perms": "You must be a club admin or owner in order to perform this action.", + "club_ban_fail_user_not_found": "That user is not in your club or applied to it.", + "club_ban_fail_unbannable": "Only the club owner can ban club admins.", + "club_user_unbanned": "Unbanned user {0} in {1} club.", + "club_unban_fail_user_not_found": "That user is not banned in this club.", + "club_desc_update": "Club Description Updated", + "club_desc_update_failed": "Failed changing club description.", + "club_disbanded": "Club {0} has been disbanded", + "club_disband_error": "Error. You are either not in a club, or you are not the owner of your club.", + "club_icon_too_large": "Image is too large.", + "club_icon_invalid_filetype": "Specified image has an invalid filetype. Make sure you're specifying a direct image url.", + "club_icon_url_format": "You must specify an absolute image url/.", + "club_icon_set": "New club icon set.", + "club_bans_for": "Bans for {0} club", + "club_apps_for": "Applicants for {0} club", + "club_leaderboard": "Club leaderboard - page {0}", + "club_kick_hierarchy": "Only club owner can kick club admins. Owner can't be kicked.", + "template_reloaded": "Xp template has been reloaded.", + "expr_edited": "Expression Edited", + "self_assign_are_exclusive": "You can only choose 1 role from each group.", + "self_assign_are_not_exclusive": "You can choose any number of roles from any group.", + "self_assign_group": "Group {0}", + "new_reaction_event": "Add {0} reaction to this message to get {1}\n{2} left to be awarded.", + "new_gamestatus_event": "Type the secret code in any channel to receive {1}\n{2} left to be awarded.", + "event_duration_footer": "This event is active for up to {0} hours.", + "start_event_fail": "Event failed to start. Another event is running, or there was an error starting the event.", + "event_title": "{0} event started!", + "poll_closed": "Poll Closed!", + "club_admin_add": "{0} is now a club admin.", + "club_admin_remove": "{0} is no longer club admin.", + "started": "Started. Reposting every {0}s.", + "stopped": "Stopped reposting.", + "feed_added": "Feed added.", + "feed_limit_reached": "You've reached the maximum number of feeds allowed per server.", + "feed_duplicate": "You're already following that feed on this server.", + "feed_cant_parse": "Unable to access or parse that feed url's contents.", + "feed_invalid_url": "Invalid feed url. It must be an absolute http or https url.", + "feed_out_of_range": "Index out of range.", + "feed_removed": "Feed removed.", + "feed_no_feed": "You haven't subscribed to any feeds on this server.", + "restart_fail": "You must setup RestartCommand in your creds.yml", + "restarting": "Restarting.", + "streaming": "Streaming", + "rafflecur": "{0} Currency Raffle", + "rafflecur_joined": "User {0} joined the raffle", + "rafflecur_already_joined": "You have already joined this raffle or the value you used is not valid.", + "rafflecur_ended": "{0} raffle ended. {1} won {2}!", + "autodc_enable": "I will disconnect from the voice channel when there are no more tracks to play.", + "autodc_disable": "I will no longer disconnect from the voice channel when there are no more tracks to play.", + "timely_none": "Bot owner didn't specify a timely reward.", + "timely_already_claimed": "You've already claimed your timely reward. You can get it again {0}.", + "timely": "You've claimed your {0}. You can claim again in {1}h", + "timely_set": "Users will be able to claim {0} every {1}h", + "timely_set_none": "Users will not be able to claim any timely currency.", + "timely_reset": "All users will be able to claim timely currency again.", + "timely_time": "It's time for your timely reward.", + "price": "Price", + "buy": "Buy", + "use": "Use", + "in_use": "In use", + "xp_shop_item_cant_use": "You can't use this item as it doesn't exist or you don't own it.", + "market_cap": "Market Cap", + "market_cap_dominance": "Dominance", + "circulating_supply": "Circulating Supply", + "volume_24h": "Volume (24h)", + "change_7d_24h": "Change (7d / 24h)", + "crypto_not_found": "CryptoCurrency with that name was not found.", + "did_you_mean": "Did you mean {0}?", + "self_assign_level_req": "Self assignable role {0} now requires at least server level {1}.", + "self_assign_not_level": "That self-assignable role requires at least server level {0}.", + "invalid": "Invalid / Can't be found ({0})", + "mass_kill_in_progress": "Mass Banning and Blacklisting of {0} users is in progress...", + "mass_ban_in_progress": "Banning {0} users...", + "mass_ban_completed": "Banned {0} users.", + "mass_kill_completed": "Mass Banning and Blacklisting of {0} users is complete.", + "club_transfered": "Ownership of the club {0} has been transferred to {1}", + "roll_duel_challenge": "challenged {1} for a roll duel for {2}", + "roll_duel": "Roll Duel", + "roll_duel_no_funds": "Either you or your opponent don't have enough funds.", + "roll_duel_timeout": "Roll duel challenge was not accepted.", + "roll_duel_already_challenged": "That user already challenged you to a roll duel.", + "account_not_found": "That account does not exist or is set to private.", + "ninja_not_found": "Currency with that name was not found or an invalid league name was provided.", + "leagues_not_found": "Unable to retrieve data from Path of Exile API.", + "reminder_list": "List of reminders", + "reminder_server_list": "List of server reminders", + "reminder_deleted": "Reminder #{0} was deleted.", + "reminder_not_exist": "Reminder at that index does not exist.", + "reminders_none": "No reminder on this page.", + "perm_override_page_none": "No override on this page.", + "perm_override_all": "All discord permission overrides have been cleared.", + "perm_override_all_confirm": "Are you sure that you want to remove **ALL** discord permission overrides on this server? This action is irreversible.", + "perm_overrides": "Discord Permission Overrides", + "perm_override_reset": "Discord Permission Overrides for this command have been cleared.", + "bj_created": "has created a new BlackJack game in this channel.", + "bj_joined": "has joined the BlackJack game", + "reset": "Xp Reset", + "reset_server_confirm": "Are you sure that you want to reset the XP of all users on the server?", + "reset_user_confirm": "Are you sure that you want to reset specified user's XP on this server?", + "reset_user": "User with id {0} has had their XP reset on this server.", + "reset_server": "XP of all users on the server has been reset.", + "economy_state": "State of the economy", + "currency_owned": "Total currency owned by users", + "currency_one_percent": "% of currency owned by top 1%", + "currency_planted": "Currency currently planted", + "owned_waifus_total": "Total value of owned waifus", + "bot_currency": "Currency owned by the bot", + "total": "Total", + "bank_accounts": "Bank Accounts", + "no_invites": "No invites on this page.", + "invite_deleted": "Invite {0} has been deleted.", + "group_name_added": "Group #{0} now has a name: {1}", + "group_name_removed": "Group #{0} no longer has a name.", + "quote_id": "Quote {0}", + "trigger": "Trigger", + "response": "Response", + "created_by": "Created by {0}", + "module_footer": "{0}cmds {1}", + "module_page_empty": "No module on this page.", + "module_description_help": "Get command help, descriptions and usage examples", + "module_description_gambling": "Bet on dice rolls, blackjack, slots, coinflips and others", + "module_description_games": "Play trivia, nunchi, hangman, connect4 and other games", + "module_description_nsfw": "NSFW commands.", + "module_description_music": "Play music from youtube, local files soundcloud and radio streams", + "module_description_utility": "Manage custom quotes, repeating messages and check facts about the server", + "module_description_administration": "Moderation, punish users, setup self assignable roles and greet messages", + "module_description_expressions": "Setup custom bot responses to certain words or phrases", + "module_description_permissions": "Setup perms for commands, filter words and set up command cooldowns", + "module_description_searches": "Search for jokes, images of animals, anime and manga", + "module_description_xp": "Gain xp based on chat activity, check users' xp cards", + "module_description_marmalade": "**Bot Owner only.** Load, unload and handle dynamic modules. Read more [here](https://docs.elliebot.net/v4/)", + "module_description_missing": "Description is missing for this module.", + "purge_user_confirm": "Are you sure that you want to purge {0} from the database?", + "expr_import_no_input": "Invalid input. No valid file upload or input text found.", + "expr_import_invalid_data": "Unable to parse the file. Make sure it's a valid .yml file", + "inv_expire": "Expires in:", + "inv_uses": "Uses:", + "empty_page": "This page is empty.", + "pages": "Pages", + "favorites": "Favorites", + "tags": "Tags", + "imageonly_enable": "This channel is now image-only.", + "linkonly_enable": "This channel is now link-only.", + "imageonly_disable": "This channel is no longer image-only.", + "linkonly_disable": "This channel is no longer link-only.", + "deleted_x_servers": "Deleted {0} servers.", + "curtr_gift": "Gift from {0} [{1}]", + "curtr_award": "Awarded by bot owner {0} [{1}]", + "curtr_take": "Taken by bot owner {0} [{1}]", + "list_of_marmalades": "List of Marmalades", + "list_of_unloaded": "List of Available Marmalades", + "marmalade_name_not_found": "Marmalade with that name doesn't exist or isn't loaded.", + "marmalade_info": "Marmalade Information", + "canaries_count": "Canaries ({0})", + "commands_count": "Commands ({0})", + "no_marmalade_loaded": "There are no loaded marmalades.", + "no_marmalade_available": "No marmalade available.", + "loaded_marmalades": "Loaded Marmaladee", + "marmalade_not_loaded": "Marmalade with that name is not loaded.", + "marmalade_possibly_cant_unload": "Marmalade is probably not fully unloaded. Please restart the bot if issues arise.", + "marmalade_loaded": "Marmalade {0} has been loaded.", + "marmalade_unloaded": "Marmalade {0} has been unloaded.", + "marmalade_empty": "Marmalade wasn't loaded as it didn't contain any Canaries.", + "marmalade_already_loaded": "Marmalade {0} is already loaded", + "marmalade_invalid_not_found": "Marmalade with that name wasn't found or the file was invalid", + "bank_balance": "You have {0} in your bank account.", + "bank_deposited": "You deposited {0} to your bank account.", + "bank_withdrew": "You withdrew {0} from your bank account.", + "bank_withdraw_insuff": "You don't have sufficient {0} in your bank account.", + "cmd_group_commands": "'{0}' command group", + "limit_reached": "Feature limit of {0} reached.", + "feature_limit_reached_you": "You've reached the limit of {0} for the {1} feature. You may be able to increase this limit by upgrading your patron tier.", + "feature_limit_reached_owner": "Server owner has reached the limit of {0} for the {1} feature. Server owner may be able to upgrade this limit by upgrading patron tier.", + "feature_limit_reached_either": "The limit of {0} for the {1} feature has been reached. Either you or the server owner may able to upgrade this limit by upgrading the patron tier.", + "xp_shop_buy_required_tier": "Buying items from this shop requires Patron Tier {0} or higher.", + "available_commands": "Available Commands", + "tier": "Tier", + "pledge": "Pledge", + "expires": "Expires", + "commands": "Commands", + "groups": "Groups", + "modules": "Modules", + "no_quota_found": "No quota found", + "patron_info": "Patron Info", + "quotas": "<<< Quotas >>>", + "patron_not_enabled": "Patron system is disabled.", + "results_in": "{0} results in {1}s", + "patron_msg_sent": "Done sending messages to patrons at and above tier {1}. {1} successfully sent and {2} failed.", + "xpadd_users": "Added {0} server XP to {1} users.", + "xpshop_buy_success": "Successfully purchased `{0}/{1}`", + "patron_insuff_tier": "Your Patron Tier insufficient to perform this action.", + "xpshop_already_owned": "You already own this item.", + "xpshop_item_not_found": "An item with that key doesn't exist.", + "xpshop_website": "You can see the list of all Xp Shop items here: ", + "sticker_invalid_size": "Stickers must be exactly 300x300 pixels.", + "sticker_error": "You must either send a sticker along with this command, or upload a 300x300 .png or .apng image.", + "sticker_missing_name": "Please specify a name for the sticker.", + "thread_deleted": "Thread Deleted", + "thread_created": "Thread Created", + "supported_languages": "Supported Languages", + "cache_users_pending": "Updating users, please wait...", + "cache_users_done": "{0} users were added and {1} users were updated." +} \ No newline at end of file diff --git a/src/EllieBot/data/trivia_questions.json b/src/EllieBot/data/trivia_questions.json new file mode 100644 index 0000000..cfc35ba --- /dev/null +++ b/src/EllieBot/data/trivia_questions.json @@ -0,0 +1,48987 @@ +[ + { + "Category": "HISTORY", + "Question": "For the last 8 years of his life, Galileo was under house arrest for espousing this man's theory", + "Answer": "Copernicus" + }, + { + "Category": "ESPN's TOP 10 ALL-TIME ATHLETES", + "Question": "No. 2: 1912 Olympian; football star at Carlisle Indian School; 6 MLB seasons with the Reds, Giants & Braves", + "Answer": "Jim Thorpe" + }, + { + "Category": "EVERYBODY TALKS ABOUT IT...", + "Question": "The city of Yuma in this state has a record average of 4,055 hours of sunshine each year", + "Answer": "Arizona" + }, + { + "Category": "THE COMPANY LINE", + "Question": "In 1963, live on \"The Art Linkletter Show\", this company served its billionth burger", + "Answer": "McDonald's" + }, + { + "Category": "EPITAPHS & TRIBUTES", + "Question": "Signer of the Dec. of Indep., framer of the Constitution of Mass., second President of the United States", + "Answer": "John Adams" + }, + { + "Category": "3-LETTER WORDS", + "Question": "In the title of an Aesop fable, this insect shared billing with a grasshopper", + "Answer": "the ant" + }, + { + "Category": "HISTORY", + "Question": "Built in 312 B.C. to link Rome & the South of Italy, it's still in use today", + "Answer": "the Appian Way" + }, + { + "Category": "ESPN's TOP 10 ALL-TIME ATHLETES", + "Question": "No. 8: 30 steals for the Birmingham Barons; 2,306 steals for the Bulls", + "Answer": "Michael Jordan" + }, + { + "Category": "EVERYBODY TALKS ABOUT IT...", + "Question": "In the winter of 1971-72, a record 1,122 inches of snow fell at Rainier Paradise Ranger Station in this state", + "Answer": "Washington" + }, + { + "Category": "THE COMPANY LINE", + "Question": "This housewares store was named for the packaging its merchandise came in & was first displayed on", + "Answer": "Crate & Barrel" + }, + { + "Category": "EPITAPHS & TRIBUTES", + "Question": "\"And away we go\"", + "Answer": "Jackie Gleason" + }, + { + "Category": "3-LETTER WORDS", + "Question": "Cows regurgitate this from the first stomach to the mouth & chew it again", + "Answer": "the cud" + }, + { + "Category": "HISTORY", + "Question": "In 1000 Rajaraja I of the Cholas battled to take this Indian Ocean island now known for its tea", + "Answer": "Ceylon" + }, + { + "Category": "ESPN's TOP 10 ALL-TIME ATHLETES", + "Question": "No. 1: Lettered in hoops, football & lacrosse at Syracuse & if you think he couldn't act, ask his 11 \"unclean\" buddies", + "Answer": "Jim Brown" + }, + { + "Category": "EVERYBODY TALKS ABOUT IT...", + "Question": "On June 28, 1994 the nat'l weather service began issuing this index that rates the intensity of the sun's radiation", + "Answer": "the UV index" + }, + { + "Category": "THE COMPANY LINE", + "Question": "This company's Accutron watch, introduced in 1960, had a guarantee of accuracy to within one minute a month", + "Answer": "Bulova" + }, + { + "Category": "EPITAPHS & TRIBUTES", + "Question": "Outlaw: \"Murdered by a traitor and a coward whose name is not worthy to appear here\"", + "Answer": "Jesse James" + }, + { + "Category": "3-LETTER WORDS", + "Question": "A small demon, or a mischievous child (who might be a little demon!)", + "Answer": "imp" + }, + { + "Category": "HISTORY", + "Question": "Karl led the first of these Marxist organizational efforts; the second one began in 1889", + "Answer": "the International" + }, + { + "Category": "ESPN's TOP 10 ALL-TIME ATHLETES", + "Question": "No. 10: FB/LB for Columbia U. in the 1920s; MVP for the Yankees in '27 & '36; \"Gibraltar in Cleats\"", + "Answer": "Gehrig" + }, + { + "Category": "EVERYBODY TALKS ABOUT IT...", + "Question": "Africa's lowest temperature was 11 degrees below zero in 1935 at Ifrane, just south of Fez in this country", + "Answer": "Morocco" + }, + { + "Category": "THE COMPANY LINE", + "Question": "Edward Teller & this man partnered in 1898 to sell high fashions to women", + "Answer": "Bonwit" + }, + { + "Category": "EPITAPHS & TRIBUTES", + "Question": "1939 Oscar winner: \"...you are a credit to your craft, your race and to your family\"", + "Answer": "Hattie McDaniel" + }, + { + "Category": "3-LETTER WORDS", + "Question": "In geologic time one of these, shorter than an eon, is divided into periods & subdivided into epochs", + "Answer": "era" + }, + { + "Category": "HISTORY", + "Question": "This Asian political party was founded in 1885 with \"Indian National\" as part of its name", + "Answer": "the Congress Party" + }, + { + "Category": "ESPN's TOP 10 ALL-TIME ATHLETES", + "Question": "No. 5: Only center to lead the NBA in assists; track scholarship to Kansas U.; marathoner; volleyballer", + "Answer": "Chamberlain" + }, + { + "Category": "THE COMPANY LINE", + "Question": "The Kirschner brothers, Don & Bill, named this ski company for themselves & the second-highest mountain", + "Answer": "K2" + }, + { + "Category": "EPITAPHS & TRIBUTES", + "Question": "Revolutionary War hero: \"His spirit is in Vermont now\"", + "Answer": "Ethan Allen" + }, + { + "Category": "3-LETTER WORDS", + "Question": "A single layer of paper, or to perform one's craft diligently", + "Answer": "ply" + }, + { + "Category": "PRESIDENTIAL STATES OF BIRTH", + "Question": "California", + "Answer": "Nixon" + }, + { + "Category": "AIRLINE TRAVEL", + "Question": "It can be a place to leave your puppy when you take a trip, or a carrier for him that fits under an airplane seat", + "Answer": "a kennel" + }, + { + "Category": "THAT OLD-TIME RELIGION", + "Question": "He's considered the author of the Pentateuch, which is hard to believe, as Deuteronomy continues after his death", + "Answer": "Moses" + }, + { + "Category": "MUSICAL TRAINS", + "Question": "Steven Tyler of this band lent his steamin' vocals to \"Train Kept A-Rollin'\", first popularized by the Yardbirds", + "Answer": "Aerosmith" + }, + { + "Category": "\"X\"s & \"O\"s", + "Question": "Around 100 A.D. Tacitus wrote a book on how this art of persuasive speaking had declined since Cicero", + "Answer": "oratory" + }, + { + "Category": "PRESIDENTIAL STATES OF BIRTH", + "Question": "1 of the 2 born in Vermont", + "Answer": "Coolidge" + }, + { + "Category": "AIRLINE TRAVEL", + "Question": "When it began on Pan Am & Qantas in the late '70s, it was basically a roped-off part of the economy cabin with free drinks", + "Answer": "business class" + }, + { + "Category": "THAT OLD-TIME RELIGION", + "Question": "Ali, who married this man's daughter Fatima, is considered by Shia Muslims to be his true successor", + "Answer": "Muhammed" + }, + { + "Category": "MUSICAL TRAINS", + "Question": "During the 1954-1955 Sun sessions, Elvis climbed aboard this train \"sixteen coaches long\"", + "Answer": "the \"Mystery Train\"" + }, + { + "Category": "AIRLINE TRAVEL", + "Question": "In 2003 this airline agreed to buy KLM, creating Europe's largest airline", + "Answer": "Air France" + }, + { + "Category": "THAT OLD-TIME RELIGION", + "Question": "Philadelphia got its start as a colony for this religious group of which William Penn was a member", + "Answer": "the Quakers" + }, + { + "Category": "MUSICAL TRAINS", + "Question": "This \"Modern Girl\" first hit the Billboard Top 10 with \"Morning Train (Nine To Five)\"", + "Answer": "Easton" + }, + { + "Category": "\"X\"s & \"O\"s", + "Question": "This stiff silken fabric is favored for bridal gowns, like Christina Applegate's in 2001", + "Answer": "organza" + }, + { + "Category": "AIRLINE TRAVEL", + "Question": "In 2004 United launched this new service that features low fares & more seats per plane", + "Answer": "Ted" + }, + { + "Category": "THAT OLD-TIME RELIGION", + "Question": "With Mary I's accession in 1553 he ran to Geneva; he returned in 1559 & reformed the Church of Scotland", + "Answer": "Knox" + }, + { + "Category": "MUSICAL TRAINS", + "Question": "This band's \"Train In Vain\" was a hidden track on its original 1979 \"London Calling\" album", + "Answer": "The Clash" + }, + { + "Category": "\"X\"s & \"O\"s", + "Question": "Cross-country skiing is sometimes referred to by these 2 letters, the same ones used to denote 90 in Roman numerals", + "Answer": "XC" + }, + { + "Category": "AIRLINE TRAVEL", + "Question": "In the seat pocket you'll find the catalog called \"Sky\" this, with must-haves like a solar-powered patio umbrella", + "Answer": "Mall" + }, + { + "Category": "THAT OLD-TIME RELIGION", + "Question": "In 1534 he & his buddy Francis Xavier founded the Society of Jesus", + "Answer": "Loyola" + }, + { + "Category": "MUSICAL TRAINS", + "Question": "In 1961 James Brown announced \"all aboard\" for this train", + "Answer": "\"Night Train\"" + }, + { + "Category": "\"X\"s & \"O\"s", + "Question": "This 1797 imbroglio began when 3 French agents demanded a huge bribe from U.S. diplomats", + "Answer": "the XYZ Affair" + }, + { + "Category": "THE SOLAR SYSTEM", + "Question": "Objects that pass closer to the sun than Mercury have been named for this mythological figure", + "Answer": "Icarus" + }, + { + "Category": "GEOGRAPHY \"E\"", + "Question": "It's the largest kingdom in the United Kingdom", + "Answer": "England" + }, + { + "Category": "RADIO DISNEY", + "Question": "\"Party In The U.S.A.\" is by this singer who also plays a young lady named Hannah", + "Answer": "Miley Cyrus" + }, + { + "Category": "PARTS OF PEACH", + "Question": "If this part of a peach is downy or fuzzy, the fruit's called a peach; if it's smooth, a nectarine", + "Answer": "the skin" + }, + { + "Category": "BE FRUITFUL & MULTIPLY", + "Question": "4 x 12", + "Answer": "48" + }, + { + "Category": "LET'S BOUNCE", + "Question": "This verb for bouncing a basketball sounds like you're slobbering", + "Answer": "dribbling" + }, + { + "Category": "RHYMES WITH SMART", + "Question": "Blood pumper", + "Answer": "heart" + }, + { + "Category": "RADIO DISNEY", + "Question": "\"Everybody Else\" knows these huggable toys precede \"On Fire\" in the name of a Radio Disney top 30 band; do you?", + "Answer": "Care Bears" + }, + { + "Category": "PARTS OF PEACH", + "Question": "Peaches are more than 80% this compound", + "Answer": "H2O" + }, + { + "Category": "BE FRUITFUL & MULTIPLY", + "Question": "7 x 7 x 2", + "Answer": "98" + }, + { + "Category": "LET'S BOUNCE", + "Question": "Sound navigation& ranging is the full name for this device that bounces radio waves underwater", + "Answer": "sonar" + }, + { + "Category": "RHYMES WITH SMART", + "Question": "Small, slender missile thrown at a board in a game", + "Answer": "a dart" + }, + { + "Category": "GEOGRAPHY \"E\"", + "Question": "This island in the South Pacific is named for the day of its discovery, a religious holiday", + "Answer": "Easter Island" + }, + { + "Category": "RADIO DISNEY", + "Question": "\"The songs on 'Under My Skin' are...deeper than those on 'Let Go'\" said this Canadian on Radio Disney's website", + "Answer": "Avril Lavigne" + }, + { + "Category": "PARTS OF PEACH", + "Question": "5-letter word for the hard interior of a peach", + "Answer": "the stone" + }, + { + "Category": "BE FRUITFUL & MULTIPLY", + "Question": "3 x 4 x 5 x 6", + "Answer": "360" + }, + { + "Category": "LET'S BOUNCE", + "Question": "In this kid's game, you bounce a small rubber ball while picking up 6-pronged metal objects", + "Answer": "jacks" + }, + { + "Category": "RHYMES WITH SMART", + "Question": "It can be a separating line in your hair or a role in a play", + "Answer": "a part" + }, + { + "Category": "GEOGRAPHY \"E\"", + "Question": "Parts of the Arabian and Libyan deserts are found in this African country", + "Answer": "Egypt" + }, + { + "Category": "RADIO DISNEY", + "Question": "\"I Never Told You\" this alliteratively named singer hit Disney's Top 30 with \"Fallin' For You\"; wait, I just did", + "Answer": "Colbie Caillat" + }, + { + "Category": "PARTS OF PEACH", + "Question": "These parts of a peach tree are glossy green, pointed & lance shaped", + "Answer": "leaves" + }, + { + "Category": "BE FRUITFUL & MULTIPLY", + "Question": "5 x 10 x 15", + "Answer": "750" + }, + { + "Category": "LET'S BOUNCE", + "Question": "It's a type of bounce house, or a dance made famous by Michael Jackson", + "Answer": "the moonwalk" + }, + { + "Category": "RHYMES WITH SMART", + "Question": "A graphic representation of information", + "Answer": "a chart" + }, + { + "Category": "GEOGRAPHY \"E\"", + "Question": "The family history you wrote for school might include entering the U.S. at this island in New York Bay", + "Answer": "Ellis Island" + }, + { + "Category": "RADIO DISNEY", + "Question": "Lead singer Ryan Tedder of this band has \"All The Right Moves\"", + "Answer": "OneRepublic" + }, + { + "Category": "PARTS OF PEACH", + "Question": "These parts of a peach tree grow at nodes along the shoots of the previous season's growth; they're usually pink", + "Answer": "blossoms" + }, + { + "Category": "BE FRUITFUL & MULTIPLY", + "Question": "2 x 1,035", + "Answer": "2,070" + }, + { + "Category": "LET'S BOUNCE", + "Question": "This device whose name is from the Italian for \"springboard\" was perfected in the 1930s", + "Answer": "a trampoline" + }, + { + "Category": "RHYMES WITH SMART", + "Question": "Composer Wolfgang", + "Answer": "Mozart" + }, + { + "Category": "SCIENCE CLASS", + "Question": "99.95% of the mass of an atom is in this part", + "Answer": "the nucleus" + }, + { + "Category": "KIDS IN SPORTS", + "Question": "Park View of Chula Vista, California beat Taipei 6-3 to win this organization's 2009 World Series", + "Answer": "the Little League" + }, + { + "Category": "JUST THE FACTS", + "Question": "This hero of several books is 11 when he discovers he's a wizard", + "Answer": "Harry Potter" + }, + { + "Category": "NEWS TO ME", + "Question": "A 7.0 magnitude earthquake in this Caribbean country Jan. 12, 2010 brought a world outpouring of aid", + "Answer": "Haiti" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "It's the 4-letter name of the pleated skirt worn by men in Scotland", + "Answer": "a kilt" + }, + { + "Category": "SCIENCE CLASS", + "Question": "During this plant process, carbon dioxide & water combine with light energy to create oxygen & glucose", + "Answer": "photosynthesis" + }, + { + "Category": "KIDS IN SPORTS", + "Question": "The perfect waves of New Zealand's Piha Beach were the site for the 2010 World Junior Championships of this", + "Answer": "surfing" + }, + { + "Category": "JUST THE FACTS", + "Question": "This city, the seat of Clark County, Nevada, has been called \"the entertainment capital of the world\"", + "Answer": "Las Vegas" + }, + { + "Category": "NEWS TO ME", + "Question": "This car company has been in the news for widespread recalls of its Corollas & other models", + "Answer": "Toyota" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "As an adjective, it can mean proper; as a verb, \"to grade papers\"", + "Answer": "correct" + }, + { + "Category": "SCIENCE CLASS", + "Question": "The wedge is an adaptation of the simple machine called the inclined this", + "Answer": "plane" + }, + { + "Category": "KIDS IN SPORTS", + "Question": "With a mighty leap of 5'1\", David Mosely set the U.S. 10 & under record in this event back in 1977", + "Answer": "the high jump" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "Maize is another word for this", + "Answer": "corn" + }, + { + "Category": "SCIENCE CLASS", + "Question": "Of the 6 noble gases on the periodic table, it is the lightest", + "Answer": "helium" + }, + { + "Category": "KIDS IN SPORTS", + "Question": "11-year-old Ashlyn White won a 2009 U.S. youth title in this martial art in which you try to throw your opponent", + "Answer": "judo" + }, + { + "Category": "JUST THE FACTS", + "Question": "In 1751 the Penn Provincial Assembly placed the order for this symbol of freedom, now in Philadelphia", + "Answer": "the Liberty Bell" + }, + { + "Category": "NEWS TO ME", + "Question": "In a surprise, Ted Kennedy's old Senate seat in this state went to a Republican in a January 2010 election", + "Answer": "Massachusetts" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This word for someone who walks comes from the Latin for \"foot\"", + "Answer": "pedestrian" + }, + { + "Category": "SCIENCE CLASS", + "Question": "Lava & igneous rock are formed from this hot liquid rock material found under the earth's crust", + "Answer": "magma" + }, + { + "Category": "KIDS IN SPORTS", + "Question": "This sport has an under-17 World Cup every 2 years; Haris Seferovic starred for the 2009 champion Switzerland", + "Answer": "soccer" + }, + { + "Category": "JUST THE FACTS", + "Question": "He's the older son of Prince Charles and the late Princess Diana", + "Answer": "Prince William" + }, + { + "Category": "NEWS TO ME", + "Question": "Falcon Heene, who it turned out was safe at home, not flying over Colorado, became known as this \"boy\"", + "Answer": "the balloon boy" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "Kayak is an example of this, a word that reads the same forwards & backwards", + "Answer": "a palindrome" + }, + { + "Category": "HISTORIC WOMEN", + "Question": "She was born in Virginia around 1596 & died in Kent, England in 1617", + "Answer": "Pocahontas" + }, + { + "Category": "ROYAL FEMALE NICKNAMES", + "Question": "Prime Minister Tony Blair dubbed her \"The People's Princess\"", + "Answer": "Princess Diana" + }, + { + "Category": "TV ACTORS & ROLES", + "Question": "Once Tommy Mullaney on \"L.A. Law\", John Spencer now plays White House chief of staff Leo McGarry on this series", + "Answer": "The West Wing" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "The Cinderella Castle Mystery Tour is a highlight of this Asian city's Disneyland", + "Answer": "Tokyo" + }, + { + "Category": "\"I\" LADS", + "Question": "This punk rock hitmaker heard here has had numerous hits on both sides of the Atlantic", + "Answer": "Billy Idol" + }, + { + "Category": "FOREWORDS", + "Question": "\"Conrad begins (and ends) Marlow's journey... on the Thames, on the yawl, Nellie\", says the foreword to this novel", + "Answer": "Heart of Darkness" + }, + { + "Category": "BACKWORDS", + "Question": "We'll look smart in these vehicles that returned to London in 1999", + "Answer": "Trams" + }, + { + "Category": "ROYAL FEMALE NICKNAMES", + "Question": "She was \"The Untamed Heifer\" & \"The Virgin Queen\"", + "Answer": "Elizabeth I" + }, + { + "Category": "TV ACTORS & ROLES", + "Question": "Barbra Streisand knows he played Lt. Col. Bill \"Raider\" Kelly on \"Pensacola: Wings of Gold\"", + "Answer": "James Brolin" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "The home of silk merchant Jim Thompson, who disappeared in 1967, is a tourist attraction in this Thai city", + "Answer": "Bangkok" + }, + { + "Category": "\"I\" LADS", + "Question": "Czar at 17, he was famous for extraordinary sadism & cruelty, even as a boy", + "Answer": "Ivan the Terrible" + }, + { + "Category": "FOREWORDS", + "Question": "Part 2 \"is Lilliput in reverse, but...also offers some of\" his \"fiercest assaults upon the behavior of\" his countrymen", + "Answer": "Jonathan Swift" + }, + { + "Category": "BACKWORDS", + "Question": "Ed leaves pools of water on the carpet when he comes in from sailing this boat", + "Answer": "Sloop" + }, + { + "Category": "ROYAL FEMALE NICKNAMES", + "Question": "Mark Antony called her \"The Queen of Queens\"", + "Answer": "Cleopatra" + }, + { + "Category": "TV ACTORS & ROLES", + "Question": "(Hi, I'm Wallace Langham) I played Don Kirshner in VH1's TV movie about this quartet who sang \"Daydream Believer\"", + "Answer": "The Monkees" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "We're not stringing you along: this capital of the Czech Republic is famous for its puppet theatres", + "Answer": "Prague" + }, + { + "Category": "\"I\" LADS", + "Question": "Nudge, nudge, wink, wink! This man seen here starred on a classic British comedy show", + "Answer": "Eric Idle" + }, + { + "Category": "FOREWORDS", + "Question": "She said that her husband Frank O'Connor was the fuel that kept her spirited while she wrote \"The Fountainhead\"", + "Answer": "Ayn Rand" + }, + { + "Category": "BACKWORDS", + "Question": "You'd be naive to think you can make bottled water that's more popular than this", + "Answer": "Evian" + }, + { + "Category": "ROYAL FEMALE NICKNAMES", + "Question": "The 19th century's \"Widow of Windsor\"", + "Answer": "Queen Victoria" + }, + { + "Category": "TV ACTORS & ROLES", + "Question": "Teri Hatcher looked \"shipshape\" as one of the singing \"mermaids\" who jumped on board this cruisin' series in 1985", + "Answer": "The Love Boat" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "Jomo Kenyatta International Airport serves this world capital", + "Answer": "Nairobi, Kenya" + }, + { + "Category": "\"I\" LADS", + "Question": "His is the first & longest book of the Bible's major prophets", + "Answer": "Isaiah" + }, + { + "Category": "FOREWORDS", + "Question": "One edition calls this Darwin opus one of \"the most readable and approachable\" of revolutionary scientific works", + "Answer": "The Origin of Species" + }, + { + "Category": "BACKWORDS", + "Question": "Aye, lass, I'll wed thee ere this has dried on the fields", + "Answer": "Dew" + }, + { + "Category": "ROYAL FEMALE NICKNAMES", + "Question": "\"The Catholic\" of 15th century Spain", + "Answer": "Queen Isabella" + }, + { + "Category": "TV ACTORS & ROLES", + "Question": "On \"Saturday Night Live\", he's famous for playing Craig the Cheerleader, Janet Reno & moi", + "Answer": "Will Ferrell" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "Andrea Palladio's 1554 book on \"The Antiquities of\" this city was the standard guidebook for some 200 years", + "Answer": "Rome" + }, + { + "Category": "\"I\" LADS", + "Question": "This auto exec's autobiography is one of the bestselling nonfiction works in publishing history", + "Answer": "Lee Iacocca" + }, + { + "Category": "BACKWORDS", + "Question": "You know so much about policy, you qualify as this", + "Answer": "Wonk" + }, + { + "Category": "PEOPLE IN HISTORY", + "Question": "After a 15-year stay in England, this proprietor of Pennsylvania returned to his colony in 1699", + "Answer": "William Penn" + }, + { + "Category": "CINEMATIC DICTIONARY", + "Question": "SFX is the standard abbreviation for these, from the rustling of trees to cannon fire", + "Answer": "Sound effects" + }, + { + "Category": "IT'S OURS!", + "Question": "Saint-Pierre & Miquelon", + "Answer": "France" + }, + { + "Category": "BRITISH FASHION", + "Question": "Designer Vivienne Westwood ran a shop with Malcolm McLaren, who launched this Johnny Rotten band", + "Answer": "The Sex Pistols" + }, + { + "Category": "ANDY WARHOL", + "Question": "Because he had the same thing for lunch every day for 20 years, Andy Warhol painted these, beginning in 1962", + "Answer": "Campbell's Soup cans" + }, + { + "Category": "THEATRE CROSSWORD CLUES \"M\"", + "Question": "Lerner & Loewe's \"Lusty Month\" (3)", + "Answer": "May" + }, + { + "Category": "PEOPLE IN HISTORY", + "Question": "This young man put his savings into a small Cleveland refinery in 1862 & eventually had an oil monopoly", + "Answer": "John D. Rockefeller" + }, + { + "Category": "CINEMATIC DICTIONARY", + "Question": "Term for the flow of a film, maintained by keeping details consistent throughout a scene", + "Answer": "Continuity" + }, + { + "Category": "IT'S OURS!", + "Question": "Montserrat", + "Answer": "Great Britain" + }, + { + "Category": "BRITISH FASHION", + "Question": "Star designer John Galliano was born Juan Carlos Galliano in this British possession at the tip of Spain", + "Answer": "Gibraltar" + }, + { + "Category": "ANDY WARHOL", + "Question": "Warhol went against his Capitalist tendencies with his portrait of this man, seen here", + "Answer": "Mao Tse-tung" + }, + { + "Category": "THEATRE CROSSWORD CLUES \"M\"", + "Question": "Patrick Dennis' \"Auntie\" (4)", + "Answer": "Mame" + }, + { + "Category": "PEOPLE IN HISTORY", + "Question": "First Lady Helen Taft led a fund-raising drive for a memorial to this 1912 marine disaster", + "Answer": "Sinking of the Titanic" + }, + { + "Category": "CINEMATIC DICTIONARY", + "Question": "Garland Jeffreys sang of having star-studded \"dreams\" of this size, like movie film", + "Answer": "35mm" + }, + { + "Category": "IT'S OURS!", + "Question": "Cook Islands", + "Answer": "New Zealand" + }, + { + "Category": "BRITISH FASHION", + "Question": "Katharine Hamnett created the '80s T-shirt telling us to \"choose\" this", + "Answer": "Life" + }, + { + "Category": "ANDY WARHOL", + "Question": "Andy's \"15 minutes of fame\" quote was once the motto of this magazine", + "Answer": "Interview" + }, + { + "Category": "THEATRE CROSSWORD CLUES \"M\"", + "Question": "It \"Becomes Electra\" (8)", + "Answer": "Mourning" + }, + { + "Category": "PEOPLE IN HISTORY", + "Question": "This Chiricahua Apache was a popular attraction at the 1904 World's Fair in St. Louis", + "Answer": "Geronimo" + }, + { + "Category": "CINEMATIC DICTIONARY", + "Question": "The inventors of this camera-stabilizing device won a special 1977 Oscar", + "Answer": "Steadicam" + }, + { + "Category": "IT'S OURS!", + "Question": "Madeira Islands", + "Answer": "Portugal" + }, + { + "Category": "ANDY WARHOL", + "Question": "Andy's loft on East 47th Street got this nickname from its former use & Andy's mass-production techniques", + "Answer": "The Factory" + }, + { + "Category": "THEATRE CROSSWORD CLUES \"M\"", + "Question": "Colchian jilted by Jason (5)", + "Answer": "Medea" + }, + { + "Category": "PEOPLE IN HISTORY", + "Question": "In 1801 this onetime VP compiled \"A Manual of Parliamentary Practice\" still used in the U.S. Senate", + "Answer": "Thomas Jefferson" + }, + { + "Category": "CINEMATIC DICTIONARY", + "Question": "Near the end of the credits comes the \"cutter\" of this, the exposed but unfinished film", + "Answer": "Negative cutter" + }, + { + "Category": "IT'S OURS!", + "Question": "Northern Mariana Islands", + "Answer": "USA" + }, + { + "Category": "ANDY WARHOL", + "Question": "Warhol became the manager of this Lou Reed rock group in 1965 & produced their first album", + "Answer": "Velvet Underground" + }, + { + "Category": "THEATRE CROSSWORD CLUES \"M\"", + "Question": "Faust's fiendish foe (14)", + "Answer": "Mephistopheles" + }, + { + "Category": "SPORTS LEGENDS", + "Question": "If Joe DiMaggio's hitting streak had gone one more game in 1941, this company would have given him a $10,000 contract", + "Answer": "H.J. Heinz" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "This white, glossy coating on your teeth is the hardest substance in the human body", + "Answer": "Enamel" + }, + { + "Category": "GETTING POSSESSIVE", + "Question": "This bovine took the rap for the disastrous fire of October 8, 1871", + "Answer": "Mrs. O'Leary's cow" + }, + { + "Category": "FLAGS OF THE WORLD", + "Question": "It's the kingdom whose flag is seen here (Union Jack)", + "Answer": "Great Britain/England" + }, + { + "Category": "ARCHITECTS", + "Question": "Minoru Yamasaki reached new heights with this New York City complex", + "Answer": "World Trade Center" + }, + { + "Category": "1994 FILMS", + "Question": "Quentin Tarantino directed this film & also had a bit role as Jimmy of Toluca Lake", + "Answer": "Pulp Fiction" + }, + { + "Category": "THE EYES HAVE IT", + "Question": "A student, or a minor in Roman law", + "Answer": "Pupil" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "The time it takes for 50% of the atoms to decay in a radioactive substance is called this", + "Answer": "Half-life" + }, + { + "Category": "GETTING POSSESSIVE", + "Question": "At 14,140 feet, this Rocky Mountain peak discovered in 1806 is one of Colorado's highest", + "Answer": "Pike's Peak" + }, + { + "Category": "FLAGS OF THE WORLD", + "Question": "Seen here is the flag of this nation (the home of Bollywood)", + "Answer": "India" + }, + { + "Category": "ARCHITECTS", + "Question": "William Pereira erected his Transamerica \"Pyramid\" in this city", + "Answer": "San Francisco" + }, + { + "Category": "1994 FILMS", + "Question": "As mad bomber Howard Payne in this film, Dennis Hopper planted a bomb on an L.A. area transit bus", + "Answer": "Speed" + }, + { + "Category": "THE EYES HAVE IT", + "Question": "A blow with a whip", + "Answer": "Lash" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "While compounds of this element are added to table salt, in its pure form it's quite poisonous", + "Answer": "Iodine" + }, + { + "Category": "GETTING POSSESSIVE", + "Question": "While one creation slept, God took this to make Eve", + "Answer": "Adam's rib" + }, + { + "Category": "FLAGS OF THE WORLD", + "Question": "Andy Garcia is a native of this country whose flag is seen here", + "Answer": "Cuba" + }, + { + "Category": "ARCHITECTS", + "Question": "Charles Bulfinch, who contributed to the Capitol in Washington, D.C., designed this city's state house on Beacon Hill", + "Answer": "Boston" + }, + { + "Category": "1994 FILMS", + "Question": "Jean Vander Pyl, who played Wilma in the original cartoon series, played Mrs. Feldspar in this movie adaptation", + "Answer": "The Flintstones" + }, + { + "Category": "THE EYES HAVE IT", + "Question": "A hollow area that holds a light bulb", + "Answer": "Socket" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "The \"super\" class of these stars, the largest known, includes Antares & Betelgeuse", + "Answer": "Red giants" + }, + { + "Category": "GETTING POSSESSIVE", + "Question": "You'll find this triangular island about 4 miles off the southeast coast of Massachusetts", + "Answer": "Martha's Vineyard" + }, + { + "Category": "FLAGS OF THE WORLD", + "Question": "In the 1990s, this nation whose flag is seen here moved its seat of government to a different city", + "Answer": "Germany" + }, + { + "Category": "ARCHITECTS", + "Question": "Dallas-Fort Worth Airport architect Gyo Obata helped design this Smithsonian museum", + "Answer": "Air & Space Museum" + }, + { + "Category": "1994 FILMS", + "Question": "Containing the hit \"Can You Feel The Love Tonight\", it was Disney's first animated feature not based on an existing story", + "Answer": "The Lion King" + }, + { + "Category": "THE EYES HAVE IT", + "Question": "Flower seen here (that fits the category)", + "Answer": "Iris" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "On the pH scale, a pH of 7 indicates this type of solution", + "Answer": "Neutral" + }, + { + "Category": "GETTING POSSESSIVE", + "Question": "In Exodus, this was thrown down before Pharaoh at Moses' instruction", + "Answer": "Aaron's rod" + }, + { + "Category": "FLAGS OF THE WORLD", + "Question": "This Mediterranean country whose flag is seen here is \"The Word\"", + "Answer": "Greece" + }, + { + "Category": "ARCHITECTS", + "Question": "Louis Skidmore designed the secret atomic site that became this Tennessee town", + "Answer": "Oak Ridge" + }, + { + "Category": "1994 FILMS", + "Question": "In this film Martin Scorsese says the TV audience wants \"To watch the money\"", + "Answer": "Quiz Show" + }, + { + "Category": "THE EYES HAVE IT", + "Question": "People say these are what you need to make it in Hollywood", + "Answer": "Contacts" + }, + { + "Category": "ALASKA", + "Question": "4 different species of bears live in Alaska: Kodiak, grizzly, black & this", + "Answer": "Polar bears" + }, + { + "Category": "INTERNATIONAL SPORTSMEN", + "Question": "Nike's stock fell when this basketball player announced his retirement in January 1999", + "Answer": "Michael Jordan" + }, + { + "Category": "DRAMA QUEENS", + "Question": "In Euripides' play about this famed beauty, it's her double who goes to Troy", + "Answer": "Helen" + }, + { + "Category": "ANGELS", + "Question": "In 1996 John Travolta spread his wings as this archangel", + "Answer": "Michael" + }, + { + "Category": "IN EXILE", + "Question": "Porfirio Diaz seized power in this country in 1876, ruled for 35 years, fled in 1911 & died in exile", + "Answer": "Mexico" + }, + { + "Category": "THE \"I\"s HAVE IT", + "Question": "This term for a fluid can also mean \"to sign\" as a contract", + "Answer": "Ink" + }, + { + "Category": "ALASKA", + "Question": "Tony Knowles is pulling in $81,648 per annum in this job", + "Answer": "Governor" + }, + { + "Category": "INTERNATIONAL SPORTSMEN", + "Question": "Ronaldo Luiz Nazario de Lima began playing this sport for Brazil's national team at age 17", + "Answer": "Soccer" + }, + { + "Category": "DRAMA QUEENS", + "Question": "In a Shaw play, Caesar finds her hiding on a Sphinx", + "Answer": "Cleopatra" + }, + { + "Category": "ANGELS", + "Question": "In Book III of \"Paradise Lost\", the angels play these, which are \"golden\" & \"ever-tuned\"", + "Answer": "harps" + }, + { + "Category": "IN EXILE", + "Question": "In 1462 this printer known for movable type had to move out of Mainz", + "Answer": "Johannes Gutenberg" + }, + { + "Category": "THE \"I\"s HAVE IT", + "Question": "Style of the 1877 painting seen here", + "Answer": "Impressionism" + }, + { + "Category": "ALASKA", + "Question": "This second-largest Alaskan city wasn't named for an actor", + "Answer": "Fairbanks" + }, + { + "Category": "INTERNATIONAL SPORTSMEN", + "Question": "Vladimir Samsonov is touted as Europe's only hope against China in this game", + "Answer": "Ping-pong" + }, + { + "Category": "DRAMA QUEENS", + "Question": "A 1952 play covered the young life of this queen, like a 1998 Cate Blanchett film", + "Answer": "Elizabeth I" + }, + { + "Category": "ANGELS", + "Question": "ABBA sang about these & Curtis Lee sang about \"Pretty Little\" these", + "Answer": "Angel Eyes" + }, + { + "Category": "IN EXILE", + "Question": "Exiled for manslaughter, Eric the Red was forced to leave this country around 981", + "Answer": "Iceland" + }, + { + "Category": "THE \"I\"s HAVE IT", + "Question": "Arabic for \"son of\", it comes before names like Saud", + "Answer": "Ibn" + }, + { + "Category": "ALASKA", + "Question": "One of the 3 mottos that have been featured on regular Alaskan license plates", + "Answer": "\"The Last Frontier\", \"The Great Land\", or \"North to the Future\"" + }, + { + "Category": "INTERNATIONAL SPORTSMEN", + "Question": "The Times of London estimates this chess player is taking home $20 mil. a year; that's some check, mate!", + "Answer": "Garry Kasparov" + }, + { + "Category": "DRAMA QUEENS", + "Question": "In 1935 & '36 Helen Hayes reigned for 517 Broadway performances as this queen who reigned for 63 years", + "Answer": "Victoria" + }, + { + "Category": "ANGELS", + "Question": "Group whose feast day is October 2, or a group founded in 1979 by Curtis Sliwa", + "Answer": "Guardian Angels" + }, + { + "Category": "IN EXILE", + "Question": "David Ben-Gurion went to the U.S. in 1915 when this empire exiled Zionists from Palestine", + "Answer": "Ottoman Empire" + }, + { + "Category": "THE \"I\"s HAVE IT", + "Question": "From the Latin for \"to overhang\", it means \"likely to happen at any moment\"", + "Answer": "Imminent" + }, + { + "Category": "ALASKA", + "Question": "The mainland peninsula closest to Russia is named for this man", + "Answer": "William Seward" + }, + { + "Category": "INTERNATIONAL SPORTSMEN", + "Question": "New Zealand-born Jonah Lamu is tops on the pitch of this sport", + "Answer": "Rugby" + }, + { + "Category": "DRAMA QUEENS", + "Question": "The queen in Marlowe's \"Edward II\" is named this, like a famous queen of Spain", + "Answer": "Isabella" + }, + { + "Category": "ANGELS", + "Question": "With an appropriate-sounding name, John Dye plays the angel of this on \"Touched By An Angel\"", + "Answer": "Angel of Death" + }, + { + "Category": "IN EXILE", + "Question": "Moshoeshoe II was exiled twice before regaining this southern African country's throne in 1995", + "Answer": "Lesotho" + }, + { + "Category": "THE \"I\"s HAVE IT", + "Question": "Some scientists believe that the universe is undergoing expansion called this, also an economic term", + "Answer": "Inflation" + }, + { + "Category": "THE MAP OF EUROPE", + "Question": "Bordering Italy, Austria, Hungary & Croatia, it's one of the world's newest independent countries", + "Answer": "Slovenia" + }, + { + "Category": "THE CIVIL WAR", + "Question": "His first act after being sworn in as president of the Confederacy was to send a peace commission to Washington, D.C.", + "Answer": "Jefferson Davis" + }, + { + "Category": "CELEBS", + "Question": "On Sept. 14, 2005 she gave birth to Sean Preston Federline", + "Answer": "Britney Spears" + }, + { + "Category": "WHAT'S IN A NAME?", + "Question": "Yeah, baby! Meaning \"magnificent\", this Texas-sounding name comes with certain \"Powers\"", + "Answer": "Austin" + }, + { + "Category": "EMOTICONS", + "Question": ";-) Ocular act that sends a signal", + "Answer": "winking" + }, + { + "Category": "FLAG 'EM DOWN", + "Question": "The Alamo is located in this city & is depicted on its flag", + "Answer": "San Antonio" + }, + { + "Category": "\"TEEN\" SCENE", + "Question": "Numerically speaking, read up on \"Fun Stuff\", \"Fashion\", \"Health\" & \"Stars\" at this magazine.com", + "Answer": "seventeen.com" + }, + { + "Category": "THE CIVIL WAR", + "Question": "Tired of eating mule jerky, Vicksburg fell in July 1863 after a 6-week one of these military tactics", + "Answer": "a siege" + }, + { + "Category": "CELEBS", + "Question": "The TV show \"Everybody Hates Chris\" is based on the childhood of this comic", + "Answer": "Chris Rock" + }, + { + "Category": "WHAT'S IN A NAME?", + "Question": "This name shared by great & terrible rulers is a Russian variation of John", + "Answer": "Ivan" + }, + { + "Category": "EMOTICONS", + "Question": ":-$ It's where this emoticon tells you to \"put your money\"", + "Answer": "where your mouth is" + }, + { + "Category": "FLAG 'EM DOWN", + "Question": "This descriptive nickname of the U.S. flag was coined by Francis Scott Key", + "Answer": "the Star-Spangled Banner" + }, + { + "Category": "\"TEEN\" SCENE", + "Question": "If you're triskaidekaphobic, you're afraid of this number, & not just on a Friday", + "Answer": "thirteen" + }, + { + "Category": "THE CIVIL WAR", + "Question": "Robert E. Lee saved this capital from capture with his June 1862 attack on McClellan's forces", + "Answer": "Richmond" + }, + { + "Category": "CELEBS", + "Question": "He auditioned for & won the part of Ron Weasley with a rap that he wrote", + "Answer": "Rupert Grint" + }, + { + "Category": "WHAT'S IN A NAME?", + "Question": "This feminine form of Rex is from the Latin for \"queen\"", + "Answer": "Regina" + }, + { + "Category": "EMOTICONS", + "Question": ":-* Gene Simmons might accept one of these from any pretty woman", + "Answer": "a kiss" + }, + { + "Category": "FLAG 'EM DOWN", + "Question": "The 2 colors found on all 3 national flags of the U.S., Mexico & Canada", + "Answer": "red & white" + }, + { + "Category": "\"TEEN\" SCENE", + "Question": "A holder for liquid, or a military base's general store", + "Answer": "a canteen" + }, + { + "Category": "THE CIVIL WAR", + "Question": "In Feb. 2005 a reenactment was staged for this 140th anniversary of this fort's reoccupation by Union troops", + "Answer": "Fort Sumter" + }, + { + "Category": "CELEBS", + "Question": "Her 18th birthday party was \"A Cinderella Story\" with 300 guests & red velvet cake", + "Answer": "Hilary Duff" + }, + { + "Category": "WHAT'S IN A NAME?", + "Question": "This Welsh form of Margaret was among the USA's top 10 girls' names of the 1990s", + "Answer": "Megan" + }, + { + "Category": "EMOTICONS", + "Question": "=|:-)= This is an extension of the initials U.S.", + "Answer": "Uncle Sam" + }, + { + "Category": "\"TEEN\" SCENE", + "Question": "Golfing \"hole\" with a bar (where you can't go), or the amendment granting women's suffrage", + "Answer": "19th" + }, + { + "Category": "THE CIVIL WAR", + "Question": "On Sept. 2, 1864 this general sent a wire saying, \"Atlanta is ours, and fairly won\"", + "Answer": "Sherman" + }, + { + "Category": "CELEBS", + "Question": "\"You Stand Watching\" this \"Shine On\" singer", + "Answer": "Ryan Cabrera" + }, + { + "Category": "WHAT'S IN A NAME?", + "Question": "Previously attached to Theo- & Isa-, it became popular by itself after appearing in \"David Copperfield\"", + "Answer": "Dora" + }, + { + "Category": "EMOTICONS", + "Question": ":-b.. Doing this means either you're hungry or you're a pig", + "Answer": "drooling" + }, + { + "Category": "FLAG 'EM DOWN", + "Question": "The first 50-star U.S. flag was officially raised on July 4 of this year", + "Answer": "1960" + }, + { + "Category": "\"TEEN\" SCENE", + "Question": "Number of lines in Shakespeare's poem that starts \"Shall I compare thee to a summer's day?\"", + "Answer": "14" + }, + { + "Category": "NOT A CURRENT NATIONAL CAPITAL", + "Question": "Ljubljana, Bratislava, Barcelona", + "Answer": "Barcelona" + }, + { + "Category": "U.S. WINTER OLYMPIANS", + "Question": "Mike Eruzione of Winthrop, Mass. was captain of the miraculous 1980 Olympic team in this sport", + "Answer": "hockey" + }, + { + "Category": "SCIENCE", + "Question": "At sea level at 70 degrees this travels 1,129 feet per second; it speeds up over 1 foot per sec. for each rising degree", + "Answer": "sound" + }, + { + "Category": "WORDS OF THE WRITER", + "Question": "\"I beheld the wretch--the miserable monster whom I had created\"", + "Answer": "Mary Shelley" + }, + { + "Category": "AT THE MALL", + "Question": "Found \"just what I needed\" at this \"City\", an electronics store", + "Answer": "Circuit City" + }, + { + "Category": "FROM THE GREEK", + "Question": "The name of this color comes from the Greek word porphyra", + "Answer": "purple" + }, + { + "Category": "NOT A CURRENT NATIONAL CAPITAL", + "Question": "Istanbul, Ottawa, Amman", + "Answer": "Istanbul" + }, + { + "Category": "SCIENCE", + "Question": "The largest tree, the General Sherman in California, is this type, also called a Sierra Redwood", + "Answer": "a sequoia" + }, + { + "Category": "WORDS OF THE WRITER", + "Question": "\"Take thy beak from out my heart, and take thy form from off my door!\"", + "Answer": "Edgar Allan Poe" + }, + { + "Category": "AT THE MALL", + "Question": "SKX is the stock symbol for this manufacturer of sporty shoes", + "Answer": "Skechers" + }, + { + "Category": "FROM THE GREEK", + "Question": "A bowl-shaped depression, as from the impact of a meteorite, it's from the Greek for \"mixing bowl\"", + "Answer": "crater" + }, + { + "Category": "NOT A CURRENT NATIONAL CAPITAL", + "Question": "Sofia, Sarajevo, Saigon", + "Answer": "Saigon" + }, + { + "Category": "U.S. WINTER OLYMPIANS", + "Question": "Life has its ups & downs for Travis Mayer, a 2002 medalist in the event named for these little hills on the slopes", + "Answer": "moguls" + }, + { + "Category": "WORDS OF THE WRITER", + "Question": "\"'Do all lawyers defend n-negroes, Atticus?' 'Of course they do, Scout'\"", + "Answer": "Harper Lee" + }, + { + "Category": "AT THE MALL", + "Question": "This \"Urban\" store is the parent company of Anthropologie", + "Answer": "Urban Outfitters" + }, + { + "Category": "FROM THE GREEK", + "Question": "From the Greek for \"false name\", it's a fictitious name used by an author", + "Answer": "a pseudonym" + }, + { + "Category": "NOT A CURRENT NATIONAL CAPITAL", + "Question": "Bucharest, Bonn, Bern", + "Answer": "Bonn" + }, + { + "Category": "U.S. WINTER OLYMPIANS", + "Question": "In 2002 Vonetta Flowers & Jill Bakken won gold in the 2-woman version of this high-speed sport", + "Answer": "the bobsled" + }, + { + "Category": "SCIENCE", + "Question": "6 elements once known as inert gases are now known by this aristocratic name", + "Answer": "noble gases" + }, + { + "Category": "WORDS OF THE WRITER", + "Question": "\"For never man had a more faithful, loving, sincere servant, than Friday was to me\"", + "Answer": "Daniel Defoe" + }, + { + "Category": "AT THE MALL", + "Question": "This bookstore chain is named for its \"edgy\" founders, brothers Tom & Louis", + "Answer": "Borders" + }, + { + "Category": "NOT A CURRENT NATIONAL CAPITAL", + "Question": "Belize City, Guatemala City, Panama City", + "Answer": "Belize City" + }, + { + "Category": "U.S. WINTER OLYMPIANS", + "Question": "His \"Bode\" of work includes 2 Alpine skiing silver medals in 2002", + "Answer": "Bode Miller" + }, + { + "Category": "WORDS OF THE WRITER", + "Question": "\"'...Why look'st thou so?'--'With my crossbow I shot the albatross'\"", + "Answer": "Samuel Taylor Coleridge" + }, + { + "Category": "AT THE MALL", + "Question": "The name of this clothing store for teens is French for \"airmail\"", + "Answer": "Aéropostale" + }, + { + "Category": "FROM THE GREEK", + "Question": "It's an outline of the contents of a course or curriculum", + "Answer": "a syllabus" + }, + { + "Category": "FAMOUS SHIPS", + "Question": "On December 27, 1831 it departed Plymouth, England to map the coastline of South America", + "Answer": "the HMS Beagle" + }, + { + "Category": "OLD FOLKS IN THEIR 30s", + "Question": "goop.com is a lifestyles website from this Oscar-winning actress; the g & p represent her initials", + "Answer": "Gwyneth Paltrow" + }, + { + "Category": "MOVIES & TV", + "Question": "On March 19, 2009 he said, \"I'm excited and honored to introduce my first guest... Barack Obama\"", + "Answer": "Jay Leno" + }, + { + "Category": "A STATE OF COLLEGE-NESS", + "Question": "Baylor, Stephen F. Austin, Rice", + "Answer": "Texas" + }, + { + "Category": "ANIMAL COLLECTIVE", + "Question": "Synonym for dignity that's the term for a group of lions", + "Answer": "a pride" + }, + { + "Category": "I'D RATHER BE SKIING", + "Question": "If you're a beginner, you might hippity-hop over to this smaller, gentler slope", + "Answer": "a bunny hill" + }, + { + "Category": "PARLEZ VOUS?", + "Question": "If your mate from Marseilles says he's getting to LAX via \"Sud-Ouest\", pick him up at this carrier", + "Answer": "Southwest" + }, + { + "Category": "OLD FOLKS IN THEIR 30s", + "Question": "In 2008 David Gregory became moderator of this NBC Sunday morning news show", + "Answer": "Meet the Press" + }, + { + "Category": "MOVIES & TV", + "Question": "Time magazine said this 2003 Pixar film was \"the ultimate fish-out-of-water story\"", + "Answer": "Finding Nemo" + }, + { + "Category": "A STATE OF COLLEGE-NESS", + "Question": "Antioch, Bowling Green, Kent State", + "Answer": "Ohio" + }, + { + "Category": "ANIMAL COLLECTIVE", + "Question": "Like peas, whales & seals are in groups called these", + "Answer": "pods" + }, + { + "Category": "I'D RATHER BE SKIING", + "Question": "Something you'd sprinkle on after a shower, it's also the term for soft, dry, freshly fallen snow", + "Answer": "powder" + }, + { + "Category": "PARLEZ VOUS?", + "Question": "Duck, duck, l'oie; (l'oie of course referring to this other feathered friend)", + "Answer": "a goose" + }, + { + "Category": "OLD FOLKS IN THEIR 30s", + "Question": "Linus Torvalds is the father of this operating system used on cell phones & supercomputers", + "Answer": "Linux" + }, + { + "Category": "MOVIES & TV", + "Question": "Of his dialogue, this Han Solo actor said, \"You can type this (stuff), George, but you sure can't say it\"", + "Answer": "Harrison Ford" + }, + { + "Category": "A STATE OF COLLEGE-NESS", + "Question": "DePaul, Wheaton, Northwestern", + "Answer": "Illinois" + }, + { + "Category": "ANIMAL COLLECTIVE", + "Question": "A crash is a group of these large horned mammals", + "Answer": "rhinoceroses" + }, + { + "Category": "I'D RATHER BE SKIING", + "Question": "In California, a premier spot for skiing is this resort area that shares its name with a prehistoric elephant", + "Answer": "Mammoth" + }, + { + "Category": "PARLEZ VOUS?", + "Question": "\"Je ne sais pas\" means this, but you still get credit if you phrase it in the form of a question", + "Answer": "\"I don't know\"" + }, + { + "Category": "OLD FOLKS IN THEIR 30s", + "Question": "The district of conservative rep. Patrick McHenry in this state includes Mooresville, a home of NASCAR", + "Answer": "North Carolina" + }, + { + "Category": "MOVIES & TV", + "Question": "Tim Robbins played a public TV newsman in \"Anchorman: The Legend of\" him", + "Answer": "Ron Burgundy" + }, + { + "Category": "A STATE OF COLLEGE-NESS", + "Question": "Wayne State, Kalamazoo College, Madonna University (it's Franciscan Catholic, not Material Girl)", + "Answer": "Michigan" + }, + { + "Category": "ANIMAL COLLECTIVE", + "Question": "It can be a pack of dogs, or a place to board them", + "Answer": "a kennel" + }, + { + "Category": "I'D RATHER BE SKIING", + "Question": "In this type of race you have to zigzag between flags or other obstacles in proper order", + "Answer": "a slalom" + }, + { + "Category": "PARLEZ VOUS?", + "Question": "When mom tells you to do something \"Maintenant!\", she means this", + "Answer": "now" + }, + { + "Category": "OLD FOLKS IN THEIR 30s", + "Question": "Elon Musk is now making rockets & electric cars; before that he co-founded & sold this electronic payment system", + "Answer": "PayPal" + }, + { + "Category": "MOVIES & TV", + "Question": "We were frakkin' sad when this sci fi show had its series finale on March 20, 2009", + "Answer": "Battlestar Galactica" + }, + { + "Category": "A STATE OF COLLEGE-NESS", + "Question": "Grambling, McNeese State, Southern", + "Answer": "Louisiana" + }, + { + "Category": "ANIMAL COLLECTIVE", + "Question": "A flock of these black birds is called a murder", + "Answer": "crows" + }, + { + "Category": "I'D RATHER BE SKIING", + "Question": "Bumps or mounds of snow that accumulate on a slope are called these, like some very wealthy & powerful people", + "Answer": "moguls" + }, + { + "Category": "PARLEZ VOUS?", + "Question": "\"Huitieme\" is French for this ordinal number", + "Answer": "eighth" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "Her home Orchard House was the model for whre the March family lived in her most famous novel", + "Answer": "Louisa May Alcott" + }, + { + "Category": "ALBUMS THAT ROCK", + "Question": "\"X&Y\", \"Parachutes\"", + "Answer": "Coldplay" + }, + { + "Category": "ANATOMY", + "Question": "This cord that connects a fetus to the placenta contains 2 arteries & 1 vein", + "Answer": "the umbillical cord" + }, + { + "Category": "NAME THE DECADE", + "Question": "The World Wide Web gets its first page", + "Answer": "the 1990s" + }, + { + "Category": "WORD ORIGINS", + "Question": "This adjective meaning deceptive or sneaky is from the Latin de via, meaning \"out of the way\"", + "Answer": "devious" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "During the War Of 1812, this \"Rip Van Winkle\" author wrote biographies of Naval commanders", + "Answer": "Washington Irving" + }, + { + "Category": "ALBUMS THAT ROCK", + "Question": "\"American Idiot\", \"Dookie\"", + "Answer": "Green Day" + }, + { + "Category": "ANATOMY", + "Question": "The human body has 3 types of these: skeletal, smooth & cardiac, a combination of skeletal & smooth", + "Answer": "muscles" + }, + { + "Category": "MATHEM-ATTACK!", + "Question": "You should answer this one automatically: It's the property that says a = a", + "Answer": "reflexive" + }, + { + "Category": "NAME THE DECADE", + "Question": "The first controlled nuclear chain reaction", + "Answer": "the 1940s" + }, + { + "Category": "WORD ORIGINS", + "Question": "This New York island's name may come from the Algonquian word for \"island\"", + "Answer": "Manhattan" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "Susan & Benjamin Cheever, children of this short story master, are both authors as well", + "Answer": "John Cheever" + }, + { + "Category": "ALBUMS THAT ROCK", + "Question": "\"Master of Puppets\", \"Death Magnetic\"", + "Answer": "Metallica" + }, + { + "Category": "ANATOMY", + "Question": "The talus fits between the ends of these 2 bones forming the ankle joint", + "Answer": "the tibia & fibula" + }, + { + "Category": "NAME THE DECADE", + "Question": "Khruschev's \"Secret Speech\" denounces Stalin", + "Answer": "the 1950s" + }, + { + "Category": "WORD ORIGINS", + "Question": "This compass direction may come from the Proto-Germanic for \"to the left of the rising sun\"", + "Answer": "north" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "He stood 5'3\" & was the subject of movies that came out in 2005 & 2006", + "Answer": "Capote" + }, + { + "Category": "ALBUMS THAT ROCK", + "Question": "\"In Your Honor\", \"The Color and the Shape\"", + "Answer": "Foo Fighters" + }, + { + "Category": "ANATOMY", + "Question": "Humans have 33 vertebrae, 7 of them cervical, meaning they are in this part of the body", + "Answer": "your neck" + }, + { + "Category": "MATHEM-ATTACK!", + "Question": "The symbol i is used to represent the imaginary square root of this number", + "Answer": "-1" + }, + { + "Category": "NAME THE DECADE", + "Question": "George Orwell, 34 years dead, hits the bestseller list", + "Answer": "the 1980s" + }, + { + "Category": "WORD ORIGINS", + "Question": "From the Latin for \"much writing\", it's another name for a lie detector test", + "Answer": "a polygraph" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "He reviewed films & TV for the New Republic before his first book, \"Goodbye, Columbus\", was published in 1959", + "Answer": "Philip Roth" + }, + { + "Category": "ALBUMS THAT ROCK", + "Question": "\"Beggars Banquet\", \"Steel Wheels\"", + "Answer": "the Rolling Stones" + }, + { + "Category": "ANATOMY", + "Question": "The pons connects the 2 hemispheres of this part of the brain that regulates balance", + "Answer": "the cerebellum" + }, + { + "Category": "NAME THE DECADE", + "Question": "Man first reaches the South Pole", + "Answer": "the 1910s" + }, + { + "Category": "WORD ORIGINS", + "Question": "A type of ear implant to help the deaf, it's from the Greek for \"snail\"", + "Answer": "cochlear" + }, + { + "Category": "EUROPEAN HISTORY", + "Question": "He filed for divorce citing Leviticus 20:21, \"If a man shall take his brother's wife, it is an unclean thing\"", + "Answer": "Henry VIII" + }, + { + "Category": "AMERICAN EXPLORERS", + "Question": "Edward Beale brought news of this 1848 discovery in California to the east coast", + "Answer": "gold" + }, + { + "Category": "MEASURING DEVICES", + "Question": "The amount of this in a solution can be measured by a saccharometer", + "Answer": "sugar" + }, + { + "Category": "MYTHOLOGY", + "Question": "Daedalus used this substance to fasten the wings to his back", + "Answer": "wax" + }, + { + "Category": "TELEVISION", + "Question": "This Sunday night series is subtitled \"The New Adventures of Superman\"", + "Answer": "Lois & Clark" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "This state's Days of '47 Festival honors the day Brigham Young reached the Salt Lake Valley in 1847", + "Answer": "Utah" + }, + { + "Category": "HOMOPHONIC PAIRS", + "Question": "A complete donut center", + "Answer": "whole hole" + }, + { + "Category": "AMERICAN EXPLORERS", + "Question": "Stephen Long & Zebulon Pike have peaks named for them in this state, an area they said was uninhabitable", + "Answer": "Colorado" + }, + { + "Category": "MEASURING DEVICES", + "Question": "The energy from this is measured by a pyrheliometer", + "Answer": "the Sun" + }, + { + "Category": "MYTHOLOGY", + "Question": "Cadmus planted these parts of a dragon to raise some troops", + "Answer": "teeth" + }, + { + "Category": "TELEVISION", + "Question": "\"Freddy's Nightmares\", a horror anthology that debuted in 1988, was based on this movie series", + "Answer": "Nightmare on Elm Street" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Monroe, near Snohomish in this state, is the site of the annual Evergreen State Fair", + "Answer": "Washington" + }, + { + "Category": "HOMOPHONIC PAIRS", + "Question": "In a restaurant, it's a quartet's table request", + "Answer": "for four" + }, + { + "Category": "AMERICAN EXPLORERS", + "Question": "Co-commanders of the 1st U.S. expedition to explore from Mississippi to the west coast", + "Answer": "Lewis & Clark" + }, + { + "Category": "MEASURING DEVICES", + "Question": "An odometer measures the distance covered by a vehicle & this device measures how far you've walked", + "Answer": "a pedometer" + }, + { + "Category": "MYTHOLOGY", + "Question": "The sister of Orestes, mourning became her", + "Answer": "Electra" + }, + { + "Category": "TELEVISION", + "Question": "This crime drama with Robert Wagner & Stefanie Powers was created by Sidney Sheldon", + "Answer": "Hart to Hart" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Dog lovers look forward to the Westminster Kennel Club dog show, held each February in this city", + "Answer": "New York City" + }, + { + "Category": "HOMOPHONIC PAIRS", + "Question": "Contented performing kittens might be paid this way", + "Answer": "per purr" + }, + { + "Category": "AMERICAN EXPLORERS", + "Question": "Jedediah Smith was a mountain man & explorer employed in this industry", + "Answer": "fur trading" + }, + { + "Category": "MEASURING DEVICES", + "Question": "A spirometer measures the capacity of these organs", + "Answer": "the lungs" + }, + { + "Category": "MYTHOLOGY", + "Question": "Zeus' father, Cronus, was one of this group of 12", + "Answer": "Titans" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "The Pendleton Roundup, an annual rodeo, takes place in Pendleton in this northwestern state", + "Answer": "Oregon" + }, + { + "Category": "HOMOPHONIC PAIRS", + "Question": "A squash that's been pierced by a bull's horn", + "Answer": "gored gourd" + }, + { + "Category": "AMERICAN EXPLORERS", + "Question": "Senator Thomas Hart Benton's son-in-law was this \"Pathfinder\"", + "Answer": "John C. Frémont" + }, + { + "Category": "MEASURING DEVICES", + "Question": "A nilometer measures the height of the water in this", + "Answer": "the Nile River" + }, + { + "Category": "MYTHOLOGY", + "Question": "Leda laid 2 eggs: one with Helen & Pollux in it, the other containing Clytemnestra & him", + "Answer": "Castor" + }, + { + "Category": "TELEVISION", + "Question": "Jack Wagner, formerly of \"General Hospital\", now plays Dr. Peter Burns on this Fox drama", + "Answer": "Melrose Place" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "The Tanglewood Music Festival is a summer highlight in Lenox in this New England state", + "Answer": "Massachusetts" + }, + { + "Category": "HOMOPHONIC PAIRS", + "Question": "Remained sedate", + "Answer": "stayed staid" + }, + { + "Category": "NOTABLE NONHUMANS", + "Question": "This Nazi dictator sometimes dined alone with Blondi, his Alsatian", + "Answer": "Adolf Hitler" + }, + { + "Category": "WORLD FACTS", + "Question": "This isthmus connects North & South America", + "Answer": "Isthmus of Panama" + }, + { + "Category": "ART & ARTISTS", + "Question": "He painted \"Irises\" & \"Pink Roses\" as well as \"Sunflowers\"", + "Answer": "Vincent Van Gogh" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "It has over 9,700 tax preparation offices worldwide", + "Answer": "H&R Block" + }, + { + "Category": "HISTORY", + "Question": "Historians refer to the Golden Age as the time during which Pericles ruled this city", + "Answer": "Athens" + }, + { + "Category": "POETS", + "Question": "On Feb. 12, 1959, the 150th anniversary of Lincoln's birth, he addressed a joint session of Congress", + "Answer": "Carl Sandburg" + }, + { + "Category": "NOTABLE NONHUMANS", + "Question": "In 1964 he lifted his beagles Him & Her by the ears on the White House lawn, provoking protest", + "Answer": "Lyndon Johnson" + }, + { + "Category": "WORLD FACTS", + "Question": "A humid city, Rio de Janeiro lies just north of this tropic line", + "Answer": "the Tropic of Capricorn" + }, + { + "Category": "ART & ARTISTS", + "Question": "This drip artist was born in Cody, Wyoming in 1912", + "Answer": "Jackson Pollock" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "In 1961 this firm introduced its Selectric typewriter, which used a spherical typing element", + "Answer": "IBM" + }, + { + "Category": "HISTORY", + "Question": "Under the 1814 Treaty of Kiel, this country gave Norway to Sweden but kept Greenland & other islands", + "Answer": "Denmark" + }, + { + "Category": "POETS", + "Question": "Between 1842 & 1885, he repeatedly revised his \"Idylls of the King\"", + "Answer": "Alfred Lord Tennyson" + }, + { + "Category": "NOTABLE NONHUMANS", + "Question": "Colo was the first of these great apes born in captivity, in 1956 at the Columbus Zoo", + "Answer": "Gorilla" + }, + { + "Category": "WORLD FACTS", + "Question": "The lowest river in the world, it's revered by Jews, Christians & Muslims alike", + "Answer": "The River Jordan" + }, + { + "Category": "ART & ARTISTS", + "Question": "He spent several summers painting pointillist seascapes including \"Le Bec Du Hoc, Grandcamp\"", + "Answer": "Georges Seurat" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "In 1934 he plugged Bulova \"Lone Eagle\" watches", + "Answer": "Charles Lindbergh" + }, + { + "Category": "HISTORY", + "Question": "In February 1904 this country attacked the Russian fleet at Port Arthur", + "Answer": "Japan" + }, + { + "Category": "POETS", + "Question": "For much of the winter of 1794-95, he served as acting supervisor for Dumfries, Scotland", + "Answer": "Robert Burns" + }, + { + "Category": "NOTABLE NONHUMANS", + "Question": "In 1945 this famous scottie was injured in a fight with Blaze, Elliott Roosevelt's mastiff", + "Answer": "Fala" + }, + { + "Category": "WORLD FACTS", + "Question": "Discovered by David Livingstone, Botswana's Lake Ngami lies in the northern part of this desert", + "Answer": "Kalahari Desert" + }, + { + "Category": "ART & ARTISTS", + "Question": "His sculpture, \"The Age of Bronze\", exhibited in 1877, was inspired by Michelangelo", + "Answer": "Auguste Rodin" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "Only Philip Morris & this Cincinnati-based firm have yearly ad expenditures exceeding $2 billion", + "Answer": "Procter & Gamble" + }, + { + "Category": "HISTORY", + "Question": "On May 30, 1967 Colonel Ojukwu declared Biafra's independence from this country, starting a civil war", + "Answer": "Nigeria" + }, + { + "Category": "POETS", + "Question": "Her \"I Heard a Fly Buzz\" may have been based on a chapter in \"The House of the Seven Gables\"", + "Answer": "Emily Dickinson" + }, + { + "Category": "NOTABLE NONHUMANS", + "Question": "This favorite horse of Alexander the Great sometimes wore golden horns in battle", + "Answer": "Bucephalus" + }, + { + "Category": "WORLD FACTS", + "Question": "In area this country whose capital is now called Yangon is the largest in mainland southeast Asia", + "Answer": "Myanmar" + }, + { + "Category": "ART & ARTISTS", + "Question": "You can see this British sculptor's \"Reclining Mother and Child\" at the Walker Art Center in Minneapolis", + "Answer": "Henry Moore" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "In 1811 this German family began its steel-making business by constructing a plant in Essen", + "Answer": "Krupp" + }, + { + "Category": "HISTORY", + "Question": "In the midst of the Korean War, this South Korean president was elected to his second of 4 terms", + "Answer": "Syngman Rhee" + }, + { + "Category": "POETS", + "Question": "He once wrote, \"I choose to be a plain New Hampshire farmer\"", + "Answer": "Robert Frost" + }, + { + "Category": "BRITISH NOVELS", + "Question": "This 1895 novel is subtitled \"An Invention\"", + "Answer": "The Time Machine" + }, + { + "Category": "LOST IN SPACE", + "Question": "While making repairs on the Intl. Space Station, Scott Parazynski lost a needle-nose pair of these", + "Answer": "pliers" + }, + { + "Category": "TIMELESS TV", + "Question": "September 2010 brought the 45th edition of this comedian's telethon", + "Answer": "Jerry Lewis" + }, + { + "Category": "LET'S HIT IT", + "Question": "Hit this paper mache container, Spanish for \"jug\", if you want candy and small gifts", + "Answer": "pinata" + }, + { + "Category": "WORLD BOOK DESCRIBES THE \"G\" MAN", + "Question": "\"In 1997, the House (of Reps.) voted to reprimand him... It marked the first time the House had reprimanded a Speaker\"", + "Answer": "Gingrich" + }, + { + "Category": "MONEY SLANG", + "Question": "We'll give you $200, not $1,000, for this five letter word meaning stately or majestic", + "Answer": "grand" + }, + { + "Category": "LOST IN SPACE", + "Question": "In its years of operation, this Soviet space station released more than 200 objects (mostly trash) into space", + "Answer": "Mir" + }, + { + "Category": "TIMELESS TV", + "Question": "Originally a half hour, this soap started in 1963 & featured Nurse Jessie Brewer", + "Answer": "General Hospital" + }, + { + "Category": "LET'S HIT IT", + "Question": "This word seen on doors is what a right-handed batter does when he hits the ball to left field", + "Answer": "pull" + }, + { + "Category": "WORLD BOOK DESCRIBES THE \"G\" MAN", + "Question": "\"See Simon, Paul\"", + "Answer": "Garfunkel" + }, + { + "Category": "MONEY SLANG", + "Question": "Proverbially, you can \"break\" this food, or \"take (it) out of someone's mouth\"; earn some dough", + "Answer": "bread" + }, + { + "Category": "LOST IN SPACE", + "Question": "Ed White, the first U.S. spacewalker, lost one of these outside Gemini 4; he must've looked like a later \"moonwalker\"", + "Answer": "a glove" + }, + { + "Category": "TIMELESS TV", + "Question": "In 1948 Douglas Edwards became the first anchor of this network's Evening News", + "Answer": "CBS" + }, + { + "Category": "LET'S HIT IT", + "Question": "Aaron Fechter invented this carnival game where you hit a mammal with a mallet", + "Answer": "Whack-A-Mole" + }, + { + "Category": "WORLD BOOK DESCRIBES THE \"G\" MAN", + "Question": "\"American poet... became known as a leader of the Beat literary movement of the 1950s\"", + "Answer": "Ginsberg" + }, + { + "Category": "MONEY SLANG", + "Question": "The shell of this mollusk is composed chiefly of calcium carbonate", + "Answer": "a clam" + }, + { + "Category": "LOST IN SPACE", + "Question": "Piers Sellers lost a tool in space while spreading putty into this Space Shuttle named for Capt. Cook's ship", + "Answer": "Discovery" + }, + { + "Category": "TIMELESS TV", + "Question": "Shown Saturday afternoons on ABC, this sport's tour outdrew college football & moved to ESPN in 1997", + "Answer": "the pro bowling tour" + }, + { + "Category": "LET'S HIT IT", + "Question": "Everlast makes these that come in speed and heavy varieties", + "Answer": "punching bags" + }, + { + "Category": "WORLD BOOK DESCRIBES THE \"G\" MAN", + "Question": "\"Served under the Apache leaders Cochise and Mangas Coloradas... in 1894, he was moved to Fort Sill", + "Answer": "Geronimo" + }, + { + "Category": "MONEY SLANG", + "Question": "You don't get 5 guesses at this winglike appendage to the underwater portion of a hull", + "Answer": "a fin" + }, + { + "Category": "LOST IN SPACE", + "Question": "In 1992 Space Shuttle astronauts delivered ashes of this \"Star Trek\" creator into the final frontier", + "Answer": "Gene Roddenberry" + }, + { + "Category": "TIMELESS TV", + "Question": "2010's \"When Love Is Not Enough\" was the 240th presentation in this series from a greeting card company", + "Answer": "Hallmark Hall of Fame" + }, + { + "Category": "LET'S HIT IT", + "Question": "In some casinos, a blackjack dealer must hit with an ace & a 6, known as this type of 17", + "Answer": "soft" + }, + { + "Category": "WORLD BOOK DESCRIBES THE \"G\" MAN", + "Question": "\"One of the most original and provocative American architects working today\"", + "Answer": "Gehry" + }, + { + "Category": "MONEY SLANG", + "Question": "When speaking of Messrs. Netanyahu or Britten, it's all about the first name, pluralized", + "Answer": "the Benjamins" + }, + { + "Category": "PLAY HEROINES", + "Question": "Blanche DuBois", + "Answer": "A Streetcar Named Desire" + }, + { + "Category": "DEFENESTRATION IN CINEMA", + "Question": "Giving the devil his due, Fr. Karras invites the devil inside himself, then exits from the second floor in this 1973 movie", + "Answer": "The Exorcist" + }, + { + "Category": "A MASSIVE \"M\"ETROPOLIS", + "Question": "3.6 million: Down Under", + "Answer": "Melbourne" + }, + { + "Category": "TAINTED GOV", + "Question": "In 2010 this Illinois governor was tried on corruption charges, but convicted on only 1 count", + "Answer": "Blagojevich" + }, + { + "Category": "MEDICINE", + "Question": "As Franklin D. Roosevelt's blood pressure was 300/190, he suffered from this 1-word condition", + "Answer": "hypertension" + }, + { + "Category": "4 CONSONANTS IN A ROW", + "Question": "If you're vertical but supported by your palms, you're doing one of these", + "Answer": "a handstand" + }, + { + "Category": "PLAY HEROINES", + "Question": "Emily Webb of Grover's Corners", + "Answer": "Our Town" + }, + { + "Category": "DEFENESTRATION IN CINEMA", + "Question": "In this Bruce Willis movie, the villain goes out the window of the Nakatomi building, gun in hand", + "Answer": "Die Hard" + }, + { + "Category": "A MASSIVE \"M\"ETROPOLIS", + "Question": "11 million: on Luzon Island", + "Answer": "Manila" + }, + { + "Category": "TAINTED GOV", + "Question": "In 2006 this Illinois governor was busted for racketeering; what's in the water there?", + "Answer": "George Ryan" + }, + { + "Category": "MEDICINE", + "Question": "In 1905 German scientist Alfred Einhorn created this first injectable local anesthetic used in dentistry", + "Answer": "novocaine" + }, + { + "Category": "4 CONSONANTS IN A ROW", + "Question": "A caterpillar that moves by contraction & expansion", + "Answer": "an inchworm" + }, + { + "Category": "DEFENESTRATION IN CINEMA", + "Question": "Movie in which Axel Foley asks, \"where ...you get off arresting me for being thrown out a window?\"", + "Answer": "Beverly Hills Cop" + }, + { + "Category": "A MASSIVE \"M\"ETROPOLIS", + "Question": "1.1 million: in the heart of the Po River Valley", + "Answer": "Milan" + }, + { + "Category": "TAINTED GOV", + "Question": "In 2010 it was revealed that Robert Rizzo made $800,000 a year as the city this of Bell, Calif., population 37,000", + "Answer": "manager" + }, + { + "Category": "MEDICINE", + "Question": "Micro-Trach is an oxygen delivery system developed by this physician known for his \"maneuver\"", + "Answer": "Heimlich" + }, + { + "Category": "4 CONSONANTS IN A ROW", + "Question": "A loop found on footwear, it's a symbol of success through one's own efforts", + "Answer": "a bootstrap" + }, + { + "Category": "A MASSIVE \"M\"ETROPOLIS", + "Question": "18 million: on the Arabian Sea", + "Answer": "Mumbai" + }, + { + "Category": "TAINTED GOV", + "Question": "In 2010 a House committee charged this veteran Harlem congressman with ethics violations", + "Answer": "Rangel" + }, + { + "Category": "4 CONSONANTS IN A ROW", + "Question": "Hard coal that burns with little flame", + "Answer": "anthracite" + }, + { + "Category": "PLAY HEROINES", + "Question": "Barbara Undershaft", + "Answer": "Major Barbara" + }, + { + "Category": "DEFENESTRATION IN CINEMA", + "Question": "In this Coen Brothers movie, Charles Durning jumps out a window during a board meeting", + "Answer": "The Hudsucker Proxy" + }, + { + "Category": "A MASSIVE \"M\"ETROPOLIS", + "Question": "3.2 million: 150 miles from Bogota", + "Answer": "Medellin" + }, + { + "Category": "TAINTED GOV", + "Question": "Elected to the Senate in 1930, he refused to resign as Louisiana's gov. until '32, when his handpicked crony got the gig", + "Answer": "Huey Long" + }, + { + "Category": "MEDICINE", + "Question": "The name of this branch of pediatrics that deals with newborn infants literally means \"newborn study\"", + "Answer": "neonatal" + }, + { + "Category": "4 CONSONANTS IN A ROW", + "Question": "This important mechanism is what you're turning when you wind a clock", + "Answer": "the mainspring" + }, + { + "Category": "FLAGS OF THE WORLD", + "Question": "In use from 1844 to 1905, a flag representing the union of these 2 countries was nicknamed the \"herring salad\"", + "Answer": "Norway and Sweden" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "While he was in Spain in 1959, he wrote \"The Dangerous Summer\", a story about rival bullfighters", + "Answer": "Hemingway" + }, + { + "Category": "BEGINNING & END", + "Question": "Like a door, a Broadway show does these 2 things", + "Answer": "open & close" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "A valley at 282 feet below sea level in this state is the lowest point in the Western Hemisphere", + "Answer": "California" + }, + { + "Category": "3 LITTLE LETTERS", + "Question": "Like banks, many grocery stores now have these for dispensing cash & taking deposits", + "Answer": "ATMs" + }, + { + "Category": "CALL OUT THE VOICE SQUAD", + "Question": "He was the voice of Mickey Mouse in \"Steamboat Willie\"", + "Answer": "Walt Disney" + }, + { + "Category": "YOU'RE UNDER A \"REST\"", + "Question": "Eastern European capital city of more than 2.2 million", + "Answer": "Bucharest" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "In 1884 she moved to Red Cloud, Nebraska & later fictionalized it as the town of Hanover in \"O Pioneers!\"", + "Answer": "Willa Cather" + }, + { + "Category": "BEGINNING & END", + "Question": "In 2006 it began on July 1 in Strasbourg & ended on July 23 in Paris", + "Answer": "the Tour de France" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "With 6,640 miles of coast, this state has the longest shoreline", + "Answer": "Alaska" + }, + { + "Category": "YOU'RE UNDER A \"REST\"", + "Question": "Any mountain's summit", + "Answer": "crest" + }, + { + "Category": "BEGINNING & END", + "Question": "\"From\" this to this is an idiom meaning from the start of a meal (or something else) to the end", + "Answer": "from soup to nuts" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "It pumps more than one million barrels of oil a day, more than any other state", + "Answer": "Texas" + }, + { + "Category": "3 LITTLE LETTERS", + "Question": "\"Day to Day\" & \"All Things Considered\" are among the programs going out to its 26 million listeners", + "Answer": "NPR" + }, + { + "Category": "CALL OUT THE VOICE SQUAD", + "Question": "The voice of Daffy Duck (for the first 50 years)", + "Answer": "Mel Blanc" + }, + { + "Category": "YOU'RE UNDER A \"REST\"", + "Question": "A braced framework for carrying a railroad over a chasm", + "Answer": "a trestle" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "Under the name Laura Bancroft, he wrote about Twinkle & Chubbins in Nature Fairyland after taking us to Oz", + "Answer": "L. Frank Baum" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "Considered the healthiest state in 2006, it's also home to the Mayo Clinic", + "Answer": "Minnesota" + }, + { + "Category": "3 LITTLE LETTERS", + "Question": "Its headquarters compound in Langley, Virginia is named for Former President George Bush", + "Answer": "the CIA" + }, + { + "Category": "CALL OUT THE VOICE SQUAD", + "Question": "He voiced Puss In Boots in \"Shrek 2\"", + "Answer": "Antonio Banderas" + }, + { + "Category": "YOU'RE UNDER A \"REST\"", + "Question": "Quickly! (to an Italian)", + "Answer": "Presto" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "William Rose Benet won a Pulitzer for \"The Dust Which Is God\", & this brother won for \"John Brown's Body\"", + "Answer": "Stephen Vincent Benet" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "Its Boeing manufacturing plant in Everett is the world's largest building by volume", + "Answer": "Washington" + }, + { + "Category": "3 LITTLE LETTERS", + "Question": "A TV cable network, or an explosive for bombs", + "Answer": "TNT" + }, + { + "Category": "CALL OUT THE VOICE SQUAD", + "Question": "He provided the voices of both Beavis & Butthead", + "Answer": "Mike Judge" + }, + { + "Category": "YOU'RE UNDER A \"REST\"", + "Question": "The son of Agamemnon, he avenged his father's death by killing his mother Clytemnestra", + "Answer": "Orestes" + }, + { + "Category": "EARLY AMERICA", + "Question": "In 1718 this Texas town was founded by Martin de Alarcon & Father Olivares & named for St. Anthony of Padua", + "Answer": "San Antonio" + }, + { + "Category": "BEST PICTURE OSCAR-WINNERS IN OTHER WORDS", + "Question": "1980: \"Regular Folks\"", + "Answer": "Ordinary People" + }, + { + "Category": "DOWN MEXICO WAY", + "Question": "In 1986 Mexico scored as the first country to host this international sports competition twice", + "Answer": "the World Cup" + }, + { + "Category": "TAKE A PILL", + "Question": "Going on a cruise? You might pick up this Pfizer product, the \"original\" or \"less drowsy\" formula", + "Answer": "Dramamine" + }, + { + "Category": "TRANSPORTATION", + "Question": "The bestselling passenger car of all time is this company's Corolla", + "Answer": "Toyota" + }, + { + "Category": "AN E FOR AN I", + "Question": "A Hawaiian wreath becomes an area sheltered from wind", + "Answer": "a lei & a lee" + }, + { + "Category": "EARLY AMERICA", + "Question": "In defending British soldiers on trial for this 1770 event, John Adams said, \"Facts are stubborn things\"", + "Answer": "the Boston Massacre" + }, + { + "Category": "BEST PICTURE OSCAR-WINNERS IN OTHER WORDS", + "Question": "1932: \"Magnificent Inn\"", + "Answer": "Grand Hotel" + }, + { + "Category": "DOWN MEXICO WAY", + "Question": "This resort city about 200 miles southwest of Mexico City is famous for its cliff divers", + "Answer": "Acapulco" + }, + { + "Category": "TAKE A PILL", + "Question": "Antabuse is designed to make you feel really, really bad after ingesting this", + "Answer": "alcohol" + }, + { + "Category": "TRANSPORTATION", + "Question": "The transport for a 19th century double date might have been a barouche, one of these", + "Answer": "a carriage" + }, + { + "Category": "AN E FOR AN I", + "Question": "A \"landing\" area is transformed into a serious throat infection", + "Answer": "strep & strip" + }, + { + "Category": "EARLY AMERICA", + "Question": "In 1685 he joined his father in pastorship of the Old North Church, a post he held until his death", + "Answer": "Cotton Mather" + }, + { + "Category": "BEST PICTURE OSCAR-WINNERS IN OTHER WORDS", + "Question": "1976: \"A Single Colorado Mountain\"", + "Answer": "Rocky" + }, + { + "Category": "DOWN MEXICO WAY", + "Question": "Founded in the 1530s, this capital of Jalisco state is the second-largest in Mexico", + "Answer": "Guadalajara" + }, + { + "Category": "TAKE A PILL", + "Question": "Estramustine is a chemotherapy agent for this glandular cancer in men", + "Answer": "prostate cancer" + }, + { + "Category": "TRANSPORTATION", + "Question": "Cabbies in this Eur. city spend 2 years gaining \"the knowledge\", mental maps needed to get a license", + "Answer": "London" + }, + { + "Category": "AN E FOR AN I", + "Question": "\"Gentle\" becomes \"to blend\"", + "Answer": "mild & meld" + }, + { + "Category": "EARLY AMERICA", + "Question": "In 1562, in what is now S.C., these French Protestants established a colony named Port Royal", + "Answer": "the Huguenots" + }, + { + "Category": "BEST PICTURE OSCAR-WINNERS IN OTHER WORDS", + "Question": "1954: \"Dockside\"", + "Answer": "On the Waterfront" + }, + { + "Category": "DOWN MEXICO WAY", + "Question": "This gritty 1961 Tennessee Williams play unfolds in a seedy Mexican hotel", + "Answer": "Night of the Iguana" + }, + { + "Category": "TAKE A PILL", + "Question": "Pravastatin aims to block your body's ability to make this", + "Answer": "cholesterol" + }, + { + "Category": "TRANSPORTATION", + "Question": "In \"Sixteen Candles\", Molly Ringwald says, \"I loathe\" this method of transport", + "Answer": "the bus" + }, + { + "Category": "AN E FOR AN I", + "Question": "One means \"severely tested\"; the other, \"trapped on a branch\"", + "Answer": "tried & treed" + }, + { + "Category": "EARLY AMERICA", + "Question": "In \"Of Plymouth Plantation\", he wrote that there was so much disease \"the living were scarce able to bury the dead\"", + "Answer": "William Bradford" + }, + { + "Category": "BEST PICTURE OSCAR-WINNERS IN OTHER WORDS", + "Question": "1966: \"One Bloke Year-Round\"", + "Answer": "A Man For All Seasons" + }, + { + "Category": "DOWN MEXICO WAY", + "Question": "This popular resort island lies north of Cozumel off the coast of the state of Quintana Roo", + "Answer": "Cancun" + }, + { + "Category": "TAKE A PILL", + "Question": "This tranquilizer that sounds like a village was introduced in 1955 & became the USA's bestselling drug", + "Answer": "Miltown" + }, + { + "Category": "TRANSPORTATION", + "Question": "Since 1899 these stalwart animals used in transport have served as the mascots of the Army Corps of Cadets", + "Answer": "mules" + }, + { + "Category": "AN E FOR AN I", + "Question": "\"To replenish\" becomes \"to knock down\"", + "Answer": "to fill & to fell" + }, + { + "Category": "THE BRITISH THEATRE", + "Question": "Richard Attenborough, who was in the original 1952 cast of this play, helped celebrate its performance No. 20,000 in 2000", + "Answer": "The Mousetrap" + }, + { + "Category": "AT THE KENNEDY CENTER", + "Question": "Can you hear me? This rock opera by The Who was a big hit at the Kennedy Center in 1994", + "Answer": "Tommy" + }, + { + "Category": "NATIONAL MONUMENTS", + "Question": "George Custer's men are buried in a cemetery in the national monument named for this river", + "Answer": "Little Bighorn" + }, + { + "Category": "THE CIRCUS", + "Question": "Trainers shout, \"Tail Up!\" when they want these performers to follow each other trunk to tail", + "Answer": "Elephants" + }, + { + "Category": "ON THE RADIO", + "Question": "Radio abbreviation that precedes the name of rap figures Quik, Pooh & Jazzy Jeff", + "Answer": "DJ" + }, + { + "Category": "CELEB STUFF", + "Question": "On March 2, 1977 he made his first \"Tonight Show\" appearance; on May 25, 1992 he took over as host", + "Answer": "Jay Leno" + }, + { + "Category": "COMMON BONDS", + "Question": "Door, Nobel, booby", + "Answer": "prizes" + }, + { + "Category": "AT THE KENNEDY CENTER", + "Question": "In 1995 Luigi Bonino starred in a ballet about this \"Little Tramp\" of silent films", + "Answer": "Charlie Chaplin" + }, + { + "Category": "NATIONAL MONUMENTS", + "Question": "Scotts Bluff National Monument lies in western Nebraska on this pioneer trail", + "Answer": "Oregon Trail" + }, + { + "Category": "THE CIRCUS", + "Question": "It's the familiar term for a circus' largest tent, where the main show appears", + "Answer": "the big top" + }, + { + "Category": "ON THE RADIO", + "Question": "Robin Quivers is the radio consort of this self-proclaimed \"King of All Media\"", + "Answer": "Howard Stern" + }, + { + "Category": "COMMON BONDS", + "Question": "Inner tubes, doughnuts, the ozone layer", + "Answer": "things with holes" + }, + { + "Category": "AT THE KENNEDY CENTER", + "Question": "This president's 1972 visit to China inspired an opera that played at the Kennedy Center in 1988", + "Answer": "Richard Nixon" + }, + { + "Category": "NATIONAL MONUMENTS", + "Question": "Seminole Indian leader Osceola is buried at this fort where the Civil War began", + "Answer": "Fort Sumter" + }, + { + "Category": "THE CIRCUS", + "Question": "Pink is the most popular color of this fluffy confection made from spun sugar", + "Answer": "cotton candy" + }, + { + "Category": "ON THE RADIO", + "Question": "Call letters east of the Mississippi generally start with W; in the west, most start with this", + "Answer": "K" + }, + { + "Category": "CELEB STUFF", + "Question": "People Magazine called his 1997 solo album \"Destination Anywhere\", \"Tres Bon\"", + "Answer": "Jon Bon Jovi" + }, + { + "Category": "COMMON BONDS", + "Question": "Peeling onions, watching Mel Gibson's film \"Forever Young\", missing Final Jeopardy!", + "Answer": "things that make you cry" + }, + { + "Category": "AT THE KENNEDY CENTER", + "Question": "Every December, the Kennedy Center invites the public to a free sing-along of this composer's \"Messiah\"", + "Answer": "G.F. Handel" + }, + { + "Category": "NATIONAL MONUMENTS", + "Question": "This Wyoming monument contains an 865-foot-high fluted column of igneous rock", + "Answer": "Devils Tower" + }, + { + "Category": "THE CIRCUS", + "Question": "Antoinette Concello's triple somersault helped make her the \"Queen of\" this \"flying\" apparatus", + "Answer": "trapeze" + }, + { + "Category": "ON THE RADIO", + "Question": "Detroit-born broadcaster who created \"American Top 40\" & now has his own weekly \"Countdown\"", + "Answer": "Casey Kasem" + }, + { + "Category": "CELEB STUFF", + "Question": "In a 1997 issue of \"George\", he said his cousins Michael & Joseph were \"poster boys for bad behavior\"", + "Answer": "John F. Kennedy, Jr." + }, + { + "Category": "COMMON BONDS", + "Question": "Bobby, bowling, rolling", + "Answer": "pins" + }, + { + "Category": "AT THE KENNEDY CENTER", + "Question": "A 1994 festival honoring this country featured the Tjapukai Aboriginal Dance Company", + "Answer": "Australia" + }, + { + "Category": "NATIONAL MONUMENTS", + "Question": "Castillo de San Marcos in this Florida city is the oldest masonry fort in the continental U.S.", + "Answer": "St. Augustine" + }, + { + "Category": "THE CIRCUS", + "Question": "This steam whistle organ draws crowds to circus parades because it can be heard from miles away: [audio clue]", + "Answer": "calliope" + }, + { + "Category": "ON THE RADIO", + "Question": "The AAA format, featuring artists like the Cranberries & Tom Petty, stands for adult album this", + "Answer": "alternative" + }, + { + "Category": "CELEB STUFF", + "Question": "Her 1988 major label debut album was \"Y Kant Tori Read\"", + "Answer": "Tori Amos" + }, + { + "Category": "COMMON BONDS", + "Question": "Hollywood, salad, Super", + "Answer": "bowls" + }, + { + "Category": "THE OBLIGATORY POETRY CATEGORY", + "Question": "The one word quothed by Edgar Allan Poe's raven", + "Answer": "\"Nevermore!\"" + }, + { + "Category": "ART", + "Question": "You can't make a genuine tempera painting without breaking these", + "Answer": "eggs" + }, + { + "Category": "THE REDCOATS ARE COMING!", + "Question": "On Sept. 5, 1781, 24 of this country's ships engaged British ships in Cheaspeake Bay & turned them back", + "Answer": "France" + }, + { + "Category": "\"HIGH\" SCHOOL", + "Question": "Chuck Taylor, from whom Converse named a line of these shoes, was a basketball star of the 1910s", + "Answer": "high-tops" + }, + { + "Category": "OFF TO A GOOD START", + "Question": "It's the go-ahead in a kid's game & for a car at an intersection", + "Answer": "a green light" + }, + { + "Category": "THE OBLIGATORY POETRY CATEGORY", + "Question": "It follows \"Poems are made by fools like me...\"", + "Answer": "\"But only God can make a tree\"" + }, + { + "Category": "ART", + "Question": "Surrealists used odd juxtapositions in this form whose name is French for \"gluing\"", + "Answer": "collage" + }, + { + "Category": "THE REDCOATS ARE COMING!", + "Question": "During the war, this first signer of the Declaration of Independence commanded the Mass. Militia", + "Answer": "John Hancock" + }, + { + "Category": "\"HIGH\" SCHOOL", + "Question": "The L.A. Dodgers & the U. of Louisville basketball team pioneered this gesture in the late '70s", + "Answer": "the high five" + }, + { + "Category": "OFF TO A GOOD START", + "Question": "A baker who never uses packaged mixes always \"starts from\" here", + "Answer": "scratch" + }, + { + "Category": "THE OBLIGATORY POETRY CATEGORY", + "Question": "In preparing to write this poem, Longfellow used \"An historical and statistical account of Nova Scotia\"", + "Answer": "Evangeline" + }, + { + "Category": "ART", + "Question": "Edward Steichen led the movement to recognize as art these images, whose name means \"drawn with light\"", + "Answer": "photographs" + }, + { + "Category": "THE REDCOATS ARE COMING!", + "Question": "In it, Thomas Paine wrote, \"The cause of America is in a great measure the cause of all mankind\"", + "Answer": "Common Sense" + }, + { + "Category": "\"HIGH\" SCHOOL", + "Question": "Coastal waters beyond national jurisdiction, or the tops of some sopranos' ranges", + "Answer": "High seas/C's" + }, + { + "Category": "OFF TO A GOOD START", + "Question": "It's a ship at home in the Arctic, or a remark that starts a conversation", + "Answer": "an icebreaker" + }, + { + "Category": "THE OBLIGATORY POETRY CATEGORY", + "Question": "In a poem titled for the date when Germany invaded Poland, W.H. Auden called this \"A low dishonest decade\"", + "Answer": "1930s" + }, + { + "Category": "THE REDCOATS ARE COMING!", + "Question": "The Battle of Long Island was fought in what is now this New York City borough", + "Answer": "Brooklyn" + }, + { + "Category": "\"HIGH\" SCHOOL", + "Question": "The HD in the new digital format HDTV stands for this", + "Answer": "high definition" + }, + { + "Category": "OFF TO A GOOD START", + "Question": "It begins a football game or a special event like a political campaign", + "Answer": "the kickoff" + }, + { + "Category": "THE OBLIGATORY POETRY CATEGORY", + "Question": "Observing pilgrims traveling to the shrine of Thomas Becket inspired him to write his greatest work", + "Answer": "Geoffrey Chaucer" + }, + { + "Category": "ART", + "Question": "In 1920 this impressionist, known for his water lilies, painted another plant, \"Wisteria\"", + "Answer": "Claude Monet" + }, + { + "Category": "THE REDCOATS ARE COMING!", + "Question": "The British ferried 2,200 troops across this river to battle the Americans at Bunker Hill", + "Answer": "the Charles River" + }, + { + "Category": "\"HIGH\" SCHOOL", + "Question": "Acolytes, a subdeacon & a choir take part in this Catholic service", + "Answer": "high mass" + }, + { + "Category": "OFF TO A GOOD START", + "Question": "In a business project, it's the level investors try to \"get in on\"", + "Answer": "the ground floor" + }, + { + "Category": "THE CONSTITUTION", + "Question": "Word completing the line \"Nor shall any person be subject for the same offense to be twice put in\" this", + "Answer": "Jeopardy" + }, + { + "Category": "THRILLER", + "Question": "This author's techno-thriller \"Rainbow Six\" focuses on John Clark, also a hero in \"Clear & Present Danger\"", + "Answer": "Tom Clancy" + }, + { + "Category": "BEN", + "Question": "Ben Franklin went to London in 1757 to represent this colony's assembly", + "Answer": "Pennsylvania" + }, + { + "Category": "\"BLACK\" OR \"WHITE\"", + "Question": "Name shared by a Sauk chief famous for his war & a U.S. military helicopter", + "Answer": "Black Hawk" + }, + { + "Category": "REMEMBER THE TIME", + "Question": "In 1958 this country launched its second 5-year plan, called \"The Great Leap Forward\"", + "Answer": "China" + }, + { + "Category": "ROCK WITH YOU", + "Question": "This Jackson 5 (& later Mariah Carey) hit begins, \"You & I must make a pact, we must bring salvation back...\"", + "Answer": "\"I'll Be There\"" + }, + { + "Category": "EAT IT!", + "Question": "This Hormel product was once simply known as \"spiced ham\"", + "Answer": "Spam" + }, + { + "Category": "THRILLER", + "Question": "This author made a University of Virginia law professor the protagonist of his 2002 novel \"The Summons\"", + "Answer": "Grisham" + }, + { + "Category": "BEN", + "Question": "This publication that Ben first put out in 1732 often sold 10,000 copies a year", + "Answer": "Poor Richard's Almanack" + }, + { + "Category": "\"BLACK\" OR \"WHITE\"", + "Question": "This \"Golden Girl\" had her own show in 1958 & 1977 & in 1999 became part of the cast of \"Ladies Man\"", + "Answer": "Betty White" + }, + { + "Category": "REMEMBER THE TIME", + "Question": "In 960 Mieczyslaw I became the first ruler of this country", + "Answer": "Poland" + }, + { + "Category": "ROCK WITH YOU", + "Question": "Jakob Dylan, the son of Bob Dylan, is the frontman for this group", + "Answer": "The Wallflowers" + }, + { + "Category": "EAT IT!", + "Question": "It's the Spanish-named appetizer of tortilla chips & often beans, beef & onions topped with melted cheese", + "Answer": "nachos" + }, + { + "Category": "THRILLER", + "Question": "You were born to identify this author of \"The Bourne Identity\"", + "Answer": "Ludlum" + }, + { + "Category": "BEN", + "Question": "In 1783 Franklin asked Congress to recall him from this country; he finally made it home in 1785", + "Answer": "France" + }, + { + "Category": "\"BLACK\" OR \"WHITE\"", + "Question": "People have asked why the whole airplane isn't made out of the same material as this \"indestructible\" device", + "Answer": "the black box" + }, + { + "Category": "REMEMBER THE TIME", + "Question": "In 1526 he greeted an Inca nobleman on his ship, but conquest would have to wait a few years until funds were raised", + "Answer": "Pizarro" + }, + { + "Category": "ROCK WITH YOU", + "Question": "Eric Clapton charted 3 times with this song: in 1971, 1972 & 1992", + "Answer": "\"Layla\"" + }, + { + "Category": "EAT IT!", + "Question": "Paper-thin & often served for dessert, it's the French equivalent of a pancake", + "Answer": "crêpes" + }, + { + "Category": "THRILLER", + "Question": "\"The Numa Files\" are paperback spin-offs of this writer's novels featuring Dirk Pitt", + "Answer": "Clive Cussler" + }, + { + "Category": "BEN", + "Question": "Current events of 1751 included the appearance of Ben's scientific work \"Experiments and Observations on\" this", + "Answer": "\"Electricity\"" + }, + { + "Category": "\"BLACK\" OR \"WHITE\"", + "Question": "John Archibald Wheeler coined this term in the '60s for a collapsed star so dense, no light can escape it", + "Answer": "black hole" + }, + { + "Category": "REMEMBER THE TIME", + "Question": "In 1998 U.S. cruise missiles hit this African country in response to bombings of U.S. embassies", + "Answer": "Sudan" + }, + { + "Category": "THRILLER", + "Question": "\"The Attorney\" Paul Madriani appears in several legal thrillers by this lawyer-turned-author", + "Answer": "Steve Martini" + }, + { + "Category": "BEN", + "Question": "The Hutchinson Letters scandal got Ben fired as deputy this in 1774", + "Answer": "postmaster general" + }, + { + "Category": "\"BLACK\" OR \"WHITE\"", + "Question": "Famous landmark composed of chalk in the county of Kent in England", + "Answer": "the White Cliffs of Dover" + }, + { + "Category": "REMEMBER THE TIME", + "Question": "This 1904-1905 war began in Manchuria & ended with the battle of Tsushima Strait", + "Answer": "Russo-Japanese War" + }, + { + "Category": "ROCK WITH YOU", + "Question": "Quit your yellin' & name this 1995 hit duet for Michael & Janet Jackson, their first together", + "Answer": "\"Scream\"" + }, + { + "Category": "EAT IT!", + "Question": "Traditionally, shepherd's pie contains this meat, ground or diced", + "Answer": "lamb" + }, + { + "Category": "SCOTLAND", + "Question": "About 80,000 Scots still speak the Scottish version of this ancient Celtic language", + "Answer": "Gaelic" + }, + { + "Category": "BABY BOOMER MEMORIES", + "Question": "In 1960 this Democrat spoke first in the first televised U.S. presidential election debate", + "Answer": "John F. Kennedy" + }, + { + "Category": "SOMETHING'S FISHY", + "Question": "So as not to confuse it with the mammal, this fish is commonly referred to as mahi-mahi", + "Answer": "a dolphinfish" + }, + { + "Category": "\"T\"ELEVISION", + "Question": "Running for 5 years, it starred William Shatner as a hard-nosed veteran police officer", + "Answer": "T.J. Hooker" + }, + { + "Category": "WORLD RELIGION", + "Question": "In the presence of the Adi Granth, the sacred book of the Sikhs, you cover your head & remove these", + "Answer": "your shoes" + }, + { + "Category": "SORTA SOUNDS LIKE OPRAH?", + "Question": "Bizet's \"Carmen\", for example", + "Answer": "an opera" + }, + { + "Category": "SCOTLAND", + "Question": "Ben More, Ben Alder & Ben Macdui are not people but tall ones of these in Scotland", + "Answer": "mountains" + }, + { + "Category": "BABY BOOMER MEMORIES", + "Question": "Likely containing a sandwich, the first of these depicting a TV character came along in 1950 with Hopalong Cassidy", + "Answer": "a lunchbox" + }, + { + "Category": "SOMETHING'S FISHY", + "Question": "The black type of this fish with a woman's name is a striking addition to any aquarium", + "Answer": "a molly" + }, + { + "Category": "\"T\"ELEVISION", + "Question": "Reminiscent of \"Highway to Heaven\", this popular series stars Roma Downey & Della Reese", + "Answer": "Touched by an Angel" + }, + { + "Category": "WORLD RELIGION", + "Question": "Sukkot, a Jewish festival, began as a harvest celebration & was a model for this centuries-old American holiday", + "Answer": "Thanksgiving" + }, + { + "Category": "SORTA SOUNDS LIKE OPRAH?", + "Question": "Phrase that precedes \"dope\" in Ali's famed boxing strategy", + "Answer": "\"rope-a\"" + }, + { + "Category": "SCOTLAND", + "Question": "Defeated at Dunsinane by Malcolm in 1054, he wasn't dethroned until killed by Malcolm in 1057", + "Answer": "Macbeth" + }, + { + "Category": "BABY BOOMER MEMORIES", + "Question": "The John Birch Society coined the term comsymp, short for this", + "Answer": "Communist sympathizer" + }, + { + "Category": "SOMETHING'S FISHY", + "Question": "Less than half an inch long, this tiniest fish is found in the Indian Ocean, not in an Asian desert", + "Answer": "a goby" + }, + { + "Category": "\"T\"ELEVISION", + "Question": "This offbeat series on E! provides a daily recap of funny chat show highlights", + "Answer": "Talk Soup" + }, + { + "Category": "WORLD RELIGION", + "Question": "As they were partial to using hymns, these brothers, Charles & John, were the first rhythm Methodists", + "Answer": "the Wesleys" + }, + { + "Category": "SORTA SOUNDS LIKE OPRAH?", + "Question": "In an Irish battle cry, these 2 words follow \"Erin\"", + "Answer": "\"Go Bragh\"" + }, + { + "Category": "SCOTLAND", + "Question": "The Church of Scotland, the country's national church, is a branch of this Christian denomination", + "Answer": "Presbyterian" + }, + { + "Category": "BABY BOOMER MEMORIES", + "Question": "In a heartbreaking scene, Travis has to kill his beloved dog in this 1957 film based on a Fred Gipson book", + "Answer": "Old Yeller" + }, + { + "Category": "SOMETHING'S FISHY", + "Question": "Until one was caught in 1938, it was thought that this fish had been extinct for more than 70 million years", + "Answer": "the coelacanth" + }, + { + "Category": "WORLD RELIGION", + "Question": "Meaning \"sign of God\", it's the title of a Shi'ite Muslim scholar & leader", + "Answer": "Ayatollah" + }, + { + "Category": "SCOTLAND", + "Question": "Hundreds of years old, the de facto national flag features this saint's cross", + "Answer": "Andrew" + }, + { + "Category": "BABY BOOMER MEMORIES", + "Question": "In 1967 this 21-year-old started Rolling Stone magazine", + "Answer": "Jann Wenner" + }, + { + "Category": "\"T\"ELEVISION", + "Question": "Co-hosted by John Davidson, it was ABC's response to NBC's \"Real People\"", + "Answer": "That's Incredible!" + }, + { + "Category": "WORLD RELIGION", + "Question": "Made up of 1,028 hymns in 10 books, it's the oldest of the Vedas in Hinduism", + "Answer": "Rigveda" + }, + { + "Category": "SORTA SOUNDS LIKE OPRAH?", + "Question": "In 2001 this author of \"The Seven Spiritual Laws of Success\" published \"The Deeper Wound\"", + "Answer": "Chopra" + }, + { + "Category": "GEOGRAPHIC PHRASES", + "Question": "This common term originated in the early 1500s with the book \"De Rebus Oceanicis et Novo Orbe\"", + "Answer": "the New World" + }, + { + "Category": "ACTRESSES' FIRST FILMS", + "Question": "\"Body Heat\"", + "Answer": "Kathleen Turner" + }, + { + "Category": "LIBRARIES", + "Question": "Marsh's Library in this country was founded c. 1702 by the Archbishop of Dublin", + "Answer": "Ireland" + }, + { + "Category": "TELEPHONE HISTORY", + "Question": "In 1991 this telephone company launched its Friends & Family promotion", + "Answer": "MCI" + }, + { + "Category": "VERMONTERS", + "Question": "This leader of the Green Mountain Boys did not live to see Vermont become a state", + "Answer": "Ethan Allen" + }, + { + "Category": "\"X\", \"Y\", \"Z\"", + "Question": "It looks like a sweet potato, but it isn't even a distant relative", + "Answer": "a yam" + }, + { + "Category": "SHAKESPEAREAN LAST SCENES", + "Question": "You could say this comedy \"ends well\" -- Helena finally wins the love of her husband Bertram", + "Answer": "All's Well That Ends Well" + }, + { + "Category": "ACTRESSES' FIRST FILMS", + "Question": "\"To Have and Have Not\"", + "Answer": "Bacall" + }, + { + "Category": "LIBRARIES", + "Question": "Architect Gordon Bunshaft designed this presidential library in Austin, Texas", + "Answer": "the LBJ library" + }, + { + "Category": "TELEPHONE HISTORY", + "Question": "As of July 1, 1968 you could dial this 3-digit number in New York City & get the police", + "Answer": "911" + }, + { + "Category": "VERMONTERS", + "Question": "This founding prophet of Mormonism was born in Sharon, Vermont in 1805", + "Answer": "Joseph Smith" + }, + { + "Category": "\"X\", \"Y\", \"Z\"", + "Question": "It's a kind of striped mussel as well as a striped equine", + "Answer": "a zebra" + }, + { + "Category": "SHAKESPEAREAN LAST SCENES", + "Question": "Though this comedy has Verona in its title, it ends in a forest on the frontiers of Mantua", + "Answer": "The Two Gentlemen of Verona" + }, + { + "Category": "ACTRESSES' FIRST FILMS", + "Question": "\"The Outlaw\"", + "Answer": "Jane Russell" + }, + { + "Category": "LIBRARIES", + "Question": "Sterling Memorial Library in New Haven, Connecticut houses the archives of this university", + "Answer": "Yale" + }, + { + "Category": "TELEPHONE HISTORY", + "Question": "On Oct. 30, 1938 phone traffic peaked in cities all over America as people discussed this broadcast", + "Answer": "the \"War of the Worlds\"" + }, + { + "Category": "VERMONTERS", + "Question": "This plow inventor was a Vermont blacksmith before moving to Grand Detour, Illinois", + "Answer": "John Deere" + }, + { + "Category": "\"X\", \"Y\", \"Z\"", + "Question": "Despite its bulk, this wild ox found in Tibet is an excellent swimmer", + "Answer": "a yak" + }, + { + "Category": "SHAKESPEAREAN LAST SCENES", + "Question": "Near the end of \"Henry VIII\", this princess is described as \"a most unspotted lily\", who will die a virgin", + "Answer": "Elizabeth I" + }, + { + "Category": "ACTRESSES' FIRST FILMS", + "Question": "\"Oklahoma!\"", + "Answer": "Shirley Jones" + }, + { + "Category": "LIBRARIES", + "Question": "Salinas, California, has a public library named for this novelist", + "Answer": "Steinbeck" + }, + { + "Category": "TELEPHONE HISTORY", + "Question": "In 1980 Dial-It National Sports became the first service on this new area code", + "Answer": "1-900" + }, + { + "Category": "VERMONTERS", + "Question": "George Franklin Edmunds wrote most of this antitrust act of 1890", + "Answer": "the Sherman" + }, + { + "Category": "\"X\", \"Y\", \"Z\"", + "Question": "Some of these are produced by bremsstrahlung, from the German for \"breaking radiation\"", + "Answer": "x-rays" + }, + { + "Category": "SHAKESPEAREAN LAST SCENES", + "Question": "Puck's last speech in this play begins, \"If we shadows have offended, think but this--and all is mended\"", + "Answer": "A Midsummer Night's Dream" + }, + { + "Category": "ACTRESSES' FIRST FILMS", + "Question": "\"Halloween\"", + "Answer": "Jamie Lee Curtis" + }, + { + "Category": "LIBRARIES", + "Question": "In 1602 this university's library reopened after restoration work by Sir Thomas Bodley", + "Answer": "Oxford University" + }, + { + "Category": "TELEPHONE HISTORY", + "Question": "In 1880 he invented the photophone, a device that sent messages through the air on beams of light", + "Answer": "Alexander Graham Bell" + }, + { + "Category": "VERMONTERS", + "Question": "At age 15 this future New York Tribune editor was apprenticed to a printer in East Poultney", + "Answer": "Horace Greeley" + }, + { + "Category": "\"X\", \"Y\", \"Z\"", + "Question": "This Saint Francis was the \"Apostle of the Indies\"", + "Answer": "Xavier" + }, + { + "Category": "SHAKESPEAREAN LAST SCENES", + "Question": "In the last scene of this comedy, Petruchio wins a bet that he has the most obedient wife", + "Answer": "The Taming of the Shrew" + }, + { + "Category": "MEDICAL MILESTONES", + "Question": "In 1751, with Benjamin Franklin's help, the 1st hospital in the U.S. was founded in this city", + "Answer": "Philadelphia" + }, + { + "Category": "POETS & POETRY", + "Question": "Of the 31 pilgrims in this Chaucer work, only 23 tell their stories", + "Answer": "The Canterbury Tales" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "Large aboriginal populations live in this country's states of Queensland & New South Wales", + "Answer": "Australia" + }, + { + "Category": "MIXED DRINKS", + "Question": "The juice of one of these citrus fruits makes a Whiskey Sour sour", + "Answer": "a lemon" + }, + { + "Category": "THE 1930s", + "Question": "In 1936, in defiance of the Treaty of Versailles, this country began remilitarizing the Rhineland", + "Answer": "Germany" + }, + { + "Category": "POP MUSIC", + "Question": "He recorded \"Gone At Last\" with Phoebe Snow, not Art Garfunkel", + "Answer": "Paul Simon" + }, + { + "Category": "MEDICAL MILESTONES", + "Question": "In 1867 Thomas Allbutt invented one of these instruments which took 5 minutes to register instead of 20", + "Answer": "a thermometer" + }, + { + "Category": "POETS & POETRY", + "Question": "This Longfellow poem was suggested by a smithy under a chestnut tree in Cambridge, Massachusetts", + "Answer": "\"The Village Blacksmith\"" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "Administrative units in this country include Giza, Aswan & Suez", + "Answer": "Egypt" + }, + { + "Category": "MIXED DRINKS", + "Question": "This pomegranate syrup turns a Pink Lady pink", + "Answer": "grenadine" + }, + { + "Category": "THE 1930s", + "Question": "This longtime anchor of the CBS Evening News became a UPI correspondent in 1939", + "Answer": "Walter Cronkite" + }, + { + "Category": "POP MUSIC", + "Question": "She sang \"Better Be Good To Me\" in 1984, a few years after she broke up with Ike", + "Answer": "Tina Turner" + }, + { + "Category": "MEDICAL MILESTONES", + "Question": "Dutch physician Willem Kolff developed the 1st of these kidney machines that cleanse the blood", + "Answer": "a dialysis machine" + }, + { + "Category": "POETS & POETRY", + "Question": "Oliver Wendell Holmes wrote of this ship, \"Oh better that her shattered hulk should sink beneath the wave\"", + "Answer": "\"Old Ironsides\"" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "This longest river on the Iberian Peninsula is also known as the Tajo", + "Answer": "the Tagus" + }, + { + "Category": "MIXED DRINKS", + "Question": "A teaspoon of creme de cassis is added to this to make a Kir", + "Answer": "white wine" + }, + { + "Category": "THE 1930s", + "Question": "Helen Keller brought the first of these Japanese dogs to the United States in 1937", + "Answer": "the akita" + }, + { + "Category": "POP MUSIC", + "Question": "In \"Take Me Home, Country Roads\", John Denver sang, \"Almost heaven,\" this state", + "Answer": "West Virginia" + }, + { + "Category": "MEDICAL MILESTONES", + "Question": "In 1906 August von Wassermann developed a well-known test for this sexually transmitted disease", + "Answer": "syphilis" + }, + { + "Category": "POETS & POETRY", + "Question": "His \"When the Frost is on the Punkin\" was written for a series in the Indianapolis Journal", + "Answer": "Riley" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "Cabinda, an area of this former Portuguese colony, is separated from the rest of it by Zaire", + "Answer": "Angola" + }, + { + "Category": "MIXED DRINKS", + "Question": "A basic Gin Rickey is gin, lime & this non-potent potable", + "Answer": "soda water" + }, + { + "Category": "THE 1930s", + "Question": "He was appointed conductor of the Boston Pops in 1930", + "Answer": "Arthur Fiedler" + }, + { + "Category": "POP MUSIC", + "Question": "Alan, Merrill & Wayne, 3 of these Utah brothers, co-wrote their own 1972 hit \"Crazy Horses\"", + "Answer": "the Osmonds" + }, + { + "Category": "MEDICAL MILESTONES", + "Question": "In 1982 William DeVries performed the 1st permanent artificial heart transplant on this man", + "Answer": "Barney Clark" + }, + { + "Category": "POETS & POETRY", + "Question": "He was descended from an Abyssinian prince, Peter the Great's godson", + "Answer": "Pushkin" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "The Indus River provides the western border of this desert also known as the Great Indian Desert", + "Answer": "the Thar Desert" + }, + { + "Category": "MIXED DRINKS", + "Question": "Using Scotch whisky turns a Manhattan into this drink", + "Answer": "a Rob Roy" + }, + { + "Category": "THE 1930s", + "Question": "This author of \"Anne of Green Gables\" was awarded the Order of the British Empire in 1935", + "Answer": "Montgomery" + }, + { + "Category": "POP MUSIC", + "Question": "This singer's 1970 hit \"I'll Never Fall In Love Again\" was from the Broadway musical \"Promises, Promises\"", + "Answer": "Dionne Warwick" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "On May 29, 1765 Patrick Henry's Stamp Act protest was interrupted with this one word", + "Answer": "Treason!" + }, + { + "Category": "CANADIAN GEOGRAPHY, EH?", + "Question": "A narrow passage separates Canada's Ellesmere Island from this large Danish island", + "Answer": "Greenland" + }, + { + "Category": "ON HIS BASEBALL HALL OF FAME PLAQUE", + "Question": "This Yankee was the \"greatest drawing card in history of baseball\"", + "Answer": "Babe Ruth" + }, + { + "Category": "STAMPS", + "Question": "Woo hoo! In 2009 this animated family was chosen to grace stamps, though postage did go up to 44 cents (D'oh!)", + "Answer": "the Simpsons" + }, + { + "Category": "THE KILLERS", + "Question": "In Genesis 4 he becomes the first killer; God isn't happy", + "Answer": "Cain" + }, + { + "Category": "SPOTT THA MISPELED WURD", + "Question": "Meet me in the library for a liaison at your liesure", + "Answer": "leisure" + }, + { + "Category": "THE BIG 10", + "Question": "The first 10 of these are known as the Bill of Rights", + "Answer": "the Amendments" + }, + { + "Category": "CANADIAN GEOGRAPHY, EH?", + "Question": "Mount Logan, Canada's highest peak, is found in this territory", + "Answer": "the Yukon Territory" + }, + { + "Category": "ON HIS BASEBALL HALL OF FAME PLAQUE", + "Question": "\"Detroit - Philadelphia, A.L. - 1905-1926... retired with 4191 major league hits\"", + "Answer": "Cobb" + }, + { + "Category": "STAMPS", + "Question": "This astronomer for whom a space telescope is named is honored in the American Scientists series", + "Answer": "Hubble" + }, + { + "Category": "THE KILLERS", + "Question": "In one of the few documented one-on-one Old West gunfights, this \"Wild\" man killed Davis Tutt in 1865", + "Answer": "Wild Bill Hickok" + }, + { + "Category": "SPOTT THA MISPELED WURD", + "Question": "The occasional misspelling is noticable on a telecast like \"Jeopardy!\"", + "Answer": "noticeable" + }, + { + "Category": "THE BIG 10", + "Question": "In Israel Tevet is the tenth of these", + "Answer": "month" + }, + { + "Category": "CANADIAN GEOGRAPHY, EH?", + "Question": "Of the top 5 Canadian cities in population, it's the one closest to the Pacific Ocean", + "Answer": "Vancouver" + }, + { + "Category": "ON HIS BASEBALL HALL OF FAME PLAQUE", + "Question": "\"'Mr. Octobe", + "Answer": "Jackson" + }, + { + "Category": "STAMPS", + "Question": "A stamp honors this 19th c. author about whom it was said, \"So this is the little lady who made this big war\"", + "Answer": "Harriet Beecher Stowe" + }, + { + "Category": "THE KILLERS", + "Question": "Bodyguards Satwant & Beant Singh killed this female leader of India in 1984", + "Answer": "Indira Gandhi" + }, + { + "Category": "SPOTT THA MISPELED WURD", + "Question": "If you supersede the competition, you will excede all expectations", + "Answer": "exceed" + }, + { + "Category": "THE BIG 10", + "Question": "In L.A., the western tip of Interstate 10 is called this \"freeway\", after the beach community it passes through", + "Answer": "Santa Monica" + }, + { + "Category": "CANADIAN GEOGRAPHY, EH?", + "Question": "Appropriately, New Glasgow is in this Canadian province", + "Answer": "Nova Scotia" + }, + { + "Category": "ON HIS BASEBALL HALL OF FAME PLAQUE", + "Question": "This 2009 inductee was \"faster than a speeding bullet\"", + "Answer": "Rickey Henderson" + }, + { + "Category": "THE KILLERS", + "Question": "This \"insect\" of a gangster was a real-life hit man for Murder Incorporated in the 1930s & '40s", + "Answer": "Bugsy Siegel" + }, + { + "Category": "SPOTT THA MISPELED WURD", + "Question": "We want you to be committed to catagorizing your collectibles cohesively", + "Answer": "categorizing" + }, + { + "Category": "THE BIG 10", + "Question": "The title of this Boccaccio work means \"10 Days\"", + "Answer": "Decameron" + }, + { + "Category": "CANADIAN GEOGRAPHY, EH?", + "Question": "This province has the longest border, including water, with the United States", + "Answer": "Ontario" + }, + { + "Category": "ON HIS BASEBALL HALL OF FAME PLAQUE", + "Question": "\"Boston Red Sox A.L. 1939-1960... batted .406 in 1941\"", + "Answer": "Ted Williams" + }, + { + "Category": "STAMPS", + "Question": "The Distinguished Marines series honors the man for whom a North Carolina Marine Corps base was named", + "Answer": "Lt. Gen. John Lejeune" + }, + { + "Category": "THE KILLERS", + "Question": "Pausanius, a young Macedonian noble, killed this man, Alexander's dad, in 336 B.C.", + "Answer": "Philip" + }, + { + "Category": "SPOTT THA MISPELED WURD", + "Question": "The accomodations at the monastery were rudimentary at best", + "Answer": "accommodations" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "In 1869 this Austrian monk published a paper on hawkweed: the experiments didn't work as well as the ones with peas", + "Answer": "Mendel" + }, + { + "Category": "INSTRUMENT ETYMOLOGY", + "Question": "It's appropriate that the name of this double reed instrument with a low range comes from the Italian for \"low\"", + "Answer": "a bassoon" + }, + { + "Category": "FACIAL EXPRESSIONS", + "Question": "This word meaning \"empty\" or \"to be filled in\" describes a vacant type of stare", + "Answer": "blank" + }, + { + "Category": "LIT MY FIRE", + "Question": "\"The Fire Sermon\" is Part III of this poet's \"The Waste Land\"", + "Answer": "T.S. Eliot" + }, + { + "Category": "THE STAR'S TV SHOW & MOVIE", + "Question": "\"Sex and the City\", \"Sex and the City\" (& \"Did you Hear About the Morgans?\")", + "Answer": "Sarah Jessica Parker" + }, + { + "Category": "THE BIG 10-LETTER WORDS", + "Question": "Relatively speaking, it's your mom's husband by a later marriage", + "Answer": "a stepfather" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "Unusual names borne by these celestial objects include 3834 Zappafrank & 10221 Kubrick", + "Answer": "asteroids" + }, + { + "Category": "INSTRUMENT ETYMOLOGY", + "Question": "Your dog will scratch his head if you don't know the ukulele's name comes from the Hawaiian for this \"jumping\" insect", + "Answer": "the flea" + }, + { + "Category": "FACIAL EXPRESSIONS", + "Question": "It's a self-satisfied smile or grin that you may be asked to wipe off your face", + "Answer": "smirk" + }, + { + "Category": "LIT MY FIRE", + "Question": "The burning of Moscow after Napoleon's exit is dramatized in this Tolstoy novel", + "Answer": "War and Peace" + }, + { + "Category": "THE STAR'S TV SHOW & MOVIE", + "Question": "\"Bosom Buddies\", \"The Green Mile\"", + "Answer": "Tom Hanks" + }, + { + "Category": "THE BIG 10-LETTER WORDS", + "Question": "From the late Latin for \"word\", this book is the last word on words", + "Answer": "dictionary" + }, + { + "Category": "INSTRUMENT ETYMOLOGY", + "Question": "The first 4 letters of xylophone refer etymologically to this material used to make its sounding bars", + "Answer": "wood" + }, + { + "Category": "LIT MY FIRE", + "Question": "In Book 1 of this, Satan is \"hurld hedlong flaming from th' ethereal skies... to dwell in adamantine chains and penal fire\"", + "Answer": "Paradise Lost" + }, + { + "Category": "THE STAR'S TV SHOW & MOVIE", + "Question": "\"Friends\", \"Bruce Almighty\"", + "Answer": "Jennifer Aniston" + }, + { + "Category": "THE BIG 10-LETTER WORDS", + "Question": "Don't lose your head: this French device shares its name with an instrument for surgically removing tonsils", + "Answer": "guillotine" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "This 4-letter neutral compound is produced by the reaction of an acid & a base", + "Answer": "a salt" + }, + { + "Category": "INSTRUMENT ETYMOLOGY", + "Question": "From the Latin for \"clear\" comes the name for this woodwind instrument", + "Answer": "clarinet" + }, + { + "Category": "FACIAL EXPRESSIONS", + "Question": "Jack Nicholson movie villain known for his rictus", + "Answer": "the Joker" + }, + { + "Category": "LIT MY FIRE", + "Question": "This Irish poet's \"Sailing to Byzantium\" urges \"sages... in God's holy fire\" to be \"singing masters of my soul\"", + "Answer": "William Butler Yeats" + }, + { + "Category": "THE STAR'S TV SHOW & MOVIE", + "Question": "\"In Living Color\", \"Bruce Almighty\"", + "Answer": "Jim Carrey" + }, + { + "Category": "THE BIG 10-LETTER WORDS", + "Question": "The report's back from the lab; it's the science dealing with the detection of poisons", + "Answer": "toxicology" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "Plants having these underground stems, from the Greek for \"root\", include irises, bamboo & wild ginger", + "Answer": "rhizomes" + }, + { + "Category": "FACIAL EXPRESSIONS", + "Question": "This word for a sidelong glance of crude desire used to mean \"the cheek\"", + "Answer": "a leer" + }, + { + "Category": "LIT MY FIRE", + "Question": "His 1963 bestseller \"The Fire Next Time\" took its title from an old spiritual", + "Answer": "James Baldwin" + }, + { + "Category": "THE STAR'S TV SHOW & MOVIE", + "Question": "\"The Office\", \"Bruce Almighty\"", + "Answer": "Steve Carell" + }, + { + "Category": "THE BIG 10-LETTER WORDS", + "Question": "Something that's the first son's due; Esau sold his", + "Answer": "birthright" + }, + { + "Category": "RANKS & TITLES", + "Question": "Owain Glyndwr, who died circa 1416, was the last native of his country to claim this title", + "Answer": "Prince of Wales" + }, + { + "Category": "WEATHER WORLD", + "Question": "Libya's arid climate is made worse by the ghibli, a crop-destroying wind from this desert", + "Answer": "Sahara" + }, + { + "Category": "ON THE COVER OF SGT. PEPPER", + "Question": "He's an African explorer, \"I presume\"", + "Answer": "Dr. Livingstone" + }, + { + "Category": "CLOTHING WORDS", + "Question": "A score of 22-22, for instance", + "Answer": "tie" + }, + { + "Category": "MY PLACE?", + "Question": "A Norman could say, \"I'm the king of the motte-and-bailey style of\" this", + "Answer": "castle" + }, + { + "Category": "IT'S A DATE!", + "Question": "You'll find this date on a calendar only once every 4 years", + "Answer": "February 29" + }, + { + "Category": "\"J\" WHIZ", + "Question": "It's a trip taken by a public official at public expense, ostensibly for official business", + "Answer": "junket" + }, + { + "Category": "WEATHER WORLD", + "Question": "In addition to helping commerce, these ocean winds bring pleasant weather to islands like Hawaii", + "Answer": "trade winds" + }, + { + "Category": "ON THE COVER OF SGT. PEPPER", + "Question": "Bob Dylan appears as does this poet from whom he may have taken his stage name", + "Answer": "Dylan Thomas" + }, + { + "Category": "CLOTHING WORDS", + "Question": "To lose footing on icy ground", + "Answer": "slip" + }, + { + "Category": "MY PLACE?", + "Question": "As he often said, Chris Farley's character Matt Foley lived in one of these down by the river", + "Answer": "van" + }, + { + "Category": "IT'S A DATE!", + "Question": "(Jimmy of the Clue Crew at the USS Arizona Memorial in Pearl Harbor, Hawaii) Pearl Harbor will always be remembered for this date in 1941, which FDR said \"will live in infamy\"", + "Answer": "7-Dec" + }, + { + "Category": "\"J\" WHIZ", + "Question": "It's not a type of fruit spread, but a large extended campout for several Boy Scout troops together", + "Answer": "jamboree" + }, + { + "Category": "WEATHER WORLD", + "Question": "In Venezuela, this \"season\" is from April to October; in the mountains of Peru, from November to March", + "Answer": "rainy season" + }, + { + "Category": "ON THE COVER OF SGT. PEPPER", + "Question": "This actor is in costume from his film \"The Wild One\"", + "Answer": "Marlon Brando" + }, + { + "Category": "CLOTHING WORDS", + "Question": "Breathes heavily, like a dog or a tired jogger", + "Answer": "pants" + }, + { + "Category": "MY PLACE?", + "Question": "The introduction to \"The Song of Hiawatha\" mentions \"the curling smoke of\" these dwellings", + "Answer": "wigwams" + }, + { + "Category": "IT'S A DATE!", + "Question": "Oregon entered the union on this date in 1859, sweetie", + "Answer": "14-Feb" + }, + { + "Category": "\"J\" WHIZ", + "Question": "It's believed that the Virgin Mary died in this Middle Eastern city", + "Answer": "Jerusalem" + }, + { + "Category": "WEATHER WORLD", + "Question": "It's the U.S. state that experiences the most tornadoes", + "Answer": "Texas" + }, + { + "Category": "ON THE COVER OF SGT. PEPPER", + "Question": "The Beatles' bass player before Paul took over", + "Answer": "Stu Sutcliffe" + }, + { + "Category": "CLOTHING WORDS", + "Question": "A layer of paint", + "Answer": "coat" + }, + { + "Category": "MY PLACE?", + "Question": "A book subtitled \"Architecture in the Colombian Countryside\" showcases the estates called these in Spanish", + "Answer": "haciendas" + }, + { + "Category": "IT'S A DATE!", + "Question": "It's Bird Day in Oklahoma, & a popular date for pole dancing", + "Answer": "1-May" + }, + { + "Category": "\"J\" WHIZ", + "Question": "This 1847 novel takes place mainly at Lowood Orphan Asylum & Thornfield Hall", + "Answer": "\"Jane Eyre\"" + }, + { + "Category": "WEATHER WORLD", + "Question": "The Australian mountains that include the Charlotte's Pass ski area, or the weather there in July", + "Answer": "Snowy" + }, + { + "Category": "ON THE COVER OF SGT. PEPPER", + "Question": "This \"Das Kapital\" author stands between comedian Oliver Hardy & H.G. Wells", + "Answer": "Karl Marx" + }, + { + "Category": "CLOTHING WORDS", + "Question": "Hits hard", + "Answer": "socks/belts" + }, + { + "Category": "MY PLACE?", + "Question": "A western camper pitches a tent; a central Asian nomad pitches this", + "Answer": "yurt" + }, + { + "Category": "IT'S A DATE!", + "Question": "O Canada celebrates Canada Day on this date, 3 days before a big American holiday", + "Answer": "1-Jul" + }, + { + "Category": "\"J\" WHIZ", + "Question": "The Hagia Sophia in Istanbul was one of the many churches built by this 6th century Byzantine emperor", + "Answer": "Justinian I" + }, + { + "Category": "PLAYWRIGHTS", + "Question": "Critic Walter Kerr called this man's \"Camino Real\" \"The worst play yet written by the best playwright of his generation\"", + "Answer": "Tennessee Williams" + }, + { + "Category": "THE 1890s", + "Question": "Japan had an emperor, Russia, a czar & Italy was ruled by one of these", + "Answer": "king" + }, + { + "Category": "AMERICAN NICKNAMES", + "Question": "She was called \"Little Missy\" & \"Little Sure Shot\"", + "Answer": "Annie Oakley" + }, + { + "Category": "\"S\"-OTERICA", + "Question": "Examples of this TV format include \"Leave It to Beaver\" & \"The King of Queens\"", + "Answer": "sitcom" + }, + { + "Category": "VIETNAM", + "Question": "It's not the capital, but this Vietnamese city is the most populous", + "Answer": "Ho Chi Minh City" + }, + { + "Category": "TOUR OF JUDY", + "Question": "Liza & Lorna's mom", + "Answer": "Judy Garland" + }, + { + "Category": "PLAYWRIGHTS", + "Question": "\"May All Your Fences Have Gates\" is a book of \"Essays on the Drama of\" this African-American playwright", + "Answer": "August Wilson" + }, + { + "Category": "THE 1890s", + "Question": "Of \"Frankenstein\", \"The Invisible Man\" or \"Dracula\", the one not created in 1897", + "Answer": "\"Frankenstein\"" + }, + { + "Category": "AMERICAN NICKNAMES", + "Question": "The \"Plant Magician\" was Luther Burbank; this man was the \"Plant Doctor\"", + "Answer": "George Washington Carver" + }, + { + "Category": "\"S\"-OTERICA", + "Question": "Slang term for a left-handed boxer or fiddle player", + "Answer": "southpaw" + }, + { + "Category": "VIETNAM", + "Question": "Of the 3 countries that border Vietnam, the one whose name does not begin with the same letter as the other 2", + "Answer": "Laos" + }, + { + "Category": "TOUR OF JUDY", + "Question": "This animated girl attends Orbit High School", + "Answer": "Judy Jetson" + }, + { + "Category": "PLAYWRIGHTS", + "Question": "(Sofia of the Clue Crew at the Nederlander Theatre in New York City) This creator of \"Rent\" died the night of its final dress rehearsal, never knowing he would win the Pulitzer Prize", + "Answer": "Jonathan Larson" + }, + { + "Category": "THE 1890s", + "Question": "Relationship of Lizzie Borden to the woman she was acquitted of killing", + "Answer": "stepdaughter" + }, + { + "Category": "AMERICAN NICKNAMES", + "Question": "Born in 1905, he was the \"Billionaire Recluse\"", + "Answer": "Howard Hughes" + }, + { + "Category": "\"S\"-OTERICA", + "Question": "It's a low-level football \"catch\" made near the ground by a running player", + "Answer": "shoestring catch" + }, + { + "Category": "VIETNAM", + "Question": "A fertile marshland, Vietnam's southernmost region is the broad delta of this river", + "Answer": "Mekong" + }, + { + "Category": "TOUR OF JUDY", + "Question": "Twice nominated for Oscars, this actress once studied at an Australian convent & sang in a rock band", + "Answer": "Judy Davis" + }, + { + "Category": "PLAYWRIGHTS", + "Question": "These British twin brother playwrights wrote mystery novels under the rather obvious alias Peter Anthony", + "Answer": "Peter & Anthony Shaffer" + }, + { + "Category": "AMERICAN NICKNAMES", + "Question": "Sam Rayburn was \"Mr. Sam\", not \"Mr. Democrat\"; this politician was \"Mr. Republican\", not \"Mr. Robert\"", + "Answer": "Robert Taft" + }, + { + "Category": "\"S\"-OTERICA", + "Question": "(I'm NFL running back Shaun Alexander) I play in this city that's the farthest distance away from any other NFL city", + "Answer": "Seattle" + }, + { + "Category": "VIETNAM", + "Question": "The large \"S\" shape that is Vietnam juts out into this sea with a directional name", + "Answer": "South China Sea" + }, + { + "Category": "TOUR OF JUDY", + "Question": "She played an airheaded blonde to whom William Holden had to teach manners in \"Born Yesterday\"", + "Answer": "Judy Holliday" + }, + { + "Category": "PLAYWRIGHTS", + "Question": "Born in 1799, this poet, novelist & playwright is to Russian literature what Shakespeare is to English literature", + "Answer": "Alexander Pushkin" + }, + { + "Category": "AMERICAN NICKNAMES", + "Question": "Gloria Vanderbilt or Doris Duke; it's also the translation of the Victoria Ruffo telenovela title \"Pobre Nina Rica\"", + "Answer": "Poor Little Rich Girl" + }, + { + "Category": "\"S\"-OTERICA", + "Question": "Peter Falk narrated this 1978 documentary in which hardened convicts frightened delinquent kids", + "Answer": "Scared Straight" + }, + { + "Category": "VIETNAM", + "Question": "Vietnam's narrowest point, about 30 miles, is just north of this port city where U.S. troops landed in 1965", + "Answer": "Da Nang" + }, + { + "Category": "TOUR OF JUDY", + "Question": "This CNN news anchor once worked as a correspondent for \"The MacNeil/Lehrer Newshour\"", + "Answer": "Judy Woodruff" + }, + { + "Category": "CANDY", + "Question": "Bill Harmsen, who raised horses in Colo., happily founded this candy co. in 1949 to make money during the winter", + "Answer": "Jolly Rancher" + }, + { + "Category": "HISTORIC NICKNAMES", + "Question": "Because of his Hanoverian heritage, American colonists called this monarch \"German Georgie\" or \"Geordie\"", + "Answer": "George III" + }, + { + "Category": "BIG, REALLY BIG!", + "Question": "Built on 200 acres, this Washington, D.C. train station was once the world's largest", + "Answer": "Union Station" + }, + { + "Category": "POLITICAL MOVIES", + "Question": "2 reporters unearth a political scandal that goes all the way to the top in this 1976 film based on a book", + "Answer": "All the President's Men" + }, + { + "Category": "THE 1990s", + "Question": "On Jan. 31, 1999 this team repeated as Super Bowl champs with John Elway throwing for 336 yards", + "Answer": "the Denver Broncos" + }, + { + "Category": "U.S. STATES", + "Question": "Do the wild fais-do-do in this state while motoring on Interstate 10 to Baton Rouge or Ponchatoula", + "Answer": "Louisiana" + }, + { + "Category": "HISTORIC NICKNAMES", + "Question": "Among the more colorful nicknames of this agricultural chemist were \"Peanut Man\" & \"Sweet-Potato Man\"", + "Answer": "George Washington Carver" + }, + { + "Category": "BIG, REALLY BIG!", + "Question": "The 120-foot big bat being transported here is now at the Kentucky museum named for this 2-word brand", + "Answer": "Louisville Slugger" + }, + { + "Category": "POLITICAL MOVIES", + "Question": "Jimmy Stewart played Jefferson Smith, the naive & idealistic appointee to the U.S. Senate in this Capra classic", + "Answer": "Mr. Smith Goes to Washington" + }, + { + "Category": "THE 1990s", + "Question": "On January 4, 1995 he was sworn in as the first Republican speaker of the house in more than 40 years", + "Answer": "Newt Gingrich" + }, + { + "Category": "U.S. STATES", + "Question": "It's the only U.S. state named for a French king", + "Answer": "Louisiana" + }, + { + "Category": "HISTORIC NICKNAMES", + "Question": "This animal phrase meaning \"courageous\" was Richard I of England's nickname", + "Answer": "the Lionhearted" + }, + { + "Category": "BIG, REALLY BIG!", + "Question": "In 1956 a 12,000-square-mile one of these was seen floating off Antarctica; you might call it titanic", + "Answer": "an iceberg" + }, + { + "Category": "POLITICAL MOVIES", + "Question": "This political satire starred John Travolta as a Southern governor running for president", + "Answer": "Primary Colors" + }, + { + "Category": "THE 1990s", + "Question": "On Nov. 5, 1996, this GOP candidate joked, \"Tomorrow will be the first time in my life I don't have anything to do\"", + "Answer": "Bob Dole" + }, + { + "Category": "HISTORIC NICKNAMES", + "Question": "He was the \"Father of Texas\", but the Indians called him \"Big Drunk\"", + "Answer": "Sam Houston" + }, + { + "Category": "BIG, REALLY BIG!", + "Question": "(Jimmy of the Clue Crew) In 1996 a 505 X 255-foot flag decorated this structure seen here in the West", + "Answer": "the Hoover Dam" + }, + { + "Category": "POLITICAL MOVIES", + "Question": "Frank Langella is the power hungry chief of staff in this film in which Kevin Kline plays a presidential impersonator", + "Answer": "Dave" + }, + { + "Category": "THE 1990s", + "Question": "In April 1992 riots broke out in L.A. after a jury failed to convict the policemen involved in the beating of this man", + "Answer": "Rodney King" + }, + { + "Category": "HISTORIC NICKNAMES", + "Question": "This 19th century American politician & orator was nicknamed \"The Little Giant\"", + "Answer": "Stephen Douglas" + }, + { + "Category": "BIG, REALLY BIG!", + "Question": "Lady Hamilton could tell you the name of this 185-foot column that went up in the early 1840s", + "Answer": "Nelson's Column" + }, + { + "Category": "POLITICAL MOVIES", + "Question": "Michael Douglas played Andrew Shepherd, the title character of this film, & even he had trouble dating", + "Answer": "The American President" + }, + { + "Category": "THE 1990s", + "Question": "Queen Elizabeth II & Francois Mitterrand appeared together at the opening of this on May 6, 1994", + "Answer": "the opening of the \"Chunnel\"" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "Scotch, & make it this (6)", + "Answer": "double" + }, + { + "Category": "CAPITOL THINKERS", + "Question": "This man from Mass. is the ranking Democrat of the Senate's Health, Education, Labor & Pensions Committee", + "Answer": "Edward Kennedy" + }, + { + "Category": "MEET THE PARENTS", + "Question": "CBS, Blockbuster, Simon & Schuster", + "Answer": "Viacom" + }, + { + "Category": "YOU SHOULD BE IN A BALLET!", + "Question": "This fluffy skirt that you may have to wear was not named for archbishop Desmond", + "Answer": "tutu" + }, + { + "Category": "GROSS NATIONAL PRODUCTS", + "Question": "In this largest country, comrades left & right enjoy coulibiac, a pie made with the spinal marrow of the sturgeon", + "Answer": "Russia" + }, + { + "Category": "POTPOURRI", + "Question": "Some think this Irving Berlin song should replace \"The Star-Spangled Banner\" as the national anthem -- it's easier to sing", + "Answer": "\"God Bless America\"" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "He's the shadowy Watergate source (4,6)", + "Answer": "\"Deep Throat\"" + }, + { + "Category": "CAPITOL THINKERS", + "Question": "This self-made man has the distinction of being the longest serving senator ever from West Virginia", + "Answer": "Robert Byrd" + }, + { + "Category": "MEET THE PARENTS", + "Question": "Aiwa, Epic Records, Columbia Tristar", + "Answer": "Sony" + }, + { + "Category": "YOU SHOULD BE IN A BALLET!", + "Question": "Your allergy to feathers may prevent you from playing Odette, the queen of the swans in this ballet", + "Answer": "Swan Lake" + }, + { + "Category": "GROSS NATIONAL PRODUCTS", + "Question": "The Masai people of this African country mix cow blood with milk for a refreshing drink", + "Answer": "Kenya" + }, + { + "Category": "POTPOURRI", + "Question": "Politicians often complain about having to make appearances on this \"unappetizing poultry\" circuit", + "Answer": "the \"rubber chicken\" circuit" + }, + { + "Category": "CAPITOL THINKERS", + "Question": "This Ariz. senator said of Bush's energy plan, \"Just one pork barrel project larded onto another\"", + "Answer": "John McCain" + }, + { + "Category": "MEET THE PARENTS", + "Question": "D.C. Comics, MapQuest.com, CNN", + "Answer": "Time Warner" + }, + { + "Category": "YOU SHOULD BE IN A BALLET!", + "Question": "To star in this 1890 fairy tale ballet, you shouldn't have spindly legs but you will need a spindle", + "Answer": "Sleeping Beauty" + }, + { + "Category": "GROSS NATIONAL PRODUCTS", + "Question": "Sanma aisu is fish-flavored ice cream & taco aisu is octopus-flavored ice cream made in this country", + "Answer": "Japan" + }, + { + "Category": "POTPOURRI", + "Question": "There are Blue & White branches of this African river", + "Answer": "the Nile" + }, + { + "Category": "CAPITOL THINKERS", + "Question": "This Tennessee senator is a practicing physician", + "Answer": "Bill Frist" + }, + { + "Category": "MEET THE PARENTS", + "Question": "First Colony Life Insurance, Telemundo, NBC", + "Answer": "General Electric" + }, + { + "Category": "YOU SHOULD BE IN A BALLET!", + "Question": "Your striking resemblance to Kirk Douglas has convinced us to star you in the ballet about this gladiator", + "Answer": "Spartacus" + }, + { + "Category": "GROSS NATIONAL PRODUCTS", + "Question": "When on this north Atlantic island be sure to try hakarl, a traditional dish of rotten shark", + "Answer": "Iceland" + }, + { + "Category": "POTPOURRI", + "Question": "VP Garret Hobart cast the deciding vote against independence for these formerly Spanish Pacific islands", + "Answer": "the Philippines" + }, + { + "Category": "CAPITOL THINKERS", + "Question": "This Vermont senator wrote, \"You get 15 Democrats together in a room, and you get 20 opinions\"", + "Answer": "Patrick Leahy" + }, + { + "Category": "MEET THE PARENTS", + "Question": "Hyperion Books, Mammoth Records, Miramax Films", + "Answer": "Disney" + }, + { + "Category": "YOU SHOULD BE IN A BALLET!", + "Question": "Your \"Romeo and Juliet\" will make everyone forget the 1965 triumph of Rudolf Nureyev & this partner", + "Answer": "Margot Fonteyn" + }, + { + "Category": "GROSS NATIONAL PRODUCTS", + "Question": "Consisting of a sheep's minced heart, lung & liver, haggis is a specialty of this U.K. country", + "Answer": "Scotland" + }, + { + "Category": "POTPOURRI", + "Question": "The website for this Bureau of the Treasury department is www.moneyfactory.com", + "Answer": "the Bureau of Printing and Engraving" + }, + { + "Category": "THE PRESIDENCY", + "Question": "If a president is impeached, this official presides over the trial in the Senate", + "Answer": "the Chief Justice of the United States" + }, + { + "Category": "AFRICAN GEOGRAPHY", + "Question": "The Qattara Depression, one of Africa's lowest points, lies 300 miles southwest of this country's pyramids", + "Answer": "Egypt" + }, + { + "Category": "BON APPE-\"T\"", + "Question": "A folded tortilla filled with various ingredients", + "Answer": "Taco" + }, + { + "Category": "MONEY SLANG", + "Question": "Cheap way off a rodeo bronco", + "Answer": "Buck" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "The Mackinac Bridge joins the upper & lower peninsulas of this U.S. state", + "Answer": "Michigan" + }, + { + "Category": "WHY?", + "Question": "These events occur because gas-filled magma is forced to the surface by pressure from solid rock", + "Answer": "Volcanic eruptions" + }, + { + "Category": "THE BUTLER DID IT", + "Question": "Ted Cassidy played Bigfoot on \"The Six Million Dollar Man\" & filled this servant's shoes on \"The Addams Family\"", + "Answer": "Lurch" + }, + { + "Category": "AFRICAN GEOGRAPHY", + "Question": "Arabs call this Libyan capital Tarabulus", + "Answer": "Tripoli" + }, + { + "Category": "BON APPE-\"T\"", + "Question": "This \"steak\" is a hot dog", + "Answer": "Tube steak" + }, + { + "Category": "MONEY SLANG", + "Question": "No \"Wonder\" you're on a \"roll\" -- you're not a \"loaf\"er & you're earning a lot of this", + "Answer": "Bread/dough" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "This state was named for a man who was a European king from 1643 to 1715", + "Answer": "Louisiana" + }, + { + "Category": "WHY?", + "Question": "They're \"unlucky\" because in the Middle Ages they were thought to be the mascots of witches", + "Answer": "Black cats" + }, + { + "Category": "THE BUTLER DID IT", + "Question": "He must have a great benefit plan; Alfred began his service to this crime fighter way back in 1943", + "Answer": "Batman" + }, + { + "Category": "AFRICAN GEOGRAPHY", + "Question": "Most of Africa's major rivers, including the Congo & the Niger, flow into this ocean", + "Answer": "Atlantic" + }, + { + "Category": "BON APPE-\"T\"", + "Question": "This root vegetable often has white skin & a purple-tinged top", + "Answer": "Turnip" + }, + { + "Category": "MONEY SLANG", + "Question": "If you have the itch to start a business \"from\" it, you'll certainly need some of it", + "Answer": "Scratch" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "There are more farms in this large southwestern state than in any other", + "Answer": "Texas" + }, + { + "Category": "WHY?", + "Question": "According to Genesis 3:14, because it tricked Eve", + "Answer": "Why does the snake crawl on the ground?" + }, + { + "Category": "THE BUTLER DID IT", + "Question": "Robert Guillaume cleaned up on \"Soap\" before moving to the governor's mansion on this series", + "Answer": "Benson" + }, + { + "Category": "AFRICAN GEOGRAPHY", + "Question": "In addition to its bountiful wildlife, this desert is the site of the Orapa diamond mine, one of the world's largest", + "Answer": "Kalahari" + }, + { + "Category": "BON APPE-\"T\"", + "Question": "It's a cross between a pomelo & a tangerine", + "Answer": "Tangelo" + }, + { + "Category": "MONEY SLANG", + "Question": "Bank notes that sing before fa-so-la", + "Answer": "Do-re-mi" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "This town bearing the name of an old TV game show is the seat of Sierra County, New Mexico", + "Answer": "Truth or Consequences" + }, + { + "Category": "WHY?", + "Question": "To punish Vronsky for turning cold to her, & to escape from everything", + "Answer": "Why does Anna Karenina kill herself?" + }, + { + "Category": "THE BUTLER DID IT", + "Question": "Daniel Davis played Niles the butler on this \"Fine\" TV comedy that featured the Sheffield family", + "Answer": "The Nanny" + }, + { + "Category": "AFRICAN GEOGRAPHY", + "Question": "Jebel Musa, a promontory in this mountain range, is one of the Pillars of Hercules", + "Answer": "Atlas Mountains" + }, + { + "Category": "BON APPE-\"T\"", + "Question": "A yellow cheddar from Oregon", + "Answer": "Tillamook" + }, + { + "Category": "MONEY SLANG", + "Question": "2-word phrase for Henny Penny's lunch", + "Answer": "Chicken feed" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "On June 17, 1969 this controversial erotic revue opened off-Broadway; oh my!", + "Answer": "Oh! Calcutta!" + }, + { + "Category": "WHY?", + "Question": "Because bacteria from carbon dioxide bubbles around which the curd hardens", + "Answer": "Why does Swiss cheese have holes?" + }, + { + "Category": "THE BUTLER DID IT", + "Question": "Giles was the first name of this Sebastian Cabot character on \"Family Affair\"", + "Answer": "Mr. French" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "In the East Indies certain species of this reptile are called flying dragons because they can glide from tree to tree", + "Answer": "Lizards" + }, + { + "Category": "THE MELBOURNE OLYMPICS, 1956", + "Question": "As an 8-year-old in 1956, she sang with a group welcoming Queen Elizabeth II; later she sang to open the 2000 games", + "Answer": "Olivia Newton-John" + }, + { + "Category": "WRITERS CUBED", + "Question": "In 1845 he published \"The Raven and Other Poems\"; the other poems include \"The Conqueror Worm\"", + "Answer": "Edgar Allan Poe" + }, + { + "Category": "BRITISH ROYAL HOUSES", + "Question": "Henry VIII", + "Answer": "Tudor" + }, + { + "Category": "AND I QUOTE", + "Question": "Type of quotations in the title of \"Bartlett's\"", + "Answer": "Familiar" + }, + { + "Category": "THE \"BUTLER\" DID IT", + "Question": "Film character who said, \"You should be kissed, and often, and by someone who knows how\"", + "Answer": "Rhett Butler" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Newton, Cassegrain, Schmidt & Maksutov all have types of this instrument named for them", + "Answer": "Telescope" + }, + { + "Category": "THE MELBOURNE OLYMPICS, 1956", + "Question": "Teams were pulling out left & right, some in protest of the Soviet invasion of this country", + "Answer": "Hungary" + }, + { + "Category": "WRITERS CUBED", + "Question": "In 1977 a reconstruction of her \"Little House\" was put on the original site 13 miles southwest of Independence", + "Answer": "Laura Ingalls Wilder" + }, + { + "Category": "BRITISH ROYAL HOUSES", + "Question": "George VI", + "Answer": "Windsor" + }, + { + "Category": "AND I QUOTE", + "Question": "A quote can be taken \"out of\" this, from the Latin for \"to weave together\"", + "Answer": "Context" + }, + { + "Category": "THE \"BUTLER\" DID IT", + "Question": "A former Dodger outfielder & TV's \"Grace Under Fire\" both go by this name", + "Answer": "Brett Butler" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "The flexible neck of this bird of prey allows it to rotate its head an amazing 270 degrees", + "Answer": "Owl" + }, + { + "Category": "THE MELBOURNE OLYMPICS, 1956", + "Question": "Like Korea in 2000, this country entered the stadium in 1956 as a \"United\" team", + "Answer": "Germany" + }, + { + "Category": "WRITERS CUBED", + "Question": "19th century minister of the Second Church of Boston, known for essays like \"Self-Reliance\"", + "Answer": "Ralph Waldo Emerson" + }, + { + "Category": "BRITISH ROYAL HOUSES", + "Question": "Richard I", + "Answer": "Plantagenet" + }, + { + "Category": "AND I QUOTE", + "Question": "Kim Walker's character in \"Say Anything\" has this annoying habit when quoting", + "Answer": "Making quotations with your fingers" + }, + { + "Category": "THE \"BUTLER\" DID IT", + "Question": "This Irish poet who penned \"The Winding Stair\" shares his middle name with his brother Jack & father John", + "Answer": "William Butler Yeats" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Change 1 letter in \"protest\" to get this word for a protozoan & others in its kingdom", + "Answer": "Protist" + }, + { + "Category": "WRITERS CUBED", + "Question": "Her 2000 novel \"Blonde\" is, of course, about Marilyn Monroe", + "Answer": "Joyce Carol Oates" + }, + { + "Category": "BRITISH ROYAL HOUSES", + "Question": "James I", + "Answer": "Stuart" + }, + { + "Category": "AND I QUOTE", + "Question": "3-word phrase for a quote meant for attribution, or a quote like \"Gretzky's 92 goals are unbeatable!\"", + "Answer": "On the record" + }, + { + "Category": "THE \"BUTLER\" DID IT", + "Question": "In his 1872 novel \"Erewhon\", poverty is considered a crime", + "Answer": "Samuel Butler" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Sir Humphry Davy named this yellowish-green gas from a Greek word meaning \"greenish-yellow\"", + "Answer": "Chlorine" + }, + { + "Category": "WRITERS CUBED", + "Question": "\"Before I Say Good-Bye\" is her 22nd romantic thriller, so it's no mystery -- she's good", + "Answer": "Mary Higgins Clark" + }, + { + "Category": "BRITISH ROYAL HOUSES", + "Question": "George III", + "Answer": "Hanover" + }, + { + "Category": "AND I QUOTE", + "Question": "Publishing term for the type of quote seen here: [Trebek's...made it into record books as host of television's #1-rated quiz show.]", + "Answer": "Pull quote" + }, + { + "Category": "THE \"BUTLER\" DID IT", + "Question": "The mission statement of this school says it's located \"In...Indianapolis, one of America's most livable cities\"", + "Answer": "Butler University" + }, + { + "Category": "THEATRE", + "Question": "The 1996 musical \"Play On!\" gets its title from the first line of this Shakespeare play, on which it is based", + "Answer": "\\\"Twelfth Night\\\"" + }, + { + "Category": "20th CENTURY QUOTES", + "Question": "A minister, 1968: \"I've seen the promised land...and I'm happy tonight...I'm not fearing any man\"", + "Answer": "Dr. Martin Luther King, Jr." + }, + { + "Category": "ALL ABOARD THE SOUL TRAIN", + "Question": "\"Soul Train\" premiered in this decade", + "Answer": "1970s" + }, + { + "Category": "WAR STORIES", + "Question": "\"Marching On\", \"By Antietam Creek\"", + "Answer": "Civil War" + }, + { + "Category": "EUROPE", + "Question": "Descriptive term for the flag of Italy & the flag of France", + "Answer": "Tricolor" + }, + { + "Category": "WEEDS", + "Question": "The most common cause of hay fever in the U.S. is this substance from ragweed", + "Answer": "Pollen" + }, + { + "Category": "SEEING \"RED\"", + "Question": "In \"Peanuts\", Snoopy often fancied himself a flying ace out to get this pilot", + "Answer": "The Red Baron" + }, + { + "Category": "20th CENTURY QUOTES", + "Question": "A Communist, 1938: \"Political power grows out of the barrel of a gun\"", + "Answer": "Mao Tse-tung" + }, + { + "Category": "ALL ABOARD THE SOUL TRAIN", + "Question": "Oh yessssssss...he created the show & was the original producer & host", + "Answer": "Don Cornelius" + }, + { + "Category": "WAR STORIES", + "Question": "\"Body Count\", \"Coming Home\"", + "Answer": "Vietnam War" + }, + { + "Category": "EUROPE", + "Question": "From 1963 to 1978 he was Archbishop of Krakow", + "Answer": "Karol Wojtyla" + }, + { + "Category": "WEEDS", + "Question": "This common weed seen here has a beverage in its name", + "Answer": "Milkweed" + }, + { + "Category": "SEEING \"RED\"", + "Question": "Excessive bureaucratic procedure resulting in inaction or delay", + "Answer": "Red tape" + }, + { + "Category": "20th CENTURY QUOTES", + "Question": "A physicist, 1955: \"If only I had known, I would have become a watchmaker\"", + "Answer": "Albert Einstein" + }, + { + "Category": "ALL ABOARD THE SOUL TRAIN", + "Question": "White crossover artists featured on \"Soul Train\" have included David Bowie & this \"Island Girl\" singer", + "Answer": "Elton John" + }, + { + "Category": "WAR STORIES", + "Question": "\"The Good Soldier Schweik\", \"Paths of Glory\"", + "Answer": "World War I" + }, + { + "Category": "EUROPE", + "Question": "Geographic region within the Arctic Circle named for the people who call themselves the Sami", + "Answer": "Lapland" + }, + { + "Category": "WEEDS", + "Question": "This plant whose alkaloids ended Socrates' life now grows on American roadsides", + "Answer": "Hemlock" + }, + { + "Category": "SEEING \"RED\"", + "Question": "Stephen Crane wrote, \"He wished that he, too, had a wound,\" this", + "Answer": "A red badge of courage" + }, + { + "Category": "20th CENTURY QUOTES", + "Question": "A governor, 1963: \"Segregation now! Segregation tomorrow! Segregation forever!\"", + "Answer": "George Wallace" + }, + { + "Category": "ALL ABOARD THE SOUL TRAIN", + "Question": "This hair care product was among the first major backers of the show", + "Answer": "Afro Sheen" + }, + { + "Category": "WAR STORIES", + "Question": "\"A Walk in the Sun\", \"They Were Expendable\"", + "Answer": "World War II" + }, + { + "Category": "EUROPE", + "Question": "It's the smallest in area of the Benelux countries", + "Answer": "Luxembourg" + }, + { + "Category": "WEEDS", + "Question": "This fabric follows Queen Anne's in the name of the weed seen here", + "Answer": "Lace" + }, + { + "Category": "SEEING \"RED\"", + "Question": "In song, just \"remember\" this place \"and the cowboy that loves you so true\"", + "Answer": "Red River Valley" + }, + { + "Category": "20th CENTURY QUOTES", + "Question": "A professor, 1967: \"Turn on, tune in, drop out\"", + "Answer": "Timothy Leary" + }, + { + "Category": "ALL ABOARD THE SOUL TRAIN", + "Question": "To gain better production values, \"Soul Train\" was moved from this city to Los Angeles", + "Answer": "Chicago" + }, + { + "Category": "WAR STORIES", + "Question": "\"Arundel\", \"Johnny Tremain\"", + "Answer": "The Revolutionary War" + }, + { + "Category": "EUROPE", + "Question": "The fertile plain east of the Danube, making up half this country's area, is called the Great Alfold", + "Answer": "Hungary" + }, + { + "Category": "WEEDS", + "Question": "In the names of weeds, this old word for a plant follows soap- & St. John's", + "Answer": "Wort" + }, + { + "Category": "SEEING \"RED\"", + "Question": "The title of a 1928 song Sophie Tucker introduced, it was also her nickname", + "Answer": "\"The Last of the Red Hot Mamas\"" + }, + { + "Category": "INITIAL T.V.", + "Question": "This show which had a 9-year-run on ABC was produced with help from J. Edgar Hoover", + "Answer": "The F.B.I." + }, + { + "Category": "SAINTS BE PRAISED", + "Question": "The emblem of St. Lawrence, it's also a nickname for a football field", + "Answer": "Gridiron" + }, + { + "Category": "MR. OR MS. WILLIAMS", + "Question": "Elected to the Hall of Fame in 1966, his lifetime batting average was .344", + "Answer": "Ted Williams" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "This state's largest lake may be 20 times as salty as any ocean", + "Answer": "Utah" + }, + { + "Category": "SOMETHIN' TO \"C\"", + "Question": "Oscar & Felix were an \"odd\" one", + "Answer": "Couple" + }, + { + "Category": "INITIAL T.V.", + "Question": "This '60s police drama with Jack Warden was missing the \"blue\" of the series that began in 1993", + "Answer": "N.Y.P.D." + }, + { + "Category": "SAINTS BE PRAISED", + "Question": "The first American citizen canonized was an immigrant from this country", + "Answer": "Italy" + }, + { + "Category": "MR. OR MS. WILLIAMS", + "Question": "This crooner's hits include 1971's \"Where Do I Begin\" & 1959's \"Lonely Street\"", + "Answer": "Andy Williams" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "Francis Scott Key wrote \"The Star-Spangled Banner\" while in this state during the War of 1812", + "Answer": "Maryland" + }, + { + "Category": "SOMETHIN' TO \"C\"", + "Question": "Ichabod's patronymic", + "Answer": "Crane" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "Max Planck gave this name to the smallest amount of energy that can be emitted as electromagnetic radiation", + "Answer": "Quantum" + }, + { + "Category": "INITIAL T.V.", + "Question": "[Hi, I'm Pat O'Brien] David E. Kelley won 2 Emmys for this show in 1991, one as executive producer, one as writer", + "Answer": "L.A. Law" + }, + { + "Category": "SAINTS BE PRAISED", + "Question": "Saint Brigid was buried at Kildare, but was later moved to be buried with this saint", + "Answer": "Saint Patrick" + }, + { + "Category": "MR. OR MS. WILLIAMS", + "Question": "\"The Hillbilly Shakespeare\" is one nickname of this legendary singer", + "Answer": "Hank Williams, Sr." + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "Ice cream cones were reportedly first served at the 1904 World's Fair in this state", + "Answer": "Missouri" + }, + { + "Category": "SOMETHIN' TO \"C\"", + "Question": "The means of production are privately owned in this economic system", + "Answer": "Capitalism" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "To scientists, it's force times distance; to Twain, it's \"whatever a body is obliged to do\"", + "Answer": "Work" + }, + { + "Category": "INITIAL T.V.", + "Question": "This '70s series about a harsh Navy drill instructor with a soft heart starred Don Rickles", + "Answer": "C.P.O. Sharkey" + }, + { + "Category": "SAINTS BE PRAISED", + "Question": "Philip of Moscow foresaw that his post as primate of the Russian church might lead to martyrdom, as this man was czar", + "Answer": "Ivan the Terrible" + }, + { + "Category": "MR. OR MS. WILLIAMS", + "Question": "The aquatic Mrs. Fernando Lamas", + "Answer": "Esther Williams" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "In 1886 a pharmacist in this southern state became the first man to enjoy a Coke and a smile", + "Answer": "Georgia" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "Stoichiometry is defined as the study of the quantities involved in these chemical events", + "Answer": "Chemical reactions" + }, + { + "Category": "INITIAL T.V.", + "Question": "Organization that employed Alexander Waverly, Mark Slate & Illya Kuryakin", + "Answer": "U.N.C.L.E." + }, + { + "Category": "SAINTS BE PRAISED", + "Question": "In September 1999 an abridged version of his \"City of God\" ranked 9,821st on Amazon.com's sales list", + "Answer": "Saint Augustine" + }, + { + "Category": "MR. OR MS. WILLIAMS", + "Question": "This devoted mom has been called the most famous Miss America of all time", + "Answer": "Vanessa Williams" + }, + { + "Category": "AIN'T THAT AMERICA", + "Question": "From 1784 to 1788 the eastern part of this state was a separate state called Franklin", + "Answer": "Tennessee" + }, + { + "Category": "SOMETHIN' TO \"C\"", + "Question": "In 41 A.D. Cassius Chaerea & company assassinated this Roman emperor", + "Answer": "Caligula" + }, + { + "Category": "FILM CLASSICS", + "Question": "This 1951 classic stars the AFI's top picks for the greatest male & female film legends", + "Answer": "The African Queen" + }, + { + "Category": "NUMBERS", + "Question": "Fittingly, the book of Numbers begins with God telling this man to count the number of Israelites", + "Answer": "Moses" + }, + { + "Category": "'65", + "Question": "These 2 countries nicknamed the Bear & the Dragon conducted a \"verbal war\"", + "Answer": "Soviet Union & China" + }, + { + "Category": "FORE!", + "Question": "In 1994 at age 18, he became the youngest golfer to win the U.S. Amateur Golf Tournament", + "Answer": "Tiger Woods" + }, + { + "Category": "THREE", + "Question": "Mother Goose rhyming line that follows \"Rub-a-dub-dub\"", + "Answer": "Three men in a tub" + }, + { + "Category": "TWO", + "Question": "In suds: Eberhard Anheuser &...", + "Answer": "Adolphus Busch" + }, + { + "Category": "JUAN", + "Question": "Days out of prison in 1945, he married Maria Eva Duarte; we now know her as Evita", + "Answer": "Juan Peron" + }, + { + "Category": "NUMBERS", + "Question": "Numbers appears at this number position in the order of the books of the Bible", + "Answer": "Fourth" + }, + { + "Category": "'65", + "Question": "Strike up the band; this Christian organization turned 100 in June", + "Answer": "The Salvation Army" + }, + { + "Category": "FORE!", + "Question": "Except during WWII, this golf tournament has been played at the Augusta National Golf Club every year since 1934", + "Answer": "The Masters" + }, + { + "Category": "THREE", + "Question": "It beats 2 pair, but not a straight", + "Answer": "Three of a kind" + }, + { + "Category": "TWO", + "Question": "In pharmaceuticals: William Bristol &...", + "Answer": "John Myers" + }, + { + "Category": "JUAN", + "Question": "While trying to colonize what's now this state, Juan Ponce de Leon received a mortal wound from the natives", + "Answer": "Florida" + }, + { + "Category": "NUMBERS", + "Question": "Of the 12 spies sent, only Caleb & this future leader believed the Israelites could take Canaan", + "Answer": "Joshua" + }, + { + "Category": "'65", + "Question": "On January 20, 1965 he was inaugurated as U.S. vice president", + "Answer": "Hubert H. Humphrey" + }, + { + "Category": "FORE!", + "Question": "This stretch of closely mowed grass from the tee to the green may be straight or at an angle called a dogleg", + "Answer": "Fairway" + }, + { + "Category": "THREE", + "Question": "Stalin, FDR & Churchill were known by this collective nickname when they met in Teheran in 1943", + "Answer": "\"The Big Three\"" + }, + { + "Category": "TWO", + "Question": "In advertising: Jay Chiat &...", + "Answer": "Guy Day" + }, + { + "Category": "JUAN", + "Question": "Juan Belmonte is considered the founder of the modern version of this sport, ole!", + "Answer": "Bullfighting" + }, + { + "Category": "NUMBERS", + "Question": "In chapter 8, this tribe of Israelites is appointed to work in the tabernacle", + "Answer": "Levites" + }, + { + "Category": "'65", + "Question": "Awarded the Nobel Peace Prize on Oct. 25, 1965, maybe it got its prize money in pennies on the 31st", + "Answer": "UNICEF" + }, + { + "Category": "FORE!", + "Question": "This hazard is simply a depression in the ground; if it contains sand it's called a sand trap", + "Answer": "Bunker" + }, + { + "Category": "THREE", + "Question": "In 1979 this nuclear power plant near Harrisburg experienced a near meltdown", + "Answer": "Three Mile Island" + }, + { + "Category": "TWO", + "Question": "In engines: Stephen Briggs &...", + "Answer": "Harold Stratton" + }, + { + "Category": "JUAN", + "Question": "1998's MVP in the American League was outfielder Juan Gonzalez, then with this team", + "Answer": "Texas Rangers" + }, + { + "Category": "NUMBERS", + "Question": "In chapter 20, Eleazar succeeds this man, his father, as high priest", + "Answer": "Aaron" + }, + { + "Category": "'65", + "Question": "This company's new Toronado eliminated the hump on the floor with a new drive system", + "Answer": "Oldsmobile" + }, + { + "Category": "FORE!", + "Question": "This \"Royal & Ancient Golf Club\" of Scotland set the standard for a round of golf at 18 holes", + "Answer": "St. Andrews" + }, + { + "Category": "THREE", + "Question": "Brecht & Weill's \"Die Dreigroschenoper\" is known as this in English", + "Answer": "\"The Threepenny Opera\"" + }, + { + "Category": "TWO", + "Question": "In fashion: Domenico Dolce &...", + "Answer": "Stefano Gabbana" + }, + { + "Category": "JUAN", + "Question": "In 1995 he was named ASCAP's Latin Songwriter of the Year & in 1996, sang a duet with Paul Anka", + "Answer": "Juan Gabriel" + }, + { + "Category": "KOREA", + "Question": "In 1976 this company produced the Pony, the first Korean car", + "Answer": "Hyundai" + }, + { + "Category": "\"NEVER\" AT THE MOVIES", + "Question": "Advice that's the title of a 1941 W.C. Fields film", + "Answer": "Never Give a Sucker an Even Break" + }, + { + "Category": "POLAR EXPLORATION", + "Question": "Robert Peary was surprised to hear these natives accompanying him complain of cold noses", + "Answer": "Eskimos" + }, + { + "Category": "AIRPORT CODES", + "Question": "ATL", + "Answer": "Atlanta" + }, + { + "Category": "THAT'S NO LADY...", + "Question": "In the '70s he played America's favorite bigot, Archie Bunker", + "Answer": "Carroll O'Connor" + }, + { + "Category": "DOUBLE A", + "Question": "Quirks of this Eurocar include the ignition lock in the center console", + "Answer": "Saab" + }, + { + "Category": "KOREA", + "Question": "It's enlightening to know the eighth day of the fourth lunar month is celebrated as his birthday", + "Answer": "Buddha" + }, + { + "Category": "\"NEVER\" AT THE MOVIES", + "Question": "(Hi, I'm Garry Marshall) I sent copy editor Drew Barrymore back to high school for an undercover assignment in this 1999 comedy", + "Answer": "Never Been Kissed" + }, + { + "Category": "POLAR EXPLORATION", + "Question": "Edward Bransfield, a possible discoverer of Antarctica, had to battle these birds to get ashore", + "Answer": "Penguins" + }, + { + "Category": "AIRPORT CODES", + "Question": "BRU", + "Answer": "Brussels" + }, + { + "Category": "THAT'S NO LADY...", + "Question": "Before he was a Yippie leader & one of the \"Chicago Seven\", he was a pharmaceuticals salesman", + "Answer": "Abbie Hoffman" + }, + { + "Category": "DOUBLE A", + "Question": "It's how you properly address the Queen of England", + "Answer": "Maam" + }, + { + "Category": "KOREA", + "Question": "The name of this martial art resembling karate is Korean for \"art of kicking and punching\"", + "Answer": "Taekwondo" + }, + { + "Category": "\"NEVER\" AT THE MOVIES", + "Question": "This 1977 movie about a schizophrenic girl was adapted from Joanne Greenberg's book of the same name", + "Answer": "I Never Promised You a Rose Garden" + }, + { + "Category": "POLAR EXPLORATION", + "Question": "In 1969, on dogsled, a British team made the first surface crossing of this ocean", + "Answer": "Arctic Ocean" + }, + { + "Category": "AIRPORT CODES", + "Question": "In Scandinavia: CPH", + "Answer": "Copenhagen" + }, + { + "Category": "THAT'S NO LADY...", + "Question": "A legendary lineman for the Giants & the Rams, he also published a \"Needlepoint Book for Men\"", + "Answer": "RosieGrier" + }, + { + "Category": "DOUBLE A", + "Question": "Biblical man with a talking ass", + "Answer": "Balaam" + }, + { + "Category": "KOREA", + "Question": "Reportedly, the farther south you go, the hotter you'll find this common dish of pickled cabbage", + "Answer": "Kimchi" + }, + { + "Category": "\"NEVER\" AT THE MOVIES", + "Question": "Despite the promise of its title, this 1984 fantasy movie is 94 minutes long; the 1991 sequel is only 90 minutes", + "Answer": "The Neverending Story" + }, + { + "Category": "POLAR EXPLORATION", + "Question": "This South Pole conqueror died trying to rescue Umberto Nobile, who eventually lived to be 93", + "Answer": "Roald Amundsen" + }, + { + "Category": "AIRPORT CODES", + "Question": "On the continent: ORY", + "Answer": "Paris" + }, + { + "Category": "THAT'S NO LADY...", + "Question": "He was a comic foil as Mr. Mooney on \"The Lucy Show\" & Mr. Wilson on \"Dennis the Menace\"", + "Answer": "Gale Gordon" + }, + { + "Category": "DOUBLE A", + "Question": "Architect Eero", + "Answer": "Saarinen" + }, + { + "Category": "KOREA", + "Question": "South Korea's second-largest city, it gave its name to a Korean war \"perimeter\"", + "Answer": "Pusan" + }, + { + "Category": "\"NEVER\" AT THE MOVIES", + "Question": "The 2 James Bond films that have \"Never\" in the title", + "Answer": "Never Say Never Again & Tomorrow Never Dies" + }, + { + "Category": "POLAR EXPLORATION", + "Question": "This man who sailed with Scott later made a daring trek when his ship Endurance was trapped by ice", + "Answer": "Ernest Shackleton" + }, + { + "Category": "AIRPORT CODES", + "Question": "In the Midwest: MSP", + "Answer": "Minneapolis-St. Paul" + }, + { + "Category": "THAT'S NO LADY...", + "Question": "He played the title character in \"Sunday in the Park with George\" when it debuted on Broadway", + "Answer": "Mandy Patinkin" + }, + { + "Category": "DOUBLE A", + "Question": "This river \"trans\"its South Africa & flows into the Orange", + "Answer": "Vaal River" + }, + { + "Category": "NONFICTION AUTHORS", + "Question": "First published in 1946, a book written by this man became the bestselling book in the U.S. after the Bible", + "Answer": "Dr. Benjamin Spock" + }, + { + "Category": "THOSE DARN ETRUSCANS", + "Question": "The Tebenna, an Etruscan mantle, evolved into this garment perhaps worn most strikingly by John Belushi", + "Answer": "a toga" + }, + { + "Category": "PEOPLE", + "Question": "This wrestler nicknamed his daughter born in August 2001 Pebbles", + "Answer": "The Rock" + }, + { + "Category": "SO YOU WANT TO BE A 19th CENTURY HEROINE", + "Question": "If you have this adjective before your name, like Nell or Eva, don't bother planning for your old age", + "Answer": "Little" + }, + { + "Category": "CENTRAL PARK", + "Question": "What's now officially called the Central Park Wildlife Center is probably better-known by this name", + "Answer": "the zoo" + }, + { + "Category": "THIS CATEGORY STINKS!", + "Question": "Proverbially, this pungent bulb \"makes a man wink, drink & stink\"", + "Answer": "garlic" + }, + { + "Category": "ABBREVIATED STATES", + "Question": "This state that acts as a conjunction between Nevada & Washington has an abbreviation that is a conjunction", + "Answer": "Oregon" + }, + { + "Category": "THOSE DARN ETRUSCANS", + "Question": "Oscar Mayer could tell you that this is the city the Etruscans called Felsina", + "Answer": "Bologna" + }, + { + "Category": "PEOPLE", + "Question": "Fatally, American groupie Nancy Spungen was this British punk rocker's girlfriend", + "Answer": "Sid Vicious" + }, + { + "Category": "SO YOU WANT TO BE A 19th CENTURY HEROINE", + "Question": "Your job options include teacher & this related job of the heroines in \"Jane Eyre\" & \"Vanity Fair\"", + "Answer": "governess" + }, + { + "Category": "CENTRAL PARK", + "Question": "Central Park has a statue of King Wladyslaw II Jagiello of this country, who was also Grand Duke of Lithuania", + "Answer": "Poland" + }, + { + "Category": "THIS CATEGORY STINKS!", + "Question": "It's the Belgian province bordering the Netherlands that's famous for originating a smelly cheese", + "Answer": "Limburgh" + }, + { + "Category": "ABBREVIATED STATES", + "Question": "The abbreviation of this state is also an abbreviation for the largest city in California", + "Answer": "Louisiana" + }, + { + "Category": "THOSE DARN ETRUSCANS", + "Question": "Along with the Borgia apartments, the Etruscan Museum is one of the top attractions in this 109-acre country", + "Answer": "Vatican City" + }, + { + "Category": "PEOPLE", + "Question": "She owns the St. Louis Rams", + "Answer": "Georgia Frontiere" + }, + { + "Category": "SO YOU WANT TO BE A 19th CENTURY HEROINE", + "Question": "Even if you're 27 & still single, like Anne in this author's \"Persuasion\", your life may not be over", + "Answer": "Jane Austen" + }, + { + "Category": "THIS CATEGORY STINKS!", + "Question": "This cartoon character's big screen credits include \"For Scent-imental Reasons\" & \"Heaven Scent\"", + "Answer": "Pepé Le Pew" + }, + { + "Category": "ABBREVIATED STATES", + "Question": "Show me that the abbreviation for this state means the habits of a predictable criminal", + "Answer": "Missouri" + }, + { + "Category": "THOSE DARN ETRUSCANS", + "Question": "The wolf in the Capitoline Wolf statue may be Etruscan; these 2 babies she's suckling were added around 1509", + "Answer": "Romulus & Remus" + }, + { + "Category": "PEOPLE", + "Question": "This actor gave a speech for Harvard roommate Al Gore at the 2000 Democratic Convention", + "Answer": "Tommy Lee Jones" + }, + { + "Category": "SO YOU WANT TO BE A 19th CENTURY HEROINE", + "Question": "Like Gertrude in this author's \"The Europeans\", go ahead & marry a relative (it might get you out of your house, too)", + "Answer": "Henry James" + }, + { + "Category": "CENTRAL PARK", + "Question": "In the 1953 film \"The Band Wagon\" Fred Astaire & this leggy partner were \"Dancing In The Dark\" through Central Park", + "Answer": "Cyd Charisse" + }, + { + "Category": "THIS CATEGORY STINKS!", + "Question": "The strong odor of this semi-aquatic rodent gives it its name", + "Answer": "the muskrat" + }, + { + "Category": "ABBREVIATED STATES", + "Question": "When abbreviated before the number 47, this state becomes an assault weapon", + "Answer": "Alaska" + }, + { + "Category": "THOSE DARN ETRUSCANS", + "Question": "A 1927 visit to Etruscan sites inspired this author of \"The Plumed Serpent\" to write \"Etruscan Places\"", + "Answer": "D.H. Lawrence" + }, + { + "Category": "PEOPLE", + "Question": "M.C. Hammer earned his nickname from his resemblance to this \"Hammerin'\" home run king", + "Answer": "Hank Aaron" + }, + { + "Category": "SO YOU WANT TO BE A 19th CENTURY HEROINE", + "Question": "Unlike Dorothea in this George Eliot book, marry for love, not intellectual compatibility", + "Answer": "Middlemarch" + }, + { + "Category": "CENTRAL PARK", + "Question": "Cleopatra's Needle is a short walk from this Egyptian Temple in the Metropolitan Museum of Art", + "Answer": "the Temple of Dendur" + }, + { + "Category": "THIS CATEGORY STINKS!", + "Question": "The only film ever released in \"Odorama\", it shares its name with a synthetic fabric popular in the 1970s", + "Answer": "Polyester" + }, + { + "Category": "ABBREVIATED STATES", + "Question": "State whose abbreviation is also a cabinet department that was formed in 1989", + "Answer": "Virginia" + }, + { + "Category": "COLONIAL ARTS", + "Question": "This South Carolina city that gave us a popular dance in the 1930s was the site of the first opera in America in 1735", + "Answer": "Charleston" + }, + { + "Category": "INTERNATIONAL CUISINE", + "Question": "When making this classic Chinese soup, be sure to remove the twigs, feathers & insects first", + "Answer": "bird's nest soup" + }, + { + "Category": "WE ARE THE CHAMPIONS", + "Question": "On New Year's Day 2002, this school's Seminoles beat Virginia Tech 30-17 to win the Gator Bowl", + "Answer": "Florida State University" + }, + { + "Category": "RELIGION", + "Question": "The A.M.E. in A.M.E. Church stands for African Methodist this", + "Answer": "Episcopal" + }, + { + "Category": "PROBLEMS, PROBLEMS", + "Question": "The four-color problem relates to the minimum number of colors needed for this cartographic item", + "Answer": "a map" + }, + { + "Category": "\"EN\" THE BEGINNING", + "Question": "These peptide hormones in the brain reduce the sensation of pain", + "Answer": "endorphins" + }, + { + "Category": "COLONIAL ARTS", + "Question": "In 1750 theater was banned in this then-colonial capital as a form of Mass. entertainment", + "Answer": "Boston" + }, + { + "Category": "INTERNATIONAL CUISINE", + "Question": "To enjoy this national Swiss dish, you'd better like cheese, lots of it, melted in wine", + "Answer": "fondue" + }, + { + "Category": "WE ARE THE CHAMPIONS", + "Question": "In 2001 Brian Cappelletto won this game's World Championship with words like vozhd for 50 points & jerrid for 44", + "Answer": "Scrabble" + }, + { + "Category": "RELIGION", + "Question": "Less than 20% of all Muslims are Shi'ites or of other groups; the rest belong to this branch", + "Answer": "Sunni" + }, + { + "Category": "PROBLEMS, PROBLEMS", + "Question": "Ferdinand von Lindemann proved the problem of \"squaring\" this with compass & ruler was impossible", + "Answer": "the circle" + }, + { + "Category": "\"EN\" THE BEGINNING", + "Question": "2-word term for the consumer, for whom a computer is ultimately designed", + "Answer": "an end user" + }, + { + "Category": "COLONIAL ARTS", + "Question": "Some of the earliest surviving colonial portraits are of Richard & Increase, members of this family", + "Answer": "the Mathers" + }, + { + "Category": "INTERNATIONAL CUISINE", + "Question": "The seafood in this Mexican dish is \"cooked\" not by heat, but by the acid in lime juice", + "Answer": "ceviche" + }, + { + "Category": "WE ARE THE CHAMPIONS", + "Question": "In 1993 she became the first woman from Ukraine to win the world figure skating championships", + "Answer": "Oksana Baiul" + }, + { + "Category": "RELIGION", + "Question": "Founded by & named for a Persian prophet, this religion flourished during Persia's Achaemenian empire", + "Answer": "Zoroastrianism" + }, + { + "Category": "\"EN\" THE BEGINNING", + "Question": "This Baja California port city is known as \"Yellowtail Capital of the World\"", + "Answer": "Ensenada" + }, + { + "Category": "COLONIAL ARTS", + "Question": "Meaning \"tobacco peddler\", it's the title of a 1708 Ebenezer Cooke poem & a 1960 John Barth novel about Cooke", + "Answer": "The Sot-Weed Factor" + }, + { + "Category": "INTERNATIONAL CUISINE", + "Question": "This Greek dish typically consists of layers of eggplant & ground lamb or beef topped with a white sauce", + "Answer": "moussaka" + }, + { + "Category": "WE ARE THE CHAMPIONS", + "Question": "At Wimbledon 2000, Venus Williams expressed appreciation for this 1957 & '58 champion", + "Answer": "Althea Gibson" + }, + { + "Category": "RELIGION", + "Question": "Traditionally, in Judaism a ram's horn called this is blown at the end of Yom Kippur", + "Answer": "shofar" + }, + { + "Category": "PROBLEMS, PROBLEMS", + "Question": "To apply relativity to the cosmos, Einstein introduced a term called the \"cosmological\" this", + "Answer": "constant" + }, + { + "Category": "\"EN\" THE BEGINNING", + "Question": "The U.S. conducted nuclear tests on this atoll in the Marshall Islands from 1948 to 1958", + "Answer": "Enewetak" + }, + { + "Category": "COLONIAL ARTS", + "Question": "James Alexander, whose doggerel contributed to this publisher's arrest, helped defend him as a lawyer", + "Answer": "Zenger" + }, + { + "Category": "INTERNATIONAL CUISINE", + "Question": "On an Italian menu this term describes pasta with a sauce of eggs, cream, parmesan & bacon", + "Answer": "carbonara" + }, + { + "Category": "WE ARE THE CHAMPIONS", + "Question": "The last British athlete to win the Olympic decathlon, he won it back-to-back in 1980 & 1984", + "Answer": "Daley Thompson" + }, + { + "Category": "RELIGION", + "Question": "Joseph Smith translated the Book of Mormon from gold plates revealed to him by an angel named this", + "Answer": "Moroni" + }, + { + "Category": "PROBLEMS, PROBLEMS", + "Question": "This Frenchman's \"last theorem\", stated in 1637, was proved by Andrew Wiles in the 1990s", + "Answer": "Fermat" + }, + { + "Category": "\"EN\" THE BEGINNING", + "Question": "John Keats wrote a poem about this handsome Greek whose youth was preserved by eternal sleep", + "Answer": "Endymion" + }, + { + "Category": "KNOWLEDGE BY THE NUMBERS", + "Question": "Number of males who served as British PM in the 1990s plus Oscars won by Tom Hanks plus protons in a helium nucleus", + "Answer": "6" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "Crackowes were a style of these with toes so long they were sometimes attached to the knees with chains", + "Answer": "shoes" + }, + { + "Category": "MANIAS", + "Question": "One suffering from bruxomania unconsciously gnashes these", + "Answer": "Teeth" + }, + { + "Category": "JEWELRY", + "Question": "Sotheby's has announced it won't sell any items of this tusk material produced since 1939", + "Answer": "Ivory" + }, + { + "Category": "AUSTRALIA", + "Question": "It's the basic unit of currency of Australia", + "Answer": "Australian Dollar" + }, + { + "Category": "SPORTS EQUIPMENT", + "Question": "Until 1954 major league players could leave these on the field when it was their team's turn to bat", + "Answer": "Gloves" + }, + { + "Category": "PEANUTS", + "Question": "When Charlie Brown gave Snoopy one of these, it took Snoopy an hour to put it on the flea", + "Answer": "Flea Collar" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "Eleanor of Aquitaine accompanied her 1st husband, King Louis VII, on the 2nd one of these in 1147", + "Answer": "Crusades" + }, + { + "Category": "MANIAS", + "Question": "In a 1987 hit Whitney Houston showed signs of choreomania when she wanted to do this with somebody", + "Answer": "Dance" + }, + { + "Category": "JEWELRY", + "Question": "The scarab, lotus flower & Isis knot were all designs used in this country's jewelry", + "Answer": "Egypt" + }, + { + "Category": "AUSTRALIA", + "Question": "After America won its independence, the British decided to ship these people to Australia", + "Answer": "Convicts/Prisoners" + }, + { + "Category": "SPORTS EQUIPMENT", + "Question": "A curved wicker basket called a cesta is used to catch & throw the ball in this sport", + "Answer": "jai alai" + }, + { + "Category": "PEANUTS", + "Question": "Of a 25th, 30th or 40th anniversary, what \"Peanuts\" is celebrating in 1990", + "Answer": "40th Anniversary" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "It's estimated this dread 14th century epidemic killed 1/3 of the population of Europe", + "Answer": "Black Death" + }, + { + "Category": "MANIAS", + "Question": "A lycomaniac has a howling time believing he is one of these", + "Answer": "Wolf" + }, + { + "Category": "JEWELRY", + "Question": "Known for its malleability & white brilliance, this rare metal has been used in jewelry since the 19th C.", + "Answer": "Platinum" + }, + { + "Category": "AUSTRALIA", + "Question": "The name of this capital city is Aboriginal for \"meeting place\"", + "Answer": "Canberra" + }, + { + "Category": "SPORTS EQUIPMENT", + "Question": "1 of 2 pieces of equipment in track & field that weigh 16 pounds", + "Answer": "Hammer & Shot-Put" + }, + { + "Category": "PEANUTS", + "Question": "When Lucy invites Charlie Brown to kick a football, you can expect her to do this", + "Answer": "Pull it out from under him" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "2 types of these which were especially popular during the Middle Ages were \"Miracle\" & \"Morality\"", + "Answer": "Types of plays" + }, + { + "Category": "MANIAS", + "Question": "A dipsomaniac craves this, not guacamole", + "Answer": "Alcoholic Beverages" + }, + { + "Category": "JEWELRY", + "Question": "Josiah Wedgwood designed these jewelry pieces using a white paste relief on a colored backgorund", + "Answer": "Cameos" + }, + { + "Category": "AUSTRALIA", + "Question": "\"Banjo\" Paterson, known for his \"bush ballads\", wrote this song, 1st published in 1917", + "Answer": "\"Waltzing Matilda\"" + }, + { + "Category": "SPORTS EQUIPMENT", + "Question": "Alternate name for the number one wood in golf", + "Answer": "Driver" + }, + { + "Category": "PEANUTS", + "Question": "This girl's name was inspired by a type of candy", + "Answer": "Peppermint Patty" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "This famous \"song\" is a romanticized account of the Battle of Roncesvalles, fought in 778", + "Answer": "\"Song Of Roland\"" + }, + { + "Category": "MANIAS", + "Question": "From the Greek for \"great\", it's the delusion of wealth, power or omnipotence", + "Answer": "Megalomania" + }, + { + "Category": "JEWELRY", + "Question": "Tahiti & French Polynesia are famous for pearls of this color", + "Answer": "Black" + }, + { + "Category": "AUSTRALIA", + "Question": "This flightless bird is featured on Australia's coat of arms", + "Answer": "Emu" + }, + { + "Category": "SPORTS EQUIPMENT", + "Question": "This apparatus used in women's gymnastics is about 4 in. wide & 16 ft. long", + "Answer": "Balance Beam" + }, + { + "Category": "PEANUTS", + "Question": "Charlie Brown's parents bought Snoopy at this puppy farm", + "Answer": "Daisy Hill Puppy Farm" + }, + { + "Category": "U.S.A.", + "Question": "On average this city packs more than 23,000 people into 1 sq. mile", + "Answer": "New York City" + }, + { + "Category": "PEN NAMES", + "Question": "2 of his pen names were rather transparent: Antosha Chekhonte & Anton Ch.", + "Answer": "Anton Chekhov" + }, + { + "Category": "ANATOMY", + "Question": "The only mobile bone of the face", + "Answer": "Mandible" + }, + { + "Category": "MYTHOLOGICAL PAIRS", + "Question": "Both a she-wolf & a woodpecker fed & cared for them until they were found by Faustulus", + "Answer": "Romulus & Remus" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Something that evokes happiness & sadness at the same time, or a kind of chocolate", + "Answer": "Bittersweet" + }, + { + "Category": "MUSICALS", + "Question": "This title character's last name is McLonergan, not Rainbow", + "Answer": "Finian" + }, + { + "Category": "U.S.A.", + "Question": "Caucasians constitute about 1/3 of this state's population", + "Answer": "Hawaii" + }, + { + "Category": "PEN NAMES", + "Question": "Dublin-born playwright John Casey changed his name to this, which sounds more Irish", + "Answer": "Sean O' Casey" + }, + { + "Category": "ANATOMY", + "Question": "The nephrons function as filtering units in this pair of organs", + "Answer": "Kidneys" + }, + { + "Category": "MYTHOLOGICAL PAIRS", + "Question": "In all of Babylonia, Pyramus was the handsomest youth & she was the fairest maiden", + "Answer": "Thisbe" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Term for stunt pilots or politicians who tour small towns to show they've got the right stuff", + "Answer": "Barnstormer" + }, + { + "Category": "MUSICALS", + "Question": "(AUDIO DAILY DOUBLE): Gwen Verdon sang the following song in the original Broadway version of this show: \"Whatever Lola wants, Lola gets...\"", + "Answer": "\"Damn Yankees!\"" + }, + { + "Category": "U.S.A.", + "Question": "Even though it's officially \"dry\", this state's Moore County is the home of Jack Daniel's Whiskey", + "Answer": "Tennessee" + }, + { + "Category": "PEN NAMES", + "Question": "We don't know why this dame sometimes wrote under the name Mary Westmacott; it's a mystery to us", + "Answer": "Agatha Christie" + }, + { + "Category": "ANATOMY", + "Question": "The term for the brain & spinal cord, often abbreviated CNS", + "Answer": "Central Nervous System" + }, + { + "Category": "MYTHOLOGICAL PAIRS", + "Question": "He travels to Ireland to ask the hand of the princess Isolde for his uncle, King Mark of Cornwall", + "Answer": "Tristan" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Don't complain to your waiter that your soup is cold if you're served this French potato soup", + "Answer": "Vichysoisse" + }, + { + "Category": "MUSICALS", + "Question": "This show opens with a Ziegfeld star waiting for her husband to be released from prison", + "Answer": "\"Funny Girl\"" + }, + { + "Category": "U.S.A.", + "Question": "Ironically, the prison inmates of this state produce license plates which read \"Live Free Or Die\"", + "Answer": "New Hampshire" + }, + { + "Category": "PEN NAMES", + "Question": "Pseudonym of the mysterious recluse who wrote \"The Treasure of the Sierra Madre\"", + "Answer": "B. Traven" + }, + { + "Category": "ANATOMY", + "Question": "This section of the digestive tract is divided into the duodenum, jejunum & ileum", + "Answer": "Small Intestine" + }, + { + "Category": "MYTHOLOGICAL PAIRS", + "Question": "Wounded by Cupid's arrow, Venus fell in love with this handsome guy at 1st sight", + "Answer": "Adonis" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Another name for mercury, it also means mercurial or temperamental", + "Answer": "Quicksilver" + }, + { + "Category": "MUSICALS", + "Question": "Mrs. Ray Bolger co-produced this 1948 Ray Bolger musical based on \"Charley's Aunt\"", + "Answer": "\"Where's Charley?\"" + }, + { + "Category": "U.S.A.", + "Question": "1 of the largest lakes in Minnesota, its name begins with the same 5 letters as Minnesota", + "Answer": "Lake Minnetonka" + }, + { + "Category": "PEN NAMES", + "Question": "Rosemary Jansze, who was born in Ceylon, writes her romance novels under this married name", + "Answer": "Rosemary Rogers" + }, + { + "Category": "ANATOMY", + "Question": "The 4 principal arteries of the head & neck are all called this", + "Answer": "Carotid Arteries" + }, + { + "Category": "MYTHOLOGICAL PAIRS", + "Question": "Until the night he drowned, Leander swam across the Hellespont every night to meet her", + "Answer": "Hero" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Term for someone who collects deniers, drachmas & doubloons", + "Answer": "Numismatist" + }, + { + "Category": "MUSICALS", + "Question": "This show features a concubine from Burma named Tuptim", + "Answer": "\"The King And I\"" + }, + { + "Category": "FAMOUS NAMES", + "Question": "He published a history of Virginia & New England in 1624, after escaping from Turks, Indians & pirates", + "Answer": "Captain John Smith" + }, + { + "Category": "FAMOUS NAMES", + "Question": "This star of \"Kojak\" admits he shaves his head every morning", + "Answer": "Telly Savalas" + }, + { + "Category": "ADVERTISING SLOGANS", + "Question": "\"When you care enough to send the very best\", send one of these", + "Answer": "Hallmark Card" + }, + { + "Category": "THE BIBLE", + "Question": "Among these tales told by Jesus were those \"of the net\", \"of the mustard seed\" & \"of the hidden treasures\"", + "Answer": "Parables" + }, + { + "Category": "WEATHER", + "Question": "Airplanes can trigger bolts of this when traveling through electrified clouds", + "Answer": "Lightning" + }, + { + "Category": "4-LETTER WORDS", + "Question": "This word commonly follows cuff or missing", + "Answer": "Link" + }, + { + "Category": "PRESIDENTIAL ASTROLOGY", + "Question": "Gerald Ford was the last president born under this \"crab\"by sign", + "Answer": "Cancer" + }, + { + "Category": "FAMOUS NAMES", + "Question": "Creator of \"The Cisco Kid\", William Sidney Porter was better known by this name", + "Answer": "O. Henry" + }, + { + "Category": "ADVERTISING SLOGANS", + "Question": "\"Wouldn't you really rather have\" one of these cars", + "Answer": "Buick" + }, + { + "Category": "THE BIBLE", + "Question": "I Corinthians 7:9 states, \"It is better to marry than to\" do this", + "Answer": "Burn" + }, + { + "Category": "WEATHER", + "Question": "Air is described as supersaturated when the relative humidity is higher than this percent", + "Answer": "100%" + }, + { + "Category": "4-LETTER WORDS", + "Question": "From the Greek word for \"deep sleep\", it's a deep, prolonged unconsciousness", + "Answer": "Coma" + }, + { + "Category": "PRESIDENTIAL ASTROLOGY", + "Question": "It's Jimmy Carter's sign, so don't tip his scales", + "Answer": "Libra" + }, + { + "Category": "FAMOUS NAMES", + "Question": "\"The First Time Ever\" she had a No. 1 album was \"First Take\" in 1972", + "Answer": "Roberta Flack" + }, + { + "Category": "ADVERTISING SLOGANS", + "Question": "\"I like\" this lemon-lime soda \"in you\"", + "Answer": "Sprite" + }, + { + "Category": "THE BIBLE", + "Question": "It was like coriander seed, white; & the taste of it was like wafers made with honey", + "Answer": "Manna" + }, + { + "Category": "WEATHER", + "Question": "Tornadoes that develop over water are called these", + "Answer": "Waterspouts" + }, + { + "Category": "4-LETTER WORDS", + "Question": "It can be part of your foot, your shoe, your stocking or your loaf of bread", + "Answer": "Heel" + }, + { + "Category": "PRESIDENTIAL ASTROLOGY", + "Question": "Appropriately, we've had 2 presidents born under this sign, Bush & Kennedy", + "Answer": "Gemini" + }, + { + "Category": "FAMOUS NAMES", + "Question": "George Bush pardoned this 91-year-old industrialist for his illegal contributions to Nixon's campaign", + "Answer": "Armand Hammer" + }, + { + "Category": "ADVERTISING SLOGANS", + "Question": "\"Tan, don't burn use\" this", + "Answer": "Coppertone" + }, + { + "Category": "THE BIBLE", + "Question": "Things saved from this city were the gold & silver, the iron & brass vessels & Rahab & her family", + "Answer": "Jericho" + }, + { + "Category": "WEATHER", + "Question": "Season of the year when Arizona has its \"monsoons\"", + "Answer": "Summer" + }, + { + "Category": "4-LETTER WORDS", + "Question": "A roue, or his garden implement", + "Answer": "Rake" + }, + { + "Category": "PRESIDENTIAL ASTROLOGY", + "Question": "Our last Sagittarian pres.; his last name sounds like something Sagittarius' arrows could do", + "Answer": "Pierce" + }, + { + "Category": "FAMOUS NAMES", + "Question": "Ines de la Fressange was a Chanel model when she was chosen to represent this French symbol", + "Answer": "Marianne" + }, + { + "Category": "ADVERTISING SLOGANS", + "Question": "This maker of pre-school toys says, \"Our work is child's play\"", + "Answer": "Fisher-Price" + }, + { + "Category": "THE BIBLE", + "Question": "While carting this, Uzza touched it to right it after the oxen stumbled, & the Lord smote him", + "Answer": "The Ark of the Covenant" + }, + { + "Category": "WEATHER", + "Question": "An increase in air temperature at higher altitudes is unusual & is called this", + "Answer": "Inversion" + }, + { + "Category": "4-LETTER WORDS", + "Question": "A raisin can be called by this other fruit's name when it's added to a pudding or a cake", + "Answer": "Plum" + }, + { + "Category": "PRESIDENTIAL ASTROLOGY", + "Question": "With the exception of R. Reagan, all the presidents born under this sign died in office", + "Answer": "Aquarius" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "The iris is a flower & the ibis is one of these", + "Answer": "Bird" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "This country is named after the town of Oporto", + "Answer": "Portugal" + }, + { + "Category": "PIRATE MOVIES", + "Question": "In this 1935 film that made him a star, Errol Flynn was Dr. Peter Blood, a physician who turns to piracy", + "Answer": "\"Captain Blood\"" + }, + { + "Category": "AUTHORS", + "Question": "He wrote a non-baby book called \"Decent And Indecent: Our Personal And Political Behavior\"", + "Answer": "Dr. Benjamin Spock" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "It became a U.S. territory in 1900 & a state 59 years later", + "Answer": "Hawaii" + }, + { + "Category": "WINE", + "Question": "Malaga is a sweet dessert wine that originated in this country", + "Answer": "Spain" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "In a healthy mouth, this line separates the crown from the root of a tooth", + "Answer": "Gum Line" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "The Sea of Galilee is just a broad basin of this river", + "Answer": "The River Jordan" + }, + { + "Category": "PIRATE MOVIES", + "Question": "Anthony Quinn was a pirate stuck with stowaway children in the film \"A High Wind In\" this place", + "Answer": "Jamaica" + }, + { + "Category": "AUTHORS", + "Question": "This author's home where he wrote \"To Have And Have Not\" is now a nat'l landmark in Key West, Fla.", + "Answer": "Ernest Hemingway" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "Susan B. Anthony was arrested in 1872 for doing this", + "Answer": "Voting" + }, + { + "Category": "WINE", + "Question": "On wine labels, this word which means \"estate\" precedes Lafite & Mouton-Rothschild", + "Answer": "Chateau" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Every summer thousands of these animals go to the Pribilof Islands in the north Pacific to breed", + "Answer": "Seals" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "The surface of this lake in Siberia is about 1,490 ft. above sea level, the bottom over 5,300 ft. below", + "Answer": "Lake Baikal" + }, + { + "Category": "PIRATE MOVIES", + "Question": "Silent screen swashbuckler; his film \"The Black Pirate\" has been called \"a definitive pirate movie\"", + "Answer": "Douglas Fairbanks, Sr." + }, + { + "Category": "AUTHORS", + "Question": "Oscar Wilde's only novel", + "Answer": "\"The Picture Of Dorian Gray\"" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1949 Henry H. Arnold became the first general of this branch of the armed forces", + "Answer": "Air Force" + }, + { + "Category": "WINE", + "Question": "\"Anatomical\" term for a wine's bouquet", + "Answer": "Nose" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Man-made metal 1st positively identified in 1958 & named for a Swedish inventor; it has no known use", + "Answer": "Nobelium" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "Papua New Guinea is just off this country's Cape York Peninsula", + "Answer": "Australia" + }, + { + "Category": "PIRATE MOVIES", + "Question": "Robert Newton played this pirate before Peter Ustinov played his ghost in a Disney film", + "Answer": "Blackbeard" + }, + { + "Category": "AUTHORS", + "Question": "An eye ailment contracted at Eton School ended his plans to study biology, like his brother Julian", + "Answer": "Aldous Huxley" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In April 1984 this U.S. government agency admitted its role in the mining of Nicaraguan harbors", + "Answer": "CIA" + }, + { + "Category": "WINE", + "Question": "The term for pouring wine into another container before serving; it helps clear it of sediments", + "Answer": "Decanting" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Take the fibrinogen out of blood plasma & you're left with a fluid called this", + "Answer": "Serum" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "1 of the 2 Central American countries with only 1 sea coast", + "Answer": "Belize & El Salvador" + }, + { + "Category": "PIRATE MOVIES", + "Question": "Ingrid Bergman's husband in \"Casablanca\", he played a pirate captain in \"Pirates Of Tripoli\"", + "Answer": "Paul Henreid" + }, + { + "Category": "AUTHORS", + "Question": "A member of the Algonquin Round Table, this petite brunette wrote a story called \"Big Blonde\"", + "Answer": "Dorothy Parker" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "John Hancock held this political position from 1780-85 & from 1787-93", + "Answer": "Governor of Massachusetts" + }, + { + "Category": "WINE", + "Question": "The famous Moselle wines come from this country", + "Answer": "Germany" + }, + { + "Category": "CABLE TELEVISION", + "Question": "The name of this channel can be traced back to a movie theater that opened in 1905 in McKeesport, Pa.", + "Answer": "Nickelodeon" + }, + { + "Category": "MUSIC VIDEOS", + "Question": "At the beginning of her 2005 \"Boyfriend\" video, she is being chased by the police", + "Answer": "Ashlee Simpson" + }, + { + "Category": "HOW DO YOU...", + "Question": "Hold the ends of the coiled toy first sold in 1945, then raise & lower each hand in a rhythmic motion", + "Answer": "work a Slinky" + }, + { + "Category": "TELL 'EM WHAT THEY'VE WON, JOHNNY", + "Question": "The first of these were awarded in 1901 & they are given out yearly for Physics, Chemistry, Peace & 3 other disciplines", + "Answer": "the Nobel Prizes" + }, + { + "Category": "PIZZA TOPPINGS", + "Question": "This type of hard sausage is America's favorite pizza topping", + "Answer": "pepperoni" + }, + { + "Category": "ALLITERATION STATION", + "Question": "\"If\" he \"picked a peck of pickled peppers, where's the peck of pickled peppers\" he \"picked\"?", + "Answer": "Peter Piper" + }, + { + "Category": "MUSIC VIDEOS", + "Question": "Paris Hilton is in this rapper's \"Just Lose It\" video; he appears as himself & as Santa Claus, among others", + "Answer": "Eminem" + }, + { + "Category": "HOW DO YOU...", + "Question": "Churn a sweet dairy mix in a container that's surrounded by frozen water & salt", + "Answer": "make ice cream" + }, + { + "Category": "TELL 'EM WHAT THEY'VE WON, JOHNNY", + "Question": "In 1990 Paul McCartney received a Lifetime Achievement Award at these awards", + "Answer": "the Grammys" + }, + { + "Category": "PIZZA TOPPINGS", + "Question": "How about a nice traditional Hawaiian pizza topped with ham or Canadian bacon & this fruit", + "Answer": "pineapple" + }, + { + "Category": "ALLITERATION STATION", + "Question": "An evening where 2 couples go out together", + "Answer": "a double date" + }, + { + "Category": "MUSIC VIDEOS", + "Question": "At the 2004 MTV VMAs, No Doubt won Best Group Video & Best Pop Video for this song", + "Answer": "\"It's My Life\"" + }, + { + "Category": "HOW DO YOU...", + "Question": "Holding the bottom of the ear in the left hand, grasp the husk from the top with the right hand & pull down", + "Answer": "shuck corn" + }, + { + "Category": "TELL 'EM WHAT THEY'VE WON, JOHNNY", + "Question": "A brave French soldier might receive the award known as the \"Croix de Guerre\", meaning \"Cross of\" this", + "Answer": "War" + }, + { + "Category": "PIZZA TOPPINGS", + "Question": "These on your pizza may be fire-roasted, sun-dried, or just fresh sliced Romas", + "Answer": "tomatoes" + }, + { + "Category": "ALLITERATION STATION", + "Question": "An appointed hour to play golf", + "Answer": "tee time" + }, + { + "Category": "MUSIC VIDEOS", + "Question": "This former \"Moesha\" star rides around on the bus in her \"Who Is She 2 U\" video", + "Answer": "Brandy" + }, + { + "Category": "HOW DO YOU...", + "Question": "Dial 011-33-1 & a local number, say \"Pourrais-je parler a M. Chirac?\"", + "Answer": "call the president of France" + }, + { + "Category": "TELL 'EM WHAT THEY'VE WON, JOHNNY", + "Question": "The Borg-Warner Trophy is awarded every year to the winner of this epic auto race held on Memorial Day weekend", + "Answer": "the Indy 500" + }, + { + "Category": "PIZZA TOPPINGS", + "Question": "On November 12 celebrate National Pizza with the Works Except these fish Day", + "Answer": "Anchovies" + }, + { + "Category": "ALLITERATION STATION", + "Question": "The almost indestructible flight recording device is known by this \"colorful\" name", + "Answer": "the black box" + }, + { + "Category": "MUSIC VIDEOS", + "Question": "Her video for \"Baby It's You\" features Bow Wow & takes place at an amusement park", + "Answer": "Jojo" + }, + { + "Category": "HOW DO YOU...", + "Question": "Attach a pencil to a string, pin the other end of the string down & move the pencil around the pin", + "Answer": "draw a circle" + }, + { + "Category": "TELL 'EM WHAT THEY'VE WON, JOHNNY", + "Question": "In 1921 Edith Wharton became the first woman to win the Fiction prize named for this news publisher", + "Answer": "Pulitzer" + }, + { + "Category": "PIZZA TOPPINGS", + "Question": "Wild ones of these found on pizza include shiitakes, morels & chanterelles", + "Answer": "mushrooms" + }, + { + "Category": "ALLITERATION STATION", + "Question": "Daisy Buchanan is the object of a racketeer's desire in this 1925 Fitzgerald novel", + "Answer": "The Great Gatsby" + }, + { + "Category": "WOMEN ON U.S. STAMPS", + "Question": "1902: The first First Lady", + "Answer": "Martha Washington" + }, + { + "Category": "MOVIE TITLE TRANSLATIONS", + "Question": "Hong Kong titled the second movie about this creature \"I May Be A Pig, But I Am Not Stupid\"", + "Answer": "Babe" + }, + { + "Category": "NATIONAL INVENTORS HALL OF FAME", + "Question": "He was honored for discovering \"hundreds of new uses for crops such as the peanut\"", + "Answer": "George Washington Carver" + }, + { + "Category": "JULIUS CAESAR", + "Question": "In 46 B.C. this Egyptian came with Caesar to Rome, where her statue was placed in the temple of Venus Genetrix", + "Answer": "Cleopatra" + }, + { + "Category": "LOVE POETRY", + "Question": "The immortal 6 words that begin Lee Bernstein's opus sung on \"Barney & Friends\" to the tune of \"This Old Man\"", + "Answer": "I love you; you love me" + }, + { + "Category": "WORDS IN (THE) ENCYCLOPEDIA", + "Question": "Book of Genesis garden", + "Answer": "Eden" + }, + { + "Category": "WOMEN ON U.S. STAMPS", + "Question": "1952: A famous seamstress & flagmaker", + "Answer": "Betsy Ross" + }, + { + "Category": "MOVIE TITLE TRANSLATIONS", + "Question": "They were the 2 main stars of the sequel Hong Kong knew as \"Special Unit in Black Glasses Part 2\"", + "Answer": "Tommy Lee Jones & Will Smith" + }, + { + "Category": "NATIONAL INVENTORS HALL OF FAME", + "Question": "Inducted in 1973, he \"earned patents for more than a thousand inventions, including... the phonograph\"", + "Answer": "Edison" + }, + { + "Category": "JULIUS CAESAR", + "Question": "Caesar divorced his wife after a scandal & said, \"Caesar's wife must be above\" this", + "Answer": "suspicion" + }, + { + "Category": "LOVE POETRY", + "Question": "Marvell rhymed, \"Had we but world enough, and\" this, his mistress' coyness \"were no crime\"", + "Answer": "time" + }, + { + "Category": "WORDS IN (THE) ENCYCLOPEDIA", + "Question": "This type of year happens once every four", + "Answer": "leap" + }, + { + "Category": "WOMEN ON U.S. STAMPS", + "Question": "1994: A Shoshone guide for a famous expedition", + "Answer": "Sacagawea" + }, + { + "Category": "MOVIE TITLE TRANSLATIONS", + "Question": "China and Taiwan reached the agreement that this film at \"Full Throttle\" would be \"Hot Chicks: Full Speed\"", + "Answer": "Charlie's Angels" + }, + { + "Category": "NATIONAL INVENTORS HALL OF FAME", + "Question": "\"'Snow White and the Seven Dwarfs' was the first full length animated film to use\" this inductee's multiplane camera", + "Answer": "Walt Disney" + }, + { + "Category": "JULIUS CAESAR", + "Question": "In his early 20s, Julius Caesar traveled to this \"colossal\" island to study rhetoric under Molon", + "Answer": "Rhodes" + }, + { + "Category": "LOVE POETRY", + "Question": "It makes sense that Marlowe's \"passionate shepherd\" promises his love \"a gown made of the finest\" this", + "Answer": "wool" + }, + { + "Category": "WORDS IN (THE) ENCYCLOPEDIA", + "Question": "Brown & white are the main U.S. types of this pouch-mouthed bird", + "Answer": "pelican" + }, + { + "Category": "WOMEN ON U.S. STAMPS", + "Question": "1907: A Powhatan princess", + "Answer": "Pocahontas" + }, + { + "Category": "MOVIE TITLE TRANSLATIONS", + "Question": "In Greece, this Eddie Murphy film became \"Daddies as Nannies\"", + "Answer": "Daddy Day Care" + }, + { + "Category": "NATIONAL INVENTORS HALL OF FAME", + "Question": "A 1975 inductee, he gave us \"an electronic alphabet that could carry messages\"", + "Answer": "Morse" + }, + { + "Category": "JULIUS CAESAR", + "Question": "After defeating Pharnaces II at Zela, Caesar dispatched this 3-part message to the Roman Senate", + "Answer": "Veni, vidi, vici" + }, + { + "Category": "LOVE POETRY", + "Question": "A Shakespeare sonnet accuses this purple flower of steaing its smell from the poet's love", + "Answer": "the violet" + }, + { + "Category": "WORDS IN (THE) ENCYCLOPEDIA", + "Question": "Fake wooden bird used by hunters to attract ducks", + "Answer": "decoy" + }, + { + "Category": "WOMEN ON U.S. STAMPS", + "Question": "1963: A pilot", + "Answer": "Amelia Earhart" + }, + { + "Category": "MOVIE TITLE TRANSLATIONS", + "Question": "In Finland, this Tim Burton film was subtitled \"Fish Stories as Large as Life Itself\"", + "Answer": "Big Fish" + }, + { + "Category": "NATIONAL INVENTORS HALL OF FAME", + "Question": "This French chemist inducted in 1978 \"was the founder of microbiological sciences\"", + "Answer": "Pasteur" + }, + { + "Category": "JULIUS CAESAR", + "Question": "Around 48 B.C. Caesar pardoned this man & later made him governor of Cisalpine Gaul; oops", + "Answer": "Brutus" + }, + { + "Category": "WORDS IN (THE) ENCYCLOPEDIA", + "Question": "Genetic duplicate", + "Answer": "clone" + }, + { + "Category": "THE 50 STATES", + "Question": "Since 1776, it has been the only U.S. state to be the most populous state for more than a century", + "Answer": "New York" + }, + { + "Category": "FIRST NOVELS", + "Question": "Few have heard of his first novel, \"The Snake's Pass\", but everyone knows his \"Dracula\"", + "Answer": "Bram Stoker" + }, + { + "Category": "CLASSIC AD LINES", + "Question": "\"Fly The Friendly Skies...\"", + "Answer": "United Airlines" + }, + { + "Category": "LESSER-KNOWN MUSICALS", + "Question": "Elementary, my dear Watson: \"Baker Street\" was a musical about this detective", + "Answer": "Sherlock Holmes" + }, + { + "Category": "HORNS", + "Question": "Christian tradition says this archangel will blow his trumpet to announce the Second Coming", + "Answer": "Gabriel" + }, + { + "Category": "IT'S A DOGGY DOG WORLD", + "Question": "Jura, Schweitzer, Lucerne & Berner are the 4 types of this country's laufhund", + "Answer": "Switzerland" + }, + { + "Category": "\"MUM\"s THE WORD", + "Question": "This contagious viral disease can occasionally cause sterility in males", + "Answer": "Mumps" + }, + { + "Category": "FIRST NOVELS", + "Question": "His first novel, \"The Town And The City\", might be good to read while you're \"On The Road\"", + "Answer": "Jack Kerouac" + }, + { + "Category": "CLASSIC AD LINES", + "Question": "\"We Bring Good Things To Life\"", + "Answer": "General Electric" + }, + { + "Category": "LESSER-KNOWN MUSICALS", + "Question": "\"Comin' Uptown\" moved this classic tale to Harlem; it starred Gregory Hines as a slumlord named Scrooge", + "Answer": "A Christmas Carol" + }, + { + "Category": "HORNS", + "Question": "South America's southernmost point, its rocky terrain rises to a height of 1,391 feet", + "Answer": "Cape Horn" + }, + { + "Category": "IT'S A DOGGY DOG WORLD", + "Question": "Seen here, it's named for a peninsula shared by Quebec & Newfoundland", + "Answer": "Labrador Retriever" + }, + { + "Category": "\"MUM\"s THE WORD", + "Question": "....I said it's to utter something quietly & unclearly!", + "Answer": "Mumble" + }, + { + "Category": "FIRST NOVELS", + "Question": "This \"Brideshead Revisited\" author's career was ascendant when he published his first novel, \"Decline And Fall\"", + "Answer": "Evelyn Waugh" + }, + { + "Category": "CLASSIC AD LINES", + "Question": "\"Tastes So Good Cats Ask For It By Name\"", + "Answer": "Meow Mix" + }, + { + "Category": "LESSER-KNOWN MUSICALS", + "Question": "Danny Kaye's career \"ark\" included this Biblical role in \"Two By Two\"", + "Answer": "Noah" + }, + { + "Category": "HORNS", + "Question": "All species of this large land creature, whose name is from the Greek for \"nose-horned\", are nearly extinct", + "Answer": "Rhinoceros" + }, + { + "Category": "IT'S A DOGGY DOG WORLD", + "Question": "If this Norwegian breed had originated in North America, it would be called the moosehound", + "Answer": "Elkhound" + }, + { + "Category": "\"MUM\"s THE WORD", + "Question": "This 2-word term for confusing language may come from a Mande phrase for \"ancestor wearing a pompom\"", + "Answer": "Mumbo-jumbo" + }, + { + "Category": "FIRST NOVELS", + "Question": "Sadly, the manuscript of her very first novel was destroyed in a fire in Nanking", + "Answer": "Pearl S. Buck" + }, + { + "Category": "CLASSIC AD LINES", + "Question": "\"The Power To Be Your Best\"", + "Answer": "Apple Computer" + }, + { + "Category": "LESSER-KNOWN MUSICALS", + "Question": "Bully for Len Cariou, who played this famous man in the musical \"Teddy And Alice\"", + "Answer": "Theodore Roosevelt" + }, + { + "Category": "HORNS", + "Question": "This \"continental\" wind instrument is played with one hand inside the bell to control its tone", + "Answer": "French horn" + }, + { + "Category": "IT'S A DOGGY DOG WORLD", + "Question": "This dog once prized by the Aztecs is sometimes called perro pelon, \"bald dog\"", + "Answer": "the Mexican hairless" + }, + { + "Category": "\"MUM\"s THE WORD", + "Question": "Formerly called Bombay, it's in the top 5 cities in the world in population", + "Answer": "Mumbai" + }, + { + "Category": "FIRST NOVELS", + "Question": "He was poet-in-residence at the University of South Carolina when he delivered his first novel, \"Deliverance\"", + "Answer": "James Dickey" + }, + { + "Category": "CLASSIC AD LINES", + "Question": "\"When It Absolutely, Positively Has To Be There Overnight\"", + "Answer": "Federal Express" + }, + { + "Category": "LESSER-KNOWN MUSICALS", + "Question": "Shaun Cassidy was 10 years old when these actors, his parents, starred in the 1968 musical \"Maggie Flynn\"", + "Answer": "Jack Cassidy & Shirley Jones" + }, + { + "Category": "HORNS", + "Question": "According to mythology, this Horn of Plenty is the horn of the goat Amalthea", + "Answer": "Cornucopia" + }, + { + "Category": "IT'S A DOGGY DOG WORLD", + "Question": "The Australian cattle dog was first bred in the 19th century from collies, kelpies & this wild canine", + "Answer": "Dingo" + }, + { + "Category": "\"MUM\"s THE WORD", + "Question": "You'll see this group parading through Philly each New Year's Day", + "Answer": "Mummers" + }, + { + "Category": "THE BIBLE", + "Question": "This wise king of Israel had \"Forty thousand stalls of horses for his chariots, and twelve thousand horsemen\"", + "Answer": "Solomon" + }, + { + "Category": "TELEVISION", + "Question": "In 1998 Brian Dennehy made his first appearance as Red Finch, David Spade's firefighter father, on this hit series", + "Answer": "Just Shoot Me" + }, + { + "Category": "LICENSE PLATE MOTTOS", + "Question": "\"Aloha State\"", + "Answer": "Hawaii" + }, + { + "Category": "BIG MERGERS", + "Question": "In January 1999 we found out Viacom had its eye on this TV network", + "Answer": "CBS" + }, + { + "Category": "\"D\" IN HISTORY", + "Question": "In 1578 a Mongolian ruler first gave the leader of Tibet's Yellow Hat sect of Buddhism this title", + "Answer": "Dalai Lama" + }, + { + "Category": "THE BIBLE", + "Question": "Under the command of this Babylonian king, Nebuzaradan burned \"All the houses of Jerusalem\"", + "Answer": "Nebuchadnezzar" + }, + { + "Category": "LICENSE PLATE MOTTOS", + "Question": "\"10,000 Lakes\"", + "Answer": "Minnesota" + }, + { + "Category": "BIG MERGERS", + "Question": "In November 1998 Daimler-Benz-AG parked this American automaker in its garage", + "Answer": "Chrysler" + }, + { + "Category": "\"D\" IN HISTORY", + "Question": "The Vikings founded this city in the mid-800s, probably naming it for a black pool in the river Liffey", + "Answer": "Dublin" + }, + { + "Category": "ADJECTIVES", + "Question": "As a noun, it's pieces for fastening; as an adjective it's large & robust, like some young men", + "Answer": "strapping" + }, + { + "Category": "THE BIBLE", + "Question": "In 1 Corinthians, he wrote that \"Your faith should not stand in the wisdom of men, but in the power of God\"", + "Answer": "Paul" + }, + { + "Category": "TELEVISION", + "Question": "In January 2000 this libidinous HBO show won the Golden Globe for Best Comedy Series", + "Answer": "Sex and the City" + }, + { + "Category": "LICENSE PLATE MOTTOS", + "Question": "\"Native America\"", + "Answer": "Oklahoma" + }, + { + "Category": "BIG MERGERS", + "Question": "In 1998 Norwest Corporation acquired this bank all in one stage without coaching", + "Answer": "Wells Fargo" + }, + { + "Category": "\"D\" IN HISTORY", + "Question": "In 1868 he became the first person of Jewish ancestry to become prime minister of Great Britain", + "Answer": "Benjamin Disraeli" + }, + { + "Category": "ADJECTIVES", + "Question": "It can refer to a person without mercy or to a Bible missing the book between Judges & Samuel", + "Answer": "ruthless" + }, + { + "Category": "THE BIBLE", + "Question": "This son of Jacob served under Potiphar, captain of Pharaoh's palace guard", + "Answer": "Joseph" + }, + { + "Category": "TELEVISION", + "Question": "In 1999 an ABC sitcom dropped \"a Pizza Place\" from its name, which changed to this", + "Answer": "Two Guys and a Girl" + }, + { + "Category": "LICENSE PLATE MOTTOS", + "Question": "\"First In Flight\"", + "Answer": "North Carolina" + }, + { + "Category": "BIG MERGERS", + "Question": "Exxon moved to merge with this corporation in December 1998", + "Answer": "Mobil" + }, + { + "Category": "\"D\" IN HISTORY", + "Question": "In 1793 this former mistress of Louis XV was guillotined for aiding those seeking to restore the monarchy", + "Answer": "Madame Dubarry" + }, + { + "Category": "ADJECTIVES", + "Question": "Adjective in the name of Hans, the turn-of-the-century calculating horse", + "Answer": "clever" + }, + { + "Category": "THE BIBLE", + "Question": "While they were mending their nets, John & this brother were summoned by Jesus to become disciples", + "Answer": "James" + }, + { + "Category": "TELEVISION", + "Question": "\"Gilligan's Island\" creator Sherwood Schwartz said he wrote this role with his friend Jim Backus in mind", + "Answer": "Thurston Howell III" + }, + { + "Category": "LICENSE PLATE MOTTOS", + "Question": "\"Great Lakes Splendor\"", + "Answer": "Michigan" + }, + { + "Category": "BIG MERGERS", + "Question": "On March 9, 1999 AT&T officially hooked itself up with this cable company (we figure sometime between 1 & 5 PM)", + "Answer": "TCI" + }, + { + "Category": "\"D\" IN HISTORY", + "Question": "This long-range radar \"line\" was established in 1957 to warn the U.S. & Canada of air attack from over the North Pole", + "Answer": "DEWLine" + }, + { + "Category": "ADJECTIVES", + "Question": "When found before \"potato\", it's not a potato; before \"meats\", not meats; & before \"bread\", not bread", + "Answer": "sweet" + }, + { + "Category": "ASIA", + "Question": "It's Asia's southernmost national capital", + "Answer": "Jakarta" + }, + { + "Category": "TRIALS OF THE CENTURY", + "Question": "In 1946 Hans Frank, Rudolf Hess & Fritz Sauckel were among those convicted of war crimes in this city", + "Answer": "Nuremberg" + }, + { + "Category": "LET'S GET M*A*S*Hed", + "Question": "It was Major Margaret Houlihan's sexy nickname", + "Answer": "\"Hot Lips\"" + }, + { + "Category": "VALUABLE PLACES", + "Question": "Hickham Field sustained damage during the Japanese attack on this nearby site December 7, 1941", + "Answer": "Pearl Harbor" + }, + { + "Category": "NAME THE AUTOMAKER", + "Question": "Taurus & T-Bird", + "Answer": "Ford" + }, + { + "Category": "THEATRE HODGEPODGE", + "Question": "In a song in \"The Fantasticks\", \"Soon it's gonna\" do this, \"I can see it. Soon it's gonna\" do this, \"I can tell\"", + "Answer": "Rain" + }, + { + "Category": "\"PRO\"NOUNS", + "Question": "An introductory part in a novel", + "Answer": "Prologue" + }, + { + "Category": "TRIALS OF THE CENTURY", + "Question": "After their convictions, this pair became the first civilians put to death for espionage in the U.S.", + "Answer": "Julius & Ethel Rosenberg" + }, + { + "Category": "LET'S GET M*A*S*Hed", + "Question": "Johnny Mandel wrote this \"painless\" tune that was the show's theme song", + "Answer": "\"Suicide is Painless\"" + }, + { + "Category": "VALUABLE PLACES", + "Question": "The Yellow Brick Road leads to it", + "Answer": "The Emerald City" + }, + { + "Category": "NAME THE AUTOMAKER", + "Question": "Legend & Integra", + "Answer": "Acura" + }, + { + "Category": "THEATRE HODGEPODGE", + "Question": "This William Inge play inspired a Marilyn Maxwell TV series & a Marilyn Monroe film", + "Answer": "Bus Stop" + }, + { + "Category": "\"PRO\"NOUNS", + "Question": "Gosh darn it! It's abusive, vulgar or irreverent language", + "Answer": "Profanity" + }, + { + "Category": "TRIALS OF THE CENTURY", + "Question": "This famous orator aided the prosecution of John Scopes during Tennessee's sensational \"Monkey\" trial", + "Answer": "William Jennings Bryan" + }, + { + "Category": "LET'S GET M*A*S*Hed", + "Question": "William Christopher played this lovable chaplain on the show", + "Answer": "Father Mulcahy" + }, + { + "Category": "VALUABLE PLACES", + "Question": "Sir Joseph Paxton's palace, or Dr. Robert Schuller's cathedral", + "Answer": "Crystal" + }, + { + "Category": "NAME THE AUTOMAKER", + "Question": "Stratus & Stealth", + "Answer": "Dodge" + }, + { + "Category": "THEATRE HODGEPODGE", + "Question": "In titles of musicals, this word stands alone, follows \"Bubbling Brown\" & precedes \"Babies\"", + "Answer": "Sugar" + }, + { + "Category": "\"PRO\"NOUNS", + "Question": "The \"dry\" period in which the 18th Amendment was in force", + "Answer": "Prohibition" + }, + { + "Category": "TRIALS OF THE CENTURY", + "Question": "Despite a highly controversial trial, these 2 were executed for murders in 1920 at a Mass. factory", + "Answer": "Sacco & Vanzetti" + }, + { + "Category": "LET'S GET M*A*S*Hed", + "Question": "Company clerk \"Radar\" O'Reilly was from this state", + "Answer": "Iowa" + }, + { + "Category": "VALUABLE PLACES", + "Question": "You can keep the valuable rocks you find in the state park near Murfreesboro, Arkansas: Crater of these", + "Answer": "Diamonds" + }, + { + "Category": "NAME THE AUTOMAKER", + "Question": "Protege & Millenia", + "Answer": "Mazda" + }, + { + "Category": "THEATRE HODGEPODGE", + "Question": "Big Stone Gap, Virginia is home to the outdoor drama \"Trail of the Lonesome\" this", + "Answer": "Pine" + }, + { + "Category": "\"PRO\"NOUNS", + "Question": "The working class", + "Answer": "Proletariat" + }, + { + "Category": "TRIALS OF THE CENTURY", + "Question": "Evidence of this man's guilt in a famous 1935 kidnapping case included finding ransom money at his house", + "Answer": "Bruno Hauptmann" + }, + { + "Category": "LET'S GET M*A*S*Hed", + "Question": "The colonel & lt. colonel who were the 4077th's commanding officers", + "Answer": "Lt. Col. Henry Blake & Col. Sherman Potter" + }, + { + "Category": "VALUABLE PLACES", + "Question": "During a 1992 standoff, the FBI captured white supremacist Randy Weaver at this Idaho site", + "Answer": "Ruby Ridge" + }, + { + "Category": "NAME THE AUTOMAKER", + "Question": "Corniche & Silver Shadow", + "Answer": "Rolls-Royce" + }, + { + "Category": "THEATRE HODGEPODGE", + "Question": "Shakespeare's play about this Tudor king begins, \"I come no more to make you laugh...\"", + "Answer": "Henry VIII" + }, + { + "Category": "\"PRO\"NOUNS", + "Question": "The ceremonial etiquette observed by diplomats & heads of state", + "Answer": "Protocol" + }, + { + "Category": "HEADS OF STATE", + "Question": "In July 1994 this Jordanian king signed a peace agreement with Israel's prime minister Yitzhak Rabin", + "Answer": "King Hussein" + }, + { + "Category": "MAGAZINES", + "Question": "Departments in this weekly include \"Faces in the Crowd\", \"Catching Up With...\" & \"SI View\"", + "Answer": "Sports Illustrated" + }, + { + "Category": "RHYMES WITH STONEHENGE", + "Question": "Statues of Ms. Baez, Ms. Collins & Ms. Didion are part of this monument", + "Answer": "Joanhenge" + }, + { + "Category": "QUEEN VICTORIA", + "Question": "In 1876 Victoria was delighted to receive the title \"Empress of\" this Asian land", + "Answer": "India" + }, + { + "Category": "WE ARE AMUSED", + "Question": "6-letter term for the job associated with the item seen here (medieval mask)", + "Answer": "Jester" + }, + { + "Category": "HEADS OF STATE", + "Question": "In 1976 this current president of France founded the Rally for the Republic Party", + "Answer": "Jacques Chirac" + }, + { + "Category": "MAGAZINES", + "Question": "In 1953 Triangle Publications began publishing this media magazine...& boy was it successful!", + "Answer": "TV Guide" + }, + { + "Category": "THE CAST OF THE TEN COMMANDMENTS", + "Question": "This \"Mannix\" star was known as Touch Connors when he played an Amalekite herder in the film", + "Answer": "Mike Connors" + }, + { + "Category": "RHYMES WITH STONEHENGE", + "Question": "This area with structures called \"Princess\" & \"Trimline\" may have been a communication center", + "Answer": "Phonehenge" + }, + { + "Category": "QUEEN VICTORIA", + "Question": "Britain celebrated Victoria's Golden Jubilee in 1887 & recovered in time for this jubilee in 1897", + "Answer": "Diamond" + }, + { + "Category": "WE ARE AMUSED", + "Question": "Ms. Rodham Clinton's first name comes from the same Latin root as this word meaning \"very funny\"", + "Answer": "Hilarious" + }, + { + "Category": "HEADS OF STATE", + "Question": "He was born in 1921 on the island of Java; he left office in 1998", + "Answer": "Suharto" + }, + { + "Category": "MAGAZINES", + "Question": "Conan O'Brien was the first since Robert Benchley to be president of this Harvard humor magazine 2 straight years", + "Answer": "Harvard Lampoon" + }, + { + "Category": "RHYMES WITH STONEHENGE", + "Question": "It's easy to get lost in this arrangement of genetically identical creations", + "Answer": "Clonehenge" + }, + { + "Category": "QUEEN VICTORIA", + "Question": "Victoria found this poet laureate's \"In Memoriam\" a great comfort in her widowhood", + "Answer": "Alfred Lord Tennyson" + }, + { + "Category": "WE ARE AMUSED", + "Question": "Shylock asked, \"If you prick us, do we not bleed? If you\" do this, \"do we not laugh?\"", + "Answer": "Tickle us" + }, + { + "Category": "HEADS OF STATE", + "Question": "On August 29, 1995 Eduard Shevardnadze, president of this country, was wounded by a car bomb", + "Answer": "Georgia" + }, + { + "Category": "MAGAZINES", + "Question": "In 1990, he became editor-in-chief of his late father's namesake business magazine", + "Answer": "Steve Forbes" + }, + { + "Category": "RHYMES WITH STONEHENGE", + "Question": "Head down south to see this, a plain covered with pieces of fried corn bread", + "Answer": "Ponehenge" + }, + { + "Category": "QUEEN VICTORIA", + "Question": "As seen in a 1997 film, he was Victoria's beloved servant, but we're not sure how she felt about his \"body\"", + "Answer": "John Brown" + }, + { + "Category": "WE ARE AMUSED", + "Question": "The first one was added in 1950 by the producers of NBC's \"The Hank McCune Show\"", + "Answer": "Laugh track" + }, + { + "Category": "HEADS OF STATE", + "Question": "In 1964 Luxembourg's grand duchess abdicated in favor of this man, her son", + "Answer": "Grand Duke Jean" + }, + { + "Category": "MAGAZINES", + "Question": "This man's \"Lady's Book\" was published in Philadelphia from 1830 to 1892", + "Answer": "Louis Godey" + }, + { + "Category": "RHYMES WITH STONEHENGE", + "Question": "The queen bee is missing from the center of this enclosure; only a ring of males remains", + "Answer": "Dronehenge" + }, + { + "Category": "QUEEN VICTORIA", + "Question": "Queen Victoria was said to be happiest at this \"humble\" Scottish home", + "Answer": "Balmoral Castle" + }, + { + "Category": "WE ARE AMUSED", + "Question": "As a noted joke pirate, Milton Berle was punningly known as \"The Thief of\" these", + "Answer": "Bad Gags" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "One story says this point was so named becuase it was a positive sign of a sea route from Europe to India", + "Answer": "Cape of Good Hope" + }, + { + "Category": "COLLEGES & UNIVERSITIES", + "Question": "It has the largest enrollment of any university in Utah", + "Answer": "Brigham Young" + }, + { + "Category": "SI's SIGNS OF THE APOCALYPSE", + "Question": "This tire co. paid Rip Hamilton \"to braid his hair in the tread pattern of one of its tires\", not blimps", + "Answer": "Goodyear" + }, + { + "Category": "LITERARY GENRES", + "Question": "\"Pamela\" is an epistolary one & may be the first English one", + "Answer": "a novel" + }, + { + "Category": "RECORD LOSSES IN 2005", + "Question": "A computer with 98,000 names & SSNs was reported stolen from this oldest campus of the Univ. of Calif.", + "Answer": "Berkeley" + }, + { + "Category": "SO \"LONG\"", + "Question": "A unit of distance equal to 220 yards", + "Answer": "a furlong" + }, + { + "Category": "& THANKS FOR ALL THE FISH", + "Question": "Varieties of this fish include brown, rainbow & cutthroat", + "Answer": "trout" + }, + { + "Category": "COLLEGES & UNIVERSITIES", + "Question": "In 1865 this school in Poughkeepsie became the first women's college in the U.S. to have facilities equal to the men's schools", + "Answer": "Vassar" + }, + { + "Category": "SI's SIGNS OF THE APOCALYPSE", + "Question": "A Little League team in Kentucky is sponsored by this \"delightfully tacky yet unrefined\" restaurant", + "Answer": "Hooters" + }, + { + "Category": "LITERARY GENRES", + "Question": "A villanella, an Italian song, became a villanelle, a French this", + "Answer": "a poem" + }, + { + "Category": "RECORD LOSSES IN 2005", + "Question": "Named for a sport that embodies high society, this Ralph Lauren co. was hacked for 180,000 credit card numbers", + "Answer": "Polo" + }, + { + "Category": "SO \"LONG\"", + "Question": "This arachnid is also called a harvestman", + "Answer": "a daddy long-legs" + }, + { + "Category": "COLLEGES & UNIVERSITIES", + "Question": "In 1937 this Malibu, Calif. university was established by & named for the founder of Western Auto Supply Company", + "Answer": "Pepperdine" + }, + { + "Category": "SI's SIGNS OF THE APOCALYPSE", + "Question": "This Miami Heat superstar center's \"wife, Shaunie, said their family has outgrown its 18-bedroom home\"", + "Answer": "Shaquille O'Neal" + }, + { + "Category": "LITERARY GENRES", + "Question": "The name of this literary form also means \"to try\"", + "Answer": "an essay" + }, + { + "Category": "RECORD LOSSES IN 2005", + "Question": "This company that owns HBO & Turner Broadcasting lost a backup tape with 600,000 names & SSNs", + "Answer": "Time Warner" + }, + { + "Category": "SO \"LONG\"", + "Question": "Random House says this is a \"chiefly Texas\" term for a bottle of beer", + "Answer": "a longneck" + }, + { + "Category": "& THANKS FOR ALL THE FISH", + "Question": "Pleuronectidae, one family of this fish, generally has eyes on the right side; another, Bothidae, on the left", + "Answer": "flounder" + }, + { + "Category": "COLLEGES & UNIVERSITIES", + "Question": "This Tulsa, Oklahoma school's athletic teams are called the Golden Eagles, not the Evangelists", + "Answer": "Oral Roberts University" + }, + { + "Category": "SI's SIGNS OF THE APOCALYPSE", + "Question": "\"A ski jumping competition in\" this country, Land of the Midnight Sun, \"rewarded competitors for landing in trees\"", + "Answer": "Norway" + }, + { + "Category": "LITERARY GENRES", + "Question": "The story of Gisli Sursson, or John Jakes' chronicle of the Kent family", + "Answer": "sagas" + }, + { + "Category": "RECORD LOSSES IN 2005", + "Question": "Data on 4 million customers were lost by this group formed by a 1998 merger with Travelers", + "Answer": "Citigroup" + }, + { + "Category": "SO \"LONG\"", + "Question": "12-letter term for one employed on the wharves of a port", + "Answer": "a longshoreman" + }, + { + "Category": "& THANKS FOR ALL THE FISH", + "Question": "When this fish is \"red\", it's been smoked; if \"red\" in slang, it's a misleading clue", + "Answer": "a herring" + }, + { + "Category": "COLLEGES & UNIVERSITIES", + "Question": "This West Lafayette, Indiana school's Hall of Music has seating for more than 6,000", + "Answer": "Purdue" + }, + { + "Category": "SI's SIGNS OF THE APOCALYPSE", + "Question": "\"Golfer John Daly has... endorsement deals with\" Dunkin' Donuts & this Anna Nicole Smith-endorsed diet aid", + "Answer": "TrimSpa" + }, + { + "Category": "LITERARY GENRES", + "Question": "In the 1880s Guy de Maupassant published 300 of these", + "Answer": "short stories" + }, + { + "Category": "RECORD LOSSES IN 2005", + "Question": "A medical group lost 185,000 personal & medical records in this city, the seat of Santa Clara County", + "Answer": "San Jose" + }, + { + "Category": "CANALS", + "Question": "The city of Balboa is the Pacific terminus of this 51-mile-long canal", + "Answer": "the Panama Canal" + }, + { + "Category": "NYPD TV", + "Question": "Detectives Diane Russell, Jill Kirkendall & Connie McDowell were on the job for this ABC drama", + "Answer": "NYPD Blue" + }, + { + "Category": "HIDDEN BOOKS OF THE BIBLE", + "Question": "Sending money was the best her friends could do for her", + "Answer": "Esther" + }, + { + "Category": "INDEPENDENCE DAYS", + "Question": "This country celebrates its 1945 independence from Fascism on April 25th", + "Answer": "Italy" + }, + { + "Category": "BACK IN 1906", + "Question": "Burned in 1864, this city was placed under martial law following racial tensions in September 1906", + "Answer": "Atlanta" + }, + { + "Category": "FROM THE LATIN", + "Question": "You'll often find a statue's feet atop this kind of base whose name is from the Latin for \"foot\"", + "Answer": "a pedestal" + }, + { + "Category": "CANALS", + "Question": "While in Milan in the late 15th century, this artist designed locks to join the city's canals", + "Answer": "Leonardo da Vinci" + }, + { + "Category": "NYPD TV", + "Question": "Wojo, Harris, Yemana & Fish were 12th Precinct detectives on this sitcom", + "Answer": "Barney Miller" + }, + { + "Category": "HIDDEN BOOKS OF THE BIBLE", + "Question": "Fight the evil mojo by using your good voodoo", + "Answer": "Job" + }, + { + "Category": "INDEPENDENCE DAYS", + "Question": "Though it was first settled by the French, July 1 marks its partial independence from the U.K.", + "Answer": "Canada" + }, + { + "Category": "BACK IN 1906", + "Question": "Now take this question... please! This \"King of the One Liners\" was born March 16, 1906", + "Answer": "Henny Youngman" + }, + { + "Category": "FROM THE LATIN", + "Question": "Fancy Valentines often feature this delicate fabric whose name comes from the Latin for \"to trap or snare\"", + "Answer": "lace" + }, + { + "Category": "CANALS", + "Question": "In 1825 the Seneca Chief became the first boat to traverse the length of this canal, reaching NYC on Nov. 4", + "Answer": "the Erie Canal" + }, + { + "Category": "NYPD TV", + "Question": "Max Greevey & Mike Logan were the original 2 N.Y. detectives who investigated crimes in the 1st half of this show", + "Answer": "Law & Order" + }, + { + "Category": "HIDDEN BOOKS OF THE BIBLE", + "Question": "Top chefs know that Pez rarely makes it onto the menu", + "Answer": "Ezra" + }, + { + "Category": "INDEPENDENCE DAYS", + "Question": "This Asian island nation gained independence from the U.S. in 1946 but celebrates its 1898 freedom from Spain on June 12", + "Answer": "the Philippines" + }, + { + "Category": "BACK IN 1906", + "Question": "In September the Platt Amendment was invoked, allowing U.S. intervention in this Caribbean country", + "Answer": "Cuba" + }, + { + "Category": "CANALS", + "Question": "With capital of about $40 million set in place, work was begun on this waterway in April 1859", + "Answer": "the Suez Canal" + }, + { + "Category": "NYPD TV", + "Question": "In 1982 Sharon Gless took over for Meg Foster to partner with Tyne Daily as this title pair", + "Answer": "Cagney & Lacey" + }, + { + "Category": "HIDDEN BOOKS OF THE BIBLE", + "Question": "For hungry sandwich lovers, jam ostensibly makes the peanut butter better", + "Answer": "Amos" + }, + { + "Category": "INDEPENDENCE DAYS", + "Question": "This North European country marks December 6 for its 1917 independence from Russia", + "Answer": "Finland" + }, + { + "Category": "BACK IN 1906", + "Question": "In 1906 there were 90 of these; nearly two-thirds of them were Republican", + "Answer": "senators" + }, + { + "Category": "FROM THE LATIN", + "Question": "From the Latin for \"tail\", it's the section of a musical composition that brings it to a close", + "Answer": "the coda" + }, + { + "Category": "CANALS", + "Question": "Located at Sault Ste. Marie, the St. Marys Falls Canal connects these 2 Great Lakes", + "Answer": "Lake Superior & Lake Huron" + }, + { + "Category": "NYPD TV", + "Question": "In the '70s this Taos, N.M. Deputy Marshal was on temporary assignment in Manhattan's 27th Precinct", + "Answer": "McCloud" + }, + { + "Category": "HIDDEN BOOKS OF THE BIBLE", + "Question": "From answers to questions; that's \"Jeopardy!\"", + "Answer": "Romans" + }, + { + "Category": "INDEPENDENCE DAYS", + "Question": "It was annexed by Indonesia but became independent on May 20, 2002", + "Answer": "East Timor" + }, + { + "Category": "BACK IN 1906", + "Question": "The 1906 murder of Grace Brown in New York State inspired Theodore Dreiser to write this novel", + "Answer": "An American Tragedy" + }, + { + "Category": "FROM THE LATIN", + "Question": "A fun way to get to the top of a mountain is this kind of cable railway whose name is from the Latin for \"rope\"", + "Answer": "a funicular" + }, + { + "Category": "20th CENTURY BOOKS", + "Question": "Chapter I of this book tells us: \"Worse than the ordinary miserable childhood is the miserable Irish childhood...\"", + "Answer": "Angela's Ashes" + }, + { + "Category": "NONFICTION PEOPLE", + "Question": "Stephen Ambrose looked at this president's \"Ruin and Recovery, 1973-1990\"", + "Answer": "Richard Nixon" + }, + { + "Category": "WHAT A WEEK", + "Question": "In 1958 the theme of the first national week for these places was \"Wake up & read!\"", + "Answer": "libraries" + }, + { + "Category": "THE SILVER SCREEN", + "Question": "1960 film that says \"Matricide is probably the most unbearable crime of all\", especially for \"the son who commits it\"", + "Answer": "Psycho" + }, + { + "Category": "ENGLAND, SCOTLAND OR WALES", + "Question": "The largest in area of the 3", + "Answer": "England" + }, + { + "Category": "THE TITANIC", + "Question": "Milvina Dean, who had this distinction among the 2,200 people on board, lived to see the 95th anniv. in 2007", + "Answer": "the youngest person" + }, + { + "Category": "\"TOO\" MUCH", + "Question": "Fighting ferociously, you go at it this \"& nail\"", + "Answer": "tooth" + }, + { + "Category": "NONFICTION PEOPLE", + "Question": "A biography of him is subtitled \"Man's Slave Becomes God's Scientist\"", + "Answer": "George Washington Carver" + }, + { + "Category": "WHAT A WEEK", + "Question": "This is a rough week for pledges, but if they can make it through, they can be fraternity members", + "Answer": "hell week" + }, + { + "Category": "THE SILVER SCREEN", + "Question": "Her 6-minute role as Queen Elizabeth in \"Shakespeare in Love\" was the shortest Oscar-winning role", + "Answer": "Judi Dench" + }, + { + "Category": "ENGLAND, SCOTLAND OR WALES", + "Question": "Tony Blair was born there", + "Answer": "Scotland" + }, + { + "Category": "THE TITANIC", + "Question": "The U.S. Senate inquiry noted that the 16 compartments in the Titanic's hull that supposedly were this, weren't", + "Answer": "watertight" + }, + { + "Category": "\"TOO\" MUCH", + "Question": "It's a signal at night for soldiers to go to their quarters, or an indelible pattern drawn on the skin", + "Answer": "a tattoo" + }, + { + "Category": "NONFICTION PEOPLE", + "Question": "\"The Apotheosis of\" this English navigator explores \"European Mythmaking in the Pacific\"", + "Answer": "Cook" + }, + { + "Category": "WHAT A WEEK", + "Question": "Each year, World Space Week is at the start of October, commemorating this 1957 event", + "Answer": "the Sputnik launch" + }, + { + "Category": "THE SILVER SCREEN", + "Question": "Chris O'Donnell was originally cast as her son in \"Prince of Tides\", but she chose her real son instead", + "Answer": "Barbra Streisand" + }, + { + "Category": "ENGLAND, SCOTLAND OR WALES", + "Question": "The one that is technically a principality", + "Answer": "Wales" + }, + { + "Category": "THE TITANIC", + "Question": "The Titanic carried plenty of these, 3,560, but many passengers died wearing them in the 28-degree water", + "Answer": "lifejackets" + }, + { + "Category": "\"TOO\" MUCH", + "Question": "It's a small porch on the front of the house", + "Answer": "a stoop" + }, + { + "Category": "NONFICTION PEOPLE", + "Question": "He's called a \"Rough Stone Rolling\" in a 2005 \"Cultural Biography of Mormonism's Founder\"", + "Answer": "Joseph Smith" + }, + { + "Category": "WHAT A WEEK", + "Question": "In 1999 this country began 3 \"golden weeks\" of vacation for its vast populace, including one around May Day", + "Answer": "China" + }, + { + "Category": "THE SILVER SCREEN", + "Question": "Anthony Hopkins said his voice for this movie role was \"a combination of Truman Capote and Katharine Hepburn\"", + "Answer": "Hannibal Lecter" + }, + { + "Category": "ENGLAND, SCOTLAND OR WALES", + "Question": "It has the westernmost territory", + "Answer": "Scotland" + }, + { + "Category": "THE TITANIC", + "Question": "You can still see the crane to lower these; the starboard & port ones weighed 9 tons, the center one, 17 tons", + "Answer": "anchors" + }, + { + "Category": "NONFICTION PEOPLE", + "Question": "\"The Corsican\" is a diary of his life \"In His Own Words\"", + "Answer": "Napoleon" + }, + { + "Category": "WHAT A WEEK", + "Question": "Carrie on \"Sex and the City\" really enjoyed this event that brings ships & thousands of sailors to NYC", + "Answer": "Fleet Week" + }, + { + "Category": "THE SILVER SCREEN", + "Question": "Schwarzenegger is a Soviet cop teamed with James Belushi's Chicago cop in this action movie", + "Answer": "Red Heat" + }, + { + "Category": "ENGLAND, SCOTLAND OR WALES", + "Question": "The Cambrian Mountains cover most of it", + "Answer": "Wales" + }, + { + "Category": "THE TITANIC", + "Question": "The ship was so big, communication was by telegraph from this navigating area to the engine room", + "Answer": "the bridge" + }, + { + "Category": "\"TOO\" MUCH", + "Question": "It's a string or garland of flowers hung in a curve, or to decorate with them", + "Answer": "festoon" + }, + { + "Category": "HISPANIC HISTORY", + "Question": "As president of this country, Antonio Guzman Blanco had a new capital built in Caracas", + "Answer": "Venezuela" + }, + { + "Category": "THE LAST POPE OF THIS NAME", + "Question": "There have been more popes of this name than any other, but the last, number XXIII, was more than 40 years ago", + "Answer": "John" + }, + { + "Category": "\"IBLE\"S & BITS", + "Question": "Adjective for handwriting that can actually be read, unlike my doctor's", + "Answer": "legible" + }, + { + "Category": "SCIENCE GUYS", + "Question": "His grandfather Erasmus argued in favor of evolution 60 years before he took up the cause himself", + "Answer": "Darwin" + }, + { + "Category": "FUNNY FOR NOTHIN'", + "Question": "On his first night taking over \"The Daily Show\", he informed us, \"Craig Kilborn is on assignment in Kuala Lumpur\"", + "Answer": "Jon Stewart" + }, + { + "Category": "CHICKENS FOR FREE", + "Question": "He celebrated his 86th birthday at \"21\" by having his own famous fried chicken delivered to his table in section 21", + "Answer": "Colonel Sanders" + }, + { + "Category": "HISPANIC HISTORY", + "Question": "The USA's second \"drug czar\", Bob Martinez had been governor of this state", + "Answer": "Florida" + }, + { + "Category": "THE LAST POPE OF THIS NAME", + "Question": "The VI & last pope to have this name reigned from 1963 to 1978", + "Answer": "Paul" + }, + { + "Category": "\"IBLE\"S & BITS", + "Question": "Easily duped or conned, perhaps like a seabird", + "Answer": "gullible" + }, + { + "Category": "SCIENCE GUYS", + "Question": "This astronomer was born in Pisa, Italy February 15, 1564", + "Answer": "Galileo" + }, + { + "Category": "FUNNY FOR NOTHIN'", + "Question": "A writer, on the U.S. soccer team's 4 total shots in 3 games: \"Four shots?\" This Laker \"takes that many during a timeout\"", + "Answer": "Kobe Bryant" + }, + { + "Category": "CHICKENS FOR FREE", + "Question": "In doro wat, Ethiopian chicken stew, these go in at the end of cooking, so the chicken stew comes first", + "Answer": "the eggs" + }, + { + "Category": "HISPANIC HISTORY", + "Question": "To supply Coronado's party, Hernando de Alarcon sailed 3 ships up this river in 1540 to where Yuma, Ariz. is now", + "Answer": "the Colorado" + }, + { + "Category": "THE LAST POPE OF THIS NAME", + "Question": "1878 to 1903 was the tenure of the XIII & last pope with this name that's also a sign of the Zodiac", + "Answer": "Leo" + }, + { + "Category": "\"IBLE\"S & BITS", + "Question": "You chew with it", + "Answer": "mandible" + }, + { + "Category": "SCIENCE GUYS", + "Question": "In 1920, he was named director of the Institute of Theoretical Physics in Copenhagen", + "Answer": "Bohr" + }, + { + "Category": "FUNNY FOR NOTHIN'", + "Question": "This Fox-TV cartoon boy: \"Just so you don't hear any wild rumors, I'm being indicted for fraud in Australia\"", + "Answer": "Bart Simpson" + }, + { + "Category": "CHICKENS FOR FREE", + "Question": "Chicken this \"royal\" way is served in a rich cream sauce with mushrooms, pimentos, green peppers & sherry", + "Answer": "a la king" + }, + { + "Category": "HISPANIC HISTORY", + "Question": "The dictator of Paraguay from 1816 to 1840 wasn't called just \"El Bueno\" but this superlative", + "Answer": "El Supremo" + }, + { + "Category": "THE LAST POPE OF THIS NAME", + "Question": "The XII & last pope of this name that sounds like a synonym for \"devout\" ended his 19-year reign in 1958", + "Answer": "Pius" + }, + { + "Category": "\"IBLE\"S & BITS", + "Question": "14-letter adjective for something that can't be wiped out", + "Answer": "indestructible" + }, + { + "Category": "SCIENCE GUYS", + "Question": "Until his death in 1907, this chemist headed the Weights & Measures Bureau in St. Petersburg, Russia", + "Answer": "Mendeleev" + }, + { + "Category": "FUNNY FOR NOTHIN'", + "Question": "This deadpan comic said, \"I installed a skylight in my apartment... The people who live above me are furious\"", + "Answer": "Steven Wright" + }, + { + "Category": "CHICKENS FOR FREE", + "Question": "Da, comrade-- a fork pierces the bird, launching a jet of fragrant melted butter in chicken this", + "Answer": "chicken Kiev" + }, + { + "Category": "HISPANIC HISTORY", + "Question": "Around 1829 this Mexican began calling himself the \"Napoleon of the West\"", + "Answer": "General Antonio Lopez de Santa Ana" + }, + { + "Category": "THE LAST POPE OF THIS NAME", + "Question": "He wasn't the calendar dude, but when he died in 1846, he was the XVI & last pope with this name", + "Answer": "Gregory" + }, + { + "Category": "\"IBLE\"S & BITS", + "Question": "Miller's witch-hunting play", + "Answer": "The Crucible" + }, + { + "Category": "SCIENCE GUYS", + "Question": "In 1855 Napoleon III \"swung\" a deal arranging for his appointment as physicist at the Paris Observatory", + "Answer": "Jean Foucault" + }, + { + "Category": "FUNNY FOR NOTHIN'", + "Question": "This Brit comic cross-dresser: \"Guns don't kill people, people do... but monkeys do too, if they've got a gun\"", + "Answer": "Eddie Izzard" + }, + { + "Category": "CHICKENS FOR FREE", + "Question": "A rich dish combines chicken strips, spaghetti & a sherry-parmesan cheese cream sauce in chicken this opera star", + "Answer": "chicken Tetrazzini" + }, + { + "Category": "19th CENTURY POLITICIANS", + "Question": "As Territories Committee chair, this Midwest senator helped draw the borders of 7 territories, including Kansas & Nebraska", + "Answer": "Stephen Douglas" + }, + { + "Category": "IT HAPPENED IN NOVEMBER", + "Question": "Abraham Lincoln delivered this November 19, 1863; it lasted all of 2 minutes", + "Answer": "the Gettysburg Address" + }, + { + "Category": "INSTRUMENTS OF CHANGE", + "Question": "Reed all about it: ARC INLET", + "Answer": "clarinet" + }, + { + "Category": "BOOK NAMES", + "Question": "Charles Dickens: \"Little ____\"", + "Answer": "Dorrit" + }, + { + "Category": "WHAT ARE YOU DOING?", + "Question": "Making one of these with a few people; a frame holds it taut; we'll back it with muslin & fill it with batting", + "Answer": "making a quilt" + }, + { + "Category": "COVER ME!", + "Question": "In 1965 Otis Redding took \"Respect\" to No. 35; 2 years later, her cover was No. 1", + "Answer": "Aretha Franklin" + }, + { + "Category": "I'M GOING \"INN\"", + "Question": "It's the third word in the first book of the Bible", + "Answer": "beginning" + }, + { + "Category": "IT HAPPENED IN NOVEMBER", + "Question": "18-year-old Will Shakespeare married her in November 1582; their daughter was born 6 months later", + "Answer": "Anne Hathaway" + }, + { + "Category": "INSTRUMENTS OF CHANGE", + "Question": "It's a brass wind instrument: OH OX ASPEN", + "Answer": "saxophone" + }, + { + "Category": "BOOK NAMES", + "Question": "Theodore Dreiser: \"Sister ____\"", + "Answer": "Carrie" + }, + { + "Category": "WHAT ARE YOU DOING?", + "Question": "Celebrating January 6, the Feast of this, commemorating the day the Magi arrived to honor the Christ Child", + "Answer": "the Epiphany" + }, + { + "Category": "COVER ME!", + "Question": "A No. 1 hit for The Eurythmics in 1983, \"Sweet Dreams\" was covered in '95 by this goth rocker, the former Brian Warner", + "Answer": "Marilyn Manson" + }, + { + "Category": "I'M GOING \"INN\"", + "Question": "2-word term for a tuxedo", + "Answer": "dinner jacket" + }, + { + "Category": "IT HAPPENED IN NOVEMBER", + "Question": "He stepped out of Northwest Airlines Flight 305 on November 24, 1971, & hasn't been seen since", + "Answer": "D.B. Cooper" + }, + { + "Category": "INSTRUMENTS OF CHANGE", + "Question": "Blow in & out: NO CHAIR MA", + "Answer": "harmonica" + }, + { + "Category": "BOOK NAMES", + "Question": "George Bernard Shaw: \"Major ____\"", + "Answer": "Barbara" + }, + { + "Category": "WHAT ARE YOU DOING?", + "Question": "Heading to Valparaiso, a seaport in this South American country", + "Answer": "Chile" + }, + { + "Category": "COVER ME!", + "Question": "This Van Halen frontman re-did Louis Prima's \"Just A Gigolo\" in 1985", + "Answer": "David Lee Roth" + }, + { + "Category": "I'M GOING \"INN\"", + "Question": "Another word for entrails or viscera (sorry, mealtime America)", + "Answer": "innards" + }, + { + "Category": "IT HAPPENED IN NOVEMBER", + "Question": "The start of his reign in Spain falls mainly on the 22nd of November, 1975", + "Answer": "Juan Carlos" + }, + { + "Category": "INSTRUMENTS OF CHANGE", + "Question": "Oh, it bellows: RANCID COO", + "Answer": "accordion" + }, + { + "Category": "BOOK NAMES", + "Question": "Nietzsche: \"Thus Spoke ____\"", + "Answer": "Zarathustra" + }, + { + "Category": "WHAT ARE YOU DOING?", + "Question": "Learning this Bantu language whose name comes from a word meaning \"of the coast\"", + "Answer": "Swahili" + }, + { + "Category": "COVER ME!", + "Question": "In 1979 this Sex Pistols bassist did \"My Way\", his way", + "Answer": "Sid Vicious" + }, + { + "Category": "IT HAPPENED IN NOVEMBER", + "Question": "In Nov. 1922, after years of searching, Lord Carnarvon & Howard Carter made this discovery", + "Answer": "Tutankhamen's tomb" + }, + { + "Category": "INSTRUMENTS OF CHANGE", + "Question": "Pear-shaped? Abso-lute-ly: NIL NOMAD", + "Answer": "mandolin" + }, + { + "Category": "BOOK NAMES", + "Question": "Alexander Solzhenitsyn: \"One Day in the Life of ____ ____\"", + "Answer": "Ivan Denisovich" + }, + { + "Category": "WHAT ARE YOU DOING?", + "Question": "Giving a room visual interest with this trim aka a dado rail; it protects plaster walls from the item in its name", + "Answer": "a chair rail" + }, + { + "Category": "COVER ME!", + "Question": "\"Are We Not Men? We Are\" this '80s group who covered the Stones' \"Satisfaction\"", + "Answer": "Devo" + }, + { + "Category": "I'M GOING \"INN\"", + "Question": "An indirect intimation about a person of a disparaging or derogatory nature", + "Answer": "innuendo" + }, + { + "Category": "ASIAN CAPITALS", + "Question": "Check out the Kokugikan Sumo Budokan Arena in this capital", + "Answer": "Tokyo" + }, + { + "Category": "I LOVE L.A. KERS", + "Question": "Kobe called it \"idiotic criticism\" that he hadn't (until 2009) won an NBA title without this teammate", + "Answer": "Shaquille O'Neal" + }, + { + "Category": "COOKING EQUIPMENT FOOD", + "Question": "Go to logcabinsyrups.com & you'll immediately see a stack of them", + "Answer": "pancakes" + }, + { + "Category": "INTERNATIONAL NAMES", + "Question": "As a boy Bolivia's president Evo Morales herded these pack animals", + "Answer": "llamas" + }, + { + "Category": "MYTHICAL CREATURES", + "Question": "This bird was said to embalm the ashes of its predecessor & then fly to Heliopolis", + "Answer": "the phoenix" + }, + { + "Category": "THE \"CO\"-CATEGORY", + "Question": "It's the smallest armed service of the United States", + "Answer": "the Coast Guard" + }, + { + "Category": "ASIAN CAPITALS", + "Question": "This capital lies on the north coast of West Java at the mouth of the Liwung River", + "Answer": "Jakarta" + }, + { + "Category": "I LOVE L.A. KERS", + "Question": "A wizard at passing the ball, this Laker is the NBA's all-time leader in assists per game", + "Answer": "Magic Johnson" + }, + { + "Category": "INTERNATIONAL NAMES", + "Question": "Alex Salmond, first minister of this country, wants to take it out of the United Kingdom", + "Answer": "Scotland" + }, + { + "Category": "MYTHICAL CREATURES", + "Question": "Marco Polo told us of this 3-letter bird that could carry an elephant in its claws", + "Answer": "the roc" + }, + { + "Category": "THE \"CO\"-CATEGORY", + "Question": "A Greek word for \"poppy\" gives us the name of this analgesic, an alkaloid of opium", + "Answer": "codeine" + }, + { + "Category": "ASIAN CAPITALS", + "Question": "Once the capital of the French protectorate of Tonkin, it's now the capital of an entire country", + "Answer": "Hanoi" + }, + { + "Category": "I LOVE L.A. KERS", + "Question": "This Laker giant was nicknamed \"The Big Dipper\" for his habit of dipping his head to fit through doorways", + "Answer": "Wilt Chamberlain" + }, + { + "Category": "COOKING EQUIPMENT FOOD", + "Question": "Made with cornmeal, it comes out of the oven so soft you have to eat it with the utensil in its name", + "Answer": "spoon bread" + }, + { + "Category": "INTERNATIONAL NAMES", + "Question": "4 times married, ex-German leader Gerhard Schroeder is aka Audi Man, for the car's symbol of 4 of these", + "Answer": "rings" + }, + { + "Category": "MYTHICAL CREATURES", + "Question": "The word \"panic\" comes from the name of a Greek god who was this type of creature", + "Answer": "a satyr" + }, + { + "Category": "THE \"CO\"-CATEGORY", + "Question": "It's a coop for sheep or pigeons", + "Answer": "a cote" + }, + { + "Category": "ASIAN CAPITALS", + "Question": "Inhabitants of this Armenian capital can see Mount Ararat, which is 35 miles to the south in Turkey", + "Answer": "Yerevan" + }, + { + "Category": "I LOVE L.A. KERS", + "Question": "This Hall-of-Fame guard & former Lakers GM is said to be the model for the player depicted in the NBA's logo", + "Answer": "Jerry West" + }, + { + "Category": "COOKING EQUIPMENT FOOD", + "Question": "Orville Redenbacher sells this sweet & salty treat as well as its more famous cousin", + "Answer": "kettle corn" + }, + { + "Category": "INTERNATIONAL NAMES", + "Question": "The U.N. ties of this Secretary-General date back to 1975, when he was a South Korean diplomat", + "Answer": "Ban Ki-moon" + }, + { + "Category": "MYTHICAL CREATURES", + "Question": "This winged creature sprang from the blood of Medusa after Perseus beheaded her", + "Answer": "Pegasus" + }, + { + "Category": "THE \"CO\"-CATEGORY", + "Question": "In 2009 Paul McCartney headlined this music fest near Palm Springs, California", + "Answer": "Coachella" + }, + { + "Category": "ASIAN CAPITALS", + "Question": "The name of this capital is Mongol for \"City of the Red Hero\"", + "Answer": "Ulan Bator" + }, + { + "Category": "I LOVE L.A. KERS", + "Question": "This flashy Lakers forward was nicknamed \"Big Game\" for his clutch playoff performances", + "Answer": "James Worthy" + }, + { + "Category": "COOKING EQUIPMENT FOOD", + "Question": "Bobby Flay's recipe for this includes as special equipment a rod to skewer the bird with", + "Answer": "rotisserie chicken" + }, + { + "Category": "INTERNATIONAL NAMES", + "Question": "In 2008 he succeeded his close ally Vladimir Putin as Russia's president", + "Answer": "Medvedev" + }, + { + "Category": "MYTHICAL CREATURES", + "Question": "If you know that a Kirin is the Japanese type of this mythological creature, pour yourself a beer", + "Answer": "unicorn" + }, + { + "Category": "THE \"CO\"-CATEGORY", + "Question": "It's an exclusive group or clique", + "Answer": "a coterie" + }, + { + "Category": "PRESIDENTIAL ELECTIONS", + "Question": "He was the last sitting president to run for re-election & finish third in the Electoral College", + "Answer": "William Howard Taft" + }, + { + "Category": "A DICKENSIAN NIGHTMARE", + "Question": "The prospect of an endless lawsuit winding through generations leaves a \"bleak\" vision", + "Answer": "Bleak House" + }, + { + "Category": "UNIVERSITY SPORTS TEAMS", + "Question": "While Harvard has the Crimson, this university has the Crimson Tide", + "Answer": "Alabama" + }, + { + "Category": "\"GENERAL\" JOB INFORMATION", + "Question": "Alberto Gonzales & Robert F. Kennedy both held this cabinet position", + "Answer": "Attorney General" + }, + { + "Category": "BATTLE TO NAME THE WAR", + "Question": "The Battle of Stalingrad", + "Answer": "World War II" + }, + { + "Category": "MAGAZINE FEATURES", + "Question": "Leading Off, Faces in the Crowd, Scorecard", + "Answer": "Sports Illustrated" + }, + { + "Category": "3-LETTER ABBREV.", + "Question": "Everyone has one: POV", + "Answer": "a point of view" + }, + { + "Category": "A DICKENSIAN NIGHTMARE", + "Question": "That wedding gown, that faded gown--I cannot get it, or poor Miss Havisham, out of my head", + "Answer": "Great Expectations" + }, + { + "Category": "UNIVERSITY SPORTS TEAMS", + "Question": "Penn State's teams, they were named partly for a mountain & partly for a creature that could defeat Princeton's Tigers", + "Answer": "the Nittany Lions" + }, + { + "Category": "\"GENERAL\" JOB INFORMATION", + "Question": "In 1775 the Continental Congress appointed man of letters Benjamin Franklin to this job", + "Answer": "postmaster general" + }, + { + "Category": "BATTLE TO NAME THE WAR", + "Question": "Quang Tri City; the cavalry was sent!", + "Answer": "the Vietnam War" + }, + { + "Category": "MAGAZINE FEATURES", + "Question": "Goings on About Town, The Talk of the Town, The Critics", + "Answer": "The New Yorker" + }, + { + "Category": "3-LETTER ABBREV.", + "Question": "On some forms & applications: DOB", + "Answer": "date of birth" + }, + { + "Category": "A DICKENSIAN NIGHTMARE", + "Question": "Bill was mean to his dog, Bull's Eye, then he killed Nancy... & so, I ran, but he kept gaining on me...", + "Answer": "Oliver Twist" + }, + { + "Category": "UNIVERSITY SPORTS TEAMS", + "Question": "You could say these athletes at UNLV aren't \"without a cause\"", + "Answer": "theRebels" + }, + { + "Category": "\"GENERAL\" JOB INFORMATION", + "Question": "It's the rank just below (the very model of a modern) major general", + "Answer": "brigadier general" + }, + { + "Category": "BATTLE TO NAME THE WAR", + "Question": "Quebec &, a year later, Trenton", + "Answer": "the Revolutionary War" + }, + { + "Category": "MAGAZINE FEATURES", + "Question": "Agenda, Fairground, Fanfair", + "Answer": "Vanity Fair" + }, + { + "Category": "3-LETTER ABBREV.", + "Question": "A religious group: LDS", + "Answer": "Latter Day Saints" + }, + { + "Category": "A DICKENSIAN NIGHTMARE", + "Question": "Oh no, it's the cruel headmaster of Salem House, Mr. Creakle, & his peg leg buddy, Tungay--will this never end?!", + "Answer": "David Copperfield" + }, + { + "Category": "\"GENERAL\" JOB INFORMATION", + "Question": "The U.N.'s website says this job is \"a spokesman for the interests of the world's peoples, in particular the poor\"", + "Answer": "the Secretary-General" + }, + { + "Category": "BATTLE TO NAME THE WAR", + "Question": "No one enjoyed the portions at Pork Chop Hill", + "Answer": "the Korean War" + }, + { + "Category": "MAGAZINE FEATURES", + "Question": "Star Tracks, Scoop, Chatter", + "Answer": "People" + }, + { + "Category": "3-LETTER ABBREV.", + "Question": "For tax purposes, the total amount you earned less deductions: AGI", + "Answer": "adjusted gross income" + }, + { + "Category": "A DICKENSIAN NIGHTMARE", + "Question": "It's no \"mystery\" why John Jasper haunts me--his fingers have knives on them!", + "Answer": "The Mystery of Edwin Drood" + }, + { + "Category": "UNIVERSITY SPORTS TEAMS", + "Question": "They're the sports teams of Fresno State as well as Georgia", + "Answer": "the Bulldogs" + }, + { + "Category": "\"GENERAL\" JOB INFORMATION", + "Question": "In 1870 Congress created this position to direct the Marine Hospital Service", + "Answer": "the Surgeon General" + }, + { + "Category": "BATTLE TO NAME THE WAR", + "Question": "Let me take you down, 'cause we're going to... Bosworth Field", + "Answer": "the War of the Roses" + }, + { + "Category": "MAGAZINE FEATURES", + "Question": "Your Shot, Where in the World?, Visions of Earth", + "Answer": "National Geographic" + }, + { + "Category": "3-LETTER ABBREV.", + "Question": "Organization founded by Carrie Chapman Catt in 1920: LWV", + "Answer": "the League of Women Voters" + }, + { + "Category": "PHILMOGRAPHIES", + "Question": "\"Jingle All the Way\", \"So I Married an Axe Murderer\" (plus 153 episodes of \"SNL\")", + "Answer": "Phil Hartman" + }, + { + "Category": "ARTISTS' RETREATS", + "Question": "\"Ariel\", \"Portnoy's Complaint\" & this 1969 mob novel were all written partly in Yaddo in Upstate N.Y.", + "Answer": "The Godfather" + }, + { + "Category": "GET SMART", + "Question": "Choline may help adult brains grow; one of these breakfast items has about a third of your RDA--want an omelette?", + "Answer": "an egg" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Instead of counties, this state has boroughs (or is it brrr-oughs?)", + "Answer": "Alaska" + }, + { + "Category": "\"CH\"ILL OUT!", + "Question": "15th century Pope Innocent VIII \"The Honest\" was the first pope to publicly admit having these", + "Answer": "children" + }, + { + "Category": "BIBLICAL PEOPLE & PLACES", + "Question": "Ezra was the leader of the Jews who returned from this land, by whose waters they had sat down & wept", + "Answer": "Babylon" + }, + { + "Category": "PHILMOGRAPHIES", + "Question": "\"A Funny Thing Happened on the Way to the Forum\", \"It's a Mad Mad Mad Mad World\" (plus his own 1955-59 TV show)", + "Answer": "Phil Silvers" + }, + { + "Category": "ARTISTS' RETREATS", + "Question": "Proceeds from \"Who's Afraid of Virginia Woolf?\" helped him start a residency program on Long Island", + "Answer": "Edward Albee" + }, + { + "Category": "GET SMART", + "Question": "A study of 3,500 Japanese men's brains found those who did this in moderation aged better than those who didn't", + "Answer": "drank alcohol" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "This state capital is located on the Merrimack River about 15 miles north of Manchester", + "Answer": "Concord" + }, + { + "Category": "\"CH\"ILL OUT!", + "Question": "The Battle of Missionary Ridge was a chief encounter of the 1863 battle of this southeastern city", + "Answer": "Chattanooga" + }, + { + "Category": "PHILMOGRAPHIES", + "Question": "\"Buster\", \"Hook\", \"The Genesis Concert Movie\"", + "Answer": "Phil Collins" + }, + { + "Category": "ARTISTS' RETREATS", + "Question": "The patronage of Mabel Dodge Luhan made an artists' magnet of this town 55 miles from Santa Fe", + "Answer": "Taos, New Mexico" + }, + { + "Category": "GET SMART", + "Question": "A Boston study found doing this for 40 minutes a day builds up the cerebral cortex; monks must be really smart!", + "Answer": "meditate" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Tributaries of this Mississippi tributary include the Cheyenne, James & Platte", + "Answer": "the Missouri" + }, + { + "Category": "\"CH\"ILL OUT!", + "Question": "The Chinese call these kuaizi", + "Answer": "chopsticks" + }, + { + "Category": "BIBLICAL PEOPLE & PLACES", + "Question": "It was the wealthiest Greek city in Paul's time; he founded a church there & wrote 2 letters to its Christians", + "Answer": "Corinth" + }, + { + "Category": "PHILMOGRAPHIES", + "Question": "\"Doubt\", \"Capote\"", + "Answer": "Philip Seymour Hoffman" + }, + { + "Category": "ARTISTS' RETREATS", + "Question": "The colony bearing this single name features a barn poet Edna built from a Sears kit", + "Answer": "Millay" + }, + { + "Category": "GET SMART", + "Question": "Excess weight can interfere with this hormone, raising risk of diabetes & impairing brain function--so hit the gym, Einstein", + "Answer": "insulin" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "The Houston ship channel flows into this bay that shares its name with a city", + "Answer": "Galveston Bay" + }, + { + "Category": "\"CH\"ILL OUT!", + "Question": "Don't squawk if you're accused of having illegible handwriting, aka this", + "Answer": "chicken scratches" + }, + { + "Category": "PHILMOGRAPHIES", + "Question": "As a director: \"The Right Stuff\", \"Invasion of the Body Snatchers\"", + "Answer": "Philip Kaufman" + }, + { + "Category": "ARTISTS' RETREATS", + "Question": "Around 1912, 2 painters from the Art Institute of this city founded the Ox-Bow Institute in Saugatuck, Mich.", + "Answer": "Chicago" + }, + { + "Category": "GET SMART", + "Question": "A U. of California study found that listening to the too many notes in this guy's sonatas raised IQ scores 8-9 points", + "Answer": "Mozart" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "This N.C. peak, the highest east of the Mississippi, was named for the man who surveyed it, died on it & is buried at the top", + "Answer": "Mt. Mitchell" + }, + { + "Category": "\"CH\"ILL OUT!", + "Question": "Specific 5-letter term for the block of wood you wedge under the wheels when jacking up a car", + "Answer": "chock" + }, + { + "Category": "INFLUENTIAL 19th CENTURY THINKERS", + "Question": "At the University of Bonn in 1836, he was wounded in a duel with a member of an aristocratic Prussian fraternity", + "Answer": "Karl Marx" + }, + { + "Category": "STATE OF THE UNION", + "Question": "The Jack Daniel's distillery is in Lynchburg in this state", + "Answer": "Tennessee" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Willis's Snapples and Cran-apples", + "Answer": "Bruce's juices" + }, + { + "Category": "NORM!", + "Question": "The dad of this First Gulf War general was a N.J. State Police bigwig & worked the Lindbergh kidnapping case", + "Answer": "Schwarzkopf" + }, + { + "Category": "iPOD, YOUTUBE OR WII", + "Question": "It was introduced as a way to \"put 1,000 songs in your pocket\"", + "Answer": "iPod" + }, + { + "Category": "ALL ASHORE FOR BIRD LORE", + "Question": "Lions don't like to attack ostriches because the big birds do this & can even kill the king of beasts this way", + "Answer": "kick" + }, + { + "Category": "THE ENGLISH TOP 100", + "Question": "It's No. 1, & no, you don't get a hint", + "Answer": "the" + }, + { + "Category": "STATE OF THE UNION", + "Question": "When Jimi Hendrix played \"The Star-Spangled Banner\" at Woodstock, he was strumming in this state", + "Answer": "New York" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Ashton's meat sellers", + "Answer": "Kutcher's butchers" + }, + { + "Category": "iPOD, YOUTUBE OR WII", + "Question": "There are websites devoted to injuries suffered by its users, such as pulled muscles & bloodied hands", + "Answer": "Wii" + }, + { + "Category": "ALL ASHORE FOR BIRD LORE", + "Question": "This forward from French Lick, Indiana was NBA MVP 3 times in the 1980s", + "Answer": "Larry Bird" + }, + { + "Category": "THE ENGLISH TOP 100", + "Question": "This No. 30 must be obeyed", + "Answer": "she" + }, + { + "Category": "STATE OF THE UNION", + "Question": "The Trinity site in this state was the location of the USA's first atomic explosion", + "Answer": "New Mexico" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Cattrall's rooms for hot, sweaty workouts", + "Answer": "Kim's gyms" + }, + { + "Category": "NORM!", + "Question": "In 1981 this \"All in the Family\" producer co-founded People for the American Way", + "Answer": "Norman Lear" + }, + { + "Category": "iPOD, YOUTUBE OR WII", + "Question": "This has been banned in Thailand, Turkey, Pakistan & Iran", + "Answer": "YouTube" + }, + { + "Category": "ALL ASHORE FOR BIRD LORE", + "Question": "This bird term for pro-war politicians was popular in the period leading up to the War of 1812", + "Answer": "hawks" + }, + { + "Category": "THE ENGLISH TOP 100", + "Question": "Self-congratulations, egotists! This word made it all the way to No. 10", + "Answer": "I" + }, + { + "Category": "STATE OF THE UNION", + "Question": "The Tennis Hall of Fame in Newport is in this state", + "Answer": "Rhode Island" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Amanda's avenues", + "Answer": "Peet's streets" + }, + { + "Category": "NORM!", + "Question": "Think positively! You'll know this man who wrote the newspaper column \"Confident Living\"", + "Answer": "Peale" + }, + { + "Category": "iPOD, YOUTUBE OR WII", + "Question": "Its name was reportedly inspired by a line from \"2001: A Space Odyssey\"", + "Answer": "iPod" + }, + { + "Category": "ALL ASHORE FOR BIRD LORE", + "Question": "It's the color in the name of New Hampshire's state bird, a finch, & a state flower, a lilac", + "Answer": "purple" + }, + { + "Category": "THE ENGLISH TOP 100", + "Question": "No. 2, this verb form is a homophone of a letter of the alphabet", + "Answer": "be" + }, + { + "Category": "STATE OF THE UNION", + "Question": "\"Where The Columbines Grow\" is its official state song", + "Answer": "Colorado" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Lauer's chiropterans", + "Answer": "Matt's bats" + }, + { + "Category": "NORM!", + "Question": "1968 \"The Armies of the Night\" won him a Pulitzer & the National Book Award", + "Answer": "Norman Mailer" + }, + { + "Category": "iPOD, YOUTUBE OR WII", + "Question": "Britain's Prince William got one last Christmas & Queen Elizabeth promptly commandeered it", + "Answer": "Wii" + }, + { + "Category": "ALL ASHORE FOR BIRD LORE", + "Question": "Like its relative the peacock, the Argus type of this bird has \"eyes\" in its elaborate tail feathers", + "Answer": "the pheasant" + }, + { + "Category": "THE ENGLISH TOP 100", + "Question": "Title of the Beatles song that tells us \"life is very short\"--5 words: Nos. 27, 53, 87, 11, 43", + "Answer": "\"We Can Work It Out\"" + }, + { + "Category": "BRASS", + "Question": "In 1989 this son of Jamaican immigrants became Chairman of the Joint Chiefs of Staff", + "Answer": "Powell" + }, + { + "Category": "STRINGS", + "Question": "When this product was introduced in 1972, it was said to have a full \"quarter mile\" of fun shot out of a can", + "Answer": "Silly String" + }, + { + "Category": "WOOD & WIND", + "Question": "This author wrote of Fangorn Forest, named for the oldest of the Ents-or was the Ent named for the forest?", + "Answer": "Tolkien" + }, + { + "Category": "\"PER\"CUSSION", + "Question": "A type of fish, or to sit on an elevated platform", + "Answer": "perch" + }, + { + "Category": "CONDUCTORS", + "Question": "The Lone Ranger could tell you this precious metal is the best conductor of electricity among metals", + "Answer": "silver" + }, + { + "Category": "SYMPHONIES ON FILM", + "Question": "The Philadelphia Orchestra played Beethoven's \"Pastoral Symphony\" for this 1940 Disney film", + "Answer": "Fantasia" + }, + { + "Category": "BRASS", + "Question": "If you don't know he was made commander of the 2nd Armored Tank Division in April 1941, I'll slap you silly", + "Answer": "Patton" + }, + { + "Category": "STRINGS", + "Question": "In the 1630s it was a backup bow & arrow part; today it means backup on a sports team", + "Answer": "second string" + }, + { + "Category": "WOOD & WIND", + "Question": "In this Herman Wouk tale, Pug Henry is an advisor to FDR prior to the attack on Pearl Harbor", + "Answer": "The Winds of War" + }, + { + "Category": "SYMPHONIES ON FILM", + "Question": "This Russian director's Mexico footage was compiled as \"Mexican Symphony\" in 1941", + "Answer": "Eisenstein" + }, + { + "Category": "BRASS", + "Question": "We shall return to this man who graduated from West Point in 1903 with the highest honors in his class", + "Answer": "Doug MacArthur" + }, + { + "Category": "STRINGS", + "Question": "To make this candy, put a string in a glass of sugar & water that was boiled to a syrup & let stand for a week", + "Answer": "rock candy" + }, + { + "Category": "WOOD & WIND", + "Question": "His play \"Under Milk Wood\", about the inhabitants of a Welsh seaside town, was published posthumously", + "Answer": "Dylan Thomas" + }, + { + "Category": "\"PER\"CUSSION", + "Question": "Russian for \"rebuilding\", this term was first used by Gorbachev in the mid-1980s", + "Answer": "perestroika" + }, + { + "Category": "CONDUCTORS", + "Question": "Unlike most nonmetals, this element with the symbol B is a workable conductor", + "Answer": "boron" + }, + { + "Category": "SYMPHONIES ON FILM", + "Question": "In 1998's \"Serengeti Symphony\", the title nature reserve in this country is shown with only music & natural sound", + "Answer": "Tanzania" + }, + { + "Category": "BRASS", + "Question": "A 10-man, 22-ton \"infantry fighting vehicle\" named for this general has a 2-man turret & a 25mm cannon", + "Answer": "Bradley" + }, + { + "Category": "STRINGS", + "Question": "According to Bud Collins' \"Encyclopedia of Modern Tennis\", the best of this string material comes from cows", + "Answer": "gut" + }, + { + "Category": "WOOD & WIND", + "Question": "The line \"O wild west wind, thou breath of autumn's being\" starts an 1819 ode by this man", + "Answer": "Percy Shelley" + }, + { + "Category": "\"PER\"CUSSION", + "Question": "This daughter of Zeus & Demeter made regular trips to Hades", + "Answer": "Persephone" + }, + { + "Category": "CONDUCTORS", + "Question": "It's the term for material that conducts at high temperatures & insulates at low temperatures", + "Answer": "a semiconductor" + }, + { + "Category": "BRASS", + "Question": "In 1864 Democrats nominated this Union general for president, though he repudiated their platform", + "Answer": "George McClellan" + }, + { + "Category": "STRINGS", + "Question": "The hope behind String Theory is that it will result in this, sometimes shortened to \"T.O.E.\"", + "Answer": "the theory of everything" + }, + { + "Category": "WOOD & WIND", + "Question": "This Frost poem ends with \"And miles to go before I sleep, And miles to go before I sleep\"", + "Answer": "\"Stopping by Woods on a Snowy Evening\"" + }, + { + "Category": "\"PER\"CUSSION", + "Question": "11-letter word for the sac containing the heart", + "Answer": "pericardium" + }, + { + "Category": "SYMPHONIES ON FILM", + "Question": "The 1934 drama \"The Unfinished Symphony\" was director Anthony Asquith's tribute to this Austrian composer", + "Answer": "Shubert" + }, + { + "Category": "HISTORIC PROPERTY TRANSACTIONS", + "Question": "On May 15, 1768 France bought this island from Genoa for 2 million livres", + "Answer": "Corsica" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Of Hawaii's 8 main islands, this one receives the lion's share of the tourist dollars", + "Answer": "Oahu" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Cash, Depp", + "Answer": "Johnny" + }, + { + "Category": "NOVELS", + "Question": "The 1719 1st edition told of him \"having been cast on shore by shipwreck, wherein all... men perished but himself\"", + "Answer": "Robinson Crusoe" + }, + { + "Category": "BRIGHT IDEAS", + "Question": "Edwin Budding adapted a rotary shearer used to remove excess fibers from carpets into this outdoor tool", + "Answer": "the lawnmower" + }, + { + "Category": "TEENS IN HISTORY", + "Question": "In 1468 this teen was recognized as heiress to the throne of Castile", + "Answer": "Queen Isabella" + }, + { + "Category": "RHYME TIME", + "Question": "An intelligent beginning", + "Answer": "a smart start" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "When the Russians owned Alaska, they referred to this tall peak as Bolshaya Gora", + "Answer": "Mt. McKinley" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Bakula, Wolf", + "Answer": "Scott" + }, + { + "Category": "NOVELS", + "Question": "Even the epilogue is lengthy in this 1869 Tolstoy epic; it comes out in 2 parts &, in our copy, is 105 pages long", + "Answer": "War and Peace" + }, + { + "Category": "BRIGHT IDEAS", + "Question": "In 1948 scientists at Bristol-Meyers \"buffered\" this medicine for the first time", + "Answer": "aspirin" + }, + { + "Category": "TEENS IN HISTORY", + "Question": "She was a teenage farm girl when she beat the famous marksman Frank Butler in an 1870s shooting match", + "Answer": "Annie Oakley" + }, + { + "Category": "RHYME TIME", + "Question": "A more obese baseball slugger", + "Answer": "a fatter batter" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "This river begins in Colorado & empties into the Gulf of Mexico near Brownsville, Texas", + "Answer": "Rio Grande" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Carey, Bledsoe", + "Answer": "Drew" + }, + { + "Category": "NOVELS", + "Question": "This 1939 Steinbeck novel helped publicize the plight of Dust Bowl refugees", + "Answer": "The Grapes of Wrath" + }, + { + "Category": "BRIGHT IDEAS", + "Question": "Lawrence Sperry used the gyroscope his dad developed in this device that keeps planes on course without human aid", + "Answer": "autopilot" + }, + { + "Category": "TEENS IN HISTORY", + "Question": "In the 1850s this future sculptor failed the Ecole des Beaux-Arts entrance exam 3 times (think about it)", + "Answer": "Rodin" + }, + { + "Category": "RHYME TIME", + "Question": "A wealthy sorceress", + "Answer": "a rich witch" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Florida's panhandle borders these 2 states", + "Answer": "Alabama and Georgia" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Lillard, Modine", + "Answer": "Matthew" + }, + { + "Category": "NOVELS", + "Question": "Chapter 10 of this 1960 novel begins, \"Atticus was feeble: he was nearly fifty\"", + "Answer": "To Kill a Mockingbird" + }, + { + "Category": "BRIGHT IDEAS", + "Question": "In 1882 Schuyler Wheeler put a propellor on the shaft of an electric motor & created this--how cool!", + "Answer": "a fan" + }, + { + "Category": "TEENS IN HISTORY", + "Question": "Betrothed as a teen to her creepy cousin in 1744, she later became a \"Great\" empress of Russia", + "Answer": "Catherine the Great" + }, + { + "Category": "RHYME TIME", + "Question": "Written text of a movie about an underground burial chamber", + "Answer": "a crypt script" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "This large lake on the New York-Vermont border is Vermont's lowest point", + "Answer": "Lake Champlain" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Connelly, Garner, Holliday", + "Answer": "Jennifer" + }, + { + "Category": "NOVELS", + "Question": "Published in 1949, this futuristic tale is set in Oceania, a few years before you were born", + "Answer": "1984" + }, + { + "Category": "BRIGHT IDEAS", + "Question": "James Fergason invented this type of \"display\" that found an early use in calculators", + "Answer": "LCD" + }, + { + "Category": "TEENS IN HISTORY", + "Question": "Apprenticed to a British shipowner as a teen in the 1740s, he became one of the great explorers of the Pacific", + "Answer": "Captain Cook" + }, + { + "Category": "RHYME TIME", + "Question": "Voraciously eat an \"all-purpose\" baking ingredient", + "Answer": "devour flour" + }, + { + "Category": "CONSTITUTIONAL AMENDMENTS", + "Question": "Of particular interest to the NRA is the amendment that allows us \"to keep & bear\" these", + "Answer": "arms" + }, + { + "Category": "SPORTS OF THE FEMALE OLYMPIANS", + "Question": "Mia Hamm, Brandi Chastain & their 9 teammates on the field", + "Answer": "soccer" + }, + { + "Category": "LOW CUT GENES", + "Question": "Because they develop from a single ovum, this variety of twins has the same genetic makeup", + "Answer": "identical" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This math term comes from the Latin frangere, \"to break\"", + "Answer": "fraction" + }, + { + "Category": "FINE DINING", + "Question": "A Vacherin dessert features this crisp concoction of beaten egg whites & sugar", + "Answer": "meringue" + }, + { + "Category": "TAKE OUT", + "Question": "It's the common operation to remove 2 small oval masses of tissue at the back of the mouth", + "Answer": "a tonsillectomy" + }, + { + "Category": "CONSTITUTIONAL AMENDMENTS", + "Question": "Under the 5th Amendment, 1 of the 3 things that no person shall be deprived of \"without due process of law\"", + "Answer": "life" + }, + { + "Category": "SPORTS OF THE FEMALE OLYMPIANS", + "Question": "Sheryl Swoopes, Lisa Leslie & their 3 teammates on the floor", + "Answer": "basketball" + }, + { + "Category": "LOW CUT GENES", + "Question": "Genes that affect hereditary traits are called alleles & are either \"dominant\" or this", + "Answer": "recessive" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This synonym for \"room\" can precede music & maid", + "Answer": "chamber" + }, + { + "Category": "FINE DINING", + "Question": "NYC sushi chef Masa Takayama has paid more than $120 a pound for this fish--a bit pricier than Star-Kist's", + "Answer": "tuna" + }, + { + "Category": "TAKE OUT", + "Question": "A rhytidectomy removes these surgically; botox takes them out another way", + "Answer": "wrinkles" + }, + { + "Category": "CONSTITUTIONAL AMENDMENTS", + "Question": "The 13th Amendment, which abolished slavery, was ratified in this year", + "Answer": "1865" + }, + { + "Category": "SPORTS OF THE FEMALE OLYMPIANS", + "Question": "Misty May & Kerri Walsh", + "Answer": "beach volleyball" + }, + { + "Category": "LOW CUT GENES", + "Question": "Since the 1980s this hormone used by diabetics has been produced by genetically engineered bacteria", + "Answer": "insulin" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "The name of this 6-pointed star comes from the Greek for \"six\" & \"letter\"", + "Answer": "a hexagram" + }, + { + "Category": "FINE DINING", + "Question": "This word for a French stew is pronounced the same as a pasta sauce brand", + "Answer": "ragout" + }, + { + "Category": "TAKE OUT", + "Question": "A lobectomy removes one of the 5 lobes of the lungs; a lobotomy takes out part of this organ", + "Answer": "the brain" + }, + { + "Category": "CONSTITUTIONAL AMENDMENTS", + "Question": "The 24th Amendment says you don't have to pay this type of tax, or any other in order to vote", + "Answer": "poll" + }, + { + "Category": "SPORTS OF THE FEMALE OLYMPIANS", + "Question": "Mohini Bhardwaj, Courtney Kupets & their 4 teammates", + "Answer": "gymnastics" + }, + { + "Category": "LOW CUT GENES", + "Question": "A pair of chromosomes with this 2-letter designation makes a woman a woman", + "Answer": "XX" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "The name of this African equine comes from the Portuguese for \"wild ass\"", + "Answer": "a zebra" + }, + { + "Category": "FINE DINING", + "Question": "A company at Union Wharf in Portland ships all kinds of seafood, but is called \"Maine\" this creature \"Direct\"", + "Answer": "Lobster" + }, + { + "Category": "TAKE OUT", + "Question": "A keratotomy is an incision of this eye part; a keratectomy removes part of it", + "Answer": "the cornea" + }, + { + "Category": "CONSTITUTIONAL AMENDMENTS", + "Question": "Decade when the 27th & last amendment, having to do with pay raises in Congress, took effect", + "Answer": "the 1990s" + }, + { + "Category": "SPORTS OF THE FEMALE OLYMPIANS", + "Question": "Lisa Fernandez, Jennie Finch & their 7 teammates on the field", + "Answer": "softball" + }, + { + "Category": "LOW CUT GENES", + "Question": "Named for a German neuropathologist, this memory loss disease may be caused by a gene on chromosome 21", + "Answer": "Alzheimer's disease" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This cutting implement has the same name as a type of dive & a kind of trailer-truck accident", + "Answer": "a jackknife" + }, + { + "Category": "FINE DINING", + "Question": "En croute, as in salmon en croute, is French for \"in\" this, also found on toast", + "Answer": "crust" + }, + { + "Category": "TAKE OUT", + "Question": "The embolus removed from an artery in an embolectomy is usually one of these obstructions", + "Answer": "aclot" + }, + { + "Category": "MOUNTAINS", + "Question": "To trek through its Khumbu Icefall, Lhotse Face & South Col, your team needs a $70,000 permit from Nepal's government", + "Answer": "Mount Everest" + }, + { + "Category": "COMMON BONDS", + "Question": "Fife, Rubble, Miller", + "Answer": "Barney" + }, + { + "Category": "SIMPLE SCIENCE", + "Question": "State of matter a substance is in after it's gone through evaporation", + "Answer": "gaseous" + }, + { + "Category": "ROCK MUSIC", + "Question": "In April of 1990 she began her worldwide \"Blond Ambition\" tour to promote her CD \"I'm Breathless\"", + "Answer": "Madonna" + }, + { + "Category": "AT THE BUILDING SITE", + "Question": "He's got the building wired for \"current\" affairs", + "Answer": "an electrician" + }, + { + "Category": "HEY, GOOD-LOOKIN'", + "Question": "A 4-legged one may be a vixen; a 2-legged one may be a vixen, too", + "Answer": "a fox" + }, + { + "Category": "WHAT'CHA GOT COOKIN'?", + "Question": "I'm boiling these to mix with red cabbage; it's too darn hot to roast them on an open fire", + "Answer": "chestnuts" + }, + { + "Category": "COMMON BONDS", + "Question": "Foehn, Zephyr, Simoom", + "Answer": "winds" + }, + { + "Category": "SIMPLE SCIENCE", + "Question": "Number of sides on a honeycomb cell or on a snowflake", + "Answer": "6" + }, + { + "Category": "ROCK MUSIC", + "Question": "His \"Doggystyle\" CD was the first debut album ever to enter the Billboard charts at No. 1", + "Answer": "Snoop Doggy Dogg" + }, + { + "Category": "AT THE BUILDING SITE", + "Question": "The current affairs this person deals with are labelled H & C", + "Answer": "the plumber" + }, + { + "Category": "HEY, GOOD-LOOKIN'", + "Question": "In a 1979 film, Dudley Moore gives her a rating of 11 on a scale of 1-10", + "Answer": "Bo Derek" + }, + { + "Category": "WHAT'CHA GOT COOKIN'?", + "Question": "Don't be intimidated by the skewers; I'll use them on the marinated lamb to make this", + "Answer": "shish kabob" + }, + { + "Category": "COMMON BONDS", + "Question": "Shirt, kite, donkey", + "Answer": "tails" + }, + { + "Category": "SIMPLE SCIENCE", + "Question": "We wouldn't fib, your fibula runs parallel with this bone", + "Answer": "your tibia" + }, + { + "Category": "AT THE BUILDING SITE", + "Question": "A Fats Waller is a pianist & this \"waller\" is an installer of plasterboard", + "Answer": "a drywaller" + }, + { + "Category": "HEY, GOOD-LOOKIN'", + "Question": "In boxing, it's when you've fallen & you can't get up", + "Answer": "a knockout" + }, + { + "Category": "WHAT'CHA GOT COOKIN'?", + "Question": "I'm making passover breakfast fun by using this unleavened bread in a version of French toast", + "Answer": "matzah" + }, + { + "Category": "COMMON BONDS", + "Question": "Roofs, halos, quantum mechanics", + "Answer": "things that are over my head" + }, + { + "Category": "SIMPLE SCIENCE", + "Question": "A poison in pure form, this element used as a germicide on cuts has a chemical symbol that's a pronoun", + "Answer": "iodine" + }, + { + "Category": "ROCK MUSIC", + "Question": "This Seattle grunge band backed Neil Young on his \"Mirror Ball\" CD", + "Answer": "Pearl Jam" + }, + { + "Category": "AT THE BUILDING SITE", + "Question": "He'll get you stoned or brickworked, & maybe even teach you a secret handshake", + "Answer": "a mason" + }, + { + "Category": "HEY, GOOD-LOOKIN'", + "Question": "Psalm 8 declares, \"Out of the mouth of\" these \"and sucklings hast thou ordained strength\"", + "Answer": "babes" + }, + { + "Category": "WHAT'CHA GOT COOKIN'?", + "Question": "I'm sauteeing this organ meat in butter & lemon juice, as you'd know, if you had any", + "Answer": "brains" + }, + { + "Category": "SIMPLE SCIENCE", + "Question": "French mathematician who devised the plotting system that uses coordinates named for him", + "Answer": "Rene Descartes" + }, + { + "Category": "ROCK MUSIC", + "Question": "He recorded his 1982 hit album, \"Nebraska\", as a series of demos on a 4-track machine at home", + "Answer": "Bruce Springsteen" + }, + { + "Category": "AT THE BUILDING SITE", + "Question": "A teacher could handle this, the moving of earth to form a smooth surface for a roadway", + "Answer": "a grader" + }, + { + "Category": "HEY, GOOD-LOOKIN'", + "Question": "An explosive device, a stunning revelation, or a stunning blonde", + "Answer": "a bombshell" + }, + { + "Category": "WHAT'CHA GOT COOKIN'?", + "Question": "This clear meat soup will be finished in a jiffy; actually, \"finished\" is what its name means", + "Answer": "a consommé" + }, + { + "Category": "LITERARY HOUSES", + "Question": "Harry Angstrom's house burns to the ground in this author's 1971 novel \"Rabbit Redux\"", + "Answer": "Updike" + }, + { + "Category": "THE MAINE ATTRACTION", + "Question": "Summer is the time for Whatever Week, a celebration of the Kennebec River in this state capital", + "Answer": "Augusta" + }, + { + "Category": "ACTRESSES", + "Question": "Ralph Macchio's love interest in \"The Karate Kid\", she took a darker turn in \"Leaving Las Vegas\"", + "Answer": "Elisabeth Shue" + }, + { + "Category": "CROSSWORD CLUES \"M\"", + "Question": "Diamond deposit; it ain't yours! (4)", + "Answer": "mine" + }, + { + "Category": "IT'S GREEK MYTHOLOGY TO ME", + "Question": "Menelaus not only wanted this wife back, but the treasure Paris stole along with her", + "Answer": "Helen" + }, + { + "Category": "TAKE A GUESS", + "Question": "Gwilym is the Welsh form of this name that's been popular in England for centuries", + "Answer": "William" + }, + { + "Category": "LITERARY HOUSES", + "Question": "In this Anne Tyler novel, a travel writer breaks his leg & moves into his siblings' home", + "Answer": "The Accidental Tourist" + }, + { + "Category": "THE MAINE ATTRACTION", + "Question": "Parson's Way, a scenic walkway in Kennebunkport, passes near this former president's home, Walker's Point", + "Answer": "Bush" + }, + { + "Category": "ACTRESSES", + "Question": "Her first name honors the playwriting partner of Russel Crouse, her father", + "Answer": "Lindsey Crouse" + }, + { + "Category": "CROSSWORD CLUES \"M\"", + "Question": "When it's \"praying\", it's preying (6)", + "Answer": "mantis" + }, + { + "Category": "IT'S GREEK MYTHOLOGY TO ME", + "Question": "This god zapped Salmoneus into oblivion for trying to imitate his thunder & lightning", + "Answer": "Zeus" + }, + { + "Category": "TAKE A GUESS", + "Question": "John David Joyce set a Guinness record by doing this continuously in a hammock for 240 hours", + "Answer": "rocking" + }, + { + "Category": "THE MAINE ATTRACTION", + "Question": "Maine is so famous for these berries that the town of Machias honors them with a festival", + "Answer": "blueberries" + }, + { + "Category": "ACTRESSES", + "Question": "Tamara Dobson fought drugs as \"Cleopatra Jones\" in 1973, 10 years after this woman was \"Cleopatra\"", + "Answer": "Liz Taylor" + }, + { + "Category": "CROSSWORD CLUES \"M\"", + "Question": "Actor Fredric's month (5)", + "Answer": "March" + }, + { + "Category": "IT'S GREEK MYTHOLOGY TO ME", + "Question": "This war god wasn't too successful in battle; he was once captured & stuck in a jar for 13 months", + "Answer": "Ares" + }, + { + "Category": "TAKE A GUESS", + "Question": "Of a pogo stick injury, a dense winter fog or the bite of a comic strip possum, what a pogonip is", + "Answer": "a dense winter fog" + }, + { + "Category": "LITERARY HOUSES", + "Question": "In the novel by Isabel Allende, Clara del Valle Trueba shares a house with these title entities", + "Answer": "the Spirits" + }, + { + "Category": "THE MAINE ATTRACTION", + "Question": "A national wildlife refuge near Kittery is named for this biologist who wrote \"Silent Spring\"", + "Answer": "Rachel Carson" + }, + { + "Category": "ACTRESSES", + "Question": "This star brought \"Beaches\" & \"For the Boys\" to the screen through her All Girl Productions", + "Answer": "Bette Midler" + }, + { + "Category": "CROSSWORD CLUES \"M\"", + "Question": "Stubborn slippers (5)", + "Answer": "mules" + }, + { + "Category": "IT'S GREEK MYTHOLOGY TO ME", + "Question": "This underworld kingpin had a helmet that made him invisible; after all, his name means \"the unseen\"", + "Answer": "Hades" + }, + { + "Category": "TAKE A GUESS", + "Question": "2 of the 4 actors who earned 1974 Oscar nominations for \"The Godfather Part II\"; one of them won", + "Answer": "Robert De Niro, Al Pacino, Michael V. Gazzo, & Lee Strasberg" + }, + { + "Category": "LITERARY HOUSES", + "Question": "In this novel by John Kennedy Toole, Ignatius J. Reilly lives with his mother in her New Orleans home", + "Answer": "The Confederacy of Dunces" + }, + { + "Category": "THE MAINE ATTRACTION", + "Question": "It's the only National Park in all of New England", + "Answer": "Acadia" + }, + { + "Category": "CROSSWORD CLUES \"M\"", + "Question": "Eggplant entree, in Greece (6)", + "Answer": "musaka" + }, + { + "Category": "IT'S GREEK MYTHOLOGY TO ME", + "Question": "Atalanta excelled in this blood sport of which Artemis was goddess", + "Answer": "hunting" + }, + { + "Category": "TAKE A GUESS", + "Question": "Armenia is bordered by this other \"A\" country on the East & on the Southwest", + "Answer": "Azerbaijan" + }, + { + "Category": "ASIA", + "Question": "19th century novelist Jose Rizal was a hero of this country's independence movement", + "Answer": "the Philippines" + }, + { + "Category": "FARAWAY PLACES", + "Question": "This large African desert is home to 2 million people, about as many as Utah", + "Answer": "Sahara" + }, + { + "Category": "BIRDS! BIRDS! BIRDS!", + "Question": "It loves to swim, but this bird seen here is one of the few that do not fly", + "Answer": "Penguin" + }, + { + "Category": "CANDY & GUM SLOGANS", + "Question": "\"Gimme a Break, Gimme a Break, Break Me Off a Piece\" of this candy bar", + "Answer": "Kit Kat" + }, + { + "Category": "THOSE WACKY GERMANS", + "Question": "Gesundheit, meaning \"health\", is what Germans say instead of \"bless you\" when you do this", + "Answer": "Sneeze" + }, + { + "Category": "CARTOONS", + "Question": "On Saturday morning, this Disney hero attends Prometheus Academy", + "Answer": "Hercules" + }, + { + "Category": "THE \"X\" FILES", + "Question": "A shortened form of Christmas is spelled this way", + "Answer": "Xmas" + }, + { + "Category": "FARAWAY PLACES", + "Question": "This land that's north of England has odd place names lile Loch Lochy & Loch Oich", + "Answer": "Scotland" + }, + { + "Category": "BIRDS! BIRDS! BIRDS!", + "Question": "Seen here, the great horned type of this bird is found from Alaska to South America", + "Answer": "Owl" + }, + { + "Category": "CANDY & GUM SLOGANS", + "Question": "\"The Milk Chocolate Melts in Your Mouth -- not in Your Hand\"", + "Answer": "M&M's" + }, + { + "Category": "THOSE WACKY GERMANS", + "Question": "The food many Germans like best is wurst, which are these hot-dog-shaped meat treats", + "Answer": "Sausages" + }, + { + "Category": "CARTOONS", + "Question": "The monster seen here (Godzilla) originally appeared in movies from this country", + "Answer": "Japan" + }, + { + "Category": "THE \"X\" FILES", + "Question": "High-energy radiation used to take a picture of your insides", + "Answer": "X-rays" + }, + { + "Category": "FARAWAY PLACES", + "Question": "The Forbidden City is at the heart of this capital of China, also called Peking", + "Answer": "Beijing" + }, + { + "Category": "BIRDS! BIRDS! BIRDS!", + "Question": "The largest bird in the world, this one, seen here, is also the fastest on land", + "Answer": "Ostrich" + }, + { + "Category": "CANDY & GUM SLOGANS", + "Question": "\"The Great American Chocolate Bar\"", + "Answer": "Hershey's" + }, + { + "Category": "THOSE WACKY GERMANS", + "Question": "Germans decorate Christmas trees with silvery strings & call it the \"hair\" of these heavenly beings", + "Answer": "Angels" + }, + { + "Category": "CARTOONS", + "Question": "This \"Funnie\" middle school student got his first movie in March 1999", + "Answer": "Doug" + }, + { + "Category": "THE \"X\" FILES", + "Question": "Breastplated \"Warrior Princess\" played by Lucy Lawless", + "Answer": "Xena" + }, + { + "Category": "FARAWAY PLACES", + "Question": "To get from Africa to Arabia, you cross (or part) this sea that has a colorful name", + "Answer": "Red Sea" + }, + { + "Category": "BIRDS! BIRDS! BIRDS!", + "Question": "The colorful macaw variety of this bird is seen here", + "Answer": "Parrot" + }, + { + "Category": "CANDY & GUM SLOGANS", + "Question": "\"4 Out of 5 Dentists Surveyed Recommend Sugarless Gum for their Patients who Chew Gum\"", + "Answer": "Trident" + }, + { + "Category": "THOSE WACKY GERMANS", + "Question": "From 1949 to 1990 Germany was split into 2 countries, which were called this", + "Answer": "East & West Germany" + }, + { + "Category": "CARTOONS", + "Question": "Ms. Frizzle, a science teacher, drives this title vehicle", + "Answer": "The Magic School Bus" + }, + { + "Category": "THE \"X\" FILES", + "Question": "A percussion instrument played with small mallets", + "Answer": "Xylophone" + }, + { + "Category": "FARAWAY PLACES", + "Question": "In 1999 all of Nunavut became a territory in this country, the second largest in area in the world", + "Answer": "Canada" + }, + { + "Category": "BIRDS! BIRDS! BIRDS!", + "Question": "A national symbol, this endangered bird has been making a comeback in recent years", + "Answer": "Bald eagle" + }, + { + "Category": "CANDY & GUM SLOGANS", + "Question": "\"Packed with Peanuts\", it \"Really Satisfies\"", + "Answer": "Snickers" + }, + { + "Category": "THOSE WACKY GERMANS", + "Question": "A rathaus isn't as bad as it sounds: it's this \"hall\" where the mayor might work", + "Answer": "City hall" + }, + { + "Category": "CARTOONS", + "Question": "Bubbles, Blossom & Buttercup make up this group devoted to \"Saving the Day Before Bedtime\"", + "Answer": "The Powerpuff Girls" + }, + { + "Category": "THE \"X\" FILES", + "Question": "A trademarked name, it's often used as a synonym for a photocopy", + "Answer": "Xerox" + }, + { + "Category": "THE CIVIL WAR", + "Question": "On April 12, 1861 Confederate general Beauregard attacked this fort in Charleston Harbor", + "Answer": "Fort Sumter" + }, + { + "Category": "LANGUAGES", + "Question": "Romanian developed from this language of the ancient Romans", + "Answer": "Latin" + }, + { + "Category": "NURSERY RHYMES", + "Question": "Simple Simon met him \"going to the fair\"", + "Answer": "A pieman" + }, + { + "Category": "ARE WE THERE YET?", + "Question": "Take a trolley to tour the National Cathedral, Georgetown & the Smithsonian in this city", + "Answer": "Washington, D.C." + }, + { + "Category": "CLASSICAL MUSIC", + "Question": "This German composer's 5th Symphony in C Minor has a famous opening", + "Answer": "Ludwig van Beethoven" + }, + { + "Category": "WHOSE IS IT?", + "Question": "2 by 2 the animals were put on this \"ark\"", + "Answer": "Noah's Ark" + }, + { + "Category": "THE CIVIL WAR", + "Question": "In his second inaugural address, he said about slavery, \"All know that this...was, somehow, the cause of the war\"", + "Answer": "Abraham Lincoln" + }, + { + "Category": "LANGUAGES", + "Question": "Athenians speak the Attic dialect of this language", + "Answer": "Greek" + }, + { + "Category": "NURSERY RHYMES", + "Question": "One little pig \"went to market\"; one little pig \"stayed at home\"; one little pig ate this meat", + "Answer": "Roast beef" + }, + { + "Category": "ARE WE THERE YET?", + "Question": "A theme park in Brainerd, Minnesota welcomes you with a 26-foot-tall statue of this lumberjack", + "Answer": "Paul Bunyan" + }, + { + "Category": "CLASSICAL MUSIC", + "Question": "Escamillo is a toreador in \"Carmen\", an opera set in this European country", + "Answer": "Spain" + }, + { + "Category": "WHOSE IS IT?", + "Question": "This \"apple\" is at the front of men's throats", + "Answer": "Adam's apple" + }, + { + "Category": "THE CIVIL WAR", + "Question": "The greatest battle fought in the Western Hemisphere has the \"address\" of this small Pennsylvania town", + "Answer": "Gettysburg" + }, + { + "Category": "LANGUAGES", + "Question": "Most of the classes in Quebec schools are taught in this language", + "Answer": "French" + }, + { + "Category": "NURSERY RHYMES", + "Question": "Did you ever see such a thing in your life? The farmer's wife cut off their tails \"with a carving knife\"", + "Answer": "Three Blind Mice" + }, + { + "Category": "ARE WE THERE YET?", + "Question": "Start early; the 4 presidents sculpted on this mountain are best viewed in morning light", + "Answer": "Mount Rushmore" + }, + { + "Category": "CLASSICAL MUSIC", + "Question": "The music of this Tchaikovsky \"Suite\" comes from his 1892 ballet, popular at Christmas", + "Answer": "\"The Nutcracker\"" + }, + { + "Category": "WHOSE IS IT?", + "Question": "Ben Franklin used a pen name to publish this almanac from 1732 to 1757", + "Answer": "Poor Richard's Almanack" + }, + { + "Category": "THE CIVIL WAR", + "Question": "When this general accepted Robert E. Lee's surrender at Appomattox, he was wearing a mud-splattered private's coat", + "Answer": "Ulysses S. Grant" + }, + { + "Category": "LANGUAGES", + "Question": "Javanese is the native language of about 60 million people on the island of Java in this country", + "Answer": "Indonesia" + }, + { + "Category": "NURSERY RHYMES", + "Question": "\"Hey Diddle, Diddle!\" After the little dog laughed, these 2 things ran off together", + "Answer": "Dish & spoon" + }, + { + "Category": "ARE WE THERE YET?", + "Question": "The Congress Street Bridge is where Bostonians recreate this historic event every December", + "Answer": "Boston Tea Party" + }, + { + "Category": "CLASSICAL MUSIC", + "Question": "Prokofiev wrote a famous orchestra piece called \"Peter and\" this animal", + "Answer": "The wolf" + }, + { + "Category": "WHOSE IS IT?", + "Question": "The Battle of the Little Bighorn, won by the Sioux, also has this \"final\" name", + "Answer": "Custer's Last Stand" + }, + { + "Category": "THE CIVIL WAR", + "Question": "In February 1861 6 Southern states founded the Confederate States of America & elected him president", + "Answer": "Jefferson Davis" + }, + { + "Category": "LANGUAGES", + "Question": "Most of the people of Brazil speak this official language", + "Answer": "Portuguese" + }, + { + "Category": "NURSERY RHYMES", + "Question": "It's what Peter, Peter ate; later he kept his wife in the shell of one", + "Answer": "Pumpkin" + }, + { + "Category": "ARE WE THERE YET?", + "Question": "This oldest national park has entrances in Wyoming & Montana", + "Answer": "Yellowstone" + }, + { + "Category": "CLASSICAL MUSIC", + "Question": "This Austrian child prodigy began composing minuets when he was only 5", + "Answer": "Wolfgang Amadeus Mozart" + }, + { + "Category": "WHOSE IS IT?", + "Question": "This \"heel\" is named for thr only place a famous Greek warrior could be wounded", + "Answer": "Achilles' heel" + }, + { + "Category": "EMPIRES", + "Question": "In the early 1800s, this man's empire included the duchy of Warsaw, the kingdom of Naples & Spain", + "Answer": "Napoleon" + }, + { + "Category": "A SHAKESPEARE PLAY, FOR OPENERS", + "Question": "This play opens on the battlements of the castle at Elsinore as Barnardo asks, \"who's there?\"", + "Answer": "Hamlet" + }, + { + "Category": "THAT'S BUSINESS", + "Question": "He started a book business from his home in 1873; his son William joined forces with G. Clifford Noble in 1917", + "Answer": "Barnes" + }, + { + "Category": "NURSERY RHYMES", + "Question": "Peter, Peter was an eater of this; he kept his wife in its shell", + "Answer": "pumpkin" + }, + { + "Category": "INLETS", + "Question": "This largest Alaskan city lies at the head of cook inlet on the Kenai peninsula", + "Answer": "Anchorage" + }, + { + "Category": "THE EVOLUTION OF \"M\"USIC", + "Question": "This '60s \"Nights in White Satin\" band has another color in its name", + "Answer": "Moody Blues" + }, + { + "Category": "FOREIGN", + "Question": "In Portuguese, domingo is this day of the week", + "Answer": "Sunday" + }, + { + "Category": "A SHAKESPEARE PLAY, FOR OPENERS", + "Question": "\"Othello\" opens with Roderigo addressing this villain: \"Tush, never tell me; I take it much unkindly\"", + "Answer": "Iago" + }, + { + "Category": "THAT'S BUSINESS", + "Question": "In 1997 Tyco International moved to this U.K. territory in the Atlantic for tax purposes", + "Answer": "Bermuda" + }, + { + "Category": "NURSERY RHYMES", + "Question": "\"I had a little hobby-horse and it was dapple gray; its head was made of pea-straw, its tail was made of\" this", + "Answer": "hay" + }, + { + "Category": "INLETS", + "Question": "Big ships must pass through Admiralty Inlet to enter or leave this Washington State sound", + "Answer": "Puget Sound" + }, + { + "Category": "THE EVOLUTION OF \"M\"USIC", + "Question": "1974's \"Mandy\" was his first Top 40 hit--& it reached No.1", + "Answer": "Barry Manilow" + }, + { + "Category": "FOREIGN", + "Question": "In French, l'oiseau is this; it sports les plumes", + "Answer": "a bird" + }, + { + "Category": "A SHAKESPEARE PLAY, FOR OPENERS", + "Question": "The chorus of \"Romeo & Juliet\" tells us it's in this city \"where we lay our scene\"", + "Answer": "Verona" + }, + { + "Category": "THAT'S BUSINESS", + "Question": "An Italian clothier is known as the United Colors of this", + "Answer": "Benetton" + }, + { + "Category": "NURSERY RHYMES", + "Question": "In a counting nursery rhyme, they were \"a-courting\", \"in the kitchen\" & \"a-waiting\"", + "Answer": "maids" + }, + { + "Category": "INLETS", + "Question": "Faxa Bay in the North Atlantic is between this country's Snaefells & Reykjanes peninsulas", + "Answer": "Iceland" + }, + { + "Category": "THE EVOLUTION OF \"M\"USIC", + "Question": "This singer of \"Jack & Diane\" had to fight to record under his own name", + "Answer": "John Mellencamp" + }, + { + "Category": "FOREIGN", + "Question": "If Popeye spoke Hebrew he'd ask for tered, this", + "Answer": "spinach" + }, + { + "Category": "A SHAKESPEARE PLAY, FOR OPENERS", + "Question": "Completes the opening sentence \"Now is the winter of our discontent made glorious summer by this sun of...\"", + "Answer": "York" + }, + { + "Category": "THAT'S BUSINESS", + "Question": "In 1851 this company started using a logo with a man in the moon & 13 stars; now it uses its initials", + "Answer": "Proctor & Gamble" + }, + { + "Category": "NURSERY RHYMES", + "Question": "While \"January brings the snow\", \"may brings flocks of pretty\" these, \"skipping by their fleecy dams\"", + "Answer": "lambs" + }, + { + "Category": "INLETS", + "Question": "This Chilean city whose name means \"valley of paradise\" lies on a wide inlet of the Pacific", + "Answer": "Valparaiso" + }, + { + "Category": "THE EVOLUTION OF \"M\"USIC", + "Question": "In the '90s it was \"Enter Sandman\" with this group", + "Answer": "Metallica" + }, + { + "Category": "FOREIGN", + "Question": "Tredici is Italian for this symbol of bad luck", + "Answer": "thirteen" + }, + { + "Category": "A SHAKESPEARE PLAY, FOR OPENERS", + "Question": "This play opens most dramatically with thunder & lightning. A ship is seen. Then a cry of \"bos'n!\"", + "Answer": "The Tempest" + }, + { + "Category": "THAT'S BUSINESS", + "Question": "In 1927 this brand name first appeared on a Sears washing machine", + "Answer": "Kenmore" + }, + { + "Category": "NURSERY RHYMES", + "Question": "\"Here we go round\" this bush \"on a cold and frosty morning\"", + "Answer": "the mulberry bush" + }, + { + "Category": "INLETS", + "Question": "North Carolina's Albemarle Sound is no deeper than 25 feet & is protected from the Atlantic by this island chain", + "Answer": "the Outer Banks" + }, + { + "Category": "THE EVOLUTION OF \"M\"USIC", + "Question": "In the 2000s \"Makes Me Wonder\" got this group noticed", + "Answer": "Maroon 5" + }, + { + "Category": "FOREIGN", + "Question": "In German, berg is this topographical feature on a map", + "Answer": "a mountain" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In December 1974 this former New York governor was sworn in as Vice President", + "Answer": "Rockefeller" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "If you can't stand the heat, there's always this raw dish that includes onions, capers, egg yolks & beef tenderloin", + "Answer": "steak tartare" + }, + { + "Category": "WEAPONS OF WORLD WAR II", + "Question": "The British A22 Mark IV tank carried a 75-millimeter gun & this prime minister's name", + "Answer": "Churchill" + }, + { + "Category": "THE LIVING PLANET", + "Question": "Able to lift 850 times its own weight, the strongest animal is the rhinoceros type of this insect", + "Answer": "beetle" + }, + { + "Category": "ACTING PRESIDENTS ON TV", + "Question": "Blair Underwood as President Elias Martinez", + "Answer": "The Event" + }, + { + "Category": "4 N", + "Question": "Number of \"beers on the wall\" at the beginning of the song", + "Answer": "ninety-nine" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1951 he told a joint session of congress that he \"tried to do his duty as god gave him the light to see that duty\"", + "Answer": "McArthur" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "A New England boiled dinner is traditionally made with this cured deli meat", + "Answer": "corned beef" + }, + { + "Category": "WEAPONS OF WORLD WAR II", + "Question": "Ships in the U.S. Navy's Casablanca class of \"escort\" these were smaller than their big cousins like the Lexington", + "Answer": "aircraft carriers" + }, + { + "Category": "ACTING PRESIDENTS ON TV", + "Question": "Dennis Haysbert & D.B. Woodside as David & Wayne Palmer, respectively", + "Answer": "24" + }, + { + "Category": "4 N", + "Question": "\"U\" know it means not deliberate; I'm sorry, that slip of the tongue was completely this", + "Answer": "unintentional" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "This political party founded around 1789 stood for a strong central government", + "Answer": "the Federalists" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "A New York steak is also known as this alliterative steak", + "Answer": "strip steak" + }, + { + "Category": "WEAPONS OF WORLD WAR II", + "Question": "Today, this Japanese car company makes the galant; in WWII, it was better known for its A6M \"Zero\" fighter", + "Answer": "Mitsubishi" + }, + { + "Category": "THE LIVING PLANET", + "Question": "Relative to the size of the bird, this flightless New Zealand denizen has the largest egg", + "Answer": "the kiwi" + }, + { + "Category": "ACTING PRESIDENTS ON TV", + "Question": "Fred Armisen as Barack Obama", + "Answer": "Saturday Night Live" + }, + { + "Category": "4 N", + "Question": "It's the church festival on March 25 commemorating what Gabriel told Mary", + "Answer": "the annunciation" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "His foes said that in 1877 he agreed to withdraw remaining federal troops from the south in return for electoral support", + "Answer": "Hayes" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "The second word in the French name of this boneless steak means \"dainty\"", + "Answer": "filet mignon" + }, + { + "Category": "WEAPONS OF WORLD WAR II", + "Question": "It was the alphanumeric designation of the U.S. Army's Garand rifle", + "Answer": "the M1" + }, + { + "Category": "ACTING PRESIDENTS ON TV", + "Question": "On Fox, Patricia Wettig as Caroline Reynolds", + "Answer": "Prison Break" + }, + { + "Category": "4 N", + "Question": "Adjective preceding the railroad completed in 1869", + "Answer": "transcontinental" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1917 the U.S. purchased the islands of St. Croix, St. John & St. Thomas from this country for $25 million", + "Answer": "Denmark" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "To make this dish, beef is topped with pate de foie gras & a mushroom paste before it's wrapped in pastry & cooked", + "Answer": "beef Wellington" + }, + { + "Category": "WEAPONS OF WORLD WAR II", + "Question": "\"Hefty\" nickname of the second & last atomic bomb used during the war", + "Answer": "Fat Man" + }, + { + "Category": "THE LIVING PLANET", + "Question": "The April 2009 issue of Science magazine reported that cows were the first livestock animal to have this \"mapped\"", + "Answer": "their genome" + }, + { + "Category": "ACTING PRESIDENTS ON TV", + "Question": "Mary McDonnell as Laura Roslin", + "Answer": "Battlestar Galactica" + }, + { + "Category": "4 N", + "Question": "Inopportune or untimely, like the title \"woman\" in a Dominick Dunne novel", + "Answer": "inconvenient" + }, + { + "Category": "SPORTS & THE MOVIES", + "Question": "When asked for a home address in \"The Blues Bros.\" Elwood gives 1060 W. Addison St., the home of this facility", + "Answer": "Wrigley Field" + }, + { + "Category": "WARNER BROS.", + "Question": "In May 1999 her Warners talk show was hit with a $2.5 million judgment after one guest killed another", + "Answer": "Jenny Jones" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1791 this Treasury Secretary issued his \"Report On Manufactures\", a critique of American industry", + "Answer": "Alexander Hamilton" + }, + { + "Category": "MORTAL MATTERS", + "Question": "In NYC June 14, 1999 it was \"Dead Man Riding\", as it took hours to notice a passenger on one of these wasn't just sleeping", + "Answer": "Subway" + }, + { + "Category": "BIRDS", + "Question": "Only the adelie & emperor species of this bird actually breed in Antarctica", + "Answer": "Penguin" + }, + { + "Category": "LEVITICUS", + "Question": "This tribe that gives the book its English name is only mentioned in one passage", + "Answer": "Levites" + }, + { + "Category": "AUTHORS' RHYME TIME", + "Question": "Sir Walter's saucepans", + "Answer": "Scott's pots" + }, + { + "Category": "WARNER BROS.", + "Question": "You can tour the Warner Bros. lot online, or in person in this San Fernando Valley city", + "Answer": "Burbank" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "When West Virginia became a state in 1863, Wheeling was its capital; this city became the permanent capital in 1885", + "Answer": "Charleston" + }, + { + "Category": "MORTAL MATTERS", + "Question": "Willie, the animal Wiarton, Canada used for this celebration, died Jan. 31, 1999, 2 days before his next appearance", + "Answer": "Groundhog Day" + }, + { + "Category": "BIRDS", + "Question": "This bird seen here is the provincial bird of Prince Edward Island", + "Answer": "Blue jay" + }, + { + "Category": "LEVITICUS", + "Question": "God bans mean pranks in 19:14, \"Thou shalt not... put a stumbling block before\" these people", + "Answer": "The blind" + }, + { + "Category": "AUTHORS' RHYME TIME", + "Question": "Stoker's sheeplings", + "Answer": "Bram's lambs" + }, + { + "Category": "WARNER BROS.", + "Question": "Former mortuary entrepreneur Steve Ross negotiated Warners' 1989 merger with this publisher", + "Answer": "Time" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1698, after an absence of 15 years, he returned to the colony named for his father", + "Answer": "William Penn" + }, + { + "Category": "MORTAL MATTERS", + "Question": "When Dallas sent out this annual tax form to 13,000 city employees, it marked them dead", + "Answer": "W-2" + }, + { + "Category": "BIRDS", + "Question": "The racing homer breed of this domestic bird was developed in Belgium, the traditional home of the sport", + "Answer": "Pigeon" + }, + { + "Category": "LEVITICUS", + "Question": "Chapters 4, 6, 8 & 12 begin, \"And the Lord spake unto\" him", + "Answer": "Moses" + }, + { + "Category": "AUTHORS' RHYME TIME", + "Question": "Spillane's love-bites", + "Answer": "Mickey's hickeys" + }, + { + "Category": "WARNER BROS.", + "Question": "Movies found their voice in this 1927 Warner Bros. film", + "Answer": "The Jazz Singer" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "On Aug. 2, 1826 at Boston's Faneuil Hall, this great orator delivered a eulogy on Jefferson & Adams", + "Answer": "Daniel Webster" + }, + { + "Category": "MORTAL MATTERS", + "Question": "This saint's remains were in a box atop a wardrobe for 6 years before being redisplayed February 14, 1999", + "Answer": "Saint Valentine" + }, + { + "Category": "BIRDS", + "Question": "In captivitiy, these wading birds are fed carotenoid pigments to keep the plumage color they have in the wild", + "Answer": "Flamingo" + }, + { + "Category": "AUTHORS' RHYME TIME", + "Question": "Anne's bad habits", + "Answer": "Rice's vices" + }, + { + "Category": "WARNER BROS.", + "Question": "He outlasted his brothers Sam, Albert & Harry in the company, finally selling out in 1967", + "Answer": "Jack Warner" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "Completed in 1856, California's first railroad ran 22 miles between Sacramento & this prison city", + "Answer": "Folsom" + }, + { + "Category": "MORTAL MATTERS", + "Question": "In 1961 Hassan II was crowned in this country after his father died following a minor nose operation", + "Answer": "Morocco" + }, + { + "Category": "BIRDS", + "Question": "Also known as a duck hawk, it has been clocked at 175 miles per hour during a dive", + "Answer": "Peregrine falcon" + }, + { + "Category": "AUTHORS' RHYME TIME", + "Question": "Julia Ward's female swine", + "Answer": "Howe's sows;23456" + }, + { + "Category": "THE \"W.B.\"", + "Question": "It's worn by a novice in judo or karate", + "Answer": "White belt" + }, + { + "Category": "AFRICAN ISLANDS", + "Question": "Uganda's Sese Islands lie in the northern part of this large lake", + "Answer": "Lake Victoria" + }, + { + "Category": "BILLS & WILLS", + "Question": "Born in Fabens, Texas in 1931, this legendary jockey won his first of 8,833 races at age 18", + "Answer": "Willie Shoemaker" + }, + { + "Category": "U.S. COLLEGES", + "Question": "The Wren Building at this school named for 2 monarchs is the oldest U.S. academic building still in use", + "Answer": "William and Mary" + }, + { + "Category": "CLASSICAL GASES", + "Question": "The most common isotope of hydrogen has an atomic weight of this whole number", + "Answer": "1" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "In 1999 her \"Faith\" CD reached triple platinum status", + "Answer": "Faith Hill" + }, + { + "Category": "THE \"W.B.\"", + "Question": "In a 1969 film this title group included William Holden & Warren Oates", + "Answer": "The Wild Bunch" + }, + { + "Category": "AFRICAN ISLANDS", + "Question": "Parts of this capital city lie on the islands of Gezira & Roda in the Nile River", + "Answer": "Cairo" + }, + { + "Category": "BILLS & WILLS", + "Question": "Playing center for the Boston Celtics, he led the team to 11 NBA championships in the '50s & '60s", + "Answer": "Bill Russell" + }, + { + "Category": "CLASSICAL GASES", + "Question": "Discovered separately in the 1770s by British & Swedish chemists, it was found to be a gas by a Frenchman", + "Answer": "Oxygen" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "[Well hey everybody, I'm Naomi Judd] In mid-1984 Wynonna & I made our first ever concert appearance at Ak-Sar-Ben, a large concert hall in this Nebraska city", + "Answer": "Omaha" + }, + { + "Category": "AFRICAN ISLANDS", + "Question": "Now a part of Tanzania, this island known for its cloves was mentioned in \"The Patty Duke Show\" theme song", + "Answer": "Zanzibar" + }, + { + "Category": "BILLS & WILLS", + "Question": "This outlaw of the Old West also went by the name Henry McCarty", + "Answer": "Billy the Kid" + }, + { + "Category": "CLASSICAL GASES", + "Question": "As a liquid, it's used as a cryogenic refrigerant; as a gas, it makes lights red", + "Answer": "Neon" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "\"Strawberry Wine\" was the first of 3 No. 1 hits from this debut album by Deana Carter", + "Answer": "\"Did I Shave My Legs for This?\"" + }, + { + "Category": "AFRICAN ISLANDS", + "Question": "Malagasy, 1 of its 2 official languages, is of Indonesian origin", + "Answer": "Madagascar" + }, + { + "Category": "BILLS & WILLS", + "Question": "This perennial Democratic nominee also served as Woodrow Wilson's Secretary of State", + "Answer": "William Jennings Bryan" + }, + { + "Category": "U.S. COLLEGES", + "Question": "The student newspaper of this Hanover, N.H. school calls itself \"America's Oldest College Newspaper\"", + "Answer": "Dartmouth" + }, + { + "Category": "CLASSICAL GASES", + "Question": "Lighter than air, it's also called marsh gas & is found in natural gas", + "Answer": "Methane" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "This performer became an Opry member in 1991, the same year his \"When I Call Your Name\" album went platinum", + "Answer": "Vince Gill" + }, + { + "Category": "AFRICAN ISLANDS", + "Question": "Wine production is a chief industry of this Portuguese island off Africa's northwest coast", + "Answer": "Madeira" + }, + { + "Category": "BILLS & WILLS", + "Question": "Before hosting his TV \"Journal\", he was deputy director of the Peace Corps", + "Answer": "Bill Moyers" + }, + { + "Category": "U.S. COLLEGES", + "Question": "Swarthmore College of Pennsylvania has a historical library devoted to this religious group that founded it", + "Answer": "Quakers" + }, + { + "Category": "CLASSICAL GASES", + "Question": "This gas forms tiny bubbles in a diver's bloodstream that can be dangerous if he ascends too quickly", + "Answer": "Nitrogen" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "In 1990 Jukebox named this Randy Travis cover of a Brook Benton hit the Country Record of the Year", + "Answer": "\"It's Just A Matter of Time\"" + }, + { + "Category": "FICTION", + "Question": "This 1937 mystery was written at the Old Cataract Hotel in Aswan", + "Answer": "\\\"Death on the Nile\\\"" + }, + { + "Category": "SHIPS", + "Question": "This ship, Columbus' flagship., was originally called the Marigalanti", + "Answer": "Santa Maria" + }, + { + "Category": "FOOD FACTS", + "Question": "Bread is eaten so widely it's often called the \"staff of\" this", + "Answer": "life" + }, + { + "Category": "KING ARTHUR", + "Question": "Shortly after birth, Arthur was given to this wizard for safekeeping", + "Answer": "Merlin" + }, + { + "Category": "NATURE", + "Question": "Some of the fanciest of these reptiles are beaded, horned, or frilled", + "Answer": "lizards" + }, + { + "Category": "MISC.", + "Question": "This waterfall is separated into the American Falls & Horseshoe Falls by Goat Island", + "Answer": "Niagara Falls" + }, + { + "Category": "\"KEY\"s", + "Question": "It's Pennsylvania's nickname", + "Answer": "the Keystone state" + }, + { + "Category": "SHIPS", + "Question": "Neither this admiral nor his flagship, the Trinidad, completed the circumnavigation of the globe", + "Answer": "Magellan" + }, + { + "Category": "FOOD FACTS", + "Question": "The \"pearl\" type of this is served as a vegetable or pickled & used as a condiment", + "Answer": "an onion" + }, + { + "Category": "KING ARTHUR", + "Question": "Arthur's round table had a seat reserved for this knight who could find this", + "Answer": "the Holy Grail" + }, + { + "Category": "NATURE", + "Question": "The AKC could tell that Afghans & Salukis belong to this dog group", + "Answer": "hounds" + }, + { + "Category": "MISC.", + "Question": "Before applying to become a naturalized U.S. citizen, a resident alien must have reached this age", + "Answer": "eighteen" + }, + { + "Category": "\"KEY\"s", + "Question": "Attractions in this Florida city include the homes of Ernest Hemingway & John Jacob Audubon", + "Answer": "Key West" + }, + { + "Category": "SHIPS", + "Question": "The Queen Elizabeth was a few feet lnger than this, her sister ship", + "Answer": "the Queen Mary" + }, + { + "Category": "FOOD FACTS", + "Question": "Kentucky burgoo is a thick one of these made with meat vegetables", + "Answer": "a stew" + }, + { + "Category": "KING ARTHUR", + "Question": "Arthur set up the diamond jousts, a series of 9 annual tournaments all won by this knight", + "Answer": "Lancelot" + }, + { + "Category": "NATURE", + "Question": "The oxpecker, which is this type of animal, likes to ride on the backs of giraffes", + "Answer": "a bird" + }, + { + "Category": "MISC.", + "Question": "This noble gas glows orange-red when an electric current is passed through it", + "Answer": "neon" + }, + { + "Category": "\"KEY\"s", + "Question": "This type of private establishment admits only members & their guests", + "Answer": "a key club" + }, + { + "Category": "SHIPS", + "Question": "In 1831 Charles Darwin sailed as naturalist on this ship", + "Answer": "the Beagle" + }, + { + "Category": "FOOD FACTS", + "Question": "Hard sauce is made by beating together sugar, this spread, & a flavoring such as brandy", + "Answer": "butter" + }, + { + "Category": "KING ARTHUR", + "Question": "The title of this T.H. White book refers to the object that made Arthur king", + "Answer": "a sword in the stone" + }, + { + "Category": "NATURE", + "Question": "The Dorcas type of this graceful antelope is one of the smallest; it's barely 2 feet tall", + "Answer": "a gazelle" + }, + { + "Category": "MISC.", + "Question": "Jules Verne's book \"Around the Moon\" was the sequel to this 1865 best seller", + "Answer": "From the Earth to the Moon" + }, + { + "Category": "\"KEY\"s", + "Question": "No bones about it, it opens many locks", + "Answer": "a skeleton key" + }, + { + "Category": "SHIPS", + "Question": "The Thresher & Scorpion were this type of ship; 1 was lost in 1963, 1 in 1968", + "Answer": "submarines" + }, + { + "Category": "FOOD FACTS", + "Question": "\"Crevette\" is the French word for this shellfish", + "Answer": "shrimp" + }, + { + "Category": "KING ARTHUR", + "Question": "After Mordred mortally wounded him, Arthur's body was carried away to this island", + "Answer": "Avalon" + }, + { + "Category": "NATURE", + "Question": "This spotted cat is also known as the hunting leopard", + "Answer": "the cheetah" + }, + { + "Category": "MISC.", + "Question": "This N.H. school was the last U.S. institution of higher learning to be founded by royal decree", + "Answer": "Dartmouth" + }, + { + "Category": "\"KEY\"s", + "Question": "From 1833 to 1841 he served as U.S. attorney for the District of Columbia", + "Answer": "Francis Scott Key" + }, + { + "Category": "SCIENCE", + "Question": "In metric measurement, 10 millimeters equal 1 of these", + "Answer": "a centimeter" + }, + { + "Category": "CHILDREN'S LITERATURE", + "Question": "In one Grimm tale, 12 princesses dance these to pieces in an underground castle", + "Answer": "their shoes" + }, + { + "Category": "WYOMING", + "Question": "Wyoming shares the Black Hills National Forest with this state", + "Answer": "South Dakota" + }, + { + "Category": "FIGURE SKATERS", + "Question": "In 1986 she became the 1st black woman to win the World Championship of Figure Skating", + "Answer": "Debbie Thomas" + }, + { + "Category": "ORGANIZED LABOR", + "Question": "Under this arrangement, labor and management agree to let a third party settle their dispute", + "Answer": "arbitration" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "Imprisoned in Genoa, he dictated an account of his visit to the court of Kublai Khan", + "Answer": "Marco Polo" + }, + { + "Category": "SCIENCE", + "Question": "Boyle's Law says normally if you double the pressure on a gas, the volume decreases by this amount", + "Answer": "one-half" + }, + { + "Category": "CHILDREN'S LITERATURE", + "Question": "Anne Shirley leaves the orphanage to live on this \"colorful\" farm in Avonlea", + "Answer": "Green Gables" + }, + { + "Category": "WYOMING", + "Question": "A western celebration, Frontier Days, has been held each year since 1897 in this capital", + "Answer": "Cheyenne" + }, + { + "Category": "FIGURE SKATERS", + "Question": "In 1986 this East German beauty was called \"the warmest thing to hit the Cold War since vodka\"", + "Answer": "Katarina Witt" + }, + { + "Category": "ORGANIZED LABOR", + "Question": "This board was created in 1935 to correct or prevent unfair labor practices by employers or unions", + "Answer": "the National Labor Relations Board" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "This continent's Mali empire reached its apogee under Mansa Musa in the 14th century", + "Answer": "Africa" + }, + { + "Category": "SCIENCE", + "Question": "In 1973 it became the first comet studied by men in space", + "Answer": "Kohoutek" + }, + { + "Category": "CHILDREN'S LITERATURE", + "Question": "\"The Comic Adventures of\" this elderly woman \"and her Dog\" were first published in 1805", + "Answer": "Old Mother Hubbard" + }, + { + "Category": "WYOMING", + "Question": "The source of this main tributary of the Columbia River is located in Yellowstone National Park", + "Answer": "the Snake River" + }, + { + "Category": "FIGURE SKATERS", + "Question": "Native country of Barbara Ann Scott, who in 1947 became the 1st N. American to win the European title", + "Answer": "Canada" + }, + { + "Category": "ORGANIZED LABOR", + "Question": "In 1978 legislation raised the mandatory retirement age to this", + "Answer": "seventy" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "In 1301 Edward II was the first English heir to be given this title", + "Answer": "Prince of Wales" + }, + { + "Category": "SCIENCE", + "Question": "One mole of any substance always has the same number, 6.022 x 1023 of these", + "Answer": "atoms" + }, + { + "Category": "CHILDREN'S LITERATURE", + "Question": "Dinarzade is the younger sister of this woman known for her nocturnal stories", + "Answer": "Shahrazad" + }, + { + "Category": "WYOMING", + "Question": "Settlement began in earnest when this railroad pushed across the state in the 1860s", + "Answer": "the Union Pacific" + }, + { + "Category": "FIGURE SKATERS", + "Question": "An injury forced him & Tai Babilonia to withdraw from the pairs competition at Lake Placid in 1980", + "Answer": "Randy Gardner" + }, + { + "Category": "ORGANIZED LABOR", + "Question": "The United Steelworkers of America is headquartered in this city", + "Answer": "Pittsburgh" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "Irene, who reigned from 797-802, declared herselt Emperor, not Empress, of this empire", + "Answer": "the Byzantine Empire" + }, + { + "Category": "SCIENCE", + "Question": "This resin, a natural polymer used as a varnish, is produced by insects in India and Myanmar", + "Answer": "shellac" + }, + { + "Category": "CHILDREN'S LITERATURE", + "Question": "Madeline is one of \"twelve little girls in two straight lines\" who attend a school in this city", + "Answer": "Paris" + }, + { + "Category": "WYOMING", + "Question": "1 of Wyoming's 2 U.S. senators", + "Answer": "Alan Simpson" + }, + { + "Category": "FIGURE SKATERS", + "Question": "Dorothy Hamill developed a spin now known as the \"Hamill\" one of these", + "Answer": "camel" + }, + { + "Category": "ORGANIZED LABOR", + "Question": "This union withdrew from the AFL-CIO in 168 under Walter Reuther, but rejoined in 1981", + "Answer": "the United Autoworkers Union" + }, + { + "Category": "THE MIDDLE AGES", + "Question": "In 1358 this league of North German trading towns made Lubeck its administrative headquarters", + "Answer": "the Hanseatic League" + }, + { + "Category": "VICE PRESIDENTS", + "Question": "He served FDR as Commerce Secretary, Agriculture Secretary, and Vice President", + "Answer": "Henry Wallace" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "Though his last name means \"pertaining to a city\", this \"Defying Gravity\" singer is a country superstar", + "Answer": "Keith Urban" + }, + { + "Category": "YOUR HONOR, I OBJECT!", + "Question": "The witness is testifying based on what someone else told her--that's called this", + "Answer": "hearsay" + }, + { + "Category": "GOOD CAUSES", + "Question": "This word precedes \"Conservancy\" in the name of a group with a million members", + "Answer": "Nature" + }, + { + "Category": "BLARNEY", + "Question": "Now applied to Shakespeare, this word referred originally to Celtic minstrel poets", + "Answer": "bard" + }, + { + "Category": "LESSER-KNOWN AMERICANS", + "Question": "A. Philip Randolph, who first proposed a march on this city in 1941, also helped organize the one in 1963", + "Answer": "Washington, D.C." + }, + { + "Category": "COUNTRY MUSIC", + "Question": "In 2010 this movie soundtrack featuring Jeff Bridges was a Billboard Top 10 country album", + "Answer": "Crazy Heart" + }, + { + "Category": "THE LOYOLA OPPOSITION", + "Question": "In 1521, Ignatius was struck by a cannonball while defending this country against the French", + "Answer": "Spain" + }, + { + "Category": "YOUR HONOR, I OBJECT!", + "Question": "Calls for an opinion--only allowed for this type of witness with special knowledge of a subject", + "Answer": "an expert witness" + }, + { + "Category": "GOOD CAUSES", + "Question": "The Environmental Defense Fund helped convince this fast-food co. to abandon polystyrene containers in 1990", + "Answer": "McDonald's" + }, + { + "Category": "BLARNEY", + "Question": "For peat sake, you should know this word for wet, spongy ground", + "Answer": "a bog" + }, + { + "Category": "LESSER-KNOWN AMERICANS", + "Question": "In 1945 Virginia Gildersleeve was the only female U.S. delegate to the conference that drafted this charter", + "Answer": "the United Nations" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "Not to be confused with Lady Gaga is Lady this, the country music group with the CD \"Need You Now\"", + "Answer": "Lady Antebellum" + }, + { + "Category": "THE LOYOLA OPPOSITION", + "Question": "When Clement XIV abolished the Jesuits in 1773, they thrived in Russia with help from this empress", + "Answer": "Catherine the Great" + }, + { + "Category": "YOUR HONOR, I OBJECT!", + "Question": "Counsel is putting words in the witness' mouth with this type of question; the word also means \"in first place\"", + "Answer": "a leading question" + }, + { + "Category": "GOOD CAUSES", + "Question": "A \"Mission\" to help the homeless is named for this Lower Manhattan street known as a skid row since the 1800s", + "Answer": "Bowery" + }, + { + "Category": "BLARNEY", + "Question": "This type of sprite will lead you to the gold", + "Answer": "a leprechaun" + }, + { + "Category": "LESSER-KNOWN AMERICANS", + "Question": "Named for his cousin, James Buchanan Eads built the first bridge across this river at St. Louis", + "Answer": "the Mississippi" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "This sound, like that made by plucking a guitar, is the title of a 2009 album by George Strait", + "Answer": "twang" + }, + { + "Category": "THE LOYOLA OPPOSITION", + "Question": "In 1542 missionaries sent by Ignatius to Ireland were hampered by this king", + "Answer": "Henry VIII" + }, + { + "Category": "YOUR HONOR, I OBJECT!", + "Question": "Counsel is being argumentative, also known as doing this to the witness, as seen here", + "Answer": "badgering" + }, + { + "Category": "GOOD CAUSES", + "Question": "The LFA is a leading group battling this disease named for lesions that resemble a wolf's bite", + "Answer": "lupus" + }, + { + "Category": "BLARNEY", + "Question": "Tiny pieces, or the New Jersey band that sang \"Only a Memory\"", + "Answer": "smithereens" + }, + { + "Category": "LESSER-KNOWN AMERICANS", + "Question": "Doris Eaton Travis, who passed away in 2010 at age 106, was the last surviving showgirl from these follies", + "Answer": "Ziegfeld" + }, + { + "Category": "COUNTRY MUSIC", + "Question": "This frontman of Hootie & the Blowfish went country with his solo album \"Learn to Live\"", + "Answer": "Rucker" + }, + { + "Category": "THE LOYOLA OPPOSITION", + "Question": "While in Paris, Ignatius was accused & brought before Ori, this type of truth-seeking 10-letter holy man", + "Answer": "an inquisitor" + }, + { + "Category": "YOUR HONOR, I OBJECT!", + "Question": "We've heard the question already; I'm making this objection that could be called \"triple a\"", + "Answer": "asked and answered" + }, + { + "Category": "GOOD CAUSES", + "Question": "The Andre Agassi foundation for education runs Agassi Prep in this city", + "Answer": "Las Vegas" + }, + { + "Category": "BLARNEY", + "Question": "This word for a type of liquor applies to a 1794 American rebellion", + "Answer": "whiskey" + }, + { + "Category": "MOVIE CITIES", + "Question": "Of course there's a car chase on the freeway in 1985's \"To Live and Die in __.__.\"", + "Answer": "L.A." + }, + { + "Category": "WOMEN: WRITE ON!", + "Question": "Sadly, she died in Boston in 1888, just 2 days after her transcendentalist father Bronson", + "Answer": "Louisa May Alcott" + }, + { + "Category": "GOAT-POURRI", + "Question": "Goat Island splits Niagara Falls into the American Falls & this waterfall on the Canadian side", + "Answer": "Horseshoe Falls" + }, + { + "Category": "EPONYMS", + "Question": "Although sources disagree over the origin of this \"do-over\" golf shot, many accept that it was named for a bad golfer", + "Answer": "a Mulligan" + }, + { + "Category": "\"A\" SCIENCE CATEGORY", + "Question": "It's what the \"A\" stands for in AIDS", + "Answer": "acquired" + }, + { + "Category": "MOVIE CITIES", + "Question": "2010 brought Travolta as a spy in \"From ____ with Love\"", + "Answer": "Paris" + }, + { + "Category": "LAST NAME'S THE SAME", + "Question": "Entertainment mogul Barry & funny lady Phyllis", + "Answer": "Diller" + }, + { + "Category": "WOMEN: WRITE ON!", + "Question": "In 2009 she published her 76th bestseller, \"Matters of the Heart\", & was inducted into the Calif. Hall of Fame", + "Answer": "Danielle Steel" + }, + { + "Category": "GOAT-POURRI", + "Question": "In 1846 Neptune was discovered in this constellation, the 10th sign of the zodiac", + "Answer": "Capricorn" + }, + { + "Category": "EPONYMS", + "Question": "This country is named after \"the George Washington of South America\" (the actual George only got cities & a state)", + "Answer": "Bolivia" + }, + { + "Category": "\"A\" SCIENCE CATEGORY", + "Question": "(Kelly of the Clue Crew stands behind a table) The experiment showing that two objects weighing the same displace different amounts of water because they have different densities was developed by this mathematician", + "Answer": "Archimedes" + }, + { + "Category": "MOVIE CITIES", + "Question": "2010, starring Kristen Bell: \"When in ____\"", + "Answer": "Rome" + }, + { + "Category": "LAST NAME'S THE SAME", + "Question": "Late radio commentator Paul & James I's physician William", + "Answer": "Harvey" + }, + { + "Category": "WOMEN: WRITE ON!", + "Question": "Esther Greenwood is an aspiring poet in this poet's novel \"The Bell Jar\"", + "Answer": "Sylvia Plath" + }, + { + "Category": "GOAT-POURRI", + "Question": "In \"The Hunchback of Notre Dame\", Pierre Gringoire rescues this gypsy girl's goat from a mob", + "Answer": "Esmeralda" + }, + { + "Category": "EPONYMS", + "Question": "Meaning elegant or fancy, it's from the name of a hotel chain founded by a Swiss businessman", + "Answer": "ritzy" + }, + { + "Category": "\"A\" SCIENCE CATEGORY", + "Question": "In the 1920s Edwin Hubble determined that this galaxy was in fact a separate galaxy from the Milky Way", + "Answer": "Andromeda" + }, + { + "Category": "MOVIE CITIES", + "Question": "2008's \"The Mysteries of ____\" was based on a novel", + "Answer": "Pittsburgh" + }, + { + "Category": "LAST NAME'S THE SAME", + "Question": "\"Tennessee Tailor\" Andrew & poet/NAACP leader James Weldon", + "Answer": "Johnson" + }, + { + "Category": "WOMEN: WRITE ON!", + "Question": "\"Shiksa Goddess: (or, How I Spent My Forties)\" is a collection of essays by this \"Heidi Chronicles\" playwright", + "Answer": "Wasserstein" + }, + { + "Category": "GOAT-POURRI", + "Question": "The backward-curving horns of the Siberian species of this 4-letter goat may be nearly 5 feet long", + "Answer": "ibex" + }, + { + "Category": "EPONYMS", + "Question": "This submachine gun was named for an Israeli army officer whose design won a competition in the 1950s", + "Answer": "Uzi" + }, + { + "Category": "\"A\" SCIENCE CATEGORY", + "Question": "These are just small masses of lymphoid tissue in the nasopharynx", + "Answer": "adenoids" + }, + { + "Category": "MOVIE CITIES", + "Question": "The 1980 Oscar winner for Foreign Language Film was \"____ does Not Believe in Tears\"", + "Answer": "Moscow" + }, + { + "Category": "LAST NAME'S THE SAME", + "Question": "17th century philosopher Sir Francis & 20th century painter Francis", + "Answer": "Bacon" + }, + { + "Category": "WOMEN: WRITE ON!", + "Question": "\"Seducing the Demon: Writing for my Life\" is a 2006 memoir by this \"Fear of Flying\" author", + "Answer": "Erica Jong" + }, + { + "Category": "GOAT-POURRI", + "Question": "Crippled beggar Sammy Smalls, who traveled in a goat cart, inspired a title character of this opera set on Catfish Row", + "Answer": "Porgy and Bess" + }, + { + "Category": "EPONYMS", + "Question": "Named for a French courtesan, Pommes Anna is a dish of layered these, not apples", + "Answer": "potatoes" + }, + { + "Category": "THE WESTERN HEMISPHERE", + "Question": "Made up of 1 large & many smaller islands, it's the most populous of Britain's remaining overseas territories", + "Answer": "Bermuda" + }, + { + "Category": "THE DIRECTOR SPEAKS", + "Question": "\"I never believed in anything before I believed in movies\", said this \"E.T.\" director", + "Answer": "Spielberg" + }, + { + "Category": "PLACES", + "Question": "A small & informal restaurant, or one who eats there", + "Answer": "diner" + }, + { + "Category": "\"LIGHT\"s", + "Question": "Famous ones include Ray \"Boom Boom\" Mancini & Roberto \"Hands of Stone\" Duran", + "Answer": "lightweights" + }, + { + "Category": "CAMERA", + "Question": "The names of TV cameras & videocassette recorders are combined in this device", + "Answer": "a camcorder" + }, + { + "Category": "ACTION!", + "Question": "This hero made his comic book debut in & on the cover of Action Comics No. 1", + "Answer": "Superman" + }, + { + "Category": "WHERE'S MY COFFEE?", + "Question": "Once Yemen's chief coffee port, its name now refers to a flavor of chocolate & coffee", + "Answer": "Mocha" + }, + { + "Category": "THE DIRECTOR SPEAKS", + "Question": "\"Everybody denies I am a genius--but nobody ever called me one!\" noted this man who raised \"Kane\"", + "Answer": "Orson Welles" + }, + { + "Category": "PLACES", + "Question": "A building for religious veneration, or the L.A. auditorium that hosted 1997's Academy Awards", + "Answer": "shrine" + }, + { + "Category": "\"LIGHT\"s", + "Question": "To do this to someone's plight, you could trivialize it, or just take the P away", + "Answer": "make light of it" + }, + { + "Category": "CAMERA", + "Question": "Aptly, underwater photography may require these widest wide-angle lenses", + "Answer": "fisheye lenses" + }, + { + "Category": "ACTION!", + "Question": "In a 1965 speech this president put out a call for \"affirmative action\" in hiring by federal contractors", + "Answer": "Johnson" + }, + { + "Category": "WHERE'S MY COFFEE?", + "Question": "The flavorful coffee beans from this country are grown at high altitudes near Nairobi", + "Answer": "Kenya" + }, + { + "Category": "THE DIRECTOR SPEAKS", + "Question": "When an actress in his \"Lifeboat\" asked him what her best side was, he said, \"My dear, you're sitting on it\"", + "Answer": "Hitchcock" + }, + { + "Category": "PLACES", + "Question": "Libraries & the Christian Science Church maintain these areas; the British Museum built a big one in 1857", + "Answer": "reading rooms" + }, + { + "Category": "\"LIGHT\"s", + "Question": "Ben Franklin invented this device & would have been shocked if it hadn't worked", + "Answer": "the lightning rod" + }, + { + "Category": "CAMERA", + "Question": "In 1986 Kodak left the instant camera business after a judge found it had violated this company's patents", + "Answer": "Polaroid" + }, + { + "Category": "ACTION!", + "Question": "You may not give a fig, but according to Newton, there's one of these for every action", + "Answer": "an equal & opposite reaction" + }, + { + "Category": "WHERE'S MY COFFEE?", + "Question": "Java is a synonym for coffee; a high-grade bean also comes from this next most populous Indonesian island", + "Answer": "Sumatra" + }, + { + "Category": "THE DIRECTOR SPEAKS", + "Question": "\"Manhattan\"ite who said, \"Life is divided into the horrible and the miserable\"--sounds \"Bananas\" to us", + "Answer": "Woody Allen" + }, + { + "Category": "PLACES", + "Question": "A place where a river is shallow enough to cross on foot, alone or with an \"escort\"", + "Answer": "a ford" + }, + { + "Category": "\"LIGHT\"s", + "Question": "A joking question asked about many groups is \"How many does it take to\" do this", + "Answer": "screw in a light bulb" + }, + { + "Category": "ACTION!", + "Question": "The action of a boy can ring a girl's bell, & the action of these can ring a buoy's bell", + "Answer": "a wave" + }, + { + "Category": "WHERE'S MY COFFEE?", + "Question": "Mexico's best coffee comes from Chiapas, a state that borders this noted coffee-growing nation", + "Answer": "Guatemala" + }, + { + "Category": "THE DIRECTOR SPEAKS", + "Question": "\"The best director is the one you don't see\", observed this director of \"Some Like It Hot\"", + "Answer": "Billy Wilder" + }, + { + "Category": "PLACES", + "Question": "This term for a house's entrance hall also refers to the space between cars on a train", + "Answer": "the vestibule" + }, + { + "Category": "\"LIGHT\"s", + "Question": "\"I'm gonna let it shine, let it shine, let it shine, let it shine\"", + "Answer": "this little light of mine" + }, + { + "Category": "ACTION!", + "Question": "Dutch-American artist about whose work the term \"action painting\" was coined", + "Answer": "Willem de Kooning" + }, + { + "Category": "SHAKESPEAREAN OPERAS & BALLETS", + "Question": "It's the play that inspired Reynaldo Hahn's opera \"Le Marchand de Venise\"", + "Answer": "The Merchant of Venice" + }, + { + "Category": "BACKWARDS", + "Question": "In T minus 5 seconds, you'll say this word for the inverted series used before a rocket launch", + "Answer": "a countdown" + }, + { + "Category": "CARTOONS", + "Question": "Mel Blanc said he created this character's voice by combining Brooklyn & Bronx accents", + "Answer": "Bugs Bunny" + }, + { + "Category": "19th CENTURY AMERICA", + "Question": "The discovery of this in 1896 turned Seward's Folly into Seward's Good Fortune", + "Answer": "gold" + }, + { + "Category": "MEN OF THE WORLD", + "Question": "Armando Munoz Garcia sculpted a 55' statue of a nude woman & lived in it in this Mexican city near San Diego", + "Answer": "Tijuana" + }, + { + "Category": "WORD ORIGINS", + "Question": "This state's name is from the Sioux for \"sky-tinted waters\"; maybe they meant the 10,000 lakes", + "Answer": "Minnesota" + }, + { + "Category": "SHAKESPEAREAN OPERAS & BALLETS", + "Question": "The Bolshoi presented this ballet at the Met in 1959, with Yuri Zhdanov & Galina Ulanova as the title lovers", + "Answer": "Romeo & Juliet" + }, + { + "Category": "BACKWARDS", + "Question": "In psychology it's the process of reverting to an earlier, childlike form of behavior", + "Answer": "regression" + }, + { + "Category": "CARTOONS", + "Question": "I say there, son, this Warner Bros. cartoon rooster is sometimes pursued by a chicken hawk", + "Answer": "Foghorn Leghorn" + }, + { + "Category": "19th CENTURY AMERICA", + "Question": "The 1866 Civil Rights Act was passed over this president's veto", + "Answer": "Johnson" + }, + { + "Category": "WORD ORIGINS", + "Question": "The Old Norse word \"vindauga\" gave us this pane-ful word for an opening in a wall", + "Answer": "window" + }, + { + "Category": "SHAKESPEAREAN OPERAS & BALLETS", + "Question": "You'll need some long-winded singers to star in \"Stormen\", a Swedish opera based on this play", + "Answer": "The Tempest" + }, + { + "Category": "BACKWARDS", + "Question": "Field Marshal Barclay used this maneuver associated with defeat to lure Napoleon deep into Russia", + "Answer": "a retreat" + }, + { + "Category": "CARTOONS", + "Question": "On screen, he's a \"tubby little cubby all stuffed with fluff\"", + "Answer": "Winnie the Pooh" + }, + { + "Category": "19th CENTURY AMERICA", + "Question": "Kansas homesteader Bewster Higley's poem \"The Western Home\" was retitled this when set to music", + "Answer": "\"Home On The Range\"" + }, + { + "Category": "MEN OF THE WORLD", + "Question": "This media mogul from Melbourne has been called a real-life Citizen Kane", + "Answer": "Rupert Murdoch" + }, + { + "Category": "WORD ORIGINS", + "Question": "Derived from the Latin for \"salted vegetables\", this cold dish might be enhanced with a little oil & vinegar", + "Answer": "salad" + }, + { + "Category": "SHAKESPEAREAN OPERAS & BALLETS", + "Question": "Verdi wrote an aria called \"La Luce Langue\"--The Light Fails--for this bloothirsty villainess", + "Answer": "Lady Macbeth" + }, + { + "Category": "BACKWARDS", + "Question": "In competitive rowing, this is the only person in the boat whose back is not to the finish line", + "Answer": "the coxswain" + }, + { + "Category": "CARTOONS", + "Question": "Ted Cassidy, who played Thing on \"The Addams Family\", was also the voice of The Thing of this superhero group", + "Answer": "The Fantastic 4" + }, + { + "Category": "19th CENTURY AMERICA", + "Question": "To avoid Boss Tweed's graft, Alfred Beach secretly built one of these under Broadway in 1869-70", + "Answer": "a subway" + }, + { + "Category": "WORD ORIGINS", + "Question": "This number can be traced back to the Sankrit \"Shunya\", or empty", + "Answer": "zero" + }, + { + "Category": "SHAKESPEAREAN OPERAS & BALLETS", + "Question": "Title character played by former Alvin Ailey dancer Desmond Richardson in a 1997 ballet", + "Answer": "Othello" + }, + { + "Category": "BACKWARDS", + "Question": "Called \"Bojangles\", he was renowned for tap dancing on stairs & running backwards at high speed", + "Answer": "Robinson" + }, + { + "Category": "CARTOONS", + "Question": "Sylvester believes Hippety Hopper, a baby one of these, to be a gigantic mouse", + "Answer": "a kangaroo" + }, + { + "Category": "WORD ORIGINS", + "Question": "The -sex suffix on British placenames refers to this Germanic people", + "Answer": "the Saxons" + }, + { + "Category": "FAMOUS VOYAGES", + "Question": "Capt. Robert Fitzroy of this ship argued that its scientific discoveries supported the Bible", + "Answer": "the Beagle" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "This title folk story guy steals a golden egg-laying hen, bags of gold & a golden harp; the \"giant-cide\" comes later", + "Answer": "Jack" + }, + { + "Category": "THE MOVIES", + "Question": "Jack Palance's character is described as \"a saddlebag with eyes\" in this 1991 comedy", + "Answer": "City Slickers" + }, + { + "Category": "WEAPONRY", + "Question": "Standard-issue weapons for stormtroopers in \"Star Wars\" included energy-bolt-firing pistols called these", + "Answer": "blasters" + }, + { + "Category": "MEDICAL TALK", + "Question": "This term refers to the painful inflammation of any of the fibrous structures that connect muscles to bones", + "Answer": "tendinitis" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "What a happy ending: this title orphan of a Dickens novel is adopted by Mr. Brownlow", + "Answer": "Oliver Twist" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Chips' aquatic partner (4)", + "Answer": "fish" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "Playing the pass line in craps, it's the winning number on the opening roll other than 7", + "Answer": "11" + }, + { + "Category": "WEAPONRY", + "Question": "In the 1960s Nelson Mandela led the military group \"Umkhonto we Sizwe\", or this weapon \"of the Nation\"", + "Answer": "Spear" + }, + { + "Category": "MEDICAL TALK", + "Question": "To test for visual acuity, the Snellen chart is designed to be read from this many feet away", + "Answer": "20" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "This character in \"The Legend of Sleepy Hollow\" is said to be the ghost of a Hessian trooper", + "Answer": "the Headless Horseman" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Honshu volcano (4)", + "Answer": "Fuji" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "Found in Southeast Asia, they're the smallest apes", + "Answer": "gibbons" + }, + { + "Category": "THE MOVIES", + "Question": "Irene Bedard, the speaking voice of this heroine in an animated Disney film, played her mother in \"The New World\"", + "Answer": "Pocahontas" + }, + { + "Category": "WEAPONRY", + "Question": "The first 2 weapons Hamlet mentions in his \"To be or not to be\" soliloquy", + "Answer": "slings & arrows" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "She is the narrator of \"To Kill a Mockingbird\"", + "Answer": "Scout" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Greek-letter group (10)", + "Answer": "fraternity" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "Pick up a GT from this car co. for a tidy $169,000, or maybe start out with a Focus for a more reasonable $13,715", + "Answer": "Ford" + }, + { + "Category": "WEAPONRY", + "Question": "In the missile called a \"SAM\", it's what the \"A\" stands for", + "Answer": "air" + }, + { + "Category": "MEDICAL TALK", + "Question": "It begins, \"I swear by Apollo physician and Asclepius...\"", + "Answer": "the hippocratic oath" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "2 names that follow Gerald, who speaks in weird sounds instead of words in a Dr. Seuss story", + "Answer": "McBoing-Boing" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "A Mrs., in Munich (4)", + "Answer": "Frau" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "The tuliptree, or \"yellow\" this, was planted by Washington at Mt. Vernon, & Daniel Boone used its wood in his canoe", + "Answer": "poplar" + }, + { + "Category": "THE MOVIES", + "Question": "Jane Russell & Marilyn Monroe sang about being \"Two Little Girls from Little Rock\" in this 1953 movie musical", + "Answer": "Gentlemen Prefer Blondes" + }, + { + "Category": "WEAPONRY", + "Question": "The weapons that are \"bursting\" in line 5 of \"The Star-Spangled Banner\"", + "Answer": "bombs" + }, + { + "Category": "MEDICAL TALK", + "Question": "Luteinizing hormone is one of the many produced by this cherry-shaped gland", + "Answer": "the pituitary" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "In a story by Rudyard Kipling, this mongoose protects an English family from snakes", + "Answer": "Rikki-Tikki-Tavi" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "It's spoken in Hameenlinna & Hyvinkaa (7)", + "Answer": "Finnish" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "This general, first in his class at West Point, ran for president in 2004", + "Answer": "Wesley Clark" + }, + { + "Category": "TV PRODUCERS", + "Question": "The Fairmont in this city's Nob Hill was the exterior used for Aaron Spelling's \"Hotel\" TV series", + "Answer": "San Francisco" + }, + { + "Category": "TOUGH BODIES OF WATER", + "Question": "St. George's Channel separates Wales from this country", + "Answer": "Ireland" + }, + { + "Category": "HELLO, DELI!", + "Question": "I think I'll just have a nosh--a bagel, cream cheese & the Nova Scotia type of this", + "Answer": "lox" + }, + { + "Category": "ALSO A BOOK IN THE BIBLE", + "Question": "Caesar, Antony, Cicero, et al.", + "Answer": "Romans" + }, + { + "Category": "IS IT \"TEA\" TIME YET?", + "Question": "I see in my crystal ball that Bill Hewitt wrote a book about how to read these", + "Answer": "tea leaves" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "This \"old soldier\" was a general at age 38; in 1930 at age 50, he was Chief of Staff of the U.S. Army", + "Answer": "MacArthur" + }, + { + "Category": "TV PRODUCERS", + "Question": "David Chase created this HBO series & wrote many of its episodes, like \"Mr. Ruggerio's Neighborhood\"", + "Answer": "The Sopranos" + }, + { + "Category": "TOUGH BODIES OF WATER", + "Question": "Bristol Bay is an arm of this sea off Alaska", + "Answer": "the Bering" + }, + { + "Category": "HELLO, DELI!", + "Question": "I'll have one of these \"city\" omelets stuffed with ham, onions & green peppers", + "Answer": "a Denver omelette" + }, + { + "Category": "ALSO A BOOK IN THE BIBLE", + "Question": "In a 1971 song he \"was a bullfrog\"", + "Answer": "Jeremiah" + }, + { + "Category": "IS IT \"TEA\" TIME YET?", + "Question": "A tea room in Cambria, California is named for this kind of teapot cover--& it sells them, too", + "Answer": "a cozy" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "More than 540,000 men & women served under this general's command of the U.S. forces in the Persian Gulf War of 1991", + "Answer": "Schwarzkopf" + }, + { + "Category": "TV PRODUCERS", + "Question": "He moved from \"Melrose Place\" to the east coast for \"Central Park West\" & \"Sex & the City\"", + "Answer": "Darren Star" + }, + { + "Category": "TOUGH BODIES OF WATER", + "Question": "Rivers that flow into this sea include the Dnieper, Dniester & Danube", + "Answer": "the Black Sea" + }, + { + "Category": "HELLO, DELI!", + "Question": "Someone pass me this noodle pudding filled with raisins & nuts", + "Answer": "kugel" + }, + { + "Category": "ALSO A BOOK IN THE BIBLE", + "Question": "Hey, this, don't be \"obscure\"", + "Answer": "Jude" + }, + { + "Category": "IS IT \"TEA\" TIME YET?", + "Question": "This slang synonym for oil is mentioned in the theme song to \"The Beverly Hillbillies\"", + "Answer": "Texas tea" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "The only place this general wouldn't \"march\" was to the presidency; he told the GOP \"I will not accept if nominated\" in 1884", + "Answer": "Sherman" + }, + { + "Category": "TV PRODUCERS", + "Question": "In 2003 this \"Survivor\" head honcho began conducting a search to give Donald Trump an apprentice", + "Answer": "Mark Burnett" + }, + { + "Category": "TOUGH BODIES OF WATER", + "Question": "The Uruguay River forms the border between Uruguay & Argentina & most of the border between Argentina & this country", + "Answer": "Brazil" + }, + { + "Category": "HELLO, DELI!", + "Question": "It's a good knight for one of these Jewish turnovers with a meat or potato filling", + "Answer": "a knish" + }, + { + "Category": "ALSO A BOOK IN THE BIBLE", + "Question": "This character first hit the radio in 1928 with his partner Andy", + "Answer": "Amos" + }, + { + "Category": "IS IT \"TEA\" TIME YET?", + "Question": "When Lady Diana had doubts about marrying Prince Charles, she was told: Too late. \"Your face is on\" these cloth items", + "Answer": "tea towels" + }, + { + "Category": "GENERAL INFORMATION", + "Question": "This Army general headed American-led forces during the initial combat phase of the Iraq War as it began in 2003", + "Answer": "Tommy Franks" + }, + { + "Category": "TV PRODUCERS", + "Question": "He probably has another 6 or 7 \"Law & Order\" offshoots on his desk just waiting for network slots", + "Answer": "Dick Wolf" + }, + { + "Category": "TOUGH BODIES OF WATER", + "Question": "This Venezuelan lake is the only one of the world's 25 largest lakes whose elevation is sea level", + "Answer": "Lake Maracaibo" + }, + { + "Category": "HELLO, DELI!", + "Question": "Something smells fishy--must be this chopped fish patty mixed with crumbs & eggs & served cold in a jellied broth", + "Answer": "gefilte fish" + }, + { + "Category": "ALSO A BOOK IN THE BIBLE", + "Question": "Few were \"better than\" this Mr. Cornell who founded the university in 1865", + "Answer": "Ezra" + }, + { + "Category": "IS IT \"TEA\" TIME YET?", + "Question": "In 1975 the Perfumer's Workshop introduced a fragrance named for this flower", + "Answer": "a tea rose" + }, + { + "Category": "BEFORE THEY WERE SENATORS", + "Question": "Later a U.S. senator, in 1962 he made a famous 75,000-mile trip", + "Answer": "John Glenn" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "Between 1856 & 1860, 2,962 of this faith set out from Iowa & Nebraska to Utah in the Handcart Migration", + "Answer": "Mormonism" + }, + { + "Category": "CABLE CHANNELS", + "Question": "The Dire Straits song \"Money For Nothing\" says, \"You play the guitar on\" this cable channel", + "Answer": "MTV" + }, + { + "Category": "PROPHET SHARING", + "Question": "Before he was a prophet, Smohalla gained fame as one of these alliterative Native American healers", + "Answer": "a medicine man" + }, + { + "Category": "WOMEN OF THE WORLD", + "Question": "This Nobel Peace Prize winner was born in what is now Skopje, Macedonia in 1910", + "Answer": "Mother Teresa" + }, + { + "Category": "SWEET!", + "Question": "This slang term for coffee precedes \"chip\" in a Starbucks ice cream flavor", + "Answer": "java" + }, + { + "Category": "\"IND\" THE KNOW", + "Question": "This adjective refers to the original natives of any region", + "Answer": "indigenous" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "On April 2, 1917 President Wilson told Congress, \"The world must be made safe for\" this", + "Answer": "democracy" + }, + { + "Category": "CABLE CHANNELS", + "Question": "This channel for women produces the original drama \"Army Wives\"", + "Answer": "Lifetime" + }, + { + "Category": "PROPHET SHARING", + "Question": "In I Kings this fiery Biblical prophet won a contest with the prophets of Baal", + "Answer": "Elijah" + }, + { + "Category": "WOMEN OF THE WORLD", + "Question": "This British dame, Rudolf Nureyev's dance partner, was married to a Panamanian diplomat", + "Answer": "Margot Fonteyn" + }, + { + "Category": "SWEET!", + "Question": "Butter is an ingredient of this hard candy that has \"butter\" in its name; the rest of its name doesn't refer to whisky", + "Answer": "butterscotch" + }, + { + "Category": "\"IND\" THE KNOW", + "Question": "The systematic teaching of beliefs to gain uncritical acceptance", + "Answer": "indoctrination" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "On April 20, 1971 the U.S. Supreme Court upheld this transportation method as a way to achieve school integration", + "Answer": "busing" + }, + { + "Category": "CABLE CHANNELS", + "Question": "This channel shows films like \"The Magnificent Seven\" & original series like \"Mad Men\" & \"Breaking Bad\"", + "Answer": "AMC" + }, + { + "Category": "PROPHET SHARING", + "Question": "The soothsayer Calchas told this king he had to offer up his daughter Iphigenia to Artemis to get winds to rise", + "Answer": "Agamemnon" + }, + { + "Category": "WOMEN OF THE WORLD", + "Question": "She wrote her first novel, \"The House of the Spirits\", in exile soon after her uncle's assassination", + "Answer": "Isabel Allende" + }, + { + "Category": "SWEET!", + "Question": "A confection called a kiss is baked this: sugar & stiffly beaten egg whites", + "Answer": "meringue" + }, + { + "Category": "\"IND\" THE KNOW", + "Question": "Punjab means \"land of 5 rivers\", & all 5 of the rivers eventually flow into this one", + "Answer": "the Indus" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "John O'Sullivan, who later became a diplomat, coined this term for the USA's right to cover the continent", + "Answer": "Manifest Destiny" + }, + { + "Category": "CABLE CHANNELS", + "Question": "You'll \"find\" that this channel features \"Cash Cab\" & \"Dirty Jobs\"", + "Answer": "Discovery" + }, + { + "Category": "PROPHET SHARING", + "Question": "Poems known as the \"Gathas\" are attributed to this ancient prophet & teacher who lived in eastern Iran", + "Answer": "Zoroaster" + }, + { + "Category": "WOMEN OF THE WORLD", + "Question": "This Norwegian beauty is noted for her work with Ingmar Bergman & with UNICEF", + "Answer": "Liv Ullmann" + }, + { + "Category": "SWEET!", + "Question": "A red cake named for this smooth fabric is really a chocolate cake--food coloring gives it the distinctive color", + "Answer": "velvet" + }, + { + "Category": "\"IND\" THE KNOW", + "Question": "Insurance term meaning to protect against damage, loss or injury", + "Answer": "indemnity" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1798 Congress passed this collection of bills to control domestic dissent & conspiracy against the federal govt.", + "Answer": "the Alien & Sedition Acts" + }, + { + "Category": "CABLE CHANNELS", + "Question": "Channel that's been home to gritty shows like \"Dirt\" & \"Rescue Me\"", + "Answer": "FX" + }, + { + "Category": "PROPHET SHARING", + "Question": "On the Sistine Chapel ceiling, Michelangelo included some of these ancient oracle-like prophetesses", + "Answer": "sibyls" + }, + { + "Category": "WOMEN OF THE WORLD", + "Question": "Under 5 feet tall & all of about 90 pounds, this frail French chanteuse was nicknamed the \"Little Sparrow\"", + "Answer": "Piaf" + }, + { + "Category": "SWEET!", + "Question": "Some pies have a top named for this garden structure", + "Answer": "a lattice" + }, + { + "Category": "\"IND\" THE KNOW", + "Question": "Also a term in logic, it's the process by which a magnetic field is ordered into poles", + "Answer": "induction" + }, + { + "Category": "RUSSIAN SCIENTISTS", + "Question": "Sergey Korolyov was instrumental in the success of this first artificial satellite of the Earth", + "Answer": "Sputnik" + }, + { + "Category": "CANADIAN FOOTBALL", + "Question": "One of the 8 teams in the CFL is the Stampeders, who play for this city in the Canadian Rockies", + "Answer": "Calgary" + }, + { + "Category": "GUYANESE GEOGRAPHY", + "Question": "Guyana is divided into 3 regions: a highland, an inland forest & a coastal plain along this ocean", + "Answer": "the Atlantic" + }, + { + "Category": "TURKISH LITERATURE", + "Question": "The poem called the \"Garibnameh\" contains 11,000 masnavi, which we know as these rhymed 2-line units of verse", + "Answer": "couplets" + }, + { + "Category": "CHINESE CALENDAR ANIMALS", + "Question": "This first sign is a nocturnal animal; those born under it work best in quiet hours; oo, you dirty...", + "Answer": "rat" + }, + { + "Category": "BRAZILIAN WORDS & PHRASES", + "Question": "Unlike some, I like my women to be \"cranio\", this quality we also admire on \"Jeopardy!\"", + "Answer": "intelligence" + }, + { + "Category": "RUSSIAN SCIENTISTS", + "Question": "Rehovot in this country has an institute named for Russian-born Chaim Weizmann, who synthesized acetone", + "Answer": "Israel" + }, + { + "Category": "CANADIAN FOOTBALL", + "Question": "Unlike the NFL, a CFL team gets this many downs in a series to advance the ball 10 yards", + "Answer": "three" + }, + { + "Category": "GUYANESE GEOGRAPHY", + "Question": "Located at the mouth of the Demerara River, it's the capital & largest city", + "Answer": "Georgetown" + }, + { + "Category": "TURKISH LITERATURE", + "Question": "A religious kaside poem praised God, this man or his son-in-law, Ali Ibn Abi Talib, the fourth caliph", + "Answer": "Muhammad" + }, + { + "Category": "CHINESE CALENDAR ANIMALS", + "Question": "This wascally sign whose years include 1951 & 1999 shows bravery against high odds & is rarely be-Fudd-led", + "Answer": "a rabbit" + }, + { + "Category": "BRAZILIAN WORDS & PHRASES", + "Question": "Forget about him, he met someone down at Ipanema Beach & now he's \"apaixonado\", this condition", + "Answer": "in love" + }, + { + "Category": "RUSSIAN SCIENTISTS", + "Question": "In the mid-18th c. Mikhail Lomonosov became the first scientist to record the freezing of this liquid metal", + "Answer": "mercury" + }, + { + "Category": "CANADIAN FOOTBALL", + "Question": "French for \"red\", it's the term used for the point that is scored if a punt goes out of the end zone untouched", + "Answer": "rouge" + }, + { + "Category": "GUYANESE GEOGRAPHY", + "Question": "Spectacular waterfalls in Guyana include one named for a British king of this name, who ruled 1901-10", + "Answer": "Edward" + }, + { + "Category": "TURKISH LITERATURE", + "Question": "Sultan Abdulhamid II's censorship hindered Ottoman writers until this \"youthful\" group's 1908 revolution", + "Answer": "the Young Turks" + }, + { + "Category": "CHINESE CALENDAR ANIMALS", + "Question": "This sign for 2006 shows devotion to family; aren't you a good sign? Yes you are! Good sign!", + "Answer": "the dog" + }, + { + "Category": "BRAZILIAN WORDS & PHRASES", + "Question": "Cousin Fred said he was Napoleon last night; I'm afraid he might be \"maluco\", this", + "Answer": "crazy" + }, + { + "Category": "RUSSIAN SCIENTISTS", + "Question": "Lev Landau won a 1962 Nobel Prize for working in low-temperature physics, also known as this", + "Answer": "cryogenics" + }, + { + "Category": "CANADIAN FOOTBALL", + "Question": "This former Boston College & New England Patriots QB was the CFL's most outstanding player 6 times", + "Answer": "Doug Flutie" + }, + { + "Category": "GUYANESE GEOGRAPHY", + "Question": "One of Guyana's largest cities, it's also an old name for New York City", + "Answer": "New Amsterdam" + }, + { + "Category": "TURKISH LITERATURE", + "Question": "Peter Ustinov directed & starred in the film version of the Yasar Kemal novel \"Memed, My\" this predatory bird", + "Answer": "Hawk" + }, + { + "Category": "CHINESE CALENDAR ANIMALS", + "Question": "1967 folks \"flock\" to this sign that represents the essence of the Yin, the feminine passive principle", + "Answer": "the sheep" + }, + { + "Category": "BRAZILIAN WORDS & PHRASES", + "Question": "If you want another drink, hand over some \"grana\", this; I'm not covering for you anymore after last night", + "Answer": "money" + }, + { + "Category": "CANADIAN FOOTBALL", + "Question": "The Alouettes play their home games at Molson Stadium on the campus of this Montreal university", + "Answer": "McGill" + }, + { + "Category": "GUYANESE GEOGRAPHY", + "Question": "Guyana has had a long-standing border dispute with this small country to its southeast", + "Answer": "Suriname" + }, + { + "Category": "TURKISH LITERATURE", + "Question": "Seyid Imadeddin Nesimi wrote 2 of these poetry collections, also a word from Turkish for a couch", + "Answer": "divan" + }, + { + "Category": "CHINESE CALENDAR ANIMALS", + "Question": "The only 2-letter sign, it represents solid dependability, method & routine", + "Answer": "the ox" + }, + { + "Category": "BRAZILIAN WORDS & PHRASES", + "Question": "That very blond guy you met at carnival is called an \"alemao\", literally a man from this country", + "Answer": "Germany" + }, + { + "Category": "CLASSIC MOVIE CHARACTERS", + "Question": "The parents of this 1942 film character are an unnamed mother & a father known as \"the great prince of the forest\"", + "Answer": "Bambi" + }, + { + "Category": "THE BIG BANGLADESH", + "Question": "Over 80% of those in Bangladesh follow this religion", + "Answer": "Islam" + }, + { + "Category": "WHO'S THE MRS.?", + "Question": "Mrs. Brad Pitt", + "Answer": "Jennifer Aniston" + }, + { + "Category": "TRANSPORTATION", + "Question": "The twin rotor type of this has 2 main rotors going in opposite directions, so it doesn't need a tail rotor", + "Answer": "a helicopter" + }, + { + "Category": "MYTHELLANEOUS", + "Question": "The mythical Sumerian hero Utnapishtim built a big vessel at God's urging & thereby survived this catastrophe", + "Answer": "a flood" + }, + { + "Category": "BIRD HUNTING", + "Question": "The stars of the movie \"Network\" include Faye Dunaway, Beatrice Straight & Peter Finch", + "Answer": "a finch" + }, + { + "Category": "THE BIG BANGLADESH", + "Question": "About two-thirds of all Bangladeshis work in agriculture, mostly farming this product", + "Answer": "rice" + }, + { + "Category": "WHO'S THE MRS.?", + "Question": "Mrs. Tim McGraw", + "Answer": "Faith Hill" + }, + { + "Category": "TRANSPORTATION", + "Question": "There are no knife or spoon varieties of these vehicles used in warehouses to raise & carry merchandise", + "Answer": "forklifts" + }, + { + "Category": "MYTHELLANEOUS", + "Question": "Lotis, later turned into the lotus tree, was one of these female spirits of nature", + "Answer": "a nymph" + }, + { + "Category": "NOW YOU'RE TALKING MY LANGUAGE", + "Question": "\"Namaste\" is a greeting in this official language of India used by over a quarter of a billion speakers", + "Answer": "Hindi" + }, + { + "Category": "BIRD HUNTING", + "Question": "One of the cardinal rules of e-mail listed on insiderreports.com is to turn off your Caps-Lock", + "Answer": "a cardinal" + }, + { + "Category": "THE BIG BANGLADESH", + "Question": "The green on the flag of Bangladesh represents its lush vegetation; the red circle in the middle is this", + "Answer": "the sun" + }, + { + "Category": "WHO'S THE MRS.?", + "Question": "Mrs. James Carville", + "Answer": "Matalin" + }, + { + "Category": "TRANSPORTATION", + "Question": "The U.S. U-2, first built in the 1950s, was an airplane; the German U-1, first built in the 1910s, was one of these", + "Answer": "a submarine" + }, + { + "Category": "MYTHELLANEOUS", + "Question": "In Zuni myth, a kachina named Paiyatemu attracted these colorfully winged insects when she played the flute", + "Answer": "butterflies" + }, + { + "Category": "NOW YOU'RE TALKING MY LANGUAGE", + "Question": "The official language of Niger, it's a remnant of its colonial times", + "Answer": "French" + }, + { + "Category": "BIRD HUNTING", + "Question": "At NYU, Martin Scorsese taught future filmmakers Spike Lee & Oliver Stone", + "Answer": "a martin" + }, + { + "Category": "THE BIG BANGLADESH", + "Question": "After India was partitioned in 1947, what would later become Bangladesh was the \"East\" part of this country", + "Answer": "Pakistan" + }, + { + "Category": "WHO'S THE MRS.?", + "Question": "Mrs. Maury Povich", + "Answer": "Connie Chung" + }, + { + "Category": "TRANSPORTATION", + "Question": "In 1994 the trip across this body of water was cut from a little more than an hour to about 35 minutes", + "Answer": "the English Channel" + }, + { + "Category": "MYTHELLANEOUS", + "Question": "This goddess after whom a major city in Greece is named sprang from the head of Zeus", + "Answer": "Athena" + }, + { + "Category": "NOW YOU'RE TALKING MY LANGUAGE", + "Question": "The official language of Andorra, it's the second-most spoken language in Spain", + "Answer": "Catalan" + }, + { + "Category": "BIRD HUNTING", + "Question": "The third rail in a subway system is the one with the juice & should be avoided like a touchy subject", + "Answer": "a rail" + }, + { + "Category": "WHO'S THE MRS.?", + "Question": "Mrs. Blake Edwards", + "Answer": "Julie Andrews" + }, + { + "Category": "TRANSPORTATION", + "Question": "The Kearsarge was the only one of these not named for a U.S. state", + "Answer": "a battleship" + }, + { + "Category": "MYTHELLANEOUS", + "Question": "Riding this winged horse made it possible for Bellerophon to approach & kill the chimera", + "Answer": "Pegasus" + }, + { + "Category": "NOW YOU'RE TALKING MY LANGUAGE", + "Question": "Felipe Guaman Poma de Ayala is a well-known writer in this language of the Incas", + "Answer": "Quechua" + }, + { + "Category": "BIRD HUNTING", + "Question": "The Academy of Pro Players Power Hitting Baseball Camp can help you with bat speed, bunting & hitting the curve", + "Answer": "a bunting" + }, + { + "Category": "OSCARS OF THE '70s", + "Question": "No relation to the Lakers' center, she's the youngest ever to win a Supporting Actress Oscar", + "Answer": "Tatum O'Neal" + }, + { + "Category": "THE STING", + "Question": "Most bar recipes for the stinger call for the white version of this potent potable, not the green", + "Answer": "crème de menthe" + }, + { + "Category": "\"ROCK\"Y", + "Question": "\"SF Sorrow\" by The Pretty Things was the first of these works; \"Tommy\" came soon after", + "Answer": "a rock opera" + }, + { + "Category": "THE GODFATHER", + "Question": "This S.F. Giant, Barry Bonds' godfather, got his nickname from his unique greetings to fans", + "Answer": "Say Hey Willie Mays" + }, + { + "Category": "DEAR JUNTA", + "Question": "Shortly after the death of Gen. Omar Torrijos, Manuel Noriega controlled the junta that ruled this country", + "Answer": "Panama" + }, + { + "Category": "THE FRENCH CONNECTION", + "Question": "From Old French, its [sic] what we call the person who runs the roulette table", + "Answer": "croupier" + }, + { + "Category": "THE STING", + "Question": "Singer/actor Sting played Feyd-Rautha in this David Lynch film based on a Frank Herbert novel", + "Answer": "Dune" + }, + { + "Category": "\"ROCK\"Y", + "Question": "National Guard troops escorted black students to class in this southern state capital in August 1959", + "Answer": "Little Rock" + }, + { + "Category": "THE GODFATHER", + "Question": "After the death of his mother, this future poet was taken in by his godfather John Allan in 1811", + "Answer": "Poe" + }, + { + "Category": "DEAR JUNTA", + "Question": "The \"Juntas Provinciales\" organized the Spanish resistance to this man's 1808 invasion", + "Answer": "Napoleon" + }, + { + "Category": "THE FRENCH CONNECTION", + "Question": "Campari & Pernod are good options for this pre-meal potent potable", + "Answer": "apéritif" + }, + { + "Category": "OSCARS OF THE '70s", + "Question": "Of Jack Nicholson's 5 nominations in the 1970s, this was the only movie for which he won", + "Answer": "One Flew Over the Cuckoo's Nest" + }, + { + "Category": "THE STING", + "Question": "The creature known as this \"false\" arachnid has venomous pincers & no tail", + "Answer": "a scorpion" + }, + { + "Category": "\"ROCK\"Y", + "Question": "Also known as the Mosque of Omar, it was home to the Knights Templar during the Crusades", + "Answer": "the Dome of the Rock" + }, + { + "Category": "THE GODFATHER", + "Question": "He was the royal godfather to the son of French playwright Moliere", + "Answer": "King Louis XIV" + }, + { + "Category": "DEAR JUNTA", + "Question": "This former priest was ousted in Feb. 2004, even after a U.S.-brokered deal in 1994 with the Haitian junta kept him in power", + "Answer": "Aristide" + }, + { + "Category": "OSCARS OF THE '70s", + "Question": "For her portrayal of Greta Ohlsson in a 1974 mystery, this legendary actress scored her third Oscar", + "Answer": "Ingrid Bergman" + }, + { + "Category": "THE STING", + "Question": "The WNBA team belonging to this southern city is known as The Sting", + "Answer": "Charlotte" + }, + { + "Category": "\"ROCK\"Y", + "Question": "Also called halite, this common mineral can be formed by the drying of enclosed bodies of seawater", + "Answer": "rock salt" + }, + { + "Category": "THE GODFATHER", + "Question": "After a mock funeral for this counterculture icon, his goddaughter, Winona Ryder, moved in with him", + "Answer": "Timothy Leary" + }, + { + "Category": "DEAR JUNTA", + "Question": "After the junta released activist Aung San Suu Kyi to house arrest, Japan restored aid to this country", + "Answer": "Burma" + }, + { + "Category": "THE FRENCH CONNECTION", + "Question": "A homophone for the French word for \"wheel\", you need a good one to make gumbo", + "Answer": "a roux" + }, + { + "Category": "OSCARS OF THE '70s", + "Question": "This son of a famous French impressionist painter received an honorary Oscar in 1975", + "Answer": "Jean Renoir" + }, + { + "Category": "THE STING", + "Question": "This famous FBI sting derived its name from one its fictitious enterprises, Abdul Enterprises", + "Answer": "Abscam" + }, + { + "Category": "\"ROCK\"Y", + "Question": "This peninsula in the borough of Queens is one of the principal resort areas for New Yorkers", + "Answer": "Rockaway Beach" + }, + { + "Category": "THE GODFATHER", + "Question": "This British philosopher who won a Nobel Prize in 1950 was the godchild of John Stuart Mill", + "Answer": "Bertrand Russell" + }, + { + "Category": "DEAR JUNTA", + "Question": "In 1998 Nigerian-led forces captured Freetown, ousting the junta that controlled this African country", + "Answer": "Sierra Leone" + }, + { + "Category": "THE FRENCH CONNECTION", + "Question": "From the French for \"to sort\" comes the word for this process of treating patients based on need", + "Answer": "triage" + }, + { + "Category": "SHAKESPEARE", + "Question": "2 of the 4 Shakespeare plays in which ghosts appear on stage", + "Answer": "Hamlet, Julius Caesar, Macbeth, Richard III" + }, + { + "Category": "5-LETTER CAPITALS", + "Question": "12 avenues radiate from Place Charles de Gaulle in this city", + "Answer": "Paris" + }, + { + "Category": "SPORTS", + "Question": "This Florida-born women's great who retired in 1989 wrote the World Book Encyclopedia article on tennis", + "Answer": "Chris Evert" + }, + { + "Category": "PRE-COLUMBIAN CULTURES", + "Question": "Probably the biggest big game the Clovis culture went after 11,200 years ago, it was woolly", + "Answer": "Mammoth" + }, + { + "Category": "20th CENTURY INVENTION", + "Question": "3M's Richard Drew invented it in 1930 to have something to seal the cellophane of food products", + "Answer": "Scotch tape" + }, + { + "Category": "ON THE MOVE", + "Question": "Long, flat-bottomed & painted a somber black, they're the traditional taxis of Venice", + "Answer": "Gondolas" + }, + { + "Category": "DOUBLE TALK", + "Question": "In the familiar jokes, it precedes \"Who's there?\"", + "Answer": "Knock Knock" + }, + { + "Category": "5-LETTER CAPITALS", + "Question": "Bridges crossing the Nile River in this capital include El Gama'a & El Giza", + "Answer": "Cairo" + }, + { + "Category": "SPORTS", + "Question": "In 1984 this quarterback became the first Boston College player to win the Heisman Trophy", + "Answer": "Doug Flutie" + }, + { + "Category": "PRE-COLUMBIAN CULTURES", + "Question": "The Folsom culture about 10,900 years ago had a fluted type of this weapon & a \"thrower\" for it", + "Answer": "Spear" + }, + { + "Category": "20th CENTURY INVENTION", + "Question": "Newsweek reports Westinghouse made one in 1952 that played \"How Dry I Am\" at the end of each cycle", + "Answer": "Clothes dryer" + }, + { + "Category": "ON THE MOVE", + "Question": "In 1980 the U.S. government loaned this auto company $1.5 billion; the loans were repaid within 3 years", + "Answer": "Chrysler" + }, + { + "Category": "DOUBLE TALK", + "Question": "It's a sailor's way of saying to a superior \"I understand & will obey\"", + "Answer": "Aye-Aye" + }, + { + "Category": "5-LETTER CAPITALS", + "Question": "Haiphong near the Gulf of Tonkin serves as this city's main port", + "Answer": "Hanoi" + }, + { + "Category": "SPORTS", + "Question": "Babe Ruth's father once operated a saloon on what is now center field in this Baltimore ballpark", + "Answer": "Oriole Park at Camden Yards" + }, + { + "Category": "PRE-COLUMBIAN CULTURES", + "Question": "The Anasazi, a word from this Indian language for \"ancient ones\", lived in what's now the 4 Corners area", + "Answer": "Navajo" + }, + { + "Category": "20th CENTURY INVENTION", + "Question": "In 1939 the Hydra-Matic system made this automatic in the Oldsmobile", + "Answer": "Transmission" + }, + { + "Category": "ON THE MOVE", + "Question": "This U.S. city has more miles of subway than any other subway system in the Western Hemisphere", + "Answer": "New York City" + }, + { + "Category": "DOUBLE TALK", + "Question": "This full, loose women's garment with a bright print is traditional attire in Hawaii", + "Answer": "Muumuu" + }, + { + "Category": "5-LETTER CAPITALS", + "Question": "The ancient Greeks called this Jordanian capital Philadelphia", + "Answer": "Amman" + }, + { + "Category": "SPORTS", + "Question": "In the 1997 Belmont Stakes, Touch Gold dashed this \"charmed\" horse's Triple Crown bid", + "Answer": "Silver Charm" + }, + { + "Category": "PRE-COLUMBIAN CULTURES", + "Question": "The Adena-Hopewell culture in the Ohio area was known for building these, both the burial & effigy types", + "Answer": "Mounds" + }, + { + "Category": "20th CENTURY INVENTION", + "Question": "In 1983 the first U.S. commercial call on one of these was from Chicago to a descendant of Bell in Germany", + "Answer": "Cellular phone" + }, + { + "Category": "ON THE MOVE", + "Question": "In Britain, it's a kitchen on a ship's deck; in the U.S., it's traditionally the last car on a freight train", + "Answer": "Caboose" + }, + { + "Category": "DOUBLE TALK", + "Question": "It's a hand-beaten drum used by American Indians", + "Answer": "Tom-tom" + }, + { + "Category": "5-LETTER CAPITALS", + "Question": "In 1809 one of the first revolts for independence in Latin America broke out in this Ecuadoran capital", + "Answer": "Quito" + }, + { + "Category": "SPORTS", + "Question": "National Hockey League team whose logo is seen here: (knife through a \"B\")", + "Answer": "Buffalo Sabres" + }, + { + "Category": "PRE-COLUMBIAN CULTURES", + "Question": "Warriors of this Yucatan civilization battle in the computer-enhanced mural seen here:", + "Answer": "Mayans" + }, + { + "Category": "20th CENTURY INVENTION", + "Question": "They were invented in 1947 & by the 1990s millions were being placed on a single chip", + "Answer": "Transistors" + }, + { + "Category": "ON THE MOVE", + "Question": "When it opened, it cut the distance from London to Bombay by 5,100 miles", + "Answer": "Suez Canal" + }, + { + "Category": "DOUBLE TALK", + "Question": "He's Barney & Betty Rubble's noisy son", + "Answer": "Bamm-Bamm" + }, + { + "Category": "DIARIES", + "Question": "The diary of this woman, wife of a famous aviator, describes the kidnapping of her son", + "Answer": "Anne Morrow Lindbergh" + }, + { + "Category": "TOUGH MOVIE TRIVIA", + "Question": "Kurt Russell, who later played Elvis, was in the 1963 Elvis film \"It Happened\" here", + "Answer": "At the World's Fair" + }, + { + "Category": "\"O\" YOU ANIMAL!", + "Question": "The Pacific species of this has an arm span of up to 33 feet", + "Answer": "Octopus" + }, + { + "Category": "INTERIOR DESIGN", + "Question": "The barrel species of this spiny plant can bring a touch of the desert into your home", + "Answer": "Cactus" + }, + { + "Category": "NAME THE OPERA", + "Question": "(\"Habanera\")", + "Answer": "\"Carmen\"" + }, + { + "Category": "PEOPLE WHO BECAME WORDS", + "Question": "Don't lose your head trying to name this execution device named after a French doctor", + "Answer": "Guillotine" + }, + { + "Category": "DIARIES", + "Question": "Fittingly, Samuel Pepys began keeping his famous diary on this date in 1660", + "Answer": "1-Jan" + }, + { + "Category": "TOUGH MOVIE TRIVIA", + "Question": "It's what you wear to protect yourself against the effects of the device seen here:", + "Answer": "Sunglasses" + }, + { + "Category": "\"O\" YOU ANIMAL!", + "Question": "\"Cool\" cat seen here:", + "Answer": "Ocelot" + }, + { + "Category": "INTERIOR DESIGN", + "Question": "Some 18th C. chairs had footrests to accommodate the swollen feet of sufferers from this disease", + "Answer": "Gout" + }, + { + "Category": "NAME THE OPERA", + "Question": "(Audio clip in Italian from opera about clowns)", + "Answer": "\"Pagliacci\"" + }, + { + "Category": "PEOPLE WHO BECAME WORDS", + "Question": "Up on the highwire you might wear this bodysuit named for a famous 19th century trapeze artist", + "Answer": "Leotard" + }, + { + "Category": "DIARIES", + "Question": "\"My Name Escapes Me\" is \"The Diary of A Retiring Actor\" by this portrayer of Obi-Wan Kenobi", + "Answer": "Sir Alec Guinness" + }, + { + "Category": "TOUGH MOVIE TRIVIA", + "Question": "Actor in common to the coming-to-California films \"True Romance\" & \"Kalifornia\"", + "Answer": "Brad Pitt" + }, + { + "Category": "\"O\" YOU ANIMAL!", + "Question": "It \"coughs\" out sediment by clapping its shell shut", + "Answer": "Oyster" + }, + { + "Category": "INTERIOR DESIGN", + "Question": "China & India provide many of the \"imports\" in the name of this Texas-based home furnishings retailer", + "Answer": "Pier 1 Imports" + }, + { + "Category": "NAME THE OPERA", + "Question": "(\"La Dona e Mobile\")", + "Answer": "\"Rigoletto\"" + }, + { + "Category": "PEOPLE WHO BECAME WORDS", + "Question": "This term for artillery fragments is named for a British officer who invented a new kind of shell", + "Answer": "Shrapnel" + }, + { + "Category": "DIARIES", + "Question": "This creator of Peter Rabbit devised a private code for the journals she kept in her youth", + "Answer": "Beatrix Potter" + }, + { + "Category": "TOUGH MOVIE TRIVIA", + "Question": "1996's \"Trainspotting\" was about the underground drug life in this city", + "Answer": "Edinburgh" + }, + { + "Category": "\"O\" YOU ANIMAL!", + "Question": "They might swing through the trees asking \"What's Sumatra? Nothing, what's Sumatra with you?\"", + "Answer": "Orangutan" + }, + { + "Category": "INTERIOR DESIGN", + "Question": "Type of chair seen here named for its 20th C. designer:", + "Answer": "Eames Chair" + }, + { + "Category": "NAME THE OPERA", + "Question": "(\"Triumph March\")", + "Answer": "\"Aida\"" + }, + { + "Category": "PEOPLE WHO BECAME WORDS", + "Question": "This food poisoning bacteria is named after the scientist who identified it, not a fish", + "Answer": "Salmonella" + }, + { + "Category": "DIARIES", + "Question": "The anonymous author of this diary took her title from the Jefferson Airplane song \"White Rabbit\"", + "Answer": "\"Go Ask Alice\"" + }, + { + "Category": "TOUGH MOVIE TRIVIA", + "Question": "In this 1989 film, Eddie Murphy was the adopted son of a 1930s nightclub owner played by Richard Pryor", + "Answer": "Harlem Nights" + }, + { + "Category": "\"O\" YOU ANIMAL!", + "Question": "When the giraffe invites all its taxonomic \"family\" to a party, this is the only animal that shows up", + "Answer": "Okapi" + }, + { + "Category": "INTERIOR DESIGN", + "Question": "In 1991 Charles Hall sued Aqua Queen & other companies for infringing his patent on this furniture item", + "Answer": "the waterbed" + }, + { + "Category": "PEOPLE WHO BECAME WORDS", + "Question": "She must have been hairy, as this hairstyle is named for the big-haired mistress of a French emperor", + "Answer": "Pompadour" + }, + { + "Category": "TELEVISION & HISTORY", + "Question": "When \"60 Minutes\" premiered, this man was U.S. president", + "Answer": "Lyndon B. Johnson" + }, + { + "Category": "5 BANDS", + "Question": "Appropriately, this '80s band sang, \"You can't go on thinking, nothing's wrong, who's gonna drive you home tonight?\"", + "Answer": "The Cars" + }, + { + "Category": "THE REPLACEMENTS", + "Question": "A piece that makes it to your foe's deepest row in checkers can be replaced with one of these \"royal\" ones", + "Answer": "a king" + }, + { + "Category": "THE FALL", + "Question": "In October 1967 in Tehran, he crowned himself Light of the Aryan Race, among other things", + "Answer": "the Shah" + }, + { + "Category": "THE ENGLISH BEAT", + "Question": "This city, first mentioned in 912, is the seat of Britain's oldest university, developed in the 1100s", + "Answer": "Oxford" + }, + { + "Category": "BIG \"STAR\"", + "Question": "As soon as corn is picked, its sugar begins to turn into this, so get it into the pot fast!", + "Answer": "starch" + }, + { + "Category": "5 BANDS", + "Question": "2 members of this '70s \"Ramblin' Man\" band died in bike crashes, a year apart & within 3 blocks of each other", + "Answer": "The Allman Brothers Band" + }, + { + "Category": "THE REPLACEMENTS", + "Question": "When companies do this to their stock, they replace outstanding shares with multiple new ones", + "Answer": "a split" + }, + { + "Category": "THE FALL", + "Question": "Headed by Chief Justice Charles T. Wells, the Supreme Court of this state was in the news in November 2000", + "Answer": "Florida" + }, + { + "Category": "'HUSKER DO", + "Question": "Not just a noted NYC psychiatric hospital, it's Nebraska's oldest town, established around 1822 as a fur-trading center", + "Answer": "Belleview" + }, + { + "Category": "THE ENGLISH BEAT", + "Question": "Researchers estimate its construction on Salisbury Plain in Wiltshire took about 30 million man-hours", + "Answer": "Stonehenge" + }, + { + "Category": "BIG \"STAR\"", + "Question": "In 1990 this company expanded its Seattle HQ & built a new roasting plant", + "Answer": "Starbucks" + }, + { + "Category": "5 BANDS", + "Question": "\"Fun\", \"sleazy\" & \"raucous\" are under \"moods\" at AllMusic.com for this metal band co-founded by Tommy Lee", + "Answer": "Mötley Crüe" + }, + { + "Category": "THE REPLACEMENTS", + "Question": "The \"arthro\" in \"arthroplasty\" refers to these body parts that are replaced with stainless steel or plastic ones", + "Answer": "joints" + }, + { + "Category": "THE FALL", + "Question": "In October 1983 the U.S. invaded this Caribbean country, officially to protect American medical students there", + "Answer": "Grenada" + }, + { + "Category": "THE ENGLISH BEAT", + "Question": "In 1964 a Shakespeare center was opened on Henley Street in this city", + "Answer": "Stratford-upon-Avon" + }, + { + "Category": "BIG \"STAR\"", + "Question": "This hotel & casino at 3000 Las Vegas Blvd. South cashed out in 2006", + "Answer": "the Stardust" + }, + { + "Category": "5 BANDS", + "Question": "\"Remember when we traveled 'round the world, we met a lot of people & girls\", sang this Joey McIntyre boy band", + "Answer": "New Kids on the Block" + }, + { + "Category": "THE REPLACEMENTS", + "Question": "George Williams founded the association familiarly known as this to replace life on the street with Bible study", + "Answer": "the Young Men's Christian Association" + }, + { + "Category": "THE FALL", + "Question": "On Nov. 8, 1519 the sight of his forces made the Tenochtitlaners feel like they'd \"eaten stupefying mushrooms\"", + "Answer": "Cortés" + }, + { + "Category": "'HUSKER DO", + "Question": "One of the 2 vice presidents born in Nebraska; one in 1913, the other in 1941", + "Answer": "Gerald Ford" + }, + { + "Category": "THE ENGLISH BEAT", + "Question": "You'll find the Cavern Club at 10 Mathew Street in this port city; how fab", + "Answer": "Liverpool" + }, + { + "Category": "BIG \"STAR\"", + "Question": "In WWI Germany introduced this chemical weapon, C4H8Cl2S", + "Answer": "mustard gas" + }, + { + "Category": "5 BANDS", + "Question": "\"Welcome to Paradise\"; tre cool drums for this punk-pop band who performed at 2005's Live 8", + "Answer": "Green Day" + }, + { + "Category": "THE REPLACEMENTS", + "Question": "This cell-division process in which a cell's nucleus replicates is vital for repair & replacement of worn-out cells", + "Answer": "mitosis" + }, + { + "Category": "THE FALL", + "Question": "In 1918 this date in autumn brought the signing of the armistice ending World War I", + "Answer": "11-Nov" + }, + { + "Category": "THE ENGLISH BEAT", + "Question": "Centenary Square, in the center of this city, is its main cultural center; Alabama has a city by that name as well", + "Answer": "Birmingham" + }, + { + "Category": "BIG \"STAR\"", + "Question": "It's a dessert made of eggs, sugar & milk, either baked, boiled or frozen", + "Answer": "custard" + }, + { + "Category": "MAJOR LEAGUE BASEBALL NICKNAMES", + "Question": "\"The Ryan Express\"", + "Answer": "Nolan Ryan" + }, + { + "Category": "\"O\"PERA", + "Question": "Stravinsky enlisted the help of Cocteau for a Libretto based on Sophocles' play about this Theban king", + "Answer": "Oedipus" + }, + { + "Category": "WORLD MUSEUMS", + "Question": "Hanoi, where this man died in 1969, has a museum devoted to him", + "Answer": "Ho Chi Minh" + }, + { + "Category": "LIFE SCIENCE", + "Question": "A nematode is a roundworm; a planarian's shape gives it this name", + "Answer": "a flatworm" + }, + { + "Category": "DOUBLE MEANINGS", + "Question": "I know Mike _____ his expense account, but I can't believe he'd steal legal _____ from the conference room", + "Answer": "pads" + }, + { + "Category": "MAJOR LEAGUE BASEBALL NICKNAMES", + "Question": "\"The Rocket\"", + "Answer": "Clemens" + }, + { + "Category": "\"O\"PERA", + "Question": "George finds out Lennie has a dead mouse in his pocket in this Carlisle Floyd opera based on a 1937 novel", + "Answer": "Of Mice And Men" + }, + { + "Category": "WORLD MUSEUMS", + "Question": "Totem poles & Noh masks are at the Pitt Rivers Museum, given on condition that Oxford hire a lecturer on this -ology", + "Answer": "anthropology" + }, + { + "Category": "LIFE SCIENCE", + "Question": "In colenterates like jellyfish, the cavity called the coelenteron has an opening called this--don't get too complex", + "Answer": "a mouth" + }, + { + "Category": "DOUBLE MEANINGS", + "Question": "Maybe Don needs to get more exercise; he _____ just from pulling up his _____", + "Answer": "pants" + }, + { + "Category": "MAJOR LEAGUE BASEBALL NICKNAMES", + "Question": "\"The Big Hurt\"", + "Answer": "Frank Thomas" + }, + { + "Category": "\"O\"PERA", + "Question": "Verdi's work on this General's life opens in Cyprus; Shakespeare's tale begins in Venice", + "Answer": "Otello" + }, + { + "Category": "WORLD MUSEUMS", + "Question": "\"ANZACs in France, 1969\" was a 2006 exhibit at a war museum in this capital city", + "Answer": "Canberra" + }, + { + "Category": "LIFE SCIENCE", + "Question": "In nat. selection, a ref froggus trebekus has .5 relative fitness if it produces 1/2 as many of these as a pink one", + "Answer": "offspring" + }, + { + "Category": "DOUBLE MEANINGS", + "Question": "I liked that girl with the cute little _____ nose, so to have her _____ me really hurts", + "Answer": "snub" + }, + { + "Category": "MAJOR LEAGUE BASEBALL NICKNAMES", + "Question": "Yankee batting champ \"Donnie Baseball\"", + "Answer": "Mattingly" + }, + { + "Category": "\"O\"PERA", + "Question": "Titania & Puck play a part in the Carl Maria Von Weber opera named for this king of the fairies", + "Answer": "Oberon" + }, + { + "Category": "WORLD MUSEUMS", + "Question": "A Durer collection is highlight of this city's Kunsthistorisches Museum, built up by the Hapsburgs", + "Answer": "Vienna" + }, + { + "Category": "LIFE SCIENCE", + "Question": "In a fish's 2-chambered heart, it's the chamber that receives blood from the veins", + "Answer": "atrium" + }, + { + "Category": "DOUBLE MEANINGS", + "Question": "Chairman Mao was very resourceful when he built a seaworthy _____ out of a lot of old _____ lying around", + "Answer": "junk" + }, + { + "Category": "\"O\"PERA", + "Question": "Disney World crowds might go nuts for this title knight, aka Roland, made famous by both Hande & Vivaldi", + "Answer": "Orlando" + }, + { + "Category": "WORLD MUSEUMS", + "Question": "It's the set of museums that includes the Museo Pio-Clementino, exhibiting sculpture", + "Answer": "the Vatican Museums" + }, + { + "Category": "LIFE SCIENCE", + "Question": "The 2 main types of vascular seed plants are gymnosperms & these, 80% of known green plants", + "Answer": "angiosperms" + }, + { + "Category": "DOUBLE MEANINGS", + "Question": "I started to _____ in the hot sun, but I had to grab the _____ out of Ed's belt so he wouldn't score a TD", + "Answer": "flag" + }, + { + "Category": "LITERARY TITLES", + "Question": "This 1954 book title refers to an impaled sow's head, an offering to the \"beast\"", + "Answer": "Lord of the Flies" + }, + { + "Category": "SPORTS LEGENDS", + "Question": "Barry Bonds, among others, is currently trying to break this man's home run record of 755", + "Answer": "Hank Aaron" + }, + { + "Category": "BALLET", + "Question": "Cadets attend a dance at a girls' school in \"Graduation Ball\", a ballet set in this capital of Austria", + "Answer": "Vienna" + }, + { + "Category": "CHECK OUT MY CRIB", + "Question": "A Black Molly or 2 would be perfect to keep this calming crib feature in your living room free from algae", + "Answer": "an aquarium" + }, + { + "Category": "MOUNTAINS", + "Question": "The Hoosac Mountains are a range of these \"colorful\" mountains located in Vermont", + "Answer": "the Green Mountains" + }, + { + "Category": "WORDS", + "Question": "Chat about this in your chat room: \"chat\" is merely a shortened form of this 7-letter word", + "Answer": "chatter" + }, + { + "Category": "PRESIDENTIAL LIBRARIES", + "Question": "His presidential library is about 35 miles from the Kansas City, Missouri airport", + "Answer": "Harry Truman" + }, + { + "Category": "SPORTS LEGENDS", + "Question": "This 7-time Tour de France champ said the 2006 NYC Marathon was the \"hardest physical thing\" he'd ever done", + "Answer": "Lance Armstrong" + }, + { + "Category": "BALLET", + "Question": "The 2000 ballet \"Todo Buenos Aires\" features different interpretations of this sensual ballroom dance", + "Answer": "the tango" + }, + { + "Category": "CHECK OUT MY CRIB", + "Question": "Sit down in this chair with an X-shaped frame & a canvas seat, perfect for yelling, \"Quiet on the set!\"", + "Answer": "a director's chair" + }, + { + "Category": "WORDS", + "Question": "This name for a work of art that you may carve in art class comes from the Latin for \"to carve\"", + "Answer": "sculpture" + }, + { + "Category": "SPORTS LEGENDS", + "Question": "From 1984 to 1992, 2 of the 3 players who won all the NBA MVP awards", + "Answer": "Magic Johnson & Larry Bird" + }, + { + "Category": "BALLET", + "Question": "I may say \"neigh!\" if you do a pas de cheval, a ballet step that imitates this animal", + "Answer": "a horse" + }, + { + "Category": "CHECK OUT MY CRIB", + "Question": "Chandeliers look great but nowadays don't usually use these items from which their name is derived", + "Answer": "candles" + }, + { + "Category": "MOUNTAINS", + "Question": "The Waianae Mountains in this U.S. state rise up to 4,025-foot Mt. Kaala", + "Answer": "Hawaii" + }, + { + "Category": "WORDS", + "Question": "If you say, \"I'm eating a hot dog with\" this, you could mean a chopped pickle topping or just plain enjoyment", + "Answer": "relish" + }, + { + "Category": "PRESIDENTIAL LIBRARIES", + "Question": "His library has a desk that's an exact replica of the one that his son was photographed under in 1963", + "Answer": "John F. Kennedy" + }, + { + "Category": "SPORTS LEGENDS", + "Question": "In 1904 he became the first pitcher in the American League to throw a perfect game; now an award is named for him", + "Answer": "Cy Young" + }, + { + "Category": "BALLET", + "Question": "He designed sets & costumes for \"Where the Wlid Things Are\", a ballet based on his own beloved book", + "Answer": "Maurice Sendak" + }, + { + "Category": "CHECK OUT MY CRIB", + "Question": "In the furniture sense, this synonym of \"pride\" is dressing table", + "Answer": "vanity" + }, + { + "Category": "MOUNTAINS", + "Question": "The Caucusus Mountains of Eastern Europe are predominantly found in this large country", + "Answer": "Russia" + }, + { + "Category": "WORDS", + "Question": "Someone who sees a crime is an eyewitness; someone who experiences it aurally is this similar word", + "Answer": "an earwitness" + }, + { + "Category": "SPORTS LEGENDS", + "Question": "This Czech-born woman who retired in 2006 won a record 9 Wimbledon Singles Championships", + "Answer": "Martina Navratilova" + }, + { + "Category": "BALLET", + "Question": "The Carolina Ballet debuted a 2006 work based on this stormy Shakespearean shipwreck saga", + "Answer": "The Tempest" + }, + { + "Category": "CHECK OUT MY CRIB", + "Question": "Wanna put your feet up? How about on one of these with a \"Turkish\" name", + "Answer": "an ottoman" + }, + { + "Category": "MOUNTAINS", + "Question": "Geological evidence shows that this 5,000-mile mountain chain may extend south into Antarctica", + "Answer": "the Andes" + }, + { + "Category": "WORDS", + "Question": "The name of these small towers often seen on castles comes from Old French for \"small towers\"", + "Answer": "turrets" + }, + { + "Category": "JULY", + "Question": "William Booth founded this charitable \"army\" on July 5, 1865 in London", + "Answer": "The Salvation Army" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "This \"American Idol\" judge told one contestant, \"you sounded like Cher after she's been to the dentist\"", + "Answer": "Simon Cowell" + }, + { + "Category": "LAW ENFORCEMENT", + "Question": "The truant officer may come after you if you fail to do this", + "Answer": "go to school" + }, + { + "Category": "LITERATURE", + "Question": "In chapter 52 of this novel, a boisterous crowd is gathering for Fagin's execution", + "Answer": "Oliver Twist" + }, + { + "Category": "COMPANIES YOUNGER THAN YOU", + "Question": "This commerce site founded in 1995 now also owns Skype, Paypal, & Shopping.com", + "Answer": "eBay" + }, + { + "Category": "SYNONYMS", + "Question": "As a noun, it's a synonym for \"flower\", as a verb, it's to blossom or come into one's own", + "Answer": "bloom" + }, + { + "Category": "JULY", + "Question": "On July 20, 1861 the Congress of the Confederate States began holding sessions in this Virginia city", + "Answer": "Richmond" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "This ABC series set at Mode magazine is based on the hit Columbian telenovela \"Yo Soy Betty, La Fea\"", + "Answer": "Ugly Betty" + }, + { + "Category": "LITERATURE", + "Question": "19th c. author known for writing about a \"venerable mansion\" with \"seven acutely peaked gables\"", + "Answer": "Hawthorne" + }, + { + "Category": "COMPANIES YOUNGER THAN YOU", + "Question": "The first name of this company's search engine was Backrub, as it analyzed the back links pointing to websites", + "Answer": "Google" + }, + { + "Category": "SYNONYMS", + "Question": "Synonyms for \"crowd\" include throng, flock & this word that can also mean an infatuation", + "Answer": "a crush" + }, + { + "Category": "JULY", + "Question": "A July 17, 1917 royal proclamation changed the name of the British royal family to this, like a castle", + "Answer": "Windsor" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "This Neil Patrick Harris sitcom is narrated through flashbacks from the future", + "Answer": "How I Met Your Mother" + }, + { + "Category": "LAW ENFORCEMENT", + "Question": "This agency's criminal justice information services div. has the fingerprints of more than 47 million people", + "Answer": "the FBI" + }, + { + "Category": "LITERATURE", + "Question": "People from the past appear to a brother & sister in \"Rewards and Fairies\" by this author of \"The Jungle Book\"", + "Answer": "Kipling" + }, + { + "Category": "COMPANIES YOUNGER THAN YOU", + "Question": "While a student at Northeastern, Shawn Fanning started this P2P music-sharing service that now gone legit", + "Answer": "Napster" + }, + { + "Category": "SYNONYMS", + "Question": "In court you won't hear a lawyer say \"remonstrance!\" but this synonym", + "Answer": "objection" + }, + { + "Category": "JULY", + "Question": "John Adams' dying words on this date in 1826 were that Thomas Jefferson still lived; John Adams was wrong", + "Answer": "4-Jul" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "Penn Jillette hosts this NBC game show about first impressions", + "Answer": "Identity" + }, + { + "Category": "LAW ENFORCEMENT", + "Question": "A counter-terrorism program is called \"NYPD\" this, another term for a police badge", + "Answer": "Shield" + }, + { + "Category": "LITERATURE", + "Question": "Modern novels with biblical titles include Jane Hamilton's \"The Book of Ruth\" & Toni Morrison's \"Song of\" him", + "Answer": "Solomon" + }, + { + "Category": "COMPANIES YOUNGER THAN YOU", + "Question": "After selling Broadcast.com to Yahoo! for more than $5 billion, this Dallas NBA team owner started HDNet", + "Answer": "Mark Cuban" + }, + { + "Category": "SYNONYMS", + "Question": "Back in the 19th century, ladies didn't faint but did this 5-letter synonym", + "Answer": "swoon" + }, + { + "Category": "JULY", + "Question": "In July 1893 this president underwent a secret operation to remove part of his jaw due to cancer", + "Answer": "Grover Cleveland" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "In its 1st episode, citizens of a Kansas town saw a mushroom cloud on the horizon & were cut off from the outside world", + "Answer": "Jericho" + }, + { + "Category": "LAW ENFORCEMENT", + "Question": "Not just a remark like \"the soup's too salty\", it's a formal charge a victim can swear out, leading to an arrest", + "Answer": "a complaint" + }, + { + "Category": "LITERATURE", + "Question": "Even Grendel would love Seamus Heaney's new translation of the Anglo-Saxon epic about this title geat", + "Answer": "Beowulf" + }, + { + "Category": "COMPANIES YOUNGER THAN YOU", + "Question": "Started in 2001, Verasun Energy has now become the second-leading producer of this alternative fuel", + "Answer": "ethanol" + }, + { + "Category": "SYNONYMS", + "Question": "This synonym for \"to seclude\" is also a word for part of a monastery or convent", + "Answer": "cloister" + }, + { + "Category": "ANIMALS", + "Question": "The genus of this Asian animal is Ailuropoda, & its species name, appropriately, is melanoleuca", + "Answer": "the giant panda" + }, + { + "Category": "HISTORIC AMERICANS", + "Question": "When asked how he became a hero, this president remarked, \"It was involuntary. They sank my boat\"", + "Answer": "John F. Kennedy" + }, + { + "Category": "NATIONAL FOODS", + "Question": "This breakfast treat with deep pockets was introduced to Americans at the 1964 World's Fair", + "Answer": "Belgian waffles" + }, + { + "Category": "THE PLANET URANUS", + "Question": "Observations by astronomer James Elliot in 1977 discovered 5 of these around Uranus", + "Answer": "rings" + }, + { + "Category": "PICTURE THIS", + "Question": "One of the first printed books with illustrations was a collection of this ancient man's fables in 1476", + "Answer": "Aesop" + }, + { + "Category": "ALL MY Xs", + "Question": "In 1968 the MPAA rated a film adult by giving it this many Xs", + "Answer": "1" + }, + { + "Category": "LIVE IN TEXAS", + "Question": "If you're on the road again in Texas, stop at Luck, this singer's world headquarters", + "Answer": "Willie Nelson" + }, + { + "Category": "HISTORIC AMERICANS", + "Question": "At the time of her 1937 disappearance she was married to publisher George Palmer Putnam", + "Answer": "Amelia Earhart" + }, + { + "Category": "NATIONAL FOODS", + "Question": "Thomas' is a brand of these, famed for their nooks & crannies", + "Answer": "English muffins" + }, + { + "Category": "THE PLANET URANUS", + "Question": "Of 84, 184 or 284, the length in years of one orbit by Uranus around the sun", + "Answer": "84" + }, + { + "Category": "PICTURE THIS", + "Question": "In 1964 this first lady made the first call to inaugurate the new commercial picturephone service", + "Answer": "Lady Bird Johnson" + }, + { + "Category": "ALL MY Xs", + "Question": "In a 2002 film, number of Xs on Vin Diesel's neck tattoo", + "Answer": "3" + }, + { + "Category": "LIVE IN TEXAS", + "Question": "In June 2002 this \"Men in Black\" agent & Texas rancher was reported to be shopping for a horse farm", + "Answer": "Tommy Lee Jones" + }, + { + "Category": "HISTORIC AMERICANS", + "Question": "In 1881 Louis Tiffany & others decorated the first floor of this author's mansion in Hartford, Conn.", + "Answer": "Mark Twain" + }, + { + "Category": "NATIONAL FOODS", + "Question": "This cured meat is in the classic McDonald's Egg McMuffin", + "Answer": "Canadian bacon" + }, + { + "Category": "THE PLANET URANUS", + "Question": "Uranus' 2 largest moons share their names with characters created by this author", + "Answer": "William Shakespeare" + }, + { + "Category": "PICTURE THIS", + "Question": "In 1907 the Wall Street Journal declared Percival Lowell's photo of its \"canals\" proof of intelligent life", + "Answer": "Mars" + }, + { + "Category": "ALL MY Xs", + "Question": "Claudia Silva starred in an L.A.-area theater production of \"Cuatro Equis\", this many", + "Answer": "4" + }, + { + "Category": "LIVE IN TEXAS", + "Question": "This world-famous cyclist named his home in Austin \"Casa Linda\" after his mother", + "Answer": "Lance Armstrong" + }, + { + "Category": "HISTORIC AMERICANS", + "Question": "In 1973 he resigned as governor of New York to found the Commission on Critical Choices for Americans", + "Answer": "Nelson Rockefeller" + }, + { + "Category": "NATIONAL FOODS", + "Question": "Actually an American recipe, this condiment may have been given its name because caviar was once an ingredient", + "Answer": "Russian dressing" + }, + { + "Category": "THE PLANET URANUS", + "Question": "In 1846 astronomers found this planet from the effects it had on Uranus' orbit", + "Answer": "Neptune" + }, + { + "Category": "PICTURE THIS", + "Question": "Nose art, referring to pictures on the noses of these, really took off during WWII", + "Answer": "airplanes" + }, + { + "Category": "ALL MY Xs", + "Question": "Without getting a tic-tac-toe on \"Hollywood Squares\" you could still win a game with this many Xs", + "Answer": "5" + }, + { + "Category": "LIVE IN TEXAS", + "Question": "Man from Sugarland, Texas known as \"The Hammer\" in the U.S. House of Representatives", + "Answer": "Tom DeLay" + }, + { + "Category": "HISTORIC AMERICANS", + "Question": "This attorney was the only representative of New York to sign the U.S. Constitution", + "Answer": "Alexander Hamilton" + }, + { + "Category": "NATIONAL FOODS", + "Question": "Its other names include Poor Knights of Windsor & Pain Perdu (lost bread)", + "Answer": "French toast" + }, + { + "Category": "THE PLANET URANUS", + "Question": "He discovered Uranus as well as 2 of its moons", + "Answer": "William Herschel" + }, + { + "Category": "PICTURE THIS", + "Question": "The rights to 5 of Tom Kelley's red velvet photos of this actress taken in 1949 were put on eBay in 2001, but weren't sold", + "Answer": "Marilyn Monroe" + }, + { + "Category": "ALL MY Xs", + "Question": "Maximum number of Xs that can appear on one bowler's score sheet in one game", + "Answer": "12" + }, + { + "Category": "LIVE IN TEXAS", + "Question": "This billionaire Texan was asked to testify on his Plano company's involvement in California's energy crisis", + "Answer": "H. Ross Perot" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "Jean Duvet created a series of engravings depicting the hunting of this 1-horned mythical beast", + "Answer": "unicorn" + }, + { + "Category": "ON THE GO", + "Question": "The Wright Bros.' experiments in this type of chamber in their bicycle shop led to designs of their flyer's wings", + "Answer": "wind tunnel" + }, + { + "Category": "3-NAMED AUTHORS", + "Question": "His novels include \"The Prairie\", \"The Pioneers\", & \"The Pathfinder\"", + "Answer": "James Fenimore Cooper" + }, + { + "Category": "HORSE SENSE", + "Question": "Golden Cloud had great pull with Roy Rogers under this stage name", + "Answer": "Trigger" + }, + { + "Category": "THE EMPEROR NERO", + "Question": "In the year prior to his death, Nero participated in these games in Greece", + "Answer": "Olympic Games" + }, + { + "Category": "\"BOO\"!", + "Question": "Soft woolen shoes for a baby", + "Answer": "booties" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "Francois Lemoyne painted the Hercules ceiling at this French palace & voila! became premier peintre du roi", + "Answer": "Versailles" + }, + { + "Category": "ON THE GO", + "Question": "Created in 1971 as the National Railroad Passenger Corporation, it's better known by this name", + "Answer": "Amtrak" + }, + { + "Category": "3-NAMED AUTHORS", + "Question": "She wrote \"Jo's Boys\" in 1886, a second sequel to her 1860s novel", + "Answer": "Louisa May Alcott" + }, + { + "Category": "HORSE SENSE", + "Question": "Buck, ridden by James Arness on \"Gunsmoke\", was later used by Lorne Greene on this series", + "Answer": "Bonanza" + }, + { + "Category": "THE EMPEROR NERO", + "Question": "Nero's indulgences included poetry, acting & racing these vehicles", + "Answer": "chariots" + }, + { + "Category": "\"BOO\"!", + "Question": "An illegally made product, especially a musical recording", + "Answer": "bootleg" + }, + { + "Category": "ON THE GO", + "Question": "(Sofia of the Clue Crew paddling a canoe) Some of the earliest canoes were this type of boat, made from a hollowed-out tree trunk", + "Answer": "dugout canoe" + }, + { + "Category": "3-NAMED AUTHORS", + "Question": "This \"Ship of Fools\" author won a Pulitzer & the National Book Award for her 1965 \"Collected Stories\"", + "Answer": "Katherine Anne Porter" + }, + { + "Category": "HORSE SENSE", + "Question": "The Pie was little Liz Taylor's horse in this classic", + "Answer": "National Velvet" + }, + { + "Category": "THE EMPEROR NERO", + "Question": "Contrary to myth, no evidence exists that Nero played a fiddle, or anything else, while this happened", + "Answer": "while Rome burned" + }, + { + "Category": "\"BOO\"!", + "Question": "A hidden explosive device, it sounds like a snare for a tropical seabird", + "Answer": "boobytrap" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "In 1834 Delacroix painted the lush \"Women of\" this Algerian city \"in Their Apartment\"", + "Answer": "Algiers" + }, + { + "Category": "ON THE GO", + "Question": "Lighter than a Conestoga wagon, it was named for its white canvas covering which resembled the sails of ships", + "Answer": "prairie schooner" + }, + { + "Category": "3-NAMED AUTHORS", + "Question": "The movie \"Yentl\" was based on a story by him", + "Answer": "Isaac Bashevis Singer" + }, + { + "Category": "HORSE SENSE", + "Question": "Guy Williams rode Tornado as this hero", + "Answer": "Zorro" + }, + { + "Category": "THE EMPEROR NERO", + "Question": "At age 16, Nero was proclaimed emperor by this military unit & immediately confirmed by the Senate", + "Answer": "Praetorian Guard" + }, + { + "Category": "\"BOO\"!", + "Question": "A government project of little value funded to gain political favor", + "Answer": "boondoggle" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "Talent ran in the family: this first woman to join the Impressionists was a granddaughter of the Rococo painter Fragonard", + "Answer": "Berthe Morisot" + }, + { + "Category": "ON THE GO", + "Question": "This Newfoundland capital is the easternmost terminus of the Trans-Canada Highway", + "Answer": "St. John's" + }, + { + "Category": "3-NAMED AUTHORS", + "Question": "In 2001 this novelist & short story writer's \"We Were the Mulvaneys\" was chosen for Oprah's Book Club", + "Answer": "Joyce Carol Oates" + }, + { + "Category": "HORSE SENSE", + "Question": "Shakespeare has this king saying, \"Saddle White Surrey for the field to-morrow\"", + "Answer": "Richard III" + }, + { + "Category": "\"BOO\"!", + "Question": "According to Lewis Carroll, the snark was one of these, you see", + "Answer": "boojum" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This 5-letter word can refer to one type of work by a composer, or to several works of different types", + "Answer": "opera" + }, + { + "Category": "IT BORDERS JUST ONE OTHER COUNTRY", + "Question": "Canada", + "Answer": "the United States" + }, + { + "Category": "21st CENTURY MUSIC", + "Question": "The nickname of this woman from the Black Eyed Peas is just a shortening of her last name", + "Answer": "Fergie" + }, + { + "Category": "BABY NAMES A LA SHAKESPEARE", + "Question": "Knowing it's from the Greek for \"serpent\" might turn you off this name of a doomed lass in \"Hamlet\"", + "Answer": "Ophelia" + }, + { + "Category": "YES, THAT'S \"WHITE\"", + "Question": "Turbulent rapids", + "Answer": "whitewater" + }, + { + "Category": "WHEN THE SAINTS", + "Question": "Santa Rosa de Lima is honored with festivals each August 30 in this country where she's patron saint", + "Answer": "Peru" + }, + { + "Category": "COME, HO CHI MINH", + "Question": "Ho Chi Minh is buried in this capital city", + "Answer": "Hanoi" + }, + { + "Category": "IT BORDERS JUST ONE OTHER COUNTRY", + "Question": "South Korea", + "Answer": "North Korea" + }, + { + "Category": "21st CENTURY MUSIC", + "Question": "The stage name of this R&B singer born Shaffer Smith is a play on the name of a character in \"The Matrix\"", + "Answer": "Ne-Yo" + }, + { + "Category": "BABY NAMES A LA SHAKESPEARE", + "Question": "Name a girl this after the \"Merchant of Venice\" heroine & she'll probably grow up to like fast sports cars", + "Answer": "Portia" + }, + { + "Category": "YES, THAT'S \"WHITE\"", + "Question": "Milk with butter & flour added used as a base in cooking", + "Answer": "a white sauce" + }, + { + "Category": "WHEN THE SAINTS", + "Question": "The site of this city, now the seat of Saint Johns County, Florida, was visited by Ponce de Leon in 1513", + "Answer": "St. Augustine" + }, + { + "Category": "COME, HO CHI MINH", + "Question": "Ho Chi Minh helped start Vietnam's Communist Party & in the 1920s helped start this Eur. country's Communist Party", + "Answer": "France" + }, + { + "Category": "IT BORDERS JUST ONE OTHER COUNTRY", + "Question": "Denmark", + "Answer": "Germany" + }, + { + "Category": "21st CENTURY MUSIC", + "Question": "\"Ordinary People\" singer John Stephens took on this last name, the stuff that myths are made of", + "Answer": "Legend" + }, + { + "Category": "BABY NAMES A LA SHAKESPEARE", + "Question": "If you give your son this villainous 4-letter name from \"Othello\", you're just asking for trouble", + "Answer": "Iago" + }, + { + "Category": "YES, THAT'S \"WHITE\"", + "Question": "Condition of heavy snow or fog during daylight in which visibility is lost", + "Answer": "a whiteout" + }, + { + "Category": "WHEN THE SAINTS", + "Question": "You're a Slav to the study of language if you know that this alphabet bears the name of a 9th c. saint", + "Answer": "Cyrillic" + }, + { + "Category": "COME, HO CHI MINH", + "Question": "The trail bearing Ho's name was a series of Viet Cong supply routes mostly through this neighboring nation", + "Answer": "Laos" + }, + { + "Category": "IT BORDERS JUST ONE OTHER COUNTRY", + "Question": "San Marino", + "Answer": "Italy" + }, + { + "Category": "21st CENTURY MUSIC", + "Question": "\"Icky Thump\" was a No. 1 modern rock hit for this duo", + "Answer": "the White Stripes" + }, + { + "Category": "BABY NAMES A LA SHAKESPEARE", + "Question": "I'd think twice about naming your daughter this; she might turn into a shrew like in the play", + "Answer": "Katherine" + }, + { + "Category": "YES, THAT'S \"WHITE\"", + "Question": "A chess piece, or a company involved in a friendly takeover of another", + "Answer": "a white knight" + }, + { + "Category": "WHEN THE SAINTS", + "Question": "It's the secret identity of the British detective known as \"The Saint\"", + "Answer": "Simon Templar" + }, + { + "Category": "COME, HO CHI MINH", + "Question": "Ho Chi Minh was also known by the nickname Bac Ho, meaning this relative", + "Answer": "uncle" + }, + { + "Category": "IT BORDERS JUST ONE OTHER COUNTRY", + "Question": "Brunei", + "Answer": "Malaysia" + }, + { + "Category": "21st CENTURY MUSIC", + "Question": "Brothers Chad & Mike Kroeger make up half of this rock band", + "Answer": "Nickelback" + }, + { + "Category": "BABY NAMES A LA SHAKESPEARE", + "Question": "For an eighth child, preferably a daughter, this name from \"Antony and Cleopatra\" would be fitting", + "Answer": "Octavia" + }, + { + "Category": "YES, THAT'S \"WHITE\"", + "Question": "Down a shot & name this 1973 Burt Reynolds movie", + "Answer": "White Lightning" + }, + { + "Category": "WHEN THE SAINTS", + "Question": "This Afro-Cuban belief system uses Catholic saints as representations of the spirit world", + "Answer": "Santería" + }, + { + "Category": "COME, HO CHI MINH", + "Question": "Ho Chi Minh's real family name wasn't Ho, it was this, like many other Vietnamese", + "Answer": "Nguyen" + }, + { + "Category": "BALLETS WE'VE NEVER ASKED ABOUT BEFORE", + "Question": "In Jerome Robbins' \"Celebration\", couples representing 5 countries dance this, \"step for 2\" in French", + "Answer": "pas de deux" + }, + { + "Category": "BEST MOVIE QUOTES EVER!", + "Question": "1967: \"We rob banks\"", + "Answer": "Bonnie and Clyde" + }, + { + "Category": "6 CHARACTERS IN SEARCH OF AN AUTHOR", + "Question": "D'Artagnan", + "Answer": "Dumas" + }, + { + "Category": "SYRIA'S EATING", + "Question": "Syria had to wait until 2006 for an American fast food franchise, this fowl-selling one", + "Answer": "KFC" + }, + { + "Category": "UP IN THE AIR", + "Question": "It decreases for the first 6 miles of the atmosphere, then goes way up, way down & finally up again around 55 miles high", + "Answer": "the temperature" + }, + { + "Category": "ABBREV.", + "Question": "A recent, frightening addition to our world language: WMD", + "Answer": "weapons of mass destruction" + }, + { + "Category": "BALLETS WE'VE NEVER ASKED ABOUT BEFORE", + "Question": "\"Fete Noire\" was first presented in 1971 by the fledgling dance theatre of this Manhattan area", + "Answer": "Harlem" + }, + { + "Category": "BEST MOVIE QUOTES EVER!", + "Question": "1975: \"She turned me into a newt!\"", + "Answer": "Monty Python and the Holy Grail" + }, + { + "Category": "6 CHARACTERS IN SEARCH OF AN AUTHOR", + "Question": "Harry Angstrom, aka \"Rabbit\"", + "Answer": "Updike" + }, + { + "Category": "SYRIA'S EATING", + "Question": "Mansaf is this favorite meat cooked in a yogurt sauce", + "Answer": "lamb" + }, + { + "Category": "UP IN THE AIR", + "Question": "Warm air flows deflected by the Earth's rotation create winds that were named this by business-minded mariners", + "Answer": "trade winds" + }, + { + "Category": "ABBREV.", + "Question": "Since 1871, they've aimed to please: NRA", + "Answer": "the National Rifle Association" + }, + { + "Category": "BALLETS WE'VE NEVER ASKED ABOUT BEFORE", + "Question": "In \"Harlequinade\" the hero tries to rescue Columbine with the help of the magical \"La Bonne Fee\", this in English", + "Answer": "the good fairy" + }, + { + "Category": "BEST MOVIE QUOTES EVER!", + "Question": "1999: \"Get in my belly!\" (Second in a series)", + "Answer": "Austin Powers: The Spy Who Shagged Me" + }, + { + "Category": "6 CHARACTERS IN SEARCH OF AN AUTHOR", + "Question": "Esmeralda & Claude Frollo", + "Answer": "Hugo" + }, + { + "Category": "SYRIA'S EATING", + "Question": "Sultan Ibrahim is a Mideastern name for red mullet, a type of this creature", + "Answer": "fish" + }, + { + "Category": "UP IN THE AIR", + "Question": "At under 6,000 feet, this 7-letter layered type of cloud is one of the lowest", + "Answer": "stratus" + }, + { + "Category": "ABBREV.", + "Question": "Printer particular: DPI", + "Answer": "dots per inch" + }, + { + "Category": "BALLETS WE'VE NEVER ASKED ABOUT BEFORE", + "Question": "The ballet \"Bhakti\" features 3 Hindu gods including this \"destroyer\", whose wife, Shakti, dances for him", + "Answer": "Shiva" + }, + { + "Category": "BEST MOVIE QUOTES EVER!", + "Question": "1999: \"Excuse me, I believe you have my stapler\"", + "Answer": "Office Space" + }, + { + "Category": "6 CHARACTERS IN SEARCH OF AN AUTHOR", + "Question": "Catherine Earnshaw", + "Answer": "Emily Brontë" + }, + { + "Category": "SYRIA'S EATING", + "Question": "The leaves of mulukhiya resemble those of this vegetable; we hope Syrian kids don't turn up their noses at mulukhiya", + "Answer": "spinach" + }, + { + "Category": "UP IN THE AIR", + "Question": "Pilots are leery of CAT, or clear-air this, which often occurs over mountains & around thunderstorms", + "Answer": "turbulence" + }, + { + "Category": "ABBREV.", + "Question": "You can bank on it: FDIC", + "Answer": "Federal Deposit Insurance Corporation" + }, + { + "Category": "BALLETS WE'VE NEVER ASKED ABOUT BEFORE", + "Question": "The 1969 ballet \"Trinity\" was inspired by the peace movement in this California university city", + "Answer": "Berkeley" + }, + { + "Category": "BEST MOVIE QUOTES EVER!", + "Question": "1951: \"Nature, Mr. Allnut, is what we are put in this world to rise above\"", + "Answer": "The African Queen" + }, + { + "Category": "6 CHARACTERS IN SEARCH OF AN AUTHOR", + "Question": "Paul Baumer, a young German soldier", + "Answer": "Erich Maria Remarque" + }, + { + "Category": "SYRIA'S EATING", + "Question": "To make eish al-Saraya or \"Syrian dessert\" you need this preparation made by steeping petals in liquid", + "Answer": "rosewater" + }, + { + "Category": "UP IN THE AIR", + "Question": "From 30 to 50 miles up is this intermediate section of the atmosphere; it gets its name from the Greek for \"middle\"", + "Answer": "mesosphere" + }, + { + "Category": "ABBREV.", + "Question": "Like NAFTA, but farther south: CAFTA", + "Answer": "Central American Free Trade Agreement" + }, + { + "Category": "THE METROPOLITAN MUSEUM OF ART", + "Question": "64 paintings from the Met's founding purchase are still in its collection; over 1/3 of them are from this current European nation", + "Answer": "the Netherlands" + }, + { + "Category": "THE 23rd PSALM", + "Question": "They're the first 5 words of the psalm", + "Answer": "The Lord is my shepherd" + }, + { + "Category": "GOOD SPORTSMANSHIP", + "Question": "J.P. Hayes cost himself a 2009 spot on this tour by confessing to using an unapproved ball", + "Answer": "the PGA tour" + }, + { + "Category": "SILENCE", + "Question": "In a silent one of these, the bids are written--none of that \"do I hear...\" business", + "Answer": "an auction" + }, + { + "Category": "\"V\"", + "Question": "Sabin and Salk product", + "Answer": "vaccines" + }, + { + "Category": "PUSH BY SAFIRE", + "Question": "William Safire won this prize in 1978 \"For Commentary on the Bert Lance Affair\" (\"Affair\" being Lance's banking practices)", + "Answer": "the Pulitzer" + }, + { + "Category": "THE 23rd PSALM", + "Question": "\"He maketh me to lie down in green pastures; he leadeth me beside\" these", + "Answer": "still waters" + }, + { + "Category": "GOOD SPORTSMANSHIP", + "Question": "In 2008 Central Wash. players of this sport carried injured Sara Tucholsky of Western Oregon around the bases", + "Answer": "softball" + }, + { + "Category": "SILENCE", + "Question": "The journal of this quiet type of institution gives an award for the one \"of the Year\"; in 2010 it was in Columbus", + "Answer": "a library" + }, + { + "Category": "\"V\"", + "Question": "A tramp or wanderer", + "Answer": "a vagabond" + }, + { + "Category": "PUSH BY SAFIRE", + "Question": "Safire wrote, \"A president's ability to deflect charges of sleaze...aimed at his administration\" was a this-coated presidency", + "Answer": "teflon" + }, + { + "Category": "THE 23rd PSALM", + "Question": "These 2 items, \"they comfort me\"", + "Answer": "rod & staff" + }, + { + "Category": "GOOD SPORTSMANSHIP", + "Question": "Mike Bossy & Alexander Mogilny have won the Lady Byng Trophy for gentlemanly conduct in this sport", + "Answer": "hockey" + }, + { + "Category": "SILENCE", + "Question": "The type used for a trumpet or sax is more familiar, but string instruments can be muffled with this device", + "Answer": "a mute" + }, + { + "Category": "\"V\"", + "Question": "A silk textile with a short, smooth surface, or the covering on deer's developing antlers", + "Answer": "velvet" + }, + { + "Category": "PUSH BY SAFIRE", + "Question": "In 2006 George W. Bush awarded Safire this \"presidential\" item, the highest honor given to civilians", + "Answer": "the Medal of Freedom" + }, + { + "Category": "THE 23rd PSALM", + "Question": "\"Thou preparest a table before me in the presence of\" these", + "Answer": "mine enemies" + }, + { + "Category": "GOOD SPORTSMANSHIP", + "Question": "The chronicles of this hard-serving American include, in 2005, calling an opponent's shot in, costing himself the match", + "Answer": "Andy Roddick" + }, + { + "Category": "SILENCE", + "Question": "No cell phone use is permitted on \"quiet cars\", begun in 2000 on this service's Philly-Washington run", + "Answer": "Amtrak" + }, + { + "Category": "\"V\"", + "Question": "9-letter word meaning to waver between courses of action", + "Answer": "vacillate" + }, + { + "Category": "PUSH BY SAFIRE", + "Question": "Safire defined \"the proof of guilt that precipitates resignations\" as this 2-word term describing a discharged firearm", + "Answer": "a smoking gun" + }, + { + "Category": "THE 23rd PSALM", + "Question": "\"Surely\" these 2 quantities \"shall follow me all the days of my life\"", + "Answer": "goodness & mercy" + }, + { + "Category": "GOOD SPORTSMANSHIP", + "Question": "This backcourt partner of Isiah Thomas on the \"bad boys\" of Detroit won the NBA's 1st Sportsmanship Award", + "Answer": "Joe Dumars" + }, + { + "Category": "SILENCE", + "Question": "The name of this branch of monks known for keeping silent comes from a 17th century Cistercian Abbey", + "Answer": "the Trappists" + }, + { + "Category": "\"V\"", + "Question": "2-word legal term for preliminary examination of jurors", + "Answer": "voir dire" + }, + { + "Category": "PUSH BY SAFIRE", + "Question": "At the American National Exhibition in Moscow in 1959, Safire corralled these 2 politicos into a mock kitchen & the 2 debated", + "Answer": "Nixon & Khrushchev" + }, + { + "Category": "WORLD LEADERS", + "Question": "Elected in 2008, president Dimitris Christofias of this divided island nation is the EU's only communist head of state", + "Answer": "Cyprus" + }, + { + "Category": "THE TREES WERE ANGRY THAT DAY, MY FRIENDS", + "Question": "An apple tree angrily slaps the hand of a Kansas girl trying to pick from it in this film", + "Answer": "The Wizard of Oz" + }, + { + "Category": "BESTSELLERS", + "Question": "Numerical title of Jeffrey Toobin's look \"Inside the Secret World of the Supreme Court\"", + "Answer": "The Nine" + }, + { + "Category": "DOW JONES INDUSTRIAL AVERAGE COMPANIES", + "Question": "There's American Express & this \"of America\"", + "Answer": "Bank" + }, + { + "Category": "PHOTOGRAPHERS", + "Question": "In April 1875 the Library of Congress gained possession of his Civil War photographic plates for $25,000", + "Answer": "Mathew Brady" + }, + { + "Category": "SAY \"CHI\"s", + "Question": "Giving up your seat to the lady proves that this medieval system is not dead", + "Answer": "chivalry" + }, + { + "Category": "WORLD LEADERS", + "Question": "Lee Myung-Bak is its head of state; he makes the news a bit less often than his counterpart to the north", + "Answer": "South Korea" + }, + { + "Category": "THE TREES WERE ANGRY THAT DAY, MY FRIENDS", + "Question": "In the third film of this title guy's animated series, Fiona's planned attack on 2 tree/ guards doesn't make them happy", + "Answer": "Shrek" + }, + { + "Category": "BESTSELLERS", + "Question": "Don Piper describes his brush with death in \"90 Minutes in\" this place", + "Answer": "Heaven" + }, + { + "Category": "DOW JONES INDUSTRIAL AVERAGE COMPANIES", + "Question": "It has a Supercenter on South 9th St. in Salina, Kansas", + "Answer": "Walmart" + }, + { + "Category": "PHOTOGRAPHERS", + "Question": "Black photographer James Van Der Zee chronicled life in this NYC section for more than a half century", + "Answer": "Harlem" + }, + { + "Category": "SAY \"CHI\"s", + "Question": "Part of a house that has its own professional sweep", + "Answer": "a chimney" + }, + { + "Category": "WORLD LEADERS", + "Question": "Serzh Sargsian is its president, Tigran Sargsian is its prime minister", + "Answer": "Armenia" + }, + { + "Category": "THE TREES WERE ANGRY THAT DAY, MY FRIENDS", + "Question": "Treebeard rallies the Ents & goes after Saruman's forces in this second film in the \"Lord of the Rings\" trilogy", + "Answer": "The Two Towers" + }, + { + "Category": "BESTSELLERS", + "Question": "A vampire series by Kerrelyn Sparks is punningly titled \"Love at\" this", + "Answer": "Stake" + }, + { + "Category": "DOW JONES INDUSTRIAL AVERAGE COMPANIES", + "Question": "Roy E., the son of its co-founder, died in December 2009", + "Answer": "Disney" + }, + { + "Category": "PHOTOGRAPHERS", + "Question": "He once said that his life was \"colored and modulated by the great earth gesture of the sierra\"", + "Answer": "Adams" + }, + { + "Category": "SAY \"CHI\"s", + "Question": "In the Army today no one outranks General George W. Casey Jr., because he's this", + "Answer": "Chief of Staff" + }, + { + "Category": "WORLD LEADERS", + "Question": "Former Sofia mayor Boyko Borissov is now its prime minister", + "Answer": "Bulgaria" + }, + { + "Category": "THE TREES WERE ANGRY THAT DAY, MY FRIENDS", + "Question": "A tree snatches Robbie in this 1982 thriller known for the catchphrase \"They're heee-reee!\"", + "Answer": "Poltergeist" + }, + { + "Category": "DOW JONES INDUSTRIAL AVERAGE COMPANIES", + "Question": "Pfounded in 18P49", + "Answer": "Pfizer" + }, + { + "Category": "PHOTOGRAPHERS", + "Question": "Her 1981 Rolling Stone cover shot of a nude John Lennon was taken hours before his murder", + "Answer": "Annie Leibovitz" + }, + { + "Category": "SAY \"CHI\"s", + "Question": "You can \"pet\" this Southwestern plant, Salvia Columbariae", + "Answer": "a chia" + }, + { + "Category": "WORLD LEADERS", + "Question": "It's prime minister Mr. Tuila'Epa, won a silver medal in archery at the 2007 South Pacific Games", + "Answer": "Samoa" + }, + { + "Category": "THE TREES WERE ANGRY THAT DAY, MY FRIENDS", + "Question": "In M. Night Shyamalan's \"The Happening\", the trees are mad at us, & Elliot Moore, played by him, must deal with it", + "Answer": "Wahlberg" + }, + { + "Category": "DOW JONES INDUSTRIAL AVERAGE COMPANIES", + "Question": "Its original purpose was to insure people on journeys", + "Answer": "Travelers" + }, + { + "Category": "PHOTOGRAPHERS", + "Question": "Mattias Klum's photo essays for this magazine include 2008's \"Borneo's Moment of Truth\"", + "Answer": "National Geographic" + }, + { + "Category": "SAY \"CHI\"s", + "Question": "Deception or trickery", + "Answer": "chicanery" + }, + { + "Category": "WORD AND PHRASE ORIGINS", + "Question": "Meaning \"rapidly\", this term began in England, referring to the speed with which the mail was delivered", + "Answer": "post haste" + }, + { + "Category": "AYE! IT'S IRELAND", + "Question": "Also called Trinity College, the university of this capital was founded in 1592", + "Answer": "Dublin" + }, + { + "Category": "PRESIDENTS IN THE CABINET", + "Question": "While Secretary of State from 1811 to 1817, he might have been asked, \"What's up, doctrine?\"", + "Answer": "James Monroe" + }, + { + "Category": "TV CASTS", + "Question": "On \"Spin City\" Michael J. Fox played Mike; this actor who replaced him plays Charlie", + "Answer": "Charlie Sheen" + }, + { + "Category": "GRAVE MATTERS", + "Question": "In 1995 these married physicists were laid to rest (again), this time at the Pantheon in Paris", + "Answer": "Pierre & Marie Curie" + }, + { + "Category": "ARTISTS & THEIR WORKS", + "Question": "Robert Delaunay is known for his colorful series of Cubist paintings of this French tower", + "Answer": "Eiffel Tower" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Aykroyd's blueprints", + "Answer": "Dan's plans" + }, + { + "Category": "AYE! IT'S IRELAND", + "Question": "Held each year in County Kildare, the Irish Derby is a famous event in this sport", + "Answer": "Horse racing" + }, + { + "Category": "PRESIDENTS IN THE CABINET", + "Question": "While Secretary of State from 1801 to 1809, he was president from 1809 to 1817", + "Answer": "James Madison" + }, + { + "Category": "TV CASTS", + "Question": "In 2000 this Oscar nominee joined the cast of \"Ally McBeal\" as a lawyer", + "Answer": "Robert Downey, Jr." + }, + { + "Category": "GRAVE MATTERS", + "Question": "In 2000, 25 years after his death, this country's last emperor Haile Selassie was laid to rest in a crypt in Addis Ababa", + "Answer": "Ethiopia" + }, + { + "Category": "ARTISTS & THEIR WORKS", + "Question": "Oh oh! Chauncey B. Ives depicted this mythological woman seen here on the verge of opening a box", + "Answer": "Pandora" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Sajak's Stetsons & sombreros", + "Answer": "Pat's hats" + }, + { + "Category": "AYE! IT'S IRELAND", + "Question": "Reflecting its lush, beautiful countryside. it's Ireland's gem of a nickname", + "Answer": "\"The Emerald Isle\"" + }, + { + "Category": "PRESIDENTS IN THE CABINET", + "Question": "Through skillful negotiation, Secretary of State Martin Van Buren got the U.S. this trade status with Turkey", + "Answer": "Most favored nation" + }, + { + "Category": "TV CASTS", + "Question": "Aliens abducted Mulder on \"The X-Files\", so Scully got partnered with this \"Terminator 2\" actor", + "Answer": "Robert Patrick" + }, + { + "Category": "GRAVE MATTERS", + "Question": "It was no laughing matter when this silent film legend's body was stolen from a Swiss cemetery in 1978", + "Answer": "Charlie Chaplin" + }, + { + "Category": "ARTISTS & THEIR WORKS", + "Question": "Marcel Duchamp coined this term to describe Alexander Calder's moving sculptures", + "Answer": "Mobiles" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "The vistas seen from Ms. Barrymore's home", + "Answer": "Drew's views" + }, + { + "Category": "AYE! IT'S IRELAND", + "Question": "One of Ireland's most important exports, it's also Ireland's most popular brand of stout beer", + "Answer": "Guinness" + }, + { + "Category": "PRESIDENTS IN THE CABINET", + "Question": "As Secretary of State, John Quincy Adams told this country to govern Florida better or cede it to the U.S.", + "Answer": "Spain" + }, + { + "Category": "TV CASTS", + "Question": "This tap dancer has a recurring role on \"Will & Grace\" as Eric McCormack's boss", + "Answer": "Gregory Hines" + }, + { + "Category": "GRAVE MATTERS", + "Question": "Wayne Newton hopes to find the remains of this tribal ancestor in Britain & bring them home to her native Virginia", + "Answer": "Pocahontas" + }, + { + "Category": "ARTISTS & THEIR WORKS", + "Question": "Conrad Witz depicted this wealthy queen with King Solomon in the 15th C. work seen here", + "Answer": "Queen of Sheba" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Harrelson's yummies", + "Answer": "Woody's goodies" + }, + { + "Category": "AYE! IT'S IRELAND", + "Question": "Ireland's national coat of arms features this traditional Irish musical instrument", + "Answer": "Harp" + }, + { + "Category": "PRESIDENTS IN THE CABINET", + "Question": "He wasn't a Secretary of State, he was Andrew Johnson's Secretary of War in 1867 & 1868", + "Answer": "Ulysses S. Grant" + }, + { + "Category": "TV CASTS", + "Question": "In 2000 this rapper-turned-actor joined the cast of \"Law & Order: Special Victims Unit\" as Richard Belzer's partner", + "Answer": "Ice-T" + }, + { + "Category": "GRAVE MATTERS", + "Question": "Thomas Crawford's best-known work, \"Armed Liberty\", is the bronze atop the dome of this American landmark", + "Answer": "U.S. Capitol Building" + }, + { + "Category": "ARTISTS & THEIR WORKS", + "Question": "In Salzburg you can visit the graves of his parents & his wife Constanze; his own location is uncertain", + "Answer": "W.A. Mozart" + }, + { + "Category": "CELEBRITY RHYME TIME", + "Question": "Hairdresser Vidal's woodwinds", + "Answer": "Sassoon's bassoons" + }, + { + "Category": "\"GREEN\" THINGS", + "Question": "It's the body part you're said to have if you've a knack for growing plants easily", + "Answer": "a green thumb" + }, + { + "Category": "LITERARY CHARACTERS", + "Question": "He said, \"My mother was an ape, and of course she couldn't tell me much about it\"", + "Answer": "Tarzan" + }, + { + "Category": "AVIARY", + "Question": "Perhaps \"imitating\" Florida, in 1929 Arkansas chose this as its state bird", + "Answer": "mockingbird" + }, + { + "Category": "NUTRITION", + "Question": "For an active woman, 20 to 25 percent of her total calorie intake should be from this; don't go all Jack Sprat", + "Answer": "fat" + }, + { + "Category": "MOVIE SONGS", + "Question": "1996: \"Don't Cry For Me, Argentina\"", + "Answer": "Evita" + }, + { + "Category": "OXYMORONS", + "Question": "The \"double\" version of this card game for one requires 2 players", + "Answer": "solitaire" + }, + { + "Category": "\"GREEN\" THINGS", + "Question": "After protecting this territory during WWII, the U.S. offered to buy it, but Denmark refused", + "Answer": "Greenland" + }, + { + "Category": "LITERARY CHARACTERS", + "Question": "In \"A Connecticut Yankee in King Arthur's Court\", his character puts Hank Morgan to sleep for 1,300 years", + "Answer": "Merlin" + }, + { + "Category": "AVIARY", + "Question": "Bob Hope claimed his mother saw his nose & cried that the doctor took the baby & left this bird", + "Answer": "stork" + }, + { + "Category": "NUTRITION", + "Question": "It's good to break a little this between friends--it supplies carbs & fiber", + "Answer": "bread" + }, + { + "Category": "MOVIE SONGS", + "Question": "1995: \"Exhale (Shoop Shoop)\"", + "Answer": "Waiting to Exhale" + }, + { + "Category": "OXYMORONS", + "Question": "In November 1996 Roy Jones, Jr. knocked down Mike McCallum & won the WBC title in this division", + "Answer": "light-heavyweight" + }, + { + "Category": "\"GREEN\" THINGS", + "Question": "A political party organized after the Civil War, or a piece of U.S. currency", + "Answer": "Greenback" + }, + { + "Category": "LITERARY CHARACTERS", + "Question": "He tells his 10-year-old sister Phoebe that he wants to be a \"catcher in the rye\"", + "Answer": "Holden Caulfield" + }, + { + "Category": "NUTRITION", + "Question": "People with hypertension should diet & limit their intake of alcohol & this chemical element", + "Answer": "sodium" + }, + { + "Category": "MOVIE SONGS", + "Question": "1991: \"(Everything I Do) I Do It For You\"", + "Answer": "Robin Hood: Prince of Thieves" + }, + { + "Category": "OXYMORONS", + "Question": "The American Academy of Pediatrics called smoking \"The leading cause of\" this oxymoron in the U.S.", + "Answer": "preventable death" + }, + { + "Category": "\"GREEN\" THINGS", + "Question": "Oh yes, this North Carolina city was the birthplace of O. Henry", + "Answer": "Greensboro" + }, + { + "Category": "LITERARY CHARACTERS", + "Question": "Emma is the first name of this title character of an 1857 Gustave Flaubert novel", + "Answer": "Madame Bovary" + }, + { + "Category": "AVIARY", + "Question": "The \"sky\" type of this songbird, of which Shelley wrote, may be gone from Britain by 2009", + "Answer": "skylark" + }, + { + "Category": "NUTRITION", + "Question": "The flavonoids in this may help prevent heart disease, so a \"kiss\" a day may keep the cardiologist away", + "Answer": "chocolate" + }, + { + "Category": "MOVIE SONGS", + "Question": "1969: \"Everybody's Talkin'\"", + "Answer": "Midnight Cowboy" + }, + { + "Category": "OXYMORONS", + "Question": "Roberto Benigni's film \"Life Is Beautiful\" is a beautiful example of this oxymoronic genre", + "Answer": "tragic comedy" + }, + { + "Category": "\"GREEN\" THINGS", + "Question": "A precocious redhaired little girl is the heroine of this 1908 children's book by Lucy Maud Montgomery", + "Answer": "Anne of Green Gables" + }, + { + "Category": "LITERARY CHARACTERS", + "Question": "This Sinclair Lewis real estate broker is a member of the Zenith civic booster club", + "Answer": "George Babbitt" + }, + { + "Category": "NUTRITION", + "Question": "An ounce of cheddar cheese has 200 milligrams of this, crucial to healthy bones", + "Answer": "calcium" + }, + { + "Category": "MOVIE SONGS", + "Question": "1985: \"We Don't Need Another Hero\"", + "Answer": "Mad Max Beyond Thunderdome" + }, + { + "Category": "SPORTS NAME ORIGINS", + "Question": "This racket sport takes its name from the country home of the 19th century Duke of Beaufort", + "Answer": "Badminton" + }, + { + "Category": "PSYCHOLOGY", + "Question": "In the psychology of learning, it’s “the retention of association”; in “Cats”, it’s a showstopping song", + "Answer": "memory" + }, + { + "Category": "MINERALS", + "Question": "You’ll discover not gold, but a black mark, after rubbing this “gold” on porcelain", + "Answer": "fool’s gold" + }, + { + "Category": "\"MOON\"S", + "Question": "It brings out the worst in werewolves", + "Answer": "a full moon" + }, + { + "Category": "BICYCLES", + "Question": "The woman’s bicycle without the bar was created so women could ride while wearing these", + "Answer": "a skirt" + }, + { + "Category": "GREECE", + "Question": "Goddess of wisdom for whom Athens was named", + "Answer": "Athena" + }, + { + "Category": "STUPID ANSWERS", + "Question": "It was invented in 1911 by Hans Geiger", + "Answer": "the Geiger counter" + }, + { + "Category": "PSYCHOLOGY", + "Question": "According to psychoanalytic theory, it’s part of the personality which balances the id & superego", + "Answer": "the ego" + }, + { + "Category": "MINERALS", + "Question": "A scratch test won’t reveal a mineral’s allergies, but this property", + "Answer": "hardness" + }, + { + "Category": "\"MOON\"S", + "Question": "Michael Jackson and Neil Armstrong are both experts at this", + "Answer": "the moonwalk" + }, + { + "Category": "BICYCLES", + "Question": "A German circus performer has made the Guinness record book for riding a bicycle with this distinction", + "Answer": "the smallest" + }, + { + "Category": "GREECE", + "Question": "The popular dish moussaka is layers of ground meat & this vegetable", + "Answer": "eggplant" + }, + { + "Category": "STUPID ANSWERS", + "Question": "Number of different basic shapes in a box of Post Alpha-Bits", + "Answer": "26" + }, + { + "Category": "PSYCHOLOGY", + "Question": "Standard test of responding to a key word with the 1st words which come to your mind", + "Answer": "word association" + }, + { + "Category": "\"MOON\"S", + "Question": "Every week Cybill Shepherd & Bruce Willis have been doing this on ABC", + "Answer": "Moonlighting" + }, + { + "Category": "BICYCLES", + "Question": "This French company is known for making fine bicycles as well as cars", + "Answer": "Peugeot" + }, + { + "Category": "GREECE", + "Question": "The mainland of Greece forms the southern part of this peninsula", + "Answer": "the Balkan Peninsula" + }, + { + "Category": "STUPID ANSWERS", + "Question": "In 1842, Richard Owen coined this word for “dinosaur”", + "Answer": "dinosaur" + }, + { + "Category": "PSYCHOLOGY", + "Question": "Character from group therapy on old Bob Newhart show who checked into St. Elsewhere this season", + "Answer": "Mr. Carlin" + }, + { + "Category": "BICYCLES", + "Question": "In the 1984 Olympics, Alexi Grewal won a gold medal in cycling for this country", + "Answer": "the United States" + }, + { + "Category": "GREECE", + "Question": "By tradition, the sons in a Greek family don’t marry until this happens first", + "Answer": "the daughters marry" + }, + { + "Category": "STUPID ANSWERS", + "Question": "Whole number equidistant from 5 & 7", + "Answer": "6" + }, + { + "Category": "PSYCHOLOGY", + "Question": "Founder of “individual psychology”, he broke with Freud in 1911", + "Answer": "Alfred Adler" + }, + { + "Category": "\"MOON\"S", + "Question": "“Moon shots” referred to home runs hit by this Dodger over short left field screen in L.A. Coliseum", + "Answer": "Wally Moon" + }, + { + "Category": "BICYCLES", + "Question": "1985 film that was a story of a “rebel & his bike”", + "Answer": "Pee Wee’s Big Adventure" + }, + { + "Category": "GREECE", + "Question": "The prosperous 5th century B.C. in Greece is better known as this", + "Answer": "the Golden Age" + }, + { + "Category": "STUPID ANSWERS", + "Question": "While Bugs was “introduced” in “Porky’s Hare Hunt”, Daffy was introduced in this cartoon", + "Answer": "\"Porky’s Duck Hunt\"" + }, + { + "Category": "THE 1960s", + "Question": "It’s what chewable “chocks” were", + "Answer": "vitamins" + }, + { + "Category": "COMPOSERS", + "Question": "Composers known as “the 3 B’s”", + "Answer": "Bach, Beethoven & Brahms" + }, + { + "Category": "GOVERNMENT", + "Question": "Until 1896, majority in this branch of Congress were 1st termers, now less than 10% are", + "Answer": "the House of Representatives" + }, + { + "Category": "WORD ORIGINS", + "Question": "From Dutch “kaban huis”, meaning ship’s galley, in U.S. it came to mean last car on a train", + "Answer": "the caboose" + }, + { + "Category": "THE FUNNIES", + "Question": "Profession of Rex Morgan", + "Answer": "M.D." + }, + { + "Category": "THE 1960s", + "Question": "Vanishing in the ‘60s, it’s what YUkon, KLondike & VAlencia were examples of", + "Answer": "telephone prefixes" + }, + { + "Category": "COMPOSERS", + "Question": "In 1810, the same year as Schumann, this Polish pianist & composer was born", + "Answer": "Chopin" + }, + { + "Category": "GOVERNMENT", + "Question": "This council’s members are the president, vice president, sec’y of state & sec’y of defense", + "Answer": "the National Security Council" + }, + { + "Category": "WORD ORIGINS", + "Question": "Laboratory culture dish named for the German bacteriologist who invented it", + "Answer": "a Petri dish" + }, + { + "Category": "THE FUNNIES", + "Question": "“Marmaduke” is this breed of dog", + "Answer": "a Great Dane" + }, + { + "Category": "THE 1960s", + "Question": "Turning down ABA offer of 3,500 head of cattle & 40,000 acre ranch in 1969, he signed with NBA Bucks", + "Answer": "Lew Alcindor" + }, + { + "Category": "COMPOSERS", + "Question": "Mendelssohn wrote a series of 49 piano pieces which were appropriately titled “Songs Without” these", + "Answer": "words" + }, + { + "Category": "GOVERNMENT", + "Question": "He, not the Attorney General, represents the government in cases before the Supreme Court", + "Answer": "the Solicitor General of the U.S." + }, + { + "Category": "WORD ORIGINS", + "Question": "Chinese for “work together”, it was motto of U.S. marine raiders in WWII", + "Answer": "gung ho" + }, + { + "Category": "INSECTS", + "Question": "Migration of insects thru the air is classed as active or passive, depending on use of this", + "Answer": "wind" + }, + { + "Category": "THE FUNNIES", + "Question": "Dolly, Jeffrey, Billy & P.J.", + "Answer": "the kids in the Family Circus" + }, + { + "Category": "THE 1960s", + "Question": "The last #1 song of the ‘60s, it was Diana Ross’ last song with the Supremes", + "Answer": "\"Someday We’ll Be Together\"" + }, + { + "Category": "COMPOSERS", + "Question": "Vivaldi was known as “the red priest” due to his clerical rank & this", + "Answer": "the color of his hair" + }, + { + "Category": "GOVERNMENT", + "Question": "FDR appointed Frances Perkins, 1st woman cabinet member, to head this department", + "Answer": "the Department of Labor" + }, + { + "Category": "WORD ORIGINS", + "Question": "Originally a brand applied to slaves & criminals, it has come to mean a mark of disgrace", + "Answer": "a stigma" + }, + { + "Category": "THE FUNNIES", + "Question": "The title of this Jim Unger comic refers to everyone in it, not just a single character", + "Answer": "Herman" + }, + { + "Category": "THE 1960s", + "Question": "In “Understanding Media”, he explained the Dodgers move to L.A. & fishnet stockings", + "Answer": "Marshall McLuhan" + }, + { + "Category": "COMPOSERS", + "Question": "There’s nothing fishy about his “Trout” quintet", + "Answer": "Schubert" + }, + { + "Category": "GOVERNMENT", + "Question": "In 1966, Supreme Court ruled the 24th amendment outlawed this tax on both federal & state levels", + "Answer": "the poll tax" + }, + { + "Category": "WORD ORIGINS", + "Question": "Run-down part of town, from the rough forest paths along which newly-cut logs were dragged", + "Answer": "skid row" + }, + { + "Category": "INSECTS", + "Question": "Largest North American wasp, it hunts tarantulas like a bird of prey", + "Answer": "the tarantula hawk" + }, + { + "Category": "THE FUNNIES", + "Question": "Creator of “Beetle Bailey”, whose name was defined in “B.C.” as “a dead nightcrawler”", + "Answer": "Mort Walker" + }, + { + "Category": "GAMBLING", + "Question": "Next to slots, Nevada casinos make more money from this game than any other, nearly $3/4 billion in 1985", + "Answer": "blackjack" + }, + { + "Category": "THE 1980s", + "Question": "As many as 5,000 pro-democracy demonstrators were killed in this city's Tiananmen Square", + "Answer": "Beijing" + }, + { + "Category": "ANIMATED FILMS", + "Question": "Pretty Belle falls for a prince who's been transformed into a monster in this 1991 film", + "Answer": "Beauty and the Beast" + }, + { + "Category": "FROG ANATOMY", + "Question": "It's divided into 3 chambers: 2 auricles & 1 ventricle", + "Answer": "the frog's heart" + }, + { + "Category": "THE BIBLE", + "Question": "Adam & Eve sewed leaves of this tree \"together, and made themselves aprons\"", + "Answer": "the fig tree" + }, + { + "Category": "SWEET TREATS", + "Question": "These cookies were introduced by Nabisco in 1902 in a small box imprinted to look like a circus cage", + "Answer": "Animal Crackers" + }, + { + "Category": "RHYME TIME", + "Question": "A public recreation area devoid of light", + "Answer": "a dark park" + }, + { + "Category": "THE 1980s", + "Question": "Representative Jim Wright resigned this congressional office & his seat in the House", + "Answer": "Speaker of the House" + }, + { + "Category": "ANIMATED FILMS", + "Question": "Pop star Tiffany provided the voice of Judy for this film about a space-age family", + "Answer": "The Jetsons" + }, + { + "Category": "FROG ANATOMY", + "Question": "It's attached at the front of the mouth so the frog can flick it out rapidly", + "Answer": "the frog's tongue" + }, + { + "Category": "THE BIBLE", + "Question": "God guided the Israelites out of this country with a pillar of cloud by day & of fire by night", + "Answer": "Egypt" + }, + { + "Category": "SWEET TREATS", + "Question": "From 1910 to 1912 this popcorn confection came with prize coupons instead of the prizes themselves", + "Answer": "Cracker Jack" + }, + { + "Category": "RHYME TIME", + "Question": "A cloaklike garment for a gorilla", + "Answer": "an ape cape" + }, + { + "Category": "THE 1980s", + "Question": "On Dec. 13, 1989 Pres. F.W. De Clerk met with this imprisoned African National Congress leader for the first time", + "Answer": "Nelson Mandela" + }, + { + "Category": "ANIMATED FILMS", + "Question": "One of the highlights of this film was Sebastian the Caribbean crab singing \"Under The Sea\"", + "Answer": "The Little Mermaid" + }, + { + "Category": "FROG ANATOMY", + "Question": "The frog stores liquid waste in this organ & can reabsorb water from it in dry times", + "Answer": "the bladder" + }, + { + "Category": "THE BIBLE", + "Question": "John 1:29 calls Jesus this animal \"of God, which taketh away the sin of the world\"", + "Answer": "a lamb" + }, + { + "Category": "SWEET TREATS", + "Question": "This snack cake, which turned 60 in 1990, was originally filled with banana creme, not vanilla", + "Answer": "Twinkies" + }, + { + "Category": "RHYME TIME", + "Question": "An inexpensive Army vehicle", + "Answer": "a cheap jeep" + }, + { + "Category": "THE 1980s", + "Question": "Nicolae Ceausescu was deposed as dictator of this country & executed in 1989", + "Answer": "Romania" + }, + { + "Category": "ANIMATED FILMS", + "Question": "Cruella de Vil was the villainess who kidnapped this title brood", + "Answer": "101 Dalmatians" + }, + { + "Category": "FROG ANATOMY", + "Question": "The pancreas & this 3-lobed organ provide digestive enzymes", + "Answer": "a frog liver" + }, + { + "Category": "THE BIBLE", + "Question": "This wise successor of David is also called Jedidiah, meaning \"Yahweh's beloved\"", + "Answer": "Solomon" + }, + { + "Category": "SWEET TREATS", + "Question": "Nestle says over 125,000 tons of these chocolate chip cookies are baked in the home every year", + "Answer": "Toll House Cookies" + }, + { + "Category": "RHYME TIME", + "Question": "A quick, casual kiss on the nape", + "Answer": "a neck peck" + }, + { + "Category": "THE 1980s", + "Question": "Vaclav Havel went from political prisoner to president of this country in 1989", + "Answer": "Czechoslovakia" + }, + { + "Category": "ANIMATED FILMS", + "Question": "This 1988 film told of an orphaned baby brontosaurus named Littlefoot", + "Answer": "The Land Before Time" + }, + { + "Category": "FROG ANATOMY", + "Question": "The nictitating membrane is also called the third one of these", + "Answer": "the frog's eyelid" + }, + { + "Category": "THE BIBLE", + "Question": "God instructed Noah to use this kind of wood to build the ark", + "Answer": "gopher wood" + }, + { + "Category": "SWEET TREATS", + "Question": "This almost cube-shaped candy was named for the developer's granddaughter, a \"hefty\" baby", + "Answer": "Chunky" + }, + { + "Category": "RHYME TIME", + "Question": "A silent mob scene", + "Answer": "a quiet riot" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Known as the \"Father of Waters\", this river drains an area of approx. 1,247,000 square miles", + "Answer": "the Mississippi" + }, + { + "Category": "LAW & GOVERNMENT", + "Question": "The constitution divides the government into three branches: Executive, Judicial & this", + "Answer": "Legislative" + }, + { + "Category": "THE BYRDS & THE BEAS", + "Question": "For her, 1st came \"All In The Family\", then came \"Maude\", the came \"The Golden Girls\"", + "Answer": "Bea Arthur" + }, + { + "Category": "DANCE", + "Question": "Some dancers get their kicks doing high kicks in this Radio City Music Hall chorus line", + "Answer": "the Rockettes" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "It's the holiday on which the Tournament of Roses & Mummers parades usually take place", + "Answer": "New Year's Day" + }, + { + "Category": "SHAKESPEAREAN CHARACTERS", + "Question": "In Act 1, Scene 1 of \"Macbeth\" this trio vanishes in \"the fog and filthy air\"", + "Answer": "the three witches" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "The westernmost and northernmost points in the U.S. are both located in this state", + "Answer": "Alaska" + }, + { + "Category": "LAW & GOVERNMENT", + "Question": "A measure defeated in 1990 would have allowed states to prosecute persons who desecrated this", + "Answer": "the American flag" + }, + { + "Category": "THE BYRDS & THE BEAS", + "Question": "In 1934 he spent several months alone near the South Pole", + "Answer": "Admiral Byrd" + }, + { + "Category": "DANCE", + "Question": "19th c. women exposed their petticoats when they did this naughty French dance also known as Le Chahut", + "Answer": "the can-can" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "Nation Fire Prevention Week always includes October 9, the anniversary of this city's 1871 fire", + "Answer": "Chicago" + }, + { + "Category": "SHAKESPEAREAN CHARACTERS", + "Question": "Soon after Hamlet finishes his \"Alas, poor Yorick!\" speech he sees this woman's funeral procession", + "Answer": "Ophelia" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "The Bluegrass region, an area of gently rolling pastures, covers the north central part of this state", + "Answer": "Kentucky" + }, + { + "Category": "LAW & GOVERNMENT", + "Question": "Though given 10 years for ratification, this amendment failed by 3 states in 1982", + "Answer": "the Equal Rights Amendment" + }, + { + "Category": "THE BYRDS & THE BEAS", + "Question": "The Victoria & Albert Museum in London has the original illustrations she did for her many kids' books", + "Answer": "Beatrix Potter" + }, + { + "Category": "DANCE", + "Question": "The 1786 Opera \"Una Cosa Rara\" featured one of the first of these Viennese dances", + "Answer": "a waltz" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "This Jewish holiday is celebrated on the first day of the lunar month of Tishri", + "Answer": "Rosh Hashanah" + }, + { + "Category": "SHAKESPEAREAN CHARACTERS", + "Question": "She says, \"that death's unnatural that kills for loving\" before Othello strangles her", + "Answer": "Desdemona" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Lake Pontchartrain & St. Bernard Parish form part of this city's northern & southern boundaries", + "Answer": "New Orleans" + }, + { + "Category": "LAW & GOVERNMENT", + "Question": "Because of its secretiveness, the American Party in the 1850s was also known by this name", + "Answer": "The Know-Nothings" + }, + { + "Category": "THE BYRDS & THE BEAS", + "Question": "He was the Senate's Minority Leader from 1980-87, then moved up to Majority Leader", + "Answer": "Robert Byrd" + }, + { + "Category": "DANCE", + "Question": "The basic floor pattern of this elegant 17th c. French court dance evolved to resemble the letter Z", + "Answer": "the minuet" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "The night before the 3rd Monday in April, lanterns are hung in the steeple of this Boston church", + "Answer": "the Old North Church" + }, + { + "Category": "SHAKESPEAREAN CHARACTERS", + "Question": "\"I am a very foolish fond old man\", he tells his daughter Cordelia", + "Answer": "King Lear" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Important dams on this river include Rock Island, Rocky Reach & Grand Coulee", + "Answer": "the Columbia River" + }, + { + "Category": "LAW & GOVERNMENT", + "Question": "In 1798 Congress passed these controversial laws dealing with foreigners & with inciting rebellion", + "Answer": "the Alien & Sedition Acts" + }, + { + "Category": "THE BYRDS & THE BEAS", + "Question": "The only country in the world today with a reigning Queen Bea", + "Answer": "the Netherlands" + }, + { + "Category": "DANCE", + "Question": "Late black choreographer whose American Dance Theatre became multiracial in the 1960s", + "Answer": "Alvin Ailey" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "Medieval Europeans believed that birds begin to mate on this day", + "Answer": "St. Valentine's Day" + }, + { + "Category": "SHAKESPEAREAN CHARACTERS", + "Question": "Portia disguises herself as a male lawyer in this play set in Italy", + "Answer": "Merchant of Venice" + }, + { + "Category": "20th CENTURY VICE PRESIDENTS", + "Question": "The only VP to become president not immediately after his vice presidential term", + "Answer": "Richard Nixon" + }, + { + "Category": "GEOGRAPH\"Y\"", + "Question": "There's an active volcano on Sicily, an island that's part of this country", + "Answer": "Italy" + }, + { + "Category": "TELEVISION", + "Question": "Ben Gould & Samantha Becker roam the halls of Bayside High as part of \"The New Class\" on this show", + "Answer": "Saved By the Bell" + }, + { + "Category": "REQUIRED READING", + "Question": "In 2 classic survival stories, it's the last name of a Swiss family & the first name of Mr. Crusoe", + "Answer": "Robinson" + }, + { + "Category": "HOMOPHONES", + "Question": "Rain heavily, or a tiny opening in the skin", + "Answer": "a pour/pore" + }, + { + "Category": "YOU DO THE MATH", + "Question": "The number of items in a dozen times the number of months in a year", + "Answer": "144" + }, + { + "Category": "ODDS & ENDS", + "Question": "The Time Almanac states \"There is little reason to believe that the architects intended\" this \"to lean\"", + "Answer": "the Leaning Tower of Pisa" + }, + { + "Category": "GEOGRAPH\"Y\"", + "Question": "It's the largest city in Utah", + "Answer": "Salt Lake City" + }, + { + "Category": "TELEVISION", + "Question": "The series finale of this Fox drama aired on May 17, 2000, 2 weeks after the last \"Party of Five\"", + "Answer": "Beverly Hills, 90210" + }, + { + "Category": "HOMOPHONES", + "Question": "Masculine, or letters & packages", + "Answer": "male/mail" + }, + { + "Category": "YOU DO THE MATH", + "Question": "The number of legs on a spider plus the number of legs on a fly", + "Answer": "14" + }, + { + "Category": "ODDS & ENDS", + "Question": "This constellation is also called The Twins", + "Answer": "Gemini" + }, + { + "Category": "GEOGRAPH\"Y\"", + "Question": "This Scandinavian country has 2 forms of its official language -- Bokmal & Nynorsk", + "Answer": "Norway" + }, + { + "Category": "TELEVISION", + "Question": "This wallaby's \"Modern Life\" takes place in O Town with his dog Spunky & his pal Heffer", + "Answer": "Rocko" + }, + { + "Category": "REQUIRED READING", + "Question": "Last name of sisters Emily & Charlotte, a 1-2 punch with \"Wuthering Heights\" & \"Jane Eyre\"", + "Answer": "Bronte" + }, + { + "Category": "HOMOPHONES", + "Question": "A walkway between sections of seats in a theater, or a small piece of land surrounded by water", + "Answer": "an aisle/isle" + }, + { + "Category": "YOU DO THE MATH", + "Question": "The number of sides on an octagon minus the number of sides on a hexagon", + "Answer": "2" + }, + { + "Category": "ODDS & ENDS", + "Question": "Room of the house in which you'd normally find a four-poster", + "Answer": "the bedroom" + }, + { + "Category": "GEOGRAPH\"Y\"", + "Question": "While many countries in Europe have been splitting up, this one got back together in 1990", + "Answer": "Germany" + }, + { + "Category": "TELEVISION", + "Question": "Alice is the housekeeper on this classic sitcom; Sam the butcher is her boyfriend", + "Answer": "The Brady Bunch" + }, + { + "Category": "REQUIRED READING", + "Question": "This 19th century American writer of scary stories also wrote the love poem \"Annabel Lee\"", + "Answer": "Poe" + }, + { + "Category": "HOMOPHONES", + "Question": "A monetary gain, or one who foretells the future", + "Answer": "profit/prophet" + }, + { + "Category": "YOU DO THE MATH", + "Question": "The number of days in a week times the number of ancient \"wonders of the world\"", + "Answer": "49" + }, + { + "Category": "ODDS & ENDS", + "Question": "To make these on your own, cube day-old bread, fry in butter, oil & garlic, then bake", + "Answer": "croutons" + }, + { + "Category": "GEOGRAPH\"Y\"", + "Question": "The last British ship of convicts pulled into this Australian city's port in 1849", + "Answer": "Sydney" + }, + { + "Category": "TELEVISION", + "Question": "On this NBC sci-fi drama, genius Jarod was played by Michael T. Weiss as a man & by Ryan Merriman as a boy", + "Answer": "The Pretender" + }, + { + "Category": "REQUIRED READING", + "Question": "In works of mythology, Ajax was one of the heroes of this country in the Trojan War", + "Answer": "Greece" + }, + { + "Category": "HOMOPHONES", + "Question": "Deserve, or a large decorative vase", + "Answer": "earn/urn" + }, + { + "Category": "YOU DO THE MATH", + "Question": "The number of events in a decathlon divided by the number of years in a decade", + "Answer": "1" + }, + { + "Category": "ODDS & ENDS", + "Question": "Odds are 1 in 3 that the American spud you're eating was grown in this state", + "Answer": "Idaho" + }, + { + "Category": "THE SOLAR SYSTEM", + "Question": "Neptune also has these features, including LeVerrier & Adams; only Saturn's can be seen through a small telescope", + "Answer": "rings" + }, + { + "Category": "HISTORY IN MOVIES", + "Question": "\"The Quest for Camelot\" featured Pierce Brosnan as the voice of this Valiant Ruler", + "Answer": "King Arthur" + }, + { + "Category": "BALLET", + "Question": "A new ballet about this puppet who yearns to be a boy had it's U.S. premiere in Atlanta in 2000", + "Answer": "Pinocchio" + }, + { + "Category": "THE SPOOKY & THE MYSTERIOUS", + "Question": "Supposedly, President Harrison is heard in the attic & Jackson haunts the Rose Bedroom in this house", + "Answer": "the White House" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "If you don't mind the cold, you can pan for this metal at Tankavaara in Finland", + "Answer": "gold" + }, + { + "Category": "QUOTATIONS", + "Question": "In a 1961 speech he said, \"...ask not what America will do for you, but what together we can do for the freedom of man\"", + "Answer": "JFK" + }, + { + "Category": "THE SOLAR SYSTEM", + "Question": "It's been estimated that this planet contains about 70% of all the material in the solar system, excluding the sun", + "Answer": "Jupiter" + }, + { + "Category": "HISTORY IN MOVIES", + "Question": "Kathy Bates played the real-life \"Unsinkable\" Molly Brown in this Leonardo DiCaprio adventure", + "Answer": "Titanic" + }, + { + "Category": "BALLET", + "Question": "\"Scrooge\" is a festive holiday ballet inspired by this beloved book", + "Answer": "A Christmas Carol" + }, + { + "Category": "THE SPOOKY & THE MYSTERIOUS", + "Question": "This \"Triangle\" near Florida has been the site of numerous maritime disasters", + "Answer": "the Bermuda Triangle" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "While visiting the city of Agra in this country, don't miss the Agra Fort & the Taj Mahal", + "Answer": "India" + }, + { + "Category": "QUOTATIONS", + "Question": "This \"Huck Finn\" author wrote \"Few things are harder to put up with than the annoyance of a good example\"", + "Answer": "Mark Twain" + }, + { + "Category": "THE SOLAR SYSTEM", + "Question": "Because of its similar size, this planet is known as Earth's \"twin\"", + "Answer": "Venus" + }, + { + "Category": "HISTORY IN MOVIES", + "Question": "\"The Prince of Egypt\" featured Ralph Fiennes as the voice of this stubborn ruler", + "Answer": "the Pharaoh" + }, + { + "Category": "BALLET", + "Question": "In a Tchaikovsky ballet, this title character is awakened with a kiss", + "Answer": "Sleeping Beauty" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "The International UFO Museum & Research Center is in this New Mexico city where some say UFOs have landed", + "Answer": "Roswell" + }, + { + "Category": "QUOTATIONS", + "Question": "This talk show host said, \"I admire, respect & adore authors\" when she was honored for her book club", + "Answer": "Oprah" + }, + { + "Category": "THE SOLAR SYSTEM", + "Question": "This planet has more in common with Triton, Neptune's largest moon, than it does with any of the other planets", + "Answer": "Pluto" + }, + { + "Category": "HISTORY IN MOVIES", + "Question": "In \"Sahara\", set in this war, German soldiers attack Humphrey Bogart at a desert oasis", + "Answer": "World War II" + }, + { + "Category": "BALLET", + "Question": "\"The Nutcracker\" often features a pas de deux bythe prince and this fairy who rules the Kingdom of Sweets", + "Answer": "the Sugarplum Fairy" + }, + { + "Category": "THE SPOOKY & THE MYSTERIOUS", + "Question": "Thousands of years ago this legendary lost continent is believed by some to have vanished beneath the waves", + "Answer": "Atlantis" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "To visit Abraham Lincoln's birthplace, you have to go to this U.S. state", + "Answer": "Kentucky" + }, + { + "Category": "QUOTATIONS", + "Question": "In 1944 she wrote in her diary, \"In spite of everything I still believe that people are really good at heart\"", + "Answer": "Anne Frank" + }, + { + "Category": "HISTORY IN MOVIES", + "Question": "In this famous film Scarlett O'Hara doesn't let the South losing the Civil War slow her down", + "Answer": "Gone With the Wind" + }, + { + "Category": "BALLET", + "Question": "\"The Steadfast Tin Soldier\" is based on a fairy tale by this famous Dane", + "Answer": "Hans Christian Andersen" + }, + { + "Category": "THE SPOOKY & THE MYSTERIOUS", + "Question": "This large dinosaur-like creature possibly lives in a large Scottish lake near Inverness", + "Answer": "the Loch Ness Monster" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "This British wax museum famed for its chamber of horrors now has a time-traveling ride in it, too", + "Answer": "Madame Tussauds" + }, + { + "Category": "QUOTATIONS", + "Question": "The preamble to the U.S. Constitution begins with these 3 words", + "Answer": "\"We the People\"" + }, + { + "Category": "FAMOUS TEENAGERS", + "Question": "This young man who turned 18 on June 21, 2000 has a dog named Widgeon & a younger brother named Harry", + "Answer": "Prince William" + }, + { + "Category": "A LITERARY TOUR", + "Question": "Head to Odense, Denmark to see his childhood home & sculptures inspired by his fairy tales", + "Answer": "Andersen" + }, + { + "Category": "COLORFUL GROUPS", + "Question": "They \"Wish You Were Here\": ____ Floyd", + "Answer": "Pink" + }, + { + "Category": "UNFORESEEN FINDS", + "Question": "In 1879 this was discovered when a scientist's food was found to be sweet from the residue of a coal tar experiment", + "Answer": "saccharin" + }, + { + "Category": "THE TITANIC", + "Question": "The only country outside the British Isles where the Titanic ever anchored", + "Answer": "France" + }, + { + "Category": "WHAT'S THAT SOUND?", + "Question": "Ports lying on the banks of this sound include Bremerton, Everett & Tacoma", + "Answer": "Puget Sound" + }, + { + "Category": "\"B\" PREPARED", + "Question": "A non-rigid flexible dirigible", + "Answer": "blimp" + }, + { + "Category": "A LITERARY TOUR", + "Question": "To see the Great Bed of Ware mentioned in \"Twelfth Night\", go to this museum named for a royal couple", + "Answer": "the Victoria and Albert Museum" + }, + { + "Category": "COLORFUL GROUPS", + "Question": "They'd like you to \"Shake Your Money Maker\": The ____ Crowes", + "Answer": "Black" + }, + { + "Category": "UNFORESEEN FINDS", + "Question": "G.E. scientists looking for synthetic rubber during WWII discovered this toy that lifts images off a page", + "Answer": "Silly Putty" + }, + { + "Category": "THE TITANIC", + "Question": "2 of these towered over the deck & were used as flagpoles & to string the wireless aerial", + "Answer": "masts" + }, + { + "Category": "WHAT'S THAT SOUND?", + "Question": "Block Island Sound separates Block Island from this tiny state's mainland", + "Answer": "Rhode Island" + }, + { + "Category": "\"B\" PREPARED", + "Question": "\"I'll Go Home With Bonnie Jean\" is one of many lively songs in this Lerner & Loewe musical", + "Answer": "Brigadoon" + }, + { + "Category": "A LITERARY TOUR", + "Question": "Have a homey lunch at this author's Salinas, California birthplace; it's now a restaurant", + "Answer": "John Steinbeck" + }, + { + "Category": "COLORFUL GROUPS", + "Question": "Leaders of a \"Seven Nation Army\": The ____ Stripes", + "Answer": "White" + }, + { + "Category": "UNFORESEEN FINDS", + "Question": "To spite a customer who complained the tubers were too thick, chef George Crum created what became this treat", + "Answer": "potato chips" + }, + { + "Category": "THE TITANIC", + "Question": "This happened between the third & fourth funnel, a fact no one knew until the Titanic was found in 1985", + "Answer": "it broke in half" + }, + { + "Category": "WHAT'S THAT SOUND?", + "Question": "This state's outer banks create Pamlico Sound, the largest lagoon on the East Coast of the United States", + "Answer": "North Carolina" + }, + { + "Category": "\"B\" PREPARED", + "Question": "This period lasted from about 3500 to 1500 B.C.", + "Answer": "the Bronze Age" + }, + { + "Category": "A LITERARY TOUR", + "Question": "Chat about Lady Chatterley at this author's birthplace museum in Nottinghamshire", + "Answer": "D.H. Lawrence" + }, + { + "Category": "COLORFUL GROUPS", + "Question": "They're \"Under The Bridge\": ____ ____ Chili Peppers", + "Answer": "Red Hot" + }, + { + "Category": "UNFORESEEN FINDS", + "Question": "This product was born when a new 3M jet-fuel hose material spilled on shoes & made them waterproof & stain-resistant", + "Answer": "Scotchgard" + }, + { + "Category": "THE TITANIC", + "Question": "The first warning of the iceberg came at 11:40 P.M. from Fred Fleet, the lookout in this platform high above the deck", + "Answer": "the crow's nest" + }, + { + "Category": "WHAT'S THAT SOUND?", + "Question": "The islands in Australia's Yampi Sound are rich in hematite, an ore of this metal", + "Answer": "iron" + }, + { + "Category": "\"B\" PREPARED", + "Question": "This U.S. government department is abbreviated B.I.A.", + "Answer": "the Bureau of Indian Affairs" + }, + { + "Category": "A LITERARY TOUR", + "Question": "Perhaps you'll draft your Nobel Prize acceptance speech at NYC's Algonquin Hotel, as this Mississippi man did in 1950", + "Answer": "Faulkner" + }, + { + "Category": "COLORFUL GROUPS", + "Question": "Hard rockers \"Burnin' For You\": ____ ____ Cult", + "Answer": "Blue Öyster" + }, + { + "Category": "UNFORESEEN FINDS", + "Question": "The idea for this device occurred when a magnetron melted a candy bar in Raytheon engineer Percy Spencer's pocket", + "Answer": "the microwave" + }, + { + "Category": "THE TITANIC", + "Question": "Gates prevented 700 of these passengers from getting up to the main deck, though they didn't stop Leo in the movie", + "Answer": "third class" + }, + { + "Category": "WHAT'S THAT SOUND?", + "Question": "Antarctica's McMurdo Sound was discovered in 1841 by this Brit who has a nearby sea & ice shelf named for him", + "Answer": "Ross" + }, + { + "Category": "\"B\" PREPARED", + "Question": "Meaning a noisy commotion, it may derive from \"baruch habba\", a loud traditional greeting at a synagogue", + "Answer": "brouhaha" + }, + { + "Category": "CAESAR", + "Question": "The Arch of the Emperor Titus in Rome heralds his conquest of this city in 70 A.D., ending the Jewish revolt", + "Answer": "Jerusalem" + }, + { + "Category": "NEWMAN'S OWN", + "Question": "1969 film in which Paul Newman tells Robert Redford, \"Boy, I got vision, and the rest of the world wears bifocals\"", + "Answer": "Butch Cassidy and the Sundance Kid" + }, + { + "Category": "CRAFT", + "Question": "Saddler's pliers were created for gripping this material", + "Answer": "leather" + }, + { + "Category": "ITALIAN", + "Question": "\"Parla come mangi\", literally \"speak the way you\" do this, means to speak simply & clearly", + "Answer": "eat" + }, + { + "Category": "DRESSING", + "Question": "Traditional Highland dress includes a wide belt, presumably holding up this", + "Answer": "a kilt" + }, + { + "Category": "CAESAR", + "Question": "He was caesar & emperor when Jesus was born", + "Answer": "Augustus" + }, + { + "Category": "NEWMAN'S OWN", + "Question": "Newman played Brick opposite Liz Taylor's Maggie in this film adaptation of a play", + "Answer": "Cat on a Hot Tin Roof" + }, + { + "Category": "CRAFT", + "Question": "This word for a step in sewing a garment is also found paired with \"hawing\"", + "Answer": "hemming" + }, + { + "Category": "ITALIAN", + "Question": "Literally \"good day\", it's the basic Italian hello", + "Answer": "buon giorno" + }, + { + "Category": "DRESSING", + "Question": "The hour for mixed drinks, or the type of short evening dress appropriate then", + "Answer": "cocktail" + }, + { + "Category": "CAESAR", + "Question": "AKA the Flavian Amphitheatre, this ancient structure was begun by the Roman emperor Vespasian around 72 A.D.", + "Answer": "the Colosseum" + }, + { + "Category": "NEWMAN'S OWN", + "Question": "Paul Newman played \"Fast\" Eddie Felson in these 2 movies", + "Answer": "The Hustler & The Color of Money" + }, + { + "Category": "CRAFT", + "Question": "If you apply pieces of one material to another, you're practicing this craft, from the French for \"apply\"", + "Answer": "appliqué" + }, + { + "Category": "ITALIAN", + "Question": "The divine \"Don Giovanni\" duet \"La ci darem la mano\" means \"There, you'll give me\" this", + "Answer": "your hand" + }, + { + "Category": "DRESSING", + "Question": "In 1953 the Witty Brothers promoted the first suit made of this by having a model wear it for 67 straight days", + "Answer": "polyester" + }, + { + "Category": "CAESAR", + "Question": "According to legend, this unhinged Roman emperor made his horse a priest & a consul", + "Answer": "Caligula" + }, + { + "Category": "NEWMAN'S OWN", + "Question": "Film in which washed-up lawyer Newman redeems himself by taking a medical malpractice case to trial", + "Answer": "The Verdict" + }, + { + "Category": "CATALINA", + "Question": "Catalina had Southern Calif.'s first golf course; from 1931 to 1955 it hosted a tournament named for this Ga. great", + "Answer": "Bobby Jones" + }, + { + "Category": "CRAFT", + "Question": "With drying, drilling & maybe decorating, a gourd can be made into one of these, perhaps for a purple martin", + "Answer": "a birdhouse" + }, + { + "Category": "ITALIAN", + "Question": "From an Italian word for \"grape stalk\", it's brandy distilled from the remains of grapes after pressing", + "Answer": "grappa" + }, + { + "Category": "DRESSING", + "Question": "2-word, somewhat contradictory-sounding term for the NBA's player dress code that allows dress slacks or khakis", + "Answer": "business casual" + }, + { + "Category": "CAESAR", + "Question": "The chief figure in 2 books by Robert Graves, this emperor may have been poisoned by his fourth wife", + "Answer": "Claudius" + }, + { + "Category": "NEWMAN'S OWN", + "Question": "Newman played Irish mob boss John Rooney in Depression-era Chicago in this 2002 film", + "Answer": "Road to Perdition" + }, + { + "Category": "CRAFT", + "Question": "The tole type of this decorative activity was originally done on tin utensils but now uses lots of surfaces", + "Answer": "painting" + }, + { + "Category": "ITALIAN", + "Question": "If you're not going sinistra or destra, you're going sempre diritto, meaning this", + "Answer": "always straight" + }, + { + "Category": "DRESSING", + "Question": "Scarlett O'Hara is introduced wearing a \"tightly fitting basque\", this upper part of a dress", + "Answer": "the bodice" + }, + { + "Category": "WORLD CAPITALS", + "Question": "Started in 1988 for this city's 75th anniversary, a Springtime Flower Festival in September shows off its Commonwealth Park", + "Answer": "Canberra, Australia" + }, + { + "Category": "ISRAEL", + "Question": "If you're getting engaged, consider a visit to Netanya, a world center for cutting & polishing these", + "Answer": "diamonds" + }, + { + "Category": "ANAGRAMMED BIRDS", + "Question": "A holiday standard: key rut", + "Answer": "turkey" + }, + { + "Category": "FRANCIS SCOTT KEY", + "Question": "Washingtonians refer to the Francis Scott Key Bridge over this river as \"The Car-Strangled Spanner\"", + "Answer": "the Potomac" + }, + { + "Category": "I'LL MAKE A NOTE OF IT", + "Question": "In astrological notation, this sign is represented by 2 fish", + "Answer": "Pisces" + }, + { + "Category": "FOOD CHAIN", + "Question": "In 1979 this chain introduced its Happy Meal", + "Answer": "McDonald's" + }, + { + "Category": "HARRISON FORD MOVIES", + "Question": "\"Snakes. Why'd it have to be snakes?\"", + "Answer": "Raiders of the Lost Ark" + }, + { + "Category": "ISRAEL", + "Question": "Sde Boker, one of these cooperative communities, was the retirement home of first prime minister David Ben-Gurion", + "Answer": "kibbutz" + }, + { + "Category": "ANAGRAMMED BIRDS", + "Question": "A big African: to Chris", + "Answer": "ostrich" + }, + { + "Category": "FRANCIS SCOTT KEY", + "Question": "Part of Key's solution to this problem was helping found the American Colonization Society", + "Answer": "slavery" + }, + { + "Category": "I'LL MAKE A NOTE OF IT", + "Question": "(Sarah of the Clue Crew at the chalkboard) It's the classic game being represented here", + "Answer": "chess" + }, + { + "Category": "FOOD CHAIN", + "Question": "P.F. Chang's is an upscale bistro specializing in the cuisine of this country", + "Answer": "China" + }, + { + "Category": "HARRISON FORD MOVIES", + "Question": "\"Get off my plane!\"", + "Answer": "Air Force One" + }, + { + "Category": "ISRAEL", + "Question": "This port city on & around Mount Carmel has been compared to San Francisco, its sister city", + "Answer": "Haifa" + }, + { + "Category": "ANAGRAMMED BIRDS", + "Question": "A head-banger: cowpoke red", + "Answer": "woodpecker" + }, + { + "Category": "FRANCIS SCOTT KEY", + "Question": "Sent to this city in September 1814 to secure a prisoner exchange, Key got stuck near there during an attack", + "Answer": "Baltimore" + }, + { + "Category": "I'LL MAKE A NOTE OF IT", + "Question": "In the 1800s this Frenchman also developed a musical notation system for blind musicians", + "Answer": "Louis Braille" + }, + { + "Category": "FOOD CHAIN", + "Question": "Offering \"Home Style Meals\" & a line of frozen entrees, this chain is headquartered in Colorado, not Massachusetts", + "Answer": "Boston Market" + }, + { + "Category": "HARRISON FORD MOVIES", + "Question": "\"I didn't kill my wife!\"", + "Answer": "The Fugitive" + }, + { + "Category": "ISRAEL", + "Question": "In 1961 this Israeli airline set a record for the longest nonstop commercial flight, New York to Tel Aviv", + "Answer": "El Al" + }, + { + "Category": "ANAGRAMMED BIRDS", + "Question": "A city dweller: ego nip", + "Answer": "pigeon" + }, + { + "Category": "FRANCIS SCOTT KEY", + "Question": "James Lick of observatory fame was responsible for the Key Memorial in this San Francisco park", + "Answer": "Golden Gate Park" + }, + { + "Category": "I'LL MAKE A NOTE OF IT", + "Question": "In physics notation the speed of light is symbolized by this letter in lower case", + "Answer": "c" + }, + { + "Category": "FOOD CHAIN", + "Question": "\"Dip Into Something Different\" at the Melting Pot, found across the nation, & specializing in this Swiss dish", + "Answer": "fondue" + }, + { + "Category": "HARRISON FORD MOVIES", + "Question": "\"Replicants are like any other machine -- they're either a benefit or a hazard\"", + "Answer": "Blade Runner" + }, + { + "Category": "ISRAEL", + "Question": "Home to spectacular ruins, Caesarea was founded around 20 B.C. & named for this Caesar", + "Answer": "Augustus" + }, + { + "Category": "ANAGRAMMED BIRDS", + "Question": "A front yard favorite: I'm no flag", + "Answer": "flamingo" + }, + { + "Category": "FRANCIS SCOTT KEY", + "Question": "Key's brother-in-law & law partner Roger B. Taney served as this from 1836 to 1864", + "Answer": "Chief Justice of the Supreme Court" + }, + { + "Category": "I'LL MAKE A NOTE OF IT", + "Question": "Named for its inventor, Labanotation is a notation system for this so you know when to do a fouette", + "Answer": "dance" + }, + { + "Category": "FOOD CHAIN", + "Question": "Featuring the Famous Bloomin' Onion, this restaurant also offers a Joey Menu for kids", + "Answer": "Outback" + }, + { + "Category": "HARRISON FORD MOVIES", + "Question": "\"Something wrong with buttons?...got anything against zippers?\"", + "Answer": "Witness" + }, + { + "Category": "THE PRODUCERS", + "Question": "This central state produces more cheese than any other", + "Answer": "Wisconsin" + }, + { + "Category": "HAIRY", + "Question": "This term for a knight's apprentice is also the name of a bobbed, usually jaw-length hairstyle", + "Answer": "page boy" + }, + { + "Category": "LISA", + "Question": "She's played Phoebe Buffay on one primetime series & Phoebe's twin sister Ursula on another", + "Answer": "Lisa Kudrow" + }, + { + "Category": "ROCK-Y", + "Question": "An area in Central Park dedicated to the memory of John Lennon is named for this Beatles song", + "Answer": "\"Strawberry Fields Forever\"" + }, + { + "Category": "GEHRY", + "Question": "Though he's lived for many years in the U.S., architect Frank Gehry was born in this Ontario city of 4.5 million", + "Answer": "Toronto" + }, + { + "Category": "I'M \"L__X\"", + "Question": "It's a shorter way of saying Los Angeles International Airport", + "Answer": "LAX" + }, + { + "Category": "THE PRODUCERS", + "Question": "This state produces more lobsters than any other", + "Answer": "Maine" + }, + { + "Category": "HAIRY", + "Question": "This female ice skater lent her name to a wedge haircut she made popular during the 1976 Winter Olympics", + "Answer": "Dorothy Hamill" + }, + { + "Category": "LISA", + "Question": "In 1983 Apple introduced the Lisa personal computer, the first PC with one of these controls", + "Answer": "a mouse" + }, + { + "Category": "ROCK-Y", + "Question": "Michael Stipe formed this \"Man on the Moon\" band in Athens, Georgia", + "Answer": "R.E.M." + }, + { + "Category": "GEHRY", + "Question": "Frank Gehry's \"Easy Edges\" line built furniture out of this stuff in which your furniture usually arrives", + "Answer": "cardboard" + }, + { + "Category": "I'M \"L__X\"", + "Question": "From Middle High German, this Yiddish word means \"salmon\"", + "Answer": "lox" + }, + { + "Category": "THE PRODUCERS", + "Question": "Orange you glad to know that this state leads the U.S. in citrus production", + "Answer": "Florida" + }, + { + "Category": "HAIRY", + "Question": "Dudes, it's the \"fishy\" hairstyle worn by David Spade in \"Joe Dirt\"", + "Answer": "the mullet" + }, + { + "Category": "LISA", + "Question": "Lisa Guerrero is the sideline reporter for this popular weekly sports event", + "Answer": "Monday Night Football" + }, + { + "Category": "ROCK-Y", + "Question": "1984's \"Jump\" was the first No. 1 hit for this group that features brothers Alex & Eddie", + "Answer": "Van Halen" + }, + { + "Category": "GEHRY", + "Question": "The Gehry-designed Nationale Nederlanden Building is informally known as this film dancing pair", + "Answer": "Fred & Ginger" + }, + { + "Category": "I'M \"L__X\"", + "Question": "This \"Tax\" is found on a Monopoly board", + "Answer": "Luxury Tax" + }, + { + "Category": "THE PRODUCERS", + "Question": "It leads the states in apple production", + "Answer": "Washington" + }, + { + "Category": "HAIRY", + "Question": "The short hairstyles worn by the men who fought the Cavaliers in 17th C. England earned them this name", + "Answer": "the Roundheads" + }, + { + "Category": "LISA", + "Question": "She's the popular sports celebrity seen here", + "Answer": "Lisa Leslie" + }, + { + "Category": "ROCK-Y", + "Question": "The title of Falco's biggest hit mentions this fellow Austrian musician", + "Answer": "Mozart" + }, + { + "Category": "GEHRY", + "Question": "The Guggenheim Museum in this city of Spain's Basque region is one of the best-known structures designed by Gehry", + "Answer": "Bilbao" + }, + { + "Category": "I'M \"L__X\"", + "Question": "This city of east central Egypt is the southern half of the site of ancient Thebes", + "Answer": "Luxor" + }, + { + "Category": "THE PRODUCERS", + "Question": "This West Coast state procuces the most wind-generated energy", + "Answer": "California" + }, + { + "Category": "HAIRY", + "Question": "From the Latin for \"to clip\", it's the shaved patch on the crowns of the heads of some monks", + "Answer": "tonsure" + }, + { + "Category": "LISA", + "Question": "In 1997 Lisa Pollak won a Pulitzer Prize reporting for this Baltimore newspaper where H.L. Mencken once worked", + "Answer": "the Baltimore Sun" + }, + { + "Category": "ROCK-Y", + "Question": "His innovations include multitrack recording, overdubbing & the solid-body electric guitar", + "Answer": "Les Paul" + }, + { + "Category": "GEHRY", + "Question": "In 1989 Gehry was awarded this prize commonly referred to as \"The Nobel of Architecture\"", + "Answer": "The Pritzker Prize" + }, + { + "Category": "I'M \"L__X\"", + "Question": "From the Greek for \"of words\", it's all the words belonging to a particular branch of knowledge", + "Answer": "lexicon" + }, + { + "Category": "FAMOUS NAMES", + "Question": "A grandson of Man O' War, he defeated his uncle in a famous matchup November 1, 1938", + "Answer": "Seabiscuit" + }, + { + "Category": "ANATOMY", + "Question": "This transparent membrane in the eye covers the iris & has no blood vessels", + "Answer": "the cornea" + }, + { + "Category": "DUDE, YOU'RE A SONG!", + "Question": "\"...don't make it bad, take a sad song and make it better\"", + "Answer": "Jude" + }, + { + "Category": "ALWAYS SAY NEVER", + "Question": "There's an old expression that says these \"never prosper\"; remember that", + "Answer": "cheaters" + }, + { + "Category": "L____O", + "Question": "It's a long rope with a loop on one end, used to rope cattle", + "Answer": "a lasso" + }, + { + "Category": "AN ARTHUR BEE", + "Question": "He followed Garfield as president", + "Answer": "Chester Arthur" + }, + { + "Category": "THEN THERE'S MAUVE", + "Question": "The mauve flowers of the Paulownia tree adorn the highest grade of the Order of the Rising Sun award of this country", + "Answer": "Japan" + }, + { + "Category": "ANATOMY", + "Question": "This vein's name comes from the Latin for \"collarbone\"", + "Answer": "the jugular" + }, + { + "Category": "DUDE, YOU'RE A SONG!", + "Question": "\"...and don't you come back no more, no more, no more, no more\"", + "Answer": "Jack" + }, + { + "Category": "ALWAYS SAY NEVER", + "Question": "Line that precedes \"they simply fade away\" in a British army song", + "Answer": "Old soldiers never die" + }, + { + "Category": "L____O", + "Question": "This term for the sex drive comes from the Latin for \"lust\"", + "Answer": "libido" + }, + { + "Category": "AN ARTHUR BEE", + "Question": "Go to Flushing Meadows & see the 22,547-capacity stadium named for this man", + "Answer": "Arthur Ashe" + }, + { + "Category": "THEN THERE'S MAUVE", + "Question": "First obtained from aniline, the color mauve was the first commercially successful synthetic this", + "Answer": "a dye" + }, + { + "Category": "ANATOMY", + "Question": "The head of the femur fits into the acetabulum, a socket in this pelvic bone", + "Answer": "the hip bone" + }, + { + "Category": "DUDE, YOU'RE A SONG!", + "Question": "\"There stood a log cabin made of earth and wood, where lived a country boy named...\"", + "Answer": "Johnny B. Goode" + }, + { + "Category": "ALWAYS SAY NEVER", + "Question": "\"He that fights and runs away may\" these 5 words \"but he that is in battle slain will never rise to fight again\"", + "Answer": "live to fight another day" + }, + { + "Category": "L____O", + "Question": "How low can you go? Perhaps to this place on the border of heaven or hell", + "Answer": "limbo" + }, + { + "Category": "AN ARTHUR BEE", + "Question": "His father was Uther Pendragon", + "Answer": "King Arthur" + }, + { + "Category": "THEN THERE'S MAUVE", + "Question": "Not much mauve but lots of gray in the paintings of Anton Mauve, a member of The Hague school in this country", + "Answer": "the Netherlands" + }, + { + "Category": "ANATOMY", + "Question": "The base of the fibula forms the outer projection of this joint", + "Answer": "the ankle" + }, + { + "Category": "DUDE, YOU'RE A SONG!", + "Question": "\"Trouble ahead, trouble behind, and you know that notion just crossed my mind\" (Now we see who's the Deadhead)", + "Answer": "Casey Jones" + }, + { + "Category": "ALWAYS SAY NEVER", + "Question": "In his \"Ballad of East and West\", this Brit wrote, \"east is east and west is west and never the twain shall meet\"", + "Answer": "Kipling" + }, + { + "Category": "L____O", + "Question": "The opposite of staccato, it's a direction to play music smoothly", + "Answer": "legato" + }, + { + "Category": "AN ARTHUR BEE", + "Question": "Author of \"3001: The Final Odyssey\"", + "Answer": "Arthur C. Clarke" + }, + { + "Category": "THEN THERE'S MAUVE", + "Question": "Bella Donna Mauve is in the Color Riche line of these made by L'Oreal", + "Answer": "lipsticks" + }, + { + "Category": "ANATOMY", + "Question": "A ringlike muscle called the pyloric sphincter lies at the end of this, leading into the duodenum", + "Answer": "the stomach" + }, + { + "Category": "DUDE, YOU'RE A SONG!", + "Question": "In a Pearl Jam tune this boy \"spoke in class today\"", + "Answer": "Jeremy" + }, + { + "Category": "ALWAYS SAY NEVER", + "Question": "Shelley said of this, \"Hail to thee, blithe spirit! Bird thou never wert!\"; Wordsworth said they \"soar but never roam\"", + "Answer": "a skylark" + }, + { + "Category": "L____O", + "Question": "This term for any man who seduces & deceives women comes from a character in the 18th century play \"The Fair Penitent\"", + "Answer": "lothario" + }, + { + "Category": "AN ARTHUR BEE", + "Question": "For 50 seasons this Boston-born man was director of the Boston Pops", + "Answer": "Arthur Fiedler" + }, + { + "Category": "THEN THERE'S MAUVE", + "Question": "\"Madame de Mauves\" was an 1874 novel by this expatriate American", + "Answer": "Henry James" + }, + { + "Category": "ISLANDS", + "Question": "These islands famous for their ponies form the northernmost part of Scotland", + "Answer": "the Shetlands" + }, + { + "Category": "CALENDAR GIRLS", + "Question": "Donna Douglas played this \"Beverly Hillbillies\" gal on TV & Erika Eleniak played her in the 1993 movie", + "Answer": "Elly May" + }, + { + "Category": "POLITICAL TALK", + "Question": "Lincoln once said not to \"swap\" these \"while crossing a stream\"", + "Answer": "horses" + }, + { + "Category": "BORN IN DUBLIN", + "Question": "After the Battle of Waterloo, he said, \"Nothing except a battle lost can be half so melancholy as a battle won\"", + "Answer": "Wellington" + }, + { + "Category": "CALL ME A\"LEX\"", + "Question": "3 housing units all under one roof", + "Answer": "a triplex" + }, + { + "Category": "ISLANDS", + "Question": "Portuguese sailors originally named this island in the South China Sea Ilha Formosa, \"beautiful island\"", + "Answer": "Taiwan" + }, + { + "Category": "CALENDAR GIRLS", + "Question": "In 1963 she co-wrote \"Ring of Fire\" with Merle Kilgore", + "Answer": "Carter" + }, + { + "Category": "POLITICAL TALK", + "Question": "This type of \"son\" holds a state's convention votes together but is not a serious candidate for presidency", + "Answer": "a favorite son" + }, + { + "Category": "BORN IN DUBLIN", + "Question": "John Millington Synge wasn't born on Dublin's Synge St.; this other 3-named playwright was", + "Answer": "George Bernard Shaw" + }, + { + "Category": "CALL ME A\"LEX\"", + "Question": "Adjective meaning able to bend & snap back readily without breaking", + "Answer": "flexible" + }, + { + "Category": "ISLANDS", + "Question": "The Leeward Islands are among the \"Lesser\" of these islands; Cuba & Jamaica are among the \"Greater\"", + "Answer": "the Antilles" + }, + { + "Category": "CALENDAR GIRLS", + "Question": "Patricia Clarkson was nominated for an Oscar for \"Pieces of\" this title gal played by Katie Holmes", + "Answer": "April" + }, + { + "Category": "POLITICAL TALK", + "Question": "A \"strict\" one of these 15-letter words tends to interpret the Constitution literally", + "Answer": "a constructionist" + }, + { + "Category": "BORN IN DUBLIN", + "Question": "This red-haired beauty born in the Dublin suburb of Ranelagh played Natalie Wood's mother in \"Miracle on 34th Street\"", + "Answer": "Maureen O'Hara" + }, + { + "Category": "CALL ME A\"LEX\"", + "Question": "By profession, Noah Webster was one of these", + "Answer": "a lexicographer" + }, + { + "Category": "ISLANDS", + "Question": "In the Caribbean this island is partnered with Nevis", + "Answer": "St. Kitts" + }, + { + "Category": "POLITICAL TALK", + "Question": "According to the League of Women Voters, an \"empty chair\" one of these should be canceled", + "Answer": "debates" + }, + { + "Category": "BORN IN DUBLIN", + "Question": "His first major satire, \"A Tale of a Tub\", was published in 1704", + "Answer": "Swift" + }, + { + "Category": "CALL ME A\"LEX\"", + "Question": "Elaborate in structure or by nature", + "Answer": "complex" + }, + { + "Category": "CALENDAR GIRLS", + "Question": "Pernilla August once worked with Ingmar Bergman, but we know her best for playing Shmi in the fourth film in this series", + "Answer": "the Star Wars series" + }, + { + "Category": "POLITICAL TALK", + "Question": "Saddle up & give us this 5-letter term for an added provision that may not be germane to the purpose of a bill", + "Answer": "a rider" + }, + { + "Category": "BORN IN DUBLIN", + "Question": "This \"Babes in Toyland\" composer helped found the organization ASCAP in 1914", + "Answer": "Victor Herbert" + }, + { + "Category": "CALL ME A\"LEX\"", + "Question": "A light transparent weather-resistant man-made thermoplastic", + "Answer": "Plexiglas" + }, + { + "Category": "LITERATURE OF THE 1800s", + "Question": "This character said, \"I will live in the past, the present, and the future. The spirits of all three shall strive within me\"", + "Answer": "Ebenezer Scrooge" + }, + { + "Category": "ANATOMY", + "Question": "The layers of the skin are the epi-this, the this & the hypo-this", + "Answer": "the dermis" + }, + { + "Category": "SPORTS FACTS", + "Question": "This Giants outfielder is the only player in history to receive the MVP award 4 consecutive years, 2001 to 2004", + "Answer": "Bonds" + }, + { + "Category": "BRAND-TASTIC", + "Question": "Barry Manilow wrote the jingle that had us \"stuck on\" this brand", + "Answer": "Band-Aid" + }, + { + "Category": "APT ANAGRAMS", + "Question": "It's decorated in December: SEARCH, SET, TRIM", + "Answer": "Christmas tree" + }, + { + "Category": "A THOMAS GUIDE", + "Question": "He obtained 1,093 patents, the most the U.S. Patent Office has ever issued to one person", + "Answer": "Edison" + }, + { + "Category": "IT'S AN L.A. THING", + "Question": "Wanna live in this city, 90210? in July 2008 the median home price there was $2.3 million", + "Answer": "Beverly Hills" + }, + { + "Category": "ANATOMY", + "Question": "The uvea, the eye's middle layer, includes this contractile diaphragm, the colored part of the eye", + "Answer": "the iris" + }, + { + "Category": "SPORTS FACTS", + "Question": "In 1980 this boxer came out of retirement to fight Larry Holmes & then Trevor Berbick; he lost both bouts", + "Answer": "Ali" + }, + { + "Category": "BRAND-TASTIC", + "Question": "In 1932 George Blaisdell developed this cigarette lighter in Bradford, Pennsylvania", + "Answer": "Zippo" + }, + { + "Category": "APT ANAGRAMS", + "Question": "A \"high\" time in art: SIENNA ACRES", + "Answer": "Renaissance" + }, + { + "Category": "A THOMAS GUIDE", + "Question": "In 1989 George H.W. Bush appointed him to the U.S. Court of Appeals for the District of Columbia", + "Answer": "Clarence Thomas" + }, + { + "Category": "IT'S AN L.A. THING", + "Question": "Originally the letters in this landmark were 30 feet wide & 50 feet tall, & had 4,000 20-watt light bulbs", + "Answer": "the Hollywood sign" + }, + { + "Category": "ANATOMY", + "Question": "Each wrist has 8 of these bones, also the name of a tunnel in the wrist", + "Answer": "the carpals" + }, + { + "Category": "SPORTS FACTS", + "Question": "In 1962 this country's Dawn Fraser became the first woman swimmer to break one minute in the 100-meter freestyle", + "Answer": "Australia" + }, + { + "Category": "BRAND-TASTIC", + "Question": "Dr. Joseph Lawrence & Jordan Lambert invented this bad-breath-busting product in 1879", + "Answer": "Listerine" + }, + { + "Category": "APT ANAGRAMS", + "Question": "A Texan battle cry: A MEMORABLE TERM, EH?", + "Answer": "Remember the Alamo" + }, + { + "Category": "A THOMAS GUIDE", + "Question": "In 1952 this poet told us to \"Rage, rage against the dying of the light\"", + "Answer": "Dylan Thomas" + }, + { + "Category": "IT'S AN L.A. THING", + "Question": "Good times are Bruin in this district, home to UCLA, where John Wooden was a \"wizard\"", + "Answer": "Westwood" + }, + { + "Category": "SPORTS FACTS", + "Question": "In the 1960s he won 7 major tournaments, more than any other golfer", + "Answer": "Nicklaus" + }, + { + "Category": "BRAND-TASTIC", + "Question": "This yogurt brand is named for founder Isaac Carasso's son Daniel", + "Answer": "Dannon" + }, + { + "Category": "APT ANAGRAMS", + "Question": "He co-wrote \"South Pacific\": MASS ROMANTIC HERE", + "Answer": "Oscar Hammerstein" + }, + { + "Category": "A THOMAS GUIDE", + "Question": "His 1947 novel \"Doctor Faustus\" symbolically paralleled the rise of Nazism", + "Answer": "Thomas Mann" + }, + { + "Category": "IT'S AN L.A. THING", + "Question": "You can hit the Comedy Store, House of Blues, Whisky A Go Go & the Viper Room on this \"strip\" of L.A.", + "Answer": "Sunset Strip" + }, + { + "Category": "ANATOMY", + "Question": "Familiar to pitchers, the group of muscles called this includes the subscapularis muscle", + "Answer": "the rotator cuff" + }, + { + "Category": "SPORTS FACTS", + "Question": "Iowa state's Dan Gable won 2 NCAA titles in this sport & then coached Iowa to 15 team titles from1978 to 1997", + "Answer": "wrestling" + }, + { + "Category": "APT ANAGRAMS", + "Question": "This Internet service was big in the '90s: I ONCE RAN EMAIL", + "Answer": "America Online" + }, + { + "Category": "A THOMAS GUIDE", + "Question": "This late medieval Christian spiritual writer is the probable author of \"Imitation of Christ\"", + "Answer": "Thomas à Kempis" + }, + { + "Category": "WHO'S ON FIRST?", + "Question": "In many cities \"Jeopardy!\" leads into this sister show", + "Answer": "Wheel of Fortune" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "The Norns are counterparts of the Fates: Urd represents the past; Verdandi & Skuld, these 2 things", + "Answer": "the present & the future" + }, + { + "Category": "GIVE THE BUCHAREST", + "Question": "Times change: in 1990 a statue of this Russian was removed from a Bucharest square after 3 decades there", + "Answer": "Lenin" + }, + { + "Category": "IT'S ALL ABOUT ME", + "Question": "Excessive self-contemplation is called this anatomical gazing", + "Answer": "navel" + }, + { + "Category": "BARD BITS", + "Question": "Mark Antony called him \"the noblest Roman of them all\"", + "Answer": "Brutus" + }, + { + "Category": "CROSSWORD CLUES \"R\"", + "Question": "A stuffed pasta pocket (7)", + "Answer": "a ravioli" + }, + { + "Category": "WHO'S ON FIRST?", + "Question": "I pity the fool who doesn't know that this show led into \"Remington Steele\" on NBC's 1983-84 schedule", + "Answer": "The A-Team" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "Hymir was really hammered by the hammer of this god", + "Answer": "Thor" + }, + { + "Category": "GIVE THE BUCHAREST", + "Question": "1913's treaty of Bucharest ended the second of these peninsular wars", + "Answer": "the Balkan Wars" + }, + { + "Category": "IT'S ALL ABOUT ME", + "Question": "Self, launched in 1979, is one of these", + "Answer": "amagazine" + }, + { + "Category": "BARD BITS", + "Question": "In the first line of \"Twelfth Night\", this is described as the \"food of love\"", + "Answer": "music" + }, + { + "Category": "CROSSWORD CLUES \"R\"", + "Question": "Beam, beacon & frequency preceder (5)", + "Answer": "radar" + }, + { + "Category": "WHO'S ON FIRST?", + "Question": "Sundays from 1984 to 1995, \"60 Minutes\" led into this CBS crime drama--guess Jessica finally got tired of writing", + "Answer": "Murder, She Wrote" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "The name Midgard, the world of humans, can be translated as this, a place familiar to Tolkien", + "Answer": "Middle Earth" + }, + { + "Category": "GIVE THE BUCHAREST", + "Question": "In 1977 one of these phenomena devastated Bucharest, killing about 1,500 people", + "Answer": "an earthquake" + }, + { + "Category": "IT'S ALL ABOUT ME", + "Question": "Albrecht Durer's first known drawing, done at the age of 13, was one of these artistic efforts", + "Answer": "a self-portrait" + }, + { + "Category": "BARD BITS", + "Question": "In \"Henry VIII\" this cardinal bids \"a long farewell to all my greatness\"", + "Answer": "Cardinal Wolsey" + }, + { + "Category": "CROSSWORD CLUES \"R\"", + "Question": "Room or building in the round (7)", + "Answer": "rotunda" + }, + { + "Category": "WHO'S ON FIRST?", + "Question": "On Mondays in 1970, something called \"The Silent Force\" led into this longer-running ABC program", + "Answer": "Monday Night Football" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "Laerad is the great tree around which this hall of the slain was built", + "Answer": "Valhalla" + }, + { + "Category": "GIVE THE BUCHAREST", + "Question": "This star of 1937's \"The Last Gangster\" was born Emanuel Goldenberg in Bucharest, Romania", + "Answer": "Edward G. Robinson" + }, + { + "Category": "IT'S ALL ABOUT ME", + "Question": "Self-referential prefix before -didact, -suggestion & -biography", + "Answer": "auto" + }, + { + "Category": "BARD BITS", + "Question": "Much of the action takes place in the court of the Duke of Milan in this play with another Italian locale in its title", + "Answer": "Two Gentlemen of Verona" + }, + { + "Category": "CROSSWORD CLUES \"R\"", + "Question": "Boat race, Italian style (7)", + "Answer": "regatta" + }, + { + "Category": "WHO'S ON FIRST?", + "Question": "For the 2000-2001 season, \"The Simpsons\" led into this show that led into \"The X-Files\"--you might say it was...", + "Answer": "Malcolm In The Middle" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "This mischief-maker was up to his old tricks when he stole Freya's necklace", + "Answer": "Loki" + }, + { + "Category": "GIVE THE BUCHAREST", + "Question": "In 1659 Bucharest became the capital of this principality", + "Answer": "Wallachia" + }, + { + "Category": "IT'S ALL ABOUT ME", + "Question": "Per the \"American Psychiatric Glossary\", this mania is \"pathological preoccupation with self\"", + "Answer": "egomania" + }, + { + "Category": "BARD BITS", + "Question": "Comparing \"thee to a summer's day\" in sonnet 18, the bard realizes that \"Thou art more lovely and more\" this", + "Answer": "temperate" + }, + { + "Category": "CROSSWORD CLUES \"R\"", + "Question": "South American ostrich cousin (4)", + "Answer": "a rhea" + }, + { + "Category": "CIVIL WAR PEOPLE", + "Question": "He was the only person who died during the Civil War to be featured on Confederate currency", + "Answer": "Stonewall Jackson" + }, + { + "Category": "NOTED EUROPEANS", + "Question": "In 1863, this man from Wuppertal started a dye company that evolved into an aspirin-making giant", + "Answer": "Bayer" + }, + { + "Category": "AT THE MOVIES", + "Question": "1980: Jake LaMotta battles his way to the middleweight title", + "Answer": "Raging Bull" + }, + { + "Category": "THE HIGHEST-SCORING SCRABBLE WORD", + "Question": "Hell, heaven or limbo", + "Answer": "heaven" + }, + { + "Category": "AMERICAN COUNTIES", + "Question": "All the letters in this state's name are found in the name of its Uintah County", + "Answer": "Utah" + }, + { + "Category": "SATURDAY", + "Question": "In 1916, he sold his first of more than 300 Saturday Evening Post covers", + "Answer": "Rockwell" + }, + { + "Category": "\"NIGHT\"", + "Question": "A bedtime nip of alcohol, or the second game of a doubleheader", + "Answer": "a nightcap" + }, + { + "Category": "NOTED EUROPEANS", + "Question": "On the 50th anniv. of Bunker Hill, this European was back on our shores to lay the monument's cornerstone", + "Answer": "Lafayette" + }, + { + "Category": "THE HIGHEST-SCORING SCRABBLE WORD", + "Question": "Vow, knight or grail", + "Answer": "knight" + }, + { + "Category": "AMERICAN COUNTIES", + "Question": "Ogemaw, Saginaw & Washtenaw are all counties in this state", + "Answer": "Michigan" + }, + { + "Category": "SATURDAY", + "Question": "In a classic \"SNL\" skit, Laraine Newman found this NYC landmark less than packed when covering the Jewish New Year", + "Answer": "Times Square" + }, + { + "Category": "AT THE MOVIES", + "Question": "2002: A young Maori girl defies tradition & mounts a cetacean", + "Answer": "Whale Rider" + }, + { + "Category": "THE HIGHEST-SCORING SCRABBLE WORD", + "Question": "Happy, snappy or pappy", + "Answer": "happy" + }, + { + "Category": "AMERICAN COUNTIES", + "Question": "Name shared by the counties in which you'll find Disneyland & Disney World", + "Answer": "Orange" + }, + { + "Category": "SATURDAY", + "Question": "Established in 1875, this Louisville event is run annually on the first Saturday in May", + "Answer": "the Kentucky Derby" + }, + { + "Category": "\"NIGHT\"", + "Question": "Any of the various plants of the family Solanaceae; some may be \"deadly\"", + "Answer": "nightshades" + }, + { + "Category": "NOTED EUROPEANS", + "Question": "Giuseppina Strepponi, a prima donna in \"Nabucco\", married this famous Giuseppe in 1859", + "Answer": "Verdi" + }, + { + "Category": "AT THE MOVIES", + "Question": "1977: After an experience with a UFO, an electric-line worker is drawn to a remote mountain", + "Answer": "Close Encounters of the Third Kind" + }, + { + "Category": "THE HIGHEST-SCORING SCRABBLE WORD", + "Question": "Cozy, wax or quilt", + "Answer": "cozy" + }, + { + "Category": "AMERICAN COUNTIES", + "Question": "This state's Norfolk County disappeared in 1963 when it became part of the city of Chesapeake", + "Answer": "Virginia" + }, + { + "Category": "SATURDAY", + "Question": "Founded in 1932 as The Palestine Post, this morning paper appears daily, except for Saturday", + "Answer": "The Jerusalem Post" + }, + { + "Category": "\"NIGHT\"", + "Question": "Get to the Bottom of this Shakespeare play, published in 1600", + "Answer": "A Midsummer Night's Dream" + }, + { + "Category": "AT THE MOVIES", + "Question": "2005: A group of teenage chicks share some trousers", + "Answer": "The Sisterhood of the Traveling Pants" + }, + { + "Category": "THE HIGHEST-SCORING SCRABBLE WORD", + "Question": "Fad, dad or glad", + "Answer": "fad" + }, + { + "Category": "AMERICAN COUNTIES", + "Question": "While many states have counties named Lincoln, this is the only state that has one named Snohomish", + "Answer": "Washington" + }, + { + "Category": "SATURDAY", + "Question": "At age 3, as Bubbles Silverman, this opera star sang on a Sat. morning radio show, \"Uncle Bob's Rainbow House\"", + "Answer": "Beverly Sills" + }, + { + "Category": "\"NIGHT\"", + "Question": "\"Timely\" 5-word nickname that describes Scandinavia north of the Arctic Circle", + "Answer": "\"Land of the Midnight Sun\"" + }, + { + "Category": "SHIPS", + "Question": "On May 7, 1915 German submarine commander Walter Schweiger gave the command to torpedo this British liner", + "Answer": "the Lusitania" + }, + { + "Category": "THE MUSICAL DR. IS IN", + "Question": "This rapper & producer co-founded N.W.A. & is the stepbrother of Warren G", + "Answer": "Dr. Dre" + }, + { + "Category": "LITERARY CROSSWORD CLUES \"L\"", + "Question": "Delicious \"Doone\" damsel (5)", + "Answer": "Lorna" + }, + { + "Category": "14:59", + "Question": "This government employee was in the spotlight in the late 1990s for her conduct as a girlfriend of Monica Lewinsky", + "Answer": "Linda Tripp" + }, + { + "Category": "RELIGION", + "Question": "The Talmud says \"when\" this \"goes in, secrets are revealed\" & on the Sabbath, Kiddush is said over a cup of it", + "Answer": "wine" + }, + { + "Category": "FROM THE FRENCH", + "Question": "This type of needlework gets its name from the French for \"hook\"", + "Answer": "crochet" + }, + { + "Category": "SHIPS", + "Question": "In 1717 this pirate captured La Concorde & renamed it Queen Anne's Revenge; a year later it ran aground off N.C.", + "Answer": "Edward Teach" + }, + { + "Category": "THE MUSICAL DR. IS IN", + "Question": "\"Doctor, doctor, give me the news, I've got\" this Robert Palmer title affliction", + "Answer": "\"Bad Case Of Loving You\"" + }, + { + "Category": "LITERARY CROSSWORD CLUES \"L\"", + "Question": "Jack's \"capital\" surname (6)", + "Answer": "London" + }, + { + "Category": "14:59", + "Question": "Before her 15 minutes expired, this gal who got mixed up with televangelist Jim Bakker got onto Playboy's cover", + "Answer": "Jessica Hahn" + }, + { + "Category": "RELIGION", + "Question": "In this Asian religion, a lohan is not an actress but a holy person, & monasteries have images of lohans", + "Answer": "Buddhism" + }, + { + "Category": "FROM THE FRENCH", + "Question": "This word for any style of cooking is from the French for \"kitchen\"", + "Answer": "cuisine" + }, + { + "Category": "SHIPS", + "Question": "The 1st ship built in the colonies by English settlers was built in 1607 on the Kennebec River in what is now this state", + "Answer": "Maine" + }, + { + "Category": "THE MUSICAL DR. IS IN", + "Question": "He dealt with ophthalmological issues in the 1972 hit \"Doctor My Eyes\"", + "Answer": "Jackson Browne" + }, + { + "Category": "LITERARY CROSSWORD CLUES \"L\"", + "Question": "A singable poem, perhaps \"of the Last Minstrel\" (3)", + "Answer": "lay" + }, + { + "Category": "14:59", + "Question": "\"The joke's over\", said Simon Cowell about this \"American Idol\" singer with a unique rendition of \"She Bangs\"", + "Answer": "William Hung" + }, + { + "Category": "RELIGION", + "Question": "The Southern Convention of this denomination split from the Yankees in 1845", + "Answer": "the Baptists" + }, + { + "Category": "FROM THE FRENCH", + "Question": "A term for a keepsake or memento, it comes from the French for \"to remember\"", + "Answer": "souvenir" + }, + { + "Category": "SHIPS", + "Question": "The flagship of Oliver Hazard Perry was named for this captain who said, \"Don't give up the ship\"", + "Answer": "James Lawrence" + }, + { + "Category": "THE MUSICAL DR. IS IN", + "Question": "The \"Billboard Book of Top 40 Hits\" describes this \"Right Place Wrong Time\" man as a \"swamp-rock singer/pianist\"", + "Answer": "Dr. John" + }, + { + "Category": "LITERARY CROSSWORD CLUES \"L\"", + "Question": "Imagist Amy (6)", + "Answer": "Lowell" + }, + { + "Category": "RELIGION", + "Question": "This 13th century Italian theologian was born in Roccasecca near the town of Aquino", + "Answer": "St. Thomas Aquinas" + }, + { + "Category": "FROM THE FRENCH", + "Question": "This light tannish color gets its name from the French for \"raw\", as in raw vegetables", + "Answer": "ecru" + }, + { + "Category": "SHIPS", + "Question": "In 1994, 9 years after it was hijacked by PLF members, this Italian cruise ship burned & sank in the Indian Ocean", + "Answer": "Achille Lauro" + }, + { + "Category": "THE MUSICAL DR. IS IN", + "Question": "Despite its name, this synth-pop English band who gave us 1984's \"Doctor! Doctor!\" was a trio", + "Answer": "The Thompson Twins" + }, + { + "Category": "LITERARY CROSSWORD CLUES \"L\"", + "Question": "Writer Wyndham (5)", + "Answer": "Lewis" + }, + { + "Category": "RELIGION", + "Question": "Jainism, with 4 1/2 million adherents, was founded in this country by Mahavira, \"the Great Hero\"", + "Answer": "India" + }, + { + "Category": "FAMOUS NAMES", + "Question": "Once a top spy, he invented the mug shot seen on reward posters in the Wild West", + "Answer": "Allan Pinkerton" + }, + { + "Category": "SOCIOLOGY", + "Question": "Going from rags to riches is what sociologists call \"social\" this, specifically the \"upward\" type", + "Answer": "mobility" + }, + { + "Category": "THE STARTING INFIELD", + "Question": "In 1977 Chambliss, Randolph, Dent & Nettles took the field for this team", + "Answer": "the Yankees" + }, + { + "Category": "DICTATORS & TYRANTS", + "Question": "On Sept. 9, 1948 the DPRK, aka North Korea, was established with this man as its supreme leader", + "Answer": "Kim Il-sung" + }, + { + "Category": "THE ONION", + "Question": "Nov. 15, 2001: This pasta treat \"discontinued as Franco-American relations break down\"", + "Answer": "SpaghettiOs" + }, + { + "Category": "WORLD AUTHORS", + "Question": "This Brit coined \"doublethink\" & \"Big Brother is watching you\"", + "Answer": "Orwell" + }, + { + "Category": "CROSSWORD CLUES \"J\"", + "Question": "Carroll's slithy nonsense poem (11)", + "Answer": "\"Jabberwocky\"" + }, + { + "Category": "SOCIOLOGY", + "Question": "Expecting my son to be a cop & my daughter to be a nurse is assigning these sex-based roles", + "Answer": "gender roles" + }, + { + "Category": "THE STARTING INFIELD", + "Question": "From 1974 through 1981 the Dodgers fielded Garvey, Lopes, Russell & this third baseman, \"The Penguin\"", + "Answer": "Ron Cey" + }, + { + "Category": "DICTATORS & TYRANTS", + "Question": "As the dictator of this city-state, Francesco Foscari ruined its army & economy by endlessly fighting Milan", + "Answer": "Venice" + }, + { + "Category": "THE ONION", + "Question": "Feb. 20, 2006: This late \"Feminine Mystique\" writer \"honored with second-class postage stamp\"", + "Answer": "Friedan" + }, + { + "Category": "WORLD AUTHORS", + "Question": "In a 1605 prologue, this Spaniard tells the reader that he has written an \"invective against books of chivalry\"", + "Answer": "Cervantes" + }, + { + "Category": "CROSSWORD CLUES \"J\"", + "Question": "Jettisoned goods (6)", + "Answer": "jetsam" + }, + { + "Category": "SOCIOLOGY", + "Question": "William H. White put this word before \"think\" to mean conformity to consensus", + "Answer": "group" + }, + { + "Category": "THE STARTING INFIELD", + "Question": "The 1908 Chicago Cubs featured Harry Steinfeldt & these 3 guys of yore", + "Answer": "Tinker, Evers & Chance" + }, + { + "Category": "DICTATORS & TYRANTS", + "Question": "By murdering all his brothers around 1413, Mehmed I took power as the fifth ruler of this empire", + "Answer": "the Ottoman Empire" + }, + { + "Category": "THE ONION", + "Question": "Aug. 9, 2000: Popular names for these include Shopwood, Storemont & Indianburialgroundbrook", + "Answer": "shopping malls" + }, + { + "Category": "WORLD AUTHORS", + "Question": "While at University College, Dublin, he wrote the essay \"The Day of the Rabblement\", attacking the Irish Literary Theatre", + "Answer": "James Joyce" + }, + { + "Category": "CROSSWORD CLUES \"J\"", + "Question": "Riding breeches (8)", + "Answer": "jodhpurs" + }, + { + "Category": "SOCIOLOGY", + "Question": "A joint author on a paper, or someone who assists the power occupying his country", + "Answer": "a collaborator" + }, + { + "Category": "THE STARTING INFIELD", + "Question": "The 1955 Brooklyn Dodgers sent out Hodges, Gilliam, Reese & this groundbreaking infielder", + "Answer": "Jackie Robinson" + }, + { + "Category": "DICTATORS & TYRANTS", + "Question": "The pro-Soviet dictator Babrak Karmal came to power in this country after a 1979 invasion", + "Answer": "Afghanistan" + }, + { + "Category": "THE ONION", + "Question": "From an issue in 2056: This island & commonwealth ceded to the U.S. in 1898... \"Should it become our 63rd state?\"", + "Answer": "Puerto Rico" + }, + { + "Category": "WORLD AUTHORS", + "Question": "This literary whiz' name is sometimes transliterated from Bengali as Ravindranatha Thakura", + "Answer": "Tagore" + }, + { + "Category": "CROSSWORD CLUES \"J\"", + "Question": "A joyful celebration (10)", + "Answer": "jubilation" + }, + { + "Category": "SOCIOLOGY", + "Question": "A plant, animal or object that's the symbol of a clan; it's often taboo & was paired with \"Taboo\" in a Freud title", + "Answer": "totem" + }, + { + "Category": "THE STARTING INFIELD", + "Question": "The 1975 Reds fielded Rose, Concepcion, Perez & this Hall of Fame second sacker, now a broadcaster", + "Answer": "Joe Morgan" + }, + { + "Category": "DICTATORS & TYRANTS", + "Question": "A humble lawyer from Arras, in 1793 he became Head of the Committee of Public Safety & launched a bloodbath", + "Answer": "Robespierre" + }, + { + "Category": "THE ONION", + "Question": "Sept. 12, 1928: This \"It Girl\" \"to appear sleeveless in Oct. Collier's; 'Besleeve yourself, strumpet!' clergy urge\"", + "Answer": "Bow" + }, + { + "Category": "WORLD AUTHORS", + "Question": "This French writer \"steaked\" a claim as \"The Father of Romanticism\" by writing such works as \"Atala\"", + "Answer": "Chateaubriand" + }, + { + "Category": "CROSSWORD CLUES \"J\"", + "Question": "Belligerent nationalist (5)", + "Answer": "jingo" + }, + { + "Category": "BUSINESS LEADERS", + "Question": "His business card bore the Golden Arches & the titles \"Founder\" & \"Senior Chairman of the Board\"", + "Answer": "Kroc" + }, + { + "Category": "RADIO", + "Question": "Instrument struck when a contestant failed on the \"Original Amateur Hour\"", + "Answer": "a gong" + }, + { + "Category": "THAT'S ITALIAN!", + "Question": "It's the Italian name for the country's biggest island", + "Answer": "Sicilia" + }, + { + "Category": "NEW WEAPONS", + "Question": "The USA's \"E-Bomb\" will disable grids & computers and reheat the enemies' lasagna by sending out these waves", + "Answer": "microwaves" + }, + { + "Category": "5-LETTER WORDS", + "Question": "One who steals by stealth: Thessalonians speaks of one \"in the night\"", + "Answer": "a thief" + }, + { + "Category": "BUSINESS LEADERS", + "Question": "In 1886 he started his first successful business, the Lancaster Caramel Co.; the chocolate came later", + "Answer": "Hershey" + }, + { + "Category": "RADIO", + "Question": "This word ends the title of a 1941 Bill of Rights tribute program heard by 60 million, \"We hold these...\"", + "Answer": "Truths" + }, + { + "Category": "THAT'S ITALIAN!", + "Question": "Roman soldiers passed the time playing this game, the Italian version of lawn bowling", + "Answer": "bocce" + }, + { + "Category": "NEW WEAPONS", + "Question": "The \"Storm Shadow\" is a new British version of this type of low-altitude, radar-evading missile", + "Answer": "a cruise missile" + }, + { + "Category": "5-LETTER WORDS", + "Question": "A big fishing net, maybe in the river of the same name", + "Answer": "a seine" + }, + { + "Category": "BUSINESS LEADERS", + "Question": "In the 1880s he built a town in Illinois to house employees of his sleeping car company", + "Answer": "Pullman" + }, + { + "Category": "RADIO", + "Question": "Can't forget the sponsor--Jack Benny's opening line wasn't \"Hello again\" but this dessert \"again\"", + "Answer": "Jell-O" + }, + { + "Category": "THAT'S ITALIAN!", + "Question": "These thin tubes of pasta, Italian for \"bridegrooms\", are often baked", + "Answer": "ziti" + }, + { + "Category": "NEW WEAPONS", + "Question": "It's the Indian tribe in the name of the USA's AH-64D Longbow, the most advanced combat helicopter in the world", + "Answer": "Apache" + }, + { + "Category": "5-LETTER WORDS", + "Question": "It can mean \"brief & forceful\" or \"resembling the inner core of a stem\"", + "Answer": "pithy" + }, + { + "Category": "BUSINESS LEADERS", + "Question": "Before founding his own corp., John K. Northrop was chief engineer for this company & designed its Vega airplane", + "Answer": "Lockheed" + }, + { + "Category": "RADIO", + "Question": "In 2005 NPR revived this 1950s program in which people state their credos", + "Answer": "This I Believe" + }, + { + "Category": "NEW WEAPONS", + "Question": "The FA-18E/F is the \"Super\" version of this high-tech U.S. Navy fighter jet with a wasplike name", + "Answer": "a Hornet" + }, + { + "Category": "5-LETTER WORDS", + "Question": "Teddy Roosevelt said \"The credit belongs to the man\" in this, \"whose face is marred by dust & sweat & blood\"", + "Answer": "the arena" + }, + { + "Category": "BUSINESS LEADERS", + "Question": "Since founding Amazon.com in 1994, he's tried to make it \"The Earth's most customer-centric company\"", + "Answer": "Jeff Bezos" + }, + { + "Category": "RADIO", + "Question": "On April 3, 1936 a nation listened as Gabriel Heatter covered this man's execution", + "Answer": "Bruno Hauptmann" + }, + { + "Category": "THAT'S ITALIAN!", + "Question": "This 15th century movement may have first been named in a 1550 book, using the Italian word rinascita", + "Answer": "the Renaissance" + }, + { + "Category": "5-LETTER WORDS", + "Question": "Greek for \"word\", it can mean the word of God", + "Answer": "logos" + }, + { + "Category": "SCIENTISTS", + "Question": "\"American Prometheus\" is a biography of this physicist who died in 1967", + "Answer": "J. Robert Oppenheimer" + }, + { + "Category": "BALLET", + "Question": "The New York City ballet's first visit to this city's famous festival inspired the ballet \"Scotch Symphony\"", + "Answer": "Edinburgh" + }, + { + "Category": "IT'S ONLY ROCK & ROLL", + "Question": "He perked up his career by letting Starbucks release his album \"Memory Almost Full\"", + "Answer": "McCartney" + }, + { + "Category": "ALSO A TOOL", + "Question": "This drink consists of 2 ounces of vodka & 5 ounces of orange juice", + "Answer": "a screwdriver" + }, + { + "Category": "HABEAS CORPSES", + "Question": "In part due to fears of body snatching, his body was moved 17 times around his Springfield, Ill. national monument", + "Answer": "Lincoln" + }, + { + "Category": "\"IRA\"", + "Question": "Hey, you saps who think pneumonia killed President Harrison--I've got this kind of theory involving a group plan", + "Answer": "a conspiracy theory" + }, + { + "Category": "BALLET", + "Question": "The 1972 ballet \"Printemps\" premiered in the winter, but its name is French for this season", + "Answer": "spring" + }, + { + "Category": "IT'S ONLY ROCK & ROLL", + "Question": "This '80s trio were \"Spirits in the Material World\" before the synchronicity of their 2007 reunion", + "Answer": "The Police" + }, + { + "Category": "ALSO A TOOL", + "Question": "We recommend giving someone this figuratively if you must fire him; later he might have one to grind", + "Answer": "the axe" + }, + { + "Category": "HABEAS CORPSES", + "Question": "4 places claimed to be the burial site of this explorer, including crypts in Seville & Santo Domingo", + "Answer": "Christopher Columbus" + }, + { + "Category": "\"IRA\"", + "Question": "The lady was quite overcome by this moisture exuded by the muscular estate gardener", + "Answer": "perspiration" + }, + { + "Category": "BALLET", + "Question": "Balanchine choreographed the leading role in \"Allegro Brillante\" for this part-Osage Indian ex-wife", + "Answer": "Maria Tallchief" + }, + { + "Category": "IT'S ONLY ROCK & ROLL", + "Question": "\"Who Knew\" this colorful singer could be so \"M!ssundaztood\"", + "Answer": "Pink" + }, + { + "Category": "ALSO A TOOL", + "Question": "\"U Can't Touch This\" bone, aka the malleus, just behind the eardrum", + "Answer": "the hammer" + }, + { + "Category": "HABEAS CORPSES", + "Question": "Kept for years in her husband's dining room, her embalmed body was buried in Buenos Aires in '74", + "Answer": "Eva Peron" + }, + { + "Category": "\"IRA\"", + "Question": "The Motion Picture Association of America says this cost producers, theater owners, etc. $18.2 billion in 2005", + "Answer": "piracy" + }, + { + "Category": "BALLET", + "Question": "Alexandre Dumas fils' tale about \"The Lady of\" these flowers bloomed as the ballet \"Marguerite and Armand\"", + "Answer": "the Camellias" + }, + { + "Category": "IT'S ONLY ROCK & ROLL", + "Question": "This band is now part of the \"Zeitgeist\" after suffering \"Mellon Collie and the Infinite Sadness\"", + "Answer": "Smashing Pumpkins" + }, + { + "Category": "ALSO A TOOL", + "Question": "A light, stroking touch, or a dense growth of bushes", + "Answer": "a brush" + }, + { + "Category": "HABEAS CORPSES", + "Question": "Executed in 1915, this radical labor activist was cremated & his ashes mailed to labor unions all over the world", + "Answer": "Joe Hill" + }, + { + "Category": "FINANCE", + "Question": "It's often set up by the wealthy for their kids, but California has a state children's one for poor folks", + "Answer": "a trust fund" + }, + { + "Category": "\"IRA\"", + "Question": "Australia's Yellow Tail winery sells this on its own as well as in a cabernet blend", + "Answer": "shiraz" + }, + { + "Category": "BALLET", + "Question": "As a law student in St. Petersburg, this man became interested in the arts, & in 1909 he founded the Ballets Russes", + "Answer": "Diaghilev" + }, + { + "Category": "IT'S ONLY ROCK & ROLL", + "Question": "\"Hybrid Theory\", the title of this rock-rap band's first hit album, was one of the band's former names", + "Answer": "Linkin Park" + }, + { + "Category": "ALSO A TOOL", + "Question": "Hit the backyard with this old term for a libertine", + "Answer": "a rake" + }, + { + "Category": "HABEAS CORPSES", + "Question": "This 19th century philosopher's body has been very utilitarian; it's on display at a university in London", + "Answer": "Jeremy Bentham" + }, + { + "Category": "\"IRA\"", + "Question": "This type of medieval play often shows the Virgin Mary coming to the rescue", + "Answer": "a miracle play" + }, + { + "Category": "WAR MOVIES", + "Question": "2004: Angry Greeks attack a fortified city-state", + "Answer": "Troy" + }, + { + "Category": "ISLANDS", + "Question": "This \"colossal\" island is the largest in Greece's Dodecanese archipelago", + "Answer": "Rhodes" + }, + { + "Category": "HISTORIC BIRTH ANNOUNCEMENTS", + "Question": "Older brother Frank is thrilled to welcome this Sept. 5, 1847 baby; 10 days old & making guns with his tiny fingers", + "Answer": "Jesse James" + }, + { + "Category": "WAR MOVIES", + "Question": "1978: The wife of a soldier fighting in Vietnam works at a VA hospital & has an affair with a wounded vet", + "Answer": "Coming Home" + }, + { + "Category": "THE RULE OF THIRDS", + "Question": "On Jan. 19, 1966 this woman was elected the third prime minister of her country", + "Answer": "Indira Gandhi" + }, + { + "Category": "ISLANDS", + "Question": "This group of islands off the northern coast of France was the only British soil occupied by the Germans in WWII", + "Answer": "the Channel Islands" + }, + { + "Category": "HISTORIC BIRTH ANNOUNCEMENTS", + "Question": "This king is thrilled by the birth of Mary, Feb. 18, 1516; there's still plenty of time to have a son--right?", + "Answer": "Henry VIII" + }, + { + "Category": "AFRICAN LANGUAGE LAB", + "Question": "Whether a surfin' one or a Pontiac, this term comes from the Swahili meaning \"journey\"", + "Answer": "safari" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "Jules Verne-Wilkie Collins sci-fi/detective novel about Civil War vets who want to shoot a cannon into a gem", + "Answer": "From the Earth to the Moonstone" + }, + { + "Category": "WAR MOVIES", + "Question": "1970: An historically correct re-creation of Pearl Harbor", + "Answer": "Tora! Tora! Tora!" + }, + { + "Category": "THE RULE OF THIRDS", + "Question": "You have to go through this ceremony in order to become a Freemason", + "Answer": "the Third Degree" + }, + { + "Category": "ISLANDS", + "Question": "This island nation's highest peak, Yu Shan, in the Chungyang range, is also called Mount Morrison", + "Answer": "Taiwan" + }, + { + "Category": "HISTORIC BIRTH ANNOUNCEMENTS", + "Question": "Henry & Clara Ford are proud to announce the rollout of this model Nov. 6, 1893", + "Answer": "the Edsel" + }, + { + "Category": "AFRICAN LANGUAGE LAB", + "Question": "The word \"okra\" is West African; in the language of Angola, okra was called this, which to us is a soup or stew", + "Answer": "gumbo" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "Novel-poem in which Sal & Dean hitchhike through a yellow wood where the path diverges, making all the difference", + "Answer": "On the Road Not Taken" + }, + { + "Category": "WAR MOVIES", + "Question": "1936: Errol Flynn leads a cavalry unit into cannon, annihilation & everlasting glory", + "Answer": "Charge of the Light Brigade" + }, + { + "Category": "THE RULE OF THIRDS", + "Question": "Twice in the 1990s, he came in third in U.S. presidential elections", + "Answer": "Ross Perot" + }, + { + "Category": "ISLANDS", + "Question": "A causeway connects this Persian Gulf nation with the Saudi Arabian mainland", + "Answer": "Bahrain" + }, + { + "Category": "HISTORIC BIRTH ANNOUNCEMENTS", + "Question": "A 1906 announcement: dad Socrates & mom Penelope celebrate the launch of this new little ship", + "Answer": "Aristotle Onassis" + }, + { + "Category": "AFRICAN LANGUAGE LAB", + "Question": "Go where some men have gone before with this 4-letter term from the Afrikaans for \"migrate\"", + "Answer": "trek" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "Faulkner novel about Joe Christmas that's the Swedish playwright of \"The Dance of Death\"", + "Answer": "The Light in August Strindberg" + }, + { + "Category": "WAR MOVIES", + "Question": "1951: Erwin Rommel succeeds... for a while... in North Africa", + "Answer": "The Desert Fox" + }, + { + "Category": "THE RULE OF THIRDS", + "Question": "A member of the British Commonwealth, this country is the third-largest island in the Caribbean", + "Answer": "Jamaica" + }, + { + "Category": "ISLANDS", + "Question": "One of France's 26 regions, it doesn't count as an overseas one though it's 100 miles across the Mediterranean", + "Answer": "Corsica" + }, + { + "Category": "HISTORIC BIRTH ANNOUNCEMENTS", + "Question": "James & Lady Blanche have a \"declaration\": the July 25, 1848 birth of this future foreign secretary & prime minister", + "Answer": "Balfour" + }, + { + "Category": "AFRICAN LANGUAGE LAB", + "Question": "The marimba was popularized in Central America, but the word is from this sub-Saharan group of about 500 langs.", + "Answer": "the Bantu languages" + }, + { + "Category": "SCIENTISTS", + "Question": "In 2007 this 1962 American Nobel laureate became the first person to receive his own personal genome map", + "Answer": "James Watson" + }, + { + "Category": "THE BIG APPLE", + "Question": "There's an annual footrace up its 86 flights of stairs", + "Answer": "the Empire State Building" + }, + { + "Category": "COMPOSERS ON FILM", + "Question": "Kevin Kline in \"De-Lovely\"", + "Answer": "Porter" + }, + { + "Category": "A SHAPELY CATEGORY", + "Question": "Often stuffed & baked, conchiglioni is jumbo pasta shaped like these", + "Answer": "shells" + }, + { + "Category": "SALMON", + "Question": "\"Fish ladders\" help salmon travel upstream over these man-made obstructions", + "Answer": "dams" + }, + { + "Category": "CHANTED", + "Question": "In a children's playground chant, they're the 2 things that will \"break my bones, but names will never hurt me\"", + "Answer": "sticks & stones" + }, + { + "Category": "\"EVE\"NING", + "Question": "Dangerous ones include hemorrhagic & scarlet", + "Answer": "fever" + }, + { + "Category": "THE BIG APPLE", + "Question": "On the NYC subway this train will also take you to Harlem, but then it splits off & heads for Yankee Stadium", + "Answer": "the B train" + }, + { + "Category": "COMPOSERS ON FILM", + "Question": "Cary Grant in \"Night and Day\"", + "Answer": "Cole Porter" + }, + { + "Category": "A SHAPELY CATEGORY", + "Question": "Something that's cordate is shaped like this, my love", + "Answer": "a heart" + }, + { + "Category": "SALMON", + "Question": "World Book says this country leads the world in salmon fishing, with more than 450,000 tons caught each year", + "Answer": "the United States" + }, + { + "Category": "CHANTED", + "Question": "This musical instrument consists of a chanter, several drones & an air sack", + "Answer": "a bagpipe" + }, + { + "Category": "\"EVE\"NING", + "Question": "In a hit song by the Monkees, \"Then I saw her face, now I'm\" one of these", + "Answer": "a believer" + }, + { + "Category": "THE BIG APPLE", + "Question": "In 1865 NYC, already home to 800,000, finally abandoned this type of fire department", + "Answer": "volunteer" + }, + { + "Category": "COMPOSERS ON FILM", + "Question": "James Cagney in \"Yankee Doodle Dandy\"", + "Answer": "George M. Cohan" + }, + { + "Category": "A SHAPELY CATEGORY", + "Question": "It's the more common 4-letter name for a regular hexahedron", + "Answer": "a cube" + }, + { + "Category": "SALMON", + "Question": "The roe of the chum salmon is a popular source for the red variety of this", + "Answer": "caviar" + }, + { + "Category": "CHANTED", + "Question": "Their chant in \"Macbeth\" begins, \"Double, double, toil and trouble\"", + "Answer": "the witches" + }, + { + "Category": "\"EVE\"NING", + "Question": "In 1905 this former U.S. president remarked, \"Sensible and responsible women do not want to vote\"", + "Answer": "Grover Cleveland" + }, + { + "Category": "THE BIG APPLE", + "Question": "One of NYC's most famous seafood joints is the bar for these bivalves in Grand Central", + "Answer": "oysters" + }, + { + "Category": "COMPOSERS ON FILM", + "Question": "James Cagney in \"The Seven Little Foys\"", + "Answer": "George M. Cohan" + }, + { + "Category": "A SHAPELY CATEGORY", + "Question": "Dendroid means shaped like a tree; dentiform means shaped like this", + "Answer": "a tooth" + }, + { + "Category": "SALMON", + "Question": "Salmon are members of the same family as the speckled or brook variety of this fish", + "Answer": "trout" + }, + { + "Category": "CHANTED", + "Question": "The Kol Nidre prayer is chanted by the cantor on the eve of this Jewish day of atonement", + "Answer": "Yom Kippur" + }, + { + "Category": "\"EVE\"NING", + "Question": "A bracketed projecting beam supported on only one end, or a type of bridge", + "Answer": "a cantilever" + }, + { + "Category": "THE BIG APPLE", + "Question": "Artsy types like Maya Lin & Art Spiegelman find inspiration in this area that gets its name from its northern border", + "Answer": "SoHo" + }, + { + "Category": "COMPOSERS ON FILM", + "Question": "Toralv Maurstad in \"Song of Norway\"", + "Answer": "Edvard Grieg" + }, + { + "Category": "SALMON", + "Question": "Weighing up to 100 pounds, this large type of salmon shares its name with a warm, dry wind", + "Answer": "chinook" + }, + { + "Category": "CHANTED", + "Question": "Named for a 6th century pope, these a capella songs might have earned a Papal's Choice Award", + "Answer": "Gregorian chants" + }, + { + "Category": "\"EVE\"NING", + "Question": "It's the \"A\" in JA, the youth organization begun in 1919 to teach young people about American business", + "Answer": "Achievement" + }, + { + "Category": "HISTORIC NAMES", + "Question": "In 312, emboldened by the sight of a cross in the sky, this man defeated the Emperor Maxentius & seized Rome", + "Answer": "Constantine" + }, + { + "Category": "WHAT A CHARACTER!", + "Question": "Well, goll-ly! He left his job & home in Mayberry to join the Marine Corps", + "Answer": "Gomer Pyle" + }, + { + "Category": "GEOLOGY", + "Question": "The Mercalli scale measures the intensity of these from I to XII", + "Answer": "earthquakes" + }, + { + "Category": "HOME, SWEET HOME", + "Question": "Scout out the home Kit Carson shared with his lovely bride in Taos in this state", + "Answer": "New Mexico" + }, + { + "Category": "NAME THE POET", + "Question": "\"The caged bird sings / With a fearful trill / Of things unknown / But longed for still\"", + "Answer": "Maya Angelou" + }, + { + "Category": "CROSSWORD CLUES \"B\"", + "Question": "A baby belch (4)", + "Answer": "burp" + }, + { + "Category": "HISTORIC NAMES", + "Question": "In 1955 Ngo Dinh Diem became the first president of this country that no longer exists", + "Answer": "South Vietnam" + }, + { + "Category": "WHAT A CHARACTER!", + "Question": "On \"The Addams Family\", he was married to Morticia", + "Answer": "Gomez" + }, + { + "Category": "GEOLOGY", + "Question": "Geysers aren't common; major centers include Yellowstone, Iceland & this country's North Island", + "Answer": "New Zealand" + }, + { + "Category": "HOME, SWEET HOME", + "Question": "Doris Duke never had to rough it at Rough Point, her 105-room estate in this ritzy Rhode Island town", + "Answer": "Newport" + }, + { + "Category": "NAME THE POET", + "Question": "\"Wee, sleeket, cowran, tim'rous beastie, / O, what a panic's in thy breastie!\"", + "Answer": "Rabbie Burns" + }, + { + "Category": "CROSSWORD CLUES \"B\"", + "Question": "It precedes dance, laugh or flop (5)", + "Answer": "belly" + }, + { + "Category": "HISTORIC NAMES", + "Question": "This Apache tried to keep peace with the palefaces, but after his death, his son joined with the militant Geronimo", + "Answer": "Cochise" + }, + { + "Category": "GEOLOGY", + "Question": "This rock can be formed by the accumulation of shells or coral, but not from citrus fruit", + "Answer": "limestone" + }, + { + "Category": "HOME, SWEET HOME", + "Question": "People in this job never had an official home until \"Number One Observatory Circle\" was chosen in the '70s", + "Answer": "the vice president" + }, + { + "Category": "NAME THE POET", + "Question": "\"There was an old man with a beard, / Who said, 'It is just as I feared!'\"", + "Answer": "Edward Lear" + }, + { + "Category": "CROSSWORD CLUES \"B\"", + "Question": "Bestselling book that has its own \"belt\" (5)", + "Answer": "Bible" + }, + { + "Category": "HISTORIC NAMES", + "Question": "Margaret Roper, who died in 1544, is said to have been buried with the head of this \"Utopia\" author, her father", + "Answer": "Saint Thomas More" + }, + { + "Category": "WHAT A CHARACTER!", + "Question": "During a dream sequence, it was revealed that this Richard Dean Anderson character had the first name Angus", + "Answer": "MacGyver" + }, + { + "Category": "GEOLOGY", + "Question": "This 9-letter geologic science is the study of the movement & distribution of all the Earth's waters", + "Answer": "hydrology" + }, + { + "Category": "HOME, SWEET HOME", + "Question": "Ralph Waldo Emerson owned a Concord home nicknamed this; Hawthorne rented it & wrote some \"Mosses from\" it", + "Answer": "the Old Manse" + }, + { + "Category": "NAME THE POET", + "Question": "\"A little learning is a dang'rous thing; / Drink deep, or taste not the Pierian spring\"", + "Answer": "Alexander Pope" + }, + { + "Category": "CROSSWORD CLUES \"B\"", + "Question": "A throng, often \"of beauties\" (4)", + "Answer": "bevy" + }, + { + "Category": "WHAT A CHARACTER!", + "Question": "Hardcore fans of \"Gilligan's Island\" known that this character's real name is Roy Hinkley", + "Answer": "the Professor" + }, + { + "Category": "GEOLOGY", + "Question": "A 6-mile-wide caldera, or volcanic crater, is a highlight of La Palma in this Spanish Island group off Africa", + "Answer": "the Canaries" + }, + { + "Category": "HOME, SWEET HOME", + "Question": "As a bachelor in the 1970s, Prince Charles romanced Camilla at Broadlands, the home of this lord, his great-uncle", + "Answer": "Mountbatten" + }, + { + "Category": "NAME THE POET", + "Question": "\"Drink to me only with thine eyes, / And I will pledge with mine\"", + "Answer": "Ben Jonson" + }, + { + "Category": "CROSSWORD CLUES \"B\"", + "Question": "Mr. Bumble's occupation in \"Oliver Twist\" (6)", + "Answer": "beadle" + }, + { + "Category": "U.S. POLITICS", + "Question": "Since 1960, only Massachusetts & this state have produced more than one of the 10 Democratic presidential nominees", + "Answer": "Minnesota" + }, + { + "Category": "ASSASSINS", + "Question": "In May 1981 would-be assassin Mehmet Ali Agca shot this man in St. Peter's Square", + "Answer": "Pope John Paul II" + }, + { + "Category": "THE REEL STORY", + "Question": "Kate Winslet wears a blue diamond necklace called the \"Heart of the Ocean\" in this 1997 film", + "Answer": "Titanic" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "The first seal designed for what is now this U.S. state depicted icebergs, igloos & the Northern Lights", + "Answer": "Alaska" + }, + { + "Category": "GOVERNMENT", + "Question": "Since 1909 every government in Denmark's parliament has been this type that needs to strike deals", + "Answer": "minority government" + }, + { + "Category": "WORLD \"P\"s", + "Question": "The \"4 questions\" asked on this occasion include wondering why we have to eat unleavened bread", + "Answer": "Passover" + }, + { + "Category": "ASSASSINS", + "Question": "Reginald Fitzurse was among the Knights who took Henry II's remark literally to rid him of this archbishop", + "Answer": "Thomas à Becket" + }, + { + "Category": "THE REEL STORY", + "Question": "Keanu Reeves is a supernatural detective in this 2005 flick based on the Hellblazer comic book", + "Answer": "Constantine" + }, + { + "Category": "GOVERNMENT", + "Question": "In 1978 Ricardo Bordallo was Guam's head of government & this man was its head of state", + "Answer": "Jimmy Carter" + }, + { + "Category": "WORLD \"P\"s", + "Question": "Malay or Sinai", + "Answer": "peninsula" + }, + { + "Category": "ASSASSINS", + "Question": "In 1994, 31 years after the crime, Byron de la Beckwith was convicted of murdering this Civil Rights leader", + "Answer": "Medgar Evers" + }, + { + "Category": "THE REEL STORY", + "Question": "This singer starred in \"Waiting to Exhale\" & \"The Bodyguard\"", + "Answer": "Whitney Houston" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "Sleepy Bear has been this motel chain's logo since 1954", + "Answer": "Travelodge" + }, + { + "Category": "GOVERNMENT", + "Question": "This country's National People's Congress has had up to around 3,500 members", + "Answer": "China" + }, + { + "Category": "WORLD \"P\"s", + "Question": "Gunmen after this South American dictator in 1986 used rockets, bazookas, rifles & grenades--& missed!", + "Answer": "Pinochet" + }, + { + "Category": "ASSASSINS", + "Question": "Yigal Amir, a student at Bar-Ilan University, is serving a life sentence for assassinating this leader in 1995", + "Answer": "Rabin" + }, + { + "Category": "THE REEL STORY", + "Question": "He played Mozart in the 1984 film \"Amadeus\"", + "Answer": "Tom Hulce" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "The 3 Zodiac signs with horns", + "Answer": "Aries, Capricorn & Taurus" + }, + { + "Category": "GOVERNMENT", + "Question": "Brazil has 2 federal legislative houses, the Chamber of Deputies & this", + "Answer": "the Senate" + }, + { + "Category": "WORLD \"P\"s", + "Question": "World Heritage sites in this nation include the Nasca Lines", + "Answer": "Peru" + }, + { + "Category": "ASSASSINS", + "Question": "Ramon Mercader, who killed this man in 1940, was later awarded the Order of Lenin", + "Answer": "Trotsky" + }, + { + "Category": "THE REEL STORY", + "Question": "M. Night Shyamalan wrote & directed this creepy Bruce Willis-Haley Joel Osment film", + "Answer": "The Sixth Sense" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "The same 2 letters in the same order make up Arkansas' postal abbreviation & the symbol of this chemical element", + "Answer": "argon" + }, + { + "Category": "GOVERNMENT", + "Question": "This country with \"Republic\" in its name was less republican after a 2003 coup by General Francois Bozize", + "Answer": "the Central African Republic" + }, + { + "Category": "WORLD \"P\"s", + "Question": "Named for an adviser to Catherine the Great, this type of \"village\" looks deceptively impressive", + "Answer": "a Potemkin village" + }, + { + "Category": "EUROPE", + "Question": "In 1917 the name of this castle that dates back to the 11th century was adopted by a royal house", + "Answer": "Windsor" + }, + { + "Category": "MUSICALS OF THE '20s", + "Question": "The 1924 musical revue \"I'll Say She Is\" made these goofy brothers legitimate Broadway stars", + "Answer": "the Marx Brothers" + }, + { + "Category": "NOVELS OF THE PAST", + "Question": "In Barry Unsworth's \"The Songs of the Kings\", the Greek fleet bound for here is trapped by unfavorable winds", + "Answer": "Troy" + }, + { + "Category": "CITY OF BIRTH", + "Question": "The controversial Ahmed Chalabi", + "Answer": "Baghdad" + }, + { + "Category": "CROSSWORD CLUES \"K\"", + "Question": "A \"bear\"y nice Alaskan island (6)", + "Answer": "Kodiak" + }, + { + "Category": "EUROPE", + "Question": "This country whose abbreviation is a conjunction joins Spain to France", + "Answer": "Andorra" + }, + { + "Category": "MUSICALS OF THE '20s", + "Question": "In a 1927 title, this phrase preceded \"Bonnie\" (it didn't precede \"Birdie\" until 1960)", + "Answer": "Bye Bye" + }, + { + "Category": "NOVELS OF THE PAST", + "Question": "James Fenimore Cooper's \"Mercedes of Castile\" combines a love story with the voyages of this man", + "Answer": "Columbus" + }, + { + "Category": "TRANSPLANTS", + "Question": "This organ was first successfully transplanted in 1981, as a package deal with a heart", + "Answer": "a lung" + }, + { + "Category": "CITY OF BIRTH", + "Question": "Mad magazine illustrator James Warhola", + "Answer": "Pittsburgh" + }, + { + "Category": "CROSSWORD CLUES \"K\"", + "Question": "Jean-Claude of the slopes (5)", + "Answer": "Killy" + }, + { + "Category": "EUROPE", + "Question": "The person with this title gets to appoint people to Luxembourg's Council of State & they get to stay on for life", + "Answer": "the Grand Duke" + }, + { + "Category": "MUSICALS OF THE '20s", + "Question": "The big attraction of the 1923 hit \"Poppy\" was this future film comic as Eustace McGargle", + "Answer": "W.C. Fields" + }, + { + "Category": "NOVELS OF THE PAST", + "Question": "The hero of Neal Stephenson's \"Quicksilver\" has to settle the calculus dispute between Leibniz & him", + "Answer": "Newton" + }, + { + "Category": "CITY OF BIRTH", + "Question": "Frederick the Great & Mike Nichols", + "Answer": "Berlin" + }, + { + "Category": "CROSSWORD CLUES \"K\"", + "Question": "Shy-sounding swimmers (3)", + "Answer": "koi" + }, + { + "Category": "EUROPE", + "Question": "France has about 100,000 of these Defense Ministry employees who perform police functions outside the main cities", + "Answer": "gendarmes" + }, + { + "Category": "MUSICALS OF THE '20s", + "Question": "The saucy 1928 musical \"Paris\" introduced this composer's immortal song \"Let's Do It\"", + "Answer": "Cole Porter" + }, + { + "Category": "NOVELS OF THE PAST", + "Question": "This antagonist of the Crusaders looks back on his life in a novel by Tariq Ali", + "Answer": "Saladin" + }, + { + "Category": "CITY OF BIRTH", + "Question": "Philosopher Jean-Jacques Rousseau was not born in France; his birthplace was this European city", + "Answer": "Geneva" + }, + { + "Category": "CROSSWORD CLUES \"K\"", + "Question": "Its alias is turnip cabbage (8)", + "Answer": "kohlrabi" + }, + { + "Category": "EUROPE", + "Question": "Until recently, Slovakia was part of Czechoslovakia & Slovenia was part of this", + "Answer": "Yugoslavia" + }, + { + "Category": "MUSICALS OF THE '20s", + "Question": "As a servant in the musical \"Bombo\", he sang \"Toot, Toot, Tootsie!\" & \"California, Here I Come\"", + "Answer": "Al Jolson" + }, + { + "Category": "NOVELS OF THE PAST", + "Question": "It's the second name of Taras, a 16th century Cossack in a 19th century Gogol novel", + "Answer": "Bulba" + }, + { + "Category": "CITY OF BIRTH", + "Question": "Sidney Bechet", + "Answer": "New Orleans" + }, + { + "Category": "CROSSWORD CLUES \"K\"", + "Question": "Ceremonial chamber you'd \"Hopi\" into (4)", + "Answer": "a kiva" + }, + { + "Category": "ARLINGTON'S TOMB OF UNKNOWNS", + "Question": "Sentinels at the tomb walk exactly this many steps at a time before they stop & turn", + "Answer": "21" + }, + { + "Category": "LUXEMBOURG", + "Question": "Rivaner is a profitable type of this planted in Luxembourg's Moselle Valley", + "Answer": "grape" + }, + { + "Category": "THE CINEMA", + "Question": "1999 film with the line \"The answer is out there, Neo, and it's looking for you, and it will find you if you want it to\"", + "Answer": "The Matrix" + }, + { + "Category": "Y-R", + "Question": "An astronomer may speak of a solar, lunar, equinoctial or sidereal one", + "Answer": "a year" + }, + { + "Category": "HAIR TODAY", + "Question": "This palindromic word can mean to cut short, or a short, blunt cut, with or without bangs", + "Answer": "bob" + }, + { + "Category": "GONE TOMORROW?", + "Question": "The Oahu tree one of these gastropods is quickly, not slowly, disappearing", + "Answer": "a snail" + }, + { + "Category": "LUXEMBOURG", + "Question": "Encyclopedia Britannica says this, not French, is the lingua franca of Luxembourg", + "Answer": "German" + }, + { + "Category": "THE CINEMA", + "Question": "The park bench Tom Hanks sat on in much of this 1994 film was in Chippewa Square in Savannah, Georgia", + "Answer": "Forrest Gump" + }, + { + "Category": "Y-R", + "Question": "A short war between Israel & Egypt & Syria in October 1973 was named for this high holiday", + "Answer": "Yom Kippur" + }, + { + "Category": "HAIR TODAY", + "Question": "In 2004 this real estate tycoon told People magazine that his signature swept-forward style is his own handiwork", + "Answer": "Trump" + }, + { + "Category": "GONE TOMORROW?", + "Question": "The Hine's emerald species of this insect has a wingspan that can reach about 3.5 inches", + "Answer": "a dragonfly" + }, + { + "Category": "LUXEMBOURG", + "Question": "During his years in exile, this \"Les Miserables\" author lived for a while in Vianden; his house there is now a museum", + "Answer": "Victor Hugo" + }, + { + "Category": "THE CINEMA", + "Question": "The popular soundtrack of this 2000 film includes \"I Am A Man Of Constant Sorrow\" & \"You Are My Sunshine\"", + "Answer": "O Brother, Where Art Thou?" + }, + { + "Category": "Y-R", + "Question": "In October 2002 he made another supersonic flight, 55 years after his first", + "Answer": "Chuck Yeager" + }, + { + "Category": "HAIR TODAY", + "Question": "This rastafarian style is Whoopi Goldberg's trademark", + "Answer": "dreadlocks" + }, + { + "Category": "GONE TOMORROW?", + "Question": "The endangerment of the New Mexico ridge-nosed species of this snake was caused in part by collectors", + "Answer": "a rattlesnake" + }, + { + "Category": "LUXEMBOURG", + "Question": "In the 1940s Luxembourg joined with these 2 countries to form a customs union", + "Answer": "Belgium & the Netherlands" + }, + { + "Category": "THE CINEMA", + "Question": "It was the mythological container sought by Lara Croft in \"Lara Croft Tomb Raider: The Cradle of Life\"", + "Answer": "Pandora's box" + }, + { + "Category": "Y-R", + "Question": "This Cole was a known associate of Jesse James", + "Answer": "Younger" + }, + { + "Category": "HAIR TODAY", + "Question": "This 6-letter hairstyle is \"business in front, party in the back\"", + "Answer": "a mullet" + }, + { + "Category": "GONE TOMORROW?", + "Question": "Picoides Borealis is the red-cockaded species of this bird, still on the endangered list in 2004", + "Answer": "the woodpecker" + }, + { + "Category": "LUXEMBOURG", + "Question": "The Congress of Vienna in 1815 made Luxembourg a state headed by this type of ruler", + "Answer": "a grand duke" + }, + { + "Category": "THE CINEMA", + "Question": "In this animated film, Henry J. Waternoose says, \"Kids these days. They just don't get scared like they used to\"", + "Answer": "Monsters, Inc." + }, + { + "Category": "Y-R", + "Question": "\"Savage Sam\" is a sequel to the Fred Gipson book called \"Old\" this", + "Answer": "Yeller" + }, + { + "Category": "HAIR TODAY", + "Question": "George Clooney popularized the close-cut style named this, like a certain leader", + "Answer": "a Caesar" + }, + { + "Category": "GONE TOMORROW?", + "Question": "Among the colorful mammals on the endangered list are the gray & the red ones of these predators", + "Answer": "a wolf" + }, + { + "Category": "MAIN STREET U.S.A.", + "Question": "Borgen's Cafe, on Main St. in Westby, Wisconsin, feels a bit like Oslo, with menus & banter in this language", + "Answer": "Norwegian" + }, + { + "Category": "POP MUSIC", + "Question": "This rapper won a 2000 MTV award for Best Male Video for \"The Real Slim Shady\"", + "Answer": "Eminem" + }, + { + "Category": "\"A\"NCIENT GREEKS", + "Question": "A fabulist: 620-560 B.C.", + "Answer": "Aesop" + }, + { + "Category": "FLOWERS", + "Question": "The white petals of this flower are usually pulled to see if \"she loves me\" or \"she loves me not\"", + "Answer": "a daisy" + }, + { + "Category": "BRITISH INVENTIONS", + "Question": "A perambulator or pram to the Brits, it was invented in 1733 by William Kent for the Duke of Devonshire's kids", + "Answer": "a baby carriage" + }, + { + "Category": "BEFORE & AFTER", + "Question": "1980 scarefest in which mom & daughter switch bodies one day & are stalked by Jason at Camp Crystal Lake", + "Answer": "Freaky Friday the 13th" + }, + { + "Category": "MAIN STREET U.S.A.", + "Question": "In Salt Lake City take Main Street to this square to find the Mormon Tabernacle", + "Answer": "Temple Square" + }, + { + "Category": "POP MUSIC", + "Question": "'60s Dylan classic that begins, \"Once upon a time you dressed so fine\"", + "Answer": "\"Like A Rolling Stone\"" + }, + { + "Category": "\"A\"NCIENT GREEKS", + "Question": "A philosopher & student of Plato: 384-322 B.C.", + "Answer": "Aristotle" + }, + { + "Category": "BRITISH INVENTIONS", + "Question": "In 1676 Robert Hooke came up with a universal one of these to manipulate the mirrors of his helioscope", + "Answer": "a universal joint" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Leif Ericson's dad who was a huge star with low surface temperature", + "Answer": "Erik the Red Giant" + }, + { + "Category": "MAIN STREET U.S.A.", + "Question": "There's a house dating from 1648 on Main St. in this \"directional\" resort village in New York's Hamptons", + "Answer": "Southampton" + }, + { + "Category": "POP MUSIC", + "Question": "In the summer of 2002 this country star hit the Hot 100 chart with \"Courtesy Of The Red, White and Blue\"", + "Answer": "Toby Keith" + }, + { + "Category": "\"A\"NCIENT GREEKS", + "Question": "A comedic dramatist: 445-385 B.C.", + "Answer": "Aristophanes" + }, + { + "Category": "FLOWERS", + "Question": "These flowers blooming in a Flanders cemetery during WWI inspired a famous poem by Major John McCrae", + "Answer": "poppies" + }, + { + "Category": "BRITISH INVENTIONS", + "Question": "The name of this Scot who invented the steam hammer sounds just like the American who invented basketball", + "Answer": "Nasmyth" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Fictional girl sleuth who's the granddaughter of \"The Great Profile\"", + "Answer": "Nancy Drew Barrymore" + }, + { + "Category": "MAIN STREET U.S.A.", + "Question": "Bob Seger was \"down on Main Street\" in this city, home to a university", + "Answer": "Ann Arbor" + }, + { + "Category": "POP MUSIC", + "Question": "Alicia Keys received 5 Grammys for 2001, including best new artist & song of the year for this hit", + "Answer": "\"Fallin'\"" + }, + { + "Category": "\"A\"NCIENT GREEKS", + "Question": "A mathematician: 287-212 B.C.", + "Answer": "Archimedes" + }, + { + "Category": "BRITISH INVENTIONS", + "Question": "For the military, zoologist John Kerr developed the \"dazzle paint\" type of this, something animals also use", + "Answer": "camouflage" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Projection at the southern tip of South America also called a cornucopia", + "Answer": "Cape Horn o' Plenty" + }, + { + "Category": "MAIN STREET U.S.A.", + "Question": "Your feelings may run deep on historic Main Street in this city, home of Oklahoma State University", + "Answer": "Stillwater" + }, + { + "Category": "POP MUSIC", + "Question": "\"Come Back Home\" is the first single from his 2003 album \"Day I Forgot\"", + "Answer": "Pete Yorn" + }, + { + "Category": "\"A\"NCIENT GREEKS", + "Question": "The \"Oresteia\" tragedian: 525-456 B.C.", + "Answer": "Aeschylus" + }, + { + "Category": "FLOWERS", + "Question": "In song, Colorado is where these bluish & white state flowers grow", + "Answer": "the Rocky Mountain columbines" + }, + { + "Category": "BRITISH INVENTIONS", + "Question": "The miner's safety lamp was also called by the name of this British chemist who invented it in 1815", + "Answer": "Sir Humphry Davy" + }, + { + "Category": "BEFORE & AFTER", + "Question": "\"Lethal Weapon\" director whose group was caught in a Sierra Nevada pass in the winter of 1846-47", + "Answer": "the Richard Donner Party" + }, + { + "Category": "BOOK TITLES", + "Question": "\"I am the rose of Sharon\" & \"When you know your name, you should hang on to it\" are from 2 different books titled this", + "Answer": "Song of Solomon" + }, + { + "Category": "U.S. PRESIDENTIAL NICKNAMES", + "Question": "\"The Surveyor President\"", + "Answer": "George Washington" + }, + { + "Category": "BALLPARK FIGURES", + "Question": "In 2004 he published \"My Prison Without Bars\"", + "Answer": "Pete Rose" + }, + { + "Category": "NOVEL QUOTES", + "Question": "(1937) \"'It's me, Bilbo Baggins, companion of Thorin!'\"", + "Answer": "The Hobbit" + }, + { + "Category": "THREE CHEERS!", + "Question": "It's the breakfast cereal pitched by the animated elves Snap, Crackle & Pop", + "Answer": "Rice Krispies" + }, + { + "Category": "GIVE ME AN \"A\"!", + "Question": "Wow! In 2002 a \"supercolony\" of billions of these was discovered stretching across several countries in Europe", + "Answer": "ants" + }, + { + "Category": "U.S. PRESIDENTIAL NICKNAMES", + "Question": "\"The Illinois Baboon\" & \"The Martyr President\"", + "Answer": "Abraham Lincoln" + }, + { + "Category": "BALLPARK FIGURES", + "Question": "With the Yankees from 1923 to 1939, his No. 4 was the first number retired in either league", + "Answer": "Lou Gehrig" + }, + { + "Category": "WEDDINGS", + "Question": "In 2002 a hot pink frock worn by Robin Durr won the DeKuyper Contest for the worst of these", + "Answer": "a bridesmaid's dress" + }, + { + "Category": "NOVEL QUOTES", + "Question": "(1719) \"I made him know his name should be Friday, which was the day I saved his life\"", + "Answer": "Robinson Crusoe" + }, + { + "Category": "THREE CHEERS!", + "Question": "The 3 U.K. countries that make up the island of Great Britain", + "Answer": "England, Scotland & Wales" + }, + { + "Category": "GIVE ME AN \"A\"!", + "Question": "Robert Frost wondered \"How many\" of these \"fell on Newton's head before he took the hint!\"", + "Answer": "apples" + }, + { + "Category": "U.S. PRESIDENTIAL NICKNAMES", + "Question": "\"Red Fox\" & \"The Scribe of the Revolution\"", + "Answer": "Thomas Jefferson" + }, + { + "Category": "BALLPARK FIGURES", + "Question": "Baseball's \"Mr. October\", he generated headlines for his cantankerous personality & his athletic prowess", + "Answer": "Reggie Jackson" + }, + { + "Category": "WEDDINGS", + "Question": "The traditional conclusion of the pre-vow line \"If anyone can show just cause why they may not be joined together...\"", + "Answer": "\"let him speak now or forever hold his peace\"" + }, + { + "Category": "NOVEL QUOTES", + "Question": "(1945) \"All animals are equal, but some animals are more equal than others\"", + "Answer": "Animal Farm" + }, + { + "Category": "THREE CHEERS!", + "Question": "The 4-legged Omaha made the record books in 1935 with this 3-feat", + "Answer": "racing's Triple Crown" + }, + { + "Category": "GIVE ME AN \"A\"!", + "Question": "In 2004 an Arctic Beauty wild hair contest became part of the famous Fur Rendezvous in this U.S. city", + "Answer": "Anchorage" + }, + { + "Category": "BALLPARK FIGURES", + "Question": "Famous nickname of Leon Goslin, who played in all 19 World Series games with the Washington Senators", + "Answer": "\"Goose\"" + }, + { + "Category": "WEDDINGS", + "Question": "A Navy wedding features an arch of swords; an Army wedding, an arch of these heavy cavalry swords", + "Answer": "sabres" + }, + { + "Category": "NOVEL QUOTES", + "Question": "(1932) \"Over the main entrance the words, Central London Hatchery and Conditioning Centre\"", + "Answer": "Brave New World" + }, + { + "Category": "THREE CHEERS!", + "Question": "Since the 1979 incident at this location, no new nuclear reactors have been ordered in the U.S.", + "Answer": "Three-Mile Island" + }, + { + "Category": "U.S. PRESIDENTIAL NICKNAMES", + "Question": "\"The Schoolmaster in Politics\"", + "Answer": "Woodrow Wilson" + }, + { + "Category": "BALLPARK FIGURES", + "Question": "Sadly, this lefty pitcher who coined the Mets' battle cry \"You gotta believe\" died in 2004", + "Answer": "Tug McGraw" + }, + { + "Category": "WEDDINGS", + "Question": "It's the festive-sounding name for one who officiates at a wedding", + "Answer": "the celebrant" + }, + { + "Category": "NOVEL QUOTES", + "Question": "(1972) \"Rabbits need dignity and above all the will to accept their fate\"", + "Answer": "Watership Down" + }, + { + "Category": "GIVE ME AN \"A\"!", + "Question": "The name Zog is not as much in vogue as it once was, when King Zog I ruled this European country", + "Answer": "Albania" + }, + { + "Category": "RUBY", + "Question": "In newspapers, Jack Ruby was invariably described as an \"operator\" of these joints", + "Answer": "strip joints" + }, + { + "Category": "THE EMERALD ISLE", + "Question": "It's the only Irish city with a population above 500,000", + "Answer": "Dublin" + }, + { + "Category": "PEARLS OF WISDOM", + "Question": "An artist: \"In the future, everyone will be world-famous for 15 minutes\"", + "Answer": "Andy Warhol" + }, + { + "Category": "CORAL REEF LIFE", + "Question": "Just off Australia, it's the largest chain of coral reefs in the world", + "Answer": "the Great Barrier Reef" + }, + { + "Category": "\"DIAMOND\"s IN THE ROUGH", + "Question": "Dangerous American pit viper", + "Answer": "the diamondback" + }, + { + "Category": "WHAT A GEM!", + "Question": "The largest deposits of this fossil tree resin are found in the sands along the shores of the Baltic Sea", + "Answer": "amber" + }, + { + "Category": "RUBY", + "Question": "On Feb. 29, 2004 she won an Oscar for playing a woman named Ruby", + "Answer": "Renée Zellweger" + }, + { + "Category": "THE EMERALD ISLE", + "Question": "It's the one-word term for the traditional 6 counties known as Northern Ireland", + "Answer": "Ulster" + }, + { + "Category": "PEARLS OF WISDOM", + "Question": "A Founding Father: \"There never was a good war or a bad peace\"", + "Answer": "Benjamin Franklin" + }, + { + "Category": "CORAL REEF LIFE", + "Question": "John Pennekamp Coral Reef State Park, the USA's first underwater park, is just off the coast of this Florida key", + "Answer": "Key Largo" + }, + { + "Category": "\"DIAMOND\"s IN THE ROUGH", + "Question": "Honolulu high spot", + "Answer": "Diamond Head" + }, + { + "Category": "WHAT A GEM!", + "Question": "This December birthstone is the state gem of Arizona & New Mexico", + "Answer": "turquoise" + }, + { + "Category": "RUBY", + "Question": "She was married to Al Jolson when she starred in those classic 1930s Busby Berkeley musicals", + "Answer": "Ruby Keeler" + }, + { + "Category": "THE EMERALD ISLE", + "Question": "This U.S. president visited his family's ancestral village of Ballyporeen in 1984", + "Answer": "Reagan" + }, + { + "Category": "PEARLS OF WISDOM", + "Question": "A 17th century writer: \"Angling can be said to be so like the mathematics, that it can never be fully learnt\"", + "Answer": "Izaak Walton" + }, + { + "Category": "CORAL REEF LIFE", + "Question": "A species of these well-armed creatures known as the crown-of-thorns feasts on coral reefs", + "Answer": "starfish" + }, + { + "Category": "\"DIAMOND\"s IN THE ROUGH", + "Question": "Carol Channing's Broadway ballad from \"Gentlemen Prefer Blondes\"", + "Answer": "\"Diamonds Are A Girl's Best Friend\"" + }, + { + "Category": "WHAT A GEM!", + "Question": "Cornflower blue is the most prized color of this gem", + "Answer": "a sapphire" + }, + { + "Category": "RUBY", + "Question": "Harry Ruby & Bert Kalmar wrote this classic song about \"eight little letters which simply mean I love you\"", + "Answer": "\"Three Little Words\"" + }, + { + "Category": "THE EMERALD ISLE", + "Question": "This Irish port city on the River Suir is world famous for its crystal", + "Answer": "Waterford" + }, + { + "Category": "PEARLS OF WISDOM", + "Question": "A playwright: \"We are all born mad. Some remain so.\"", + "Answer": "Samuel Beckett" + }, + { + "Category": "\"DIAMOND\"s IN THE ROUGH", + "Question": "Arkansassy state park near Murfreesboro", + "Answer": "Crater of Diamonds State Park" + }, + { + "Category": "WHAT A GEM!", + "Question": "Mexico is known for its water & fire varieties of this gem", + "Answer": "opal" + }, + { + "Category": "RUBY", + "Question": "In a 1999 TV movie, she played Bessie, of the centenarian Delany sisters", + "Answer": "Ruby Dee" + }, + { + "Category": "THE EMERALD ISLE", + "Question": "At about 230 miles, it's not only the longest river in Ireland, it's the longest in the British Isles", + "Answer": "the River Shannon" + }, + { + "Category": "PEARLS OF WISDOM", + "Question": "A philosopher: \"Those who cannot remember the past are condemned to repeat it\"", + "Answer": "George Santayana" + }, + { + "Category": "CORAL REEF LIFE", + "Question": "It's a ring-shaped coral island surrounding a lagoon, like Bikini or Eniwetok", + "Answer": "an atoll" + }, + { + "Category": "\"DIAMOND\"s IN THE ROUGH", + "Question": "This lavish-living turn-of-the-century financier rose from a job as a bellhop", + "Answer": "Diamond Jim Brady" + }, + { + "Category": "WHAT A GEM!", + "Question": "In 1750 a Parisian jeweler found that heat turns this sherry-colored Brazilian gem pink", + "Answer": "topaz" + }, + { + "Category": "HISTORIC ENGLISHMEN", + "Question": "Ironically, he might have saved himself from death in 1779 if he had known how to swim", + "Answer": "Captain Cook" + }, + { + "Category": "AUTHORS", + "Question": "During WWII this \"Gone with the Wind\" author was an American Red Cross volunteer & sold war bonds", + "Answer": "Mitchell" + }, + { + "Category": "1987", + "Question": "This British prime minister won a rare third term in June", + "Answer": "Margaret Thatcher" + }, + { + "Category": "SNACK ATTACK", + "Question": "I'll sip a Berries & Kreme Chiller with my hot Original Glazed doughnut from this chain", + "Answer": "Krispy Kreme" + }, + { + "Category": "ODDS & ENDS", + "Question": "This oil cartel controls 40% of world production", + "Answer": "OPEC" + }, + { + "Category": "FIRST LADIES' RHYME TIME", + "Question": "Mrs. Reagan's whims", + "Answer": "Nancy's fancies" + }, + { + "Category": "AUTHORS", + "Question": "In 1842 he lived with cannibals in the Taipi Valley in the Marquesas; his novel \"Typee\" was based on the experience", + "Answer": "Herman Melville" + }, + { + "Category": "1987", + "Question": "Pat Cash beat this Czech-born tennis great to win the Wimbledon singles title", + "Answer": "Lendl" + }, + { + "Category": "SNACK ATTACK", + "Question": "I've got a big appetite, so give me the Big Cup version of this Reese's treat", + "Answer": "a peanut butter cup" + }, + { + "Category": "BIRDS", + "Question": "Listen, you white-bellied bustard, I know where you live-- this continent's savanna", + "Answer": "Africa" + }, + { + "Category": "ODDS & ENDS", + "Question": "The USA's highest occupied office space is the 98th floor of this Chicago structure", + "Answer": "the Sears Tower" + }, + { + "Category": "FIRST LADIES' RHYME TIME", + "Question": "Mrs. Nixon's floor pads for gymnastics", + "Answer": "Pat's mats" + }, + { + "Category": "AUTHORS", + "Question": "He wrote his last short story, \"The Betrothed\", shortly before his play \"The Cherry Orchard\"", + "Answer": "Chekhov" + }, + { + "Category": "1987", + "Question": "A judge said no custody of \"Baby M\" for this type of mother who'd agreed to bear her for $10,000", + "Answer": "a surrogate" + }, + { + "Category": "SNACK ATTACK", + "Question": "I'd love some Honey Apple Raisin Chocolate Cookie ice cream, but this duo purposely misplaced the recipe", + "Answer": "Ben & Jerry" + }, + { + "Category": "ODDS & ENDS", + "Question": "On April 9, 1963 this Brit was made the first honorary U.S. citizen", + "Answer": "Winston Churchill" + }, + { + "Category": "FIRST LADIES' RHYME TIME", + "Question": "Mrs. Truman's frocks", + "Answer": "Bess's dresses" + }, + { + "Category": "AUTHORS", + "Question": "After years of writing science fiction, he found his niche with historical novels such as \"North and South\"", + "Answer": "Jakes" + }, + { + "Category": "1987", + "Question": "2 Russians made an impromptu spacewalk outside this space station & found a bag of trash that hindered docking", + "Answer": "Mir" + }, + { + "Category": "SNACK ATTACK", + "Question": "Wow! The Chocolate Delight snack bar named for this \"Miami\" diet has just 100 calories! I'll have 6 of them", + "Answer": "the South Beach diet" + }, + { + "Category": "BIRDS", + "Question": "Perhaps this \"thrush\", a type of babbler, hangs out at comedy clubs with the same-named hyena", + "Answer": "laughing thrush" + }, + { + "Category": "ODDS & ENDS", + "Question": "This French tennis star of the 1920s who went on to start a clothing line was known as \"the Crocodile\"", + "Answer": "Lacoste" + }, + { + "Category": "FIRST LADIES' RHYME TIME", + "Question": "Mrs. Ford's landing wharfs", + "Answer": "Betty's jetties" + }, + { + "Category": "AUTHORS", + "Question": "She first wrote \"Ethan Frome\" in French, then later translated it into English", + "Answer": "Edith Wharton" + }, + { + "Category": "1987", + "Question": "In October the Senate rejected this former Watergate figure's nomination to the Supreme Court", + "Answer": "Robert Bork" + }, + { + "Category": "SNACK ATTACK", + "Question": "I could eat a whole bag of this type of snack invented in Saratoga Springs in 1853", + "Answer": "potato chips" + }, + { + "Category": "ODDS & ENDS", + "Question": "Using beeswax, olive oil, rose petals & water, Galen invented this skin cleanser with a \"frigid\" name c. 200 A.D.", + "Answer": "cold cream" + }, + { + "Category": "FIRST LADIES' RHYME TIME", + "Question": "Mrs. Bush's luminous radiations", + "Answer": "Laura's auras" + }, + { + "Category": "MUNICH", + "Question": "In 1634 & 1635 an outbreak of this deadly contagion devastated Munich, killing more than one third of its residents", + "Answer": "bubonic plague" + }, + { + "Category": "\"AI\"", + "Question": "China or other ceramic objects can also be called this, after the material they're made of", + "Answer": "porcelain" + }, + { + "Category": "THE COLOR PURPLE", + "Question": "Established by George Washington in 1782, it can also be given to P.O.W.s who've been mistreated", + "Answer": "Purple Heart" + }, + { + "Category": "MINORITY REPORT", + "Question": "A 1936 dissent by Justice Stone accused 6 other justices of a \"tortured construction\" of this document", + "Answer": "the Constitution" + }, + { + "Category": "CLOSE ENCOUNTERS", + "Question": "When the earth is at perihelion, it is having its closest encounter with this", + "Answer": "the sun" + }, + { + "Category": "SPIELBERG MOVIES", + "Question": "Spielberg directed segment 2 of this 1983 movie based on a creepy anthology series", + "Answer": "Twilight Zone" + }, + { + "Category": "MUNICH", + "Question": "Munich's motto used to be \"die weltstadt mit herz\", the world city with one of these", + "Answer": "heart" + }, + { + "Category": "\"AI\"", + "Question": "This dictionary term meaning \"old\" is applied to words like \"wast\"", + "Answer": "archaic" + }, + { + "Category": "THE COLOR PURPLE", + "Question": "Day of the week in February 2006 when the top of the Empire State Building was lit purple, green & gold", + "Answer": "Tuesday" + }, + { + "Category": "MINORITY REPORT", + "Question": "In his first major case as Chief Justice, he found himself in the minority in 2006 as Oregon assisted suicide was okayed", + "Answer": "John Roberts" + }, + { + "Category": "CLOSE ENCOUNTERS", + "Question": "In a Wilde tale, an American family in the mansion Canterville Chase encounters this trying to scare them", + "Answer": "a ghost" + }, + { + "Category": "SPIELBERG MOVIES", + "Question": "This 1968 short film with a \"strollin\" title lent its name to Spielberg's production company", + "Answer": "Amblin" + }, + { + "Category": "MUNICH", + "Question": "The Summer Olympics in Munich in this year were sadly marred by terrorism & tragedy", + "Answer": "1972" + }, + { + "Category": "\"AI\"", + "Question": "This often blended rum & juice cocktail is named for a Cuban town", + "Answer": "daiquiri" + }, + { + "Category": "THE COLOR PURPLE", + "Question": "Defensive tackle Alan Page was part of the \"purple people eaters\" of this NFL team", + "Answer": "the Minnesota Vikings" + }, + { + "Category": "MINORITY REPORT", + "Question": "Justice Brennan, dissenting in Paris Adult Theater v. Slaton, said this quality is too vaguely defined to regulate", + "Answer": "obscenity" + }, + { + "Category": "CLOSE ENCOUNTERS", + "Question": "He's now a correspondant emeritus for \"60 Minutes\"; his memoir \"Close Encounters\" came out in 1984", + "Answer": "Mike Wallace" + }, + { + "Category": "SPIELBERG MOVIES", + "Question": "Spielberg wasn't paid for directing this film; he said it would be \"blood money\"", + "Answer": "Schindler's List" + }, + { + "Category": "MUNICH", + "Question": "On Munich's coat of arms you'll find one of these religious figures who originally settled the city and gave it its name", + "Answer": "monk" + }, + { + "Category": "\"AI\"", + "Question": "This 2-word term for a nanny is French for \"equal\"", + "Answer": "an au pair" + }, + { + "Category": "THE COLOR PURPLE", + "Question": "2 centuries late, this unstable British king was diagnosed with an excess of purple pigments in the blood", + "Answer": "King George III" + }, + { + "Category": "MINORITY REPORT", + "Question": "Justice Holmes dissented when seditionist Jacob Abrams' conviction was upheld, saying he didn't pose this type of \"danger\"", + "Answer": "clear and present" + }, + { + "Category": "CLOSE ENCOUNTERS", + "Question": "On May 13, 1981 he had a close encounter with Mehmet Ali Agca in Rome; he would later visit Agca in prison", + "Answer": "Pope John Paul II" + }, + { + "Category": "SPIELBERG MOVIES", + "Question": "13-year-old Christian Bale starred in this J.G. Ballard tale about a young prisoner in WWII China", + "Answer": "Empire of the Sun" + }, + { + "Category": "MUNICH", + "Question": "In the 16th century, Munich was a center of the German phase of this movement against Protestantism", + "Answer": "the Counter-Reformation" + }, + { + "Category": "\"AI\"", + "Question": "Broad-snouted and smooth-fronted are 2 types of this South American reptile", + "Answer": "caiman" + }, + { + "Category": "THE COLOR PURPLE", + "Question": "This purple flower is the state flower of Colorado", + "Answer": "the columbine" + }, + { + "Category": "MINORITY REPORT", + "Question": "Justice Harlan was an honorable one-man minority in this 1896 decision that enshrined the \"separate but equal\" doctrine", + "Answer": "Plessy v. Ferguson" + }, + { + "Category": "CLOSE ENCOUNTERS", + "Question": "In meteorology, when a cold one has a close encounter with a warm one & takes it over, it's called an occluded one", + "Answer": "a front" + }, + { + "Category": "SPIELBERG MOVIES", + "Question": "Before \"The Blues Brothers\", Dan Aykroyd & John Belushi starred in this WWII farce", + "Answer": "1941" + }, + { + "Category": "SHAKESPEAREAN TRAGEDY CHARACTERS", + "Question": "To the consternation of the title character, we learn that this character was born by C-section", + "Answer": "Macduff" + }, + { + "Category": "OPERA", + "Question": "Stationed in Seville, Don Jose is bewitched by a gypsy girl in this Bizet opera", + "Answer": "Carmen" + }, + { + "Category": "A TOM CRUISE FILM FESTIVAL", + "Question": "\"I lost the Number 1 draft pick the night before the draft!\"", + "Answer": "Jerry Maguire" + }, + { + "Category": "BODIES OF WATER", + "Question": "In 1975 the United Kingdom began piping oil from this sea to its shores", + "Answer": "the North Sea" + }, + { + "Category": "OCCUPATION HAZARDS", + "Question": "Chafing from chaps, rope burns from lassos & that saddle horn -- watch where you sit if you're one of these", + "Answer": "cowboy" + }, + { + "Category": "PLANT PARENTHOOD", + "Question": "Named for the Virgin Mary, these carnivorous little red beetles can help rid your garden of aphids & other insects", + "Answer": "ladybugs" + }, + { + "Category": "PRESIDENTIAL RHYME TIME", + "Question": "Ulysses' trousers", + "Answer": "Grant's pants" + }, + { + "Category": "OPERA", + "Question": "Like many of his works, this composer's \"Tannhauser\" is based on Germanic legends", + "Answer": "Wagner" + }, + { + "Category": "A TOM CRUISE FILM FESTIVAL", + "Question": "\"What I wouldn't give for a drop of good old-fashioned Creole blood\"", + "Answer": "Interview with the Vampire" + }, + { + "Category": "BODIES OF WATER", + "Question": "The St. Mary's River connects Lake Superior to this second-largest Great Lake", + "Answer": "Lake Huron" + }, + { + "Category": "OCCUPATION HAZARDS", + "Question": "If this is you're job you'd be fired if this clue go t by you uncorected", + "Answer": "proofreader" + }, + { + "Category": "PLANT PARENTHOOD", + "Question": "(Jimmy of the Clue Crew in the laboratory) Any glass or plastic container can be used to build one of these self-contained indoor gardens", + "Answer": "terrariums" + }, + { + "Category": "PRESIDENTIAL RHYME TIME", + "Question": "Arthur's school terms", + "Answer": "Chester's semesters" + }, + { + "Category": "OPERA", + "Question": "Mozart opera in which the count tries to thwart & postpone his valet's wedding", + "Answer": "The Marriage of Figaro" + }, + { + "Category": "A TOM CRUISE FILM FESTIVAL", + "Question": "\"I am a Vietnam veteran! I fought for my country!\"", + "Answer": "Born on the Fourth of July" + }, + { + "Category": "BODIES OF WATER", + "Question": "12,500' above sea level, this South American lake bordering Bolivia & Peru is the world's most navigable lake", + "Answer": "Lake Titicaca" + }, + { + "Category": "OCCUPATION HAZARDS", + "Question": "In this job aiding a medical professional, Angie might get a finger nipped by little Billy while X-raying his molar", + "Answer": "dental hygienist" + }, + { + "Category": "PLANT PARENTHOOD", + "Question": "Juniper & maple are good trees to use in this cultivating art whose name means \"plant in a tray\" in Japanese", + "Answer": "bonsai" + }, + { + "Category": "PRESIDENTIAL RHYME TIME", + "Question": "Zachary's wardens", + "Answer": "Taylor's jailers" + }, + { + "Category": "OPERA", + "Question": "Musetta has her very own waltz in Act II of this Puccini opera", + "Answer": "La boheme" + }, + { + "Category": "A TOM CRUISE FILM FESTIVAL", + "Question": "\"I'm gonna let ya in on a little secret, Ray. K-Mart sucks\"", + "Answer": "Rain Man" + }, + { + "Category": "BODIES OF WATER", + "Question": "At Khartoum, Sudan these colorful branches meet to form the Nile River", + "Answer": "the Blue Nile & the White Nile" + }, + { + "Category": "OCCUPATION HAZARDS", + "Question": "He has to listen to his wheels going round, round, round all day & may get a paper cut from a transfer", + "Answer": "bus driver" + }, + { + "Category": "PLANT PARENTHOOD", + "Question": "(Sarah of the Clue Crew in the laboratory) A must for any gardener, a soil testing kit is used to take a reading of this level, a measure of acidity", + "Answer": "pH level" + }, + { + "Category": "PRESIDENTIAL RHYME TIME", + "Question": "James' egg parts", + "Answer": "Polk's yolks" + }, + { + "Category": "OPERA", + "Question": "At 35 he decided for the first time to sit right down & write himself an opera; he produced \"Fidelio\"", + "Answer": "Beethoven" + }, + { + "Category": "A TOM CRUISE FILM FESTIVAL", + "Question": "\"They're dead...my team is dead...they knew we were coming\"", + "Answer": "Mission: Impossible" + }, + { + "Category": "BODIES OF WATER", + "Question": "After a 1,750-mile trip from Germany, this river breaks into 3 branches in Romania before emptying into the Black Sea", + "Answer": "the Danube" + }, + { + "Category": "OCCUPATION HAZARDS", + "Question": "If this is your job you might get brine in your eye after dropping the cucumber in the barrel", + "Answer": "pickler" + }, + { + "Category": "PLANT PARENTHOOD", + "Question": "The 3 elements most commonly found in garden fertilizers are phosphorus, potassium & this element", + "Answer": "nitrogen" + }, + { + "Category": "PRESIDENTIAL RHYME TIME", + "Question": "Tyler's conducting sticks", + "Answer": "John's batons" + }, + { + "Category": "THE ROYALS", + "Question": "She was the Virgin Queen or Good Queen Bess", + "Answer": "Elizabeth I" + }, + { + "Category": "THE TIGERS", + "Question": "Founded by Claire Chennault, these aviators shot down hundreds of Japanese planes during World War II", + "Answer": "the Flying Tigers" + }, + { + "Category": "THE GIANTS", + "Question": "1 Samuel 17 informs us that the Philistine city of Gath was the home of this giant", + "Answer": "Goliath" + }, + { + "Category": "THE REDS", + "Question": "This man's most avid supporters during the Cultural Revolution were students mobilized as \"Red Guards\"", + "Answer": "Mao Tse-tung" + }, + { + "Category": "THE \"A\"s", + "Question": "Winston Churchill said that this weapon \"brought peace, but man alone can keep that peace\"", + "Answer": "the atomic bomb" + }, + { + "Category": "BASEBALL HISTORY", + "Question": "In a June 19, 1846 game, J.W. Davis of the N.Y. Nine was fined 6 cents for swearing at this person", + "Answer": "the umpire" + }, + { + "Category": "THE ROYALS", + "Question": "Louis VI of France was known as this; as a child he must have shopped in le husky department", + "Answer": "Louis the Fat" + }, + { + "Category": "THE TIGERS", + "Question": "Now endangered, this largest variety of tiger bears the name of a large Russian region", + "Answer": "the Siberian tiger" + }, + { + "Category": "THE GIANTS", + "Question": "In Lilliput he's a giant", + "Answer": "Gulliver" + }, + { + "Category": "THE REDS", + "Question": "In the Catholic Church, they wear red hats", + "Answer": "cardinals" + }, + { + "Category": "THE \"A\"s", + "Question": "Some scientists believe the dinosaurs died out when one of these interstellar objects struck the Earth", + "Answer": "an asteroid" + }, + { + "Category": "BASEBALL HISTORY", + "Question": "To injure opposing players, Ty Cobb was said to sharpen these", + "Answer": "his spikes" + }, + { + "Category": "THE ROYALS", + "Question": "Russia's first ruler with this name was called Kalita, meaning \"moneybags\"; not so terrible", + "Answer": "Ivan" + }, + { + "Category": "THE TIGERS", + "Question": "Genus sphyraena, this long, thin predatory fish with protruding jaws & teeth is known as the \"tiger of the sea\"", + "Answer": "barracuda" + }, + { + "Category": "THE GIANTS", + "Question": "Jett Rink, a poor ranch hand, becomes an oil millionaire in her novel \"Giant\"", + "Answer": "Edna Ferber" + }, + { + "Category": "THE REDS", + "Question": "It's the world-famous \"colorful\" area seen here in the 1950s", + "Answer": "Red Square" + }, + { + "Category": "THE \"A\"s", + "Question": "Whether for a sorcerer or a craft guild, one serves time as one of these before becoming a journeyman", + "Answer": "apprentice" + }, + { + "Category": "BASEBALL HISTORY", + "Question": "Topps' 1952 series No. 311 was this player's first card & is a holy grail among collectors", + "Answer": "Mickey Mantle" + }, + { + "Category": "THE ROYALS", + "Question": "Charles Edward Stuart could have worn a T.Y.P. necklace for \"The Young Pretender\" or a B.P.C. one for this nickname", + "Answer": "Bonnie Prince Charlie" + }, + { + "Category": "THE TIGERS", + "Question": "One of this man's most famous poems begins, \"Tyger! Tyger! burning bright, in the forests of the night\"", + "Answer": "William Blake" + }, + { + "Category": "THE GIANTS", + "Question": "\"Giants in the Earth\" is Ole Rolvaag's novel about immigrants from this country adjusting to life on the prairie", + "Answer": "Norway" + }, + { + "Category": "THE REDS", + "Question": "About 1,200 miles long, it has a maximum depth of almost 10,000 feet", + "Answer": "the Red Sea" + }, + { + "Category": "THE \"A\"s", + "Question": "This \"Khan\" is the spiritual leader of the Ismaili sect of Muslims", + "Answer": "the Aga Khan" + }, + { + "Category": "BASEBALL HISTORY", + "Question": "2 of the 5 cities that had both National League & American League teams in 1903", + "Answer": "Boston, Chicago, New York, Philadelphia, St. Louis" + }, + { + "Category": "THE ROYALS", + "Question": "This first king of Poland was alliteratively nicknamed \"the Brave\"", + "Answer": "Boleslaw" + }, + { + "Category": "THE TIGERS", + "Question": "The autobiography written by this famous Nepalese was titled \"Tiger of the Snows\"", + "Answer": "Tenzing Norgay" + }, + { + "Category": "THE GIANTS", + "Question": "Odysseus incurs the wrath of Poseidon by blinding this giant Cyclops", + "Answer": "Polyphemus" + }, + { + "Category": "THE REDS", + "Question": "The flag of this U.K. division features an impressive red dragon with a forked tongue & tail", + "Answer": "Wales" + }, + { + "Category": "THE \"A\"s", + "Question": "In 1841 ex-president John Quincy Adams represented the mutineers of this ship before the Supreme Court", + "Answer": "the Amistad" + }, + { + "Category": "BASEBALL HISTORY", + "Question": "During his 22-year career he walked a then-record 2,056 times", + "Answer": "Babe Ruth" + }, + { + "Category": "20th CENTURY NOTABLES", + "Question": "Einstein said of him, \"Generations to come will scarcely believe\" one such as he \"walked the Earth in flesh & blood\"", + "Answer": "Mohandas Gandhi" + }, + { + "Category": "CINCO DE MAYO BIRTHDAYS", + "Question": "This co-author of \"Manifest Der Kommunisttischen Partei\" was born May 5, 1818", + "Answer": "Marx" + }, + { + "Category": "SAME TITLE, DIFFERENT SONG", + "Question": "You're nuts if you don't know this title of hits by Seal, Icehouse & Patsy Cline", + "Answer": "\"Crazy\"" + }, + { + "Category": "LOW TECH", + "Question": "A tactical formation in the form of a V, or an \"issue\" dividing an otherwise unified group", + "Answer": "a wedge" + }, + { + "Category": "POLITICIANS MAKE ME CUSS", + "Question": "\"For\" Michigan Republican congressman Hoekstra's \"sake!\"", + "Answer": "Pete's" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "This state's largest county, San Bernardino, was divided in 1893 to form Riverside county", + "Answer": "California" + }, + { + "Category": "ALL \"AMERICAN\"", + "Question": "Their publications include \"First Aid Fast\" & a \"Babysitter's Handbook\"", + "Answer": "the American Red Cross" + }, + { + "Category": "CINCO DE MAYO BIRTHDAYS", + "Question": "Philosopher Soren Kierkegaard was born May 5, 1813 in this capital", + "Answer": "Copenhagen" + }, + { + "Category": "SAME TITLE, DIFFERENT SONG", + "Question": "The Eagles in 1975 & The Emotions in 1977 both hit No. 1 singing about \"The Best Of\" this", + "Answer": "\"My Love\"" + }, + { + "Category": "LOW TECH", + "Question": "Ticonderoga is no. 1 in making no. 2 these, introduced in 1913", + "Answer": "pencils" + }, + { + "Category": "POLITICIANS MAKE ME CUSS", + "Question": "\"For the love of\" Wyoming senator Enzi!", + "Answer": "Mike" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Leadville in the Rockies in this state is the USA's highest incorporated city", + "Answer": "Colorado" + }, + { + "Category": "ALL \"AMERICAN\"", + "Question": "A gorilla named Koko learned to communicate using gestures from this", + "Answer": "American Sign Language" + }, + { + "Category": "CINCO DE MAYO BIRTHDAYS", + "Question": "Born May 5, 1919, Giorgios Papadopoulos became dictator of this country in 1967", + "Answer": "Greece" + }, + { + "Category": "SAME TITLE, DIFFERENT SONG", + "Question": "Robbie Nevil & B*witched had tunes called this French phrase meaning \"that's life\"", + "Answer": "\"C'est La Vie\"" + }, + { + "Category": "LOW TECH", + "Question": "16 tablespoons equals one of these", + "Answer": "a cup" + }, + { + "Category": "POLITICIANS MAKE ME CUSS", + "Question": "\"Heavens to\" ex-New York lieutenant governor McCaughey!", + "Answer": "Betsy" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "At about 1,700 square miles, this saline lake is one of the largest lakes in the world with no outlet", + "Answer": "the Salt Lake" + }, + { + "Category": "ALL \"AMERICAN\"", + "Question": "In 2009 this organization that maintains the largest registry for purebred dogs celebrated its 125th anniversary", + "Answer": "the American Kennel Club" + }, + { + "Category": "CINCO DE MAYO BIRTHDAYS", + "Question": "This May-5 born Monty Python member & BBC travel filmmaker is a commando of the Order of the British Empire", + "Answer": "Palin" + }, + { + "Category": "SAME TITLE, DIFFERENT SONG", + "Question": "Sammy Davis Jr. in 1972 & Christina Aguilera in 2007 sang about this sweet guy", + "Answer": "\"Candyman\"" + }, + { + "Category": "LOW TECH", + "Question": "This brand says its \"magic\" tape is \"the original matte-finish, invisible tape\"", + "Answer": "Scotch" + }, + { + "Category": "POLITICIANS MAKE ME CUSS", + "Question": "\"Geez\" House Rules Committee ranking Democrat Slaughter", + "Answer": "Louise" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Nome, Alaska lies on this peninsula named for a 19th century Secretary of State", + "Answer": "the Seward peninsula" + }, + { + "Category": "ALL \"AMERICAN\"", + "Question": "When Iowa farmers & their wives first saw this 1930 painting of a farm couple, many of them were downright angry", + "Answer": "American Gothic" + }, + { + "Category": "CINCO DE MAYO BIRTHDAYS", + "Question": "A culinary foundation is named for this dean of American cookery who was born in Portland May 5, 1903", + "Answer": "James Beard" + }, + { + "Category": "SAME TITLE, DIFFERENT SONG", + "Question": "Sticky-sweet title of no. 1s for Bobby Goldsboro in 1968 & Mariah Carey in 1997", + "Answer": "\"Honey\"" + }, + { + "Category": "LOW TECH", + "Question": "11-letter word for embroidery on canvas, with uniform spacing of stitches in a pattern", + "Answer": "needlepoint" + }, + { + "Category": "POLITICIANS MAKE ME CUSS", + "Question": "South Carolina legislator John \"O'Goshen!\"", + "Answer": "land" + }, + { + "Category": "ALL \"AMERICAN\"", + "Question": "In 2009 the U.S. Mint issued a quarter for this territory featuring an ava bowl, a whisk & a coconut tree", + "Answer": "American Samoa" + }, + { + "Category": "SCIENTISTS", + "Question": "This man's injected dead virus vaccine inspired Albert Sabin's live-virus oral vaccine for polio", + "Answer": "Salk" + }, + { + "Category": "ELIZABETH TAYLOR FILMS", + "Question": "This 1963 epic included 79 sets & 26,000 costumes", + "Answer": "Cleopatra" + }, + { + "Category": "WHY SO BLUE?", + "Question": "Utah's state tree is the blue type of this evergreen", + "Answer": "the spruce" + }, + { + "Category": "JURY DUTY", + "Question": "A deadlocked jury is this 4-letter word", + "Answer": "hung" + }, + { + "Category": "WHEN IN ROME?", + "Question": "The U.S. Fifth Army comes to town: June 4 of this year", + "Answer": "1944" + }, + { + "Category": "EPONYMS", + "Question": "This 2-word term for a skeptic refers to one of Jesus' apostles", + "Answer": "a doubting Thomas" + }, + { + "Category": "SCIENTISTS", + "Question": "This naturalist wrote, \"for my own part I would as soon be descended from that heroic little monkey\"", + "Answer": "Darwin" + }, + { + "Category": "ELIZABETH TAYLOR FILMS", + "Question": "Variety called it \"a horse picture\" with \"a new dramatic find-- moppet Elizabeth Taylor\"", + "Answer": "National Velvet" + }, + { + "Category": "JURY DUTY", + "Question": "This type of jury charged with deciding whether there's enough evidence to try a person may have up to 23 members", + "Answer": "a grand jury" + }, + { + "Category": "WHEN IN ROME?", + "Question": "Michaelangelo paints the Sistine Chapel: this century", + "Answer": "the 16th" + }, + { + "Category": "EPONYMS", + "Question": "This big hair style is derived from the title of a mistress of Louis XV", + "Answer": "a madame pompadour" + }, + { + "Category": "SCIENTISTS", + "Question": "Despite his advocacy of megadoses of vitamin c, he & his wife Ava got cancer", + "Answer": "Linus Pauling" + }, + { + "Category": "ELIZABETH TAYLOR FILMS", + "Question": "Mike Todd was killed in a plane crash while Liz was making this film in which she played Maggie Pollitt", + "Answer": "Cat on a Hot Tin Roof" + }, + { + "Category": "WHY SO BLUE?", + "Question": "This jeweler's blue box is a registered trademark", + "Answer": "Tiffany" + }, + { + "Category": "JURY DUTY", + "Question": "The general type of this military tribunal must have at least 5 members & the defense attorney may be military or civilian", + "Answer": "court martial" + }, + { + "Category": "WHEN IN ROME?", + "Question": "Mussolini becomes prime minister: this decade", + "Answer": "the 1920s" + }, + { + "Category": "EPONYMS", + "Question": "To abstain from buying or doing trade with, in honor of an Irish landlord against whom such tactics were used", + "Answer": "to boycott" + }, + { + "Category": "SCIENTISTS", + "Question": "This Russian's work on gastrointestinal secretions in animals earned him a Nobel prize", + "Answer": "Pavlov" + }, + { + "Category": "ELIZABETH TAYLOR FILMS", + "Question": "Liz won an Oscar for her role as a battlesome wife in this adaptation of an Albee play", + "Answer": "Who's Afraid of Virginia Woolf?" + }, + { + "Category": "JURY DUTY", + "Question": "In the Manson trial this isolation of a jury to protect it from outside influences lasted 8 1/2 months", + "Answer": "sequestering" + }, + { + "Category": "WHEN IN ROME?", + "Question": "Rome burns while an emperor relaxes in his villa at Antium: this century", + "Answer": "1st" + }, + { + "Category": "EPONYMS", + "Question": "This ancient king of Lydia, thought the wealthiest man on earth, had the Midas touch, hence the phrase \"as rich as\" him", + "Answer": "Croesus" + }, + { + "Category": "SCIENTISTS", + "Question": "He discovered that the observed frequency of light waves is affected by the relative motion of the source & detector", + "Answer": "Doppler" + }, + { + "Category": "ELIZABETH TAYLOR FILMS", + "Question": "James Dean, Rock Hudson & Liz formed a love triangle in this Texas-set film", + "Answer": "Giant" + }, + { + "Category": "WHY SO BLUE?", + "Question": "The blue type of this game fish, M. Nigricans, has a long pointed bill", + "Answer": "a marlin" + }, + { + "Category": "JURY DUTY", + "Question": "In selecting jurors, an attorney may reject some for no stated reason-- this type of challenge", + "Answer": "a peremptory challenge" + }, + { + "Category": "WHEN IN ROME?", + "Question": "Charlemagne is crowned emperor by Pope Leo III: this day, 800 A.D.", + "Answer": "Christmas" + }, + { + "Category": "WORLD LEADERS", + "Question": "Shortly after he received the 1990 Nobel Peace Prize, his country ceased to exist", + "Answer": "Mikhail Gorbachev" + }, + { + "Category": "I HAVE A PREPOSITION FOR YOU", + "Question": "This word meaning \"for each\" precedes annum or diem", + "Answer": "per" + }, + { + "Category": "2011 MOVIES", + "Question": "In \"Rise of the Planet of the Apes\" the name of the fictional drug ALZ112 indicates it's a possible treatment for this", + "Answer": "Alzheimer's" + }, + { + "Category": "GOING TO PIECES", + "Question": "This type of \"piece\" sounds like a smoking pipe, but it's an article written to flatter or glorify the subject", + "Answer": "a puff piece" + }, + { + "Category": "GROUP COUNTDOWN", + "Question": "In this sporting quintet, the center is considered No. 5 when diagramming plays", + "Answer": "a basketball team" + }, + { + "Category": "THE LAST BATTLE", + "Question": "The Siege of Yorktown", + "Answer": "the American Revolution" + }, + { + "Category": "THE NOBEL PEACE PRIZE", + "Question": "In his acceptance speech, Pres. Obama quoted this 1964 American recipient saying, \"violence never brings permanent peace\"", + "Answer": "King" + }, + { + "Category": "I HAVE A PREPOSITION FOR YOU", + "Question": "5-letter word meaning less by the subtraction of; don't overthink it", + "Answer": "minus" + }, + { + "Category": "2011 MOVIES", + "Question": "Emma Stone starred as aspiring writer Skeeter Phelan in this '60s-set drama based on a novel", + "Answer": "The Help" + }, + { + "Category": "GOING TO PIECES", + "Question": "Every Christmas, the Indiana post office in the town named for him postmarks a half a million pieces of mail", + "Answer": "Santa Claus" + }, + { + "Category": "GROUP COUNTDOWN", + "Question": "A foursome is required to play this game where you try to win the rubber", + "Answer": "bridge" + }, + { + "Category": "THE LAST BATTLE", + "Question": "The Battle of New Orleans", + "Answer": "the War of 1812" + }, + { + "Category": "I HAVE A PREPOSITION FOR YOU", + "Question": "It's the \"A\" in the advocacy group known as MADD", + "Answer": "Against" + }, + { + "Category": "2011 MOVIES", + "Question": "He was busy in 2011, with parts in \"Paul\", \"Horrible Bosses\" & \"The Change-Up\"", + "Answer": "Bateman" + }, + { + "Category": "GOING TO PIECES", + "Question": "The U.S. hasn't minted these, between a penny & a nickel, since 1872", + "Answer": "a two-cent coin" + }, + { + "Category": "GROUP COUNTDOWN", + "Question": "If Andy yearns for Brenda & Brenda cares about Charlene who pines for Andy, the 3 of them form one of these", + "Answer": "a love triangle" + }, + { + "Category": "THE LAST BATTLE", + "Question": "The Battle of the Meuse-Argonne", + "Answer": "World War I" + }, + { + "Category": "THE NOBEL PEACE PRIZE", + "Question": "1997's prize went in part to an international group trying to clear these from the world", + "Answer": "land mines" + }, + { + "Category": "I HAVE A PREPOSITION FOR YOU", + "Question": "Neil Gaiman wrote, \"Now slip, now slide, now move unseen, above, beneath, betwixt,\" this", + "Answer": "between" + }, + { + "Category": "2011 MOVIES", + "Question": "Known for his work as a Shakespearean actor, he directed \"Thor\"", + "Answer": "Branagh" + }, + { + "Category": "GOING TO PIECES", + "Question": "5-letter archaeological term for a broken scrap of earthenware", + "Answer": "a shard" + }, + { + "Category": "GROUP COUNTDOWN", + "Question": "In interrogation, one officer who acts threatening & another who comes on nicer to win the suspect's trust", + "Answer": "good cop, bad cop" + }, + { + "Category": "THE LAST BATTLE", + "Question": "The Battle of Chapultepec", + "Answer": "the Mexican-American War" + }, + { + "Category": "THE NOBEL PEACE PRIZE", + "Question": "This U.N. agency, created in 1946 to aid children in Europe, won the 1965 Peace Prize", + "Answer": "UNICEF" + }, + { + "Category": "I HAVE A PREPOSITION FOR YOU", + "Question": "It means against, & is also a prefix found before -diction", + "Answer": "contra" + }, + { + "Category": "2011 MOVIES", + "Question": "Kate Bosworth & James Marsden star in the 2011 remake of this Sam Peckinpah film", + "Answer": "Straw Dogs" + }, + { + "Category": "GOING TO PIECES", + "Question": "From the Latin for \"of the night\", these pensive musical pieces were popularized by Chopin & Bartok", + "Answer": "nocturnes" + }, + { + "Category": "GROUP COUNTDOWN", + "Question": "It can mean \"one\" or a military entity like the army's Third Armored Division", + "Answer": "unit" + }, + { + "Category": "THE LAST BATTLE", + "Question": "The Battle of Bosworth", + "Answer": "the Wars of the Roses" + }, + { + "Category": "THE NOBEL PEACE PRIZE", + "Question": "This 1990 winner said it was \"a recognition of what we call perestroika and innovative political thinking\"", + "Answer": "Gorbachev" + }, + { + "Category": "WHO'S AFRAID OF VIRGINIA WOOLF?", + "Question": "In an essay Woolf wrote, \"A woman must have money and a\" this \"of her own... to write fiction\"", + "Answer": "a room of one's own" + }, + { + "Category": "CARBON CREDITS", + "Question": "This gas, CO, prevents hemoglobin from supplying oxygen to the body", + "Answer": "carbon monoxide" + }, + { + "Category": "THEIR 4th TOP 40 HIT OF THE '60s", + "Question": "1964: \"Please Please Me\"", + "Answer": "The Beatles" + }, + { + "Category": "19th CENTURY PRESIDENTS", + "Question": "James K. Polk is the only president to have previously held this position in the House of Representatives", + "Answer": "Speaker" + }, + { + "Category": "IT CAME FROM THE NEW WORLD", + "Question": "In 1604 King James I called this plant a \"perpetual stinking torment\" & \"dangerous to the lungs\"; he was right", + "Answer": "tobacco" + }, + { + "Category": "TRANSLATION EXERCISES", + "Question": "Yiddish to French: The polite \"a sheynem dank\"", + "Answer": "merci beaucoup" + }, + { + "Category": "WHO'S AFRAID OF VIRGINIA WOOLF?", + "Question": "Virginia's father Sir Leslie Stephen was earlier married to a daughter of this \"Vanity Fair\" author", + "Answer": "Thackeray" + }, + { + "Category": "CARBON CREDITS", + "Question": "This 2-word study of living things is primarily devoted to carbon compounds", + "Answer": "organic chemistry" + }, + { + "Category": "THEIR 4th TOP 40 HIT OF THE '60s", + "Question": "1965: \"My Girl\"", + "Answer": "The Temptations" + }, + { + "Category": "IT CAME FROM THE NEW WORLD", + "Question": "Christopher Columbus sampled this grain in Cuba, declaring it \"most tasty boiled, roasted or ground into flour\"", + "Answer": "corn" + }, + { + "Category": "TRANSLATION EXERCISES", + "Question": "Turkish to Spanish: Relatively speaking, \"anne\" & \"baba\"", + "Answer": "madre y padre" + }, + { + "Category": "WHO'S AFRAID OF VIRGINIA WOOLF?", + "Question": "This 1928 title character begins as a man & ends, almost 400 years later, as a young woman (but not in Florida)", + "Answer": "Orlando" + }, + { + "Category": "CARBON CREDITS", + "Question": "AKA black lead, this form of carbon has a greasy feel & is used in making lubricants", + "Answer": "graphite" + }, + { + "Category": "THEIR 4th TOP 40 HIT OF THE '60s", + "Question": "1963: \"Walk Like A Man\"", + "Answer": "Frankie Valli and the Four Seasons" + }, + { + "Category": "19th CENTURY PRESIDENTS", + "Question": "The time of his administration was known as \"the Era of Good Feelings\"", + "Answer": "Monroe" + }, + { + "Category": "IT CAME FROM THE NEW WORLD", + "Question": "This fruit from the family Bromeliaceae is native to Brazil & Paraguay; it didn't reach Hawaii until the early 1500s", + "Answer": "the pineapple" + }, + { + "Category": "TRANSLATION EXERCISES", + "Question": "Portuguese to Russian: The positive \"sim\"", + "Answer": "da" + }, + { + "Category": "WHO'S AFRAID OF VIRGINIA WOOLF?", + "Question": "In 1904 Virginia & her siblings moved to this London district, where they would host \"group\" gatherings", + "Answer": "Bloomsbury" + }, + { + "Category": "CARBON CREDITS", + "Question": "This carbon isotope, 2 down from radiocarbon, is the standard for the relative atomic mass of other elements", + "Answer": "C-12" + }, + { + "Category": "THEIR 4th TOP 40 HIT OF THE '60s", + "Question": "1967: \"Girl, You'll Be A Woman Soon\"", + "Answer": "Neil Diamond" + }, + { + "Category": "IT CAME FROM THE NEW WORLD", + "Question": "When this member of the nightshade family reached Italy, it was known as pomi d'oro, or gold apple", + "Answer": "a tomato" + }, + { + "Category": "TRANSLATION EXERCISES", + "Question": "Polish to Latin: \"Bog\", a divine word", + "Answer": "deus" + }, + { + "Category": "WHO'S AFRAID OF VIRGINIA WOOLF?", + "Question": "Michael Cunningham's \"The Hours\" was inspired by this novel that Woolf originally called \"The Hours\"", + "Answer": "Mrs. Dalloway" + }, + { + "Category": "CARBON CREDITS", + "Question": "The atoms in a diamond are arranged in this \"4-faced\" pyramid-shaped pattern, giving it a rigid structure", + "Answer": "tetrahedral" + }, + { + "Category": "THEIR 4th TOP 40 HIT OF THE '60s", + "Question": "1963: \"You've Really Got A Hold On Me\"", + "Answer": "Smokey Robinson and the Miracles" + }, + { + "Category": "19th CENTURY PRESIDENTS", + "Question": "On Nov. 2, 1880 he was a member of the House of Representatives from Ohio, a senator-elect & president-elect", + "Answer": "Garfield" + }, + { + "Category": "IT CAME FROM THE NEW WORLD", + "Question": "Also known as butter beans, they were, prior to being exported to Europe, a diet staple of the Inca", + "Answer": "lima beans" + }, + { + "Category": "TRANSLATION EXERCISES", + "Question": "Swahili to German: The magic word \"tafadhali\"", + "Answer": "bitte" + }, + { + "Category": "COUNTRIES' HIGHEST PEAKS", + "Question": "These 2 nations, one an island, have highest peaks with the same name; they also share a common European culture", + "Answer": "Greece & Cyprus" + }, + { + "Category": "SNL CELEBRITY JEOPARDY!", + "Question": "As he did in \"Anchorman\", Will Ferrell sports this facial feature in the \"SNL\" \"Jeopardy!\" skits", + "Answer": "a mustache" + }, + { + "Category": "STATES THAT END IN HAMPSHIRE", + "Question": "The Franklin Pierce Law Center & Christa McAuliffe Planetarium can be found in this capital of New Hampshire", + "Answer": "Concord" + }, + { + "Category": "WHAT COLOR IS GREEN?", + "Question": "God did make these, & some of them are Granny Smiths", + "Answer": "apples" + }, + { + "Category": "CURRENT BLACK PRESIDENTS", + "Question": "Africa's oldest democracy, this nation headed by Pres. Ian Khama is mainly made up of the Tswana people", + "Answer": "Botswana" + }, + { + "Category": "SOUNDS THAT KITTIES MAKE", + "Question": "This sound made by lions can carry 5 miles", + "Answer": "a roar" + }, + { + "Category": "TWINKLE TWINKLE LITTLE WORD THAT RHYMES WITH STAR", + "Question": "Proverbial food storage container where your \"hand is caught\" when busted for taking a bribe", + "Answer": "the cookie jar" + }, + { + "Category": "SNL CELEBRITY JEOPARDY!", + "Question": "Darrell Hammond played this Scottish actor who... Nope, I can't say anything else; just name him", + "Answer": "Sean Connery" + }, + { + "Category": "STATES THAT END IN HAMPSHIRE", + "Question": "New Hampshire is bounded to the north by this Canadian province, the country's largest in area", + "Answer": "Quebec" + }, + { + "Category": "WHAT COLOR IS GREEN?", + "Question": "Lincoln Green is also called this green, where you might see it were it not for the trees", + "Answer": "a forest" + }, + { + "Category": "CURRENT BLACK PRESIDENTS", + "Question": "Taking over from his assassinated father in 2001, Joseph Kabila is the president of this country abbreviated D.R.C.", + "Answer": "the Democratic Republic of the Congo" + }, + { + "Category": "SOUNDS THAT KITTIES MAKE", + "Question": "This sound of aggression from a domestic cat is also produced by vipers", + "Answer": "a hiss" + }, + { + "Category": "TWINKLE TWINKLE LITTLE WORD THAT RHYMES WITH STAR", + "Question": "A 1-pound tin of premium sevruga this can go for more than $2,000", + "Answer": "caviar" + }, + { + "Category": "SNL CELEBRITY JEOPARDY!", + "Question": "Norm MacDonald played this \"Smokey and the Bandit\" star who had a slight problem IDing Pat Morita's ancestry", + "Answer": "Burt Reynolds" + }, + { + "Category": "STATES THAT END IN HAMPSHIRE", + "Question": "Chartered in 1769, this Ivy League school is N.H.'s oldest & ranks among the 10 oldest U.S. colleges", + "Answer": "Dartmouth" + }, + { + "Category": "WHAT COLOR IS GREEN?", + "Question": "This old song says, \"Alas, my love, you do me wrong, to cast me off discourteously\"", + "Answer": "\"Greensleeves\"" + }, + { + "Category": "CURRENT BLACK PRESIDENTS", + "Question": "Troubles with neighboring Somalia & Eritrea surely occupy President Girma Woldegiorgis of this country", + "Answer": "Ethiopia" + }, + { + "Category": "SOUNDS THAT KITTIES MAKE", + "Question": "In \"The Maltese Falcon\", Dashiell Hammett wrote, \"'That will be excellent,' Gutman\" did this", + "Answer": "purred" + }, + { + "Category": "TWINKLE TWINKLE LITTLE WORD THAT RHYMES WITH STAR", + "Question": "Django Reinhardt was a master of this instrument", + "Answer": "the guitar" + }, + { + "Category": "SNL CELEBRITY JEOPARDY!", + "Question": "Ben Stiller played this star of \"The Firm\" on a show where one category was \"FOODS THAT END IN 'AMBURGER'\"", + "Answer": "Tom Cruise" + }, + { + "Category": "STATES THAT END IN HAMPSHIRE", + "Question": "New Hampshire's Squam Lakes provided the title location for this 1981 Fonda & Hepburn film", + "Answer": "On Golden Pond" + }, + { + "Category": "WHAT COLOR IS GREEN?", + "Question": "This American political party that formed in 1874 favored an increase in paper currency", + "Answer": "the Greenback Party" + }, + { + "Category": "CURRENT BLACK PRESIDENTS", + "Question": "President Laurent Gbagbo heads this country that goes by its French name most of the time", + "Answer": "Côte d'Ivoire" + }, + { + "Category": "SOUNDS THAT KITTIES MAKE", + "Question": "This threatening sound can also mean \"to become tangled\"", + "Answer": "snarled" + }, + { + "Category": "TWINKLE TWINKLE LITTLE WORD THAT RHYMES WITH STAR", + "Question": "The incarnation of a god in Hindu myth, or an Internet graphical image representing a person", + "Answer": "an avatar" + }, + { + "Category": "SNL CELEBRITY JEOPARDY!", + "Question": "Kristen Wiig played this \"Today\" co-host, who, like so many of our players, brought Chardonnay on stage", + "Answer": "Kathie Lee Gifford" + }, + { + "Category": "STATES THAT END IN HAMPSHIRE", + "Question": "Also the name of a \"United\" city in England, this city lies along the banks of the Merrimack River", + "Answer": "Manchester" + }, + { + "Category": "WHAT COLOR IS GREEN?", + "Question": "This play says, \"Beware, my lord, of jealousy; it is the green-eyed monster\"", + "Answer": "Othello" + }, + { + "Category": "CURRENT BLACK PRESIDENTS", + "Question": "President Amadou Toure has led this Saharan nation with a 4-letter name since 2002", + "Answer": "Mali" + }, + { + "Category": "SOUNDS THAT KITTIES MAKE", + "Question": "Starting around 1922, this phrase meant something excellent or desirable", + "Answer": "the cat's meow" + }, + { + "Category": "TWINKLE TWINKLE LITTLE WORD THAT RHYMES WITH STAR", + "Question": "This animal's scientific name is Panthera onca", + "Answer": "jaguar" + }, + { + "Category": "WORDS OF LOVE", + "Question": "He concludes \"The Divine Comedy\" with \"The love that moves the sun and the other stars\"", + "Answer": "Dante" + }, + { + "Category": "NEEDY NO.1 HITMAKERS", + "Question": "1964: \"I Want To Hold Your Hand\"", + "Answer": "The Beatles" + }, + { + "Category": "FRUIT", + "Question": "The name of this fruit, genus Prunus, can precede picker, pie & Coke", + "Answer": "cherry" + }, + { + "Category": "ENDS WITH 3 VOWELS", + "Question": "Hawaiian feast", + "Answer": "a luau" + }, + { + "Category": "DON'T BE A PAIN", + "Question": "This drug marketed as Advil & Nuprin reduces pain by inhibiting chemicals that cause inflammation", + "Answer": "ibuprofen" + }, + { + "Category": "WORDS OF LOVE", + "Question": "Marlowe rhymed, \"Where both deliberate, the love is slight; who ever loved, that loved not at\" this?", + "Answer": "first sight" + }, + { + "Category": "NEEDY NO.1 HITMAKERS", + "Question": "1987: \"I Wanna Dance With Somebody (Who Loves Me)\"", + "Answer": "Houston" + }, + { + "Category": "FRUIT", + "Question": "More than 50 medications are affected by the juice of this citrus fruit; its enzymes break down the meds", + "Answer": "grapefruit" + }, + { + "Category": "ENDS WITH 3 VOWELS", + "Question": "Pierre's \"farewell\"", + "Answer": "adieu" + }, + { + "Category": "DON'T BE A PAIN", + "Question": "To control pain, some patients try this technique in which they monitor their body functions & try to alter them", + "Answer": "biofeedback" + }, + { + "Category": "WORDS OF LOVE", + "Question": "In \"Prometheus Unbound\", he wrote, \"All love is sweet, given or returned. Common as light is love\"", + "Answer": "Percy Bysshe Shelley" + }, + { + "Category": "NEEDY NO.1 HITMAKERS", + "Question": "1956: \"I Want You, I Need You, I Love You\"", + "Answer": "Elvis" + }, + { + "Category": "FRUIT", + "Question": "This fuzzy fruit is also a slang term meaning inform against or betray", + "Answer": "peach" + }, + { + "Category": "ENDS WITH 3 VOWELS", + "Question": "Dresser", + "Answer": "a bureau" + }, + { + "Category": "DON'T BE A PAIN", + "Question": "Trigger point injections are used to treat this muscle contraction, from the Latin for \"convulsion\"", + "Answer": "a spasm" + }, + { + "Category": "WORDS OF LOVE", + "Question": "Virgil's \"omnia vincit amor\" is translated as this", + "Answer": "love conquers all" + }, + { + "Category": "NEEDY NO.1 HITMAKERS", + "Question": "1984: \"I Want To Know What Love Is\"", + "Answer": "Foreigner" + }, + { + "Category": "FRUIT", + "Question": "The liqueur creme de cassis is made with the black type of this fruit", + "Answer": "currant" + }, + { + "Category": "ENDS WITH 3 VOWELS", + "Question": "Emmy-winning actor Bridges", + "Answer": "Beau" + }, + { + "Category": "DON'T BE A PAIN", + "Question": "Pain registers in one area of the outer portion of the cerebrum called the cerebral this", + "Answer": "cortex" + }, + { + "Category": "WORDS OF LOVE", + "Question": "\"In her first passion woman loves her lover, in all the others all she loves is love\", he wrote in \"Don Juan\"", + "Answer": "Byron" + }, + { + "Category": "NEEDY NO.1 HITMAKERS", + "Question": "1970: \"I Want You Back\"", + "Answer": "The Jackson 5" + }, + { + "Category": "FRUIT", + "Question": "Fraise is French for this fruit", + "Answer": "strawberry" + }, + { + "Category": "ENDS WITH 3 VOWELS", + "Question": "Environment or setting", + "Answer": "milieu" + }, + { + "Category": "DON'T BE A PAIN", + "Question": "There are several types of these nerve cells: some respond to temperature, some to pressure & some to pain", + "Answer": "sensory receptors" + }, + { + "Category": "ODD TITLES", + "Question": "Gilbert & Sullivan's \"Mikado\", not Milne, gave us this hyphenated title for a pompous functionary", + "Answer": "grand poo-bah" + }, + { + "Category": "STATES' FORMER CAPITALS", + "Question": "New Haven", + "Answer": "Connecticut" + }, + { + "Category": "NBA HALL OF FAMERS", + "Question": "He won an NBA title ring in 1973 as a reserve forward with the Knicks & coached the Bulls to 6 titles in the '90s", + "Answer": "Phil Jackson" + }, + { + "Category": "SECRET MENUS", + "Question": "A move to healthy eating got the Pizza Sub nixed from this chain, but we hear if you ask nicely some stores will make it", + "Answer": "Subway" + }, + { + "Category": "DIED ON THE SAME DAY", + "Question": "C.S. Lewis & Aldous Huxley's deaths on Nov. 22, 1963 were overshadowed by this man's death in Dallas", + "Answer": "John Kennedy" + }, + { + "Category": "LET'S CALL TRIPLE \"A\"", + "Question": "From the Italian for \"bad air\", this disease kills more than one million people each year", + "Answer": "malaria" + }, + { + "Category": "STRING THEORY 101", + "Question": "String puppets are often called these, affer a certain virgin", + "Answer": "marionettes" + }, + { + "Category": "STATES' FORMER CAPITALS", + "Question": "Knoxville", + "Answer": "Tennessee" + }, + { + "Category": "NBA HALL OF FAMERS", + "Question": "In 2000 this former Celtics player coached the Indiana Pacers to the NBA finals", + "Answer": "Larry Bird" + }, + { + "Category": "SECRET MENUS", + "Question": "Wendy's will make you a grand slam burger with this many patties, but don't tell everyone", + "Answer": "four" + }, + { + "Category": "DIED ON THE SAME DAY", + "Question": "Just hours before Michael Jackson's death, Hollywood lost this TV \"Angel\"", + "Answer": "Farrah Fawcett" + }, + { + "Category": "LET'S CALL TRIPLE \"A\"", + "Question": "In 1775 this island in San Francisco Bay was called \"Island of the Pelicans\"", + "Answer": "Alcatraz" + }, + { + "Category": "STRING THEORY 101", + "Question": "If you're emotionally dependent on mom, you're \"tied to\" these \"strings\"", + "Answer": "apron strings" + }, + { + "Category": "STATES' FORMER CAPITALS", + "Question": "Wheeling", + "Answer": "West Virginia" + }, + { + "Category": "NBA HALL OF FAMERS", + "Question": "Abe Saperstein is in the Hall of Fame, as is this team he promoted & coached for decades", + "Answer": "The Harlem Globetrotters" + }, + { + "Category": "SECRET MENUS", + "Question": "Have it your way at this chain & order a Mustard Whopper, which substitutes the yellow stuff for mayo", + "Answer": "Burger King" + }, + { + "Category": "DIED ON THE SAME DAY", + "Question": "On April 25,1995 first \"Jeopardy!\" host Art Fleming passed away & the dance was over for this partner of Fred", + "Answer": "Ginger Rogers" + }, + { + "Category": "LET'S CALL TRIPLE \"A\"", + "Question": "God requires adult Muslims to fast during this month so they may cultivate piety", + "Answer": "Ramadan" + }, + { + "Category": "STRING THEORY 101", + "Question": "A 1942 big band hit was entitled \"String Of\" these", + "Answer": "\"String Of Pearls\"" + }, + { + "Category": "STATES' FORMER CAPITALS", + "Question": "Huntsville", + "Answer": "Alabama" + }, + { + "Category": "NBA HALL OF FAMERS", + "Question": "As a rookie in the 1980 NBA finals, this Michigan State alum played all 5 positions & scored 42 points in the final game", + "Answer": "Magic Johnson" + }, + { + "Category": "SECRET MENUS", + "Question": "Fatburger offers a \"Hypocrite Burger\" featuring this type of patty with slabs of bacon", + "Answer": "veggie patty" + }, + { + "Category": "DIED ON THE SAME DAY", + "Question": "This famed aviator outlived his brother by 35 years, passing away in 1948 on the same day Gandhi was assassinated", + "Answer": "Orville Wright" + }, + { + "Category": "LET'S CALL TRIPLE \"A\"", + "Question": "The university environment", + "Answer": "academia" + }, + { + "Category": "STRING THEORY 101", + "Question": "In the U.S. string cheese is usually a type of this cheese", + "Answer": "mozzarella" + }, + { + "Category": "STATES' FORMER CAPITALS", + "Question": "Guthrie", + "Answer": "Oklahoma" + }, + { + "Category": "NBA HALL OF FAMERS", + "Question": "This Nigeria-born Rockets player holds the NBA record for career blocked shots with 3,830", + "Answer": "Hakeem Olajuwon" + }, + { + "Category": "SECRET MENUS", + "Question": "Ask this chain that's inspired by a fictional pirate for a \"side of crumbs\", & you'll get some fried batter bits", + "Answer": "Long John Silver's" + }, + { + "Category": "DIED ON THE SAME DAY", + "Question": "Italian filmmaker Michelangelo Antonioni died in 2007 at age 94 on the same day as this 89-year-old Swedish director", + "Answer": "Ingmar Bergman" + }, + { + "Category": "LET'S CALL TRIPLE \"A\"", + "Question": "San Diego County is estimated to have a million acres of this Spanish-named dense shrub growth", + "Answer": "chaparral" + }, + { + "Category": "STRING THEORY 101", + "Question": "Aglets are found on the ends of these strings", + "Answer": "shoelaces" + }, + { + "Category": "LIBRARIES", + "Question": "In 1889 this philanthropist funded his first U.S. library in Braddock, Penn., home to one of his steel mills", + "Answer": "Carnegie" + }, + { + "Category": "THE HOUND OF MUSIC", + "Question": "Songwriter Scott English started an urban myth when he jokingly said this 1975 Barry Manilow No. 1 hit was about a dog", + "Answer": "\"Mandy\"" + }, + { + "Category": "PLAY ADJECTIVES", + "Question": "David Yazbek & Jeffrey Lane's musical \"____ ____ Scoundrels\"", + "Answer": "Dirty Rotten" + }, + { + "Category": "JERSEY GIRLS", + "Question": "Doing laundry in the sink, this \"Jersey Shore\" girl aka Nicole Polizzi said, \"I feel like a pilgrim from the friggin' '20s\"", + "Answer": "Snooki" + }, + { + "Category": "RUSSIAN", + "Question": "A shapka is this: mikhavaya shapka is a fur one, to keep your ears warm", + "Answer": "a hat" + }, + { + "Category": "STRING THEORY 201", + "Question": "String theory attempts to merge quantum mechanics with Einstein's general theory of this", + "Answer": "relativity" + }, + { + "Category": "LIBRARIES", + "Question": "Raffaele Farina, known as Bibliothecarius XLVI, is its head librarian", + "Answer": "the Vatican" + }, + { + "Category": "PLAY ADJECTIVES", + "Question": "Tennessee Williams' \"____ Bird of Youth\"", + "Answer": "Sweet Bird of Youth" + }, + { + "Category": "JERSEY GIRLS", + "Question": "This Algonquin wit was born in West End, N.J. in 1893 & was a drama critic for Vanity Fair by 1917", + "Answer": "Dorothy Parker" + }, + { + "Category": "RUSSIAN", + "Question": "\"Idyot snyek\" means this is happening, a common weather condition in January", + "Answer": "snowing" + }, + { + "Category": "STRING THEORY 201", + "Question": "In certain string theories, you can get up to 26 of these; we're used to dealing with 4 of them, of which length is one", + "Answer": "dimensions" + }, + { + "Category": "LIBRARIES", + "Question": "This Ivy League school's Nassau Hall once served as its library; today, books are housed in the Firestone library", + "Answer": "Princeton" + }, + { + "Category": "THE HOUND OF MUSIC", + "Question": "Paul Anka & Donny Osmond both had hits with this tune that sounds like it's about a young dog's affection", + "Answer": "\"Puppy Love\"" + }, + { + "Category": "PLAY ADJECTIVES", + "Question": "Mark Medoff's \"Children of a ____ God\"", + "Answer": "Lesser" + }, + { + "Category": "JERSEY GIRLS", + "Question": "Jersey City-born, this \"Living Omnimedia\" lifestyle maven was raised in Nutley, & that's a good thing", + "Answer": "Martha Stewart" + }, + { + "Category": "RUSSIAN", + "Question": "Blinaya means this, the \"hop\" in IHOP", + "Answer": "house of pancakes" + }, + { + "Category": "STRING THEORY 201", + "Question": "A successful string theory would describe nature's 4 forces: weak, strong, electromagnetism & this one", + "Answer": "gravity" + }, + { + "Category": "LIBRARIES", + "Question": "This Maryland community is home to the National Library of Medicine & the National Naval Medical Center", + "Answer": "Bethesda" + }, + { + "Category": "THE HOUND OF MUSIC", + "Question": "Title question posed by Patti Page in a 1953 smash", + "Answer": "\"How Much Is That Doggie In The Window?\"" + }, + { + "Category": "PLAY ADJECTIVES", + "Question": "Noel Coward 's \"____ Spirit\"", + "Answer": "Blithe Spirit" + }, + { + "Category": "JERSEY GIRLS", + "Question": "This \"Fudge\"-tastic children's author was born in Elizabeth, New Jersey", + "Answer": "Judy Blume" + }, + { + "Category": "STRING THEORY 201", + "Question": "String theory is part of this \"P\" branch of physics that studies eensy little items", + "Answer": "particle" + }, + { + "Category": "LIBRARIES", + "Question": "Among this San Marino, California library's exhibits are a 15th century manuscript of \"The Canterbury Tales\" & a Gutenberg Bible", + "Answer": "the Huntington Library" + }, + { + "Category": "PLAY ADJECTIVES", + "Question": "Howard Sackler's \"The ____ ____ Hope\"", + "Answer": "The Great White Hope" + }, + { + "Category": "JERSEY GIRLS", + "Question": "Governor of New Jersey form 1994 to 2001, she appointed the state's first female Attorney General", + "Answer": "Christine Whitman" + }, + { + "Category": "RUSSIAN", + "Question": "Russian word for a home like Novo-Ogarevo, Vladimir Putin's forest retreat near Moscow", + "Answer": "a dacha" + }, + { + "Category": "STRING THEORY 201", + "Question": "Bosonic string theory has only bosons & none of these particles named for physicist Enrico", + "Answer": "fermions" + }, + { + "Category": "PRISONS", + "Question": "Nazi Rudolf Hess in 1941 & the notorious Kray twins in 1952 were among the last people briefly held here", + "Answer": "the Tower of London" + }, + { + "Category": "RUSSIA", + "Question": "In the July 3, 1996 runoff, he defeated Gennadi Zyuganov", + "Answer": "Boris Yeltsin" + }, + { + "Category": "ACTORS & ACTRESSES", + "Question": "This \"Alien\" actress starred in her long-time pal Christopher Durang's 1996 play \"Sex and Longing\"", + "Answer": "Sigourney Weaver" + }, + { + "Category": "BIOGRAPHIES", + "Question": "\"Rare Air\" is a photo biography of this basketball star", + "Answer": "Michael Jordan" + }, + { + "Category": "BUSINESS", + "Question": "The tires on Lindbergh's \"Spirit of St. Louis\" were made by this former competitor of Goodyear", + "Answer": "B.F. Goodrich" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "This \"Messiah\" composer's first job was as a church organist in Halle, Germany, at age 17", + "Answer": "Georg Handel" + }, + { + "Category": "PROVERBS", + "Question": "\"You can't make a silk purse\" out of this", + "Answer": "a sow's ear" + }, + { + "Category": "RUSSIA", + "Question": "In 1996 this Russian newspaper stopped publishing after 84 years", + "Answer": "Pravda" + }, + { + "Category": "ACTORS & ACTRESSES", + "Question": "Don't blink--or you'll miss Richard Dreyfuss in this 1967 film based on a Jacqueline Susann novel", + "Answer": "Valley of the Dolls" + }, + { + "Category": "BIOGRAPHIES", + "Question": "This actor-director is the subject of David Thomson's biography \"Rosebud\"", + "Answer": "Orson Welles" + }, + { + "Category": "BUSINESS", + "Question": "In 1866, William A. Breyer started the company that's now the oldest national producer of this", + "Answer": "ice cream" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "\"Variations on a Theme by Haydn\" was this \"lullaby\" composer's first major work for full orchestra", + "Answer": "Johannes Brahms" + }, + { + "Category": "PROVERBS", + "Question": "\"Imitation is the sincerest form of\" it, but beware, it \"corrupts both the receiver and the giver\"", + "Answer": "flattery" + }, + { + "Category": "RUSSIA", + "Question": "In April of 1996, Russian rockets killed Dzhokhar Dudayev, this breakaway republic's leader", + "Answer": "Chechnya" + }, + { + "Category": "ACTORS & ACTRESSES", + "Question": "This \"Seinfeld\" co-star became a Broadway star at age 23 in Stephen Sondheim's musical \"Merrily we Roll Along\"", + "Answer": "Jason Alexander" + }, + { + "Category": "BIOGRAPHIES", + "Question": "\"Shalom, Friend\" tells of \"The Life and Legacy\" of this slain Israeli leader", + "Answer": "Yitzhak Rabin" + }, + { + "Category": "BUSINESS", + "Question": "This San Francisco-based clothing company's full name includes \"De Corps\"", + "Answer": "Esprit" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "In 1977, his \"Immortal Beloved\" was identified as Antonie Brentano, wife of a merchant", + "Answer": "Beethoven" + }, + { + "Category": "PROVERBS", + "Question": "It's where you should \"never tell tales\"", + "Answer": "out of school" + }, + { + "Category": "RUSSIA", + "Question": "Abbreviated CIS, it replaced the USSR", + "Answer": "Commonwealth of Independent States" + }, + { + "Category": "ACTORS & ACTRESSES", + "Question": "John Mahoney, who plays Martin Crane on this sitcom, was born in England; he moved to the U.S. when he was 19", + "Answer": "Frasier" + }, + { + "Category": "BIOGRAPHIES", + "Question": "\"The Education of a Woman\" by Carolyn G. Heilbrun tells of this feminist and famous Ms", + "Answer": "Gloria Steinem" + }, + { + "Category": "BUSINESS", + "Question": "From 1875 to 1989, this New York company's name included \"Glassworks\"", + "Answer": "Corning" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "This father-in-law of Richard Wagner died July 31, 1886, during the Wagner festival at Bayreuth", + "Answer": "Franz Liszt" + }, + { + "Category": "PROVERBS", + "Question": "The saying \"Strike while the iron is hot\" originally alluded to this profession", + "Answer": "blacksmith" + }, + { + "Category": "RUSSIA", + "Question": "They're the colors of the three stripes on the Russian flag", + "Answer": "red, white, and blue" + }, + { + "Category": "ACTORS & ACTRESSES", + "Question": "Professional name used by the actress seen here during her film career; it's different from her married name (clip from \"Hellcats of the Navy\")", + "Answer": "Nancy Davis" + }, + { + "Category": "BIOGRAPHIES", + "Question": "Known for his \"Compleat Angler\", he also wrote a biography of his friend, writer John Donne", + "Answer": "Izaak Walton" + }, + { + "Category": "BUSINESS", + "Question": "This Warner-Lambert product contains retsyn, a finely homogenized vegetable oil", + "Answer": "Certs" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "He composed his \"Leningrad Symphony\" during the World War II siege of Leningrad", + "Answer": "Dmitri Shostakovich" + }, + { + "Category": "PROVERBS", + "Question": "These two things \"wait for no man\"", + "Answer": "time and tide" + }, + { + "Category": "THE SUPREME COURT", + "Question": "Justices Butler, Van DeVanter, Sutherland, and McReynolds opposed this president's \"New Deal\"", + "Answer": "F.D. Roosevelt" + }, + { + "Category": "LANGUAGES", + "Question": "This Scandinavian language changed \"aa\" to a circle-topped \"a\", making it closer to Swedish and Norwegian", + "Answer": "Danish" + }, + { + "Category": "SCIENTISTS", + "Question": "In 1633 this astronomer was found guilty of \"vehement suspicion of heresy\"", + "Answer": "Galileo" + }, + { + "Category": "THE CIVIL WAR", + "Question": "Union pay department officers wore the M1840, one of these weapons that featured a straight 31\" all-gilt blade", + "Answer": "Sword" + }, + { + "Category": "POETRY", + "Question": "In stanza three of \"The Star Spangled Banner\", he mocks \"The hireling and slave\" who doubt America's victory", + "Answer": "Francis Scott Key" + }, + { + "Category": "ODDS & ENDS", + "Question": "This city's Hartsfield International overtook O'Hare as the world's busiest airport even before the Summer Olympics", + "Answer": "Atlanta" + }, + { + "Category": "THE SUPREME COURT", + "Question": "This president called his 1953 appointment of Earl Warren \"the biggest damn' fool mistake I ever made\"", + "Answer": "Eisenhower" + }, + { + "Category": "LANGUAGES", + "Question": "All of the Romance languages have their roots in this language", + "Answer": "Latin" + }, + { + "Category": "SCIENTISTS", + "Question": "This botanist was hailed as \"The Wizard of Tuskegee\"", + "Answer": "George Washington Carver" + }, + { + "Category": "THE CIVIL WAR", + "Question": "On May 29, 1865, he issued a general amnesty for most rebels; the rich and those with high ranks weren't included", + "Answer": "Andrew Johnson" + }, + { + "Category": "POETRY", + "Question": "Poe said this maiden \"lived with no other thought than to love and be loved by me\"", + "Answer": "Annabel Lee" + }, + { + "Category": "ODDS & ENDS", + "Question": "For about $200 a whack, you can spend the night at the Fall River MA home of this alleged murderess", + "Answer": "Lizzie Borden" + }, + { + "Category": "THE SUPREME COURT", + "Question": "In 1995 two justices rejected The Citadel's appeal of an order to admit her", + "Answer": "Shannon Faulkner" + }, + { + "Category": "LANGUAGES", + "Question": "Balinese is spoken on several islands of this country", + "Answer": "Indonesia" + }, + { + "Category": "SCIENTISTS", + "Question": "The symbol \"J\" as a unit of energy honors this physicist", + "Answer": "Joule" + }, + { + "Category": "THE CIVIL WAR", + "Question": "In June of 1861, Dorothea Dix was appointed to supervise the female ones of these", + "Answer": "nurses" + }, + { + "Category": "POETRY", + "Question": "Originally, he didn't want his \"Elegy Written in a Country Churchyard\" published", + "Answer": "Gray" + }, + { + "Category": "ODDS & ENDS", + "Question": "They're the two main ingredients in a Cape Codder cocktail", + "Answer": "cranberry juice and vodka" + }, + { + "Category": "THE SUPREME COURT", + "Question": "He served as Chief Justice the longest; 34 years from 1801-1835", + "Answer": "John Marshall" + }, + { + "Category": "LANGUAGES", + "Question": "Hungarians call their official language this", + "Answer": "Magyar" + }, + { + "Category": "SCIENTISTS", + "Question": "In 1791 this Italian published the results of his experiments in \"animal electricity\"", + "Answer": "Luigi Galvani" + }, + { + "Category": "THE CIVIL WAR", + "Question": "In the Gettysburg campaign, Lee's forces were along Seminary Ridge and the federal forces along this ridge", + "Answer": "Cemetery Ridge" + }, + { + "Category": "POETRY", + "Question": "His series \"Bells and Pomegranates\" included \"Pippa Passes\" and \"My Last Duchess\"", + "Answer": "Robert Browning" + }, + { + "Category": "ODDS & ENDS", + "Question": "Muhammad received the first of the Koran's revelations during this holy month", + "Answer": "Ramadan" + }, + { + "Category": "THE SUPREME COURT", + "Question": "After the 1987 rejection of this man's nomination to the court, Anthony Kennedy filled Powell's seat", + "Answer": "Robert Bork" + }, + { + "Category": "LANGUAGES", + "Question": "Punjabi is spoken by about half of all households in this country", + "Answer": "Pakistan" + }, + { + "Category": "SCIENTISTS", + "Question": "His 1637 \"Discours de la methode\" prefaced a series of essays on optics, meteorology, and geometry", + "Answer": "Rene Descartes" + }, + { + "Category": "THE CIVIL WAR", + "Question": "Hero of the War of 1812 and the Mexican War, he resigned November 1, 1861, as head of the Union army", + "Answer": "Winfield Scott" + }, + { + "Category": "POETRY", + "Question": "This poet to whom T.S. Eliot dedicated \"The Wasteland\" ended up in a mental institution", + "Answer": "Ezra Pound" + }, + { + "Category": "ODDS & ENDS", + "Question": "It's the smaller of the two bones in the lower leg", + "Answer": "the fibula" + }, + { + "Category": "RIVERS", + "Question": "It was once believed that this river \"originated in the Mountains of the Moon\"", + "Answer": "the Nile" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "In June 1991 weightlessness experiments were conducted on about 2,500 jellyfish aboard this", + "Answer": "the Space Shuttle" + }, + { + "Category": "RUN, RUN, RUN", + "Question": "If you want to hit this type of \"contained\" home run, you probably will need to run really fast", + "Answer": "an inside-the-park home run" + }, + { + "Category": "MILITARY SLANG", + "Question": "This 2-word term, also a movie title, is slang for Navy Fighter Weapons School", + "Answer": "Top Gun" + }, + { + "Category": "SCULPTURE", + "Question": "In 1953 sculptor William Zorach created the relief \"Man and Work\" for this Rochester, Minnesota clinic", + "Answer": "the Mayo Clinic" + }, + { + "Category": "BUSINESS BUDDIES", + "Question": "S. Duncan Black & this partner filed a patent for a drill in 1914", + "Answer": "Decker" + }, + { + "Category": "COMMON SIMILES", + "Question": "If you're scared, you might be \"shaking like\" this botanical item", + "Answer": "a leaf" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "The ARS, an agency of this U.S. government department, is looking to develop better bio-insecticides", + "Answer": "the Department of Agriculture" + }, + { + "Category": "RUN, RUN, RUN", + "Question": "In 1925 N.Y. Journal-American writer Bill Corum first called the Kentucky Derby the \"run for\" these", + "Answer": "the roses" + }, + { + "Category": "MILITARY SLANG", + "Question": "\"Angels\" is slang for this measurement of height, in thousands of feet", + "Answer": "altitude" + }, + { + "Category": "SCULPTURE", + "Question": "This country's 12th century sculptor Unkei is known for his wooden statues carved for Buddhist temples", + "Answer": "Japan" + }, + { + "Category": "BUSINESS BUDDIES", + "Question": "This maker of optical products borrowed money from his good friend Henry Lomb, but it turned out okay", + "Answer": "Bausch" + }, + { + "Category": "COMMON SIMILES", + "Question": "Adjective found before \"as leather\" & \"as nails\"", + "Answer": "tough" + }, + { + "Category": "RUN, RUN, RUN", + "Question": "Due to an increase of endorphins in the brain, it's a state of euphoria experienced by exercisers", + "Answer": "runner's high" + }, + { + "Category": "MILITARY SLANG", + "Question": "\"SAR\" stands for this, the effort to extract a downed aircrew in a combat zone", + "Answer": "search and rescue" + }, + { + "Category": "SCULPTURE", + "Question": "Bartolommeo Ammannati designed this city's Fountain of Neptune & the courtyard of the Pitti Palace", + "Answer": "Florence" + }, + { + "Category": "BUSINESS BUDDIES", + "Question": "Book publisher Henry Houghton made this guy his partner", + "Answer": "Mifflin" + }, + { + "Category": "COMMON SIMILES", + "Question": "This ichthyological simile might apply to someone spending too much time at the bar", + "Answer": "drinking like a fish" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Platinum, atomic number 78, is worth more than this other metal, atomic number 79", + "Answer": "gold" + }, + { + "Category": "RUN, RUN, RUN", + "Question": "This 2-word hoops term is an offensive rush to beat the defense to the hoop", + "Answer": "a fast break" + }, + { + "Category": "MILITARY SLANG", + "Question": "A \"polliwog\" has never crossed this geographic line while aboard ship", + "Answer": "the equator" + }, + { + "Category": "SCULPTURE", + "Question": "An art museum on Madison Avenue is named for this sculptress who created the Titanic Memorial in Washington, D.C.", + "Answer": "Gertrude Vanderbilt Whitney" + }, + { + "Category": "BUSINESS BUDDIES", + "Question": "Postage meter inventor Arthur Pitney merged his company with that of this entrepreneur", + "Answer": "Bowes" + }, + { + "Category": "COMMON SIMILES", + "Question": "Ironically, something incomprehensible is said to be \"as clear as\" this 3-letter word", + "Answer": "mud" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "In 2009 a new hominid skeleton dubbed Ardi was aged at 4.4 million years, predating this other \"girly\" find by 1 mil. years", + "Answer": "Lucy" + }, + { + "Category": "RUN, RUN, RUN", + "Question": "In the modern pentathlon, athletes go 3,000 meters in this hyphenated type of running", + "Answer": "cross-country" + }, + { + "Category": "MILITARY SLANG", + "Question": "A \"ROAD\" scholar is \"retired on\" this (coasting until actual retirement)", + "Answer": "active duty" + }, + { + "Category": "SCULPTURE", + "Question": "This English sculptor made one of his reclining figures for the 1951 Festival of Britain", + "Answer": "Henry Moore" + }, + { + "Category": "BUSINESS BUDDIES", + "Question": "A crossword puzzle book started it all for Richard L. Simon & this publishing partner", + "Answer": "Schuster" + }, + { + "Category": "WORLD CAPITALS", + "Question": "It's located about 30 miles south of the DMZ", + "Answer": "Seoul" + }, + { + "Category": "LYRICS FROM MUSICALS", + "Question": "\"Beauty school dropout, no graduation day for you\"", + "Answer": "Grease" + }, + { + "Category": "THE NEW YORK TIMES 2009 FICTION BESTSELLERS", + "Question": "Temperance Brennan is accused of mishandling an autopsy in Kathy Reichs' \"206\" these body parts", + "Answer": "Bones" + }, + { + "Category": "PAPAL NAMES", + "Question": "The constellation between Cancer & Virgo", + "Answer": "Leo" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "From the Greek for \"shape\", it means to transform an image into something else by computer", + "Answer": "morph" + }, + { + "Category": "WORLD CAPITALS", + "Question": "Until 1918 & the collapse of the dynasty, it was home base for the Hapsburgs", + "Answer": "Vienna" + }, + { + "Category": "LYRICS FROM MUSICALS", + "Question": "\"A boy like that who'd kill your brother, forget that boy & find another, one of your own kind\"", + "Answer": "West Side Story" + }, + { + "Category": "THE NEW YORK TIMES 2009 FICTION BESTSELLERS", + "Question": "Hey, y'all, this CNN legal analyst made the list with her novel \"The Eleventh Victim\"", + "Answer": "Nancy Grace" + }, + { + "Category": "PAPAL NAMES", + "Question": "Not guilty", + "Answer": "Innocent" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "In the scientific classification of animals, it's Chordata for a domesticated dog", + "Answer": "phylum" + }, + { + "Category": "WORLD CAPITALS", + "Question": "It's the largest English-speaking city in the Caribbean, mon", + "Answer": "Kingston" + }, + { + "Category": "LYRICS FROM MUSICALS", + "Question": "\"Shoeless Joe from Hannibal, Mo. Lucky are we to be having him\"", + "Answer": "Damn Yankees" + }, + { + "Category": "THE NEW YORK TIMES 2009 FICTION BESTSELLERS", + "Question": "In \"Dead and Gone\" by Charlaine Harris, this \"True Blood\" waitress searches for the killer of a werepanther", + "Answer": "Sookie Stackhouse" + }, + { + "Category": "PAPAL NAMES", + "Question": "From the Latin for \"blessed\"", + "Answer": "Benedict" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "The bar type is one common form of this chart", + "Answer": "graph" + }, + { + "Category": "WORLD CAPITALS", + "Question": "This South American capital's original longer name translated to \"Saint Mary of the Fair Winds\"", + "Answer": "Buenos Aires" + }, + { + "Category": "LYRICS FROM MUSICALS", + "Question": "\"Once I'm with the Wizard my whole life will change, 'cuz once you're with the Wizard no one thinks you're strange\"", + "Answer": "Wicked" + }, + { + "Category": "THE NEW YORK TIMES 2009 FICTION BESTSELLERS", + "Question": "\"Homer & Langley\" by this author of \"Ragtime\" details the lives of the reclusive Collyer Brothers", + "Answer": "Doctorow" + }, + { + "Category": "PAPAL NAMES", + "Question": "The winner of a contest", + "Answer": "Victor" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "Now meaning those who are hostile to the arts, in biblical times it was a people subdued by King David", + "Answer": "a Philistine" + }, + { + "Category": "WORLD CAPITALS", + "Question": "On a plane trip to this capital, you'd likely land at Soekarno-Hatta International Airport", + "Answer": "Jakarta" + }, + { + "Category": "LYRICS FROM MUSICALS", + "Question": "\"Suddenly Seymour is standing beside me, he don't give me orders, he don't condescend\"", + "Answer": "Little Shop of Horrors" + }, + { + "Category": "THE NEW YORK TIMES 2009 FICTION BESTSELLERS", + "Question": "Richard DiLallo & this author teamed to write \"Alex Cross's 'Trial", + "Answer": "Patterson" + }, + { + "Category": "PAPAL NAMES", + "Question": "From a Latin word for \"doer of good\"", + "Answer": "Boniface" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "Because the Greek goddess Artemis was associated with the Moon, she was also called this, which means \"light one\"", + "Answer": "Phoebe" + }, + { + "Category": "COMPOSERS", + "Question": "In 1928, the 100th anniversary of his death, a $10,000 prize was offered for the completion of his 8th Symphony", + "Answer": "Schubert" + }, + { + "Category": "THE VIRTUES", + "Question": "It's paired with liberty in the Pledge of Allegiance", + "Answer": "justice" + }, + { + "Category": "\"L.B.\"s", + "Question": "Even before Thomas Edison, Sir Joseph Wilson Swan was aglow with his invention of this", + "Answer": "light bulb" + }, + { + "Category": "SPORTS HOME CITIES", + "Question": "The NFL's Saints", + "Answer": "New Orleans" + }, + { + "Category": "JUBAL EARLY", + "Question": "Confederate general Jubal Early idolized this general, who called him \"My Bad Old Man\"", + "Answer": "Robert E. Lee" + }, + { + "Category": "BIRDS", + "Question": "The akepa & akiapola'au are found in forest areas, only in this state", + "Answer": "Hawaii" + }, + { + "Category": "WORMS", + "Question": "This mythological bird was reborn from a worm which emerged from its funeral ashes", + "Answer": "phoenix" + }, + { + "Category": "THE VIRTUES", + "Question": "We assume that Bill Clinton was born with it; we know he was born in it", + "Answer": "Hope" + }, + { + "Category": "\"L.B.\"s", + "Question": "And now the weather forecast: tonight expect these gentle winds of 4 to 7 miles per hour", + "Answer": "light breezes" + }, + { + "Category": "SPORTS HOME CITIES", + "Question": "MLB's Royals", + "Answer": "Kansas City" + }, + { + "Category": "JUBAL EARLY", + "Question": "After moving back to the U.S. from Canada in 1869, Early, rebel that he was, wore only this color", + "Answer": "gray" + }, + { + "Category": "BIRDS", + "Question": "The only birds in the family Trochilidae are these \"hovercrafts\"", + "Answer": "hummingbirds" + }, + { + "Category": "WORMS", + "Question": "He told the Diet of Worms, \"I do not accept the authority of popes and councils\"", + "Answer": "Martin Luther" + }, + { + "Category": "THE VIRTUES", + "Question": "You \"Gotta Have\" this virtue; at least according to George Michael", + "Answer": "Faith" + }, + { + "Category": "\"L.B.\"s", + "Question": "Herbie, the endearing Volkswagen in a classic Disney film", + "Answer": "The Love Bug" + }, + { + "Category": "SPORTS HOME CITIES", + "Question": "The NBA's Cavaliers", + "Answer": "Cleveland" + }, + { + "Category": "JUBAL EARLY", + "Question": "In July 1864, Early & his troops threatened this city & were later criticized for not taking it", + "Answer": "Washington, D.C." + }, + { + "Category": "BIRDS", + "Question": "During mating season the male ruff develops a large frill of feathers around this body part", + "Answer": "neck" + }, + { + "Category": "WORMS", + "Question": "In \"Henry VI, Part 3\", Clifford tells the king that \"The smallest worm will\" do this \"being trodden on\"", + "Answer": "turn" + }, + { + "Category": "THE VIRTUES", + "Question": "It was the \"T\" in the 19th century's WCTU", + "Answer": "Temperance" + }, + { + "Category": "\"L.B.\"s", + "Question": "Oscar-nominated for her role in \"Goodfellas\", she went on to play Dr. Jennifer Melfi on \"The Sopranos\"", + "Answer": "Lorraine Bracco" + }, + { + "Category": "SPORTS HOME CITIES", + "Question": "The NHL's Senators", + "Answer": "Ottawa" + }, + { + "Category": "JUBAL EARLY", + "Question": "Before the Civil War, Early had garrison duty in the Mexican War under this man, \"Old Rough and Ready\"", + "Answer": "Zachary Taylor" + }, + { + "Category": "BIRDS", + "Question": "This falcon's name is from the Latin for \"foreign\" or \"a foreigner\"", + "Answer": "peregrine" + }, + { + "Category": "WORMS", + "Question": "The name of this red shade is from the Latin for \"worm\"; the dye was first made from cochineal insects", + "Answer": "vermillion" + }, + { + "Category": "THE VIRTUES", + "Question": "This virtue is also a name of a Rhode Island island & of prim, cautious women", + "Answer": "Prudence" + }, + { + "Category": "\"L.B.\"s", + "Question": "In 1893 this horticulturist published his first nursery catalog offering his \"New Creations in Fruits and Flowers\"", + "Answer": "Luther Burbank" + }, + { + "Category": "SPORTS HOME CITIES", + "Question": "MLS' Burn", + "Answer": "Dallas" + }, + { + "Category": "JUBAL EARLY", + "Question": "Early, a man known for his patriarchal beard, was active in this party in Virginia in the 1840s", + "Answer": "Whig" + }, + { + "Category": "BIRDS", + "Question": "The scientific name of this big bird is Diomedea exulans, as in \"exile\"", + "Answer": "albatross" + }, + { + "Category": "WORMS", + "Question": "In this 1965 sci-fi novel, giant sandworms on the planet Arrakis create a much-desired spice called melange", + "Answer": "\"Dune\"" + }, + { + "Category": "STATES OF THE UNION", + "Question": "Its near islands are farthest from its mainland; Kodiak is closer", + "Answer": "Alaska" + }, + { + "Category": "MUD", + "Question": "Of an artist, a fish, or a wasp, it's what a mud dauber is", + "Answer": "wasp" + }, + { + "Category": "\"T\" TIME AT THE LIBRARY", + "Question": "In book titles, this adjective precedes Gertrude Stein's \"Buttons\" & Fitzgerald's \"is the Night\"", + "Answer": "Tender" + }, + { + "Category": "JULIA ROBERTS FILM FEST", + "Question": "It was viva Las Vegas for Julia, who played the Angie Dickinson role in the remake of this film", + "Answer": "Ocean's Eleven" + }, + { + "Category": "WOMEN'S HEALTH", + "Question": "It's the trimester of pregnancy in which women gain the least weight", + "Answer": "first" + }, + { + "Category": "DOUBLE LETTERS", + "Question": "It's the one of the 4 gospels in the New Testament that fits the category", + "Answer": "Matthew" + }, + { + "Category": "STATES OF THE UNION", + "Question": "Cimarron & Beaver are counties in its Panhandle", + "Answer": "Oklahoma" + }, + { + "Category": "MUD", + "Question": "In 1943 McKinley Morganfield, under this name, settled in Chicago & continued singing the blues", + "Answer": "Muddy Waters" + }, + { + "Category": "\"T\" TIME AT THE LIBRARY", + "Question": "Check out this famous British woman's 2002 book \"Statecraft: Strategies for a Changing World\"", + "Answer": "Margaret Thatcher" + }, + { + "Category": "JULIA ROBERTS FILM FEST", + "Question": "(Hi, I'm Leonard Maltin) I like to think of this 2000 Julia Roberts movie as an \"Energetic, engaging David vs. Goliath story\"", + "Answer": "Erin Brockovich" + }, + { + "Category": "WOMEN'S HEALTH", + "Question": "Set down that plastic bottle -- CNN reports that you don't really need this mythical number of glasses of water a day", + "Answer": "8" + }, + { + "Category": "DOUBLE LETTERS", + "Question": "It can precede \"sickness\" or \"beauty\" as well as \"porch\"", + "Answer": "sleeping" + }, + { + "Category": "STATES OF THE UNION", + "Question": "To go from Norwalk to Norwich in this state, head east on I-95 to I-395 north", + "Answer": "Connecticut" + }, + { + "Category": "MUD", + "Question": "The phrase \"His name is mud\" predates Dr. Mudd's setting this assassin's leg, so it doesn't mean the doctor", + "Answer": "John Wilkes Booth" + }, + { + "Category": "\"T\" TIME AT THE LIBRARY", + "Question": "Watch out for \"personal injuries\" if you lift all his legal thrillers, including \"Personal Injuries\", at once", + "Answer": "Scott Turow" + }, + { + "Category": "JULIA ROBERTS FILM FEST", + "Question": "The 2 movies in which Julia starred opposite Richard Gere", + "Answer": "Pretty Woman & Runaway Bride" + }, + { + "Category": "WOMEN'S HEALTH", + "Question": "Often given with progesterone, it's the main hormone in hormone replacement therapy", + "Answer": "estrogen" + }, + { + "Category": "DOUBLE LETTERS", + "Question": "(Jimmy of the Clue Crew having a pass thrown to him by Charlie Batch of the Pittsburgh Steelers) The name of this pass pattern is also a type of fastener", + "Answer": "buttonhook" + }, + { + "Category": "STATES OF THE UNION", + "Question": "Commonwealth whose state seal [\"United We Stand, Divided We Fall\"] is seen here", + "Answer": "Kentucky" + }, + { + "Category": "MUD", + "Question": "This poem set in Mudville was first published in the San Francisco Examiner, in 1888", + "Answer": "\"Casey at the Bat\"" + }, + { + "Category": "\"T\" TIME AT THE LIBRARY", + "Question": "It's the third book of the autobiographical trilogy that began with \"Tropic of Cancer\"", + "Answer": "\"Triopic of Capricorn\"" + }, + { + "Category": "JULIA ROBERTS FILM FEST", + "Question": "In her first major role, Julia served up Italian food New England style in this movie", + "Answer": "Mystic Pizza" + }, + { + "Category": "WOMEN'S HEALTH", + "Question": "In a \"Got Milk\" ad, Jennifer Love Hewitt says she hates this bone condition, so she has fat free milk with every meal", + "Answer": "osteoporosis" + }, + { + "Category": "DOUBLE LETTERS", + "Question": "The petals of a flower considered as a group, or a model of Toyota", + "Answer": "Corolla" + }, + { + "Category": "STATES OF THE UNION", + "Question": "The 4 large stars on the flag of Arkansas represent the U.S., France, Spain & this", + "Answer": "the Confederacy" + }, + { + "Category": "MUD", + "Question": "In 1999 scientists found the remains of one of these giant creatures embedded in the frozen mud in Siberia", + "Answer": "mammoth" + }, + { + "Category": "\"T\" TIME AT THE LIBRARY", + "Question": "Hawthorne's college classmate Horatio Bridge paid for the publication of this collection of \"Tales\"", + "Answer": "\"Twice-Told Tales\"" + }, + { + "Category": "JULIA ROBERTS FILM FEST", + "Question": "Justine Bateman, not Julia, got top billing in this 1988 film about teenage girls who form a band", + "Answer": "Satisfaction" + }, + { + "Category": "WOMEN'S HEALTH", + "Question": "Joint pain is one symptom of SLE, a common disorder in women that's also called by this 5-letter name", + "Answer": "lupus" + }, + { + "Category": "DOUBLE LETTERS", + "Question": "This Anglo-Saxon kingdom east of Cornwall was probably founded in the 6th century by Prince Cerdic & his son Cynric", + "Answer": "Wessex" + }, + { + "Category": "20th CENTURY U.S. PRESIDENTS", + "Question": "This president shares his middle name with the name of a 1st C. Jewish theologian mentioned in the New Testament", + "Answer": "Warren Gamaliel Harding" + }, + { + "Category": "LANGUAGES", + "Question": "Scholars agree that the oldest form of this language can be found in the song of Deborah in Judges", + "Answer": "Hebrew" + }, + { + "Category": "MAD", + "Question": "TV host seen here on the cover of Mad Magazine", + "Answer": "Jeff Probst" + }, + { + "Category": "SPORTS", + "Question": "Ben Crenshaw & Phil Mickelson are the only 3-time winners of this college sport's championship tournament", + "Answer": "golf" + }, + { + "Category": "WHO IS THEON OF SMYRNA?", + "Question": "Like Ptolemy, about whom he wrote, Theon placed this body in the center of the cosmos", + "Answer": "Earth" + }, + { + "Category": "\"LESS\" IS MORE", + "Question": "Type of whisper in the title of a Wham! hit", + "Answer": "Careless" + }, + { + "Category": "VEGAS, BABY", + "Question": "An illusion, a fantasy, a pipe dream, or a Las Vegas hotel", + "Answer": "Mirage" + }, + { + "Category": "LANGUAGES", + "Question": "This language is known by its speakers as Nederlands", + "Answer": "Dutch" + }, + { + "Category": "MAD", + "Question": "What made this Mel Gibson character mad was outlaw bikers killing his wife & kid", + "Answer": "Max" + }, + { + "Category": "SPORTS", + "Question": "(I'm Hall of Fame running back Tony Dorsett) This man was my coach for my first 11 seasons in the NFL", + "Answer": "Tom Landry" + }, + { + "Category": "WHO IS THEON OF SMYRNA?", + "Question": "Theon's home of Smyrna is now called Izmir & is one of the chief seaports of this country of Asia Minor", + "Answer": "Turkey" + }, + { + "Category": "\"LESS\" IS MORE", + "Question": "It's Southwest Airlines' name for the paper-free type of travel it introduced on all routes in January 1995", + "Answer": "Ticketless" + }, + { + "Category": "VEGAS, BABY", + "Question": "A legendary weapon that emerged from a lake, or a Las Vegas hotel", + "Answer": "Excalibur" + }, + { + "Category": "LANGUAGES", + "Question": "Of Inka, Dinka or Doo, an actual language spoken in southern Sudan", + "Answer": "Dinka" + }, + { + "Category": "MAD", + "Question": "Back in the '60s Sue Kaufman wrote the \"Diary of a Mad\" this", + "Answer": "Housewife" + }, + { + "Category": "SPORTS", + "Question": "In 1994, at age 45, he became heavyweight boxing champ again & was the AP's Male Athlete of the Year", + "Answer": "George Foreman" + }, + { + "Category": "WHO IS THEON OF SMYRNA?", + "Question": "Theon's greatest work, available on Amazon.com, has mathematics useful for understanding this \"Republic\" author", + "Answer": "Plato" + }, + { + "Category": "\"LESS\" IS MORE", + "Question": "Putting it before \"Communism\", Harry Truman popularized the use of this word meaning \"atheistic\"", + "Answer": "godless" + }, + { + "Category": "VEGAS, BABY", + "Question": "The European playground seen here, or a Las Vegas hotel", + "Answer": "Monte Carlo" + }, + { + "Category": "LANGUAGES", + "Question": "More than 375 languages & dialects are spoken in this country's Madhya Pradesh state", + "Answer": "India" + }, + { + "Category": "MAD", + "Question": "Clicking on the Encarta index entry of Mad Anthony will take you to this man", + "Answer": "Anthony Wayne" + }, + { + "Category": "SPORTS", + "Question": "He was director of athletics at NYC's Downtown Athletic Club from 1928 to 1936", + "Answer": "John Heisman" + }, + { + "Category": "WHO IS THEON OF SMYRNA?", + "Question": "Writing on these, Theon covers, among others, the circular, oblong, prime & even ones", + "Answer": "numbers" + }, + { + "Category": "\"LESS\" IS MORE", + "Question": "(Video clue of a pair of glasses; text unavailable due to sound problems)", + "Answer": "rimless" + }, + { + "Category": "VEGAS, BABY", + "Question": "The bird Phoenicopterus ruber roseus, or a Las Vegas hotel", + "Answer": "Flamingo" + }, + { + "Category": "LANGUAGES", + "Question": "Gaspar Karolyi's translation of the Bible in 1590 was influential in the development of this as a national language", + "Answer": "Hungarian" + }, + { + "Category": "MAD", + "Question": "The Cold War nuclear balance was known as \"MAD\", mutually assured this", + "Answer": "destruction" + }, + { + "Category": "SPORTS", + "Question": "In the 1992-93 season this Pittsburgh Penguin missed 24 games but still won the NHL scoring title", + "Answer": "Mario Lemieux" + }, + { + "Category": "WHO IS THEON OF SMYRNA?", + "Question": "Theon seems to have lived at the same time that this Roman emperor was building his famous wall", + "Answer": "Hadrian" + }, + { + "Category": "\"LESS\" IS MORE", + "Question": "Jean-Paul Belmondo is the cool criminal Michel in this French New Wave classic", + "Answer": "Breathless" + }, + { + "Category": "THE BLUE ANGELS", + "Question": "(Sarah of the Clue Crew riding in a Blue Angels jet) On takeoff, for a high-performance climb, pilots can experience six times the force of this", + "Answer": "gravity" + }, + { + "Category": "TONY-WINNING COMPOSERS", + "Question": "1980: \"Evita\"", + "Answer": "Andrew Lloyd Webber" + }, + { + "Category": "SPEECH! SPEECH!", + "Question": "Subject of Daniel Webster's March 7, 1850 & Frederick Douglass' July 5, 1852 speeches", + "Answer": "slavery" + }, + { + "Category": "FEDERAL AID PROGRAMS", + "Question": "The Black Lung Program benefits those who worked as these, & their widows & their dependents", + "Answer": "coal miners" + }, + { + "Category": "\"A\" PLUS", + "Question": "Iran & Pakistan both border this nation", + "Answer": "Afghanistan" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "Meg, Jo, Beth & Amy March have crushes on Rupert Birkin & Gerald Crich in this D.H. Lawrence novel", + "Answer": "Little Women in Love" + }, + { + "Category": "THE BLUE ANGELS", + "Question": "(Sarah of the Clue Crew on the tarmac) When the Blue Angels perform the formation known for this precious gem, the jets are only 12 inches apart", + "Answer": "diamond" + }, + { + "Category": "TONY-WINNING COMPOSERS", + "Question": "1993: \"The Who's Tommy\"", + "Answer": "Pete Townshend" + }, + { + "Category": "SPEECH! SPEECH!", + "Question": "Nicholas Butler told Columbia grads, \"An expert is one who knows more and more about\" this and this", + "Answer": "less and less" + }, + { + "Category": "FEDERAL AID PROGRAMS", + "Question": "State with the highest average monthly food stamp benefit per person; at over $100, that's a lot of poi", + "Answer": "Hawaii" + }, + { + "Category": "\"A\" PLUS", + "Question": "When he launched the comic strip \"Dilbert\" in 1989, this man was an engineer working for Pacific Bell", + "Answer": "Scott Adams" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "Daisy Miller & Natty Bumppo could have joined forces in a novel by this author", + "Answer": "Henry James Fenimore Cooper" + }, + { + "Category": "THE BLUE ANGELS", + "Question": "(Sarah of the Clue Crew riding in a Blue Angels jet) With a ceiling of over 50,000 feet, the Blue Angels jets, FA-18s, are known by the name of this insect", + "Answer": "hornet" + }, + { + "Category": "TONY-WINNING COMPOSERS", + "Question": "1973: \"A Little Night Music\"", + "Answer": "Stpehen Sondheim" + }, + { + "Category": "SPEECH! SPEECH!", + "Question": "This onetime governor of Texas delivered the keynote speech at the 1988 Democratic Convention", + "Answer": "Ann Richards" + }, + { + "Category": "FEDERAL AID PROGRAMS", + "Question": "Perkins & Stafford Loans & Pell Grants are for these people", + "Answer": "college students" + }, + { + "Category": "\"A\" PLUS", + "Question": "In February 1999 several of these killed 38 people in the Austrian towns of Galtur & Valzur", + "Answer": "avalanches" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "Clym Yeobright comes back home & is killed by Bigger Thomas in this Thomas Hardy-Richard Wright work", + "Answer": "Return of the Native Son" + }, + { + "Category": "THE BLUE ANGELS", + "Question": "(Sarah of the Clue Crew on the tarmac) Bearing the name of a Greek letter, this classic Blue Angels formation uses all 6 jets", + "Answer": "Delta" + }, + { + "Category": "TONY-WINNING COMPOSERS", + "Question": "1950: \"South Pacific\"", + "Answer": "Richard Rodgers" + }, + { + "Category": "SPEECH! SPEECH!", + "Question": "On July 19, 1988 he was out proclaiming \"Keep hope alive\"", + "Answer": "Jesse Jackson" + }, + { + "Category": "FEDERAL AID PROGRAMS", + "Question": "The National School Lunch Program comes from this dept., also concerned with foot-and-mouth disease", + "Answer": "Agriculture" + }, + { + "Category": "\"A\" PLUS", + "Question": "From Greek words meaning \"to watch from both sides\", it's a large open arena for public entertainments", + "Answer": "amphitheatre" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "American ambulance driver Frederic Henry satirizes romantic ideas about war in this work by Hemingway & Shaw", + "Answer": "A Farewell to Arms and the Man" + }, + { + "Category": "THE BLUE ANGELS", + "Question": "(Sarah of the Clue Crew on the tarmac) Using only 5 planes, this formation pays tribute to fallen heroes & comrades", + "Answer": "Missing Man Formation" + }, + { + "Category": "TONY-WINNING COMPOSERS", + "Question": "1949: \"Kiss Me, Kate\"", + "Answer": "Cole Porter" + }, + { + "Category": "SPEECH! SPEECH!", + "Question": "In 1653 he told the Rump Parliament to get off its rump & \"In the name of God, go!\"", + "Answer": "Oliver Cromwell" + }, + { + "Category": "FEDERAL AID PROGRAMS", + "Question": "This cabinet department operates over 160 hospitals & has guaranteed over 16 million loans", + "Answer": "Veterans Affairs" + }, + { + "Category": "\"A\" PLUS", + "Question": "It's the color mentioned in the second line of \"America the Beautiful\"", + "Answer": "amber" + }, + { + "Category": "LITERARY BEFORE & AFTER", + "Question": "The horror! The horror! Marlow travels up the Congo to find Kurtz & Rubashov in a totalitarian prison state", + "Answer": "Heart of Darkness at Noon" + }, + { + "Category": "ALL GOD'S CREATURES", + "Question": "Edison proposed a flying machine based on the flight of this creature, also the subject of a musical work", + "Answer": "bumblebee" + }, + { + "Category": "\"B\" IN GEOGRAPHY", + "Question": "It's the Canadian province that borders Idaho", + "Answer": "British Columbia" + }, + { + "Category": "YOU'RE AN ANIMAL!", + "Question": "The dwarf variety of this cold-blooded killer is seen here", + "Answer": "Crocodile" + }, + { + "Category": "WORLD HISTORY", + "Question": "This Navy commander flew from a base at Little America to the South Pole & back Nov. 28-29, 1929", + "Answer": "Admiral Richard Byrd" + }, + { + "Category": "FAIRY TALE FEMMES", + "Question": "One of the few times she laughs in Wonderland is when she has to use a flamingo to play croquet", + "Answer": "Alice" + }, + { + "Category": "ANAGRAMMED STATE CAPITALS", + "Question": "Any lab", + "Answer": "Albany" + }, + { + "Category": "TOM JONES", + "Question": "Singer Tom Jones is the son of one of these workers; Loretta Lynn is famous for being the daughter of one", + "Answer": "Coal miner" + }, + { + "Category": "\"B\" IN GEOGRAPHY", + "Question": "One of the newer large cities in the world, it's located in the central plateau of Brazil", + "Answer": "Brasilia" + }, + { + "Category": "YOU'RE AN ANIMAL!", + "Question": "A river, a city & a hound all bear the name of this member of the deer family", + "Answer": "Elk" + }, + { + "Category": "WORLD HISTORY", + "Question": "Accused of accepting bribes, Francis Bacon was imprisoned in this forbidding complex in 1621", + "Answer": "Tower of London" + }, + { + "Category": "FAIRY TALE FEMMES", + "Question": "She ate the window pane of the witch's cottage", + "Answer": "Gretel" + }, + { + "Category": "ANAGRAMMED STATE CAPITALS", + "Question": "Males", + "Answer": "Salem" + }, + { + "Category": "TOM JONES", + "Question": "Tom hails from Pontypridd in this British Isles country", + "Answer": "Wales" + }, + { + "Category": "\"B\" IN GEOGRAPHY", + "Question": "Since 1969 this Northern Ireland port city of 300,000 has been the site of violent religious conflict", + "Answer": "Belfast" + }, + { + "Category": "YOU'RE AN ANIMAL!", + "Question": "The critter seen here (bulldog) is a symbol of this nation", + "Answer": "Great Britain" + }, + { + "Category": "WORLD HISTORY", + "Question": "More than 250,000 died in fighting before France granted this African nation independence July 3, 1962", + "Answer": "Algeria" + }, + { + "Category": "FAIRY TALE FEMMES", + "Question": "She would have been popular in the '60s; she was always letting her hair down", + "Answer": "Rapunzel" + }, + { + "Category": "ANAGRAMMED STATE CAPITALS", + "Question": "Proved nice", + "Answer": "Providence" + }, + { + "Category": "TOM JONES", + "Question": "Tom played -- who else? -- himself on the \"Marge Gets a Job\" episode of this animated TV series in 1992", + "Answer": "The Simpsons" + }, + { + "Category": "\"B\" IN GEOGRAPHY", + "Question": "This city located on the Rhine River became West Germany's capital in 1949", + "Answer": "Bonn" + }, + { + "Category": "YOU'RE AN ANIMAL!", + "Question": "These predatory birds are named for a place they might dwell", + "Answer": "Barn owls" + }, + { + "Category": "WORLD HISTORY", + "Question": "In 1784 she founded the city of Sevastopol in her new domain of the Crimea", + "Answer": "Catherine the Great" + }, + { + "Category": "FAIRY TALE FEMMES", + "Question": "The Brothers Grimm gave no name for the miller's daughter who guessed the name of this little man", + "Answer": "Rumpelstiltskin" + }, + { + "Category": "ANAGRAMMED STATE CAPITALS", + "Question": "Poke at", + "Answer": "Topeka" + }, + { + "Category": "TOM JONES", + "Question": "Tom played -- who else? -- in this 1996 Tim Burton film about invaders from outer space", + "Answer": "Mars Attacks!" + }, + { + "Category": "\"B\" IN GEOGRAPHY", + "Question": "It's the capital of Catalonia", + "Answer": "Barcelona" + }, + { + "Category": "YOU'RE AN ANIMAL!", + "Question": "It's the genus & species of this animal (\"caveman\")", + "Answer": "Homo sapiens" + }, + { + "Category": "WORLD HISTORY", + "Question": "This Portuguese \"Admiral of the Indian Seas\" discovered & named the Amirante Islands", + "Answer": "Vasco da Gama" + }, + { + "Category": "FAIRY TALE FEMMES", + "Question": "He wrote a little about women: \"The Little Match Girl\", \"The Little Mermaid\"...", + "Answer": "Hans Christian Andersen" + }, + { + "Category": "ANAGRAMMED STATE CAPITALS", + "Question": "Leg hair", + "Answer": "Raleigh" + }, + { + "Category": "TOM JONES", + "Question": "It's not odd that this 1965 song is heard in the 1998 film \"Little Voice\"", + "Answer": "\"It's Not Unusual\"" + }, + { + "Category": "PARISIANS", + "Question": "When Lenin moved to Paris in 1908, he naturally settled on this bank of the Seine", + "Answer": "Left Bank" + }, + { + "Category": "FRUIT", + "Question": "The Bing & other sweet varieties of this fruit are self-sterile; they cannot pollinate themselves", + "Answer": "Cherries" + }, + { + "Category": "SHAKESPEAREAN OPERAS", + "Question": "\"Amleto\"", + "Answer": "Hamlet" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "The French for \"scandal\" gave us the name of this high-kicking dance popular in music halls of the 19th century", + "Answer": "Can-Can" + }, + { + "Category": "FILM FACTS", + "Question": "This TV star played a senator who had his \"Hawkeye\" on Meryl Streep in \"The Seduction of Joe Tynan\"", + "Answer": "Alan Alda" + }, + { + "Category": "TOM JONES", + "Question": "In book 13 country boy Tom arrives in this metropolis, where the climactic action takes place", + "Answer": "London" + }, + { + "Category": "PARISIANS", + "Question": "For speaking too \"Candide\"ly, he did time in the Bastille, but later lived in a mansion on Ile St-Louis", + "Answer": "Voltaire" + }, + { + "Category": "FRUIT", + "Question": "The Bartlett type of this fruit begins to ripen in summer; other varieties ripen later in the year", + "Answer": "Pears" + }, + { + "Category": "SHAKESPEAREAN OPERAS", + "Question": "\"Il Mercante Di Venezia\"", + "Answer": "The Merchant of Venice" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "This phrase for taking a break from a long period of sitting goes back to 19th century baseball", + "Answer": "Seventh-inning stretch" + }, + { + "Category": "FILM FACTS", + "Question": "This Beatle not only strarred in \"Give My Regards to Broad Street\", he wrote the screenplay & the score", + "Answer": "Paul McCartney" + }, + { + "Category": "TOM JONES", + "Question": "This author of the novel based the heroine, Sophia, on his beloved late wife", + "Answer": "Henry Fielding" + }, + { + "Category": "PARISIANS", + "Question": "The voice of this woman, born in Paris in 1915, evokes the city in songs like \"Non, Je Ne Regrette Rien\"", + "Answer": "Edith Piaf" + }, + { + "Category": "FRUIT", + "Question": "This fruit often originates from peach seeds & peaches sometimes come from its seeds", + "Answer": "Nectarines" + }, + { + "Category": "SHAKESPEAREAN OPERAS", + "Question": "\"Cordelia\"", + "Answer": "KIng Lear" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "An illustrated \"girl\" & a variation on the martini are named for this U.S. artist", + "Answer": "Charles Dana Gibson" + }, + { + "Category": "FILM FACTS", + "Question": "\"Titanic\" tied this 1959 film's record of 11 Oscars but didn't overtake it", + "Answer": "Ben-Hur" + }, + { + "Category": "TOM JONES", + "Question": "Tom finally learns the true identity of this person; he thought it was Jenny the maid", + "Answer": "His mother" + }, + { + "Category": "PARISIANS", + "Question": "In the 1880s he introduced his brother & roommate, Vincent, to the Impressionists", + "Answer": "Theo Van Gogh" + }, + { + "Category": "FRUIT", + "Question": "A cluster, or hand, of this fruit consists of 10-20 fingers", + "Answer": "Bananas" + }, + { + "Category": "SHAKESPEAREAN OPERAS", + "Question": "\"Der Sturm\"", + "Answer": "The Tempest" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "From the Italian for \"chatter\", it's a person who claims knowledge or skill he doesn't have", + "Answer": "Charlatan" + }, + { + "Category": "FILM FACTS", + "Question": "Roy Rogers sang \"Buttons and Bows\" with Bob Hope & Jane Russell in this sequel to \"The Paleface\"", + "Answer": "Son of Paleface" + }, + { + "Category": "TOM JONES", + "Question": "The benevolent Mr. Allworthy & the crude Mr. Western have this title given to English country gentlemen", + "Answer": "Squire" + }, + { + "Category": "PARISIANS", + "Question": "This saint taught at the University of Paris while working on \"Summa Theologica\" in the 13th century", + "Answer": "St. Thomas Aquinas" + }, + { + "Category": "FRUIT", + "Question": "This hybrid of a tangerine & a grapefruit comes in 2 main varieties: Orlando & Minneola", + "Answer": "Tangelo" + }, + { + "Category": "SHAKESPEAREAN OPERAS", + "Question": "\"Beaucoup de Bruit Pour Rien\"", + "Answer": "Much Ado About Nothing" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "2 Greek words for \"long life\" give us this word which refers to a diet or lifestyle said to prolong life", + "Answer": "Macrobiotic" + }, + { + "Category": "FILM FACTS", + "Question": "As a child, this \"Doctor Zhivago\" co-star had a bit role in her father's film \"Limelight\"", + "Answer": "Geraldine Chaplin" + }, + { + "Category": "TOM JONES", + "Question": "This \"Kubla Khan\" poet thought \"Tom Jones\" had 1 of the 3 best plots in all literature", + "Answer": "Samuel Taylor Coleridge" + }, + { + "Category": "1950s ACHIEVEMENTS", + "Question": "On Nov. 20, 1953, in a Douglas D-558-2, Scott Crossfield reached this benchmark", + "Answer": "Traveling twice the speed of sound" + }, + { + "Category": "U.N. SECRETARIES-GENERAL", + "Question": "This current Secretary-General is the first U.N. career official to hold the post", + "Answer": "Kofi Annan" + }, + { + "Category": "SONGS", + "Question": "It's what \"everybody in the whole cell block was dancin' to\"", + "Answer": "\"Jailhouse Rock\"" + }, + { + "Category": "THE NEW CAR LOT", + "Question": "This company's '99 Quest minivan & Mercury's '99 Villager -- same thing", + "Answer": "Nissan" + }, + { + "Category": "\"TU\"", + "Question": "The University of Phoenix has a branch in this city", + "Answer": "Tucson" + }, + { + "Category": "MANY IRONS", + "Question": "This mythical barrier cut off the Soviet Union & its friends after World War II", + "Answer": "Iron Curtain" + }, + { + "Category": "IN THE FIRE", + "Question": "Many 17th century New York City households had one of these to form a brigade in case of fire", + "Answer": "Bucket" + }, + { + "Category": "U.N. SECRETARIES-GENERAL", + "Question": "At the time only a secretary-general to-be, this Egyptian played a major role in the 1979 Arab-Israeli peace accord", + "Answer": "Boutros Boutros-Ghali" + }, + { + "Category": "SONGS", + "Question": "Willie Nelson must be \"wond'rin' what in the world did I do\" by writing this Patsy Cline hit", + "Answer": "\"Crazy\"" + }, + { + "Category": "THE NEW CAR LOT", + "Question": "Cadillac doesn't want to rub you the wrong way with its new optional front seats that do this to you", + "Answer": "Massage" + }, + { + "Category": "\"TU\"", + "Question": "Henry VII was the first ruler from this family on the throne of England", + "Answer": "Tudor" + }, + { + "Category": "MANY IRONS", + "Question": "The male lead in \"The French Lieutenant's Woman\"; Meryl Streep played the title character", + "Answer": "Jeremy Irons" + }, + { + "Category": "IN THE FIRE", + "Question": "Since 1932 this brand has provided reliable flames for soldiers, campers & others", + "Answer": "Zippo" + }, + { + "Category": "U.N. SECRETARIES-GENERAL", + "Question": "In the 1960s this Burmese secretary-general sought to apply Buddhist principles to international problem solving", + "Answer": "U Thant" + }, + { + "Category": "SONGS", + "Question": "\"It's a marvelous night for\" this Van Morrison hit, \"with the stars up above in your eyes\"", + "Answer": "\"Moondance\"" + }, + { + "Category": "THE NEW CAR LOT", + "Question": "This Chrysler brand has flown the coop with the end of production of its Talon", + "Answer": "Eagle" + }, + { + "Category": "\"TU\"", + "Question": "Creature seen here in a non-candid photo", + "Answer": "Tuna" + }, + { + "Category": "MANY IRONS", + "Question": "It's gold! Gold, I tell you! Gold!!! Oh, no -- it's not... it's this, fool's gold", + "Answer": "Iron pyrite" + }, + { + "Category": "IN THE FIRE", + "Question": "Oliver Wendell Holmes said not to falsely yell \"Fire\" in one of these, where 850 Viennese died Dec. 8, 1881", + "Answer": "Theater" + }, + { + "Category": "U.N. SECRETARIES-GENERAL", + "Question": "Trying to resolve problems in the Congo, this Swedish secretary-general died in a plane crash in Africa in 1961", + "Answer": "Dag Hammarskjold" + }, + { + "Category": "SONGS", + "Question": "Having this title problem, Barry Manilow sings, \"I can't laugh and I can't sing, I'm finding it hard to do anything\"", + "Answer": "\"Can't Smile Without You\"" + }, + { + "Category": "THE NEW CAR LOT", + "Question": "The '99 Saab 9-5 offers a real cool option: this is \"refrigerated\"", + "Answer": "Glove compartment" + }, + { + "Category": "\"TU\"", + "Question": "From the Latin for \"uproar\", it's a confusion of voices", + "Answer": "Tumult" + }, + { + "Category": "MANY IRONS", + "Question": "Bruce Dickinson was the lead singer of this British heavy metal band", + "Answer": "Iron Maiden" + }, + { + "Category": "IN THE FIRE", + "Question": "Peshtigo, Wisc. was destroyed by a fire that began Oct. 8, 1871, the same day as this city's Great Fire", + "Answer": "Chicago" + }, + { + "Category": "U.N. SECRETARIES-GENERAL", + "Question": "This Oslo-born secretary-general served in the Norwegian government in exile during WWII", + "Answer": "Trygve Lie" + }, + { + "Category": "SONGS", + "Question": "A standard song says of this \"fickle friend\", it \"came blowin' in from across the sea\"", + "Answer": "\"The Summer Wind\"" + }, + { + "Category": "THE NEW CAR LOT", + "Question": "Your pocketbook may not \"Bond\" with the $130,000 base price of its DB7 Coupe", + "Answer": "Aston Martin" + }, + { + "Category": "\"TU\"", + "Question": "The ruins of Carthage are in this country", + "Answer": "Tunisia" + }, + { + "Category": "MANY IRONS", + "Question": "This Prusso-German statesman was the \"Iron Chancellor\"", + "Answer": "Otto von Bismarck" + }, + { + "Category": "IN THE FIRE", + "Question": "2-word phrase for what sometimes happens to oily rags & often happens to the drummers of Spinal Tap", + "Answer": "Spontaneous combustion" + }, + { + "Category": "AWARDS", + "Question": "You might have to take a bullet to earn one of these", + "Answer": "Purple Heart" + }, + { + "Category": "THE MOVIES", + "Question": "Mike Myers travels from '60s London to Vegas in the '90s as this \"International Man of Mystery\"", + "Answer": "Austin Powers" + }, + { + "Category": "RELIGION BY THE NUMBERS", + "Question": "This legendary dozen included 2 Jameses, 2 Judases & an eventual replacement named Matthias", + "Answer": "Twelve Apostles/disciples" + }, + { + "Category": "NAME THE POET", + "Question": "\"Listen, my children, and you shall hear of the midnight ride of Paul Revere\"", + "Answer": "Henry Wadsworth Longfellow" + }, + { + "Category": "AWARDS", + "Question": "Richard Pryor was the first recipient of a Kennedy Center humorists' prize named for this American author", + "Answer": "Mark Twain" + }, + { + "Category": "THE MOVIES", + "Question": "John Lithgow played a transsexual former football player in this 1982 movie based on a John Irving novel", + "Answer": "The World According to Garp" + }, + { + "Category": "THEIR COUNTRY'S LAST MONARCH", + "Question": "In 1893 the queen seen here (Liliuokalani) became the last monarch of this country", + "Answer": "Hawaii" + }, + { + "Category": "RELIGION BY THE NUMBERS", + "Question": "The sixth of these was an outbreak of boils & sores", + "Answer": "Ten Plagues of Egypt" + }, + { + "Category": "NAME THE POET", + "Question": "\"Whan that Aprill with his shoures soote the droghte of March hath perced to the roote\"", + "Answer": "Geoffrey Chaucer" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "This word can refer to laziness, a 2-toed mammal, or a group of bears", + "Answer": "Sloth" + }, + { + "Category": "AWARDS", + "Question": "In \"Good Will Hunting\", Stellan Skarsgard had a Fields Medal, called \"The Nobel Prize of\" this discipline", + "Answer": "Mathematics" + }, + { + "Category": "THE MOVIES", + "Question": "John Larroquette played Captain Stillman in this wacky 1981 comedy about misfits in the Army", + "Answer": "Stripes" + }, + { + "Category": "THEIR COUNTRY'S LAST MONARCH", + "Question": "1952: Infant king Fu'ad II", + "Answer": "Egypt" + }, + { + "Category": "RELIGION BY THE NUMBERS", + "Question": "It's the Greek term meaning \"5 tools\" that represents the 1st 5 books of the Bible", + "Answer": "Pentateuch" + }, + { + "Category": "NAME THE POET", + "Question": "\"His pride had cast him out from heaven, with all his host of rebel angels\"", + "Answer": "John Milton" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "This term for a group of elk also applies to sharks (the ones in \"West Side Story\")", + "Answer": "Gang" + }, + { + "Category": "AWARDS", + "Question": "\"Pearls for Pigs\" was 1998's best play in these off-Broadway awards given by the Village Voice", + "Answer": "Obies" + }, + { + "Category": "THE MOVIES", + "Question": "Julia Ormond was the chauffeur's daughter in love with a rich playboy in this 1995 update of a 1954 classic", + "Answer": "Sabrina" + }, + { + "Category": "THEIR COUNTRY'S LAST MONARCH", + "Question": "1910: King Manuel II", + "Answer": "Portugal" + }, + { + "Category": "RELIGION BY THE NUMBERS", + "Question": "For Muslims: witnessing, prayer, alms giving, fasting & pilgrimage", + "Answer": "Five Pillars of Faith" + }, + { + "Category": "NAME THE POET", + "Question": "\"Tho' I've belted you an' flayed you, by the livin' gawd that made you, you're a better man than I am, Gunga Din\"", + "Answer": "Rudyard Kipling" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "It's a feather filling for quilts, as well as a group of hares", + "Answer": "Down" + }, + { + "Category": "AWARDS", + "Question": "Theodore Hesburgh, once president of this university, has been awarded over 100 honorary degrees", + "Answer": "Notre Dame" + }, + { + "Category": "THE MOVIES", + "Question": "In 1985 Helena Bonham Carter portrayed this historic \"Lady\" on film", + "Answer": "Lady Jane Grey" + }, + { + "Category": "THEIR COUNTRY'S LAST MONARCH", + "Question": "1947: Eastern Europe's King Michael", + "Answer": "Romania" + }, + { + "Category": "RELIGION BY THE NUMBERS", + "Question": "Right effort, right speech & right action are 3 parts of this noble Buddhist way", + "Answer": "Eightfold Path" + }, + { + "Category": "NAME THE POET", + "Question": "\"To see a world in a grain of sand and a heaven in a wild flower\"", + "Answer": "William Blake" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "Wisconsin folks know a cete is a group of these carnivores", + "Answer": "Badgers" + }, + { + "Category": "IN THE BOOKSTORE", + "Question": "Bestselling author seen here (she's holding a large \"A\" & a large \"Z\")", + "Answer": "Sue Grafton" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "It's the lowest, flattest & smallest continent", + "Answer": "Australia" + }, + { + "Category": "WOMEN'S FASHION", + "Question": "This part of Princess Diana's wedding ensemble was 25 feet long", + "Answer": "Train" + }, + { + "Category": "STARTS WITH \"B\"", + "Question": "A little mistake, or Yogi Bear's little buddy", + "Answer": "Boo Boo" + }, + { + "Category": "CELEBRITY RELATIVES", + "Question": "\"Tucker\" marked the 1st time this father & son had worked together since \"Sea Hunt\" in the '60s", + "Answer": "Lloyd & Jeff Bridges" + }, + { + "Category": "SPORTS TRIVIA", + "Question": "In case you want to book your flights now, this will be played in Tampa in 1991 & Minneapolis in 1992", + "Answer": "The Super Bowl" + }, + { + "Category": "SAY CHEESE", + "Question": "Italian cheesecake is made with this cheese whose name means \"recooked\"", + "Answer": "Ricotta" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "Abingdon, Windsor, Gravesend & Southend-On-Sea are on this European river", + "Answer": "Thames" + }, + { + "Category": "WOMEN'S FASHION", + "Question": "The \"Cuban\" style of these shoe features came into style in the early 1900s", + "Answer": "Heels" + }, + { + "Category": "STARTS WITH \"B\"", + "Question": "An insect who hangs out in your four-poster, or what a private eye might slip under your mattress", + "Answer": "Bedbug" + }, + { + "Category": "CELEBRITY RELATIVES", + "Question": "These brothers both became TV stars: one ran Dodge City & the other led the Impossible Missions Force", + "Answer": "James Arness & Peter Graves" + }, + { + "Category": "SPORTS TRIVIA", + "Question": "In 1989 Emerson Fittipaldi knocked Al Unser Jr. out of this race on lap 199 & won", + "Answer": "The Indianapolis 500" + }, + { + "Category": "SAY CHEESE", + "Question": "The 2 cheeses coated with red wax named for towns, one in North Holland province, one in South", + "Answer": "Edam & Gouda" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "City that stands on the ruins of Tenochtitlan, the capital of the Aztec people", + "Answer": "Mexico City" + }, + { + "Category": "WOMEN'S FASHION", + "Question": "The patches European women wore on their faces in the 1600s were usually this color", + "Answer": "Black" + }, + { + "Category": "STARTS WITH \"B\"", + "Question": "A Russian grandmother, or her kerchief", + "Answer": "Babushka" + }, + { + "Category": "CELEBRITY RELATIVES", + "Question": "David Canary, who's seen on \"All My Children\", claims to be a descendant of this famous frontierswoman", + "Answer": "Calamity Jane" + }, + { + "Category": "SPORTS TRIVIA", + "Question": "The French Open tennis tournament is played on courts of this color clay", + "Answer": "Red" + }, + { + "Category": "SAY CHEESE", + "Question": "This cheese that has an orange rind originated in Alsace & is named for a city there", + "Answer": "Muenster" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "The highest airport in the world is Lhasa Airport in this country", + "Answer": "TIbet" + }, + { + "Category": "WOMEN'S FASHION", + "Question": "Popular in the 18th century, Watteau gowns were inspired by Jean Antoine Watteau, who was one of these", + "Answer": "Painter" + }, + { + "Category": "STARTS WITH \"B\"", + "Question": "This oily dressing makes your hair glossy, but it sounds like it makes you smart", + "Answer": "Brilliantine" + }, + { + "Category": "CELEBRITY RELATIVES", + "Question": "His uncle Francis Coppola directed him when he played the man to whom \"Peggy Sue Got Married\"", + "Answer": "Nicolas Cage" + }, + { + "Category": "SPORTS TRIVIA", + "Question": "The Orangemen of Syracuse were NCAA champs in '88 & '89 in this Native American sport", + "Answer": "Lacrosse" + }, + { + "Category": "SAY CHEESE", + "Question": "This name refers to natural cheddar made in the U.S. & is often confused with processed cheese", + "Answer": "American cheese" + }, + { + "Category": "WORLD GEOGRAPHY", + "Question": "The hot water heating of this northern European capital is drawn directly from underground springs", + "Answer": "Reykjavik, Iceland" + }, + { + "Category": "WOMEN'S FASHION", + "Question": "This turn-of-the-century \"girl\" wore a shortwaist dress with puffed sleeves & a Pompadour hairdo", + "Answer": "Gibson Girl" + }, + { + "Category": "STARTS WITH \"B\"", + "Question": "2-word French term for a small bundle of herbs, often tied together & used for flavoring", + "Answer": "Bouquet Garni" + }, + { + "Category": "CELEBRITY RELATIVES", + "Question": "Pam Dawber's famous father-in-law", + "Answer": "Tom Harmon" + }, + { + "Category": "SPORTS TRIVIA", + "Question": "In 1989 this Canadian team won its 1st Stanley Cup", + "Answer": "Calgary Flames" + }, + { + "Category": "SAY CHEESE", + "Question": "According to legend, it was created when a shepherd left a piece of cheese in a cave for several weeks", + "Answer": "Roquefort" + }, + { + "Category": "EXPLORERS", + "Question": "Born Giovanni Caboto, this Venetian did his exploring in the service of England", + "Answer": "John Cabot" + }, + { + "Category": "THE HUMAN BODY", + "Question": "When this organ churns & makes perisstaltic waves, some people say it's \"growling\"", + "Answer": "Stomach" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "This clergyman who wrote \"The Short History of New-England\" in 1694 was the son of Increase Mather", + "Answer": "Cotton Mather" + }, + { + "Category": "COMPOSERS", + "Question": "His sister Fanny Mendelssohn wrote some of the songs attributed to him", + "Answer": "Felix Mendelssohn" + }, + { + "Category": "THE PLANETS", + "Question": "As viewed from Earth, it's the brightest planet in the nighttime sky", + "Answer": "Venus" + }, + { + "Category": "ANTIQUES", + "Question": "Used as early as the 15th century, apostle spoons usually came in sets of this number", + "Answer": "12 or 13" + }, + { + "Category": "EXPLORERS", + "Question": "N.Y. observes a holiday honoring the 1524 discovery of N.Y. Harbor by this Italian navigator", + "Answer": "Giovanni Verrazano" + }, + { + "Category": "THE HUMAN BODY", + "Question": "The oval window is a membrane forming one of the boundaries between the middle & the inner parts of this", + "Answer": "Ear" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "He wrote \"Cadillac Jack\" & \"Lonesome Dove\" after \"Terms of Endearment\"", + "Answer": "Larry McMurtry" + }, + { + "Category": "COMPOSERS", + "Question": "Of the 3 Bs, the 2 who died in Vienna", + "Answer": "Beethoven & Brahms" + }, + { + "Category": "THE PLANETS", + "Question": "In August 1989 it became the last planet encountered by Voyager 2", + "Answer": "Neptune" + }, + { + "Category": "ANTIQUES", + "Question": "Fireplace tool that consists of matching shaped boards, a metal nozzle & flexible leather sides", + "Answer": "Bellows" + }, + { + "Category": "EXPLORERS", + "Question": "Ponce de Leon was looking for it when he discovered Florida; some are still looking for it today", + "Answer": "Fountain of Youth" + }, + { + "Category": "THE HUMAN BODY", + "Question": "They're also known as your zygomatic bones, & high ones are considered especially attractive", + "Answer": "Cheekbones" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "He lived for several weeks among the cannibalistic Typee before he wrote the book of the same name", + "Answer": "Herman Melville" + }, + { + "Category": "COMPOSERS", + "Question": "It was rumored that he committed suicide over the failure of his last symphony, the \"Pathetique\"", + "Answer": "Pyotr Ilyich Tchaikovsky" + }, + { + "Category": "THE PLANETS", + "Question": "The 4 largest moons of this planet are called Galilean satellites after Galileo, who saw them in 1610", + "Answer": "Jupiter" + }, + { + "Category": "ANTIQUES", + "Question": "A method of joining 2 pieces of wood at right angles named for its resemblance to a bird's tail", + "Answer": "Dovetail" + }, + { + "Category": "EXPLORERS", + "Question": "His 1497-98 voyage to India opened the 1st all-water trade route between Europe & Asia", + "Answer": "Vasco da Gama" + }, + { + "Category": "THE HUMAN BODY", + "Question": "It's the tube that connects your nose & mouth with your larynx & esophagus", + "Answer": "Pharynx" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "Jack Kerouac's 1957 novel about the adventures of Dean Moriarty & friends as they travel the U.S.", + "Answer": "\"On The Road\"" + }, + { + "Category": "COMPOSERS", + "Question": "G. Strepponi sang in \"Nabucco\", the opera that made this composer famous, & later married him", + "Answer": "Giuseppe Verdi" + }, + { + "Category": "THE PLANETS", + "Question": "In 1971 Mariner 9 discovered a volcano on this planet rising 15 1/2 miles above the surface", + "Answer": "Mars" + }, + { + "Category": "ANTIQUES", + "Question": "French for \"Chinese Ornament\", it refers to willow pattern china & some Chippendale furniture", + "Answer": "Chinoisserie" + }, + { + "Category": "EXPLORERS", + "Question": "Tho he didn't find the Northwest Passage, this Frenchman established France's claim to Canada", + "Answer": "Jacques Cartier" + }, + { + "Category": "THE HUMAN BODY", + "Question": "The ovaries are part of both the reproductive system & this system which produces hormones", + "Answer": "Endocrine System" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "It was called \"A Poem Of Walt Whitman, An American\" before it was called this", + "Answer": "\"Song of Myself\"" + }, + { + "Category": "COMPOSERS", + "Question": "Mussorgsky once lived with this \"Scheherazade\" composer who re-edited \"Boris Godunov\" after his death", + "Answer": "Nikolai Rimsky-Korsakov" + }, + { + "Category": "THE PLANETS", + "Question": "This remote planet orbits the sun at a 98 degree axis, almost lying on its side", + "Answer": "Uranus" + }, + { + "Category": "ANTIQUES", + "Question": "(VIDEO DAILY DOUBLE): The kind of clock shown here, invented c. 1800 & named for the musical instrument it resembles:", + "Answer": "Banjo Clock" + }, + { + "Category": "SHAKESPEAREAN TITLE CHARACTERS", + "Question": "He is introduced as \"The triple pillar of the world transformed into a strumpet's fool\"", + "Answer": "Marc Antony" + }, + { + "Category": "THE REVOLUTIONARY WAR", + "Question": "After this early battle, Americans retreated over Charlestown Neck", + "Answer": "The Battle of Bunker Hill" + }, + { + "Category": "GAME SHOWS", + "Question": "The first letter ever turned by Vanna White on this game show was a \"T\"", + "Answer": "Wheel of Fortune" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "This \"colorful\" & controversial activist environmental group was formed in Canada in 1971", + "Answer": "Greenpeace" + }, + { + "Category": "THE 50 STATES", + "Question": "The diatonic or \"Cajun\" accordion is the official musical instrument of this state", + "Answer": "Louisiana" + }, + { + "Category": "PHRASES THAT SELL", + "Question": "\"Obey your thirst\" and drink this", + "Answer": "Sprite" + }, + { + "Category": "THE \"UNDER\" WORLD", + "Question": "Lingerie is a fancy word for it", + "Answer": "underwear" + }, + { + "Category": "THE REVOLUTIONARY WAR", + "Question": "On the evening of April 18, 1775 Robert Newman displayed 2 lanterns in this Boston structure", + "Answer": "the Old North Church" + }, + { + "Category": "GAME SHOWS", + "Question": "You might phone a friend on this game show hosted by Meredith Vieira", + "Answer": "Who Wants to Be a Millionaire" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "In 1970 President Nixon created this government body that sets and enforces national pollution control standards", + "Answer": "the E.P.A." + }, + { + "Category": "THE 50 STATES", + "Question": "This state's famous Derby at Churchill Downs is held annually on the first Saturday of May", + "Answer": "Kentucky" + }, + { + "Category": "PHRASES THAT SELL", + "Question": "\"Be all that you can be\" in this military branch", + "Answer": "the Army" + }, + { + "Category": "THE \"UNDER\" WORLD", + "Question": "Abolitionist \"railroad\"", + "Answer": "underground" + }, + { + "Category": "THE REVOLUTIONARY WAR", + "Question": "In 1774 the owner of the Peggy Stewart was forced to burn his ship & its 2,000-pound cargo of this taxed item", + "Answer": "tea" + }, + { + "Category": "GAME SHOWS", + "Question": "In this \"Street\"-wise game show, you have to predict answers given by people on the street", + "Answer": "Street Smarts" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "This triatomic allotrope of oxygen protects us from the full force of harmful ultraviolet rays", + "Answer": "ozone" + }, + { + "Category": "THE 50 STATES", + "Question": "New Englanders refer to this state as \"Down East\"", + "Answer": "Maine" + }, + { + "Category": "PHRASES THAT SELL", + "Question": "This network says it's \"The most trusted name in news\"", + "Answer": "CNN" + }, + { + "Category": "THE \"UNDER\" WORLD", + "Question": "Vegetation growing beneath the trees in a forest", + "Answer": "underbrush" + }, + { + "Category": "THE REVOLUTIONARY WAR", + "Question": "On September 23, 1779 he & his men successfully attacked a British convoy off Flamborough Head in the North Sea", + "Answer": "John Paul Jones" + }, + { + "Category": "GAME SHOWS", + "Question": "9 celebrities in a tic-tac-toe-like grid help contestants score 3 in a row on this show", + "Answer": "Hollywood Squares" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "An animal fills an ecological one of these in a community, from the French for \"nest\"", + "Answer": "niche" + }, + { + "Category": "THE 50 STATES", + "Question": "The name of this state comes from 2 Choctaw words that mean \"red\" & \"people\"", + "Answer": "Oklahoma" + }, + { + "Category": "PHRASES THAT SELL", + "Question": "This shipping company asks, \"What can Brown do for you?\"", + "Answer": "UPS" + }, + { + "Category": "THE \"UNDER\" WORLD", + "Question": "The seaward pull away from shore after a wave has broken", + "Answer": "undertow" + }, + { + "Category": "THE REVOLUTIONARY WAR", + "Question": "After the defeat at Yorktown, Gen. Charles O'Hara, acting for this man, gave his sword to the Americans", + "Answer": "Cornwallis" + }, + { + "Category": "GAME SHOWS", + "Question": "Richard Karn hosts this game show where 2 clans match wits; survey says...", + "Answer": "Family Feud" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "In June 1992 over 100 heads of state met in Rio de Janeiro for this environmental \"Summit\"", + "Answer": "the Earth Summit" + }, + { + "Category": "THE 50 STATES", + "Question": "National Battlefield Parks include Manassas in Virginia & Kennesaw Mountain in this state", + "Answer": "Georgia" + }, + { + "Category": "PHRASES THAT SELL", + "Question": "It's the popular query in Verizon's TV ads", + "Answer": "Can you hear me now?" + }, + { + "Category": "THE \"UNDER\" WORLD", + "Question": "It means to weaken support for something or to unearth too little ore", + "Answer": "undermine" + }, + { + "Category": "THE EVOLUTIONARY WAR", + "Question": "In 1995 Alabama Gov. James Mocked evolution theory by imitating this type of animal whose name means \"to imitate\"", + "Answer": "an ape" + }, + { + "Category": "WHEN THEY WERE TEENS", + "Question": "This TV \"Friend\" was a cheerleader at Mountain Brook High School in Alabama", + "Answer": "Courteney Cox" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "It was the pen name of beloved children's author Theodor Geisel", + "Answer": "Dr. Seuss" + }, + { + "Category": "GREEK MYTHOLOGY", + "Question": "The Judgement of Paris refers to the picking of a winner in one of these contests", + "Answer": "a beauty contest" + }, + { + "Category": "YOU HAD TO EXPECT OPERA", + "Question": "We're not stringing you along: \"El Retablo de Maese Pedro\" is meant to be peformed by these toys", + "Answer": "puppets" + }, + { + "Category": "LONG WORDS", + "Question": "In 1923 Lts. Macready & Kelly made the first nonstop flight of this 16-letter type, Long Island to San Diego", + "Answer": "transcontinental" + }, + { + "Category": "WHEN THEY WERE TEENS", + "Question": "This daughter of Francis Ford Coppola was an intern for fashion designer Karl Lagerfeld in Paris", + "Answer": "Sofia Coppola" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "In 1844 he succeeded Joseph Smith as leader of the Mormon Church", + "Answer": "Brigham Young" + }, + { + "Category": "GREEK MYTHOLOGY", + "Question": "Ioalus, the son of Iphicles & Automedusa, helped this man, his uncle, with his labors", + "Answer": "Hercules" + }, + { + "Category": "YOU HAD TO EXPECT OPERA", + "Question": "At the beginning of an 1893 opera, these little tykes are sent into the woods to pick strawberries", + "Answer": "Hansel & Gretel" + }, + { + "Category": "THE EVOLUTIONARY WAR", + "Question": "He surprised many in 1996 when he told the Pontifical Academy of Science that evolution was no mere hypothesis", + "Answer": "Pope John Paul II" + }, + { + "Category": "WHEN THEY WERE TEENS", + "Question": "In 1991 Heather Tom was a teen when she debuted as Victor Newman's daughter on this CBS soap opera", + "Answer": "The Young & the Restless" + }, + { + "Category": "GREEK MYTHOLOGY", + "Question": "Like father like son--Cronus deposed his father Uranus & this god deposed his father Cronus", + "Answer": "Zeus" + }, + { + "Category": "YOU HAD TO EXPECT OPERA", + "Question": "King Solomon is a character in \"La Reine de Saba\", an opera about the queen of this place", + "Answer": "Sheba" + }, + { + "Category": "LONG WORDS", + "Question": "Adjective for an act done without meaning to; legally, it's a type of manslaughter", + "Answer": "involuntary" + }, + { + "Category": "THE EVOLUTIONARY WAR", + "Question": "Orderly people are bothered by the idea of thse random changes in genetic material helping evolution along", + "Answer": "mutations" + }, + { + "Category": "WHEN THEY WERE TEENS", + "Question": "This \"boulder\" sized wrestler & movie star was a star football player at Freedom High School in Bethlehem, Pa.", + "Answer": "The Rock" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "At the 1855 World's Fair in Paris, one of his sewing machines won first prize", + "Answer": "Singer" + }, + { + "Category": "GREEK MYTHOLOGY", + "Question": "Athena gave Perseus one of these to use as a mirror against Medusa &, reflecting back, it was a good thing", + "Answer": "a shield" + }, + { + "Category": "YOU HAD TO EXPECT OPERA", + "Question": "Flosshilde is a Rhinemaiden in this composer's \"Das Rheingold\"", + "Answer": "Richard Wagner" + }, + { + "Category": "LONG WORDS", + "Question": "This adjective from the Latin for \"to boil\" is used of a bubbly liquid or person", + "Answer": "effervescent" + }, + { + "Category": "THE EVOLUTIONARY WAR", + "Question": "A 1981 Arkansas law called for balanced teaching of evolution & this opposite type of \"science\"", + "Answer": "creationism" + }, + { + "Category": "WHEN THEY WERE TEENS", + "Question": "He was known as Chan Kong Sang in his native Hong Kong where he was a teenage stuntman & fight choreographer", + "Answer": "Jackie Chan" + }, + { + "Category": "GREEK MYTHOLOGY", + "Question": "With a name from the Greek for \"form\", he appeared to people in their dreams", + "Answer": "Morpheus" + }, + { + "Category": "LONG WORDS", + "Question": "Among bodily noises, hiccup & burp are this type of word that imitates sound", + "Answer": "an onomatopoeia" + }, + { + "Category": "THE WORLD OF ART", + "Question": "It's the room where you'll find the masterpiece that includes \"The Flood\" & \"The Creation of Eve\"", + "Answer": "the Sistine Chapel" + }, + { + "Category": "ART & ARTISTS", + "Question": "In 1956 Time magazine dubbed this abstract expressionist \"Jack the Dripper\"", + "Answer": "Pollock" + }, + { + "Category": "TRAVEL", + "Question": "This Rome landmark is 620 feet long by 513 wide-- plenty of room to run away from a wild beast", + "Answer": "the Colosseum" + }, + { + "Category": "CELEBRITIES' MIDDLE NAMES", + "Question": "The L. in Samuel L. Jackson stands for this, like a certain bad, bad Mr. Brown of song", + "Answer": "Leroy" + }, + { + "Category": "CATHOLIC PRIESTS", + "Question": "Served by priests, it may not exceed 18% alcohol", + "Answer": "communion wine" + }, + { + "Category": "TITLE 9", + "Question": "Daniel Okrent: \"Nine ___: The Anatomy of a Baseball Game\"", + "Answer": "Innings" + }, + { + "Category": "COME \"IN\"", + "Question": "A new design or creation; necessity is often the mother of it", + "Answer": "invention" + }, + { + "Category": "ART & ARTISTS", + "Question": "This Dutch master served as chairman of the Delft Artists' Guild from 1662-63 & 1670-71", + "Answer": "Jan Vermeer" + }, + { + "Category": "TRAVEL", + "Question": "Gamblers will love to know that the Hotel Yak & Yeti in this Nepalese capital houses the 2-story Casino Royale", + "Answer": "Kathmandu" + }, + { + "Category": "CELEBRITIES' MIDDLE NAMES", + "Question": "Feel free to sing out this middle name of Martin Scorsese; it's the same as Pavarotti's first", + "Answer": "Luciano" + }, + { + "Category": "CATHOLIC PRIESTS", + "Question": "Title of any priest's immediate boss; the U.S. has 270 of them", + "Answer": "bishop" + }, + { + "Category": "TITLE 9", + "Question": "John Buchan, filmed by Hitchcock: \"The Thirty-Nine ___\"", + "Answer": "Steps" + }, + { + "Category": "COME \"IN\"", + "Question": "Be it a stick or cone, strawberry & sandalwood are popular fragrances of this", + "Answer": "incense" + }, + { + "Category": "ART & ARTISTS", + "Question": "Aquarelle is a transparent, rather than opaque, type of this painting, as seen in Paul Klee's work \"Quarry\"", + "Answer": "watercolor" + }, + { + "Category": "TRAVEL", + "Question": "This island's Mataveri Intl. Airport, the world's most remote, is serviced only by Chile's LAN Airlines", + "Answer": "Easter Island" + }, + { + "Category": "CELEBRITIES' MIDDLE NAMES", + "Question": "Author Hawthorne would approve of this middle name of Ralph Fiennes", + "Answer": "Nathaniel" + }, + { + "Category": "CATHOLIC PRIESTS", + "Question": "The priest's duty to keep your sins secret is traditionally protected by \"the sanctity of\" this booth", + "Answer": "the confessional" + }, + { + "Category": "TITLE 9", + "Question": "Elizabeth McNeill: \"Nine and a Half ___\"", + "Answer": "Weeks" + }, + { + "Category": "COME \"IN\"", + "Question": "A military badge of rank or qualification", + "Answer": "insignia" + }, + { + "Category": "ART & ARTISTS", + "Question": "Andre Breton anagrammed this surrealist's name as \"Avida Dollars\"", + "Answer": "Salvador Dali" + }, + { + "Category": "TRAVEL", + "Question": "Beautiful Margaret Island in this river has been a Budapest park for more than 100 years", + "Answer": "the Danube" + }, + { + "Category": "CELEBRITIES' MIDDLE NAMES", + "Question": "Her middle name is Louise; her last name at birth: Ciccone", + "Answer": "Madonna" + }, + { + "Category": "CATHOLIC PRIESTS", + "Question": "Parish priests have their own one of these, John Vianney", + "Answer": "patron saint" + }, + { + "Category": "TITLE 9", + "Question": "Jeffrey Toobin: \"The Nine: Inside the Secret World of the ___ ___\"", + "Answer": "Supreme Court" + }, + { + "Category": "COME \"IN\"", + "Question": "Each Latin verb has 6 of these, including the perfect passive one, like optatus esse, \"to have been desired\"", + "Answer": "infinitive" + }, + { + "Category": "ART & ARTISTS", + "Question": "This American female impressionist modeled for many of Degas' works, including \"At the Milliner's\"", + "Answer": "Cassatt" + }, + { + "Category": "TRAVEL", + "Question": "You can buy samples of this fossilized resin at a museum devoted to it in Puerto Plata, Dominican Republic", + "Answer": "amber" + }, + { + "Category": "CELEBRITIES' MIDDLE NAMES", + "Question": "This middle name of actress Mary Masterson makes us wonder if she was named for Mary, Queen of Scots", + "Answer": "Stuart" + }, + { + "Category": "CATHOLIC PRIESTS", + "Question": "This spiritual \"director\" doesn't arrange your holiday, he helps young men pursue their calling to the priesthood", + "Answer": "a vocation director" + }, + { + "Category": "TITLE 9", + "Question": "J.D. Salinger: \"Nine ___\"", + "Answer": "Stories" + }, + { + "Category": "COME \"IN\"", + "Question": "Paul Apak Angilirq was a producer as Canada's IBC, this Broadcasting Corporation", + "Answer": "Inuit" + }, + { + "Category": "WANT ADS", + "Question": "Numbers cruncher needed! Must be member of AICPA, the American Institute of these", + "Answer": "Certified Public Accountants" + }, + { + "Category": "GO \"SOUTH\"", + "Question": "...to 90 degrees south latitude & you'll find yourself here", + "Answer": "the South Pole" + }, + { + "Category": "I KNOW THAT WORD BACKWARDS & FORWARDS", + "Question": "Anatomy-wise, the subscapularis is a muscle in this \"cuff\"", + "Answer": "rotator" + }, + { + "Category": "MESOPOTAMIA", + "Question": "After centuries of rule by the Ottoman Empire, Mesopotamia mostly became part of this new nation in 1932", + "Answer": "Iraq" + }, + { + "Category": "THE DE NIRO CODE", + "Question": "As Al Capone in this 1987 film: \"You can get further with a kind word and a gun than you can with just a kind word\"", + "Answer": "The Untouchables" + }, + { + "Category": "WANT ADS", + "Question": "Walk the Max Planck! We're Stephen Hawking a new position to be this type of scientist, like those guys", + "Answer": "physicist" + }, + { + "Category": "GO \"SOUTH\"", + "Question": "...to this Indiana college town that was originally called Big St. Joseph Station", + "Answer": "South Bend" + }, + { + "Category": "I KNOW THAT WORD BACKWARDS & FORWARDS", + "Question": "To make an allusion to something", + "Answer": "refer" + }, + { + "Category": "MESOPOTAMIA", + "Question": "Mesopotamia stretched from the Taurus Mountains in the north to this gulf in the south", + "Answer": "the Persian" + }, + { + "Category": "THE DE NIRO CODE", + "Question": "In this 1976 movie: \"Here is a man who would not take it anymore. A man who stood up against the scum\"", + "Answer": "Taxi Driver" + }, + { + "Category": "WANT ADS", + "Question": "They're out there! We need you to go get 'em! Channel your inner Boba Fett or \"Dog\" Chapman in this 2-word job", + "Answer": "a bounty hunter" + }, + { + "Category": "GO \"SOUTH\"", + "Question": "...to Juba, capital of this new nation", + "Answer": "South Sudan" + }, + { + "Category": "I KNOW THAT WORD BACKWARDS & FORWARDS", + "Question": "Reza Khan, born in Iran in 1878, & his son were these for a combined 54 years", + "Answer": "shahs" + }, + { + "Category": "MESOPOTAMIA", + "Question": "The epic poem of this Sumerian king includes an account of a great flood", + "Answer": "Gilgamesh" + }, + { + "Category": "THE DE NIRO CODE", + "Question": "To Billy Crystal in this film: \"I was gonna whack you. But I was real conflicted about it\"", + "Answer": "Analyze This" + }, + { + "Category": "WANT ADS", + "Question": "In the June 3, 2011 paper: this country wants new president after bomb explodes in Ali Saleh's presidential palace", + "Answer": "Yemen" + }, + { + "Category": "GO \"SOUTH\"", + "Question": "...to this body of water that includes the Gulf of Tonkin & the Gulf of Thailand", + "Answer": "the South China Sea" + }, + { + "Category": "I KNOW THAT WORD BACKWARDS & FORWARDS", + "Question": "Coloring something more rubicund makes it this", + "Answer": "redder" + }, + { + "Category": "MESOPOTAMIA", + "Question": "Transcribed in the 1800s, the Behistun Inscription is the Rosetta Stone for this type of writing developed in Mesopotamia", + "Answer": "cuneiform" + }, + { + "Category": "THE DE NIRO CODE", + "Question": "In Italian, in this sequel: \"Do me this favor..ask your friends...about me. They'll tell you I know how to return a favor\"", + "Answer": "The Godfather Part II" + }, + { + "Category": "WANT ADS", + "Question": "We have a primary need for this hyphenated job in our fancy French kitchen; only the head guy is your superior", + "Answer": "sous-chef" + }, + { + "Category": "GO \"SOUTH\"", + "Question": "...to here, where you'll find the cities of Christchurch & Dunedin", + "Answer": "the South Island" + }, + { + "Category": "I KNOW THAT WORD BACKWARDS & FORWARDS", + "Question": "Exalted to the rank of a god", + "Answer": "deified" + }, + { + "Category": "MESOPOTAMIA", + "Question": "From the Assyrian for \"height\", this stepped structure was used as a temple by Mesopotamian cultures", + "Answer": "ziggurat" + }, + { + "Category": "THE DE NIRO CODE", + "Question": "\"Goodfellas\": \"The two greatest things in life\" are \"never rat on\" these \"and always keep your mouth shut\"", + "Answer": "your friends" + }, + { + "Category": "FOOD ETYMOLOGY", + "Question": "Keith Downey developed rapeseed into this cooking product, now a huge cash crop for farmers in Saskatchewan", + "Answer": "canola" + }, + { + "Category": "EDGAR ALLAN POE-POURRI", + "Question": "A man's harrowing escape from torture during the Spanish Inquisition is recounted in this Poe favorite", + "Answer": "\"The Pit and the Pendulum\"" + }, + { + "Category": "HOP ON POP CULTURE", + "Question": "Meadow's dad had her boyfriend Jackie whacked on this show; A.J. had a pretty rough time, too", + "Answer": "The Sopranos" + }, + { + "Category": "RINGING THE OPENING BELL AT THE NYSE", + "Question": "Oct. 4, 2006 STOP This company's president & CEO Christina Gold rings opening bell STOP", + "Answer": "Western Union" + }, + { + "Category": "NEBRASKA, NEW YORK OR NORTH DAKOTA", + "Question": "The least populous", + "Answer": "North Dakota" + }, + { + "Category": "MOTHER GOOSE", + "Question": "Some speculate that this \"merry old soul\" of nursery rhyme fame was based on a real king of 3rd century Britain", + "Answer": "Old King Cole" + }, + { + "Category": "DEPARTMENT \"S\"", + "Question": "These elected officials in the U.S. government take their name from the Latin for \"old man\"", + "Answer": "senators" + }, + { + "Category": "EDGAR ALLAN POE-POURRI", + "Question": "This lung disease claimed the life of Poe's 24-year-old wife", + "Answer": "tuberculosis" + }, + { + "Category": "HOP ON POP CULTURE", + "Question": "Sydney's dad, Jack, was a CIA double agent working against SD-6 on this Jennifer Garner show", + "Answer": "Alias" + }, + { + "Category": "RINGING THE OPENING BELL AT THE NYSE", + "Question": "On Oct. 11, 2007 this chairman of the Virgin Group rang us up, but he didn't parachute in while on fire or anything", + "Answer": "Branson" + }, + { + "Category": "NEBRASKA, NEW YORK OR NORTH DAKOTA", + "Question": "Its name does not have a Native American origin", + "Answer": "New York" + }, + { + "Category": "MOTHER GOOSE", + "Question": "This shepherdess found her sheep's tails all hung on a tree to dry, so she tried to \"tack to each sheep its tail, oh\"", + "Answer": "Little Bo Peep" + }, + { + "Category": "DEPARTMENT \"S\"", + "Question": "Winter Olympic events using these first appeared at the 1998 Nagano games", + "Answer": "snowboards" + }, + { + "Category": "EDGAR ALLAN POE-POURRI", + "Question": "In the world's first detective story, C. Auguste Dupin solves the title crimes in \"The Murders\" here", + "Answer": "the Rue Morgue" + }, + { + "Category": "RINGING THE OPENING BELL AT THE NYSE", + "Question": "& then I saw him / Right there & like that / On Leap Day 2000 / 'Twas...", + "Answer": "the Cat in the Hat" + }, + { + "Category": "NEBRASKA, NEW YORK OR NORTH DAKOTA", + "Question": "The Oregon Trail crossed it", + "Answer": "Nebraska" + }, + { + "Category": "MOTHER GOOSE", + "Question": "Some say these 2 were actually Louis XVI & Marie Antoinette, who were beheaded (or broke their crowns) in 1793", + "Answer": "Jack & Jill" + }, + { + "Category": "DEPARTMENT \"S\"", + "Question": "Specifically, to give a shopper less money back than he is entitled to", + "Answer": "shortchange" + }, + { + "Category": "EDGAR ALLAN POE-POURRI", + "Question": "Spoiler alert! \"The Cask of\" this potent potable tells of a man sealing his enemy up behind a wall... alive!", + "Answer": "Amontillado" + }, + { + "Category": "HOP ON POP CULTURE", + "Question": "Mark Hamill played the oldest of Dick Van Patten's octet of kids in the pilot but not the series of this show", + "Answer": "Eight Is Enough" + }, + { + "Category": "RINGING THE OPENING BELL AT THE NYSE", + "Question": "Sept. 24, 2007 found this Bush cabinet member away from her piano & playing the bell", + "Answer": "Condi Rice" + }, + { + "Category": "NEBRASKA, NEW YORK OR NORTH DAKOTA", + "Question": "The largest in area", + "Answer": "Nebraska" + }, + { + "Category": "MOTHER GOOSE", + "Question": "It's the type of nail referred to in the nursery rhyme \"All for Want of a Nail\"", + "Answer": "a horseshoe nail" + }, + { + "Category": "DEPARTMENT \"S\"", + "Question": "Term for an early 20th century female agitator for women's voting rights", + "Answer": "a suffragist" + }, + { + "Category": "EDGAR ALLAN POE-POURRI", + "Question": "This French \"Flowers of Evil\" author translated Poe's tales into French", + "Answer": "Charles Baudelaire" + }, + { + "Category": "HOP ON POP CULTURE", + "Question": "Howard Cunningham actually had 3 kids on this show, but Chuck was never seen after Season 2", + "Answer": "Happy Days" + }, + { + "Category": "RINGING THE OPENING BELL AT THE NYSE", + "Question": "Oh, come on! On Feb. 28, 2008 this TV \"Kitchen Nightmares\" man added a touch of bell to his resume", + "Answer": "Gordon Ramsey" + }, + { + "Category": "NEBRASKA, NEW YORK OR NORTH DAKOTA", + "Question": "Its cities include Minot, Jamestown & Grand Forks", + "Answer": "North Dakota" + }, + { + "Category": "MOTHER GOOSE", + "Question": "After singing for his supper, he ate \"white bread and butter\"", + "Answer": "Little Tommy Tucker" + }, + { + "Category": "DEPARTMENT \"S\"", + "Question": "Eternally doomed rock roller of Greek mythology", + "Answer": "Sisyphus" + }, + { + "Category": "STATE FISH", + "Question": "This state's official saltwater fish, the tarpon, can be found in the Gulf of Mexico & in the Mobile Estuary", + "Answer": "Alabama" + }, + { + "Category": "MOVIES BY ROLES", + "Question": "1989: Heather McNamara, Heather Chandler, Heather Duke", + "Answer": "Heathers" + }, + { + "Category": "I'M HUNGRY!", + "Question": "I bought a special log to grow the shiitake type of these; let's grill some right now", + "Answer": "mushrooms" + }, + { + "Category": "\"V\" HAVE MAPS", + "Question": "Prussian Baron Friedrich von Steuben arrived at this location in the winter of 1778 to train American troops", + "Answer": "Valley Forge" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "To \"go\" this, meaning all the way, comes from an 18th c. poem about inability to decide which part of the pig to eat", + "Answer": "whole hog" + }, + { + "Category": "STATE FISH", + "Question": "A subspecies of cutthroat trout, the Bonneville cutthroat is native to this state & is its state fish", + "Answer": "Utah" + }, + { + "Category": "MOVIES BY ROLES", + "Question": "1942: Ugarte, Sascha, Major Strasser", + "Answer": "Casablanca" + }, + { + "Category": "I'M HUNGRY!", + "Question": "Yummy! Bubbie made some of these potato pancakes, & it isn't even Hanukkah", + "Answer": "latkes" + }, + { + "Category": "\"V\" HAVE MAPS", + "Question": "In 1814 the congress of this city met to redraw Europe", + "Answer": "Vienna" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "Jacobins in the French Revolution proudly called themselves these, now describing people who use fear to persuade", + "Answer": "terrorists" + }, + { + "Category": "STATE FISH", + "Question": "The reef triggerfish, this state's state fish, can be found as far south as Australia", + "Answer": "Hawaii" + }, + { + "Category": "MOVIES BY ROLES", + "Question": "1982: Mr. Hand, Stacy Hamilton, Jeff Spicoli", + "Answer": "Fast Times at Ridgemont High" + }, + { + "Category": "I'M HUNGRY!", + "Question": "Let's make Craig Claiborne's recipe for an upside-down type of this fruit pie; it's a lot like tarte tatin", + "Answer": "apple pie" + }, + { + "Category": "\"V\" HAVE MAPS", + "Question": "As a 19th century emperor of this country, Minh Mang executed several French Catholic missionaries", + "Answer": "Vietnam" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "Coined in the '70s, the term \"Ebonics\" comes from these 2 words", + "Answer": "ebony & phonics" + }, + { + "Category": "STATE FISH", + "Question": "Maryland's state fish, the rockfish, is also known as the striped species of this", + "Answer": "bass" + }, + { + "Category": "MOVIES BY ROLES", + "Question": "1998: Richard Burbage, Queen Elizabeth, Viola de Lesseps", + "Answer": "Shakespeare in Love" + }, + { + "Category": "I'M HUNGRY!", + "Question": "I can't pass up the mousse d'ecrevisse, made with these freshwater crustaceans", + "Answer": "crayfish" + }, + { + "Category": "\"V\" HAVE MAPS", + "Question": "The African country of Burkina Faso was once known as \"Upper\" this", + "Answer": "Volta" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "Politically, this word for a region reflecting a large trend comes from a lead sheep with a ringer around its neck", + "Answer": "a bellwether" + }, + { + "Category": "STATE FISH", + "Question": "Florida's state saltwater fish is this game fish known for its raised dorsal fin & spear-like nose", + "Answer": "a sailfish" + }, + { + "Category": "MOVIES BY ROLES", + "Question": "1994: Jenny Curran, Lt. Dan, \"Bubba\" Blue", + "Answer": "Forrest Gump" + }, + { + "Category": "I'M HUNGRY!", + "Question": "Let's go Penn. Dutch & have this dish, bits of pork mixed with cornmeal mush, then shaped into loaves & fried", + "Answer": "scrapple" + }, + { + "Category": "\"V\" HAVE MAPS", + "Question": "In 1323 Lithuanian Grand Duke Gediminas made this city his capital", + "Answer": "Vilnius" + }, + { + "Category": "WORD & PHRASE ORIGINS", + "Question": "The name of this South American snake comes from an Asian word, as it may have been mistaken for an Asian python", + "Answer": "an anaconda" + }, + { + "Category": "WORLD LEADERS", + "Question": "Born in Kiev & later a U.S. citizen, this leader became prime minister in 1969 of a country founded in the 20th century", + "Answer": "Golda Meir" + }, + { + "Category": "U.S. CITIES", + "Question": "This Wyoming capital is home to the annual Frontier Days celebration", + "Answer": "Cheyenne" + }, + { + "Category": "PRESIDENTS' MONOGRAMS", + "Question": "RMN", + "Answer": "Richard Milhous Nixon" + }, + { + "Category": "SOME MORE SIMIAN CINEMA", + "Question": "When this Mouseketeer starred in \"The Monkey's Uncle\", she sang the title tune with The Beach Boys", + "Answer": "Annette Funicello" + }, + { + "Category": "TRUE LIVES", + "Question": "She talks about Soon-Yi & former flame Woody Allen in her 1997 memoir \"What Falls Away\"", + "Answer": "Mia Farrow" + }, + { + "Category": "HAMMERS", + "Question": "He said to his captain, \"Before I let your steam drill beat me, I'd die with this hammer in my hand\"", + "Answer": "John Henry" + }, + { + "Category": "4-LETTER WORDS", + "Question": "It's a song of praise, like \"Rock Of Ages\"", + "Answer": "Hymn" + }, + { + "Category": "U.S. CITIES", + "Question": "It's the only Maryland city not located within a county", + "Answer": "Baltimore" + }, + { + "Category": "PRESIDENTS' MONOGRAMS", + "Question": "DDE", + "Answer": "Dwight David Eisenhower" + }, + { + "Category": "SOME MORE SIMIAN CINEMA", + "Question": "Robert Guillaume provided the voice of Rafiki, the wise old baboon, in this 1994 film", + "Answer": "The Lion King" + }, + { + "Category": "TRUE LIVES", + "Question": "\"In Her Sister's Shadow\" is a biography of Lee Radziwill, sister of this woman", + "Answer": "Jacqueline Kennedy Onassis" + }, + { + "Category": "HAMMERS", + "Question": "Up to a few years ago it was the emblem of the Soviet Union", + "Answer": "Hammer & sickle" + }, + { + "Category": "4-LETTER WORDS", + "Question": "Take off the top, or milk from which the cream has been removed", + "Answer": "Skim" + }, + { + "Category": "U.S. CITIES", + "Question": "Principal routes through this capital include Ala Moana Boulevard & Pali Highway", + "Answer": "Honolulu" + }, + { + "Category": "PRESIDENTS' MONOGRAMS", + "Question": "RWR", + "Answer": "Ronald Wilson Reagan" + }, + { + "Category": "SOME MORE SIMIAN CINEMA", + "Question": "This Rene Russo film about an eccentric & her pets is based on a true story; it features the following:", + "Answer": "Buddy" + }, + { + "Category": "TRUE LIVES", + "Question": "Isak Dinesen reflected on her years in Kenya in this book, later the title of a film about her", + "Answer": "Out Of Africa" + }, + { + "Category": "HAMMERS", + "Question": "Goods being sold \"under the hammer\" are found at these events", + "Answer": "Auctions" + }, + { + "Category": "4-LETTER WORDS", + "Question": "It's the edge of a hat, or the topmost edge of a cup or bowl", + "Answer": "Brim" + }, + { + "Category": "U.S. CITIES", + "Question": "This Arizona city's name comes from Chuk Son, Papago for \"Spring at the foot of a black mountain\"", + "Answer": "Tucson" + }, + { + "Category": "PRESIDENTS' MONOGRAMS", + "Question": "HCH", + "Answer": "Herbert Clark Hoover" + }, + { + "Category": "SOME MORE SIMIAN CINEMA", + "Question": "It's the island where Fay Wray first encountered King Kong; to think of its name, use your \"head\"", + "Answer": "Skull Island" + }, + { + "Category": "TRUE LIVES", + "Question": "Despite its title, \"The Autobiography of Alice B. Toklas\" is a book by & about this woman", + "Answer": "Gertrude Stein" + }, + { + "Category": "HAMMERS", + "Question": "A 1st century B.C. maxim of Publilius Syrus says it's when you should hammer your iron", + "Answer": "When it's hot" + }, + { + "Category": "4-LETTER WORDS", + "Question": "An arm or leg", + "Answer": "Limb" + }, + { + "Category": "U.S. CITIES", + "Question": "This Rhode Island resort city is the site of the U.S. Navy Undersea Warfare Center", + "Answer": "Newport" + }, + { + "Category": "PRESIDENTS' MONOGRAMS", + "Question": "JKP", + "Answer": "James Knox Polk" + }, + { + "Category": "SOME MORE SIMIAN CINEMA", + "Question": "1968 classic with the ad line \"Somewhere in the universe, there must be something better than man!\"", + "Answer": "Planet of the Apes" + }, + { + "Category": "TRUE LIVES", + "Question": "Extra! Extra! Read all about this retired Washington Post publisher in \"Personal History\"", + "Answer": "Katharine Graham" + }, + { + "Category": "HAMMERS", + "Question": "Paul McCartney said this song \"Epitomizes the downfalls in life\"", + "Answer": "Maxwell's Silver Hammer" + }, + { + "Category": "4-LETTER WORDS", + "Question": "Gloomy & forbidding, like a certain \"reaper\"", + "Answer": "Grim" + }, + { + "Category": "MYTHOLOGY", + "Question": "Danae gave birth to Perseus after Zeus visited her in the form of a shower of this precious metal", + "Answer": "Gold" + }, + { + "Category": "ITALIAN ART", + "Question": "Andrea del Sarto's 1527 version of this Biblical banquet is similar to that of Leonardo, a man he admired", + "Answer": "The Last Supper" + }, + { + "Category": "FOLKIES", + "Question": "The times they were a-changin' when this folk icon went electric at the 1965 Newport Festival", + "Answer": "Bob Dylan" + }, + { + "Category": "DAYS", + "Question": "Leap day date", + "Answer": "29-Feb" + }, + { + "Category": "KNIGHTS", + "Question": "Code of behavior for a knight to remember", + "Answer": "Chivalry" + }, + { + "Category": "GOING DUTCH", + "Question": "Ask a Dutchman \"Spreekt U Engels?\", which means this, & he'll probably say, \"Yes\"", + "Answer": "Do you speak English?" + }, + { + "Category": "MYTHOLOGY", + "Question": "In Australian myth, Ngunung-Ngunnut, one of these flying mammals, created the first woman", + "Answer": "Bat" + }, + { + "Category": "ITALIAN ART", + "Question": "Gentile da Fabriano used the international Gothic style for his painting \"The Adoration Of\" this trio", + "Answer": "The Magi" + }, + { + "Category": "FOLKIES", + "Question": "In his hard youth, this Oklahoman who fathered Arlo & the Folk Revival had a job washing spittoons", + "Answer": "Woody Guthrie" + }, + { + "Category": "DAYS", + "Question": "In 1954 Armistice Day was renamed this", + "Answer": "Veterans Day" + }, + { + "Category": "KNIGHTS", + "Question": "This adjective, a synonym for \"wandering\", describes the type of knight satirized by Cervantes", + "Answer": "Knight-errant" + }, + { + "Category": "GOING DUTCH", + "Question": "This relative is \"de oom\", whether or not he's a \"Dutch\" one", + "Answer": "Uncle" + }, + { + "Category": "MYTHOLOGY", + "Question": "Daphnis, who invented pastoral poetry, was the son of this Greek messenger god & a Sicilian nymph", + "Answer": "Hermes" + }, + { + "Category": "ITALIAN ART", + "Question": "For her 1997 calendar, singer Gloria Trevi recreated this artist's \"Birth Of Venus\" with herself as Venus", + "Answer": "Sandro Botticelli" + }, + { + "Category": "FOLKIES", + "Question": "Her famed soprano is heard here in a '60s recording:", + "Answer": "Judy Collins" + }, + { + "Category": "DAYS", + "Question": "In the U.S. the Jewish festivals of Hanukkah & Passover each last this many days", + "Answer": "8" + }, + { + "Category": "KNIGHTS", + "Question": "A young boy between 7 & 14 who trained as a knight, or his hairdo", + "Answer": "Page" + }, + { + "Category": "GOING DUTCH", + "Question": "The dairy is \"de melwinkel\" while \"de kaaswinkel\" specializes in this kind of dairy product", + "Answer": "Cheese" + }, + { + "Category": "MYTHOLOGY", + "Question": "This Norse god known for his great strength was a protector of peasants & farmers", + "Answer": "Thor" + }, + { + "Category": "ITALIAN ART", + "Question": "\"Pumpkin Head\" is a 1420s sculpture of a bald man by Donato di Niccolo, better known as this", + "Answer": "Donatello" + }, + { + "Category": "FOLKIES", + "Question": "Peggy, sister of this co-founder of The Weavers, wrote the feminist anthem \"Gonna Be An Engineer\"", + "Answer": "Pete Seeger" + }, + { + "Category": "DAYS", + "Question": "Many European countries celebrate the equivalent of this American holiday on May Day", + "Answer": "Labor Day" + }, + { + "Category": "KNIGHTS", + "Question": "Women given the rank corresponding to knighthood are called this", + "Answer": "Dames" + }, + { + "Category": "GOING DUTCH", + "Question": "Driving through the Netherlands? You should know a sign that says \"Parkeerverbod\" means this", + "Answer": "No Parking" + }, + { + "Category": "MYTHOLOGY", + "Question": "These fiendish feathered females swooped down over Phineus & befouled his food", + "Answer": "Harpies" + }, + { + "Category": "ITALIAN ART", + "Question": "In 1533 this Venetian was made court painter by Emperor Charles V, who also ennobled him", + "Answer": "Titian" + }, + { + "Category": "FOLKIES", + "Question": "Born Michelle Johnston, she \"stunned\" the industry in 1994 by selling her new album only at her shows", + "Answer": "Michelle Shocked" + }, + { + "Category": "DAYS", + "Question": "The British have a real blast on this day, November 5", + "Answer": "Guy Fawkes Day" + }, + { + "Category": "KNIGHTS", + "Question": "In the 12th C. these French minstrels began composing songs about knights called chansons de geste", + "Answer": "Troubadours" + }, + { + "Category": "GOING DUTCH", + "Question": "It's a cinch you know the Dutch call this fashion accessory \"een ceintuur\"", + "Answer": "Belt" + }, + { + "Category": "BRAND NAMES", + "Question": "Formulated in 1953, its first purpose was \"water displacement\" to prevent corrosion on missiles", + "Answer": "WD-40" + }, + { + "Category": "THE MISFITS", + "Question": "1965's \"The Outlaws Is Coming\" was the last movie featuring this wacky trio of comedy misfits", + "Answer": "The Three Stooges" + }, + { + "Category": "ALL MY SONS", + "Question": "Gutzon Borglum died in 1941 so his son, Lincoln, finished sculpting the 4 figures of this memorial", + "Answer": "Mount Rushmore" + }, + { + "Category": "THE CRUCIBLE", + "Question": "Nitrides of boron & silicon are used to make crucibles because they are stable when this is high", + "Answer": "temperature" + }, + { + "Category": "\"DEATH\"", + "Question": "Bubonic plague's more descriptive name", + "Answer": "the Black Death" + }, + { + "Category": "OF A SALESMAN", + "Question": "Sick of selling dry goods from a buggy, in 1872 Montgomery Ward issued a one-page one of these", + "Answer": "a catalog" + }, + { + "Category": "ARTHUR MILLER", + "Question": "Arthur Miller's marriage to her was mirrored in his play \"After the Fall\"", + "Answer": "Marilyn Monroe" + }, + { + "Category": "THE MISFITS", + "Question": "In 1953 this big-screen misfit duo met Dr. Jekyll & Mr. Hyde; in 1955 they met the mummy", + "Answer": "Abbott & Costello" + }, + { + "Category": "ALL MY SONS", + "Question": "Kidnappers got under this crooner's skin when they kidnapped his son from a Tahoe casino in 1963", + "Answer": "Frank Sinatra" + }, + { + "Category": "THE CRUCIBLE", + "Question": "Crucibles are sometimes made out of this ceramic material made by firing pure clay", + "Answer": "porcelain" + }, + { + "Category": "\"DEATH\"", + "Question": "The 7 words that complete the speech Patrick Henry gave on March 23, 1775", + "Answer": "\"Give me liberty or give me death\"" + }, + { + "Category": "OF A SALESMAN", + "Question": "In the '80s this city's Old Vic Theater was refurbished by salesman \"Honest Ed\" Mirvish", + "Answer": "London" + }, + { + "Category": "ARTHUR MILLER", + "Question": "Miller's play \"A View from the Bridge\" concerns a view from this New York bridge", + "Answer": "the Brooklyn Bridge" + }, + { + "Category": "THE MISFITS", + "Question": "Born Joseph Levitch, he's been a nutty professor & an errand boy", + "Answer": "Jerry Lewis" + }, + { + "Category": "ALL MY SONS", + "Question": "Nickname of the \"son\" who terrorized NYC in the summer of '77", + "Answer": "Son of Sam" + }, + { + "Category": "THE CRUCIBLE", + "Question": "This element, Pt, is used in crucibles & tongs because of its inertness & high fusing point", + "Answer": "platinum" + }, + { + "Category": "OF A SALESMAN", + "Question": "This direct-selling co. known for products like Nutrilite claims 3 million independent business owners", + "Answer": "Amway" + }, + { + "Category": "ARTHUR MILLER", + "Question": "In June 1999 Arthur Miller received a lifetime achievement one of these awards at Radio City Music Hall", + "Answer": "a Tony Award" + }, + { + "Category": "THE MISFITS", + "Question": "When these misfit brothers were \"at the circus\" in a 1939 film, \"Lydia the tattooed lady\" was there, too", + "Answer": "The Marx Brothers" + }, + { + "Category": "ALL MY SONS", + "Question": "Egypt is sometimes called the land of this fertile son of Noah", + "Answer": "Ham" + }, + { + "Category": "THE CRUCIBLE", + "Question": "Brass usually comes out of a crucible in this 5-letter form, more familiarly used with gold", + "Answer": "an ingot" + }, + { + "Category": "\"DEATH\"", + "Question": "Suge Knight & Tupac Shakur's rap music record label", + "Answer": "Death Row Records" + }, + { + "Category": "OF A SALESMAN", + "Question": "When dealing with a car salesman, know that the MSRP, short for this, doesn't include taxes & registration", + "Answer": "manufacturer's suggested retail price" + }, + { + "Category": "ARTHUR MILLER", + "Question": "Arthur Miller wrote the screenplay for the 1961 film \"The Misfits\", this male superstar's last film", + "Answer": "Clark Gable" + }, + { + "Category": "ALL MY SONS", + "Question": "This man whose surname means \"hammer\" counted Carloman & Pepin the Short as sons", + "Answer": "Charles Martel" + }, + { + "Category": "THE CRUCIBLE", + "Question": "A vertical crucible called a \"skull\" is used to make the gem called \"cubic\" this", + "Answer": "zirconium" + }, + { + "Category": "OF A SALESMAN", + "Question": "This 1992 presidential candidate sold IBM computers in Texas before starting his own company, EDS", + "Answer": "Ross Perot" + }, + { + "Category": "ARTHUR MILLER", + "Question": "Miller's play \"Death of a Salesman\" was his tragic tale of this title character", + "Answer": "Willy Loman" + }, + { + "Category": "PSYCHOLOGY", + "Question": "Brought to the U.S. in the 1930s, this movement's name is German for \"pattern\" or \"shape\"", + "Answer": "gestalt" + }, + { + "Category": "ON THE BIG SCREEN", + "Question": "Get some McLovin from this 2007 comedy that Seth Rogen & Evan Goldberg began writing as 13-year-olds", + "Answer": "Superbad" + }, + { + "Category": "GET YOUR FACTS STRAIGHT", + "Question": "Galaga is an arcade game; Gallagher smashes this fruit, Citrullus lanatus, with the Sledge-O-Matic", + "Answer": "watermelon" + }, + { + "Category": "COUNTRIES THAT END IN \"O\"", + "Question": "This nation has been ruled by the Grimaldi royal family since the 14th century", + "Answer": "Monaco" + }, + { + "Category": "4-LETTER VERBS", + "Question": "\"Like it or\" do this, meaning take or endure it", + "Answer": "lump it" + }, + { + "Category": "ON THE BIG SCREEN", + "Question": "Mais oui! In 2007 Chris Tucker & Jackie Chan headed to Paris, giving this film series trilogy status", + "Answer": "Rush Hour" + }, + { + "Category": "GET YOUR FACTS STRAIGHT", + "Question": "Theodore Dreiser wrote \"An American Tragedy\"; Philip Roth, \"The Great American\" this", + "Answer": "Novel" + }, + { + "Category": "COUNTRIES THAT END IN \"O\"", + "Question": "This former Yugoslavian republic broke away from Serbia in 2006", + "Answer": "Montenegro" + }, + { + "Category": "4-LETTER VERBS", + "Question": "\"And when two lovers woo they still say 'I love you' on that you can\" do this", + "Answer": "rely" + }, + { + "Category": "PSYCHOLOGY", + "Question": "It took 8 years for this 1899 Freud work to sell the initial 600 copies printed, earning him about $250 in royalties", + "Answer": "The Interpretation of Dreams" + }, + { + "Category": "GET YOUR FACTS STRAIGHT", + "Question": "If you're vulpine, you're like a fox; if you're lying on your back with your face upward, you're in this position", + "Answer": "supine" + }, + { + "Category": "COUNTRIES THAT END IN \"O\"", + "Question": "The largest country in area that ends in \"O\", it has a population of about 66 million", + "Answer": "the Congo" + }, + { + "Category": "4-LETTER VERBS", + "Question": "To stop a leak or publicize a product", + "Answer": "plug" + }, + { + "Category": "PSYCHOLOGY", + "Question": "Known for his \"box\", he wrote \"Walden Two\", a 1948 fiction work about operant conditioning", + "Answer": "B.F. Skinner" + }, + { + "Category": "ON THE BIG SCREEN", + "Question": "Kevin Costner's funeral kicks off this \"big\" 1983 film but sadly, Kevin couldn't make it; he got cut from the film in editing", + "Answer": "The Big Chill" + }, + { + "Category": "GET YOUR FACTS STRAIGHT", + "Question": "Tarantino is a director; this is a rapid, whirling dance named for an Italian city", + "Answer": "tarantella" + }, + { + "Category": "COUNTRIES THAT END IN \"O\"", + "Question": "Open an atlas & discover that the Atlas Mountains traverse the length of this country", + "Answer": "Morocco" + }, + { + "Category": "4-LETTER VERBS", + "Question": "It's said that \"Horses sweat, men perspire, women\" do this", + "Answer": "glow" + }, + { + "Category": "PSYCHOLOGY", + "Question": "In 1935 he founded the Swiss Society for Practical Psychology & became its president", + "Answer": "Carl Jung" + }, + { + "Category": "GET YOUR FACTS STRAIGHT", + "Question": "The Coriolis effect is caused by the Earth's rotation; this is a Shakespeare play about Caius Marcius", + "Answer": "Coriolanus" + }, + { + "Category": "COUNTRIES THAT END IN \"O\"", + "Question": "This small country is about 1/20th the size of NYC & its primary language is Italian", + "Answer": "San Marino" + }, + { + "Category": "4-LETTER VERBS", + "Question": "It means \"to strongly encourage\", & all its letters are found in the word encourage", + "Answer": "urge" + }, + { + "Category": "AUTHORS", + "Question": "Sherwood Anderson told him, write about what \"you know... that little patch... in Mississippi where you started from\"", + "Answer": "William Faulkner" + }, + { + "Category": "NAME THE WORK", + "Question": "Cervantes: \"At a village of La Mancha, whose name I do not wish to remember\"", + "Answer": "Don Quixote" + }, + { + "Category": "HEISMAN WINNERS", + "Question": "Carson Palmer, Reggie Bush & Matt Leinart are a few of this school's recent winners", + "Answer": "the University of Southern California" + }, + { + "Category": "I WANT TO RIDE THAT!", + "Question": "The Pitt Fall is a scary free fall ride at Kennywood, near this second-largest Pennsylvania city", + "Answer": "Pittsburgh" + }, + { + "Category": "A HORSE IS A HORSE", + "Question": "The Greek hero Bellerophon was crippled when he fell off this winged steed", + "Answer": "Pegasus" + }, + { + "Category": "THE FORTUNE 500", + "Question": "No. 242 on the list, this insurance co.'s $99.3 billion loss made it Fortune's biggest loser ever", + "Answer": "AIG" + }, + { + "Category": "RHYMES WITH TRACK", + "Question": "A pile of pancakes", + "Answer": "stack" + }, + { + "Category": "NAME THE WORK", + "Question": "Verne: \"Certainly an Englishman, it was more doubtful whether Phileas Fogg was a Londoner\"", + "Answer": "Around the World in Eighty Days" + }, + { + "Category": "HEISMAN WINNERS", + "Question": "Even though his team won the BCS Championship in 2009, this QB didn't win back-to-back Heismans", + "Answer": "Tim Tebow" + }, + { + "Category": "I WANT TO RIDE THAT!", + "Question": "No tame little swing ride, the Starflyer in this Austrian city swings you as high as a 23-story building", + "Answer": "Vienna" + }, + { + "Category": "A HORSE IS A HORSE", + "Question": "A horse named Comanche survived this man's June 1876 \"Last Stand\"", + "Answer": "Custer" + }, + { + "Category": "THE FORTUNE 500", + "Question": "Since the Fortune 500 list began in 1955, only Exxon, Wal-Mart & this now-troubled auto co. have held the top spot", + "Answer": "GM" + }, + { + "Category": "RHYMES WITH TRACK", + "Question": "A somewhat shapeless dress", + "Answer": "a sack" + }, + { + "Category": "NAME THE WORK", + "Question": "Melville: \"Captain Vere was an exceptional character\"", + "Answer": "Billy Budd" + }, + { + "Category": "HEISMAN WINNERS", + "Question": "Sam Bradford, the most recent winner of the Heisman, attended a university in this conference", + "Answer": "the Big 12" + }, + { + "Category": "I WANT TO RIDE THAT!", + "Question": "Six Flags Great America unleashed a roller coaster named for this bat-tastic 2008 blockbuster", + "Answer": "The Dark Knight" + }, + { + "Category": "A HORSE IS A HORSE", + "Question": "The Lone Ranger rode Silver & this companion of his rode a horse named Scout", + "Answer": "Tonto" + }, + { + "Category": "THE FORTUNE 500", + "Question": "Fortune's \"Most Likely to Succeed\" was this Internet search site at No. 119 with 35 different \"buy\" ratings", + "Answer": "Google" + }, + { + "Category": "RHYMES WITH TRACK", + "Question": "A knave who's a real card", + "Answer": "a jack" + }, + { + "Category": "NAME THE WORK", + "Question": "Jack London: \"'The Ghost' was rolling slightly on a calm sea without a breath of wind\"", + "Answer": "The Sea Wolf" + }, + { + "Category": "HEISMAN WINNERS", + "Question": "In 2006 Troy Smith joined Eddie George & back-to-back winner Archie Griffin as winners from this school", + "Answer": "Ohio State" + }, + { + "Category": "I WANT TO RIDE THAT!", + "Question": "I may not know \"Who Framed\" this movie bunny, but I can ride his Car Toon Spin at Disneyland", + "Answer": "Roger Rabbit" + }, + { + "Category": "A HORSE IS A HORSE", + "Question": "In \"The Lord of the Rings\", Gandalf rides this horse that only he could tame", + "Answer": "Shadowfax" + }, + { + "Category": "THE FORTUNE 500", + "Question": "With 14,000 videos, the most watched Fortune 500 CEO on YouTube was this bespectacled chairman of the No. 35 company", + "Answer": "Bill Gates" + }, + { + "Category": "RHYMES WITH TRACK", + "Question": "The cry of a canvasback", + "Answer": "quack" + }, + { + "Category": "NAME THE WORK", + "Question": "O. Henry: \"Tomorrow would be Christmas Day, and she had only $1.87 with which to buy Jim a present\"", + "Answer": "\"The Gift of the Magi\"" + }, + { + "Category": "HEISMAN WINNERS", + "Question": "An award given for the best running back in college football is named for this 1948 Heisman winner from SMU", + "Answer": "Doak Walker" + }, + { + "Category": "I WANT TO RIDE THAT!", + "Question": "Atlantis on this \"heavenly\" island in the Bahamas has a Lazy River Ride & a Mayan Temple Water Slide", + "Answer": "Paradise Island" + }, + { + "Category": "A HORSE IS A HORSE", + "Question": "Alexander the Great conquered much of the known world riding this stallion", + "Answer": "Bucephalus" + }, + { + "Category": "THE FORTUNE 500", + "Question": "At No. 9, this printer-heavy co. from Palo Alto had the biggest payroll bump after acquiring 149,000 EDS workers", + "Answer": "HP" + }, + { + "Category": "RHYMES WITH TRACK", + "Question": "It's a titan in the trucking industry", + "Answer": "Mack" + }, + { + "Category": "TAYLOR, SWIFT", + "Question": "Taylor Lautner played Jacob Black in this 2008 vampire flick", + "Answer": "Twilight" + }, + { + "Category": "PLANT LIFE", + "Question": "Carl Sandburg wrote, \"I am\" this most abundant type of flora; \"I cover all\"", + "Answer": "the grass" + }, + { + "Category": "ART", + "Question": "In the 1300s Italy gave birth to this art movement that would eventually sweep across Europe", + "Answer": "the Renaissance" + }, + { + "Category": "TIME TO CONVERT", + "Question": "It's the simplest fractional form of .75", + "Answer": "4-Mar" + }, + { + "Category": "\"V\" IS FOR", + "Question": "...this word on a sign meaning there's still room at the inn", + "Answer": "vacancy" + }, + { + "Category": "TAYLOR, SWIFT", + "Question": "\"Gossip Girl\" Taylor Momsen was Cindy Lou Who in this holiday film", + "Answer": "How the Grinch Stole Christmas" + }, + { + "Category": "PLANT LIFE", + "Question": "If someone insists your spruce is really a fir, show him that these pointy items are square, not flat", + "Answer": "needles" + }, + { + "Category": "TIME TO CONVERT", + "Question": "MMIX in Roman numerals gives us this year", + "Answer": "2009" + }, + { + "Category": "\"V\" IS FOR", + "Question": "...this third-largest city of Spain, famous for its oranges", + "Answer": "Valencia" + }, + { + "Category": "TAYLOR, SWIFT", + "Question": "Taylor Kitsch is Gambit in this 2009 X-Men flick", + "Answer": "Wolverine" + }, + { + "Category": "PLANT LIFE", + "Question": "Club, reindeer & Spanish are called this but botanically are not true this", + "Answer": "moss" + }, + { + "Category": "ART", + "Question": "This artist used trowels, sticks & even basters to create some of his drip paintings, like \"Cathedral\"", + "Answer": "Jackson Pollock" + }, + { + "Category": "TIME TO CONVERT", + "Question": ".001 grams is equal to one of these", + "Answer": "a milligram" + }, + { + "Category": "\"V\" IS FOR", + "Question": "...this pasta, thinner than spaghetti, whose name is Italian for \"little worms\"", + "Answer": "vermicelli" + }, + { + "Category": "TAYLOR, SWIFT", + "Question": "This season 5 winner of \"American Idol\" is from Alabama", + "Answer": "Taylor Hicks" + }, + { + "Category": "PLANT LIFE", + "Question": "It's the large floating leaf of a water lily", + "Answer": "pad" + }, + { + "Category": "TIME TO CONVERT", + "Question": "Multiply your liters by 1.0567 to get your amount of these units", + "Answer": "a quart" + }, + { + "Category": "\"V\" IS FOR", + "Question": "...this, like Paricutin in Mexico", + "Answer": "volcano" + }, + { + "Category": "TAYLOR, SWIFT", + "Question": "In a 2008 film he played Drillbit Taylor", + "Answer": "Owen Wilson" + }, + { + "Category": "PLANT LIFE", + "Question": "The spiny shrub ocotillo takes these as its habitat & is common in the Sonoran & Chihuahuan ones", + "Answer": "a desert" + }, + { + "Category": "ART", + "Question": "In 1865 he shocked Paris with \"Olympia\", his painting of a reclining nude", + "Answer": "Édouard Manet" + }, + { + "Category": "TIME TO CONVERT", + "Question": "You do the math: -40 degrees on the Fahrenheit temperature scale equals this on the Celsius scale", + "Answer": "-40" + }, + { + "Category": "\"V\" IS FOR", + "Question": "...this everyday form of Latin spoken by the Romans; sounds crude but it wasn't", + "Answer": "Vulgar" + }, + { + "Category": "THE 50 STATES", + "Question": "An 1881 resolution established that this state's name was to be spelled one way but pronounced another", + "Answer": "Arkansas" + }, + { + "Category": "THE 50 STATES", + "Question": "Cape Prince of Wales on the Seward Peninsula is this state's westernmost mainland point", + "Answer": "Alaska" + }, + { + "Category": "HOW TO BE A BAD SPORT", + "Question": "When keeping score in this sport, \"forget\" to add your opponent's next pin score to his spare", + "Answer": "Bowling" + }, + { + "Category": "BRAND NAMES", + "Question": "Mass production of these in the U.S. can be traced back to Donald F. Duncan in the 1920s", + "Answer": "Yo-yos" + }, + { + "Category": "THE 20th CENTURY", + "Question": "Shortly after taking power, he nationalized millions of dollars of American-owned property in Cuba", + "Answer": "Fidel Castro" + }, + { + "Category": "CLASSIC STAR TREK", + "Question": "From the Old Germanic for \"legs\", it's Dr. McCoy's nickname", + "Answer": "\"Bones\"" + }, + { + "Category": "RHYMES WITH TEEN", + "Question": "Nasty or stingy; or the average", + "Answer": "Mean" + }, + { + "Category": "THE 50 STATES", + "Question": "Among its nicknames are \"The Prairie State\" & \"The Land of Lincoln\"", + "Answer": "Illinois" + }, + { + "Category": "HOW TO BE A BAD SPORT", + "Question": "If you're playing midfield in this sport & the center is dribbling the ball towards you, kick at his shins", + "Answer": "Soccer" + }, + { + "Category": "BRAND NAMES", + "Question": "Joseph McVicker invented this after seeing the trouble kids had with modeling clay", + "Answer": "Play-Doh" + }, + { + "Category": "THE 20th CENTURY", + "Question": "On December 1, 1959, 12 nations signed a treaty setting aside this continent as a preserve for scientific research", + "Answer": "Antarctica" + }, + { + "Category": "RHYMES WITH TEEN", + "Question": "Just one Boston baked veggie", + "Answer": "Bean" + }, + { + "Category": "THE 50 STATES", + "Question": "In 1845, after nearly 10 years of independence, it became the 28th state", + "Answer": "Texas" + }, + { + "Category": "HOW TO BE A BAD SPORT", + "Question": "Get a leg up in this sport by stepping on your opponent's ball in the fairway", + "Answer": "Golf" + }, + { + "Category": "BRAND NAMES", + "Question": "In 1930 General Mills introduced this mix to make biscuits quickly", + "Answer": "Bisquick" + }, + { + "Category": "THE 20th CENTURY", + "Question": "In 1917 he called for a declaration of war against Germany saying that \"The world must be made safe for democracy\"", + "Answer": "Woodrow Wilson" + }, + { + "Category": "RHYMES WITH TEEN", + "Question": "Jack Sprat's wife couldn't eat any", + "Answer": "Lean" + }, + { + "Category": "THE 50 STATES", + "Question": "The atomic age began with a blast on July 16, 1945 in this state", + "Answer": "New Mexico" + }, + { + "Category": "HOW TO BE A BAD SPORT", + "Question": "If your opponent asks for the \"3s\" you really do have in your hand, tell him this, the name of the game", + "Answer": "Go fish" + }, + { + "Category": "BRAND NAMES", + "Question": "This cereal's name used to end in \"oats\" & its \"I\" is dotted with a piece of the product", + "Answer": "Cheerios" + }, + { + "Category": "THE 20th CENTURY", + "Question": "In January 1926 in London, John L. Baird demonstrated this new invention which used a cathode ray tube", + "Answer": "Television" + }, + { + "Category": "CLASSIC STAR TREK", + "Question": "Suave Ricardo Montalban played this sultry superhuman on the TV series & on the big screen", + "Answer": "Khan" + }, + { + "Category": "RHYMES WITH TEEN", + "Question": "\"Lois & Clark\" actor Cain", + "Answer": "Dean" + }, + { + "Category": "THE 50 STATES", + "Question": "2 of the 4 states officially called commonwealths", + "Answer": "Kentucky, Massachusetts, Pennsylvania, Virginia" + }, + { + "Category": "HOW TO BE A BAD SPORT", + "Question": "If you're cornered in Kamchatka, end this board game by bumping your opponent's armies off the board", + "Answer": "Risk" + }, + { + "Category": "BRAND NAMES", + "Question": "This VCR brand's name came from the Latin for \"great voice\"", + "Answer": "Magnavox" + }, + { + "Category": "THE 20th CENTURY", + "Question": "In 1992 this former Panamanian dictator was found guilty of drug trafficking by a Miami jury", + "Answer": "Manuel Noriega" + }, + { + "Category": "CLASSIC STAR TREK", + "Question": "Captain Kirk shares this name, his middle name, with a first century Roman emperor", + "Answer": "Tiberius" + }, + { + "Category": "RHYMES WITH TEEN", + "Question": "Noor, to her Jordanian subjects", + "Answer": "Queen" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "This method of preserving food by killing bacteria was developed by a French chemist in the 1860s", + "Answer": "Pasteurization" + }, + { + "Category": "COLLEGE FOOTBALL", + "Question": "This Dallas bowl game has been played at the same site consecutively longer than any other major bowl game", + "Answer": "Cotton Bowl" + }, + { + "Category": "TEENS OF THE PAST", + "Question": "In the 1870s this teenage outlaw was sometimes referred to as Kid Antrim", + "Answer": "Billy the Kid" + }, + { + "Category": "OPERA & BALLET", + "Question": "Choreographer Frederick Ashton played one of the ugly stepsisters when this ballet debuted in 1948", + "Answer": "Cinderella" + }, + { + "Category": "AUTHOR! AUTHOR!", + "Question": "\"Voyage of the Beagle\"", + "Answer": "Charles Darwin" + }, + { + "Category": "\"KNIFE\", \"FORK\" OR \"SPOON\"", + "Question": "A diver bends in midair to touch the toes before entering the water in this dive", + "Answer": "Jackknife" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "In 1906 she succeeded her husband as professor of physics at the Sorbonne", + "Answer": "Marie Curie" + }, + { + "Category": "COLLEGE FOOTBALL", + "Question": "In the 1999 Fiesta Bowl, quarterback Tee Martin led this school to the national title by defeating Florida State, 23-16", + "Answer": "Tennessee" + }, + { + "Category": "TEENS OF THE PAST", + "Question": "She was a teenager when she married Ferdinand in 1469", + "Answer": "Isabella" + }, + { + "Category": "OPERA & BALLET", + "Question": "Though a tenor now, Placido Domingo began singing in this vocal range below tenor", + "Answer": "Baritone" + }, + { + "Category": "AUTHOR! AUTHOR!", + "Question": "\"This Side of Paradise\"", + "Answer": "F. Scott Fitzgerald" + }, + { + "Category": "\"KNIFE\", \"FORK\" OR \"SPOON\"", + "Question": "Blushing crow for crushing blow, for example", + "Answer": "Spoonerism" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "The \"master plan of all life\", it consists of thymine, adenine, guanine, cytosine, phosphate & deoxyribose", + "Answer": "DNA " + }, + { + "Category": "COLLEGE FOOTBALL", + "Question": "This Utah school's Ty Detmer holds the NCAA career record for yards passing with 15,031", + "Answer": "Brigham Young University" + }, + { + "Category": "TEENS OF THE PAST", + "Question": "In his teens in the 1860s this \"bright light\" of inventors worked as a roving telegraph operator", + "Answer": "Thomas Edison" + }, + { + "Category": "OPERA & BALLET", + "Question": "This composer of \"The Nutcracker\" said, \"The music of a ballet is not invariably bad\"", + "Answer": "Tchaikovsky" + }, + { + "Category": "AUTHOR! AUTHOR!", + "Question": "\"The Mayor of Casterbridge\"", + "Answer": "Thomas Hardy" + }, + { + "Category": "\"KNIFE\", \"FORK\" OR \"SPOON\"", + "Question": "It's a truck with a pronged platform at the front that raises & moves loads", + "Answer": "Forklift" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "Of the noble gases, it's first, alphabetically, was the first discovered & is the most abundant in air", + "Answer": "Argon" + }, + { + "Category": "TEENS OF THE PAST", + "Question": "\"At 15 I set my heart on learning\", wrote this great Asian sage in his \"Analects\"", + "Answer": "Confucius" + }, + { + "Category": "OPERA & BALLET", + "Question": "A governess fears that her charges are communicating with ghosts in an opera based on this Henry James novella", + "Answer": "The Turn of the Screw" + }, + { + "Category": "AUTHOR! AUTHOR!", + "Question": "\"The Day of the Locust\"", + "Answer": "Nathanael West" + }, + { + "Category": "\"KNIFE\", \"FORK\" OR \"SPOON\"", + "Question": "In the 1998 movie \"Pleasantville\", she played a '90s teen transported into a 1950s sitcom", + "Answer": "Reese Witherspoon" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "This tiny planet's thin atmosphere is mostly composed of helium & sodium thought to come from the solar wind", + "Answer": "Mercury" + }, + { + "Category": "TEENS OF THE PAST", + "Question": "As a teenaer this \"Great\" guy ruled Russia jointly with his sickly half-brother Ivan", + "Answer": "Peter the Great" + }, + { + "Category": "OPERA & BALLET", + "Question": "The ballet \"Les Sylphides\" is danced to music by this Polish-French composer", + "Answer": "Frederic Chopin" + }, + { + "Category": "AUTHOR! AUTHOR!", + "Question": "\"Northanger Abbey\"", + "Answer": "Jane Austen" + }, + { + "Category": "\"KNIFE\", \"FORK\" OR \"SPOON\"", + "Question": "Its nest is a platform of sticks in a low bush or tree", + "Answer": "Spoonbill" + }, + { + "Category": "THE PRESIDENCY", + "Question": "In 1998, the highest-ranking person in the line of presidential succession who could not legally be president", + "Answer": "Madeleine Albright" + }, + { + "Category": "GEORGE WASHINGTON", + "Question": "On December 26, 1799 Washington was eulogized in Congress by this man known as \"Lighthorse Harry\"", + "Answer": "Harry Lee" + }, + { + "Category": "NO. 1 ALBUMS", + "Question": "\"Imagine\"", + "Answer": "John Lennon" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "This son of a Jewish mother & a Greek father is also called Timotheus", + "Answer": "Timothy" + }, + { + "Category": "OLYMPIC POTPOURRI", + "Question": "En Garde! Women have competed in this Olympic sport since 1924", + "Answer": "Fencing" + }, + { + "Category": "FOREIGN CURRENCY", + "Question": "Malta's currency shares its name with this monetary unit of Italy", + "Answer": "Lira" + }, + { + "Category": "WORDS WITHIN WORDS", + "Question": "Color of your face when you've done something irredeemable", + "Answer": "Red" + }, + { + "Category": "GEORGE WASHINGTON", + "Question": "On May 28, 1754, Washington & his men fired the first shots of this 9-year war near Fort Duquesne", + "Answer": "The French & Indian War" + }, + { + "Category": "NO. 1 ALBUMS", + "Question": "\"Forever Your Girl\"", + "Answer": "Paula Abdul" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "In a letter to Corinth, Paul ranked this quality over faith & hope", + "Answer": "Charity" + }, + { + "Category": "OLYMPIC POTPOURRI", + "Question": "U.S. soccer star Mia Hamm led her team to Olympic gold despite straining this the same day Kerri Strug did", + "Answer": "Ankle" + }, + { + "Category": "FOREIGN CURRENCY", + "Question": "In 1946 the Communist government of Vietnam began issuing coins with a depiction of this man", + "Answer": "Ho Chi Minh" + }, + { + "Category": "WORDS WITHIN WORDS", + "Question": "Carry something luminescent when you go down into one of these", + "Answer": "Mine" + }, + { + "Category": "GEORGE WASHINGTON", + "Question": "On December 23,1776 Washington wrote that \"Our attempt on\" this city was fixed for \"Christmas Day or night\"", + "Answer": "Trenton" + }, + { + "Category": "NO. 1 ALBUMS", + "Question": "\"Hell Freezes Over\"", + "Answer": "The Eagles" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "In Gethsemane, this apostle drew a sword & cut off Malchus' ear", + "Answer": "Peter" + }, + { + "Category": "OLYMPIC POTPOURRI", + "Question": "Of fire-eating, live pigeon-shooting or water buffalo polo, the one that was a 1900 Olympic event", + "Answer": "Live pigeon-shooting" + }, + { + "Category": "FOREIGN CURRENCY", + "Question": "The name of this currency is from the Sanskrit for \"coined silver\"", + "Answer": "Rupee" + }, + { + "Category": "WORDS WITHIN WORDS", + "Question": "A 1,496-pound one was unfortunate enough to get caught in 1979", + "Answer": "Tuna" + }, + { + "Category": "GEORGE WASHINGTON", + "Question": "In July 1749, at age 17 George was appointed to this position for the county of Culpeper, Virginia", + "Answer": "Surveyor" + }, + { + "Category": "NO. 1 ALBUMS", + "Question": "\"Glass Houses\"", + "Answer": "Billy Joel" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "This apostle, the brother of James, is traditionally credited with writing a gospel", + "Answer": "John" + }, + { + "Category": "OLYMPIC POTPOURRI", + "Question": "The name of this equestrian event is French for \"training\"; it doesn't refer to a garment", + "Answer": "Dressage" + }, + { + "Category": "FOREIGN CURRENCY", + "Question": "A Philippine one-peso coin of 1947 depicted this American, calling him \"Defender and Liberator\"", + "Answer": "Douglas MacArthur" + }, + { + "Category": "WORDS WITHIN WORDS", + "Question": "This capital city could be the climax of your world tour", + "Answer": "Lima" + }, + { + "Category": "GEORGE WASHINGTON", + "Question": "Washington warned against \"The insidious wiles of foreign influences\" in this published declaration", + "Answer": "His Farewell Address" + }, + { + "Category": "NO. 1 ALBUMS", + "Question": "\"Bat Out Of Hell II: Back Into Hell\"", + "Answer": "Meat Loaf" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "In Revelation, it was the name of he who sat on a pale horse", + "Answer": "Death" + }, + { + "Category": "OLYMPIC POTPOURRI", + "Question": "(VIDEO DAILY DOUBLE): \"(Hi, I'm Mark McEwen) I reported on the '92 W. Olympics in Albertville, France & the '94 W. Olympics hosted by this Scandinavian city\"", + "Answer": "Lillehammer, Norway" + }, + { + "Category": "FOREIGN CURRENCY", + "Question": "Its currency, the guarani, shares its name with one of its national languages & an expensive Asuncion hotel", + "Answer": "Paraguay" + }, + { + "Category": "WORDS WITHIN WORDS", + "Question": "Type of literature often produced by oversensitive youths", + "Answer": "Verse" + }, + { + "Category": "BEING THOREAU", + "Question": "This book begins, \"When I wrote the following pages...I lived alone in the woods, a mile from any neighbor...\"", + "Answer": "Walden/ Life In The Woods" + }, + { + "Category": "OFF WITH THEIR HEADS!", + "Question": "The first wife of Henry VIII to get the axe", + "Answer": "Anne Boleyn" + }, + { + "Category": "ASIAN NATIONS", + "Question": "Once known as Burma, its official language Burmese was also renamed", + "Answer": "Myanmar" + }, + { + "Category": "DICE ROLL NICKNAMES", + "Question": "Snake Eyes", + "Answer": "2" + }, + { + "Category": "YOUNG WOMEN OF TODAY", + "Question": "Royal rapper seen on TV's \"Living Single\" & in the movie \"Living Out Loud\"", + "Answer": "Queen Latifah" + }, + { + "Category": "ACRONYM EXCITEMENT!", + "Question": "At the United Nations: WHO", + "Answer": "World Health Organization" + }, + { + "Category": "BEING THOREAU", + "Question": "Thoreau praised this man's actions at Harpers Ferry & eulogized him in 3 lectures", + "Answer": "John Brown" + }, + { + "Category": "OFF WITH THEIR HEADS!", + "Question": "1980's \"Death Of A Princess\" dramatized the execution of a princess from this country & her lover's beheading", + "Answer": "Saudi Arabia" + }, + { + "Category": "ASIAN NATIONS", + "Question": "A map of this country bears many Kualas; Kuala Dungun, Kuala Lumpur....", + "Answer": "Malaysia" + }, + { + "Category": "DICE ROLL NICKNAMES", + "Question": "Boxcars, or Hobo's Delight on a Rainy Night", + "Answer": "Sixes" + }, + { + "Category": "YOUNG WOMEN OF TODAY", + "Question": "Though her name means \"wolf\", this basketball star was another canine in college -- a U. Conn. Husky", + "Answer": "Rebecca Lobo" + }, + { + "Category": "ACRONYM EXCITEMENT!", + "Question": "For feminists: NOW", + "Answer": "National Organization for Women" + }, + { + "Category": "BEING THOREAU", + "Question": "A dedicated abolitionist, Thoreau was a \"conductor\" on this", + "Answer": "The Underground Railroad" + }, + { + "Category": "OFF WITH THEIR HEADS!", + "Question": "After Charles II was restored to England's throne, he had this lord protector's body dug up & beheaded", + "Answer": "Oliver Cromwell" + }, + { + "Category": "ASIAN NATIONS", + "Question": "Railways link this country's capital of Ulaanbaatar to Moscow & Peking", + "Answer": "Mongolia" + }, + { + "Category": "DICE ROLL NICKNAMES", + "Question": "Acey-Deucy", + "Answer": "1 & 2" + }, + { + "Category": "YOUNG WOMEN OF TODAY", + "Question": "She occupies the California congressional seat once held by her late entertainer husband", + "Answer": "Mary Bono" + }, + { + "Category": "ACRONYM EXCITEMENT!", + "Question": "In San Francisco: BART", + "Answer": "Bay Area Rapid Transit" + }, + { + "Category": "BEING THOREAU", + "Question": "Work that says, \"Under a gov't which imprisons any unjustly, the true place for a just man is also a prison\"", + "Answer": "Civil Disobedience" + }, + { + "Category": "OFF WITH THEIR HEADS!", + "Question": "This principal leader of the Reign of Terror faced the guillotine himself on July 28, 1794", + "Answer": "Robespierre" + }, + { + "Category": "ASIAN NATIONS", + "Question": "The Baath party rules these 2 Mideast countries", + "Answer": "Iraq & Syria" + }, + { + "Category": "DICE ROLL NICKNAMES", + "Question": "Ada from Decatur, or Square Pair", + "Answer": "Pair of 4's" + }, + { + "Category": "YOUNG WOMEN OF TODAY", + "Question": "Born in Monaco in 1965, she's 7 & 8 years younger than her siblings Caroline & Albert", + "Answer": "Princess Stephanie" + }, + { + "Category": "ACRONYM EXCITEMENT!", + "Question": "To Neil Armstrong: NASA", + "Answer": "National Aeronautics and Space Administration" + }, + { + "Category": "BEING THOREAU", + "Question": "While in New York in the 1840s, Thoreau met this newspaper editor, who then acted as his literary agent", + "Answer": "Horace Greeley" + }, + { + "Category": "OFF WITH THEIR HEADS!", + "Question": "The last wife of Henry VIII to get the axe", + "Answer": "Catherine Howard" + }, + { + "Category": "ASIAN NATIONS", + "Question": "The Druk Gyalpo, or Dragon King, rules this neighbor of India that has a dragon on its flag", + "Answer": "Bhutan" + }, + { + "Category": "DICE ROLL NICKNAMES", + "Question": "Texas Sunflowers", + "Answer": "Two 5's" + }, + { + "Category": "YOUNG WOMEN OF TODAY", + "Question": "In \"Jerry Maguire\", this actress told Tom Cruise, \"You had me at hello\"", + "Answer": "Renee Zellweger" + }, + { + "Category": "ACRONYM EXCITEMENT!", + "Question": "For cybergeeks: MS-DOS", + "Answer": "Microsoft - Disk Operating System" + }, + { + "Category": "WORLD CITIES", + "Question": "In May 1998 this metropolis of 7 million voted to start electing its mayor for the first time", + "Answer": "London" + }, + { + "Category": "IRAQNOPHOBIA", + "Question": "This Iraqi president attended Cairo Law School in 1962 & 1963 while in exile", + "Answer": "Saddam Hussein" + }, + { + "Category": "ORDINAL NUMBER, PLEASE", + "Question": "It's where Washington was in war, in peace & in the hearts of his countrymen", + "Answer": "First" + }, + { + "Category": "TELEVISION", + "Question": "In 1996 Larry Hagman, Patrick Duffy & other actors from this series reunited for a TV movie", + "Answer": "\"Dallas\"" + }, + { + "Category": "WHAT AILS YOU?", + "Question": "Nearly 90% of all malaria cases occur on this continent", + "Answer": "Africa" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "This state with the most people is home to the largest living tree", + "Answer": "California" + }, + { + "Category": "4-LETTER WORDS", + "Question": "This sound can be emitted by an auto horn or by a wild goose", + "Answer": "Honk" + }, + { + "Category": "IRAQNOPHOBIA", + "Question": "During the Gulf War, foreign journalists used this city's Al-Rashid Hotel as their base of operations", + "Answer": "Baghdad" + }, + { + "Category": "ORDINAL NUMBER, PLEASE", + "Question": "\"Nervous Breakdown\" the Rolling Stones suffered in the '60s", + "Answer": "Nineteenth" + }, + { + "Category": "TELEVISION", + "Question": "On a 1995 episode of this sitcom, JFK Jr. dropped by the offices of \"FYI\"", + "Answer": "\"Murphy Brown\"" + }, + { + "Category": "WHAT AILS YOU?", + "Question": "Scientists have reported that this tofu legume may lower cholesterol", + "Answer": "Soybean" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "With about 1,040 people per square mile of land, life in this most densely populated state is a real garden party", + "Answer": "New Jersey" + }, + { + "Category": "4-LETTER WORDS", + "Question": "From the Latin for \"kitchen\", you literally cook ceramics in one of these", + "Answer": "Kiln" + }, + { + "Category": "IRAQNOPHOBIA", + "Question": "The ancient Greeks gave the area between the Tigris & Euphrates this name, which means \"between rivers\"", + "Answer": "Mesopotamia" + }, + { + "Category": "ORDINAL NUMBER, PLEASE", + "Question": "Shakespeare's \"night\" to remember", + "Answer": "Twelfth" + }, + { + "Category": "TELEVISION", + "Question": "Carol Burnett & Carroll O'Connor have appeared as Jamie's parents on this sitcom", + "Answer": "\"Mad About You\"" + }, + { + "Category": "WHAT AILS YOU?", + "Question": "This clouding of the eye's lens is common in people over the age of 65", + "Answer": "Cataracts" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "This \"Beef State\" is No. 1 in commercial red meat & great northern beans", + "Answer": "Nebraska" + }, + { + "Category": "4-LETTER WORDS", + "Question": "During the American Revolution, this term referred to an American who favored the British side", + "Answer": "Tory" + }, + { + "Category": "IRAQNOPHOBIA", + "Question": "Living mostly \"whey\" up north, they are Iraq's largest ethnic minority", + "Answer": "Kurds" + }, + { + "Category": "ORDINAL NUMBER, PLEASE", + "Question": "(AUDIO DAILY DOUBLE): Street in the title of the following: (audio clue - instrumental)", + "Answer": "\"42nd Street\"" + }, + { + "Category": "TELEVISION", + "Question": "This British comedy troupe's \"Flying Circus\" landed on American TV in 1974", + "Answer": "Monty Python" + }, + { + "Category": "WHAT AILS YOU?", + "Question": "Outbreaks of this form of food poisoning are often the result of improper home canning", + "Answer": "Botulism" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "The nation's highest flat-top mountain, Grand Mesa, is in this state", + "Answer": "Colorado" + }, + { + "Category": "4-LETTER WORDS", + "Question": "\"Be not deceived; God is not mocked: for whatsoever a man soweth, that shall he also\" this", + "Answer": "Reap" + }, + { + "Category": "IRAQNOPHOBIA", + "Question": "The name of this Iraqi currency is derived from a Latin word for \"ten\"", + "Answer": "Dinar" + }, + { + "Category": "ORDINAL NUMBER, PLEASE", + "Question": "In \"The Music Man\", the penultimate trombonist in \"The Big Parade\"", + "Answer": "75th" + }, + { + "Category": "TELEVISION", + "Question": "\"Dragnet\"'s Jack Webb also developed this police series starring Martin Milner & Kent McCord", + "Answer": "\"Adam-12\"" + }, + { + "Category": "WHAT AILS YOU?", + "Question": "The cause of this disorder characterized by sudden sleep attacks is unknown", + "Answer": "Narcolepsy" + }, + { + "Category": "STATE SUPERLATIVES", + "Question": "The deepest gorge in the U.S. is this state's Hells Canyon", + "Answer": "Idaho" + }, + { + "Category": "4-LETTER WORDS", + "Question": "To incline, or to thrust a lance, perhaps at a windmill", + "Answer": "Tilt" + }, + { + "Category": "1957", + "Question": "On October 4 Russia launched this first satellite into space", + "Answer": "Sputnik" + }, + { + "Category": "REALLY BIG", + "Question": "You'll find the largest one in Mexico, not Egypt; its base covers nearly 45 acres", + "Answer": "Pyramid" + }, + { + "Category": "SHOES", + "Question": "This type of shoe has a slot in the strap across each vamp into which a coin can be inserted", + "Answer": "Pennyloafer" + }, + { + "Category": "POLITICIANS", + "Question": "Bill Clinton awarded this political rival the Presidential Medal of Freedom in 1997", + "Answer": "Bob Dole" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "It's based on the memoir \"Anna And The King Of Siam\"", + "Answer": "\"The King And I\"" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "Both England's King George V & FDR put their stamp of approval on this \"King of Hobbies\"", + "Answer": "Philately" + }, + { + "Category": "1957", + "Question": "When Wham-O introduced this toy in 1957, it was called the Pluto Platter", + "Answer": "Frisbee" + }, + { + "Category": "REALLY BIG", + "Question": "Longer than 2 football fields, it was launched at Friedrichshafen, Germany in 1936", + "Answer": "The Hindenburg" + }, + { + "Category": "SHOES", + "Question": "The lad who's the symbol of a line of Sherwin-Williams paints wears this type of shoes", + "Answer": "Wooden Shoes/Clogs" + }, + { + "Category": "POLITICIANS", + "Question": "Indiana's current governor, Frank L. O'Bannon, ran against Stephen Goldsmith, the mayor of this city", + "Answer": "Indianapolis" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "(VIDEO DAILY DOUBLE - here is a special guest with the clue): \"Hello, I'm Marla Maples Trump. In 1992 I made my Broadway debut in the musical about this humorist who never met a man he didn't like\"", + "Answer": "Will Rogers" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "For many years Andre Previn conducted one", + "Answer": "Philharmonic" + }, + { + "Category": "1957", + "Question": "As the Teamsters' vice president, he was indicted for bribery, conspiracy & obstruction of justice", + "Answer": "Jimmy Hoffa" + }, + { + "Category": "REALLY BIG", + "Question": "Growing over 20 feet, it's the largest predatory fish", + "Answer": "Great White Shark" + }, + { + "Category": "SHOES", + "Question": "These boots named for a British general became popular during the Napoleonic Wars", + "Answer": "Wellingtons" + }, + { + "Category": "POLITICIANS", + "Question": "Now a Tennessee senator, he appeared in the films \"Die Hard 2\" & \"The Hunt For Red October\"", + "Answer": "Fred Dalton Thompson" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "In January 1997 Liza Minnelli returned to Broadway, filling in for Julie Andrews in this musical", + "Answer": "Victor/Victoria" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "You beta know that this letter follows upsilon in the Greek alphabet", + "Answer": "Phi" + }, + { + "Category": "1957", + "Question": "He ended his brief retirement to become chairman & president of Occidental Petroleum", + "Answer": "Armand Hammer" + }, + { + "Category": "REALLY BIG", + "Question": "Greenland is more than 2 1/2 times the size of this next largest island", + "Answer": "New Guinea" + }, + { + "Category": "SHOES", + "Question": "Miranda, Spectator & D'Orsay are types of this slip-on women's shoe", + "Answer": "Pump" + }, + { + "Category": "POLITICIANS", + "Question": "This champion stock-car racer lost the 1996 race for North Carolina's Secretary of State", + "Answer": "Richard Petty" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "The rock opera \"Rent\" is a reworking of this Puccini opera, set in modern times", + "Answer": "\"La Boheme\"" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "This Olivia Newton-John recording spent 10 weeks at No. 1, the longest of any single in the 1980's", + "Answer": "\"Physical\"" + }, + { + "Category": "1957", + "Question": "The first explorer to fly over both poles, he passed away in March", + "Answer": "Admiral Richard Byrd" + }, + { + "Category": "REALLY BIG", + "Question": "With its supporting roots & trunks, a single one of these trees in India covers some 3 acres", + "Answer": "Banyan" + }, + { + "Category": "SHOES", + "Question": "This flat shoe normally has a cloth upper & a flexible rope sole", + "Answer": "Espadrilles" + }, + { + "Category": "POLITICIANS", + "Question": "In November 1996 Rep. Maxine Waters was elected chairwoman of this caucus", + "Answer": "Congressional Black Caucus" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "This Stephen Sondheim musical was based on the Ingmar Bergman film \"Smiles Of A Summer Night\"", + "Answer": "\"A Little Night Music\"" + }, + { + "Category": "\"PH\"UN WORDS", + "Question": "The name of this Egyptian island is Greek for \"Lighthouse\"", + "Answer": "Pharos" + }, + { + "Category": "19TH CENTURY FICTION", + "Question": "The 1853 novel \"Clotel, or The President's Daughter\" alleges that this man had an affair with a slave", + "Answer": "Thomas Jefferson" + }, + { + "Category": "ROCKS & MINERALS", + "Question": "Term for the minerals from which metals are extracted", + "Answer": "ore" + }, + { + "Category": "DOUBLE DOUBLE LETTERS", + "Question": "He raises & tends the honey kind", + "Answer": "beekeeper" + }, + { + "Category": "SHAKESPEARE", + "Question": "“Sweets to the sweet: Farewell!” were Hamlet's mother's words at this woman's funeral", + "Answer": "Ophelia" + }, + { + "Category": "MS.", + "Question": "Nancy Ross, Angela Davis, & Geraldine Ferraro all sought this office in 1984", + "Answer": "vice president" + }, + { + "Category": "SODA POP QUIZ", + "Question": "It's what gives soda pop the bubbles", + "Answer": "carbon dioxide" + }, + { + "Category": "ROCKS & MINERALS", + "Question": "Single-letter chemical designation of a diamond", + "Answer": "C" + }, + { + "Category": "DOUBLE DOUBLE LETTERS", + "Question": "On a sailor's chest it might say “Mother”; on Cher it's a butterfly", + "Answer": "tattoo" + }, + { + "Category": "HOLLYWOOD DOGS", + "Question": "Higgins played the title role of this 1974 film", + "Answer": "Benji" + }, + { + "Category": "SHAKESPEARE", + "Question": "Part of Cassius' anatomy Brutus calls “itching” when accusing him of greed", + "Answer": "palm" + }, + { + "Category": "MS.", + "Question": "Joan Benoit was 1st to win this Olympic event, finally offered for women in ‘84", + "Answer": "marathon" + }, + { + "Category": "SODA POP QUIZ", + "Question": "Caleb Bradham named his elixir this because it was supposed to relieve dyspepsia", + "Answer": "Pepsi Cola" + }, + { + "Category": "ROCKS & MINERALS", + "Question": "Largest block ever found of it in U.S., 56 tons, was used for Tomb of the Unknown Soldier", + "Answer": "marble" + }, + { + "Category": "DOUBLE DOUBLE LETTERS", + "Question": "[Audio DD] 1984 film which featured the following: (opening to Dancing in the Sheets by Shalamar)", + "Answer": "Footloose" + }, + { + "Category": "SHAKESPEARE", + "Question": "“Other women cloy the appetites they feed, but she makes hungry where most she satisfies”", + "Answer": "Cleopatra" + }, + { + "Category": "MS.", + "Question": "Kristine Holderied was 1st to graduate top in her class from 1 of these", + "Answer": "service academy" + }, + { + "Category": "SODA POP QUIZ", + "Question": "They spent $250,000 to develop a can so the shuttle crew could drink their new formula in space", + "Answer": "Coke" + }, + { + "Category": "ROCKS & MINERALS", + "Question": "Mark Twain defined it as a hole in the groud with a liar standing at the top", + "Answer": "mine" + }, + { + "Category": "DOUBLE DOUBLE LETTERS", + "Question": "Quality of ice, eels, & banana peels", + "Answer": "slipperiness" + }, + { + "Category": "SHAKESPEARE", + "Question": "Susanna & the twins, Hamnet & Judith", + "Answer": "Shakespeare's children" + }, + { + "Category": "SODA POP QUIZ", + "Question": "Fenton & Fowler''s calls this elite Detroit ginger ale the best soft drink in the world", + "Answer": "Vernor's" + }, + { + "Category": "ROCKS & MINERALS", + "Question": "Fizzing when acid is applied, this mineral is the base of the Portland cement industry", + "Answer": "limestone" + }, + { + "Category": "DOUBLE DOUBLE LETTERS", + "Question": "A tenant under lease", + "Answer": "lessee" + }, + { + "Category": "SHAKESPEARE", + "Question": "The lines “And thereby hangs a tale” & “All the world's a stage” come from this comedy", + "Answer": "As You Like It" + }, + { + "Category": "SODA POP QUIZ", + "Question": "It was originally called bib-label lithiated lemon-lime soda", + "Answer": "7-UP" + }, + { + "Category": "POLITICAL SLOGANS", + "Question": "“Hell no, we won't go” was a chant often heard at rallies against this war", + "Answer": "Vietnam War" + }, + { + "Category": "TREES", + "Question": "Arboreal symbol of strength", + "Answer": "oak" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "The pair's lyricist", + "Answer": "Hammerstein" + }, + { + "Category": "BRITISH HISTORY", + "Question": "They've been guarding British royalty since 1485 & gin bottles since 1820", + "Answer": "Beefeaters" + }, + { + "Category": "HOLIDAYS", + "Question": "October holiday which Mexicans call Dia de la Raza is celebrated in the U.S. as this", + "Answer": "Columbus Day" + }, + { + "Category": "“SAINTS”", + "Question": "A patron saint of Russia, he was probably skinny & never wore a red suit", + "Answer": "St. Nicholas" + }, + { + "Category": "POLITICAL SLOGANS", + "Question": "In the early 1930s Americans were told that it was “just around the corner”", + "Answer": "prosperity" + }, + { + "Category": "TREES", + "Question": "Of the Tree of Life, Tree of Knowledge, or the Tree of Righteousness, the 1 forbidden to Adam", + "Answer": "Knowledge" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "The “Times’” Brooks Atkinson called it “an original & beautiful excursion into... the Far East", + "Answer": "The King and I" + }, + { + "Category": "BRITISH HISTORY", + "Question": "Founder of the nursing profession, she was named after the city in which she was born", + "Answer": "Florence Nightingale" + }, + { + "Category": "HOLIDAYS", + "Question": "Meaning “removal of meat”, it's Rio's 4-day pre-Lenten festival", + "Answer": "Carnival" + }, + { + "Category": "“SAINTS”", + "Question": "At 5th & 50th, its Lady Chapel is the place to get married, if you're in NYC - & Catholic", + "Answer": "St. Patrick's Cathedral" + }, + { + "Category": "POLITICAL SLOGANS", + "Question": "He railed against the “do-nothing 80th congress” during his whistle-stop campaign", + "Answer": "Truman" + }, + { + "Category": "TREES", + "Question": "The cry “sap's a runnin’” refers to this tree", + "Answer": "maple tree" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "Their 1st professional collaboration was this 1943 landmark musical", + "Answer": "Oklahoma!" + }, + { + "Category": "BRITISH HISTORY", + "Question": "First Roman army to invade Britain was led by this general", + "Answer": "Caesar" + }, + { + "Category": "HOLIDAYS", + "Question": "O. Henry called it the most “purely American” holiday", + "Answer": "Thanksgiving" + }, + { + "Category": "“SAINTS”", + "Question": "“St. Elsewhere” is the nickname for this TV hospital", + "Answer": "St. Eligius" + }, + { + "Category": "POLITICAL SLOGANS", + "Question": "“Four more years of the full dinner pail” symbolized this president's re-election campaign in 1900", + "Answer": "McKinley" + }, + { + "Category": "TREES", + "Question": "Continent on which the densest, tallest & most valuable stand of timber is found", + "Answer": "North America" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "Character who is “corny as Kansas in August”", + "Answer": "Nellie Forbush" + }, + { + "Category": "BRITISH HISTORY", + "Question": "The penultimate Anglo-Saxon king, Edward was known by this pious title", + "Answer": "Edward the Confessor" + }, + { + "Category": "HOLIDAYS", + "Question": "Muslims fast during daylight hours for this entire month", + "Answer": "Ramadan" + }, + { + "Category": "“SAINTS”", + "Question": "Chorea, as in choreographer, is a condition associated with rheumatic fever formerly called this", + "Answer": "St. Vitus" + }, + { + "Category": "POLITICAL SLOGANS", + "Question": "In 1912, this pres. candidate declared, “We stand at Armageddon, & we battle for the Lord”", + "Answer": "Teddy Roosevelt" + }, + { + "Category": "TREES", + "Question": "Hindu for “trader” this unusual tree whose branches grow down can look like a mini-forest", + "Answer": "Banyan" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "Stuart Damon & Lesley Ann Warren starred in this only R & H musical written for TV", + "Answer": "Cinderella" + }, + { + "Category": "BRITISH HISTORY", + "Question": "Though it sounds like a grim volume, it's just William the Conqueror's survey of the British kingdom", + "Answer": "The Domesday Book" + }, + { + "Category": "HOLIDAYS", + "Question": "Until 1752, the 13 colonies observed Annunciation Day, the 25th of this month, as new year's", + "Answer": "March" + }, + { + "Category": "BIOLOGY", + "Question": "Of the 4, blood group of the universal recipient", + "Answer": "AB" + }, + { + "Category": "BOY MEETS WORLD", + "Question": "At 16 in 1785, this future first consul became head of his family & graduated from the Paris Military Academy", + "Answer": "Napoleon Bonaparte" + }, + { + "Category": "WHO'S THE BOSS", + "Question": "Kelly Garrett, Jill Munroe & Sabrina Duncan all went undercover for this mysterious boss", + "Answer": "Charlie Townsend" + }, + { + "Category": "SEAQUEST", + "Question": "This sea stretches from Beirut to Gibraltar", + "Answer": "Mediterranean Sea" + }, + { + "Category": "EVERYBODY LOVES RAY", + "Question": "This \"sweet\" boxer had fought just once in 5 years when he decisioned Marvin Hagler in 1987", + "Answer": "\"Sugar\" Ray Leonard" + }, + { + "Category": "MARRIED WITH CHILDREN", + "Question": "It can be an early harmonious period for a president, or a married couple can take a \"second\" one without the kids", + "Answer": "Honeymoon" + }, + { + "Category": "PARTY OF \"FIVE\"", + "Question": "After December 1944, it was Ike's rank", + "Answer": "Five-star general" + }, + { + "Category": "BOY MEETS WORLD", + "Question": "Around 1347 B.C. at the age of 9, his rule as pharaoh began", + "Answer": "King Tut" + }, + { + "Category": "WHO'S THE BOSS", + "Question": "Miss Jane Hathaway reluctantly schemed with this miserly banker", + "Answer": "Milburn Drysdale" + }, + { + "Category": "SEAQUEST", + "Question": "One of the traditional 7 seas, it shares its name with a Rodgers & Hammerstein musical", + "Answer": "South Pacific" + }, + { + "Category": "EVERYBODY LOVES RAY", + "Question": "This pulp author was past 50 when he wrote his first novel, \"The Big Sleep\"", + "Answer": "Raymond Chandler" + }, + { + "Category": "MARRIED WITH CHILDREN", + "Question": "Parents of infants must learn to deal with these, from the medieval Greek \"diaspros\", or \"pure white\"", + "Answer": "Diapers" + }, + { + "Category": "PARTY OF \"FIVE\"", + "Question": "Whether it happens in the afternoon or not, it's facial stubble", + "Answer": "Five o'clock shadow" + }, + { + "Category": "BOY MEETS WORLD", + "Question": "In 1923 the San Francisco Symphony hosted the debut of this 7-year-old American violin prodigy", + "Answer": "Yehudi Menuhin" + }, + { + "Category": "WHO'S THE BOSS", + "Question": "Tattoo labored for this man on \"Fantasy Island\"", + "Answer": "Mr. Roarke" + }, + { + "Category": "SEAQUEST", + "Question": "Moses \"Stretched his hand over\" it & it was sundered", + "Answer": "Red Sea" + }, + { + "Category": "EVERYBODY LOVES RAY", + "Question": "\"X-Ray\" is the 1994 \"Unauthorized Biography\" of this leader of the Kinks", + "Answer": "Ray Davies" + }, + { + "Category": "MARRIED WITH CHILDREN", + "Question": "Babies are in this \"mouthy\" stage according to psychoanalytic theory", + "Answer": "Oral stage" + }, + { + "Category": "PARTY OF \"FIVE\"", + "Question": "This type of \"discount\" is slang for shoplifting", + "Answer": "Five-finger discount" + }, + { + "Category": "BOY MEETS WORLD", + "Question": "Of 6, 10 or 14, the age of Michael Kearney in 1994 when he became the USA's youngest college graduate", + "Answer": "10" + }, + { + "Category": "WHO'S THE BOSS", + "Question": "On \"Bewitched\" Darrin Stephens worked his advertising magic for this partner of McMann", + "Answer": "Larry Tate" + }, + { + "Category": "SEAQUEST", + "Question": "WWI's important naval Battle of Jutland took place in this sea", + "Answer": "North Sea" + }, + { + "Category": "EVERYBODY LOVES RAY", + "Question": "\"Write if you get work\" was Ray Goulding's catchphrase as half of this duo", + "Answer": "Bob and Ray" + }, + { + "Category": "MARRIED WITH CHILDREN", + "Question": "Make sure all your children are immunized against this \"barnyard\" disease caused by Varicella-Zoster", + "Answer": "Chickenpox" + }, + { + "Category": "PARTY OF \"FIVE\"", + "Question": "Vice President Thomas Marshall said, \"What this country needs is a good\" one of these", + "Answer": "Five-cent cigar" + }, + { + "Category": "BOY MEETS WORLD", + "Question": "The last male in the Tudor line, he became king at age 9 upon the death of Henry VIII", + "Answer": "Edward VI" + }, + { + "Category": "WHO'S THE BOSS", + "Question": "Every week Danno Williams would \"Book 'Em\" for this boss", + "Answer": "Steve McGarrett" + }, + { + "Category": "SEAQUEST", + "Question": "Despite this name, it's really the world's largest lake", + "Answer": "Caspian Sea" + }, + { + "Category": "EVERYBODY LOVES RAY", + "Question": "25 years after \"The Lost Weekend\", he played Ryan O'Neal's dad in \"Love Story\"", + "Answer": "Ray Milland" + }, + { + "Category": "PARTY OF \"FIVE\"", + "Question": "Stalin launched the first of these in 1928", + "Answer": "Five Year Plan" + }, + { + "Category": "THE HAYES YEARS", + "Question": "On November 23, 1880 this \"Sunflower State\" became the first to prohibit in its constitution the sale of liquor", + "Answer": "Kansas" + }, + { + "Category": "THE FILM VAULT", + "Question": "It's the title nickname of the psychopath Al Pacino played in a 1983 film", + "Answer": "Scarface" + }, + { + "Category": "THAT'S MY LAW", + "Question": "Snell's Law governs the angle of refraction of this as it passes from one medium to another", + "Answer": "Light" + }, + { + "Category": "GOULASH", + "Question": "In 1957 child model Jim O'Neill was chosen to grace the cover of his \"Baby and Child Care Book\"", + "Answer": "Dr. Benjamin Spock" + }, + { + "Category": "19th CENTURY LITERATURE", + "Question": "William Wells Brown's \"Clotel; or, The President's Daughter\" is about the kids this man allegedly had with a slave", + "Answer": "Thomas Jefferson" + }, + { + "Category": "ACTORS' RHYME TIME", + "Question": "Michael J.'s containers", + "Answer": "Fox's boxes" + }, + { + "Category": "THE FILM VAULT", + "Question": "Sidney Poitier starred in the 1961 film version of this Lorraine Hansberry drama about a black Chicago family", + "Answer": "A Raisin in the Sun" + }, + { + "Category": "THAT'S MY LAW", + "Question": "Kepler's first law says that planetary orbits aren't circular but have this shape", + "Answer": "Elliptical" + }, + { + "Category": "GOULASH", + "Question": "At the Oscars in 1992, Billy Crystal said this \"City Slickers\" co-star was backstage on the Stairmaster", + "Answer": "Jack Palance" + }, + { + "Category": "19th CENTURY LITERATURE", + "Question": "He wrote \"The Bride Comes to Yellow Sky\", \"The Blue Hotel\" & \"The Red Badge of Courage\"", + "Answer": "Stephen Crane" + }, + { + "Category": "ACTORS' RHYME TIME", + "Question": "Cybill's large cats", + "Answer": "Shepherd's leopards" + }, + { + "Category": "THE HAYES YEARS", + "Question": "In early 1880 Wabash in this state became the first city to illuminate its streets by electricity", + "Answer": "Indiana" + }, + { + "Category": "THE FILM VAULT", + "Question": "As Chris, a middle-class kid, this actor saw war close up in the 1986 film \"Platoon\"", + "Answer": "Charlie Sheen" + }, + { + "Category": "THAT'S MY LAW", + "Question": "Gresham's Law, named for a 16th century financier, is usually stated as \"Bad\" this \"drives out good\"", + "Answer": "Money" + }, + { + "Category": "GOULASH", + "Question": "Beechwood & juniper branches are used to smoke Germany's Westphalian type of this meat", + "Answer": "Ham" + }, + { + "Category": "19th CENTURY LITERATURE", + "Question": "Edward Bellamy's 1888 book \"Looking Backward\" sends a man to this year & doesn't mention computer bugs", + "Answer": "2000" + }, + { + "Category": "ACTORS' RHYME TIME", + "Question": "Nolte's films", + "Answer": "Nick's flicks" + }, + { + "Category": "THE HAYES YEARS", + "Question": "During 1879 he perfected his photographic dry plate", + "Answer": "George Eastman" + }, + { + "Category": "THE FILM VAULT", + "Question": "An action star from the '30s to the '70s, this actor headlined \"The Fighting Seabees\" & \"Flying Tigers\"", + "Answer": "John Wayne" + }, + { + "Category": "THAT'S MY LAW", + "Question": "The Law of Independent Assortment is one of the laws of heredity named for this 19th C. Austrian monk", + "Answer": "Gregor Mendel" + }, + { + "Category": "GOULASH", + "Question": "The most effective way of treating pernicious anemia is through injections of this vitamin", + "Answer": "B12" + }, + { + "Category": "19th CENTURY LITERATURE", + "Question": "Ydgrun is a goddess worshipped by residents of this Samuel Butler country", + "Answer": "Erewhon" + }, + { + "Category": "ACTORS' RHYME TIME", + "Question": "Torn's witticisms", + "Answer": "Rip's quips" + }, + { + "Category": "THE HAYES YEARS", + "Question": "10 members of this secret society of Irish immigrant coal workers were hanged on June 21, 1877", + "Answer": "The Molly Maguires" + }, + { + "Category": "THE FILM VAULT", + "Question": "Stephen King not only wrote the script for this 1986 film about possessed machinery, he directed it", + "Answer": "Maximum Overdrive" + }, + { + "Category": "THAT'S MY LAW", + "Question": "Objects with this property, meaning they can be deformed & regain their shapes, are covered by Hooke's Law", + "Answer": "Elasticity" + }, + { + "Category": "GOULASH", + "Question": "This fourth state of matter can be made by heating a gas or applying an electric field to it", + "Answer": "Plasma" + }, + { + "Category": "19th CENTURY LITERATURE", + "Question": "Oscar Wilde wrote \"The Picture of Dorian Gray\" & he wrote \"The Portrait of A Lady\"", + "Answer": "Henry James" + }, + { + "Category": "ACTORS' RHYME TIME", + "Question": "Calista's collection of photos of actress June", + "Answer": "Flockhart's Lockharts" + }, + { + "Category": "SISTER CITIES", + "Question": "San Francisco, California is a sister city to this one in Italy", + "Answer": "Assisi" + }, + { + "Category": "TOP O' THE CHARTS", + "Question": "In 1978 their duet \"You're The One That I Want\" replaced another duet by Johnny Mathis & Deniece Williams at No. 1", + "Answer": "Olivia Newton-John & John Travolta" + }, + { + "Category": "ALSO A VEGAS CASINO", + "Question": "A popular brand of orange juice", + "Answer": "Tropicana" + }, + { + "Category": "YOUNG ABE LINCOLN", + "Question": "Abe gained the respect of local ruffians when he held his own against one of the Clary's Grove boys in this sport", + "Answer": "wrestling" + }, + { + "Category": "COMPANIES", + "Question": "This warehouse club has over 43 million members, some of them Gold Star, lugging home the big jars of mayo", + "Answer": "Costco" + }, + { + "Category": "A CONTRADICTION IN TERMS", + "Question": "We don't see what was so good about this 2-word term for the worldwide 1930s economic disaster", + "Answer": "the Great Depression" + }, + { + "Category": "TOP O' THE CHARTS", + "Question": "Her \"Control\" album produced 5 Top 5 singles, each in a different spot; \"When I Think Of You\" hit No. 1", + "Answer": "Janet Jackson" + }, + { + "Category": "ALSO A VEGAS CASINO", + "Question": "A 3.5-million-square-mile land area between the Atlantic Ocean & the Red Sea", + "Answer": "the Sahara" + }, + { + "Category": "YOUNG ABE LINCOLN", + "Question": "Among the books read by Lincoln as a youngster were \"Robinson Crusoe\", \"Aesop's Fables\", & Mason Weems' \"Life of\" this man", + "Answer": "Washington" + }, + { + "Category": "COMPANIES", + "Question": "This co. agreed in 1993 to lease the New Amsterdam Theatre, & the old Times Square of degradation & filth was history", + "Answer": "Disney" + }, + { + "Category": "A CONTRADICTION IN TERMS", + "Question": "Both pleasant & painful, as in a memory", + "Answer": "bittersweet" + }, + { + "Category": "THE ONION HEADLINES FROM THE YEAR 2056", + "Question": "\"Refugees Row\" this entire island \"to Miami\"", + "Answer": "Cuba" + }, + { + "Category": "TOP O' THE CHARTS", + "Question": "In 1977 this \"sleepy\" song became Fleetwood Mac's only No. 1 hit", + "Answer": "\"Dreams\"" + }, + { + "Category": "ALSO A VEGAS CASINO", + "Question": "A weapon removed from a stone", + "Answer": "Excalibur" + }, + { + "Category": "YOUNG ABE LINCOLN", + "Question": "On October 5, 1818 this mother of Lincoln & 2 of her relatives died of milk sickness", + "Answer": "Nancy Hanks" + }, + { + "Category": "COMPANIES", + "Question": "This chain with a month as its name has acquired stores like Kaufmann's in Pittsburgh & Robinson's in L.A.", + "Answer": "May Company" + }, + { + "Category": "A CONTRADICTION IN TERMS", + "Question": "Alliterative two-word term for action by one's own forces causing casualties to one's own troops", + "Answer": "friendly fire" + }, + { + "Category": "THE ONION HEADLINES FROM THE YEAR 2056", + "Question": "Boston rejoices as this team \"Lose(s) In 50th Straight Pennant Race; Fans Blame 'Curse of Jeter'\"", + "Answer": "the Yankees" + }, + { + "Category": "TOP O' THE CHARTS", + "Question": "Madonna's \"This Used To Be My Playground\" was sung over the closing credits of this 1992 film", + "Answer": "A League of Their Own" + }, + { + "Category": "ALSO A VEGAS CASINO", + "Question": "Stevenson's rousing tale from 1881", + "Answer": "Treasure Island" + }, + { + "Category": "YOUNG ABE LINCOLN", + "Question": "While serving in the Illinois legislature, Abe switched to this party of his political idol Henry Clay", + "Answer": "the Whigs" + }, + { + "Category": "COMPANIES", + "Question": "Orange & Rockland Utilities is a subsidiary of this company named for an inventor", + "Answer": "Consolidated Edison" + }, + { + "Category": "A CONTRADICTION IN TERMS", + "Question": "2-word term for something supposedly confidential but actually known quite generally", + "Answer": "an open secret" + }, + { + "Category": "THE ONION HEADLINES FROM THE YEAR 2056", + "Question": "This country \"Bombed Back into the Renaissance\"", + "Answer": "Italy" + }, + { + "Category": "TOP O' THE CHARTS", + "Question": "In 1991 this heartthrob took Percy Sledge's \"When A Man Loves A Woman\" back to the top spot", + "Answer": "Michael Bolton" + }, + { + "Category": "ALSO A VEGAS CASINO", + "Question": "A market town of Upper Egypt built on the ruins of Thebes", + "Answer": "Luxor" + }, + { + "Category": "YOUNG ABE LINCOLN", + "Question": "During his 80 days of military service in 1832, Abe attempted without success to track down this Sauk & Fox Indian chief", + "Answer": "Black Hawk" + }, + { + "Category": "COMPANIES", + "Question": "In 1959 Richard De Vos & Jay Van Andel founded this company that now has 3 million independent distributors", + "Answer": "Amway" + }, + { + "Category": "A CONTRADICTION IN TERMS", + "Question": "This computer language gets oxymoronic when it follows \"Advanced\"", + "Answer": "BASIC" + }, + { + "Category": "HITCHCOCK", + "Question": "Jessica Tandy finds a farmer dead, his eyes gouged out, in this 1963 thriller", + "Answer": "The Birds" + }, + { + "Category": "CHAD IS RAD", + "Question": "Chad's colonial overlord until independence in 1960", + "Answer": "France" + }, + { + "Category": "IT'S A \"SIN\"", + "Question": "It can mean to burn slightly, or to burn the ends of hair or cloth", + "Answer": "singe" + }, + { + "Category": "TAKE-OFFS", + "Question": "This late author's representatives sued over \"The Cat Not in the Hat\", a rhyming account of the O.J. Simpson trial", + "Answer": "Dr. Seuss" + }, + { + "Category": "LANDINGS", + "Question": "As its name suggests, the tipp toe approach procedure at SFO is meant to minimize this", + "Answer": "noise" + }, + { + "Category": "HITCHCOCK", + "Question": "Hitchcock made this film in 1934 & then remade it in 1956 with Doris Day & Jimmy Stewart", + "Answer": "The Man Who Knew Too Much" + }, + { + "Category": "CHAD IS RAD", + "Question": "In the 11th century the kings of Chad converted to this faith", + "Answer": "Islam" + }, + { + "Category": "IT'S A \"SIN\"", + "Question": "For more than 200 years, the annual Baltic Herring Market & Fair has been a big to-do in this world capital", + "Answer": "Helsinki" + }, + { + "Category": "TAKE-OFFS", + "Question": "\"Molvania: A Land Untouched by Modern Dentistry\" is a satirical type of this guide", + "Answer": "a travel guide" + }, + { + "Category": "LANDINGS", + "Question": "Runways are numbered by compass degrees without the last digit, so this is the highest number used", + "Answer": "36" + }, + { + "Category": "HITCHCOCK", + "Question": "Cary Grant admires Grace Kelly's big diamonds in this 1955 caper", + "Answer": "To Catch a Thief" + }, + { + "Category": "CHAD IS RAD", + "Question": "Refugees from the neighboring Darfur region of this country have fled into eastern Chad", + "Answer": "the Sudan" + }, + { + "Category": "IT'S A \"SIN\"", + "Question": "Carson Sink & the Great Salt Lake lie in the drainage area known as the Great this", + "Answer": "Basin" + }, + { + "Category": "TAKE-OFFS", + "Question": "\"The Ninety-Nine Guardsmen\", one of Bret Harte's \"condensed novels\", parodies this French tale", + "Answer": "The Three Musketeers" + }, + { + "Category": "LANDINGS", + "Question": "You land, not anchor, at this Phoenix airport, named by a board member from Scenic Airways", + "Answer": "Sky Harbor Airport" + }, + { + "Category": "HITCHCOCK", + "Question": "Cary Grant & Ingrid Bergman fall in love & ferret out Nazis in Brazil in this classic", + "Answer": "Notorious" + }, + { + "Category": "CHAD IS RAD", + "Question": "It's the country directly north of Chad", + "Answer": "Libya" + }, + { + "Category": "IT'S A \"SIN\"", + "Question": "Of Welsh extraction, Frank Lloyd Wright named his homes & fellowship after this early Welsh poet", + "Answer": "Taliesin" + }, + { + "Category": "TAKE-OFFS", + "Question": "Rafreaky the baboon & a 30-year-old Annie have appeared in this NYC theater spoof that debuted in 1982", + "Answer": "Forbidden Broadway" + }, + { + "Category": "HITCHCOCK", + "Question": "John Dall & Farley Granger strangle a college friend just for thrills in this, Hitch's first color film", + "Answer": "Rope" + }, + { + "Category": "CHAD IS RAD", + "Question": "The capital & largest city", + "Answer": "N'Djamena" + }, + { + "Category": "IT'S A \"SIN\"", + "Question": "As well as discovering a famous gap in Saturn's rings, he also discovered 4 of Saturn's moons", + "Answer": "Cassini" + }, + { + "Category": "TAKE-OFFS", + "Question": "\"Go for Barocco\" is a take-off of Balanchine by this hairy, all-male ballet troupe", + "Answer": "the Trockadero de Monte Carlo" + }, + { + "Category": "LANDINGS", + "Question": "The ILS, short for this, was first installed at Indianapolis in 1940", + "Answer": "the Instrument Landing System" + }, + { + "Category": "20th CENTURY NOVELS", + "Question": "Ironically, this 1953 science fiction book began appearing in a censored version in 1967", + "Answer": "Fahrenheit 451" + }, + { + "Category": "SHAKESPEARE", + "Question": "These lovers do \"with their death bury their parents' strife\"", + "Answer": "Romeo and Juliet" + }, + { + "Category": "PRINCETON", + "Question": "One of its 1st presidents, John Witherspoon, was the only clergyman to sign this document", + "Answer": "Declaration of Independence" + }, + { + "Category": "THE FUNNIES", + "Question": "This Johnny Hart strip features such characters as Thor, Peter, Wiley & Clumsy Carp", + "Answer": "B.C." + }, + { + "Category": "JUST DESSERTS", + "Question": "Unlike sherbet, sorbet never contains this dairy product", + "Answer": "milk" + }, + { + "Category": "FAMOUS LLOYDS", + "Question": "This Texas Democrat has represented his state in the U.S. Senate since 1971", + "Answer": "Lloyd Bentsen" + }, + { + "Category": "BRIDGES", + "Question": "This bridge spanning NYC's East River was designated a national historic landmark in 1964", + "Answer": "Brooklyn Bridge" + }, + { + "Category": "SHAKESPEARE", + "Question": "The play in which Emilia screams, \"The moor hath kill'd my mistress! Murder! Murder!\"", + "Answer": "Othello" + }, + { + "Category": "PRINCETON", + "Question": "Princeton was given its name in 1896, the year this future Princeton student & Jazz Age author was born", + "Answer": "Scott Fitzgerald" + }, + { + "Category": "THE FUNNIES", + "Question": "In 1941 a daughter named Cookie was born to this comic strip couple", + "Answer": "Blondie and Dagwood" + }, + { + "Category": "JUST DESSERTS", + "Question": "Perfect for dipping in wine or coffee, biscotti are twice-baked cookies from this country", + "Answer": "Italy" + }, + { + "Category": "FAMOUS LLOYDS", + "Question": "In 1980 this \"Evita\" composer won a Tony for Best Score & a Grammy for Best Cast Show Album", + "Answer": "Webber" + }, + { + "Category": "BRIDGES", + "Question": "This bridge in Venice connects the doge's palace with the old state prison", + "Answer": "Bridge of Sighs" + }, + { + "Category": "SHAKESPEARE", + "Question": "In Act I, Scene 1 of this play, a ghost appears to Barnardo, Marcellus & Horatio", + "Answer": "Hamlet" + }, + { + "Category": "PRINCETON", + "Question": "Of 1769, 1869 or 1969, the year Princeton began to admit women as undergraduates", + "Answer": "1969" + }, + { + "Category": "THE FUNNIES", + "Question": "\"The Flintsones\" have a dinosaur named Dino; this strip has a dinosaur named Dinny", + "Answer": "Alley Oop" + }, + { + "Category": "JUST DESSERTS", + "Question": "This thick liquid is the traditional sweetening in Indian pudding", + "Answer": "molasses" + }, + { + "Category": "FAMOUS LLOYDS", + "Question": "This British prime minister helped draft the Treaty of Versailles, which ended World War I", + "Answer": "Lloyd George" + }, + { + "Category": "BRIDGES", + "Question": "The 1st Roman bridge of which there is any record is the Pons Sublicius, built in 621 B.C. over this river", + "Answer": "Tiber" + }, + { + "Category": "SHAKESPEARE", + "Question": "In \"The Merchant of Venice\" he tells his friend Tubal, \"Meet me at our synagogue\"", + "Answer": "Shylock" + }, + { + "Category": "PRINCETON", + "Question": "In 1783 Princeton's Nassau Hall doubled as this for the nation", + "Answer": "capital" + }, + { + "Category": "THE FUNNIES", + "Question": "Jon is this cat's master; Odie is his dog friend", + "Answer": "Garfield" + }, + { + "Category": "JUST DESSERTS", + "Question": "A rich custard topped with caramelized sugar, its name means \"burnt cream\" in French", + "Answer": "crème brûlée" + }, + { + "Category": "FAMOUS LLOYDS", + "Question": "In 1832 this editor founded the New England Anti-Slavery Society", + "Answer": "William Lloyd Garrison" + }, + { + "Category": "BRIDGES", + "Question": "The Francis Scott Key Bridge crosses the Patapsco River in this city", + "Answer": "Baltimore" + }, + { + "Category": "SHAKESPEARE", + "Question": "In \"King Lear\", she poisons her sister Regan, then stabs herself", + "Answer": "Goneril" + }, + { + "Category": "PRINCETON", + "Question": "In 1974 this Princeton grad & PBS host wrote \"How to Make Money in Wall Street\"", + "Answer": "Louis Rukeyser" + }, + { + "Category": "THE FUNNIES", + "Question": "His Stars and Stripes cartoons featured the battle-weary GIs Willie & Joe", + "Answer": "Bill Mauldin" + }, + { + "Category": "JUST DESSERTS", + "Question": "Chef Josef Dobos is famous for creating this type of cake named for him", + "Answer": "torte" + }, + { + "Category": "FAMOUS LLOYDS", + "Question": "In 1953 he orginated the role of Captain Queeg in \"The Caine Mutiny Court-Martial\" on Broadway", + "Answer": "Lloyd Nolan" + }, + { + "Category": "BRIDGES", + "Question": "This Colorado canyon has the world's highest suspension bridge – 1,053' above the Arkansas River", + "Answer": "Royal Gorge" + }, + { + "Category": "THE 14th CENTURY", + "Question": "The carol notwithstanding, a king with this \"good\" name had St. John of Nepomuk killed in 1393", + "Answer": "Wenceslas" + }, + { + "Category": "OPERA SINGERS", + "Question": "This hefty ebullient tenor once taught elementary school in Modena, Italy, his birthplace", + "Answer": "Luciano Pavarotti" + }, + { + "Category": "LITERATURE", + "Question": "Ellen Glasgow, a native of this Virginia capital, set several novels there but called it \"Queenborough\"", + "Answer": "Richmond" + }, + { + "Category": "POLITICS", + "Question": "In 1967 Richard Hatcher became the 1st elected black mayor of this steel-producing Indiana city", + "Answer": "Gary" + }, + { + "Category": "ISLANDS", + "Question": "This largest island in the world also contains the northernmost land in the world", + "Answer": "Greenland" + }, + { + "Category": "PHYSICS", + "Question": "Sublimation is the direct change from solid to gas without passing through this stage", + "Answer": "liquid" + }, + { + "Category": "THE 14th CENTURY", + "Question": "Name given to the split in the Catholic church when rival popes were elected in 1378", + "Answer": "Great Schism" + }, + { + "Category": "OPERA SINGERS", + "Question": "This Spaniard starred in Franco Zeffirelli's film \"La Traviata\"", + "Answer": "Domingo" + }, + { + "Category": "LITERATURE", + "Question": "Title character who says, \"Why did you paint it? It will mock me some day — mock me horribly!\"", + "Answer": "Doran Gray" + }, + { + "Category": "POLITICS", + "Question": "At over 30 years, this West Virginian is currently the longest-serving Democrat in the U.S. Senate", + "Answer": "Byrd" + }, + { + "Category": "ISLANDS", + "Question": "Lewis with Harris is the most northerly of this \"Outer\" Scottish island group", + "Answer": "Outer Hebrides" + }, + { + "Category": "PHYSICS", + "Question": "Plano-convex, biconvex & concavo-convex are 3 of the types of this optical component", + "Answer": "lens" + }, + { + "Category": "THE 14th CENTURY", + "Question": "Claiming the French throne, England's Edward III invaded the continent in 1337, setting off this war", + "Answer": "100 Years War" + }, + { + "Category": "OPERA SINGERS", + "Question": "This Neapolitan tenor made his last public appearance on Christmas Eve, 1920 in \"La Juive\"", + "Answer": "Caruso" + }, + { + "Category": "LITERATURE", + "Question": "She wrote in \"Emma\", \"One half of the world cannot understand the pleasures of the other\"", + "Answer": "Jane Austen" + }, + { + "Category": "POLITICS", + "Question": "During his record 11 years as FDR's Sec'y of State, this Tennessean conceived the idea of the United Nations", + "Answer": "Hull" + }, + { + "Category": "ISLANDS", + "Question": "This Indonesian island became world famous after giant lizards were discovered there in 1912", + "Answer": "Komodo" + }, + { + "Category": "PHYSICS", + "Question": "This field is the study of the properties & production of sound", + "Answer": "acoustics" + }, + { + "Category": "THE 14th CENTURY", + "Question": "Chaucer wrote a treatise on how to build one of these & use it to compute the position of a star", + "Answer": "astrolabe" + }, + { + "Category": "OPERA SINGERS", + "Question": "In 1971 this part-Maori diva had her first Covent Garden triumph in \"The Marriage of Figaro\"", + "Answer": "Kiri Te Kanawa" + }, + { + "Category": "LITERATURE", + "Question": "This \"Madame Bovary\" author visited Tunisia to research \"Salammbo\", his novel about Carthage", + "Answer": "Flaubert" + }, + { + "Category": "POLITICS", + "Question": "In December 1985 Cognress passed this bill in an effort to end the federal deficit", + "Answer": "Gramm-Rudman" + }, + { + "Category": "ISLANDS", + "Question": "Singapore seceded from this country in 1965", + "Answer": "Malaysia" + }, + { + "Category": "PHYSICS", + "Question": "The farad, the unit of capacitance, is named for this scientist", + "Answer": "Faraday" + }, + { + "Category": "THE 14th CENTURY", + "Question": "In the 1350s this Moorish palace was completed in Granada, Spain", + "Answer": "Alhambra" + }, + { + "Category": "OPERA SINGERS", + "Question": "Late, great Russian who wrote the autobiographic books \"Pages from My Life\" & \"Man and Mask\"", + "Answer": "Chaliapin" + }, + { + "Category": "LITERATURE", + "Question": "\"Eugenie Grandet\" is considered one of the finest novels in his series \"La Comedie Humaine\"", + "Answer": "Balzac" + }, + { + "Category": "POLITICS", + "Question": "When he ran for president in 1884, the Democrats called him the \"Continental Liar From the State of Maine\"", + "Answer": "James G. Blaine" + }, + { + "Category": "ISLANDS", + "Question": "The Court of Tynwald is the chief legislative body of this island in the Irish Sea", + "Answer": "Isle of Man" + }, + { + "Category": "PHYSICS", + "Question": "Deuterium is a heavy isotope of this element", + "Answer": "hydrogen" + }, + { + "Category": "AFRICAN AMERICANS", + "Question": "In 1978 she became the first black woman honored on a U.S. postage stamp", + "Answer": "Harriet Tubman" + }, + { + "Category": "WORLD HODGEPODGE", + "Question": "Pato, a combination of basketball & this game played on horseback, is quite popular in Argentina", + "Answer": "Polo" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "The November 25, 1963 front page read, this man \"Shot To Death In Jail Corridor By A Dallas Citizen\"", + "Answer": "Lee Harvey Oswald" + }, + { + "Category": "ENGINEERING", + "Question": "Tajikistan has the highest one of these in the world; the U.S. doesn't even make the Top 10 with Hoover", + "Answer": "Dam" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Marion Morrison", + "Answer": "John Wayne" + }, + { + "Category": "THE LAST MAN", + "Question": "In the 1996 book \"The Presidents: A Reference History\"", + "Answer": "Bill Clinton" + }, + { + "Category": "\"TRI\" HARDER", + "Question": "The French flag", + "Answer": "Tricolor" + }, + { + "Category": "WORLD HODGEPODGE", + "Question": "From the old French for \"ice\", these cover about 1/8 of Iceland; some are 3/4 of a mile thick", + "Answer": "Glaciers" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "The revelation of \"Undreamed Of Splendors\" was reported with the 1923 opening of his inner tomb", + "Answer": "King Tut" + }, + { + "Category": "ENGINEERING", + "Question": "The longest trip by rail you can take underwater is between these 2 countries", + "Answer": "England and France" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Raquel Tejada", + "Answer": "Raquel Welch" + }, + { + "Category": "THE LAST MAN", + "Question": "In \"Asimov's Biographical Encyclopedia of Science & Technology\" is this \"Cosmos\" astronomer", + "Answer": "Carl Sagan" + }, + { + "Category": "\"TRI\" HARDER", + "Question": "The ironman category for this sport includes a 2.4 mile swim, a 112-mile bike race & a marathon run", + "Answer": "Triathlon" + }, + { + "Category": "WORLD HODGEPODGE", + "Question": "Jorge Icaza, who was born in Quito, was one of this country's most famous 20th century authors", + "Answer": "Ecuador" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "On Sept. 9, 1974 news fit to print included the pardon of this man & \"Knievel Safe As Rocket Falls\"", + "Answer": "Richard Nixon" + }, + { + "Category": "ENGINEERING", + "Question": "Able to carry over 2 million barrels of crude a day, it runs from Prudhoe Bay to Valdez", + "Answer": "the Alaska Pipeline" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Archibald Leach", + "Answer": "Cary Grant" + }, + { + "Category": "THE LAST MAN", + "Question": "In \"Bartlett's Familiar Quotations\", he's paired with Michael Jackson for writing \"We Are The World\"", + "Answer": "Lionel Richie" + }, + { + "Category": "\"TRI\" HARDER", + "Question": "A court of justice", + "Answer": "Trribunal" + }, + { + "Category": "WORLD HODGEPODGE", + "Question": "On Dutch maps, this country is called Oostenrijk", + "Answer": "Austria" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "The 1945 headline \"Bomber Hits\" this skyscraper meant a plane, not a person", + "Answer": "Empire State Building" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Charles Buchinsky", + "Answer": "Charles Bronson" + }, + { + "Category": "THE LAST MAN", + "Question": "In the \"Book Of Sports Legends\" is this man who threw the first pitch in a World Series game", + "Answer": "Cy Young" + }, + { + "Category": "\"TRI\" HARDER", + "Question": "Collective name of Julius Caesar, Pompey the Great & Marcus Licinius Crassus", + "Answer": "Triumverate" + }, + { + "Category": "WORLD HODGEPODGE", + "Question": "When shopping on Saba, an island in this sea, look for the beautiful, delicate Saba lace", + "Answer": "Caribbean Sea" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "\"Berlin Reported Him Missing And Insane\" when he \"Flies To Scotland\" in May 1941", + "Answer": "Rudolf Hess" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Margarita Cansino", + "Answer": "Rita Hayworth" + }, + { + "Category": "THE LAST MAN", + "Question": "In \"The Almanac of Famous People\" is this \"Father of Television\"", + "Answer": "Vladimir Zworykin" + }, + { + "Category": "\"TRI\" HARDER", + "Question": "Bet in which the bettor must correctly choose the first 3 finishers in a horse race in exact order", + "Answer": "Trifecta" + }, + { + "Category": "HISTORIC QUOTES", + "Question": "Upon this man's assassination, Nehru said, \"The light has gone out of our lives\"", + "Answer": "Mahatma Gandhi" + }, + { + "Category": "DRAMA", + "Question": "In a 1997 play Stacie Chaiken starred as Constance, wife of this \"Earnest\" author", + "Answer": "Oscar Wilde" + }, + { + "Category": "LOBBYISTS", + "Question": "In the late '70s, Phyllis Schlafly lobbied for the defeat of this proposed constitutional amendment", + "Answer": "the ERA" + }, + { + "Category": "A PRAIRIE PRIMER", + "Question": "The largest cities in Canada's \"Prairie Provinces\" are Edmonton & Calgary in this one", + "Answer": "Alberta" + }, + { + "Category": "FRANCES FARMER", + "Question": "Actor Leif Erickson was Frances' first of 3 of these", + "Answer": "husbands" + }, + { + "Category": "FEELING POSSESSIVE", + "Question": "In a 1981 hit song, Rick Springfield wished that he had her", + "Answer": "\"Jessie's Girl\"" + }, + { + "Category": "HISTORIC QUOTES", + "Question": "When asked how he became a hero, this president replied, \"It was involuntary. They sank my boat\"", + "Answer": "John F. Kennedy" + }, + { + "Category": "DRAMA", + "Question": "\"Dejavu\" was \"Angry Young Man\" John Osborne's 1992 sequel to this famous play about looking back", + "Answer": "Look Back in Anger" + }, + { + "Category": "LOBBYISTS", + "Question": "She gave up Gary Hart & \"Monkey Business\" & became a spokesperson for \"Enough Is Enough\"", + "Answer": "Donna Rice" + }, + { + "Category": "FRANCES FARMER", + "Question": "She earned an Oscar nomination for playing Frances", + "Answer": "Jessica Lange" + }, + { + "Category": "FEELING POSSESSIVE", + "Question": "Jason Robards played editor Ben Bradlee in this 1976 film", + "Answer": "All the President's Men" + }, + { + "Category": "HISTORIC QUOTES", + "Question": "In 1830 Daniel Webster told the Senate, \"Liberty and\" this, \"now and forever, one and inseparable\"", + "Answer": "Union" + }, + { + "Category": "DRAMA", + "Question": "Shakespeare's 2 greatest contemporaries: one was murdered in 1593 & one killed a man in 1598", + "Answer": "Christopher Marlowe & Ben Jonson" + }, + { + "Category": "LOBBYISTS", + "Question": "After his forced resignation from the Senate in 1995, he took an interest in lumber & other natural resources", + "Answer": "Bob Packwood" + }, + { + "Category": "FRANCES FARMER", + "Question": "In \"Badlands of Dakota\" Frances was this Wild West lady to Richard Dix's Wild Bill", + "Answer": "Calamity Jane" + }, + { + "Category": "HISTORIC QUOTES", + "Question": "In 1862 Otto von Bismarck said that the questions of the day would be settled by this \"and blood\"", + "Answer": "iron" + }, + { + "Category": "DRAMA", + "Question": "Robert Bolt depicted Elizabeth I in \"Vivat! Vivat Regina!\" & Henry VIII in this play", + "Answer": "A Man for All Seasons" + }, + { + "Category": "LOBBYISTS", + "Question": "In 1997 Jack Williams of this company was indicted for lying about his dealings with Mike Espy", + "Answer": "Tyson Foods" + }, + { + "Category": "FRANCES FARMER", + "Question": "In college an essay Frances wrote for a radical newspaper won her a trip to this country", + "Answer": "the Soviet Union" + }, + { + "Category": "HISTORIC QUOTES", + "Question": "In 1973 he warned Nixon, \"We have a cancer within, close to the presidency, that is growing\"", + "Answer": "John Dean" + }, + { + "Category": "DRAMA", + "Question": "\"Romanoff and Juliet\" is one of many plays by this actor-writer of Russian descent", + "Answer": "Peter Ustinov" + }, + { + "Category": "LOBBYISTS", + "Question": "Victor Crawford lobbied for, then against, this industry before his death from cancer", + "Answer": "the tobacco industry" + }, + { + "Category": "FRANCES FARMER", + "Question": "In 1958 this TV host said, \"Frances Farmer, This Is Your Life!\"", + "Answer": "Ralph Edwards" + }, + { + "Category": "FEELING POSSESSIVE", + "Question": "In literature, gamekeeper Oliver Mellors", + "Answer": "Lady Chatterley's Lover" + }, + { + "Category": "TV CHARACTERS", + "Question": "Dozens of web sites are devoted to picking on this Sheryl Leach creation who only gives love", + "Answer": "Barney" + }, + { + "Category": "THE AUTO MAN EMPIRE", + "Question": "He had a good year in 1928; construction began on the NYC art deco building named for him & he acquired Dodge", + "Answer": "Walter Chrysler" + }, + { + "Category": "THE FILM THAT ALMOST WAS", + "Question": "Committed to TV, Tom Selleck had to turn down this role in \"Raiders of the Lost Ark\" (curse you, Hawaiian shirt!)", + "Answer": "Indiana Jones" + }, + { + "Category": "SPACE MISSIONS", + "Question": "In 2008 the Phoenix Mars lander found ice on this region of the planet", + "Answer": "the poles" + }, + { + "Category": "BUSY AS A BEAVER", + "Question": "Gee, Wally, this classic TV show premiered on October 4, 1957", + "Answer": "Leave It to Beaver" + }, + { + "Category": "DECADES OF BESTSELLERS", + "Question": "\"The Nanny Diaries\" & \"Q is for Quarry\"", + "Answer": "the 2000s" + }, + { + "Category": "SKIP TO MY \"LOO\"", + "Question": "An old gold coin equal to 2 pistoles", + "Answer": "a doubloon" + }, + { + "Category": "THE AUTO MAN EMPIRE", + "Question": "This Frenchman was the designer for the company that bore his name, GM's largest division", + "Answer": "Chevrolet" + }, + { + "Category": "THE FILM THAT ALMOST WAS", + "Question": "E.T. would have followed a trail of this candy, but the Mars company said no; not even the red ones", + "Answer": "M&Ms" + }, + { + "Category": "SPACE MISSIONS", + "Question": "The New Horizons mission was launched to explore this planet before it was downgraded to a dwarf", + "Answer": "Pluto" + }, + { + "Category": "BUSY AS A BEAVER", + "Question": "One of the 2 U.S. states with the beaver as the state animal: one's on the west coast & one's on the east", + "Answer": "Oregon" + }, + { + "Category": "DECADES OF BESTSELLERS", + "Question": "\"The Godfather\" & \"Airport\"", + "Answer": "the '60s" + }, + { + "Category": "SKIP TO MY \"LOO\"", + "Question": "5-letter word for \"remote in manner\"", + "Answer": "aloof" + }, + { + "Category": "THE AUTO MAN EMPIRE", + "Question": "In 1932 this auto racer began using the squadron badge of a WWI flying ace: a prancing horse", + "Answer": "Ferrari" + }, + { + "Category": "THE FILM THAT ALMOST WAS", + "Question": "Nicole Kidman dropped out of playing Brad Pitt's wife in this film; you may have heard Angelina Jolie got the part", + "Answer": "Mr. & Mrs. Smith" + }, + { + "Category": "SPACE MISSIONS", + "Question": "The Hinode mission showed magnetic waves are critical in driving the flow of charged particles called this wind", + "Answer": "the solar wind" + }, + { + "Category": "BUSY AS A BEAVER", + "Question": "Grey Beaver is the first master of this Jack London wolf-dog", + "Answer": "White Fang" + }, + { + "Category": "DECADES OF BESTSELLERS", + "Question": "\"The Power of Positive Thinking\" & \"Marjorie Morningstar\"", + "Answer": "the 1950s" + }, + { + "Category": "SKIP TO MY \"LOO\"", + "Question": "A sailing vessel with a single mast", + "Answer": "a sloop" + }, + { + "Category": "THE FILM THAT ALMOST WAS", + "Question": "Will Smith turned down the lead in this futuristic 1999 flick, later saying of it, \"Keanu was brilliant\"", + "Answer": "The Matrix" + }, + { + "Category": "SPACE MISSIONS", + "Question": "The Cassini project is exploring Titan & Enceladus, moons of this second-largest planet", + "Answer": "Saturn" + }, + { + "Category": "BUSY AS A BEAVER", + "Question": "As a boy Joe Namath had a dam good time growing up strong in this Pennsylvania city", + "Answer": "Beaver Falls" + }, + { + "Category": "DECADES OF BESTSELLERS", + "Question": "\"The Yearling\" & \"Of Mice and Men\"", + "Answer": "the 1930s" + }, + { + "Category": "SKIP TO MY \"LOO\"", + "Question": "Unsecured pages of a book in removable form", + "Answer": "looseleaf" + }, + { + "Category": "THE AUTO MAN EMPIRE", + "Question": "James Sumner & Henry Spurrier founded the company that became \"British\" this, owner of Jaguar", + "Answer": "British Leyland" + }, + { + "Category": "THE FILM THAT ALMOST WAS", + "Question": "Eddie Murphy got the role in this '84 police comedy after Sylvester Stallone dropped out", + "Answer": "Beverly Hills Cop" + }, + { + "Category": "SPACE MISSIONS", + "Question": "The MESSENGER craft is the first mission to explore this planet since mariner 10 in the 1970s", + "Answer": "Mercury" + }, + { + "Category": "BUSY AS A BEAVER", + "Question": "\"The Beaver's Lesson\" is the title of part 5 of this author's \"The Hunting of the Snark\"", + "Answer": "Lewis Carroll" + }, + { + "Category": "DECADES OF BESTSELLERS", + "Question": "\"The Mammoth Hunters\" & \"The Queen of the Damned\"", + "Answer": "the 1980s" + }, + { + "Category": "SKIP TO MY \"LOO\"", + "Question": "Chinese city opposite Hong Kong island", + "Answer": "Kowloon" + }, + { + "Category": "THE OTTOMAN EMPIRE", + "Question": "In 1566 this \"Magnificent\" sultan was succeeded by his not-so-magnificent son Selim II, \"the Sot\"", + "Answer": "Suleyman" + }, + { + "Category": "MUSICAL PRIME NUMBERS", + "Question": "Prince: \"2000 zero zero party over, oops, out of time, so tonight I'm gonna party like it's ____\"", + "Answer": "1999" + }, + { + "Category": "PHILOSOPHY GLOSSARY", + "Question": "Camus & Buber were big in this movement that said humans were fully responsible for making meaning of their own lives", + "Answer": "existentialism" + }, + { + "Category": "EDIBLES INSTANT REPLAY REVIEW", + "Question": "After review, the bierwurst, lop chong & kielbasa, types of these, were overcooked", + "Answer": "sausage" + }, + { + "Category": "X MARKS THE SPOT", + "Question": "Southwest of Louisville, it's where you'll find much of the U.S. government's gold reserve", + "Answer": "Fort Knox" + }, + { + "Category": "AskOxford.com", + "Question": "Put this 3-letter Latin word meaning \"thus\" or \"so\" right after the error in a quoted passage", + "Answer": "sic" + }, + { + "Category": "MUSICAL PRIME NUMBERS", + "Question": "ABBA: \"You are the dancing queen, young & sweet, only ____\"", + "Answer": "17" + }, + { + "Category": "PHILOSOPHY GLOSSARY", + "Question": "The name of this study of moral principles is derived from a Greek word meaning \"habit\"", + "Answer": "ethics" + }, + { + "Category": "EDIBLES INSTANT REPLAY REVIEW", + "Question": "This notoriously smelly cheese whose last U.S. maker is in Monroe, Wisconsin was fumbled on aisle 3", + "Answer": "Limburger" + }, + { + "Category": "X MARKS THE SPOT", + "Question": "The only Benelux country that fits the bill", + "Answer": "Luxembourg" + }, + { + "Category": "AskOxford.com", + "Question": "AskOxford.com says the most commonly cited collective term for these animals is a clowder", + "Answer": "cats" + }, + { + "Category": "THE OTTOMAN EMPIRE", + "Question": "The Ottoman empire ended in 1922 when this man led a movement that established the Republic of Turkey", + "Answer": "Kemal" + }, + { + "Category": "MUSICAL PRIME NUMBERS", + "Question": "Counting Crows: \"In 1492 Columbus sailed the ocean blue, in ____ he came home across the deep blue sea\"", + "Answer": "1493" + }, + { + "Category": "PHILOSOPHY GLOSSARY", + "Question": "This philosophical movement holds that the truth value of a proposition lies in its practicality", + "Answer": "pragmatism" + }, + { + "Category": "EDIBLES INSTANT REPLAY REVIEW", + "Question": "This rich 5-letter cake with eggs, ground nuts & little to no flour, is down by contact with my stomach", + "Answer": "torte" + }, + { + "Category": "X MARKS THE SPOT", + "Question": "The harbor of this Nova Scotia capital is one of the largest in the world", + "Answer": "Halifax" + }, + { + "Category": "AskOxford.com", + "Question": "Brits don't like this name for a phone keypad symbol--reminds them of a unit of currency that has another symbol", + "Answer": "pound" + }, + { + "Category": "THE OTTOMAN EMPIRE", + "Question": "In 1326 the Ottomans moved their capital to Bursa, which is in this Asian part of modern-day Turkey", + "Answer": "Anatolia" + }, + { + "Category": "MUSICAL PRIME NUMBERS", + "Question": "Foreigner: \"Well I'm hot blooded, check it and see, got a fever of ____\"", + "Answer": "103" + }, + { + "Category": "PHILOSOPHY GLOSSARY", + "Question": "Founded by Zeno of Citium, this -ism is the belief that detachment & self-control enable one to argue in an unbiased fashion", + "Answer": "stoicism" + }, + { + "Category": "X MARKS THE SPOT", + "Question": "This city on the Salt River sits on the eastern edge of the Sonoran Desert", + "Answer": "Phoenix" + }, + { + "Category": "AskOxford.com", + "Question": "This 2-letter abbreviation means \"which see\" in Latin & directs readers to another part of the book for info", + "Answer": "q.v." + }, + { + "Category": "THE OTTOMAN EMPIRE", + "Question": "Between 1656 & 1735 members of the Albanian Koprulu family served the sultan as this \"grand\" executive officer", + "Answer": "vizier" + }, + { + "Category": "MUSICAL PRIME NUMBERS", + "Question": "Blink-182: \"That's about the time she walked away from me, nobody likes you when you're ___\"", + "Answer": "23" + }, + { + "Category": "PHILOSOPHY GLOSSARY", + "Question": "\"Every virtue is laudable. Kindness is a virtue. Therefore, kindness is laudable\" is a logical this", + "Answer": "syllogism" + }, + { + "Category": "EDIBLES INSTANT REPLAY REVIEW", + "Question": "Upon review, this \"circular\" cut of meat from below the rump was too gristly", + "Answer": "the round" + }, + { + "Category": "X MARKS THE SPOT", + "Question": "The first winter Olympics took place in this French mountain resort", + "Answer": "Chamonix" + }, + { + "Category": "AskOxford.com", + "Question": "AskOxford.com tells us that this word is the missing one in the sequence primary, secondary... quaternary", + "Answer": "tertiary" + }, + { + "Category": "SAINTHOOD", + "Question": "In 2009 this man who died on Molokai in 1889 became Hawaii's first saint", + "Answer": "Father Damien" + }, + { + "Category": "DANGER IN WONDERLAND", + "Question": "Distinct alabaster fur; you'll know him by the big pocket watch he refers to; careful--he moves quickly", + "Answer": "the White Rabbit" + }, + { + "Category": "THAT'S HANDY", + "Question": "The hand gesture with 2 pairs of fingers bunched together was made by this Vulcan on the original \"Star Trek\"", + "Answer": "Mr. Spock" + }, + { + "Category": "SPOILER ALERT!", + "Question": "1968: The Statue of Liberty sticks up out of the sand", + "Answer": "Planet of the Apes" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "Argentina", + "Answer": "Spanish" + }, + { + "Category": "WORKING ON THE RAILROAD", + "Question": "This semipublic corporation that operates intercity U.S. passenger trains was created by Congress in 1970", + "Answer": "Amtrak" + }, + { + "Category": "BEGINS & ENDS WITH \"O\"", + "Question": "The website for this snack features the Double Stuf Racing League", + "Answer": "Oreo" + }, + { + "Category": "DANGER IN WONDERLAND", + "Question": "Don't let the smile fool you--this feline has razor-sharp claws & a cloaking device; terminate with extreme prejudice", + "Answer": "the Cheshire Cat" + }, + { + "Category": "THAT'S HANDY", + "Question": "U.S. code says that when this song plays, you put your hand over your heart", + "Answer": "the national anthem" + }, + { + "Category": "SPOILER ALERT!", + "Question": "1999: The first rule of this film is Brad Pitt doesn't really exist", + "Answer": "Fight Club" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "Austria", + "Answer": "German" + }, + { + "Category": "WORKING ON THE RAILROAD", + "Question": "The Tokaido Shinkansen, known by this \"weapon\" name, can hit 185 mph", + "Answer": "the bullet train" + }, + { + "Category": "BEGINS & ENDS WITH \"O\"", + "Question": "Herr Bismarck knows this given name comes from a Germanic word meaning \"rich\"", + "Answer": "Otto" + }, + { + "Category": "DANGER IN WONDERLAND", + "Question": "She tried to whack Alice with that \"off with her head\" line; wait 'til she gets a load of you", + "Answer": "the Queen of Hearts" + }, + { + "Category": "SPOILER ALERT!", + "Question": "1968: The baby's father, could it be... Satan?", + "Answer": "Rosemary's Baby" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "Canada (both, please)", + "Answer": "French & English" + }, + { + "Category": "WORKING ON THE RAILROAD", + "Question": "13-letter word for the operations manager of a depot or terminal", + "Answer": "stationmaster" + }, + { + "Category": "BEGINS & ENDS WITH \"O\"", + "Question": "It's another word for margarine", + "Answer": "oleo" + }, + { + "Category": "DANGER IN WONDERLAND", + "Question": "These 2 brothers may look like dimwits but they're vicious; beware the sword & umbrella, their weapons of choice", + "Answer": "Tweedledum & Tweedledee" + }, + { + "Category": "THAT'S HANDY", + "Question": "In Christian ritual it involves moving the hand from the forehead, to the chest & then to each shoulder in turn", + "Answer": "crossing oneself" + }, + { + "Category": "SPOILER ALERT!", + "Question": "1959: Joe E. Brown discovers that \"she\" is really a guy", + "Answer": "Some Like It Hot" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "Egypt", + "Answer": "Arabic" + }, + { + "Category": "WORKING ON THE RAILROAD", + "Question": "Organized in 1867, his firm built, staffed & operated sleeping cars on all major U.S. railroads", + "Answer": "Pullman" + }, + { + "Category": "BEGINS & ENDS WITH \"O\"", + "Question": "This term for an extended musical composition comes from the Italian for \"small chapel\"", + "Answer": "oratorio" + }, + { + "Category": "DANGER IN WONDERLAND", + "Question": "A suspected drug dealer who smokes from a hookah & peddles mushrooms--he's gotta go", + "Answer": "the Caterpillar" + }, + { + "Category": "SPOILER ALERT!", + "Question": "1932: The unusual circus performers discover Olga's murderous plans & turn her into a \"chicken woman\"", + "Answer": "Freaks" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "Brazil", + "Answer": "Portuguese" + }, + { + "Category": "WORKING ON THE RAILROAD", + "Question": "On April 30, 1900 this engineer gave his life in a train crash to save his passengers; his name would live on in ballads", + "Answer": "Casey Jones" + }, + { + "Category": "BEGINS & ENDS WITH \"O\"", + "Question": "L.A. restaurant Locanda Veneta serves this veal dish con risotto", + "Answer": "osso bucco" + }, + { + "Category": "THE NEW YORK TIMES THEATER", + "Question": "Frank Rich wrote you could feel Broadway history being made in this musical about a black female singing group", + "Answer": "Dreamgirls" + }, + { + "Category": "DESCRIBING THE NO. 1 SONG", + "Question": "1990: Madonna turns a magazine into a dance", + "Answer": "\"Vogue\"" + }, + { + "Category": "I COULD USE SOME SELF-HELP!", + "Question": "That hair! Those shorts! Both are still around for this exercise guy known for his \"Sweatin' to the Oldies\"", + "Answer": "Richard Simmons" + }, + { + "Category": "SCRAMBLED EGGS?", + "Question": "Denver dish: TOT MELEE", + "Answer": "omelette" + }, + { + "Category": "AMERICANS IN PARIS", + "Question": "He worked on his \"An American in Paris\" while staying with brother Ira at Paris' Hotel Majestic", + "Answer": "George Gershwin" + }, + { + "Category": "CROSSWORD CLUES \"Q\"", + "Question": "Feather pen (5)", + "Answer": "quill" + }, + { + "Category": "THE NEW YORK TIMES THEATER", + "Question": "Times multimedia features include snapshots taken at this exit, the proverbial spot to have a moment with a theater star", + "Answer": "the stage door" + }, + { + "Category": "DESCRIBING THE NO. 1 SONG", + "Question": "1975: John Denver explains why he's grateful for the simple, rural life", + "Answer": "\"Thank God I'm A Country Boy\"" + }, + { + "Category": "I COULD USE SOME SELF-HELP!", + "Question": "John Gray penned the book these 2 planets \"Together Forever--Relationship Skills for Lasting Love\"", + "Answer": "Mars & Venus" + }, + { + "Category": "SCRAMBLED EGGS?", + "Question": "A pancake-like offering in Rome: FAT TRAIT", + "Answer": "frittata" + }, + { + "Category": "CROSSWORD CLUES \"Q\"", + "Question": "To drink heartily (5)", + "Answer": "quaff" + }, + { + "Category": "THE NEW YORK TIMES THEATER", + "Question": "The Times found audience participation having a heyday in shows like \"The 25th Annual Putnam County\" this", + "Answer": "Spelling Bee" + }, + { + "Category": "DESCRIBING THE NO. 1 SONG", + "Question": "1968: Marvin Gaye gets the news through third parties that his girlfriend will be leaving him", + "Answer": "\"Heard It Through the Grapevine\"" + }, + { + "Category": "I COULD USE SOME SELF-HELP!", + "Question": "Rick Warren guided readers on a 40-day spiritual journey in the No. 1 bestseller \"The\" this \"Driven Life\"", + "Answer": "Purpose" + }, + { + "Category": "SCRAMBLED EGGS?", + "Question": "Shhh! I'm making this egg dish for a dessert!: OF FUELS", + "Answer": "soufflé" + }, + { + "Category": "AMERICANS IN PARIS", + "Question": "In March 1971 this rocker closed the door on his band & moved to Paris to focus on his poetry", + "Answer": "Jim Morrison" + }, + { + "Category": "CROSSWORD CLUES \"Q\"", + "Question": "Jelly fruit (6)", + "Answer": "quince" + }, + { + "Category": "THE NEW YORK TIMES THEATER", + "Question": "As a critics' pick in 2008, this Lin-Manuel Miranda musical was called \"a salsa-flavored soap opera\"", + "Answer": "In the Heights" + }, + { + "Category": "DESCRIBING THE NO. 1 SONG", + "Question": "Vanilla Ice, 1990: The rapper is quite confident in both his MC abilities & his appeal to women", + "Answer": "\"Ice Ice Baby\"" + }, + { + "Category": "I COULD USE SOME SELF-HELP!", + "Question": "\"The Art of Happiness\" was written by this Asian man who was picked out for his present job at the age of 2", + "Answer": "the Dalai Lama" + }, + { + "Category": "SCRAMBLED EGGS?", + "Question": "South of the border treat: OH NERVOUS SEARCH", + "Answer": "huevos rancheros" + }, + { + "Category": "AMERICANS IN PARIS", + "Question": "While minister to France, 1784-1789, this future president enjoyed Parisian culture, as well as the fine food & wine", + "Answer": "Thomas Jefferson" + }, + { + "Category": "CROSSWORD CLUES \"Q\"", + "Question": "Petty critique (7)", + "Answer": "quibble" + }, + { + "Category": "THE NEW YORK TIMES THEATER", + "Question": "Ben Brantley says \"injustice has been very good\" to this musical writing duo; see \"Chicago\" & their new \"The Scottsboro Boys\"", + "Answer": "Kander & Ebb" + }, + { + "Category": "DESCRIBING THE NO. 1 SONG", + "Question": "J. Geils, 1982: Horrors! The singer must deal with his \"angel\" being cute enough to be featured in a men's magazine", + "Answer": "\"Centerfold\"" + }, + { + "Category": "I COULD USE SOME SELF-HELP!", + "Question": "Last name of Dale, who wrote \"How to Win Friends and Influence People\"", + "Answer": "Carnegie" + }, + { + "Category": "SCRAMBLED EGGS?", + "Question": "It sounds like a dance: EMU REIGN", + "Answer": "meringue" + }, + { + "Category": "AMERICANS IN PARIS", + "Question": "Sherwood Anderson & Ernest Hemingway were among the expatriate writers who hung out at her Paris salon", + "Answer": "Gertrude Stein" + }, + { + "Category": "CROSSWORD CLUES \"Q\"", + "Question": "A literary bell ringer (9)", + "Answer": "Quasimodo" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "A contemporary review of this 1851 novel said, \"Who would have looked for... poetry in blubber?\"", + "Answer": "Moby-Dick" + }, + { + "Category": "IT'S EXTINCT", + "Question": "The baluchitherium, an extinct type of this pachyderm, had no horn, unlike modern species", + "Answer": "a rhinoceros" + }, + { + "Category": "ACTORS & THEIR ROLES", + "Question": "Aaron Spelling's daughter Tori plays Donna Martin on this popular TV series", + "Answer": "Beverly Hills, 90210" + }, + { + "Category": "TECHNOLOGY", + "Question": "A box of 64 Crayola crayons has one of these devices \"built-in\"", + "Answer": "a sharpener" + }, + { + "Category": "TAIWAN", + "Question": "In October 1971 Taiwan was expelled from this organization & Red China was admitted", + "Answer": "the UN" + }, + { + "Category": "ETIQUETTE", + "Question": "After a family meal, you may fold this item & place it back inside its ring", + "Answer": "a napkin" + }, + { + "Category": "SIMILES", + "Question": "Something that turns out well \"comes up smelling like\" these flowers", + "Answer": "roses" + }, + { + "Category": "IT'S EXTINCT", + "Question": "The dodo was found on the Islands of Reunion, Rodrigues & Mauritius in this ocean", + "Answer": "the Indian Ocean" + }, + { + "Category": "ACTORS & THEIR ROLES", + "Question": "When this singer starred in a revival of \"Funny Girl\", one critic said, \"Pia doesn't fall on her fanny\"", + "Answer": "Pia Zadora" + }, + { + "Category": "TECHNOLOGY", + "Question": "In 1835 C.S.A. Thilorier froze this gas to create the first \"dry ice\"", + "Answer": "carbon dioxide" + }, + { + "Category": "TAIWAN", + "Question": "During Japanese control of Taiwan, this largest city was called Taihoku", + "Answer": "Taipei" + }, + { + "Category": "ETIQUETTE", + "Question": "The most formal evening wear is this color \"tie\", but black tie is much more popular", + "Answer": "white tie" + }, + { + "Category": "SIMILES", + "Question": "Because artists tend to flatter their models, a fine-looking female is said to be \"as pretty as\" this", + "Answer": "a picture" + }, + { + "Category": "IT'S EXTINCT", + "Question": "The last known representative of this type of pigeon died in the Cincinnati Zoo in 1914", + "Answer": "the passenger pigeon" + }, + { + "Category": "ACTORS & THEIR ROLES", + "Question": "Patrick Stewart wrote & starred in a one-man show based on this Dickens Christmas classic", + "Answer": "A Christmas Carol" + }, + { + "Category": "TECHNOLOGY", + "Question": "After hearing this invention of his work, Edison said, \"I was never so taken aback in my life\"", + "Answer": "the phonograph" + }, + { + "Category": "TAIWAN", + "Question": "His birthday is observed as a holiday on October 31", + "Answer": "Chiang Kai-shek" + }, + { + "Category": "ETIQUETTE", + "Question": "Some small wedding receptions eliminate this greeting line that was once de rigeueur", + "Answer": "the receiving line" + }, + { + "Category": "SIMILES", + "Question": "A fine voice is \"as clear as\" one of these tintinnabulating objects", + "Answer": "a bell" + }, + { + "Category": "IT'S EXTINCT", + "Question": "Steller's Sea Cow was a relative of this rare aquatic mammal found in Florida", + "Answer": "the manatee" + }, + { + "Category": "ACTORS & THEIR ROLES", + "Question": "This British actress played Isadora Duncan on film in 1968 & onstage in 1991", + "Answer": "Vanessa Redgrave" + }, + { + "Category": "TECHNOLOGY", + "Question": "C. Vanderbilt thought George Westinghouse's idea of stopping a train by this means a fool notion", + "Answer": "the air brake" + }, + { + "Category": "TAIWAN", + "Question": "It is prohibited to bring literature promoting this ideology into Taiwan", + "Answer": "Communism" + }, + { + "Category": "ETIQUETTE", + "Question": "Black ribbon streamers on a family's front door were once a sign of this", + "Answer": "mourning" + }, + { + "Category": "SIMILES", + "Question": "A really fast person runs like this kind of \"lightning\"—as if regular lightning isn't fast enough", + "Answer": "greased lightning" + }, + { + "Category": "IT'S EXTINCT", + "Question": "The name of this extinct elephant-like creature comes from Greek meaning \"breast tooth\"", + "Answer": "a mastodon" + }, + { + "Category": "ACTORS & THEIR ROLES", + "Question": "Playwright who made his film debut in \"Renaldo and Clara\" in 1978 & won a Pulitzer Prize for Drama in '79", + "Answer": "Sam Shepard" + }, + { + "Category": "TECHNOLOGY", + "Question": "First built in 1960, it's also been called an optical maser", + "Answer": "laser" + }, + { + "Category": "TAIWAN", + "Question": "Mariners from this country named Taiwan Ilha Formosa, but didn't colonize it", + "Answer": "Portugal" + }, + { + "Category": "ETIQUETTE", + "Question": "In 1922 Emily Post wrote, \"A gentleman takes off\" this \"when a lady enters the elevator\"", + "Answer": "his hat" + }, + { + "Category": "SIMILES", + "Question": "A person who's out of his element is \"like a fish\" in this predicament", + "Answer": "out of water" + }, + { + "Category": "HISTORY", + "Question": "In 1991 B.C. Amenemhet, a former vizier, founded this country's 12th dynasty", + "Answer": "Egypt" + }, + { + "Category": "BALLET", + "Question": "\"Homage to the Queen\", a tribute to her, premiered on her coronation day in 1953", + "Answer": "Elizabeth II" + }, + { + "Category": "BIOLOGY", + "Question": "Unlike most birds, ratites like the ostrich can't do this", + "Answer": "fly" + }, + { + "Category": "FRUITS & VEGETABLES", + "Question": "The summer varieties of this gourd-like vegetable are eaten green; the winter ones, ripe", + "Answer": "squash" + }, + { + "Category": "AMERICAN INDIANS", + "Question": "In 1777 Chief Joseph Brant led his fellow Mohawks in the Battle of Oriskany during this war", + "Answer": "the Revolutionary War" + }, + { + "Category": "NOVELISTS", + "Question": "This novelist's youthful voyages provided the basis for such works as \"Lord Jim\" & \"Typhoon\"", + "Answer": "Conrad" + }, + { + "Category": "HISTORY", + "Question": "Because his proposals for constitutional change were defeated, this French president resigned in 1969", + "Answer": "Charles de Gaulle" + }, + { + "Category": "BALLET", + "Question": "This dancer choreographed a new version of \"The Nutcracker\" in 1976, a \"Turning Point\" in his career", + "Answer": "Baryshnikov" + }, + { + "Category": "BIOLOGY", + "Question": "Associated with this sense, the olfactory lobe is better developed in most vertebrates than in man", + "Answer": "smell" + }, + { + "Category": "FRUITS & VEGETABLES", + "Question": "This fruit with many seeds is grown on the Punica granatum tree", + "Answer": "a pomegranate" + }, + { + "Category": "AMERICAN INDIANS", + "Question": "A woman claiming to be this Lewis & Clark companion died in 1884; she would have been about 100", + "Answer": "Sacagawea" + }, + { + "Category": "NOVELISTS", + "Question": "He dictated his last novel, \"The Brothers Karamazov\", to his wife who took it down in shorthand", + "Answer": "Dostoevsky" + }, + { + "Category": "HISTORY", + "Question": "In 1919 this national assembly met in this city & formed a new German republic", + "Answer": "Weimar" + }, + { + "Category": "BALLET", + "Question": "The School of American Ballet is the official school of this major metropolitan ballet company", + "Answer": "New York" + }, + { + "Category": "BIOLOGY", + "Question": "Renin, an enzyme that breaks down protein, is secreted by cells in this organ", + "Answer": "the kidney" + }, + { + "Category": "FRUITS & VEGETABLES", + "Question": "Poi, a luau treat, is made from these mashed roots", + "Answer": "taro" + }, + { + "Category": "AMERICAN INDIANS", + "Question": "Geronimo rode in this U.S. president's 1905 inaugural parade", + "Answer": "Theodore Roosevelt" + }, + { + "Category": "NOVELISTS", + "Question": "This Scottish novelist is buried at the summit of Mt. Vaea on Upolu, an island of Western Samoa", + "Answer": "Robert Louis Stevenson" + }, + { + "Category": "HISTORY", + "Question": "The parents of this Peruvian president immigrated from Japan 4 years prior to his birth", + "Answer": "Fujimori" + }, + { + "Category": "BALLET", + "Question": "This Spanish seducer is attacked by furies at the end of a 1936 ballet", + "Answer": "Don Juan" + }, + { + "Category": "BIOLOGY", + "Question": "Common \"colorful\" term for the eythrocytes, which transport oxygen around the body", + "Answer": "the red blood cells" + }, + { + "Category": "FRUITS & VEGETABLES", + "Question": "A greengage is a plum & a greening is this fruit", + "Answer": "an apple" + }, + { + "Category": "AMERICAN INDIANS", + "Question": "When this chief, Pocahontas' father, died in 1618, he was succeeded by his brother Opitchapam", + "Answer": "Powhatan" + }, + { + "Category": "NOVELISTS", + "Question": "This novelist's nonfiction book \"Miami and the Siege of Chicago\" was about the 1968 political conventions", + "Answer": "Norman Mailer" + }, + { + "Category": "HISTORY", + "Question": "About 3000 B.S. the Sumerians invented this writing system which used triangular marks", + "Answer": "cuneiform" + }, + { + "Category": "BALLET", + "Question": "First performed in 1905, this very short solo ballet depicts the last minutes in the life of a bird", + "Answer": "The Dying Swan" + }, + { + "Category": "BIOLOGY", + "Question": "This nucleic acid occurs in 3 forms: messenger, ribosomal & transfer", + "Answer": "RNA" + }, + { + "Category": "FRUITS & VEGETABLES", + "Question": "This somewhat coarse root vegetable is also called a swede or a Swedish turnip", + "Answer": "a rutabaga" + }, + { + "Category": "AMERICAN INDIANS", + "Question": "This chief once called \"The Apache Napoleon\" died in the Arizona territory in 1874", + "Answer": "Cochise" + }, + { + "Category": "NOVELISTS", + "Question": "He followed his first novel, \"Appointment in Samarra\", with \"BUtterfield 8\"", + "Answer": "John O'Hara" + }, + { + "Category": "U.S. RIVERS", + "Question": "The name of this river, famous in song, may be a corruption of the Spanish for \"little Saint John\"", + "Answer": "the Swanee" + }, + { + "Category": "NATURE", + "Question": "Safes, a type of these desert formations, are often many miles long & several hundred feet high", + "Answer": "sand dunes" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "When Marie Osmond toured in this play in 1994, her eldest son, Steven, played Kurt Von Trapp", + "Answer": "The Sound of Music" + }, + { + "Category": "1988", + "Question": "At the July 1988 Democratic National Convention this Massachusetts governor was nominated for president", + "Answer": "Michael Dukakis" + }, + { + "Category": "FOOD", + "Question": "While these small bread cubes often top salads, larger versions can be used to catch drippings", + "Answer": "croutons" + }, + { + "Category": "HEALTH & MEDICINE", + "Question": "These blood-sucking worms are used in medicine today to drain hematomas", + "Answer": "leeches" + }, + { + "Category": "CROSSWORD CLUES \"E\"", + "Question": "Zealous, like a beaver (5)", + "Answer": "eager" + }, + { + "Category": "NATURE", + "Question": "Sausage trees, found in Africa, are pollinated by these flying mammals", + "Answer": "bats" + }, + { + "Category": "1988", + "Question": "The Thatcher government imposed a broadcast ban on this political wing of the IRA", + "Answer": "Sinn Fein" + }, + { + "Category": "FOOD", + "Question": "A raw egg yolk usually accompanies this raw meat dish", + "Answer": "Steak Tartare" + }, + { + "Category": "HEALTH & MEDICINE", + "Question": "Light flashes in the field of vision may mean this optic tissue has become detatched", + "Answer": "the retina" + }, + { + "Category": "CROSSWORD CLUES \"E\"", + "Question": "Mistaken (9)", + "Answer": "erroneous" + }, + { + "Category": "NATURE", + "Question": "This largest U.S. cactus can weigh as much as 10 tons", + "Answer": "saguaro" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "Scott Bakula played Joe DiMaggio in a 1983 musical about this sex symbol", + "Answer": "Marilyn Monroe" + }, + { + "Category": "1988", + "Question": "After 32 years in power, Janos Kadar was ousted as first secretary of this country's Communist Party", + "Answer": "Hungary" + }, + { + "Category": "FOOD", + "Question": "Butternut refers to both an actual nut & this type of gourd", + "Answer": "squash" + }, + { + "Category": "HEALTH & MEDICINE", + "Question": "This artificial sweetner has been associated with bladder cancer in animal experiments", + "Answer": "saccharin" + }, + { + "Category": "CROSSWORD CLUES \"E\"", + "Question": "On-screen, they're \"special\" (7)", + "Answer": "effects" + }, + { + "Category": "NATURE", + "Question": "Often found clinging to rocks, limpids are a type of this mollusk", + "Answer": "snails" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "Elaine Stritch plays Capt. Andy's wife Parthy in the current revival of this Jerome Kern musical", + "Answer": "Show Boat" + }, + { + "Category": "1988", + "Question": "A 1988 plebiscite said that this Chilean dictator had to be out of office by March of 1990", + "Answer": "Augusto Pinochet" + }, + { + "Category": "FOOD", + "Question": "It's an Italian version of an omelet, served pancake-style", + "Answer": "a frittata" + }, + { + "Category": "HEALTH & MEDICINE", + "Question": "Apnea is the temporary cessation of this", + "Answer": "breathing" + }, + { + "Category": "CROSSWORD CLUES \"E\"", + "Question": "Count off one-by-one (9)", + "Answer": "enumerate" + }, + { + "Category": "NATURE", + "Question": "In the South, buildings have been engulfed & trees have been smothered by this Oriental vine gone wild", + "Answer": "kudzu" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "\"Kismet\"'s music is adapted from the works of this \"Prince Igor\" composer", + "Answer": "Alexander Borodin" + }, + { + "Category": "1988", + "Question": "Along with the Marcoses, this Saudi arms merchant was indicted in October on charges of racketeering", + "Answer": "Adnan Khashoggi" + }, + { + "Category": "FOOD", + "Question": "They're the two common vegetables in the English dish bubble & squeak", + "Answer": "potato & cabbage" + }, + { + "Category": "HEALTH & MEDICINE", + "Question": "In vitiligo, a common disorder, patches of skin lose this", + "Answer": "pigment" + }, + { + "Category": "CROSSWORD CLUES \"E\"", + "Question": "The \"bigger picture\" (11)", + "Answer": "enlargement" + }, + { + "Category": "ANCIENT HISTORY", + "Question": "In 213 B.C., Ch'in Shih Huang-ti ordered all of these burned, except the ones in the imperial library", + "Answer": "books" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Antelope Island in this Utah lake is used as a refuge for bison", + "Answer": "the Great Salt Lake" + }, + { + "Category": "SAINTS", + "Question": "On the second Sunday in May, the French honor her with a holiday", + "Answer": "Joan of Arc" + }, + { + "Category": "FLEETS", + "Question": "When he left for his second voyage in September of 1493, he had a fleet of seventeen ships, fourteen more than his first trip", + "Answer": "Christopher Columbus" + }, + { + "Category": "CLOTHING", + "Question": "They can be crew, knee, or bobby", + "Answer": "socks" + }, + { + "Category": "LITERATURE", + "Question": "In F. Scott Fitzgerald's classic novel, Nick Carraway lives next door to this title character", + "Answer": "the Great Gatsby" + }, + { + "Category": "ANCIENT HISTORY", + "Question": "This pupil of Socrates went to Sicily to try to turn Dionysius into a philosopher king", + "Answer": "Plato" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "Albuquerque, New Mexico lies on this 1885-mile long river", + "Answer": "the Rio Grande" + }, + { + "Category": "SAINTS", + "Question": "March 1st is the feast day of this patron saint of Wales", + "Answer": "St. David" + }, + { + "Category": "FLEETS", + "Question": "The Duque de Medina- Sidonia commanded this fleet in 1588", + "Answer": "the Spanish Armada" + }, + { + "Category": "CLOTHING", + "Question": "This Channel Island has a close-fitting knitted shirt or sweater named for it, in addition to a cow", + "Answer": "Jersey" + }, + { + "Category": "LITERATURE", + "Question": "Part I of this Willa Cather novel is entitled \"The Wild Land\"", + "Answer": "O Pioneers!" + }, + { + "Category": "ANCIENT HISTORY", + "Question": "Tikal became an important ceremonial center of this civilization, prior to 300 A.D.", + "Answer": "the Mayans" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "From its incorporation in 1813 until 1901, this New York village was known as Sing-Sing", + "Answer": "Ossining" + }, + { + "Category": "SAINTS", + "Question": "St. Raphael shares his feast day, September 29, with these two archangels", + "Answer": "Michael & Gabriel" + }, + { + "Category": "FLEETS", + "Question": "This company's fleet has included the Queen Mary, Queen Elizabeth, & Queen Elizabeth II", + "Answer": "Cunard" + }, + { + "Category": "CLOTHING", + "Question": "A plastron is the quilted pad worn by competitors in this sport to protect their torso & sides", + "Answer": "fencing" + }, + { + "Category": "LITERATURE", + "Question": "His novel \"Daisy Miller\" opens at the Trois Couronnes hotel in Vevey, Switzerland", + "Answer": "Henry James" + }, + { + "Category": "ANCIENT HISTORY", + "Question": "He was only 16 when he became Roman emperor upon the death of Claudius", + "Answer": "Nero" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "South Carolina's highest point, Sassafras Mountain, rises 3,560 feet in this range of the Appalachians", + "Answer": "the Blue Ridge Mountains" + }, + { + "Category": "SAINTS", + "Question": "This man who added utopia to our vocabulary was made a saint in 1935", + "Answer": "St. Thomas More" + }, + { + "Category": "FLEETS", + "Question": "This empire's fleet was defeated in the 1571 Battle of Lepanto", + "Answer": "the Ottoman Empire" + }, + { + "Category": "CLOTHING", + "Question": "This apron for young girls has a ruffled bibbed top & a gathered skirt", + "Answer": "a pinafore" + }, + { + "Category": "LITERATURE", + "Question": "He published his third novel, \"A Cool Million\", in 1934, one year after \"Miss Lonelyhearts\"", + "Answer": "Nathanael West" + }, + { + "Category": "ANCIENT HISTORY", + "Question": "This Old Kingdom capital of Egypt was originally named Hikouptah", + "Answer": "Memphis" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "This Lake Erie port in Northwest Ohio was once called \"the Glass Capital of the World\"", + "Answer": "Toledo" + }, + { + "Category": "SAINTS", + "Question": "This scholarly 13th century saint was often called \"The Angelic Doctor\"", + "Answer": "St. Thomas Aquinas" + }, + { + "Category": "FLEETS", + "Question": "The Black Sea fleet in dispute between Russia & Ukraine is based at this Crimean port", + "Answer": "Sevastopol" + }, + { + "Category": "CLOTHING", + "Question": "It's the fur pouch that a Scotsman wears on the front of his kilt", + "Answer": "a sporon" + }, + { + "Category": "LITERATURE", + "Question": "In English, Ivan Turgenev's novel \"Ottsy i Deti\" is known by this \"familial\" title\"", + "Answer": "Fathers and Sons" + }, + { + "Category": "NAMES IN THE NEWS", + "Question": "This former U.N. ambassador is a co-chairman of the host city's committee for the 1996 Olympic Games", + "Answer": "Andrew Young" + }, + { + "Category": "SOUND LIKE A LOCAL", + "Question": "It follows \"Pitts-\" in the U.S. & \"Edin-\" in Scotland; we'll accept either pronunciation", + "Answer": "burgh" + }, + { + "Category": "BROADWAY LYRICS", + "Question": "\"Immigrant goes to America, many hellos in America; nobody knows in America, Puerto Rico's in America!\"", + "Answer": "West Side Story" + }, + { + "Category": "WHAM-O", + "Question": "In 1997 Wham-O introduced a Max Flight version of this 1950s sensation that flew farther & was easy to catch", + "Answer": "the Frisbee" + }, + { + "Category": "LITERARY BADDIES", + "Question": "This Seuss character who lived in a cave \"stood there on Christmas Eve, hating the Whos\"", + "Answer": "the Grinch" + }, + { + "Category": "STATE BIRDS", + "Question": "Ohio: This redbird", + "Answer": "a cardinal" + }, + { + "Category": "BEFORE & AFTER", + "Question": "\"Thin\" piece of disputed Israeli-Palestinian land involved in a clothes-shedding card game", + "Answer": "Gaza Strip Poker" + }, + { + "Category": "SOUND LIKE A LOCAL", + "Question": "To pass for a native of Danvers, Massachusetts, don't pronounce this letter in the town's name", + "Answer": "the R" + }, + { + "Category": "BROADWAY LYRICS", + "Question": "\"He had it comi", + "Answer": "Chicago" + }, + { + "Category": "WHAM-O", + "Question": "Wham-O owners heard about Australian kids using a bamboo ring for exercise; it became this 1958 fad", + "Answer": "a Hula hoop" + }, + { + "Category": "LITERARY BADDIES", + "Question": "This Harry Potter bad guy's name is French for \"flight from death\"", + "Answer": "Voldemort" + }, + { + "Category": "STATE BIRDS", + "Question": "Virginia: This bird, not Albert Pujols", + "Answer": "the cardinal" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Film legend who became an 1823 edict against European intervention in the Western Hemisphere", + "Answer": "the Marilyn Monroe Doctrine" + }, + { + "Category": "SOUND LIKE A LOCAL", + "Question": "Pedernales is in the Dominican Republic; north of the border, the Pedernales River is in this state", + "Answer": "Texas" + }, + { + "Category": "BROADWAY LYRICS", + "Question": "\"I can smile at the old days, I was beautiful then, I remember the time I knew that happiness was\"", + "Answer": "Cats" + }, + { + "Category": "WHAM-O", + "Question": "Wham-O received its name from this first product; when a projectile hit its target, it made a \"Wham-O\" sound", + "Answer": "a slingshot" + }, + { + "Category": "LITERARY BADDIES", + "Question": "This villainess of \"The Wizard of Oz\" ruled over the Winkies", + "Answer": "the Wicked Witch of the West" + }, + { + "Category": "STATE BIRDS", + "Question": "West Virginia: This crested bird", + "Answer": "the cardinal" + }, + { + "Category": "BEFORE & AFTER", + "Question": "\"Bouncy\" 1965 Beatles album that took over for Don Cornelius as host of a dance show", + "Answer": "Rubber Soul Train" + }, + { + "Category": "BROADWAY LYRICS", + "Question": "\"Whatever Lola wants, Lola gets, and little man, little Lola wants you\"", + "Answer": "Damn Yankees" + }, + { + "Category": "WHAM-O", + "Question": "This 1962 Wham-O game named for a dance craze came with a moveable cross bar & 2 support stands", + "Answer": "limbo" + }, + { + "Category": "LITERARY BADDIES", + "Question": "Mrs. Augustine St. Clare sold Uncle Tom to this brutal, alcoholic plantation owner who later beat him to death", + "Answer": "Simon Legree" + }, + { + "Category": "STATE BIRDS", + "Question": "Kentucky: This colorful songbird", + "Answer": "a cardinal" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Robert E. Lee's \"right arm\" general who sang \"ABC\" with a singing group", + "Answer": "Stonewall Jackson 5" + }, + { + "Category": "SOUND LIKE A LOCAL", + "Question": "This Ohio village, Thomas Edison's birthplace, is named for a North Italian city but rhymes with \"stylin'\"", + "Answer": "Milan" + }, + { + "Category": "BROADWAY LYRICS", + "Question": "\"All I need is one more try, gotta get that kite to fly\"", + "Answer": "You're a Good Man, Charlie Brown" + }, + { + "Category": "WHAM-O", + "Question": "Versions of this lawn toy to keep you cool in the summer include \"Wave Rider\" & \"Bounce 'N Splash\"", + "Answer": "a Slip 'N Slide" + }, + { + "Category": "LITERARY BADDIES", + "Question": "This villainous aide in a Shakespeare play states flatly, \"I hate the Moor\"", + "Answer": "Iago" + }, + { + "Category": "STATE BIRDS", + "Question": "Missouri: Not a redbird but this colorful creature", + "Answer": "a bluebird" + }, + { + "Category": "BEFORE & AFTER", + "Question": "1935 \"lunar\" Florida song that turned into an '80s Florida cop show", + "Answer": "\"Moon Over Miami Vice\"" + }, + { + "Category": "WOLVERINE", + "Question": "This creature is the main predator of wolverines; what else would be dumb enough to take one on?", + "Answer": "man" + }, + { + "Category": "STORM", + "Question": "This 2000 film was based on Sebastian Junger's bestseller about a hurricane that meets a cold front", + "Answer": "The Perfect Storm" + }, + { + "Category": "MAGNETO", + "Question": "Logically enough, this planet has the strongest magnetic field of any planet in our solar system", + "Answer": "Jupiter" + }, + { + "Category": "ROGUE", + "Question": "The U.S. condemned this country's October 2006 nuclear test as a \"provocative act\"", + "Answer": "North Korea" + }, + { + "Category": "COLOSSUS", + "Question": "2-syllable name for the long-ago elephant relative with 13-foot tusks that has become a synonym for \"huge\"", + "Answer": "a mammoth" + }, + { + "Category": "\"X\"-MEN", + "Question": "He was the de facto leader of China from the late 1970s to the early 1990s", + "Answer": "Deng Xiaoping" + }, + { + "Category": "WOLVERINE", + "Question": "During the winter, wolverines hunt caribou & this animal of the genus Rangifer; Santa's gonna be mad", + "Answer": "reindeer" + }, + { + "Category": "STORM", + "Question": "Bogey & Bacall's final film together was this one that saw them waiting out a storm in Florida", + "Answer": "Key Largo" + }, + { + "Category": "MAGNETO", + "Question": "Around 1904 this Norwegian explorer confirmed that the Earth's magnetic poles are not fixed", + "Answer": "Amundsen" + }, + { + "Category": "ROGUE", + "Question": "In 2000 Zalmay Khalizad, future U.S. envoy here, Talibandied its name about in \"Consolidation of a Rogue State\"", + "Answer": "Afghanistan" + }, + { + "Category": "COLOSSUS", + "Question": "From this author we get the adjective \"brobdingnagian\", meaning \"gigantic\"", + "Answer": "Swift" + }, + { + "Category": "WOLVERINE", + "Question": "The website for this state's legislature says no bear \"can match the vicious disposition... of the wolverine\"", + "Answer": "Michigan" + }, + { + "Category": "STORM", + "Question": "Hurricane Camille leaves only one operational shrimping boat in Bayou La Batre in this 1994 Oscar winner", + "Answer": "Forrest Gump" + }, + { + "Category": "ROGUE", + "Question": "This president's administration changed the term \"rogue state\" to \"states of concern\"", + "Answer": "Bill Clinton" + }, + { + "Category": "COLOSSUS", + "Question": "Rabelaisian adjective meaning \"enormous\", like a task", + "Answer": "gargantuan" + }, + { + "Category": "\"X\"-MEN", + "Question": "His dad Earl Little was an outspoken Baptist minister & supporter of black nationalist leader Marcus Garvey", + "Answer": "Malcolm X" + }, + { + "Category": "STORM", + "Question": "The probe used to investigate tornados in this film is aptly named Dorothy", + "Answer": "Twister" + }, + { + "Category": "MAGNETO", + "Question": "An alnico magnet is an alloy having these 3 elements as its principal ingredients", + "Answer": "aluminum, nickel, cobalt" + }, + { + "Category": "COLOSSUS", + "Question": "This adjective that means \"amazingly large\" or \"causing amazement\" is from the Latin for \"to be stunned\"", + "Answer": "stupendous" + }, + { + "Category": "\"X\"-MEN", + "Question": "This Persian son of Darius I burned Athens in 480 B.C.", + "Answer": "Xerxes" + }, + { + "Category": "WOLVERINE", + "Question": "Bears have cubs; wolverine newborns are known as these, like foxes & beavers", + "Answer": "kits" + }, + { + "Category": "STORM", + "Question": "In this cool 2004 film, climatologist Dennis Quaid is right & much of the U.S. evacuates to Mexico", + "Answer": "The Day After Tomorrow" + }, + { + "Category": "ROGUE", + "Question": "This country's acceptance of responsibility for the Pan Am 103 bombing helped it lose its rogue status", + "Answer": "Libya" + }, + { + "Category": "COLOSSUS", + "Question": "Immeasurably great, like the \"Jest\" in a David Foster Wallace title", + "Answer": "infinite" + }, + { + "Category": "\"X\"-MEN", + "Question": "The \"Apostle of the Indies\", this missionary helped found the Jesuits & introduced Christianity to Japan", + "Answer": "Francis Xavier" + }, + { + "Category": "EXPLORERS", + "Question": "In 1616, after Hudson died, this man became the 1st European to reach Ellesmere Island; an island & bay are named for him", + "Answer": "Baffin" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "He was living in Tahiti when he painted \"Poemes Barbares\" in 1896", + "Answer": "Paul Gauguin" + }, + { + "Category": "BOGIE MEN", + "Question": "Rick Blaine", + "Answer": "Casablanca" + }, + { + "Category": "ANNIVERSARY GIFTS", + "Question": "You shouldn't \"cast\" them \"before swine\", but you can give them for a 12th or 30th anniversary gift", + "Answer": "Pearls" + }, + { + "Category": "TELL ME \"Y\"", + "Question": "A bumpkin, perhaps a local one", + "Answer": "Yokel" + }, + { + "Category": "LOST", + "Question": "TV show whose theme says, \"The Minnow will be lost\"", + "Answer": "Gilligan's Island" + }, + { + "Category": "FOUND", + "Question": "Agnes Baden-Powell helped found the Girl Guides soon after her brother Robert founded this movement", + "Answer": "Boy Scouts" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "We know he painted the absinthe drinker seen here, though there's nary a tutu in sight:", + "Answer": "Edgar Degas" + }, + { + "Category": "BOGIE MEN", + "Question": "Sam Spade", + "Answer": "The Maltese Falcon" + }, + { + "Category": "ANNIVERSARY GIFTS", + "Question": "It's a nice gift for the 35th, but if you take it out of a U.S. reef you may be arrested", + "Answer": "Coral" + }, + { + "Category": "TELL ME \"Y\"", + "Question": "\"Meshugge\" means crazy in this language of Europe's Ashkenazic Jews", + "Answer": "Yiddish" + }, + { + "Category": "LOST", + "Question": "Lost in the forest, this pair happens upon a house made of bread, cake & sugar", + "Answer": "Hansel & Gretel" + }, + { + "Category": "FOUND", + "Question": "Ben Franklin helped found this Ivy League school that had the USA's first medical school", + "Answer": "University of Pennsylvania" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "Elisabeth Vigee Le Brun was noted for portraits of this queen, including the one with her children, seen here:", + "Answer": "Marie Antoinette" + }, + { + "Category": "BOGIE MEN", + "Question": "Captain Queeg", + "Answer": "The Caine Mutiny" + }, + { + "Category": "ANNIVERSARY GIFTS", + "Question": "In one form or another you can fork over this metal on the 5th or 25th anniversary", + "Answer": "Silver" + }, + { + "Category": "TELL ME \"Y\"", + "Question": "It can be a standard for comparison, or a measuring rod 3 feet in length", + "Answer": "Yardstick" + }, + { + "Category": "LOST", + "Question": "Presumably she was lost at sea after vanishing in the central Pacific in July 1937", + "Answer": "Amelia Earhart" + }, + { + "Category": "FOUND", + "Question": "In the early 1900s William Durant put together Buick, Oldsmobile & other companies to found this corporation", + "Answer": "General Motors" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "Andre Derain was a prominent painter in this style whose name is from the French for \"wild beasts\"", + "Answer": "Fauvism" + }, + { + "Category": "BOGIE MEN", + "Question": "Fred C. Dobbs", + "Answer": "The Treasure of the Sierra Madre" + }, + { + "Category": "ANNIVERSARY GIFTS", + "Question": "19th century American \"King of the South\" that's a 2nd anniversary gift", + "Answer": "Cotton" + }, + { + "Category": "TELL ME \"Y\"", + "Question": "First name shared by monsieurs Saint Laurent & Montand", + "Answer": "Yves" + }, + { + "Category": "LOST", + "Question": "It's said that this gem was cut from a stone called the French Blue, which was lost after a crown jewel heist in 1792", + "Answer": "Hope Diamond" + }, + { + "Category": "FOUND", + "Question": "Fritz & Laura Perls founded this school of psychotherapy, from German for \"form\"", + "Answer": "Gestalt" + }, + { + "Category": "FRENCH ART & ARTISTS", + "Question": "This resident of Argenteuil painted \"The Regatta at Argenteuil\", seen here:", + "Answer": "Claude Monet" + }, + { + "Category": "BOGIE MEN", + "Question": "Charlie Allnut", + "Answer": "The African Queen" + }, + { + "Category": "ANNIVERSARY GIFTS", + "Question": "This 10th anniversary present is present in the name of a 20th anniversary gift -- platinum", + "Answer": "Tin" + }, + { + "Category": "TELL ME \"Y\"", + "Question": "Aden is the second-largest city in this Middle Eastern hot spot", + "Answer": "Yemen" + }, + { + "Category": "LOST", + "Question": "Performed annually in North Carolina, \"The Lost Colony\" is an outdoor drama about this lost colony", + "Answer": "Roanoke Island" + }, + { + "Category": "FOUND", + "Question": "Cowboy nickname of William Donovan, founder of the OSS & of modern U.S. intelligence", + "Answer": "\"Wild Bill\"" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "It's the only provincial capital with its own Major League Baseball team", + "Answer": "Toronto" + }, + { + "Category": "SENIOR SENATORS", + "Question": "In 1990 she lost the race for California governor; in 1992 she won the race for California senator", + "Answer": "Dianne Feinstein" + }, + { + "Category": "1800", + "Question": "His First Symphony debuted April 2 in Vienna; 8 to go...", + "Answer": "Ludwig von Beethoven" + }, + { + "Category": "THAT OLD TIME NEW WAVE MUSIC", + "Question": "In a 1979 hit by the Police she's told, \"You don't have to sell your body to the night\"", + "Answer": "\"Roxanne\"" + }, + { + "Category": "LITERARY LAST NAME'S THE SAME", + "Question": "Wyndham, C.S., Sinclair", + "Answer": "Lewis" + }, + { + "Category": "FROM THE WELSH", + "Question": "Rarebit, as in Welsh Rarebit, is an alteration of this word that's not an ingredient in Welsh Rarebit", + "Answer": "Rabbit" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "This Manitoba capital's name is derived from 2 Cree Indian words meaning \"murky water\"", + "Answer": "Winnipeg" + }, + { + "Category": "SENIOR SENATORS", + "Question": "Politician seen here in 1962, the year he was first elected to the Senate:", + "Answer": "EdwardKennedy" + }, + { + "Category": "1800", + "Question": "This vulcanization inventor was born a bouncing baby boy in 1800", + "Answer": "Charles Goodyear" + }, + { + "Category": "THAT OLD TIME NEW WAVE MUSIC", + "Question": "You might think this Cars leader is married to supermodel Paulina Porizkova (& you'd be right)", + "Answer": "Ric Ocasek" + }, + { + "Category": "LITERARY LAST NAME'S THE SAME", + "Question": "C.K., Emlyn, Tennessee", + "Answer": "Williams" + }, + { + "Category": "FROM THE WELSH", + "Question": "From the Welsh for \"dwarf dog\", it's also a miniature toy car brand", + "Answer": "Corgi" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "Vancouver isn't on Vancouver Island, but this capital is", + "Answer": "Victoria" + }, + { + "Category": "SENIOR SENATORS", + "Question": "When admiring the Stamford train station, thank this state's Christopher Dodd, who helped secure funding", + "Answer": "Connecticut" + }, + { + "Category": "1800", + "Question": "William Herschel discovered these \"rays\" beyond the red end of the visible spectrum", + "Answer": "Infrared rays" + }, + { + "Category": "THAT OLD TIME NEW WAVE MUSIC", + "Question": "A drum machine christened \"Echo\" helped launch this hopping band to fame & fortune", + "Answer": "Echo & the Bunnymen" + }, + { + "Category": "LITERARY LAST NAME'S THE SAME", + "Question": "John, Taylor, Erskine", + "Answer": "Caldwell" + }, + { + "Category": "FROM THE WELSH", + "Question": "\"Arthur-itative\" sources say her name is Welsh for \"white\" or \"fair\"", + "Answer": "Guinevere" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "Now a provincial capital, it was once the capital of New France", + "Answer": "Quebec City" + }, + { + "Category": "SENIOR SENATORS", + "Question": "An IRA that allows tax-free withdrawals is named for this Delaware senator", + "Answer": "William Roth" + }, + { + "Category": "1800", + "Question": "France got this territory back from Spain in 1800, saying it wouldn't transfer it again to anyone but Spain", + "Answer": "Louisiana" + }, + { + "Category": "THAT OLD TIME NEW WAVE MUSIC", + "Question": "Last name of Gary, the former Tubeway Army leader who charted with New Wave hits like \"Cars\"", + "Answer": "Gary Numan" + }, + { + "Category": "LITERARY LAST NAME'S THE SAME", + "Question": "Frank, Hart, Stephen", + "Answer": "Crane" + }, + { + "Category": "FROM THE WELSH", + "Question": "The name of this Olympic weapon may go back to the Welsh gaflach, \"forked branch\"", + "Answer": "Javelin" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "In 1947 huge oil deposits were discovered in this city 175 miles north of Calgary; it's now Canada's oil capital", + "Answer": "Edmonton" + }, + { + "Category": "SENIOR SENATORS", + "Question": "This man has 26 years of seniority on his fellow West Virginia senator Jay Rockefeller", + "Answer": "Robert Byrd" + }, + { + "Category": "1800", + "Question": "His \"The Wealth of Nations\" was one of the first books bought to stock the new Library of Congress", + "Answer": "Adam Smith" + }, + { + "Category": "THAT OLD TIME NEW WAVE MUSIC", + "Question": "(Hi, I'm Jane Wiedlin) Among my credits is this song that starts, \"Can you hear them? Talkin' about us, telling lies...\"", + "Answer": "\"Our Lips are Sealed\"" + }, + { + "Category": "LITERARY LAST NAME'S THE SAME", + "Question": "Walter M., Arthur, Henry", + "Answer": "Miller" + }, + { + "Category": "FROM THE WELSH", + "Question": "Perhaps from the Welsh for \"goblin\", Elwood P. Dowd's Harvey was a famous one", + "Answer": "Pooka" + }, + { + "Category": "TELEVISION HISTORY", + "Question": "In the late '60s this character was created to show children it's okay to be grumpy", + "Answer": "Oscar the Grouch" + }, + { + "Category": "LARRY KING'S PUBLIC FIGURES", + "Question": "Tonight, the wooden teeth--fact or fiction? Also, his 1754 Fort Necessity battle loss...Mt. Vernon, hello", + "Answer": "George Washington" + }, + { + "Category": "DRIVING", + "Question": "Do this if you love Jesus but don't do it just as the light turns green", + "Answer": "honk" + }, + { + "Category": "MICHAEL JACKSON HITS IN OTHER WORDS", + "Question": "1983: \"Speak, Speak, Speak\"", + "Answer": "\"Say Say Say\"" + }, + { + "Category": "20th CENTURY BALLET", + "Question": "This great Spanish cubist designed sets & costumes for the 1919 ballet \"The Three-Cornered Hat\"", + "Answer": "Picasso" + }, + { + "Category": "EXPORTS", + "Question": "90% of Qatar's income comes from the export of this product", + "Answer": "oil" + }, + { + "Category": "FAMILIAR PHRASES", + "Question": "If you have other, more important things to do, you \"have other' of these \"to fry\"", + "Answer": "fish" + }, + { + "Category": "LARRY KING'S PUBLIC FIGURES", + "Question": "I'm all shook up about my next guest & the caller is from his hometown...Tupelo, MS., hello?", + "Answer": "Elvis Presley" + }, + { + "Category": "DRIVING", + "Question": "The following sound indicates a vehicle in this gear", + "Answer": "reverse" + }, + { + "Category": "MICHAEL JACKSON HITS IN OTHER WORDS", + "Question": "1987: \"Naughty\"", + "Answer": "\"Bad\"" + }, + { + "Category": "20th CENTURY BALLET", + "Question": "\"Prince Rama & the Demons\" was inspired by the \"Ramayana\", one of the great epic poems of this country", + "Answer": "India" + }, + { + "Category": "EXPORTS", + "Question": "The hills around San Jose are covered with trees growing this, Costa Rica's top export", + "Answer": "coffee" + }, + { + "Category": "FAMILIAR PHRASES", + "Question": "Big throwing don'ts include \"the baby out with the bathwater\" & \"caution to\" this", + "Answer": "the wind" + }, + { + "Category": "LARRY KING'S PUBLIC FIGURES", + "Question": "At the bottom of the hour, bet you won't miss my chat with this all time \"hit king\" of baseball...Cincinnati, hello?", + "Answer": "Pete Rose" + }, + { + "Category": "DRIVING", + "Question": "In September 2000, Congress held hearings on this company's product found on Fords", + "Answer": "Firestone" + }, + { + "Category": "MICHAEL JACKSON HITS IN OTHER WORDS", + "Question": "1983: \"Get Out Of Here!\"", + "Answer": "\"Beat It\"" + }, + { + "Category": "20th CENTURY BALLET", + "Question": "\"Happiness is just a thing called Joe\" goes one of the songs in the 1997 ballet about this late sex symbol", + "Answer": "Marilyn Monroe" + }, + { + "Category": "EXPORTS", + "Question": "This crop is king in Mali; about 1/2 of its export income comes from it", + "Answer": "cotton" + }, + { + "Category": "FAMILIAR PHRASES", + "Question": "In \"A Psalm of Life, \" Longfellow tells of leaving these behind \"on the sands of time\"", + "Answer": "footprints" + }, + { + "Category": "LARRY KING'S PUBLIC FIGURES", + "Question": "A special Larry King tonight this \"wubbulous\" children's author & his thoughts on Rosie starring in his big Broadway show", + "Answer": "Dr. Seuss" + }, + { + "Category": "DRIVING", + "Question": "Experts disagree on whether 10 & 2 o'clock or 9 & 3 is better for this; no one thinks much of the old wrist drape", + "Answer": "steering wheel position" + }, + { + "Category": "MICHAEL JACKSON HITS IN OTHER WORDS", + "Question": "1984: \"Suspenseful Movie\"", + "Answer": "\"Thriller\"" + }, + { + "Category": "20th CENTURY BALLET", + "Question": "Phillip Feeny's eerie music for the British ballet based on this spooky 19th C. novel is heard here", + "Answer": "Dracula" + }, + { + "Category": "EXPORTS", + "Question": "A big export for Tuvalu is copia, the dried meat of this", + "Answer": "coconut" + }, + { + "Category": "FAMILIAR PHRASES", + "Question": "William Congreve expounded, \"heav'n has no rage, like love to hatred turn'd, nor hell a fury like\" this", + "Answer": "a woman scorned" + }, + { + "Category": "LARRY KING'S PUBLIC FIGURES", + "Question": "He was 77 when he returned to space in '98; he talks to us now via satellite from Ohio", + "Answer": "John Glenn" + }, + { + "Category": "DRIVING", + "Question": "\"Multitudinous\" name for this part of the car that transmits gases from the cylinders to the exhaust pipe", + "Answer": "exhaust manifold" + }, + { + "Category": "MICHAEL JACKSON HITS IN OTHER WORDS", + "Question": "1982: \"Said Female Belongs To Me\"", + "Answer": "\"The Girl Is Mine\"" + }, + { + "Category": "EXPORTS", + "Question": "In ancient times, the most famous export of the Phoenician town of Byblos to Greece was this material", + "Answer": "papyrus" + }, + { + "Category": "FAMILIAR PHRASES", + "Question": "This phrase meaning \"to betray someone\" came from slaves sent illegally via the Mississippi to New Orleans", + "Answer": "to sell them down the river" + }, + { + "Category": "OOH... A WISE GUY", + "Question": "Therefore it's this 17th century mathematician and philosopher--I think", + "Answer": "Descartes" + }, + { + "Category": "WONDER DRUGS", + "Question": "Humulin used by diabetics is short for \"human\" this", + "Answer": "insulin" + }, + { + "Category": "DON'T MESS WITH SICILY", + "Question": "At nearly 11,000 feet this \"active\" spot is Sicily's highest point", + "Answer": "Mount Etna" + }, + { + "Category": "DIRECTED BUT DID NOT STAR", + "Question": "\"Ordinary People\" (1980)", + "Answer": "Robert Redford" + }, + { + "Category": "PRESIDENTIAL FINAL MOMENTS", + "Question": "He shuffled off this mortal coil in Warm Springs, GA from a cerebral hemorrhage", + "Answer": "FDR" + }, + { + "Category": "LONG GERMAN WORDS", + "Question": "The Reinheitsgebot is the law of 1516 governing the purity of this 4-letter drink", + "Answer": "beer" + }, + { + "Category": "OOH... A WISE GUY", + "Question": "Peachy thoughts from this uber philosopher include \"God is Dead\" & \"Is Man only a blunder of God?\"", + "Answer": "Nietzsche" + }, + { + "Category": "WONDER DRUGS", + "Question": "Football coach & triple-bypass patient Dan Reeves advertises Zocar, which mainly aims to lower this", + "Answer": "cholesterol" + }, + { + "Category": "DON'T MESS WITH SICILY", + "Question": "Sicily was ceded to the Romans in 241 B.C. after they won the first of these wars", + "Answer": "Punic" + }, + { + "Category": "DIRECTED BUT DID NOT STAR", + "Question": "\"Apollo 13\" (1995)", + "Answer": "Ron Howard" + }, + { + "Category": "PRESIDENTIAL FINAL MOMENTS", + "Question": "His passing came in Buffalo, New York from gunshot wounds", + "Answer": "McKinley" + }, + { + "Category": "LONG GERMAN WORDS", + "Question": "Freude is this to which Beethoven composed an ode; Schadenfreude is this at someone else's misfortune", + "Answer": "joy" + }, + { + "Category": "OOH... A WISE GUY", + "Question": "The writings of this man seen here were truly Revolutionary", + "Answer": "Karl Marx" + }, + { + "Category": "WONDER DRUGS", + "Question": "Adult migraine? Ease the throbbing with 200 milligrams of this", + "Answer": "ibuprofen" + }, + { + "Category": "DON'T MESS WITH SICILY", + "Question": "The father of this US Supreme Court Justice was a romance language professor who had emigrated from Sicily", + "Answer": "Scalia" + }, + { + "Category": "DIRECTED BUT DID NOT STAR", + "Question": "\"Midnight in the Garden of Good & Evil\" (1997)", + "Answer": "Clint Eastwood" + }, + { + "Category": "PRESIDENTIAL FINAL MOMENTS", + "Question": "He died in the White House, from pneumonia", + "Answer": "Harrison" + }, + { + "Category": "LONG GERMAN WORDS", + "Question": "A bildungsroman is this type of work covering a young hero's development", + "Answer": "novel" + }, + { + "Category": "OOH... A WISE GUY", + "Question": "He coined the term \"utopia\" now meaning \"an ideal place\" & used it for the title of a 1516 satire", + "Answer": "Thomas More" + }, + { + "Category": "WONDER DRUGS", + "Question": "The arthritis medicine lodine is an NSAID, a non-steroidal anti-this drug", + "Answer": "inflammatory" + }, + { + "Category": "DON'T MESS WITH SICILY", + "Question": "Heading west to Sicily from Calabria, Italy will take you \"strait\" to this port city of 263,000", + "Answer": "Messina" + }, + { + "Category": "DIRECTED BUT DID NOT STAR", + "Question": "\"Rachel, Rachel\" (1968)", + "Answer": "Paul Newman" + }, + { + "Category": "PRESIDENTIAL FINAL MOMENTS", + "Question": "The end finally came for this Pres. in Elberon, New Jersey from blood posioning after being shot", + "Answer": "Garfield" + }, + { + "Category": "LONG GERMAN WORDS", + "Question": "Sauerbraten is literally \"sour roast\"; this is literally \"roast sausage\"", + "Answer": "Bratwurst" + }, + { + "Category": "OOH... A WISE GUY", + "Question": "By pure reason you should know he's the categorical German seen here", + "Answer": "Immanuel Kant" + }, + { + "Category": "WONDER DRUGS", + "Question": "Chlorpromazine, aka this, was approved by the FDA in 1954 & became the prototype antipsychotic", + "Answer": "thorazine" + }, + { + "Category": "DIRECTED BUT DID NOT STAR", + "Question": "\"Cradle Will Rock\" (1999)", + "Answer": "Tim Robbins" + }, + { + "Category": "PRESIDENTIAL FINAL MOMENTS", + "Question": "The 2nd Prez to die in the White House, he was felled by acute indigestion (or was it poison?)", + "Answer": "Zachary Taylor" + }, + { + "Category": "LONG GERMAN WORDS", + "Question": "Bismarck & Kissinger are among masters of this, politics based on pragmatic concerns", + "Answer": "Realpolitik" + }, + { + "Category": "FAMOUS PEOPLE", + "Question": "In 2001, she produced & hosted the Travel Channel's \"Secrets of San Simeon\"", + "Answer": "Patty Hearst" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "In February 1865, 2 months before surrendering, he became general in chief of all the Confederate armies", + "Answer": "Robert E. Lee" + }, + { + "Category": "FEMALE ATHLETES", + "Question": "This soccer player whose real first name is Mariel is one of 4 women to have scored over 100 goals in international play", + "Answer": "Mia Hamm" + }, + { + "Category": "WEBSITES", + "Question": "An official website for this state is www.state.nm.us", + "Answer": "New Mexico" + }, + { + "Category": "___ OG", + "Question": "Hey, \"don't just sit there like a bump on\" one of these", + "Answer": "a log" + }, + { + "Category": "ENDLESS SUMER", + "Question": "The Sumerian name for the Mesopotamian plain may have given us this name of a Biblical garden", + "Answer": "Eden" + }, + { + "Category": "VACATION FUN", + "Question": "Watch out for sewer rats inside the \"Sewer Adventure\" at the Aquaria Water Museum in this Swedish capital", + "Answer": "Stockholm" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "It was the famous nickname of frontiersman & scout Christopher Carson", + "Answer": "Kit" + }, + { + "Category": "FEMALE ATHLETES", + "Question": "This track star was nicknamed \"Flo-Jo\"", + "Answer": "Florence Griffith-Joyner" + }, + { + "Category": "WEBSITES", + "Question": "Instead of .com, Amnesty International's website is www.amnesty. this", + "Answer": ".org" + }, + { + "Category": "___ OG", + "Question": "\"Pea Soup\" describes a dense one", + "Answer": "fog" + }, + { + "Category": "ENDLESS SUMER", + "Question": "Utu, who judged the dead at the end of each day, was the Sumerian god of this celestial body", + "Answer": "sun" + }, + { + "Category": "VACATION FUN", + "Question": "Ride the Nutmobile thru macadamia orchards at the Big Pineapple, a top attraction in this \"Down Under\" country", + "Answer": "Australia" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "Dismissed from West Point for \"deficiency in chemistry\", he went on to paint a famous portrait of his mother", + "Answer": "James Whistler" + }, + { + "Category": "FEMALE ATHLETES", + "Question": "A student at Great Neck North High School, she's the golden girl of the ice seen here", + "Answer": "Sarah Hughes" + }, + { + "Category": "WEBSITES", + "Question": "At whitehouse.gov you can learn all about Air Force One as well as this Maryland presidential retreat", + "Answer": "Camp David" + }, + { + "Category": "___ OG", + "Question": "One of the teeth in a gear", + "Answer": "cog" + }, + { + "Category": "ENDLESS SUMER", + "Question": "The ancient Sumerian civilization flourished in the \"Fertile Crescent\" region between these 2 rivers", + "Answer": "Tigris & Euphrates" + }, + { + "Category": "VACATION FUN", + "Question": "Wow! You can see what you'd look like in one of Ms. Parton's wigs at this theme park named for her", + "Answer": "Dollywood" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "Her appointment to the Supreme Court in 1981 to replace Potter Stewart was history-making", + "Answer": "Sandra Day O'Connor" + }, + { + "Category": "FEMALE ATHLETES", + "Question": "This tennis player won women's singles titles at Wimbledon in 2000 & 2001, but lost to her little sister in 2002", + "Answer": "Venus Williams" + }, + { + "Category": "WEBSITES", + "Question": "Seen here, Arfie fetches results at this metasearch engine", + "Answer": "Dogpile" + }, + { + "Category": "___ OG", + "Question": "Something can do this to your bad memory; it's also a wheel on a Sony Clie", + "Answer": "jog" + }, + { + "Category": "ENDLESS SUMER", + "Question": "Dating from around 3000 B.C., the Sumerians used this writing system seen here", + "Answer": "cuneiform" + }, + { + "Category": "VACATION FUN", + "Question": "For a fabulous view of Barcelona, take the elevator to the top of the Monument a Colom, built to honor him", + "Answer": "Christopher Columbus" + }, + { + "Category": "FAMOUS AMERICANS", + "Question": "In one of its reading rooms, you can read up on Mary Baker Eddy, the founder of this religion", + "Answer": "Christian Science" + }, + { + "Category": "FEMALE ATHLETES", + "Question": "This basketball star whose name rhymes with hoops named her son Jordan, after Michael Jordan", + "Answer": "Sheryl Swoopes" + }, + { + "Category": "WEBSITES", + "Question": "\"Sari Says\" is an advice column in the online version of this teen magazine", + "Answer": "Teen People" + }, + { + "Category": "___ OG", + "Question": "A fad in the '90s was this game from Hawaii that used bottle stoppers", + "Answer": "pogs" + }, + { + "Category": "ENDLESS SUMER", + "Question": "The Sumerian kingdom ended when this enemy king famous for his code conquered the city of Larsa", + "Answer": "Hammurabi" + }, + { + "Category": "VACATION FUN", + "Question": "Soar above the treetops on the Skyfari aerial tram at this West Coast's city's famous zoo", + "Answer": "San Diego" + }, + { + "Category": "BALLET", + "Question": "The ballet \"Jeu de Cartes\" features dancing playing cards, & this one is the \"trickster\" of the pack", + "Answer": "the joker" + }, + { + "Category": "COMIC & CARTOON CRITTERS", + "Question": "Alvin, Simon & Theodore", + "Answer": "chipmunks" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "\"Swing your partner\" & \"do-si-do\"; it's the state dance of Oregon & Alabama", + "Answer": "square dance" + }, + { + "Category": "ALL IN YOUR MIND", + "Question": "You can have a deja entendu, meaning \"already heard\" in addition to this, \"already seen\"", + "Answer": "deja vu" + }, + { + "Category": "SCIENCE CLASS", + "Question": "(Cheryl of the Clue Crew reports from Colorado) As snowflakes are frozen water vapor, they're made up of these 2 chemical elements", + "Answer": "hydrogen & oxygen" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This car name may come from an abbreviation of \"general purpose vehicle\"", + "Answer": "jeep" + }, + { + "Category": "BALLET", + "Question": "The longer \"romantic\" version of this ballet garment was inspired by the one Taglioni wore in the 1830s", + "Answer": "tutu" + }, + { + "Category": "COMIC & CARTOON CRITTERS", + "Question": "Heathcliff", + "Answer": "cat" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "Its state song is \"The Old North State\"", + "Answer": "North Carolina" + }, + { + "Category": "ALL IN YOUR MIND", + "Question": "Some people won't give blood due to belonephobia, fear of these", + "Answer": "needles" + }, + { + "Category": "SCIENCE CLASS", + "Question": "The forked type of this runs unobstructed between the clouds & the ground", + "Answer": "lightning" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "The name of this social insect comes from the Latin word vespa", + "Answer": "wasp" + }, + { + "Category": "BALLET", + "Question": "A ballet blanc, such as \"La Sylphide\", traditionally features costumes of this color", + "Answer": "white" + }, + { + "Category": "COMIC & CARTOON CRITTERS", + "Question": "Pumbaa", + "Answer": "warthog" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "If you \"Show Me\" some mozarkite, I'll tell you that it's this state's state rock", + "Answer": "Missouri" + }, + { + "Category": "ALL IN YOUR MIND", + "Question": "This measurement was originally measured by dividing mental age by calendar age", + "Answer": "IQ" + }, + { + "Category": "SCIENCE CLASS", + "Question": "(Sofia of the Clue Crew reports from New York's Central Park) Autumn leaves turn golden red as shorter days & cooler nights cause the breakdown of this green pigment", + "Answer": "chlorophyll" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This adjective can mean extremely ornate or refer to the music from 1600 to 1750, including that of Vivaldi & Handel", + "Answer": "Baroque" + }, + { + "Category": "BALLET", + "Question": "From the French meaning \"to bend\", this basic bending movement prepares a dancer to spring high into the air", + "Answer": "plie" + }, + { + "Category": "COMIC & CARTOON CRITTERS", + "Question": "Babar", + "Answer": "elephant" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "This \"sweet\" state tree of Vermont is an important source of syrup", + "Answer": "sugar maple" + }, + { + "Category": "ALL IN YOUR MIND", + "Question": "By definition, a hypnagogic hallucination occurs while you're about to do this", + "Answer": "fall asleep" + }, + { + "Category": "SCIENCE CLASS", + "Question": "The frequency of a note is measured in this, abbreviated Hz", + "Answer": "hertz" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This process is the diffusion of a fluid through a semipermeable membrane; some students seem to learn by it", + "Answer": "osmosis" + }, + { + "Category": "BALLET", + "Question": "French sculptor whose art inspired \"The Eternal Idol\" (hmmm...that's a \"Thinker\")", + "Answer": "Auguste Rodin" + }, + { + "Category": "COMIC & CARTOON CRITTERS", + "Question": "Franklin on Nickelodeon", + "Answer": "turtle" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "The juice of this bog fruit is Massachusetts' state beverage", + "Answer": "cranberry" + }, + { + "Category": "ALL IN YOUR MIND", + "Question": "Erik Erikson's concept of this type of \"crisis\", in which you're not sure who you are, is associated with adolescence", + "Answer": "identity crisis" + }, + { + "Category": "SCIENCE CLASS", + "Question": "(Sofia of the Clue Crew reports) Botanists divide a flower into four main parts: sepals, petals, stamens & these", + "Answer": "pistils" + }, + { + "Category": "IN THE DICTIONARY", + "Question": "This word used to describe a type of school also means \"narrow in outlook\"", + "Answer": "parochial" + }, + { + "Category": "FIRST NAMES", + "Question": "Once considered too sacred to use, it was later the top girl's name from 1880 to the 1940s", + "Answer": "Mary" + }, + { + "Category": "THE NATIONAL PARK SYSTEM", + "Question": "To oversimplify, it's a really big hole in the ground in Arizona--1 mile deep & 277 river miles long", + "Answer": "the Grand Canyon" + }, + { + "Category": "OSCAR WINNERS & NOMINEES ON TV", + "Question": "This Oscar winner for \"The Piano\" plays a feisty Oklahoma City police detective on TNT's \"Saving Grace\"", + "Answer": "Holly Hunter" + }, + { + "Category": "ALLUSIONAL THINKING", + "Question": "Someone compared to this Aesop kid has lied so many times no one believes him even when he's telling the truth", + "Answer": "the boy who cried wolf" + }, + { + "Category": "47", + "Question": "The heavenly strains of the concert grand pedal type of this instrument come from its 47 strings", + "Answer": "a harp" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "Neckwear for eating lobster", + "Answer": "bib" + }, + { + "Category": "OSCAR WINNERS & NOMINEES ON TV", + "Question": "Although he lost the supporting actor Oscar for \"Cinderella Man\", he won the Emmy vote for \"John Adams\"", + "Answer": "Paul Giamatti" + }, + { + "Category": "ALLUSIONAL THINKING", + "Question": "If you're slow but steady & you still beat a sprinter, you might be compared to this creature of fable", + "Answer": "a turtle" + }, + { + "Category": "47", + "Question": "This unit of measure is equal to .47 liters; drink up!", + "Answer": "a pint" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "It can be a small facility for outpatient care, or a whole medical establishment run by specialists", + "Answer": "a clinic" + }, + { + "Category": "THE NATIONAL PARK SYSTEM", + "Question": "Check out the glistening dunes at White Sands National Monument in this state", + "Answer": "New Mexico" + }, + { + "Category": "OSCAR WINNERS & NOMINEES ON TV", + "Question": "This 5-time Oscar nominee played captain Monica Rawling for a season on \"The Shield\"", + "Answer": "Glenn Close" + }, + { + "Category": "ALLUSIONAL THINKING", + "Question": "A small person who goes up against a bigger opponent & wins evokes the story of these 2 Valley of Elah foes", + "Answer": "David & Goliath" + }, + { + "Category": "47", + "Question": "These 2 tropic lines, north & south of the equator, are 47 degrees apart", + "Answer": "Cancer & Capricorn" + }, + { + "Category": "THE NATIONAL PARK SYSTEM", + "Question": "Celebrating \"a century of sanctuary\" in 2009, it's Utah's first national park, though it's last alphabetically", + "Answer": "Zion" + }, + { + "Category": "OSCAR WINNERS & NOMINEES ON TV", + "Question": "Executive producer of \"Ugly Betty\", she has also guest starred as Sofia Reyes", + "Answer": "Salma Hayek" + }, + { + "Category": "ALLUSIONAL THINKING", + "Question": "The allusion \"ships that pass in the night\" is from this American poet's \"Tales of a Wayside Inn\"", + "Answer": "Longfellow" + }, + { + "Category": "47", + "Question": "You deserve a medal if you know that this element, symbol Ag, is No. 47 on the periodic table", + "Answer": "silver" + }, + { + "Category": "OSCAR WINNERS & NOMINEES ON TV", + "Question": "\"An Unmarried Woman\" in the movies, she played Donald Sutherland's wife Letitia on \"Dirty Sexy Money\"", + "Answer": "Jill Clayburgh" + }, + { + "Category": "ALLUSIONAL THINKING", + "Question": "Your vulnerability might be compared to this body part of an ancient Greek hero who killed Hector", + "Answer": "an Achilles' heel" + }, + { + "Category": "47", + "Question": "The Pythagorean theorem is the 47th proposition in the first book of his \"Elements\"", + "Answer": "Euclid" + }, + { + "Category": "CODES", + "Question": "The first 5 digits in these represent the manufacturer; 16000 means General Mills", + "Answer": "a bar code" + }, + { + "Category": "FACTS & FIGURES", + "Question": "There are 88 of these, which run alphabetically from Andromeda to Vulpecula", + "Answer": "constellations" + }, + { + "Category": "THE '30s WEREN'T ALL DEPRESSING", + "Question": "In April 1930 the first 3 mysteries involving her were published & became an instant success", + "Answer": "Nancy Drew" + }, + { + "Category": "...& THE HORSE YOU RODE IN ON!", + "Question": "Noted for their \"feathery\" legs, these Scottish draft horses were taken to North America in 1842, Bud", + "Answer": "Clydesdales" + }, + { + "Category": "OH, BEE GEE", + "Question": "Barry Gibb was born in 1946; these 2 fraternal twins were born in 1949", + "Answer": "Robin & Maurice" + }, + { + "Category": "\"YN\"", + "Question": "A Jewish house of worship", + "Answer": "a synagogue" + }, + { + "Category": "CODES", + "Question": "In \"A Christmas Story\", the message Ralphie uncovers using his decoder says \"Be sure to drink your\" this", + "Answer": "Ovaltine" + }, + { + "Category": "FACTS & FIGURES", + "Question": "Since 1970 the number of U.S. men aged 25-34 still living here has increased from 10% to 15%", + "Answer": "at home" + }, + { + "Category": "THE '30s WEREN'T ALL DEPRESSING", + "Question": "In 1938 DuPont made toothbrushes, not stockings, its first product with this material", + "Answer": "nylon" + }, + { + "Category": "...& THE HORSE YOU RODE IN ON!", + "Question": "Ex-welterweight champ Carlos, or a golden-coated, silver-maned horse", + "Answer": "a palomino" + }, + { + "Category": "OH, BEE GEE", + "Question": "Though never a Bee Gee, this other brother had 3 No. 1 singles & hosted \"Solid Gold\"", + "Answer": "Andy Gibb" + }, + { + "Category": "\"YN\"", + "Question": "A bird of the family Sturnidae, capable of mimicking human speech", + "Answer": "a mynah" + }, + { + "Category": "CODES", + "Question": "On Jan. 20, 2009 a military officer carrying these codes came to the inauguration with Bush & left with Obama", + "Answer": "the codes to release nuclear warheads" + }, + { + "Category": "FACTS & FIGURES", + "Question": "Researchers have found more than 40,000 of the dust type of these microscopic bugs in 1 ounce of mattress dust", + "Answer": "mites" + }, + { + "Category": "THE '30s WEREN'T ALL DEPRESSING", + "Question": "In 1936 Los Angeles started receiving its electricity from generators at this facility", + "Answer": "Hoover Dam" + }, + { + "Category": "...& THE HORSE YOU RODE IN ON!", + "Question": "In the 17th century this type of wild horse numbered between 2 & 4 mil.; today, only about 20,000 remain, mostly in the West", + "Answer": "mustangs" + }, + { + "Category": "\"YN\"", + "Question": "A skeptic, or one of a Greek sect who espoused that virtue is the only good", + "Answer": "a cynic" + }, + { + "Category": "CODES", + "Question": "1968's Nobel Prize in Medicine was for \"interpretation of\" this \"code and its function in protein synthesis\"", + "Answer": "the genetic code" + }, + { + "Category": "FACTS & FIGURES", + "Question": "Got this river? It flows more than 600 miles through Alberta & Montana before entering the Missouri", + "Answer": "the Milk" + }, + { + "Category": "THE '30s WEREN'T ALL DEPRESSING", + "Question": "In 1932 this country finished reclaiming thousands of agricultural acres from the Zuiderzee", + "Answer": "the Netherlands" + }, + { + "Category": "...& THE HORSE YOU RODE IN ON!", + "Question": "1 tale says this breed descends from Muhammad's horses that refused water to answer a battle call", + "Answer": "Arabians" + }, + { + "Category": "\"YN\"", + "Question": "The bobcat is also known as the bay this animal", + "Answer": "a lynx" + }, + { + "Category": "FACTS & FIGURES", + "Question": "A pen with 1,400 diamonds depicting a mountain range was created in 2006 to celebrate this company's 100th anniversary", + "Answer": "Montblanc" + }, + { + "Category": "THE '30s WEREN'T ALL DEPRESSING", + "Question": "In 1939 Edwin Armstrong built the first full-scale station for this type of commercially used radio transmission", + "Answer": "FM" + }, + { + "Category": "...& THE HORSE YOU RODE IN ON!", + "Question": "This \"stately\" horse has 3 gaits; the flat-foot walk, the running walk & the canter", + "Answer": "the Tennessee walking horse" + }, + { + "Category": "OH, BEE GEE", + "Question": "In a Bee Gees hit, this title sort of communication means \"you're telling me lies\"", + "Answer": "jive talkin'" + }, + { + "Category": "\"YN\"", + "Question": "In music, to place accents on beats that are normally unaccented", + "Answer": "syncopated" + }, + { + "Category": "THE PARTS OF SPEECH", + "Question": "Of the traditional 8 parts of speech, it's the only one that doesn't end in the same 4 letters as 1 of the other parts of speech", + "Answer": "adjective" + }, + { + "Category": "LOCATION, LOCATION, LOCATION", + "Question": "Suisse is the French name for this mountainous country", + "Answer": "Switzerland" + }, + { + "Category": "HORSE & RIDER", + "Question": "Silver", + "Answer": "The Lone Ranger" + }, + { + "Category": "THE MOVIES", + "Question": "The first episode in the story told by this popular film series is subtitled \"The Phantom Menace\"", + "Answer": "Star Wars" + }, + { + "Category": "SLOGANEERING", + "Question": "When going out, take this card because \"It's Everywhere You Want to Be\"", + "Answer": "Visa" + }, + { + "Category": "FIRST LADIES", + "Question": "She married husband Ronnie in 1952 when he was president of the Screen Actors Guild", + "Answer": "NancyReagan" + }, + { + "Category": "PRIME NUMBERS", + "Question": "Dial this 3-digit prime number in L.A. only for emergencies", + "Answer": "911" + }, + { + "Category": "LOCATION, LOCATION, LOCATION", + "Question": "Washington Irving gave New York City this nickname in 1807", + "Answer": "Gotham" + }, + { + "Category": "HORSE & RIDER", + "Question": "Rocinante", + "Answer": "Don Quixote" + }, + { + "Category": "THE MOVIES", + "Question": "It was double trouble for this martial arts star playing twins in \"Twin Dragons\"", + "Answer": "Jackie Chan" + }, + { + "Category": "SLOGANEERING", + "Question": "If you need a hammer, this is \"The Place With the Helpful Hardware Folks\"", + "Answer": "Ace Hardware" + }, + { + "Category": "FIRST LADIES", + "Question": "She served as a regent of the University of Texas & as a member of the National Parks Advisory Board", + "Answer": "Lady Bird Johnson" + }, + { + "Category": "PRIME NUMBERS", + "Question": "In the rhyme, it's the number of whacks Lizzie Borden gave her father", + "Answer": "41" + }, + { + "Category": "LOCATION, LOCATION, LOCATION", + "Question": "There are only 31 states & 1 federal district in this North American country", + "Answer": "Mexico" + }, + { + "Category": "HORSE & RIDER", + "Question": "Trigger's friend Buttermilk", + "Answer": "Dale Evans" + }, + { + "Category": "THE MOVIES", + "Question": "It was double trouble for this martial arts star playing twins in \"Double Impact\"", + "Answer": "Jean-Claude Van Damme" + }, + { + "Category": "SLOGANEERING", + "Question": "\"The Relentless Pursuit of Perfection\" is the goal of this automaker", + "Answer": "Lexus" + }, + { + "Category": "FIRST LADIES", + "Question": "In January 1991 this first lady broke her left leg while sledding at Camp David", + "Answer": "Barbara Bush" + }, + { + "Category": "PRIME NUMBERS", + "Question": "Columbus' first voyage to the new world ended in this year", + "Answer": "1493" + }, + { + "Category": "LOCATION, LOCATION, LOCATION", + "Question": "The Tasman Sea separates Australia & this nation", + "Answer": "New Zealand" + }, + { + "Category": "HORSE & RIDER", + "Question": "Traveller", + "Answer": "Robert E. Lee" + }, + { + "Category": "THE MOVIES", + "Question": "Known for comedies like \"Mr. Mom\", he donned the cape & cowl of Batman in 1989", + "Answer": "Michael Keaton" + }, + { + "Category": "SLOGANEERING", + "Question": "This large company provides \"Solutions For A Small Planet\"", + "Answer": "IBM" + }, + { + "Category": "FIRST LADIES", + "Question": "Her stepfather was Hugh Auchincloss", + "Answer": "Jackie Kennedy" + }, + { + "Category": "PRIME NUMBERS", + "Question": "Fear of this prime number is called triskaidekaphobia", + "Answer": "13" + }, + { + "Category": "LOCATION, LOCATION, LOCATION", + "Question": "Robin Hood's nemesis was the sheriff of this district", + "Answer": "Nottingham" + }, + { + "Category": "HORSE & RIDER", + "Question": "Bucephalus", + "Answer": "Alexander the Great" + }, + { + "Category": "THE MOVIES", + "Question": "She turned pirate in \"Cutthroat Island\" & action star in \"The Long Kiss Goodnight\"", + "Answer": "Geena Davis" + }, + { + "Category": "SLOGANEERING", + "Question": "Relax, this brand of medicine is \"Recommended by Dr. Mom\"", + "Answer": "Robitussin" + }, + { + "Category": "FIRST LADIES", + "Question": "The only first lady whose married name was the same as her maiden name", + "Answer": "Eleanor Roosevelt" + }, + { + "Category": "PRIME NUMBERS", + "Question": "Boeing's answer in the early 1960s to the Douglas DC-9; it's good for medium hauls", + "Answer": "727" + }, + { + "Category": "DEMOCRATIC KEYNOTERS", + "Question": "1992: New Jersey senator", + "Answer": "Bill Bradley" + }, + { + "Category": "THE ASPCA", + "Question": "In 1999 Lulu, a plucky potbellied one of these, earned an ASPCA Trooper Award for saving her owner's life", + "Answer": "Pig" + }, + { + "Category": "ON BROADWAY: 1970", + "Question": "He starred on Broadway as Elwood P. Dowd in a revival of \"Harvey\"; who else could?", + "Answer": "Jimmy Stewart" + }, + { + "Category": "BOTANY", + "Question": "To the horror of homeowners, this lawn weed, taraxacum officinale, can grow 1 1/2' high", + "Answer": "Dandelion" + }, + { + "Category": "I HAVEN'T READ SHAKESPEARE, BUT...", + "Question": "This tragedy has got to be set in a small village, hence the title", + "Answer": "Hamlet" + }, + { + "Category": "WORD ORIGINS", + "Question": "Derived from the Greek for \"ice\", it's a glass of fine quality that resembles ice", + "Answer": "Crystal" + }, + { + "Category": "DEMOCRATIC KEYNOTERS", + "Question": "1984: New York governor", + "Answer": "Mario Cuomo" + }, + { + "Category": "THE ASPCA", + "Question": "An ASPCA program begun in 1992 promotes the adoption of these dogs when they retire from racing", + "Answer": "Greyhounds" + }, + { + "Category": "ON BROADWAY: 1970", + "Question": "Based on \"All About Eve\", it featured Lauren Bacall as Margo Channing", + "Answer": "Applause" + }, + { + "Category": "BOTANY", + "Question": "This \"kissing\" shrub, the state flower of Oklahoma, sometimes kills the tree that serves as its host", + "Answer": "Mistletoe" + }, + { + "Category": "I HAVEN'T READ SHAKESPEARE, BUT...", + "Question": "Obviously, it's a funny play about bad baseball players", + "Answer": "The Comedy of Errors" + }, + { + "Category": "WORD ORIGINS", + "Question": "Many scholars believe that the Celts called it \"The Wild Place\"; now this wild place is a city of over 7 million", + "Answer": "London" + }, + { + "Category": "DEMOCRATIC KEYNOTERS", + "Question": "1976: Ohio senator", + "Answer": "John Glenn" + }, + { + "Category": "THE ASPCA", + "Question": "The ASPCA reminds you that you can lengthen a cat's life by neutering a male or doing this equivalent to a female", + "Answer": "Spaying" + }, + { + "Category": "ON BROADWAY: 1970", + "Question": "Though he never won an Emmy as Barney Miller, he did win a Tony for his role in \"The Rothschilds\"", + "Answer": "Hal Linden" + }, + { + "Category": "BOTANY", + "Question": "The Jaffa variety of orange originated in this country", + "Answer": "Israel" + }, + { + "Category": "I HAVEN'T READ SHAKESPEARE, BUT...", + "Question": "It sounds to me like it's about the leader of lascivious oglers", + "Answer": "King Lear" + }, + { + "Category": "WORD ORIGINS", + "Question": "A Middle Eastern chieftain, this 4-letter term is from the Arabic for \"commander\"", + "Answer": "Emir" + }, + { + "Category": "DEMOCRATIC KEYNOTERS", + "Question": "1968: Hawaiian senator", + "Answer": "Daniel Inouye" + }, + { + "Category": "THE ASPCA", + "Question": "In 1867 the ASPCA began operating the world's first of these vehicles to carry horses, probably without a siren", + "Answer": "Ambulance" + }, + { + "Category": "ON BROADWAY: 1970", + "Question": "Anthony Quayle & Keith Baxter starred in this Anthony Shaffer mystery; the rest of the cast is another mystery", + "Answer": "Sleuth" + }, + { + "Category": "BOTANY", + "Question": "The jonquil is a short-trumpet narcissus; this yellow flower is a long-trumpet species", + "Answer": "Daffodil" + }, + { + "Category": "I HAVEN'T READ SHAKESPEARE, BUT...", + "Question": "It's about this guy who hires non-permanent secretarial help for his office", + "Answer": "The Tempest" + }, + { + "Category": "WORD ORIGINS", + "Question": "This wooden club is named for the town in county Wicklow where it originated", + "Answer": "Shillelagh" + }, + { + "Category": "DEMOCRATIC KEYNOTERS", + "Question": "1988: Texas state treasurer", + "Answer": "Ann Richards" + }, + { + "Category": "THE ASPCA", + "Question": "The ASPCA helped stop Iowa legislators from legalizing hunting of the mourning type of this", + "Answer": "Dove" + }, + { + "Category": "ON BROADWAY: 1970", + "Question": "After 2,844 performances, Broadway said, \"So long, dearie\" to this musical December 27, 1970", + "Answer": "Hello, Dolly!" + }, + { + "Category": "BOTANY", + "Question": "The finest dried form of this root spice used in pumpkin pie is produced in Jamaica", + "Answer": "Ginger" + }, + { + "Category": "I HAVEN'T READ SHAKESPEARE, BUT...", + "Question": "Toyotas! Yeah, that's it; it's about Toyotas", + "Answer": "Troilus & Cressida" + }, + { + "Category": "WORD ORIGINS", + "Question": "A Greek word for cowherd has given us this term for \"pastoral\" or \"rustic\"", + "Answer": "bucolic" + }, + { + "Category": "THE FUNNIES", + "Question": "Debuting November 18, 1985, the caption in its first box was \"So long, Pop! I'm off to check my tiger trap!\"", + "Answer": "Calvin and Hobbes" + }, + { + "Category": "U.S. CITIES", + "Question": "Its nicknames include \"The Athens of America\" & \"The Cradle of Liberty\"", + "Answer": "Boston" + }, + { + "Category": "ROLLING STONE'S 100 GREATEST GUITARISTS", + "Question": "Who was No. 50? This Who guitarist, that's who", + "Answer": "Pete Townshend" + }, + { + "Category": "THE LENIN CLOSET", + "Question": "Lenin got a degree in this in 1891, then went on to court a lot of trouble", + "Answer": "law" + }, + { + "Category": "POTPOURRI", + "Question": "In 2001 Sweden & the U.S. honored this award's 100th anniversary with a set of postage stamps", + "Answer": "the Nobel Prize" + }, + { + "Category": "MAGAZINES", + "Question": "As the old saying goes, \"An ounce of\" this magazine \"is worth a pound of cure\"", + "Answer": "Prevention" + }, + { + "Category": "ABBREVIATED", + "Question": "A \"green\" government group: EPA", + "Answer": "Environmental Protection Agency" + }, + { + "Category": "U.S. CITIES", + "Question": "When Oregon became a state in 1859, this city on the Willamette River was already the capital", + "Answer": "Salem" + }, + { + "Category": "ROLLING STONE'S 100 GREATEST GUITARISTS", + "Question": "Not surprisingly this legendary guitarist who colored the '60s with songs like \"Purple Haze\" came in at No. 1", + "Answer": "Jimi Hendrix" + }, + { + "Category": "THE LENIN CLOSET", + "Question": "Lenin met his wife Nadezhda while exiled here", + "Answer": "Siberia" + }, + { + "Category": "POTPOURRI", + "Question": "Select Comfort Corporation makes these with adjustable firmness", + "Answer": "mattresses" + }, + { + "Category": "MAGAZINES", + "Question": "In Nov. 2003 Judge Ira Gammerman said neither side would get damages from the demise of this celeb's magazine", + "Answer": "Rosie O'Donnell" + }, + { + "Category": "ABBREVIATED", + "Question": "High-ranking business operative: CFO", + "Answer": "chief financial officer" + }, + { + "Category": "U.S. CITIES", + "Question": "Benjamin Franklin Parkway & The Franklin Institute Science Museum are in this city", + "Answer": "Philadelphia" + }, + { + "Category": "ROLLING STONE'S 100 GREATEST GUITARISTS", + "Question": "It's said of No. 3, \"His string-bending & vibrato made his famous guitar, Lucille, weep like a real-life woman\"", + "Answer": "B.B. King" + }, + { + "Category": "THE LENIN CLOSET", + "Question": "When Russian Marxism split into 2 factions, Lenin led this \"majority\" group", + "Answer": "the Bolsheviks" + }, + { + "Category": "POTPOURRI", + "Question": "On an NHL rink, it's the color of the center line", + "Answer": "red" + }, + { + "Category": "MAGAZINES", + "Question": "For its Dec. 2003 issue, the U.S. Marie Claire put its first man on its cover, this star of \"The Last Samurai\"", + "Answer": "Tom Cruise" + }, + { + "Category": "ABBREVIATED", + "Question": "An international alliance: EU", + "Answer": "the European Union" + }, + { + "Category": "U.S. CITIES", + "Question": "According to a song by Ian Hunter, it \"Rocks\" (must be why the Rock & Roll Hall of Fame is there)", + "Answer": "Cleveland" + }, + { + "Category": "ROLLING STONE'S 100 GREATEST GUITARISTS", + "Question": "His \"Smooth\" guitar strains earned him a place at No. 15", + "Answer": "Carlos Santana" + }, + { + "Category": "THE LENIN CLOSET", + "Question": "Lenin spent WWI in this country, but he was far from neutral on the subject", + "Answer": "Switzerland" + }, + { + "Category": "POTPOURRI", + "Question": "In 2003 a nationwide Free Slurpee Day was on this date", + "Answer": "11-Jul" + }, + { + "Category": "MAGAZINES", + "Question": "In titles, this word follows Southern, Country & Martha Stewart", + "Answer": "Living" + }, + { + "Category": "ABBREVIATED", + "Question": "On an accountant's calendar: FY", + "Answer": "fiscal year" + }, + { + "Category": "U.S. CITIES", + "Question": "Located in this city's Garden District, Commander's Palace features a jazz brunch on weekends", + "Answer": "New Orleans" + }, + { + "Category": "ROLLING STONE'S 100 GREATEST GUITARISTS", + "Question": "Surprisingly, only 2 women made the list: Joni Mitchell & this leader of the Blackhearts", + "Answer": "Joan Jett" + }, + { + "Category": "THE LENIN CLOSET", + "Question": "When Lenin returned to Russia in 1917, he did it in a \"sealed\" one of these", + "Answer": "railway car" + }, + { + "Category": "POTPOURRI", + "Question": "This flower got its name from the belief that bees got a sweet substance out of it", + "Answer": "honeysuckle" + }, + { + "Category": "MAGAZINES", + "Question": "Marilyn Vos Savant's column appears in this magazine that comes with Sunday newspapers", + "Answer": "Parade Magazine" + }, + { + "Category": "ABBREVIATED", + "Question": "Sometimes you get extras with one of these: DVD", + "Answer": "digital video disc" + }, + { + "Category": "POETS", + "Question": "This \"Howl\" poet's father was also a poet & the 2 would perform public readings together", + "Answer": "Allen Ginsberg" + }, + { + "Category": "THE YEAR IN SPORTS", + "Question": "Bruce Jenner & Ray Leonard were American Olympic champs in this red, white & blue year", + "Answer": "1976" + }, + { + "Category": "FAMOUS JACQUES", + "Question": "His 1959 film \"The Golden Fish\" won him an Oscar", + "Answer": "Cousteau" + }, + { + "Category": "WORLD COINS", + "Question": "Its 1-shekel coin features a flower taken from a Judean coin during the Persian period", + "Answer": "Israel" + }, + { + "Category": "MEDICINE", + "Question": "A Pseudofolliculitis barbae is an \"ingrown\" one of these", + "Answer": "a hair" + }, + { + "Category": "\"SIDE\" EFFECTS", + "Question": "Manner assumed by good doctors", + "Answer": "bedside manner" + }, + { + "Category": "POETS", + "Question": "In 1953 his Norton Lectures at Harvard were published as \"i: six nonlectures\"", + "Answer": "Cummings" + }, + { + "Category": "THE YEAR IN SPORTS", + "Question": "It was the year of Babe Ruth's career high in home runs", + "Answer": "1927" + }, + { + "Category": "FAMOUS JACQUES", + "Question": "In 1995 he succeeded Francois Mitterand", + "Answer": "Jacques Chirac" + }, + { + "Category": "WORLD COINS", + "Question": "In 1999 the Cook Islands issued a half dollar coin featuring this Jim Davis comic strip title character", + "Answer": "Garfield" + }, + { + "Category": "MEDICINE", + "Question": "Adding these charged particles to the air is supposed to reduce blood pressure & relieve headaches", + "Answer": "negative ions" + }, + { + "Category": "\"SIDE\" EFFECTS", + "Question": "You can get an 18-pound collection of every one of these Gary Larson cartoons", + "Answer": "\"The Far Side\"" + }, + { + "Category": "POETS", + "Question": "She considered publishing \"Sonnets from the Portuguese\" as \"Sonnets Translated from the Bosnian\"", + "Answer": "ElizabethBrowning" + }, + { + "Category": "THE YEAR IN SPORTS", + "Question": "(Jimmy of the Clue Crew at Indianapolis Speedway) The Noc-Out Hose Clamp Special was the winning car at Indianapolis in this year; the race was cancelled the next 4 years", + "Answer": "1941" + }, + { + "Category": "FAMOUS JACQUES", + "Question": "Much of France's 16th century Canadian claim was based on his explorations", + "Answer": "Cartier" + }, + { + "Category": "WORLD COINS", + "Question": "In 1999 it issued its 1-oz. silver kookaburra coin with honor marks reproducing several U.S. state quarters", + "Answer": "Australia" + }, + { + "Category": "MEDICINE", + "Question": "Symbolized Ba, this element is put in your body, one way or another, to be seen on X-rays", + "Answer": "barium" + }, + { + "Category": "\"SIDE\" EFFECTS", + "Question": "A trial judge may call this conference with the attorneys, out of the jury's hearing", + "Answer": "sidebar" + }, + { + "Category": "POETS", + "Question": "After his death in 1821, a fellow poet wrote that he was fragile & was \"killed off by one critique\"", + "Answer": "Keats" + }, + { + "Category": "THE YEAR IN SPORTS", + "Question": "In this, his final year, Ted Williams became one of the few major leaguers to play in 4 decades", + "Answer": "1960" + }, + { + "Category": "FAMOUS JACQUES", + "Question": "He painted the death of Marat & he himself died in exile in Brussels", + "Answer": "Jacques-Louis David" + }, + { + "Category": "WORLD COINS", + "Question": "All of Ireland's coins feature this musical instrument on one side", + "Answer": "the harp" + }, + { + "Category": "MEDICINE", + "Question": "Yes, she developed a scoring system in 1952 to aid in determining a newborn's health", + "Answer": "Virginia Apgar" + }, + { + "Category": "\"SIDE\" EFFECTS", + "Question": "Economists also know it as Reaganomics", + "Answer": "supply-side economics" + }, + { + "Category": "POETS", + "Question": "In 1857 this \"Old Ironsides\" poet & others founded the Atlantic Monthly", + "Answer": "Oliver Wendell Holmes" + }, + { + "Category": "THE YEAR IN SPORTS", + "Question": "Super Bowl XXXVIII was in 2004; this was the year of Super Bowl I", + "Answer": "1967" + }, + { + "Category": "FAMOUS JACQUES", + "Question": "He composed both \"The Tales of Hoffmann\" & that scandalous \"Cancan\" music", + "Answer": "Offenbach" + }, + { + "Category": "WORLD COINS", + "Question": "In 2001 Russia issued a coin with his portrait to commemorate the 40th anniversary of manned space flight", + "Answer": "Yuri Gagarin" + }, + { + "Category": "MEDICINE", + "Question": "Nitroglycerin is an example of this type of drug that widens blood vessels", + "Answer": "vasodilator" + }, + { + "Category": "\"SIDE\" EFFECTS", + "Question": "Show that includes \"Comedy Tonight\", \"Company\" & \"Send in the Clowns\"", + "Answer": "Side by Side" + }, + { + "Category": "FAMOUS FELINES", + "Question": "He made his debut in the 1945 short film \"Life with Feathers\"", + "Answer": "Sylvester" + }, + { + "Category": "UNOFFICIAL STATE NICKNAMES", + "Question": "Because of the way it was formed, Louisiana is sometimes called \"The Child of\" this river", + "Answer": "Mississippi" + }, + { + "Category": "TV MOVIES", + "Question": "He played Tony Starr in \"Copacabana\", which was based on his own hit record", + "Answer": "Barry Manilow" + }, + { + "Category": "ARCHITECTURE", + "Question": "Many churches have a cruciform plan, which means they're shaped like one of these", + "Answer": "Cross" + }, + { + "Category": "KIDDIE LIT", + "Question": "\"Two Little Confederates\" is the story of two children who live on a plantation during this war", + "Answer": "Civil War" + }, + { + "Category": "ENDS WITH \"K\"", + "Question": "It's a slang term for a psychiatrist, even if he's not getting smaller", + "Answer": "Shrink" + }, + { + "Category": "POTPOURRI", + "Question": "Charles Schulz said Snoopy didn't become a lead character until he began walking this way", + "Answer": "on two feet" + }, + { + "Category": "UNOFFICIAL STATE NICKNAMES", + "Question": "It's \"The Land of the Saints\", the Latter-Day Saints", + "Answer": "Utah" + }, + { + "Category": "TV MOVIES", + "Question": "This series grew out of 1971's \"The Homecoming: A Christmas Story\"", + "Answer": "The Waltons" + }, + { + "Category": "ARCHITECTURE", + "Question": "A flight is a series of these unbroken by a landing", + "Answer": "stairs" + }, + { + "Category": "KIDDIE LIT", + "Question": "Chapter 4 of this 1908 classic is called \"Morning at Green Gables\"", + "Answer": "Anne of Green Gables" + }, + { + "Category": "ENDS WITH \"K\"", + "Question": "If you lack good fortune, you're out of this", + "Answer": "Luck" + }, + { + "Category": "POTPOURRI", + "Question": "It's a synonym for a lie as well as the type of tale told by Aesop", + "Answer": "Fable" + }, + { + "Category": "UNOFFICIAL STATE NICKNAMES", + "Question": "It's \"The Mother of States\" as well as \"The Mother of Presidents\"", + "Answer": "Virginia" + }, + { + "Category": "TV MOVIES", + "Question": "Arnold Schwarzenegger played Mickey Hargitay in a TV movie about this actress", + "Answer": "Jayne Mansfield" + }, + { + "Category": "ARCHITECTURE", + "Question": "One of these ancient Roman structures still carries the water supply of Segovia, Spain", + "Answer": "Aqueduct" + }, + { + "Category": "KIDDIE LIT", + "Question": "In a Grimm fairy tale one of these animals swallows six little kids, but luckily they escape", + "Answer": "Wolf" + }, + { + "Category": "ENDS WITH \"K\"", + "Question": "A snide, simpering, self-satisfied smile", + "Answer": "Smirk" + }, + { + "Category": "POTPOURRI", + "Question": "Any Brit can tell you that a Liverpudlian is one of these", + "Answer": "Someone from Liverpool" + }, + { + "Category": "UNOFFICIAL STATE NICKNAMES", + "Question": "It's \"The Plantation State\" because its full name includes the words \"And Providence Plantations\"", + "Answer": "Rhode Island" + }, + { + "Category": "TV MOVIES", + "Question": "The 1974 autobiography of this woman won 9 Emmy Awards, 2 for Cicely Tyson", + "Answer": "The Autobiography of Miss Jane Pittman" + }, + { + "Category": "ARCHITECTURE", + "Question": "In north Africa, these towers from which Muslims are called to prayer are rectangular in plan", + "Answer": "Minarets" + }, + { + "Category": "KIDDIE LIT", + "Question": "This Anna Sewell book may have inspired \"Moorland Mousie\", which was also narrated by a horse", + "Answer": "Black Beauty" + }, + { + "Category": "ENDS WITH \"K\"", + "Question": "A soda server, whether or not he's fatuous", + "Answer": "Jerk" + }, + { + "Category": "POTPOURRI", + "Question": "Persil is the French word for this ever-popular garnish", + "Answer": "Parsley" + }, + { + "Category": "UNOFFICIAL STATE NICKNAMES", + "Question": "It's also known as \"The Toothpick State\" because of a knife used by early settlers", + "Answer": "Arkansas" + }, + { + "Category": "TV MOVIES", + "Question": "She played Francine Hughes, who was accused of murdering her husband, in \"The Burning Bed\"", + "Answer": "Farrah Fawcett" + }, + { + "Category": "ARCHITECTURE", + "Question": "Gropius, Mies van der Rohe & this Swiss architect all worked for architect Peter Behrens", + "Answer": "Le Corbusier" + }, + { + "Category": "KIDDIE LIT", + "Question": "The first line of the early 19th century nursery rhyme whose original title was \"The Star\"", + "Answer": "\"Twinkle, Twinkle Little Star\"" + }, + { + "Category": "ENDS WITH \"K\"", + "Question": "This Asian capital city known for its canals has been called \"The Venice of the East\"", + "Answer": "Bangkok" + }, + { + "Category": "POTPOURRI", + "Question": "The national conference of these two religious groups sponsors Brotherhood-Sisterhood Week", + "Answer": "Christians and Jews" + }, + { + "Category": "PRESIDENTS", + "Question": "Speaking in Illinois, Benjamin Harrison said this president \"had faith in time & time has justified his faith\"", + "Answer": "Abraham Lincoln" + }, + { + "Category": "SORORITY WOMEN", + "Question": "Alpha Delta Pi Sandra Palmer is known for puttering around in this sport", + "Answer": "Golf" + }, + { + "Category": "DRAMA", + "Question": "This play begins as Willy Loman returns home from a trip", + "Answer": "Death of a Salesman" + }, + { + "Category": "WORLD HISTORY", + "Question": "This dominion was created by the British North America Act on July 1, 1867", + "Answer": "Canada" + }, + { + "Category": "INNS", + "Question": "Luke 2:7 reports that there was no room at the inn for this pair", + "Answer": "Mary & Joseph" + }, + { + "Category": "OATS", + "Question": "In 1877 Henry Seymour read about this religious group in an encyclopedia & named his oat company for them", + "Answer": "Quakers" + }, + { + "Category": "PRESIDENTS", + "Question": "Sammy Cahn wrote new lyrics for \"High Hopes\" & it became this man's 1960 campaign song", + "Answer": "John F. Kennedy" + }, + { + "Category": "SORORITY WOMEN", + "Question": "This Kappa Delta artist settled in New Mexico in 1949 because of the earth colors, the ochres & the reds", + "Answer": "Georgia O'Keeffe" + }, + { + "Category": "DRAMA", + "Question": "In Clifford Odets' \"Golden Boy\", Joe Bonaparte gives up the violin for this sport", + "Answer": "Boxing" + }, + { + "Category": "WORLD HISTORY", + "Question": "On May 9, 1946 this country's King Victor Emmanuel abdicated in favor of his son Umberto", + "Answer": "Italy" + }, + { + "Category": "INNS", + "Question": "The Chaucer Inn is located near the cathedral in this English city", + "Answer": "Canterbury" + }, + { + "Category": "OATS", + "Question": "This phrase refers to indulging in youthful excesses", + "Answer": "Sowing one's oats" + }, + { + "Category": "PRESIDENTS", + "Question": "It was the middle name of President Wilson & of his daughter Jessie", + "Answer": "Woodrow" + }, + { + "Category": "SORORITY WOMEN", + "Question": "Kappa Alpha Theta who danced in her own ballets including \"Rodeo\"", + "Answer": "Agnes de Mille" + }, + { + "Category": "DRAMA", + "Question": "Her 1946 play \"Another Part of the Forest\" is sometimes considered a prequel to \"The Little Foxes\"", + "Answer": "Lillian Hellman" + }, + { + "Category": "WORLD HISTORY", + "Question": "In 1763, as a result of this numerical war, Florida became a British possession", + "Answer": "Seven Years' War" + }, + { + "Category": "INNS", + "Question": "It was the first hotel Howard Hughes bought in Las Vegas", + "Answer": "Desert Inn" + }, + { + "Category": "OATS", + "Question": "It's a thick, pudding-like oatmeal dish that's enjoyed by Scots & by Goldilocks", + "Answer": "Porridge" + }, + { + "Category": "PRESIDENTS", + "Question": "Teddy Roosevelt sponsored the candidacy of this man in 1908 & ran against him in 1912", + "Answer": "William Howard Taft" + }, + { + "Category": "SORORITY WOMEN", + "Question": "When she began her financial column, this Phi Sigma Sigma used her initials to disguise her sex", + "Answer": "Sylvia Porter" + }, + { + "Category": "DRAMA", + "Question": "A brother & sister argue over the fate of a piano in this Pulitzer-winning play by August Wilson", + "Answer": "The Piano Lesson" + }, + { + "Category": "WORLD HISTORY", + "Question": "In 1864 Austria & Prussia went to war with Denmark, winning Schleswig & this duchy", + "Answer": "Holstein" + }, + { + "Category": "INNS", + "Question": "Gray's Inn is one of these associations that control admission to Britain's bar", + "Answer": "the Inns of Court" + }, + { + "Category": "OATS", + "Question": "Cereal lovers know it's the high-in-fiber outer casing of the oat", + "Answer": "Bran" + }, + { + "Category": "PRESIDENTS", + "Question": "The first president who wasn't born a British subject was this New Yorker", + "Answer": "Martin Van Buren" + }, + { + "Category": "SORORITY WOMEN", + "Question": "This Sigma Kappa is remembered as one of the first senators to speak out against Joseph McCarthy", + "Answer": "Margaret Chase Smith" + }, + { + "Category": "DRAMA", + "Question": "This lengthy work by Eugene O'Neill is based partly on the Oresteia of Aeschylus", + "Answer": "Mourning Becomes Electra" + }, + { + "Category": "WORLD HISTORY", + "Question": "In 1832 Otto, a Bavarian prince, was named the first king of this Balkan country", + "Answer": "Greece" + }, + { + "Category": "INNS", + "Question": "This 1936 Daphne du Maurier novel is one of her Cornish tales", + "Answer": "Jamaica Inn" + }, + { + "Category": "OATS", + "Question": "While the terms are used interchangeably, groats are usually more coarsely ground than these", + "Answer": "Grits" + }, + { + "Category": "WORD ORIGINS", + "Question": "The name of this dialect comes from a Hindi word, mantri, meaning \"counselor\"", + "Answer": "Mandarin" + }, + { + "Category": "IT BORDERS INDIA", + "Question": "Of the 6 nations India borders, this one is the most populous", + "Answer": "China" + }, + { + "Category": "CLASSIC ADS & JINGLES", + "Question": "It's \"finger lickin' good!\"", + "Answer": "Kentucky Fried Chicken" + }, + { + "Category": "OCCUPATIONS", + "Question": "Prep & line are types of this 4-letter job", + "Answer": "cook" + }, + { + "Category": "& CROWN THY GOOD", + "Question": "In 336 B.C. at age 20, he succeeded his murdered father as Macedonia's king & was just super...wait, that's not the right word", + "Answer": "Alexander the Great" + }, + { + "Category": "WITH BROTHERHOOD", + "Question": "Last name of Kevin, Joe & Nick, whose album \"Lines, Vines And Trying Times\" debuted at No. 1 in 2009", + "Answer": "Jonas" + }, + { + "Category": "FROM T TO SHINING T", + "Question": "On TV, apparently both America & Britain's \"Got\" this, a special natural ability", + "Answer": "talent" + }, + { + "Category": "IT BORDERS INDIA", + "Question": "The disputed ownership of the Kashmir region is a sore spot between India & this smaller neighbor", + "Answer": "Pakistan" + }, + { + "Category": "OCCUPATIONS", + "Question": "Of chairs, chicken or chinos, what you're most likely to haul if you drive a reefer truck", + "Answer": "chicken" + }, + { + "Category": "& CROWN THY GOOD", + "Question": "In 1696 this Russian czar conquered the Ottoman port of Azov on the Black Sea; awesome! Again the wrong word", + "Answer": "Peter the Great" + }, + { + "Category": "WITH BROTHERHOOD", + "Question": "Originally formed as a trio in Gary, Indiana in 1963, these singing siblings gained fame as a quintet", + "Answer": "the Jacksons" + }, + { + "Category": "FROM T TO SHINING T", + "Question": "It gains you admission to the ballgame; Yeah, that's the...", + "Answer": "ticket" + }, + { + "Category": "IT BORDERS INDIA", + "Question": "On its extreme east, India borders this nation that changed its name following a coup in 1989", + "Answer": "Myanmar" + }, + { + "Category": "CLASSIC ADS & JINGLES", + "Question": "\"Is it live or is it\" this?", + "Answer": "Memorex" + }, + { + "Category": "OCCUPATIONS", + "Question": "Broadly used, this term can include nurses & therapists, but it often refers just to emergency personnel", + "Answer": "paramedics" + }, + { + "Category": "& CROWN THY GOOD", + "Question": "In 1905 Haakon VII was chosen king by the people & parliament of this country after its separation from Sweden", + "Answer": "Norway" + }, + { + "Category": "WITH BROTHERHOOD", + "Question": "Twin brothers Matthew & Gunnar, Ozzie & Harriet's grandsons, had hits in the '90s under this name", + "Answer": "Nelson" + }, + { + "Category": "FROM T TO SHINING T", + "Question": "Proverbially, you can have one of these \"in a teacup\"", + "Answer": "a tempest" + }, + { + "Category": "IT BORDERS INDIA", + "Question": "The Ganges River flows through India into this neighbor, where it reaches the Bay Of Bengal", + "Answer": "Bangladesh" + }, + { + "Category": "CLASSIC ADS & JINGLES", + "Question": "\"The ultimate driving machine\"", + "Answer": "BMW" + }, + { + "Category": "OCCUPATIONS", + "Question": "A pro sports broadcasting duo consists of a play-by-play announcer & the analyst called this man", + "Answer": "a color commentator" + }, + { + "Category": "& CROWN THY GOOD", + "Question": "George I, king of this country from 1863 to 1913, supported a movement to revive the Olympics, abolished in 393", + "Answer": "Greece" + }, + { + "Category": "WITH BROTHERHOOD", + "Question": "2 motorcycle accidents, a year apart & 3 blocks from each other, claimed 2 lives of this \"Ramblin' Man\" band", + "Answer": "the Allman Brothers" + }, + { + "Category": "FROM T TO SHINING T", + "Question": "Elephants call each other with this instrument (but not literally, except maybe at Ringling Bros.)", + "Answer": "a trumpet" + }, + { + "Category": "IT BORDERS INDIA", + "Question": "This nation to India's north is also the only other nation with a Hindu population of more than 80%", + "Answer": "Nepal" + }, + { + "Category": "CLASSIC ADS & JINGLES", + "Question": "\"Solutions for a small planet\"", + "Answer": "IBM" + }, + { + "Category": "OCCUPATIONS", + "Question": "Someone employed in rousting game so it can be shot; he doesn't necessarily go \"around the bush\"", + "Answer": "a beater" + }, + { + "Category": "& CROWN THY GOOD", + "Question": "The heroic 480 B.C. death of this king of Sparta at Thermopylae made him famous; c'mon, one of you saw \"300\", right?", + "Answer": "Leonidas" + }, + { + "Category": "WITH BROTHERHOOD", + "Question": "The Dust Brothers produced this sibling band's \"Middle Of Nowhere\" which featured \"MMMBop\"", + "Answer": "Hanson" + }, + { + "Category": "FROM T TO SHINING T", + "Question": "Also meaning \"touch\", it's a keen sense of what to say to avoid giving offense", + "Answer": "tact" + }, + { + "Category": "RUSSIAN LITERATURE", + "Question": "In this 1866 Dostoevsky novel, a student named Raskolnikov murders an old woman pawnbroker & her sister", + "Answer": "Crime and Punishment" + }, + { + "Category": "CINEMA OF \"BLOOD\"", + "Question": "Daniel Day-Lewis starred in this 2008 Oscar-winning adaptation of an Upton Sinclair novel", + "Answer": "There Will Be Blood" + }, + { + "Category": "SURVIVAL AT SEA", + "Question": "Steven Callahan drifted for 76 days & 1,800 miles on one of these he called Rubber Ducky III", + "Answer": "an inflatable raft" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Jamb, hinge", + "Answer": "a door" + }, + { + "Category": "PARENT & CHILD NOBEL WINNERS", + "Question": "Nobelist George Thomson is the son of J.J. Thomson, a Nobel Prize winner who discovered this negative particle", + "Answer": "electron" + }, + { + "Category": "EPONYMS", + "Question": "From the disciple who betrayed Jesus, it's one who betrays a friend for some reward", + "Answer": "a Judas" + }, + { + "Category": "RUSSIAN LITERATURE", + "Question": "By 1890 this author & playwright had written hundreds of short stories, including \"The Steppe\"", + "Answer": "Chekhov" + }, + { + "Category": "CINEMA OF \"BLOOD\"", + "Question": "Leonardo DiCaprio's African jewel smuggler gains a conscience in this film", + "Answer": "Blood Diamond" + }, + { + "Category": "SURVIVAL AT SEA", + "Question": "Capsized off Georges Bank, Ernie Hazard survived 2 days in his underwear in this ocean", + "Answer": "Atlantic Ocean" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Cheek strap, snaffle rein", + "Answer": "horse tack" + }, + { + "Category": "PARENT & CHILD NOBEL WINNERS", + "Question": "Ulf von Euler won in 1970; dad Hans von Euler-Chelpin won for his work on the role of enzymes in this process in sugar", + "Answer": "fermentation" + }, + { + "Category": "EPONYMS", + "Question": "This religious sect living primarily in Ohio & southeast Pennsylvania gets its name from a 17th century Swiss Mennonite bishop", + "Answer": "the Amish" + }, + { + "Category": "RUSSIAN LITERATURE", + "Question": "Wounded in World War I, Yuri Zhivago is nursed back to health by this woman who was to become his mistress", + "Answer": "Lara" + }, + { + "Category": "CINEMA OF \"BLOOD\"", + "Question": "Sylvester Stallone played Vietnam vet John Rambo in this 1982 film", + "Answer": "First Blood" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "1 coiled shell, 1 foot", + "Answer": "a snail" + }, + { + "Category": "PARENT & CHILD NOBEL WINNERS", + "Question": "In 1915 William H, & William L. Bragg shared the prize for their analysis of the structure of crystals via this type of image", + "Answer": "x-ray" + }, + { + "Category": "EPONYMS", + "Question": "This screw with a cross-slotted head (& the needed screwdriver) was invented by a Portland man in 1936", + "Answer": "Phillips" + }, + { + "Category": "RUSSIAN LITERATURE", + "Question": "Lev Rubin in this Soviet dissident's \"The First Circle\" was based on 1960s Russian civil rights figure Lev Kopelev", + "Answer": "Solzhenitsyn" + }, + { + "Category": "CINEMA OF \"BLOOD\"", + "Question": "The Coen brothers debuted with this murderous Texas noir tale", + "Answer": "Blood Simple" + }, + { + "Category": "SURVIVAL AT SEA", + "Question": "This \"ancient mariner\" bird is the title of Deborah Scaling Kiley's \"True Story Of A Woman's Survival At Sea\"", + "Answer": "an albatross" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Mercury bulb, scale", + "Answer": "a thermometer" + }, + { + "Category": "PARENT & CHILD NOBEL WINNERS", + "Question": "Last name of father & son Niels & Aage, who both won the Nobel Prize in Physics; Aage was born the year his dad won", + "Answer": "Bohr" + }, + { + "Category": "EPONYMS", + "Question": "The name of this Trojan prince who was killed by Achilles is now used as a verb meaning to bully", + "Answer": "Hector" + }, + { + "Category": "RUSSIAN LITERATURE", + "Question": "This \"Taras Bulba\" author wrote his masterpiece \"Dead Souls\" while living in Rome", + "Answer": "Gogol" + }, + { + "Category": "CINEMA OF \"BLOOD\"", + "Question": "Movie in which Jean-Claude Van Damme wins a secret martial arts tournament", + "Answer": "Bloodsport" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Balk line spot, center pocket", + "Answer": "a pool table" + }, + { + "Category": "PARENT & CHILD NOBEL WINNERS", + "Question": "Arthur Kornberg won for showing how DNA duplicates in bacteria; son Roger's work was on the conversion of DNA into this", + "Answer": "RNA" + }, + { + "Category": "EPONYMS", + "Question": "Inventor & shirtmaker S.L. Cluett's first name gives us this process for minimizing fabric shrinkage", + "Answer": "Sanforizing" + }, + { + "Category": "AMERICAN POLITICIANS", + "Question": "Frank Sinatra came out of retirement to sing their praises: \"they're both unique... the Quaker & the Greek\"", + "Answer": "Richard Nixon & Spiro Agnew" + }, + { + "Category": "HISTORY", + "Question": "In 1429, she was given control of troops in France", + "Answer": "Joan of Arc" + }, + { + "Category": "RUSSELING", + "Question": "\"Stargate\" star who's Goldie Hawn's longtime companion", + "Answer": "Kurt Russell" + }, + { + "Category": "IT'S \"BIG\"", + "Question": "Sasquatch", + "Answer": "Bigfoot" + }, + { + "Category": "KANSAS CITIES", + "Question": "The Menninger Clinic founded in this capital owns a collection of Sigmund Freud's papers", + "Answer": "Topeka" + }, + { + "Category": "MILITARY TELEVISION", + "Question": "Bad guys should stay out of harm's way (that's Cmdr. Harmon Rabb's way) on this military-legal series", + "Answer": "JAG" + }, + { + "Category": "THEM'S FIGHTIN' WORDS", + "Question": "To prepare for war, \"dig up\" this ax; when you've made peace, you bury it again", + "Answer": "the hatchet" + }, + { + "Category": "HISTORY", + "Question": "Using photos he had taken the month before, Clyde Tombaugh discovered this planet February 18, 1930", + "Answer": "Pluto" + }, + { + "Category": "IT'S \"BIG\"", + "Question": "It's found in the Parliament Tower of Westminster Palace", + "Answer": "Big Ben" + }, + { + "Category": "KANSAS CITIES", + "Question": "In the 1960s this largest Kansas city became the world's largest producer of general aviation aircraft", + "Answer": "Wichita" + }, + { + "Category": "THEM'S FIGHTIN' WORDS", + "Question": "To fight with the fists, \"put up\" these noblemen", + "Answer": "your dukes" + }, + { + "Category": "HISTORY", + "Question": "In February 1984 he announced his resignation as Prime Minister of Canada", + "Answer": "Trudeau" + }, + { + "Category": "RUSSELING", + "Question": "On Nov. 7, 1959 he grabbed 35 rebounds in his first showdown with Wilt Chamberlain", + "Answer": "Bill Russell" + }, + { + "Category": "IT'S \"BIG\"", + "Question": "A 2000 Martin Lawrence film", + "Answer": "Big Momma's House" + }, + { + "Category": "KANSAS CITIES", + "Question": "As you might expect, Ulysses is the seat of this \"Presidential\" county", + "Answer": "Grant" + }, + { + "Category": "MILITARY TELEVISION", + "Question": "This future star of \"The Love Boat\" earned his sea legs playing \"Happy\" Haines on \"McHale's Navy\"", + "Answer": "Gavin McLeod" + }, + { + "Category": "THEM'S FIGHTIN' WORDS", + "Question": "\"Colorful\" verb for what's been done when you've been soundly thrashed", + "Answer": "tanned" + }, + { + "Category": "HISTORY", + "Question": "Every president since Taft has been an honorary president of this organization founded in the U.S. in Feb. 1910", + "Answer": "the Boy Scouts" + }, + { + "Category": "IT'S \"BIG\"", + "Question": "This cosmology theory's name came from Fred Hoyle's joke about it", + "Answer": "Big Bang" + }, + { + "Category": "KANSAS CITIES", + "Question": "This college town has been called the \"Little Apple\"", + "Answer": "Manhattan" + }, + { + "Category": "MILITARY TELEVISION", + "Question": "On a '50s series, this German Shepherd & his master, Rusty, were adopted by cavalry soldiers at Fort Apache", + "Answer": "Rin Tin Tin" + }, + { + "Category": "THEM'S FIGHTIN' WORDS", + "Question": "Shopkeepers aren't meeting when \"introducing the shoemaker to the tailor\" -- you've just done this to someone's rear", + "Answer": "kicked it" + }, + { + "Category": "HISTORY", + "Question": "In a 1778 treaty, the U.S. and France granted each other this commerce \"status\"", + "Answer": "most favored nation" + }, + { + "Category": "RUSSELING", + "Question": "Republican John McCain and this Wisconsin Democrat co-sponsored a campaign finance reform bill", + "Answer": "Russ Feingold" + }, + { + "Category": "IT'S \"BIG\"", + "Question": "Empire Toys' trikes for tykes", + "Answer": "Big Wheels" + }, + { + "Category": "MILITARY TELEVISION", + "Question": "This oldest of the Wayans Brothers co-starred with Yaphet Kotto on the 1983 drama series \"For Love and Honor\"", + "Answer": "Keenan Ivory Wayans" + }, + { + "Category": "THEM'S FIGHTIN' WORDS", + "Question": "\"Rock The Casbah\" is the biggest hit by this rock group", + "Answer": "The Clash" + }, + { + "Category": "LITERARY ALLUSIONS", + "Question": "This object from Arthurian & Christian legend has come to mean the object of any difficult quest", + "Answer": "the Holy Grail" + }, + { + "Category": "CLIMBING", + "Question": "Alpinism is European climbing; Andinismo refersto climbing on this continent", + "Answer": "South America" + }, + { + "Category": "JUST PLANE GEOMETRY", + "Question": "In the 3rd century B.C., this \"Father of geometry\" taught at the Museum, an institute in Alexandria, Egypt", + "Answer": "Euclid" + }, + { + "Category": "THE DIRECTOR'S CHAIR", + "Question": "\"Mister Roberts\", \"She Wore a Yellow Ribbon\", \"Stagecoach\"", + "Answer": "Ford" + }, + { + "Category": "SAINTS", + "Question": "In the 7th century Isidore was bishop of this city, not barber of it", + "Answer": "Seville" + }, + { + "Category": "IT ENDS WITH \"US\"", + "Question": "Mildew, mold or a mushroom", + "Answer": "fungus" + }, + { + "Category": "LITERARY ALLUSIONS", + "Question": "A type of nonsexual love is named for this Greek philosopher who discussed it in his \"Symposium\"", + "Answer": "platonic" + }, + { + "Category": "JUST PLANE GEOMETRY", + "Question": "A straight angle has this many degrees", + "Answer": "180" + }, + { + "Category": "THE DIRECTOR'S CHAIR", + "Question": "\"The Milagro Beanfield War\", \"Quiz Show\", \"The Legend of Bagger Vance\"", + "Answer": "Robert Redford" + }, + { + "Category": "SAINTS", + "Question": "Saint Augustine's mom, she's also a saint, as well as an L.A. boulevard that Sheryl Crow sang about", + "Answer": "Santa Monica" + }, + { + "Category": "IT ENDS WITH \"US\"", + "Question": "It's a summary or outline given to college students that covers the course of study", + "Answer": "syllabus" + }, + { + "Category": "LITERARY ALLUSIONS", + "Question": "This term for an idyllic place can be checked out in the James Hilton work \"Lost Horizon\"", + "Answer": "Shangri-La" + }, + { + "Category": "CLIMBING", + "Question": "In \"Vertical Limit\" Robin Tunney is menaced by this high-altitude condition of fluid leaking into the lungs", + "Answer": "pulmonary edema" + }, + { + "Category": "JUST PLANE GEOMETRY", + "Question": "The sum of the squares of the lengths of the legs of a right triangle is equal to the square of the length of this", + "Answer": "the hypotenuse" + }, + { + "Category": "THE DIRECTOR'S CHAIR", + "Question": "\"Hobson's Choice\", \"Oliver Twist\", \"Lawrence of Arabia\"", + "Answer": "David Lean" + }, + { + "Category": "SAINTS", + "Question": "In 1918 padre Pio, who reportedly could levitate, became the first priest in centuries to receive these \"wounds\"", + "Answer": "stigmata" + }, + { + "Category": "LITERARY ALLUSIONS", + "Question": "Jonathan Swift created Lilliputians; this author created Munchkins", + "Answer": "Baum" + }, + { + "Category": "JUST PLANE GEOMETRY", + "Question": "The word geometry means to \"measure\" this", + "Answer": "the world, the earth" + }, + { + "Category": "THE DIRECTOR'S CHAIR", + "Question": "\"Z\", \"State of Siege\", \"Missing\"", + "Answer": "Costa-Gavras" + }, + { + "Category": "SAINTS", + "Question": "During his reign St. Pius X revised this Latin version of the Bible", + "Answer": "St. Jerome's or the Vulgate" + }, + { + "Category": "IT ENDS WITH \"US\"", + "Question": "Bridges over this strait connect Asia to Europe", + "Answer": "Bosphorus" + }, + { + "Category": "LITERARY ALLUSIONS", + "Question": "\"The shot heard round the world\" was first heard in this man's \"Concord Hymn\"", + "Answer": "Ralph Waldo Emerson" + }, + { + "Category": "CLIMBING", + "Question": "Also meaning to stop an action, in climbing it means to secure another person with a rope", + "Answer": "to belay" + }, + { + "Category": "JUST PLANE GEOMETRY", + "Question": "To make this figure, put a looped string around 2 tacks, place a pencil tight against the string & draw", + "Answer": "an ellipse" + }, + { + "Category": "THE DIRECTOR'S CHAIR", + "Question": "\"Woman with a Past\", \"The Peacemaker\", \"Deep Impact\"", + "Answer": "Mimi Leder" + }, + { + "Category": "SAINTS", + "Question": "Saint Fursey's visions were recorded by this venerable saint", + "Answer": "Bede" + }, + { + "Category": "IT ENDS WITH \"US\"", + "Question": "He killed the minotaur", + "Answer": "Theseus" + }, + { + "Category": "INTERNATIONAL LANDMARKS", + "Question": "Its roof has been variously described as sails, clam shells & a huddle of nuns in a high wind", + "Answer": "the Sydney Opera House" + }, + { + "Category": "FDR", + "Question": "Referring to the attack on Pearl Harbor, FDR called December 7, 1941 \"A date which will\" do this", + "Answer": "\"Live in Infamy\"" + }, + { + "Category": "CNN", + "Question": "Named for its Brooklyn-born host, this \"live\" interview show debuted on CNN in June 1985", + "Answer": "\"Larry King Live\"" + }, + { + "Category": "LSU", + "Question": "In terms of enrollment LSU's largest campus is in this capital city", + "Answer": "Baton Rouge" + }, + { + "Category": "KFC", + "Question": "The company would have been called Indiana Fried Chicken if it were named for the birthplace of this founder", + "Answer": "Col. Harland Sanders" + }, + { + "Category": "TBA", + "Question": "White smoke rising from the Vatican announces the election of a new one of these", + "Answer": "Pope" + }, + { + "Category": "SRO", + "Question": "The stage show seen here has brought this dance to cheering audiences", + "Answer": "Tango" + }, + { + "Category": "FDR", + "Question": "FDR gave the first of these talks March 12, 1933 from the White House diplomatic reception room", + "Answer": "Fireside Chats" + }, + { + "Category": "CNN", + "Question": "He & Robert Novak have worked together since 1963 & now co-anchor a CNN discussion program", + "Answer": "Rowland Evans" + }, + { + "Category": "LSU", + "Question": "9 years after leaving LSU she won an Oscar for \"The Three Faces of Eve\"", + "Answer": "Joanne Woodward" + }, + { + "Category": "KFC", + "Question": "The formula using this many herbs & spices is locked in a safe in Louisville", + "Answer": "11" + }, + { + "Category": "TBA", + "Question": "It's the animal name of the device I'm using here TO ANNOUNCE THE CLUE", + "Answer": "Bullhorn" + }, + { + "Category": "SRO", + "Question": "A song in this Disney musical asks, \"How long must this go on?\" ---4 years & counting", + "Answer": "Beauty And The Beast" + }, + { + "Category": "FDR", + "Question": "While attending this school, FDR was editor of its newspaper, The Crimson", + "Answer": "Harvard" + }, + { + "Category": "CNN", + "Question": "It's the territory where the ceremony seen here took place on the night of June 30 - July 1, 1997", + "Answer": "Hong Kong" + }, + { + "Category": "LSU", + "Question": "This basketball star nicknamed \"Pistol Pete\" went to LSU where his dad \"Press\" was coach", + "Answer": "Pete Maravich" + }, + { + "Category": "KFC", + "Question": "General Tao was smiling in 1987 when KFC became the first U.S. fast-food chain in this country", + "Answer": "China" + }, + { + "Category": "TBA", + "Question": "When the national votes are tallied, the 43rd one of these will be announced November 7, 2000", + "Answer": "President of the United States" + }, + { + "Category": "SRO", + "Question": "3-letter word that's the title of Yasmina Reza's hit play about an all-white painting", + "Answer": "Art" + }, + { + "Category": "FDR", + "Question": "FDR was born & is now buried in this town on the Hudson River", + "Answer": "Hyde Park" + }, + { + "Category": "CNN", + "Question": "In 1997 CNN became the first U.S. news organization since 1969 with a permanent bureau in this country", + "Answer": "Cuba" + }, + { + "Category": "LSU", + "Question": "This civil \"War is Hell\" general was president of the seminary & military academy that became LSU", + "Answer": "William Tecumseh Sherman" + }, + { + "Category": "KFC", + "Question": "The conglomerate built on this soda decided everybody needs a little KFC & bought it in 1986", + "Answer": "Pepsi Cola" + }, + { + "Category": "TBA", + "Question": "Warnings of these \"floods\" are announced by the N.W.S. when large amounts of rain fall in a short amount of time", + "Answer": "Flash flood" + }, + { + "Category": "SRO", + "Question": "This musical opened its run in 1980 at the Winter Garden, 8 blocks from the title thoroughfare", + "Answer": "42nd Street" + }, + { + "Category": "FDR", + "Question": "During this 1932 campaign, FDR relied on a trusted group of advisers dubbed this --- pretty smart", + "Answer": "Brain Trust" + }, + { + "Category": "CNN", + "Question": "Anchored by Lou Dobbs, it was TV's first nightly business newscast", + "Answer": "\"Moneyline\"" + }, + { + "Category": "LSU", + "Question": "\"All The King's Men\" know this first poet laureate of the U.S. was editor of LSU's Southern Review", + "Answer": "Robert Penn Warren" + }, + { + "Category": "KFC", + "Question": "KFC introduced this menu item by building a 20,000-lb. one, unveiled with dancing carrots & peas", + "Answer": "Chicken pot pie" + }, + { + "Category": "TBA", + "Question": "A teary-eyed person, or the announcer of the latest village news", + "Answer": "Crier" + }, + { + "Category": "SRO", + "Question": "Tony-winning Tony who drew big crowds with his epic play \"Angels In America\"", + "Answer": "Tony Kushner" + }, + { + "Category": "THE USA", + "Question": "The Green Mountains of Vermont & the White Mountains of New Hampshire are part of this mountain system", + "Answer": "Appalachians" + }, + { + "Category": "THE CIA", + "Question": "The CIA's main rival for much of its existence was this Soviet counterpart", + "Answer": "KGB" + }, + { + "Category": "THE ICU", + "Question": "A myocardial infarction, better known as this, is a common reason for ICU admission", + "Answer": "Heart attack" + }, + { + "Category": "THE \"A\" \"B\" \"C\"s", + "Question": "In a 1976 Playboy interview, Jimmy Carter said he'd committed this in his heart many times", + "Answer": "Adultery" + }, + { + "Category": "THE CAT", + "Question": "Most felines have 30 of these (including the canines)", + "Answer": "Teeth" + }, + { + "Category": "THE USA", + "Question": "The discovery of the Comstock Lode in 1859 attracted miners & prospectors to this state", + "Answer": "Nevada" + }, + { + "Category": "THE CIA", + "Question": "Advanced CIA methods have included use of this high altitude aircraft; one was shot down May 1, 1960", + "Answer": "U-2" + }, + { + "Category": "THE ICU", + "Question": "3-letter abbreviation for the ICU machine seen here", + "Answer": "EKG" + }, + { + "Category": "THE \"A\" \"B\" \"C\"s", + "Question": "Ring in & tell me this correct name for a young swan", + "Answer": "Cygnet" + }, + { + "Category": "THE CAT", + "Question": "When a lioness & one of these mate, they produce a leopon", + "Answer": "Leopard" + }, + { + "Category": "THE USA", + "Question": "The name of this New Mexico city where the first atomic bomb was exploded is Spanish for \"big cottonwood\"", + "Answer": "Alamogordo" + }, + { + "Category": "THE NBA", + "Question": "(VIDEO DAILY DOUBLE): \"(Hi, I'm Kareem Abdul-Jabbar) The first and last of my 1,815 NBA games were both against this team known as the \"Bad Boys\" of the league\"", + "Answer": "Detroit Pistons" + }, + { + "Category": "THE CIA", + "Question": "He's the only CIA head who went on to become president", + "Answer": "George Herbert Walker Bush" + }, + { + "Category": "THE ICU", + "Question": "It comes from the Greek meaning \"deep sleep\", but it's deeper than that", + "Answer": "Coma" + }, + { + "Category": "THE \"A\" \"B\" \"C\"s", + "Question": "They're the 2 words describing lenses that curve outward or inward", + "Answer": "Concave & convex" + }, + { + "Category": "THE CAT", + "Question": "In Chinese lore this big cat, not the lion, was king of the beasts", + "Answer": "Tiger" + }, + { + "Category": "THE USA", + "Question": "At an altitude of about 10,200 feet, this Colorado city is the highest incorporated city in the USA", + "Answer": "Leadville" + }, + { + "Category": "THE NBA", + "Question": "For 9 straight seasons, ending in '96, this Utah Jazz player led the NBA in average assists per game", + "Answer": "John Stockton" + }, + { + "Category": "THE CIA", + "Question": "Much of the intelligence evaluation & planning is done at the CIA's HQ in this Virginia locale", + "Answer": "Langley" + }, + { + "Category": "THE ICU", + "Question": "A neonatal ICU may contain several isolettes, a type of this chamber", + "Answer": "Incubator" + }, + { + "Category": "THE \"A\" \"B\" \"C\"s", + "Question": "From 1672 to 1858 this city was the headquarters of the British East India Company", + "Answer": "Bombay" + }, + { + "Category": "THE CAT", + "Question": "Like MGM's Leo the Lion, if you can do this you're considered one of the \"big cats\"", + "Answer": "Roar" + }, + { + "Category": "THE USA", + "Question": "This river forms most of the boundary between Georgia & South Carolina", + "Answer": "Savannah River" + }, + { + "Category": "THE NBA", + "Question": "Located in the \"Rose City\", this team's home court is appropriately called the Rose Garden", + "Answer": "Portland Trail Blazers" + }, + { + "Category": "THE CIA", + "Question": "Founded in 1947, the CIA grew out of WWII's OSS, which stood for this", + "Answer": "Office of Strategic Services" + }, + { + "Category": "THE ICU", + "Question": "Intensive care is also called this \"care\", like the condition patients may be in", + "Answer": "Critical" + }, + { + "Category": "THE \"A\" \"B\" \"C\"s", + "Question": "The name of this German publisher has become synonymous with a guidebook", + "Answer": "Karl Baedeker" + }, + { + "Category": "THE CAT", + "Question": "The name of this striped color pattern may come from a market in Baghdad famous for 2-tone silk", + "Answer": "Tabby" + }, + { + "Category": "PEOPLE", + "Question": "He made the cover of Life magazine 3 times in February & March of 1962, & again in October 1998", + "Answer": "John Glenn" + }, + { + "Category": "LITERATURE", + "Question": "Chapter 13 of this classic novel is called \"Another View of Hester\"", + "Answer": "The Scarlet Letter" + }, + { + "Category": "LET THE GAMES BEGIN", + "Question": "A total of 22 means you've gone \"bust\" in this card game", + "Answer": "blackjack" + }, + { + "Category": "THAT'S WHAT I LIKE ABOUT THE SOUTH", + "Question": "The American Heritage Dictionary calls this pronoun the most famous feature of Southern dialects", + "Answer": "y'all" + }, + { + "Category": "INTO THE \"WOOD\"s", + "Question": "Knothead & Splinter are the nephew & niece of this cartoon bird produced by Walter Lantz", + "Answer": "Woody Woodpecker" + }, + { + "Category": "BRANDO", + "Question": "\"Family\" man Don Vito Corleone", + "Answer": "The Godfather" + }, + { + "Category": "LITERATURE", + "Question": "He published the first 4 of his fairy tales in an 1835 pamphlet; \"The Tinder Box\" was among them", + "Answer": "Hans Christian Andersen" + }, + { + "Category": "LET THE GAMES BEGIN", + "Question": "It's the most expensive property in the U.S. version of Monopoly", + "Answer": "Boardwalk" + }, + { + "Category": "THAT'S WHAT I LIKE ABOUT THE SOUTH", + "Question": "A state capital since 1849, it showed Southern hospitality in 2005 as its population grew by 50% after Katrina", + "Answer": "Baton Rouge" + }, + { + "Category": "INTO THE \"WOOD\"s", + "Question": "1969 rock festival site", + "Answer": "Woodstock" + }, + { + "Category": "BRANDO", + "Question": "Terry Malloy, who could've been a contender", + "Answer": "On the Waterfront" + }, + { + "Category": "LITERATURE", + "Question": "Nicodemus Frapp is a narrow-minded evangelist in \"Tono-Bungay\", a 1909 novel by this author of \"The Time Machine\"", + "Answer": "H.G. Wells" + }, + { + "Category": "LET THE GAMES BEGIN", + "Question": "On a basic playing board in this matching game, the numbers range from B-1 to O-75", + "Answer": "bingo" + }, + { + "Category": "THAT'S WHAT I LIKE ABOUT THE SOUTH", + "Question": "The Mississippi's oldest operating steamboat is this type of Southern lady \"of Louisville\"", + "Answer": "the Belle" + }, + { + "Category": "INTO THE \"WOOD\"s", + "Question": "A heavyset rodent common in northern North America", + "Answer": "a woodchuck" + }, + { + "Category": "BRANDO", + "Question": "Blanche's brother-in-law Stanley", + "Answer": "A Streetcar Named Desire" + }, + { + "Category": "LITERATURE", + "Question": "This author of \"The Good Earth\" based the heroine of her 1938 novel \"This Proud Heart\" on herself", + "Answer": "Pearl Buck" + }, + { + "Category": "LET THE GAMES BEGIN", + "Question": "\"Acey Deucey\" is a variation of this board game that was introduced to Europe by the Arabs", + "Answer": "backgammon" + }, + { + "Category": "THAT'S WHAT I LIKE ABOUT THE SOUTH", + "Question": "The name of a popular Southern liquor brand, it's also the state game bird of Alabama", + "Answer": "Wild Turkey" + }, + { + "Category": "INTO THE \"WOOD\"s", + "Question": "On an orchestral score, the music for this instrument group is at the top", + "Answer": "woodwinds" + }, + { + "Category": "BRANDO", + "Question": "Col. Kurtz, who lives in the heart of darkness", + "Answer": "Apocalypse Now" + }, + { + "Category": "LITERATURE", + "Question": "In Wonderland, Alice comes across a large one of these with a snooty caterpillar atop it", + "Answer": "a mushroom" + }, + { + "Category": "THAT'S WHAT I LIKE ABOUT THE SOUTH", + "Question": "Scenic traces include one along Lake Pontchartrain & a 500-mile one from Nashville to this city", + "Answer": "Natchez" + }, + { + "Category": "BRANDO", + "Question": "Johnny, leader of the Black Rebels", + "Answer": "The Wild One" + }, + { + "Category": "NEWS ON THE MARCH", + "Question": "On March 10, 1876 he spoke by telephone to Thomas Watson", + "Answer": "Alexander Graham Bell" + }, + { + "Category": "MUSIC/TELEVISION", + "Question": "Phil Collins, Ted Nugent & The Fat Boys hit the Sunshine State on this '80s cop show", + "Answer": "Miami Vice" + }, + { + "Category": "TREES & SHRUBS", + "Question": "A 1912 gift from Japan, the Yoshino species of this tree is found in great abundance by the Jefferson Memorial", + "Answer": "cherry trees" + }, + { + "Category": "RHYME TIME FOOD & DRINK", + "Question": "A hilarious bee product", + "Answer": "funny honey" + }, + { + "Category": "BRAND-O", + "Question": "Cryst & Krispo were potential names for this brand of shortening", + "Answer": "Crisco" + }, + { + "Category": "NEWS ON THE MARCH", + "Question": "Nationalists from this Commonwealth attacked the U.S. Capitol March 1, 1954, injuring 5 representatives", + "Answer": "Puerto Rico" + }, + { + "Category": "MUSIC/TELEVISION", + "Question": "Legendary singer Eartha Kitt was just purr-fect as this \"Batman\" villainess", + "Answer": "Catwoman" + }, + { + "Category": "TREES & SHRUBS", + "Question": "In 1963 Louisiana chose this \"bald\" tree native to the swamps & wetlands as its state tree", + "Answer": "the cypress" + }, + { + "Category": "RHYME TIME FOOD & DRINK", + "Question": "A thin pancake with a Concord fruit filling", + "Answer": "a grape crêpe" + }, + { + "Category": "LARCENY DELL'ARTE", + "Question": "This Spaniard's portrait of the Duke of Wellington was stolen from the U.K. in 1961", + "Answer": "Goya" + }, + { + "Category": "BRAND-O", + "Question": "George Blaisdell invented this lighter in 1932", + "Answer": "the Zippo" + }, + { + "Category": "NEWS ON THE MARCH", + "Question": "On March 29, 2004 Latvia & 6 other ex-Communist nations joined this organization", + "Answer": "NATO" + }, + { + "Category": "MUSIC/TELEVISION", + "Question": "This country star became a sitcom grandma at the end of her first season on the WB", + "Answer": "Reba McEntire" + }, + { + "Category": "RHYME TIME FOOD & DRINK", + "Question": "A malt beverage like O'Doul's with little or no alcohol", + "Answer": "near beer" + }, + { + "Category": "BRAND-O", + "Question": "Fido knows that Robert Hunsicker created this dog food brand", + "Answer": "Alpo" + }, + { + "Category": "NEWS ON THE MARCH", + "Question": "On March 10, 1629 this king dissolved Parliament, leading to his eventual downfall & demise", + "Answer": "Charles I" + }, + { + "Category": "MUSIC/TELEVISION", + "Question": "Going from Salt-N-Pepa to Dr. Pepa, the musician was in the house counseling Janice Dickinson on this VH1 reality show", + "Answer": "The Surreal Life" + }, + { + "Category": "TREES & SHRUBS", + "Question": "This shrub produces clusters appropriately called catkins said to resemble kittens climbing up the twig", + "Answer": "a pussy willow" + }, + { + "Category": "RHYME TIME FOOD & DRINK", + "Question": "An acrid-tasting deep-fried cake full of corn or crab", + "Answer": "a bitter fritter" + }, + { + "Category": "LARCENY DELL'ARTE", + "Question": "NYC's largest art theft happened in 1988 & saw the loss of 2 of this Renaissance friar's masterpieces", + "Answer": "Fra Angelico" + }, + { + "Category": "BRAND-O", + "Question": "Models of this car brand include the Metro & the Storm", + "Answer": "Geo" + }, + { + "Category": "NEWS ON THE MARCH", + "Question": "In March 1967 Robert Kennedy came up with a nifty Vietnam peace plan, but this Secretary of State rejected it", + "Answer": "Dean Rusk" + }, + { + "Category": "MUSIC/TELEVISION", + "Question": "Hey, now! Elvis Costello sold Hank Kingsley a lemon of a sports car on this HBO comedy", + "Answer": "The Larry Sanders Show" + }, + { + "Category": "TREES & SHRUBS", + "Question": "This shrub whose name is from Greek for \"rose tree\" is among the many plants growing on Himalayan slopes", + "Answer": "the rhododendron" + }, + { + "Category": "RHYME TIME FOOD & DRINK", + "Question": "An ever so tiny piece of the hepatic organ", + "Answer": "a liver sliver" + }, + { + "Category": "BRAND-O", + "Question": "You'll go really fast in this swimwear brand worn by Olympic gold medalists", + "Answer": "Speedo" + }, + { + "Category": "20th CENTURY THEATER", + "Question": "This play ends with 1 character asking, \"Well? Shall we go?\"; the other replies, \"Yes, let's go\", but they do not move", + "Answer": "Waiting for Godot" + }, + { + "Category": "THE CONTINENTS", + "Question": "This continent is the largest in area", + "Answer": "Asia" + }, + { + "Category": "THE SUMMER OLYMPICS", + "Question": "You might have to get as high as 20 feet off the ground to win a medal in this \"vaulting\" Olympic event", + "Answer": "the pole vault" + }, + { + "Category": "OUT OF THIS WORLD", + "Question": "The gravitational pull of this object is the main force holding the solar system together", + "Answer": "the sun" + }, + { + "Category": "YOUR NEW CLASS SCHEDULE", + "Question": "History: Study up on this ship that anchored in Plymouth Harbor on Dec. 26, 1620", + "Answer": "the Mayflower" + }, + { + "Category": "AMERICANA", + "Question": "On July 8, 1776 it was rung to proclaim the first public reading of the Declaration of Independence", + "Answer": "the Liberty Bell" + }, + { + "Category": "NOT A VERB", + "Question": "Capable, succeed, accomplish", + "Answer": "capable" + }, + { + "Category": "THE CONTINENTS", + "Question": "Early explorers called parts of this continent Vinland", + "Answer": "North America" + }, + { + "Category": "THE SUMMER OLYMPICS", + "Question": "At 26.2 miles, it's the longest running event in the Summer Olympics", + "Answer": "the marathon" + }, + { + "Category": "OUT OF THIS WORLD", + "Question": "Galileo was the first person to see the rings around this planet", + "Answer": "Saturn" + }, + { + "Category": "YOUR NEW CLASS SCHEDULE", + "Question": "Home ec.: Make this breakfast dish of battered & fried bread, called pain perdu in France", + "Answer": "French toast" + }, + { + "Category": "AMERICANA", + "Question": "Suffragettes were women who wanted the right to do this (& got to with the 19th Amendement)", + "Answer": "vote" + }, + { + "Category": "NOT A VERB", + "Question": "Paint, brush, easel", + "Answer": "easel" + }, + { + "Category": "THE CONTINENTS", + "Question": "This continent has a lot of marsupials, like the native wombat", + "Answer": "Australia" + }, + { + "Category": "THE SUMMER OLYMPICS", + "Question": "In the Olympic 400-meter relay final, this many runners compete together as a team", + "Answer": "4" + }, + { + "Category": "OUT OF THIS WORLD", + "Question": "Not the first but this second planet is the hottest, because its atmosphere causes a severe greenhouse effect", + "Answer": "Venus" + }, + { + "Category": "YOUR NEW CLASS SCHEDULE", + "Question": "Spanish: You'll have to use your cabeza, this body part, to pass the class", + "Answer": "your head" + }, + { + "Category": "AMERICANA", + "Question": "Check out exotic marine life at one of these, like the National one in Baltimore", + "Answer": "an aquarium" + }, + { + "Category": "NOT A VERB", + "Question": "Wind, wander, wonderful", + "Answer": "wonderful" + }, + { + "Category": "THE CONTINENTS", + "Question": "This continent has the longest mountain chain", + "Answer": "South America" + }, + { + "Category": "THE SUMMER OLYMPICS", + "Question": "Throwing events include this one, the hurling of a spearlike shaft", + "Answer": "the javelin" + }, + { + "Category": "OUT OF THIS WORLD", + "Question": "It was last seen in the skies in 1986 & won't return until 2061", + "Answer": "Halley's Comet" + }, + { + "Category": "AMERICANA", + "Question": "Tulsa's newspaper is called The World; Boston's is named for this object that depicts the world", + "Answer": "a globe" + }, + { + "Category": "NOT A VERB", + "Question": "Salt, pepper, sage", + "Answer": "sage" + }, + { + "Category": "THE CONTINENTS", + "Question": "In 1957 countries on this continent signed a treaty creating an economic community, or common market", + "Answer": "Europe" + }, + { + "Category": "THE SUMMER OLYMPICS", + "Question": "In 2004 the USA's Bryan Clay, with 8,820 points, took the silver in this 10-event contest", + "Answer": "the decathlon" + }, + { + "Category": "YOUR NEW CLASS SCHEDULE", + "Question": "Science: Discover animal anatomy, starting with Ursidae, this animal family", + "Answer": "the bear family" + }, + { + "Category": "AMERICANA", + "Question": "The name of this Texas city is Spanish for \"yellow\"", + "Answer": "Amarillo" + }, + { + "Category": "NOT A VERB", + "Question": "Candor, center, canter", + "Answer": "candor" + }, + { + "Category": "CHRISTOPHER COLUMBUS", + "Question": "There's no truth to the story that she had to pawn her jewels to finance Columbus' first voyage", + "Answer": "Queen Isabella" + }, + { + "Category": "MOVIE MUSIC", + "Question": "5-letter word for a group that sings exalting music, like the Bulgarian women's one heard in \"Brother Bear\"", + "Answer": "choir" + }, + { + "Category": "LITERATURE FOR KIDS", + "Question": "\"We looked! Then we saw him step in on the mat! We looked! And we saw him!\" This famous cat", + "Answer": "the Cat in the Hat" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Several different islands choose their own kings & queens as part of this state's Aloha festivals", + "Answer": "Hawaii" + }, + { + "Category": "ART", + "Question": "Ceramics is the art of making objects, even dreidels, out of this material", + "Answer": "clay" + }, + { + "Category": "WHERE WORDS COME FROM", + "Question": "Chinese or Malay: This tomato condiment that's put on French fries", + "Answer": "ketchup" + }, + { + "Category": "CHRISTOPHER COLUMBUS", + "Question": "This flagship of Columbus' first voyage was chartered from Juan de la Cosa & was his largest ship", + "Answer": "the Santa Maria" + }, + { + "Category": "MOVIE MUSIC", + "Question": "Caetano Veloso & Mr. Loco are among artists on the soundtrack of this Jack Black wrestling movie", + "Answer": "Nacho Libre" + }, + { + "Category": "LITERATURE FOR KIDS", + "Question": "In a fairy tale by this Danish author, the Snow Queen takes little Kay away in her sleigh to her icy palace", + "Answer": "Hans Christian Andersen" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Stand clear of the seed-spitting contest at the Hope, Arkansas festival for these huge picnic fruits", + "Answer": "watermelons" + }, + { + "Category": "ART", + "Question": "Someone tearing the L.A. Times into strips may be practicing this art form with a hyphenated French name", + "Answer": "papier-mâché" + }, + { + "Category": "WHERE WORDS COME FROM", + "Question": "Latin: This device you open when it's precipitating", + "Answer": "an umbrella" + }, + { + "Category": "CHRISTOPHER COLUMBUS", + "Question": "Christopher Columbus was born in this Italian seaport where his father was a merchant & wool weaver", + "Answer": "Genoa" + }, + { + "Category": "MOVIE MUSIC", + "Question": "Julie Andrews sings \"A Spoonful Of Sugar\" in this movie", + "Answer": "Mary Poppins" + }, + { + "Category": "LITERATURE FOR KIDS", + "Question": "In \"Little Women\", Margaret March is better known by this nickname", + "Answer": "\"Meg\"" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Dancers clomp around in wooden shoes at the Holland, Michigan festival honoring this flower", + "Answer": "the tulip" + }, + { + "Category": "ART", + "Question": "The name of this type of paint that contains egg yolks almost sounds like a Japanese dish, but don't eat it", + "Answer": "tempera" + }, + { + "Category": "CHRISTOPHER COLUMBUS", + "Question": "On Oct. 12, 1492 Columbus reached the New World & landed at an island he called this, Spanish for \"holy savior\"", + "Answer": "San Salvador" + }, + { + "Category": "MOVIE MUSIC", + "Question": "In \"Raise Your Voice\", Hilary Duff sings this Handel oratorio about the Savior", + "Answer": "Messiah" + }, + { + "Category": "LITERATURE FOR KIDS", + "Question": "This loving relative who takes care of Tom Sawyer was inspired by Mark Twain's own mother", + "Answer": "Aunt Polly" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Stockton, Calif. doesn't have a festival for Britney Spears, but it does have one for these green spears", + "Answer": "asparagus" + }, + { + "Category": "CHRISTOPHER COLUMBUS", + "Question": "One of the only 2 current U.S. territories visited by Columbus, who reached both in 1493", + "Answer": "Puerto Rico" + }, + { + "Category": "MOVIE MUSIC", + "Question": "She sings \"Cry\" & \"Only Hope\" on the soundtrack of her movie \"A Walk to Remember\"", + "Answer": "Mandy Moore" + }, + { + "Category": "LITERATURE FOR KIDS", + "Question": "This author who wrote about \"The Princess Who Could Not Laugh\" made us smile with \"Winnie-the-Pooh\"", + "Answer": "A.A. Milne" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "He's the only U.S. president who never lived in the District of Columbia", + "Answer": "George Washington" + }, + { + "Category": "4-LETTER CAPITALS", + "Question": "It's been said that \"All roads lead to\" this \"Eternal City\"", + "Answer": "Rome" + }, + { + "Category": "THE WOK OF FAME", + "Question": "To eat Chinese food like a native, use 2 of these 10 1/2-inch wooden implements", + "Answer": "Chopsticks" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "WWII radio propagandist Iva D'Aquino", + "Answer": "\"Tokyo Rose\"" + }, + { + "Category": "\"CAL\" STATE", + "Question": "One Big Mac has 560 of these", + "Answer": "Calories" + }, + { + "Category": "DUKE, DUKE", + "Question": "Jazz at Lincoln Center is putting on over 400 events in 1999 in honor of his 100th birthday", + "Answer": "Duke Ellington" + }, + { + "Category": "GOOSE...MOTHER GOOSE", + "Question": "Assuming that they lost them all, total number of mittens lost by the kittens", + "Answer": "6" + }, + { + "Category": "4-LETTER CAPITALS", + "Question": "Just 12 degrees south of the Equator, this Peruvian capital's temperatures are moderated by the Humboldt Current", + "Answer": "Lima" + }, + { + "Category": "THE WOK OF FAME", + "Question": "The 4 main Chinese types of these strips of dried dough are soup, sauce, stir-fried & shallow-fried", + "Answer": "Noodles" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Falsetto ukulele strummer Herbert Khaury", + "Answer": "Tiny Tim" + }, + { + "Category": "\"CAL\" STATE", + "Question": "For this lotion mentioned in a Coasters song, think pink", + "Answer": "Calamine lotion" + }, + { + "Category": "DUKE, DUKE", + "Question": "Louisiana politician David Duke was a former grand wizard in this organization", + "Answer": "Ku Klux Klan" + }, + { + "Category": "GOOSE...MOTHER GOOSE", + "Question": "Her rhyme winds up with her playing \"Pin the Tail on the Sheep\"", + "Answer": "Little Bo Peep" + }, + { + "Category": "4-LETTER CAPITALS", + "Question": "Akershus Castle, a tourist site in this capital, sits on a rocky peninsula overlooking a fjord", + "Answer": "Oslo" + }, + { + "Category": "THE WOK OF FAME", + "Question": "Some people may have adverse reactions to this Chinese food flavor enhancer that's also called \"Mei-Jing\"", + "Answer": "MSG" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "Astrologer & psychic Michel de Notredame", + "Answer": "Nostradamus" + }, + { + "Category": "\"CAL\" STATE", + "Question": "For smokers, it's a pipe with a curved stem & a large bowl made from a gourd", + "Answer": "Calabash" + }, + { + "Category": "DUKE, DUKE", + "Question": "This Brooklyn Dodger was named to the Baseball Hall of Fame in 1980", + "Answer": "Duke Snider" + }, + { + "Category": "GOOSE...MOTHER GOOSE", + "Question": "Little boys are made of frogs & snails & these, eew...", + "Answer": "Puppy dog tails" + }, + { + "Category": "4-LETTER CAPITALS", + "Question": "This Latvian capital was founded in 1201 by German crusaders", + "Answer": "Riga" + }, + { + "Category": "THE WOK OF FAME", + "Question": "Reputedly an aphrodisiac, this expensive soup uses dorsal & pectoral portions of its namesake", + "Answer": "Shark fin soup" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "The New York Mets' William Hayward Wilson", + "Answer": "Mookie Wilson" + }, + { + "Category": "\"CAL\" STATE", + "Question": "Using one of these instruments, a doctor can see just how thick-headed you are:", + "Answer": "Calipers" + }, + { + "Category": "DUKE, DUKE", + "Question": "Famous U.S. group of museums endowed by the illegitimate son of the Duke of Northumberland", + "Answer": "Smithsonian" + }, + { + "Category": "GOOSE...MOTHER GOOSE", + "Question": "The pig that he stole was actually an animal-shaped, currant-filled pastry", + "Answer": "Tom" + }, + { + "Category": "4-LETTER CAPITALS", + "Question": "In 1990 it became the capital of a unified Yemen", + "Answer": "Sana" + }, + { + "Category": "THE WOK OF FAME", + "Question": "Meaning \"heart's delight\", it's a variety of snacks like fried dumplings & steamed buns", + "Answer": "Dim sum" + }, + { + "Category": "BETTER KNOWN AS...", + "Question": "TV pitchman Jim Varney", + "Answer": "Ernest P. Worrell" + }, + { + "Category": "\"CAL\" STATE", + "Question": "Ca is calcium; Cf is this element", + "Answer": "Californium" + }, + { + "Category": "DUKE, DUKE", + "Question": "It was Duke-Duke once again with the April 1999 TV movie reunion of this 1960s series", + "Answer": "The Patty Duke Show" + }, + { + "Category": "GOOSE...MOTHER GOOSE", + "Question": "\"A man of words and not of\" these \"is like a garden full of weeds\"", + "Answer": "Deeds" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "This striped mammal reportedly can fire 6 shots of its foul spray before having to \"resupply\"", + "Answer": "Skunk" + }, + { + "Category": "FURNITURE", + "Question": "In Asia this hollow-stemmed plant is grown in a form to prebend it for use in furniture", + "Answer": "Bamboo" + }, + { + "Category": "HOMETOWNS", + "Question": "Ingrid Bergman", + "Answer": "Stockholm" + }, + { + "Category": "KILLER MUSICALS", + "Question": "A stray bullet ends the life of Eponine in this epic musical (don't \"Mis\" it!)", + "Answer": "\"Les Miserables\"" + }, + { + "Category": "Y1K", + "Question": "Finished around 1000 A.D., \"The Pillow Book\" of Sei Shonagon is one of this country's literary masterpieces", + "Answer": "Japan" + }, + { + "Category": "\"PIN\" ME", + "Question": "A child holds this toy by the stick & lets the wind do the spinning", + "Answer": "Pinwheel" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Some members of the genus Aedes of this insect transmit yellow fever", + "Answer": "Mosquito" + }, + { + "Category": "FURNITURE", + "Question": "A removable section of a tabletop; when it's hinged, it's a \"drop\"", + "Answer": "Leaf" + }, + { + "Category": "HOMETOWNS", + "Question": "Niels Bohr", + "Answer": "Copenhagen" + }, + { + "Category": "KILLER MUSICALS", + "Question": "This \"demon barber\" had his victims baked into pies (no one could accuse him of good taste)", + "Answer": "\"Sweeney Todd\"" + }, + { + "Category": "Y1K", + "Question": "Circa 1000 Polynesian migrants reach New Zealand where they settle & become this ethnic group", + "Answer": "Maoris" + }, + { + "Category": "\"PIN\" ME", + "Question": "Someone who steps up to the plate for a teammate", + "Answer": "Pinch hitter" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "The Jacobson's organ at the roof of this legless reptile's mouth is used with its tongue to detect odors", + "Answer": "Snake" + }, + { + "Category": "FURNITURE", + "Question": "Lacquer & tortoise shell were featured in this style of the 1920s", + "Answer": "Art Deco" + }, + { + "Category": "HOMETOWNS", + "Question": "Jose Marti", + "Answer": "Havana" + }, + { + "Category": "KILLER MUSICALS", + "Question": "Sting starred as the vile Macheath in a 1989 revival of this Weill musical", + "Answer": "\"The Threepenny Opera\"" + }, + { + "Category": "Y1K", + "Question": "By a vote of its parliament, the Althing, this island country adopts Christianity", + "Answer": "Iceland" + }, + { + "Category": "\"PIN\" ME", + "Question": "This type of frijole may end up refried", + "Answer": "Pinto bean" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "This innermost & larger of Mars' 2 moons orbits the planet every 7.65 hours", + "Answer": "Phobos" + }, + { + "Category": "FURNITURE", + "Question": "Jean-Pierre Rampal can tell you it's the term for the shallow channels cut into a column", + "Answer": "Fluting" + }, + { + "Category": "HOMETOWNS", + "Question": "Daphne DuMaurier", + "Answer": "London" + }, + { + "Category": "KILLER MUSICALS", + "Question": "Billy Bigelow kills himself after a botched hold-up in this Rodgers & Hammerstein classic", + "Answer": "\"Carousel\"" + }, + { + "Category": "Y1K", + "Question": "In retaliation for Viking raids, this \"Unready\" king of England attacks Norse areas of the Isle of Man", + "Answer": "Ethelred" + }, + { + "Category": "\"PIN\" ME", + "Question": "Among dog breeds, this word follows miniature & Doberman", + "Answer": "Pinscher" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "A magnetic field is measured in units called gauss or this after a real \"coil\" guy", + "Answer": "Nikola Tesla" + }, + { + "Category": "FURNITURE", + "Question": "He designed furniture for Federal Hall in New York as well as the basic layout of Washington, D.C.", + "Answer": "Pierre L'Enfant" + }, + { + "Category": "HOMETOWNS", + "Question": "Jorge Luis Borges", + "Answer": "Buenos Aires" + }, + { + "Category": "KILLER MUSICALS", + "Question": "\"Chronicle of A Death Foretold\", which begins with a murder, is based on a novel by this Colombian author", + "Answer": "Gabriel Garcia Marquez" + }, + { + "Category": "Y1K", + "Question": "With the crowning of King Boleslaw, this central European nation is recognized as an independent state", + "Answer": "Poland" + }, + { + "Category": "\"PIN\" ME", + "Question": "Gilbert & Sullivan's naval vessel", + "Answer": "H.M.S. Pinafore" + }, + { + "Category": "AMERICAN AUTHORS", + "Question": "His bestselling first novel, published in 1846, was set in Polynesia", + "Answer": "Herman Melville" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "A rectifier is an electrical device used to convert alternating current to this", + "Answer": "direct current" + }, + { + "Category": "GIRLS IN SONG", + "Question": "\"Went to a dance lookin' for romance, saw\" this girl, \"so I thought I'd take a chance\"", + "Answer": "Barbara Ann" + }, + { + "Category": "SEE THE USA", + "Question": "The science museum in this Virginia capital called its 1987 Science Circus \"The Greatest Earth on Show\"", + "Answer": "Richmond, Virginia" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "A group of vipers, even if the snakes don't live in a bird's dwelling", + "Answer": "a nest" + }, + { + "Category": "WEAPONS", + "Question": "From the Germanic \"hache\", it's a small ax", + "Answer": "a hatchet" + }, + { + "Category": "THIS IS JEOPARDY!", + "Question": "With a cash total of $172,800, he's Jeopardy!'s biggest winner ever", + "Answer": "Chuck Forrest" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "On Earth, it's the major force responsible for the weight of a body", + "Answer": "gravity" + }, + { + "Category": "GIRLS IN SONG", + "Question": "In Ritchie Valens' day, this song about a girl was more popular than its flip side, \"La Bamba\"", + "Answer": "Donna" + }, + { + "Category": "SEE THE USA", + "Question": "This is 1 of NYC's longest streets, which you'll find out when you give your regards to it", + "Answer": "Broadway" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "Kangaroos, monkeys & Boy Scouts all come in these groups", + "Answer": "troops" + }, + { + "Category": "WEAPONS", + "Question": "U.S. land-based long-range nuclear missile that shares name with type of Revolutionary War fighter", + "Answer": "a Minuteman" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "At 15 on the modified Mohs' scale, this substance still has the highest hardness number", + "Answer": "a diamond" + }, + { + "Category": "GIRLS IN SONG", + "Question": "According to Rodgers & Hart, \"The most beautiful girl in the world isn't\" either of these 2 stars", + "Answer": "Garbo & Dietrich" + }, + { + "Category": "SEE THE USA", + "Question": "This city's voodoo tours can take you to voodoo rituals & voodo queen Marie Laveau's tomb on Basin St.", + "Answer": "New Orleans" + }, + { + "Category": "ANIMAL GROUPS", + "Question": "Though not noted for their musical skills, a group of gorillas is called this", + "Answer": "a band" + }, + { + "Category": "WEAPONS", + "Question": "One might be fired \"out of the blue\"--from a crossbow", + "Answer": "a bolt" + }, + { + "Category": "THIS IS JEOPARDY!", + "Question": "On this late night host's list of 10 Things Communists Are No Damn Good At, #1 was \"Guessing Final Jeopardy\"", + "Answer": "David Letterman" + }, + { + "Category": "PHYSICAL SCIENCE", + "Question": "Abbreviated \"P\", this element comes in red, white, & black forms", + "Answer": "phosphorus" + }, + { + "Category": "GIRLS IN SONG", + "Question": "In 1964 The Bachelors told this girl, \"I'm in heaven when I see you smile\"", + "Answer": "Diane" + }, + { + "Category": "SEE THE USA", + "Question": "It was almost named \"Texas Under 6 Flags\", but someone said \"Texas ain't never been under nothin'!\"", + "Answer": "Six Flags Over Texas" + }, + { + "Category": "THIS IS JEOPARDY!", + "Question": "In 1984, he made the music video \"I Lost On Jeopardy\"", + "Answer": "\"Weird Al\" Yankovic" + }, + { + "Category": "GIRLS IN SONG", + "Question": "According to Frankie Laine, \"If ever the devil was born without a pair of horns it was\" this woman", + "Answer": "you, Jezebel, it was you" + }, + { + "Category": "SEE THE USA", + "Question": "You can \"Go Home Again\" to see this author's boyhood home in Asheville, North Carolina", + "Answer": "Thomas Wolfe" + }, + { + "Category": "THIS IS JEOPARDY!", + "Question": "On the original version, this was the highest dollar value on the Double Jeopardy! board", + "Answer": "$100 " + }, + { + "Category": "HORS D'OEUVRES", + "Question": "From Latin for \"undigested food\", crudites refers to these", + "Answer": "raw vegetables" + }, + { + "Category": "HISTORY", + "Question": "Peregrine White, the 1st child born in New England of English parents, was born on this ship", + "Answer": "the Mayflower" + }, + { + "Category": "THE HUSBAND MARRIED", + "Question": "Helen Menken, Mary Philips, Mayo Methot & Lauren Bacall", + "Answer": "Humphrey Bogart" + }, + { + "Category": "SHAKESPEARE'S WOMEN", + "Question": "Shakespearean play featuring Falstaff & some \"happy homemakers\"", + "Answer": "The Merry Wives of Windsor" + }, + { + "Category": "STARTS WITH \"W\"", + "Question": "To wrench painfully, like your mom might threaten to do to your neck", + "Answer": "wring" + }, + { + "Category": "CZECH, PLEASE", + "Question": "In Czech, it's \"Praha\", & it's over 1000 years old", + "Answer": "Prague" + }, + { + "Category": "HORS D'OEUVRES", + "Question": "Chicken livers & water chestnuts wrapped in bacon; fortune cookies to follow", + "Answer": "rumaki" + }, + { + "Category": "HISTORY", + "Question": "Year in which Franklin Roosevelt was elected for an unprecedented 3rd term as president", + "Answer": "1940" + }, + { + "Category": "THE HUSBAND MARRIED", + "Question": "Virginia Cherrill, Barbara Hutton, Betsy Drake, Dyan Cannon & Barbara Harris", + "Answer": "Cary Grant" + }, + { + "Category": "SHAKESPEARE'S WOMEN", + "Question": "Name shared by Brutus' wife & the longest female role in \"The Merchant of Venice\"", + "Answer": "Portia" + }, + { + "Category": "STARTS WITH \"W\"", + "Question": "Both the first & last emperors of modern Germany bore this name", + "Answer": "Wilhelm" + }, + { + "Category": "CZECH, PLEASE", + "Question": "His mother, Olga, was once ranked 2nd in Czechoslovakia in women's singles tennis", + "Answer": "Ivan Lendl" + }, + { + "Category": "HORS D'OEUVRES", + "Question": "Ideally, this type of small appetizer served on toast or crackers should be small enough to eat in 1 bite", + "Answer": "canapé" + }, + { + "Category": "HISTORY", + "Question": "Before he was Canada's P.M., William Lyon Mackenzie King lived in this famous house with Jane Addams", + "Answer": "Hull House" + }, + { + "Category": "THE HUSBAND MARRIED", + "Question": "He married Colleen Dewhurst twice & Trish Van Devere once", + "Answer": "George C. Scott" + }, + { + "Category": "SHAKESPEARE'S WOMEN", + "Question": "The daughter of Polonius", + "Answer": "Ophelia" + }, + { + "Category": "STARTS WITH \"W\"", + "Question": "The cicada killer is a large predatory variety of this insect", + "Answer": "a wasp" + }, + { + "Category": "CZECH, PLEASE", + "Question": "For poetry that eschews all \"dogmas & dictates\", Jaroslav Seifert won this in 1984", + "Answer": "the Nobel Prize" + }, + { + "Category": "HORS D'OEUVRES", + "Question": "This chic Middle-Eastern dip is made primarily from chickpeas & served with pita bread", + "Answer": "hummus" + }, + { + "Category": "HISTORY", + "Question": "In 1962, this country became a constitutional monarchy under King Hassan II", + "Answer": "Morocco" + }, + { + "Category": "THE HUSBAND MARRIED", + "Question": "Joan Blondell & June Allyson", + "Answer": "Dick Powell" + }, + { + "Category": "SHAKESPEARE'S WOMEN", + "Question": "Comedy which features the wedding of Hippolyta, the queen of the Amazons", + "Answer": "A Midsummer Night's Dream" + }, + { + "Category": "STARTS WITH \"W\"", + "Question": "It found no evidence of a conspiracy involving Oswald & Ruby", + "Answer": "the Warren Commission" + }, + { + "Category": "CZECH, PLEASE", + "Question": "Treaty of friendship, cooperations, & mutual assistance that Czechoslovakia signed in 1955", + "Answer": "the Warsaw Pact" + }, + { + "Category": "HORS D'OEUVRES", + "Question": "Hors d'oeuvres is French for \"outside of\" this, which is usually when they're served", + "Answer": "work" + }, + { + "Category": "HISTORY", + "Question": "The 1st prime minister of independent Kenya", + "Answer": "Jomo Kenyatta" + }, + { + "Category": "THE HUSBAND MARRIED", + "Question": "Mary Todhunter Clark & Margaretta \"Happy\" Murphy", + "Answer": "Nelson Rockefeller" + }, + { + "Category": "SHAKESPEARE'S WOMEN", + "Question": "In the 1st act, before he's king, this title character woos the newly-widowed Lady Anne", + "Answer": "Richard III" + }, + { + "Category": "STARTS WITH \"W\"", + "Question": "The eve of May Day, on which witches were believed to rendezvous", + "Answer": "Walpurgisnacht" + }, + { + "Category": "CZECH, PLEASE", + "Question": "Maryam d'Abo played a Czech cellist in this 1987 film", + "Answer": "The Living Daylights" + }, + { + "Category": "SOUTH AMERICA", + "Question": "These are the only 2 independent countries in South America named for a famous person", + "Answer": "Colombia & Bolivia" + }, + { + "Category": "EXPLORERS", + "Question": "In 1918 Roald Amundsen was attacked by one of these large white animals", + "Answer": "Polar bear" + }, + { + "Category": "NOVEL QUOTES", + "Question": "\"Never laugh at live dragons\", warned this author in \"The Hobbit\" -- good advice", + "Answer": "J.R.R. Tolkien" + }, + { + "Category": "THE ENTERTAINMENT BUSINESS", + "Question": "Russell Simmons & Rick Rubin founded Def Jam, the '80s' premier record label for this type of music", + "Answer": "Rap" + }, + { + "Category": "FLOPS", + "Question": "Ford, '57, flop, 'nuf said", + "Answer": "Edsel" + }, + { + "Category": "\"PU\"", + "Question": "It's the time of life when a young man's fancy lightly turns to thoughts of....sex", + "Answer": "Puberty" + }, + { + "Category": "RICH & FAMOUS", + "Question": "In 1968 this future presidential candidate's stock in E.D.S. made him a billionaire", + "Answer": "Ross Perot" + }, + { + "Category": "EXPLORERS", + "Question": "In 1848 Johannes Rebmann became the first European to see & describe \"the snows\" of this African mountain", + "Answer": "Kilimanjaro" + }, + { + "Category": "NOVEL QUOTES", + "Question": "The novel that gave us the famous phrase \"Tous pour un, un pour tous\"", + "Answer": "The Three Musketeers" + }, + { + "Category": "THE ENTERTAINMENT BUSINESS", + "Question": "In 1994 Pearl Jam complained to the Justice Dept. that this company held a monopoly", + "Answer": "Ticketmaster" + }, + { + "Category": "FLOPS", + "Question": "This former NFL linebacker's show \"Lawless\" was sacked in March 1997 after one airing", + "Answer": "Brian Bosworth" + }, + { + "Category": "\"PU\"", + "Question": "Oscar De La Hoya or Evander Holyfield", + "Answer": "Pugilist" + }, + { + "Category": "RICH & FAMOUS", + "Question": "This billionaire fashion designer introduced Polo jeans in 1996", + "Answer": "Ralph Lauren" + }, + { + "Category": "EXPLORERS", + "Question": "Meriwether Lewis fed her ground rattlesnake rattle to speed up her labor & the birth of her child", + "Answer": "Sacajawea" + }, + { + "Category": "NOVEL QUOTES", + "Question": "Its less famous second line is \"It was the age of wisdom, it was the age of foolishness\"", + "Answer": "A Tale Of Two Cities" + }, + { + "Category": "THE ENTERTAINMENT BUSINESS", + "Question": "Legendary promoter who ran the Fillmore West in the Bay Area & the Fillmore East in NYC", + "Answer": "Bill Graham" + }, + { + "Category": "FLOPS", + "Question": "With teams including the Florida Blazers, this football league lasted for 1 1/2 seasons in '74-'75", + "Answer": "WFL" + }, + { + "Category": "\"PU\"", + "Question": "It's another name for the cougar or mountain lion", + "Answer": "Puma" + }, + { + "Category": "RICH & FAMOUS", + "Question": "A 1994 book details the \"way\" he became \"the world's greatest investor\"", + "Answer": "Warren Buffett" + }, + { + "Category": "EXPLORERS", + "Question": "Louis Antoine de Bougainville arrived at this island in 1768 & natives gave him fowls, fruit & naked women", + "Answer": "Tahiti" + }, + { + "Category": "NOVEL QUOTES", + "Question": "\"Great men can't be ruled\", she wrote in \"The Fountainhead\"", + "Answer": "Ayn Rand" + }, + { + "Category": "THE ENTERTAINMENT BUSINESS", + "Question": "Stanley Durwood of AMC pioneered these cinemas, putting his first in a shopping mall in 1963", + "Answer": "Multiplexes" + }, + { + "Category": "FLOPS", + "Question": "Roger Ebert called this 1980 Michael Cimino film \"Painful & unpleasant to look at\"", + "Answer": "Heaven's Gate" + }, + { + "Category": "\"PU\"", + "Question": "It means downright rotten", + "Answer": "Putrid" + }, + { + "Category": "RICH & FAMOUS", + "Question": "The William who runs this chewing gum company is the grandson of the William who founded it", + "Answer": "Wrigley" + }, + { + "Category": "EXPLORERS", + "Question": "His family friend Tyrker found vines & grapes in the new land, so he called the area Vinland", + "Answer": "Leif Ericson" + }, + { + "Category": "NOVEL QUOTES", + "Question": "\"...They ought to find a way of being inoculated against love\" is a line from his \"Anna Karenina\"", + "Answer": "Leo Tolstoy" + }, + { + "Category": "THE ENTERTAINMENT BUSINESS", + "Question": "When you buy a Sunset book, a Tom Petty CD or People magazine, you're supporting this conglomerate", + "Answer": "Time Warner" + }, + { + "Category": "FLOPS", + "Question": "\"La Traviata\", his modern-dress opera version of \"La Dame Aux Camelias\", flopped in its 1853 premiere", + "Answer": "Giuseppe Verdi" + }, + { + "Category": "\"PU\"", + "Question": "The third of these wars wiped Carthage off the map, though it was later rebuilt", + "Answer": "The Punic Wars" + }, + { + "Category": "RICH & FAMOUS", + "Question": "Microsoft co-founder Paul Allen owns this Portland sports team", + "Answer": "Portland Trail Blazers" + }, + { + "Category": "\"DOUBLE\" JEOPARDY", + "Question": "Grammatical error committed by the Rolling Stones when they sang, \"I Can't Get No Satisfaction\"", + "Answer": "Double negative" + }, + { + "Category": "MUSEUM HOPPING", + "Question": "\"Ain't No Mountain High Enough\" to keep music fans from visiting this record co.'s Detroit museum", + "Answer": "Motown" + }, + { + "Category": "SPORTS", + "Question": "The new 23,500-seat U.S. Tennis Open Stadium is named for this star who died February 6, 1993", + "Answer": "Arthur Ashe" + }, + { + "Category": "GIANTS OF SCIENCE", + "Question": "You'll find this Frenchman's name on almost all milk cartons", + "Answer": "Louis Pasteur" + }, + { + "Category": "BEFORE THEY WERE POPES", + "Question": "Alexander VI was formerly a high-living nobleman of this family & the father of Cesare & Lucrezia", + "Answer": "Borgia" + }, + { + "Category": "POOR & FAMOUS", + "Question": "He drank up the money he got for songs like \"Oh! Susanna\" & died with 38c in his pocket", + "Answer": "Stephen Foster" + }, + { + "Category": "\"DOUBLE\" JEOPARDY", + "Question": "(VIDEO DAILY DOUBLE): Action seen here: (Curly Howard) - \"Hey you, this is no time to play games - ewww!\"", + "Answer": "Double take" + }, + { + "Category": "MUSEUM HOPPING", + "Question": "MoMA Mia! It houses such masterpieces as \"Starry Night\" & Cezanne's \"Bather\"", + "Answer": "Museum of Modern Art" + }, + { + "Category": "SPORTS", + "Question": "Except for 1995, the NHL scoring title has gone to either Wayne Gretzky or this Penguins star the past 16 years", + "Answer": "Mario Lemieux" + }, + { + "Category": "GIANTS OF SCIENCE", + "Question": "By then living in the U.S., he was offered the presidency of Israel in 1952", + "Answer": "Albert Einstein" + }, + { + "Category": "BEFORE THEY WERE POPES", + "Question": "Giovanni Ganganelli was educated by this teaching society; as Clement XIV, he suppressed it", + "Answer": "Jesuits" + }, + { + "Category": "POOR & FAMOUS", + "Question": "Despite help from Engels in the 1850s, he & his family often subsisted on bread & potatoes", + "Answer": "Karl Marx" + }, + { + "Category": "\"DOUBLE\" JEOPARDY", + "Question": "In this form of jumping rope, 2 people twirl 2 jump ropes in the opposite direction simultaneously", + "Answer": "Double Dutch" + }, + { + "Category": "MUSEUM HOPPING", + "Question": "This British museum received its present name in 1899, though many refer to it as the V & A", + "Answer": "Victoria & Albert" + }, + { + "Category": "SPORTS", + "Question": "On Oct. 19, 1924 Grantland Rice wrote of this team's backfield \"The Four Horsemen Rode Again\"", + "Answer": "Notre Dame" + }, + { + "Category": "GIANTS OF SCIENCE", + "Question": "In 1993 he made a \"brief\" appearance as himself on an episode of \"Star Trek: The Next Generation\"", + "Answer": "Stephen Hawking" + }, + { + "Category": "BEFORE THEY WERE POPES", + "Question": "This pope who called the Second Vatican Council was a quiet church conformist until his 1958 election", + "Answer": "Pope John XXIII" + }, + { + "Category": "POOR & FAMOUS", + "Question": "He spent years in poverty after selling his sewing machine invention to corset maker William Thomas", + "Answer": "Elias Howe" + }, + { + "Category": "\"DOUBLE\" JEOPARDY", + "Question": "In \"1984\" George Orwell coined this term for the acceptance of 2 contradictory ideas at the same time", + "Answer": "Doublethink" + }, + { + "Category": "MUSEUM HOPPING", + "Question": "Before going \"Out Of Africa\", you might visit the museum devoted to this author near Nairobi", + "Answer": "Isak Dinesen" + }, + { + "Category": "SPORTS", + "Question": "(VIDEO DAILY DOUBLE): \"(Hi, I'm Mike Piazza) I was the NL's '93 Rookie Of The Year. In '68 this Cincinnati Reds player became the 1st catcher to win the award\"", + "Answer": "Johnny Bench" + }, + { + "Category": "GIANTS OF SCIENCE", + "Question": "Good Lord! With absolute zero heirs at his death in 1907, this physicist's peerage became extinct", + "Answer": "Lord Kelvin" + }, + { + "Category": "BEFORE THEY WERE POPES", + "Question": "This Dutch Renaissance humanist was a pupil of Adrian VI, the only Dutch pope", + "Answer": "Erasmus" + }, + { + "Category": "POOR & FAMOUS", + "Question": "This Russian's 1866 novel \"The Gambler\" is based on his own ruinous passion for roulette", + "Answer": "Fyodor Dostoyevsky" + }, + { + "Category": "\"DOUBLE\" JEOPARDY", + "Question": "Line preceding \"Fire burn and cauldron bubble\"", + "Answer": "\"Double double, toil and trouble\" " + }, + { + "Category": "MUSEUM HOPPING", + "Question": "The Rosenbach Museum & Library in Philadelphia houses his original manuscript of \"Ulysses\"", + "Answer": "James Joyce" + }, + { + "Category": "SPORTS", + "Question": "Earl Anthony rolled on to a record 41 titles in this sport, Mark Roth is second", + "Answer": "Bowling" + }, + { + "Category": "GIANTS OF SCIENCE", + "Question": "\"Father of the A-Bomb\" who recalled the Hindu line \"I am become death\" after the first atomic explosion", + "Answer": "J. Robert Oppenheimer" + }, + { + "Category": "BEFORE THEY WERE POPES", + "Question": "Pius XII previously held this Vatican office that, like its U.S. cabinet counterpart, requires travel", + "Answer": "Secretary of State" + }, + { + "Category": "POOR & FAMOUS", + "Question": "She fled her rich Assisi family to found an order of \"poor\" nuns", + "Answer": "Saint Clare" + }, + { + "Category": "BATTLES", + "Question": "Napoleon's plans to invade England were dashed by this October 21, 1805 battle", + "Answer": "Battle of Trafalgar" + }, + { + "Category": "STATE CAPITALS", + "Question": "A statue of King Kamehameha I stands guard outside the judiciary building in this capital city", + "Answer": "Honolulu" + }, + { + "Category": "CliffsNotes", + "Question": "Livestock successfully stage rebellion, pigs end up blowing it for everyone", + "Answer": "\"Animal Farm\"" + }, + { + "Category": "SSSSSSSSNAKES!!!!!", + "Question": "The appendage seen here gives this variety of snake its name", + "Answer": "rattlesnake" + }, + { + "Category": "THE KIDS LOVE THAT ROCK & ROLL", + "Question": "A1, Take That & the Spice Girls are all musical acts from this country", + "Answer": "Great Britain" + }, + { + "Category": "ANYTHING BUT CHEESESTEAK", + "Question": "This hot dog condiment is basically chopped sweet pickles", + "Answer": "relish" + }, + { + "Category": "5-LETTER WORDS", + "Question": "Headgear for a king, or part of a tooth", + "Answer": "crown" + }, + { + "Category": "STATE CAPITALS", + "Question": "From 1701 to 1875 New Haven & this city were twin capitals of Connecticut; today it's the only one", + "Answer": "Hartford" + }, + { + "Category": "CliffsNotes", + "Question": "Title guy shipwrecks, ends up on 28-year island getaway, makes a friend, goes home", + "Answer": "\"Robinson Crusoe\"" + }, + { + "Category": "SSSSSSSSNAKES!!!!!", + "Question": "Snakes are found naturally on every continent except this one", + "Answer": "Antarctica" + }, + { + "Category": "THE KIDS LOVE THAT ROCK & ROLL", + "Question": "Of King Ad Rock, Thugmuffin C, MCA or Mike D, the one who's not a member of the Beastie Boys", + "Answer": "Thugmuffin C" + }, + { + "Category": "ANYTHING BUT CHEESESTEAK", + "Question": "The \"Kid' seen here represents these snacks", + "Answer": "Twinkies" + }, + { + "Category": "5-LETTER WORDS", + "Question": "It \"goes before a fall\" & before \"Prejudice\" in a Jane Austen title", + "Answer": "pride" + }, + { + "Category": "STATE CAPITALS", + "Question": "The capitol building in this city was designed by Thomas Jefferson", + "Answer": "Richmond" + }, + { + "Category": "CliffsNotes", + "Question": "2 guys dream of owning a farm, one kills the boss' daughter-in-law, then his pal kills him", + "Answer": "\"Of Mice and Men\"" + }, + { + "Category": "SSSSSSSSNAKES!!!!!", + "Question": "There are king & Asian species of this \"charming\" snake seen here", + "Answer": "cobra" + }, + { + "Category": "THE KIDS LOVE THAT ROCK & ROLL", + "Question": "In 1998 Will Smith was \"Gettin'\" to the No. 1 spot on the charts with this song", + "Answer": "\"Gettin' Jiggy Wit It\"" + }, + { + "Category": "ANYTHING BUT CHEESESTEAK", + "Question": "Chicken chunks & chopped veggies in a rich sauce topped with a pastry crust are baked in this \"pie\"", + "Answer": "chicken pot pie" + }, + { + "Category": "5-LETTER WORDS", + "Question": "It's the zodiac sign symbolized by a ram", + "Answer": "Aries" + }, + { + "Category": "STATE CAPITALS", + "Question": "The French called a land formation La Petite Roche, thus giving this capital its name", + "Answer": "Little Rock" + }, + { + "Category": "CliffsNotes", + "Question": "Frenchman swipes some bread, gets 19 years, gets out, gets pursued by a cop who dies", + "Answer": "\"Les Miserables\"" + }, + { + "Category": "SSSSSSSSNAKES!!!!!", + "Question": "This highly venomous snake of the eastern U.S. has red & black bands separated by yellow ones", + "Answer": "coral snake" + }, + { + "Category": "THE KIDS LOVE THAT ROCK & ROLL", + "Question": "That \"Fly\" band Sugar Ray is led by this heartthrob lead singer", + "Answer": "Mark McGrath" + }, + { + "Category": "ANYTHING BUT CHEESESTEAK", + "Question": "Part of a British breakfast, this jam is made from bitter Seville oranges, including the rinds", + "Answer": "marmalade" + }, + { + "Category": "5-LETTER WORDS", + "Question": "Soup's on! & we need this long-handled spoon or scoop to serve it", + "Answer": "ladle" + }, + { + "Category": "STATE CAPITALS", + "Question": "This state capital is in the Green Mountains along the Winooski River", + "Answer": "Montpelier" + }, + { + "Category": "CliffsNotes", + "Question": "Con man checks into mental hospital to avoid prison farm, meets nasty nurse, doesn't check out", + "Answer": "\"One Flew Over the Cuckoo's Nest\"" + }, + { + "Category": "SSSSSSSSNAKES!!!!!", + "Question": "The name of this deadly mottled brown snake of the tropics is from the French for \"lance head\"", + "Answer": "fer-de-lance" + }, + { + "Category": "THE KIDS LOVE THAT ROCK & ROLL", + "Question": "Known for '80s hits like \"The Reflex\" & \"Hungry Like the Wolf\", this band charted in the '90s with \"Come Undone\"", + "Answer": "Duran Duran" + }, + { + "Category": "ANYTHING BUT CHEESESTEAK", + "Question": "The French have Catherine de Medici to thank for introducing this sprouting Italian veggie to them", + "Answer": "broccoli" + }, + { + "Category": "5-LETTER WORDS", + "Question": "It can be an object from the past, or a personal item associated with a saint", + "Answer": "relic" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "He was the only U.S. president to die in the 18th century", + "Answer": "George Washington" + }, + { + "Category": "BROADWAY TEENS", + "Question": "[clue missing because of technical glitch]", + "Answer": "Anne Frank" + }, + { + "Category": "YOUTH IN ASIA", + "Question": "Like voters in the USA, young women seeking to compete in the Miss Thailand contest must be at least this age", + "Answer": "18" + }, + { + "Category": "SCIENCE GUYS", + "Question": "Not even a wheelchair & voice synthesizer can stop him from unlocking the secrets of the universe", + "Answer": "Stephen Hawking" + }, + { + "Category": "CORPORATE SPORTS VENUES", + "Question": "Chicago's United Center & Salt Lake City's Delta Center are named for this type of business", + "Answer": "airlines" + }, + { + "Category": "ANIMAL RHYME TIME", + "Question": "An informal talk about flying mammals", + "Answer": "bat chat" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "This former general was the first Republican to serve 2 full terms as president", + "Answer": "Ulysses S. Grant" + }, + { + "Category": "BROADWAY TEENS", + "Question": "Brooke Shields & Lucy Lawless played Rizzo in the '90s revival of this rockin' high school musical", + "Answer": "Grease" + }, + { + "Category": "YOUTH IN ASIA", + "Question": "The 100-member Asian Youth Orchestra recently played to rave reviews in this South Korean capital", + "Answer": "Seoul" + }, + { + "Category": "SCIENCE GUYS", + "Question": "In 1610 this Italian made his biggest discovery: the 4 largest moons of Jupiter", + "Answer": "Galileo" + }, + { + "Category": "CORPORATE SPORTS VENUES", + "Question": "This Disney-owned baseball team plays at Anaheim's Edison International Field", + "Answer": "Anaheim Angels" + }, + { + "Category": "ANIMAL RHYME TIME", + "Question": "Small vessel for shipping a nanny or a billy", + "Answer": "goat boat" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "This Mexican War hero & winning 1848 candidate had never voted for president before", + "Answer": "Zachary Taylor" + }, + { + "Category": "BROADWAY TEENS", + "Question": "R&B sensation Stephanie Mills was a teenager when she eased on down the road in this role in \"The Wiz\"", + "Answer": "Dorothy" + }, + { + "Category": "YOUTH IN ASIA", + "Question": "Young actors like Rani Mukherjee perform in movies in \"Bollywood\" in this populous Asian country", + "Answer": "India" + }, + { + "Category": "SCIENCE GUYS", + "Question": "This \"Father of Genetics\" is the subject of the biography \"The Monk in the Garden\"", + "Answer": "Gregor Mendel" + }, + { + "Category": "CORPORATE SPORTS VENUES", + "Question": "This team that won a championship in 2001 plays in PSINet Stadiun", + "Answer": "Baltimore Ravens" + }, + { + "Category": "ANIMAL RHYME TIME", + "Question": "A fake small horse", + "Answer": "phony pony" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "In 1950 he threatened a music critic who had unkind words for daughter Margaret's singing", + "Answer": "Harry S. Truman" + }, + { + "Category": "BROADWAY TEENS", + "Question": "The Jets & the Sharks are teenage gangs in this 1957 musical that features the song \"Tonight\"", + "Answer": "West Side Story" + }, + { + "Category": "YOUTH IN ASIA", + "Question": "With songs like \"Fly Away\", rock star Cui Jian is one of the leading pop musicians from this Asian country", + "Answer": "China" + }, + { + "Category": "SCIENCE GUYS", + "Question": "At the Pantheon in Paris in 1851, he demonstrated the Earth's rotation using his famous pendulum", + "Answer": "Michel Foucault" + }, + { + "Category": "CORPORATE SPORTS VENUES", + "Question": "Now that this city's Civic Arena is the Mellon Arena, its citizens can be full of Mellon pride", + "Answer": "Pittsburgh" + }, + { + "Category": "ANIMAL RHYME TIME", + "Question": "The $1.99 lamb as opposed to the $19.99 one", + "Answer": "cheap sheep" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "His 1791 marriage to Rachel Robards was invalid, so they had to do it all over again on January 17, 1794", + "Answer": "Andrew Jackson" + }, + { + "Category": "BROADWAY TEENS", + "Question": "Zaneeta Shinn, a character in this musical, is the teenage daughter of the mayor of River City", + "Answer": "The Music Man" + }, + { + "Category": "YOUTH IN ASIA", + "Question": "With a 6-wicket victory over Nepal, Bangladesh recently retained the Asian youth championship in this sport", + "Answer": "cricket" + }, + { + "Category": "SCIENCE GUYS", + "Question": "He was doing research on influenza when he accidentally discovered penicillin", + "Answer": "Alexander Fleming" + }, + { + "Category": "CORPORATE SPORTS VENUES", + "Question": "3-letter corporate name that's on the Indianapolis venue seen here", + "Answer": "RCA Dome" + }, + { + "Category": "ANIMAL RHYME TIME", + "Question": "An 18-wheeler used to get your porkers to market", + "Answer": "pig rig" + }, + { + "Category": "SOUTH AMERICA", + "Question": "One of 2 landlocked countries in South America", + "Answer": "Bolivia or Paraguay" + }, + { + "Category": "THE OLD WEST", + "Question": "This lieutenant colonel recruited some of his Rough Riders at William Menger's hotel in San Antonio", + "Answer": "Theodore Roosevelt" + }, + { + "Category": "THE 1970 TV SEASON", + "Question": "The prime time spellcaster wasn't Sabrina, but Samantha in this series", + "Answer": "Bewitched" + }, + { + "Category": "TOUGH STUFF", + "Question": "It includes the postcentral gyrus, the precentral gyrus, the parietal lobe & the occipital lobe", + "Answer": "Brain/skull" + }, + { + "Category": "INSECTS", + "Question": "The May beetle is also called this, perhaps when it shows up a few weeks late", + "Answer": "Junebug" + }, + { + "Category": "NO. 32", + "Question": "The Los Angeles Lakers retired his No. 32 jersey", + "Answer": "Earvin \"Magic\" Johnson" + }, + { + "Category": "CROSSWORD CLUES \"G\"", + "Question": "Disgruntled Disney dwarf (6)", + "Answer": "Grumpy" + }, + { + "Category": "THE OLD WEST", + "Question": "In Old West talk, \"fit\" was the past tense of this", + "Answer": "Fight" + }, + { + "Category": "TOUGH STUFF", + "Question": "Alphabetically, he's Santa's first reindeer", + "Answer": "Blitzen" + }, + { + "Category": "INSECTS", + "Question": "The katydid is also called the long-horned (meaning long-antennaed) one of these", + "Answer": "Grasshopper" + }, + { + "Category": "NO. 32", + "Question": "It begins \"Blessed is he whose transgression is forgiven\"", + "Answer": "32nd Psalm" + }, + { + "Category": "CROSSWORD CLUES \"G\"", + "Question": "Thank You, in Tampico (7)", + "Answer": "Gracias" + }, + { + "Category": "THE OLD WEST", + "Question": "This hat maker traveled west, saw a need & returned in 1865 to make his famous hat in Philadelphia", + "Answer": "John Stetson" + }, + { + "Category": "TOUGH STUFF", + "Question": "The Span. abbrev. for one of these is ovni (objecto volador no identificado)", + "Answer": "UFO" + }, + { + "Category": "INSECTS", + "Question": "Its shape allows it to hide among twigs", + "Answer": "Walking stick" + }, + { + "Category": "NO. 32", + "Question": "Before a crowd of almost 70,000, this team won Super Bowl XXXII January 25, 1998", + "Answer": "the Denver Broncos" + }, + { + "Category": "CROSSWORD CLUES \"G\"", + "Question": "A source of rumors, or of Riesling (9)", + "Answer": "Grapevine" + }, + { + "Category": "THE OLD WEST", + "Question": "He tried to help the town of Dolores, N.M. in 1900 by using static electricity to extract gold out of gravel", + "Answer": "Thomas Edison" + }, + { + "Category": "TOUGH STUFF", + "Question": "Over 14 times the mass of the Earth, this planet is seventh from the sun", + "Answer": "Uranus" + }, + { + "Category": "INSECTS", + "Question": "This fly that you might find \"in distress\" resembles a dragonfly but folds its wings back at rest", + "Answer": "Damselfly" + }, + { + "Category": "NO. 32", + "Question": "On May 11, 1858 this \"North Star\" state became U.S. state No. 32", + "Answer": "Minnesota" + }, + { + "Category": "CROSSWORD CLUES \"G\"", + "Question": "You throw it down, or run it (8)", + "Answer": "Gauntlet" + }, + { + "Category": "THE OLD WEST", + "Question": "Ogden, now this state's sixth-largest city, was named for an Old West fur trapper", + "Answer": "Utah" + }, + { + "Category": "TOUGH STUFF", + "Question": "A patron of wisdom & good fortune, the Hindu god Ganesha bears the head of this animal", + "Answer": "Elephant" + }, + { + "Category": "INSECTS", + "Question": "Because of its colors the butterfly seen here is named after this beast (orange & black colors)", + "Answer": "Tiger butterfly" + }, + { + "Category": "NO. 32", + "Question": "The 32nd Academy Award for Best Picture went to this 1959 epic", + "Answer": "Ben-Hur" + }, + { + "Category": "CROSSWORD CLUES \"G\"", + "Question": "\"Cheesy\" Dutch city (5)", + "Answer": "Gouda" + }, + { + "Category": "EXPLORERS", + "Question": "On July 4, 1803 Thomas Jefferson supplied this pair with a general letter of credit to use on their trip", + "Answer": "Lewis & Clark" + }, + { + "Category": "STOCK SYMBOLS", + "Question": "We'll never tire of telling you its symbol is GR, not B.F.", + "Answer": "Goodrich" + }, + { + "Category": "IN THE GOOD OLD SUMER TIME", + "Question": "Mythic Sumerian hero Utnapishtim built a big boat & survived this catastrophe", + "Answer": "The flood" + }, + { + "Category": "BRITISH BANDS & SINGERS", + "Question": "1997's \"Calling All Stations\" was their first album since Phil Collins left the group", + "Answer": "Genesis" + }, + { + "Category": "THEY REST IN NEBRASKA", + "Question": "Grover Cleveland Alexander was inducted into this sport's Hall of Fame in 1938 & interred in Nebraska in 1950", + "Answer": "Baseball" + }, + { + "Category": "\"AD\"JECTIVES", + "Question": "It refers to the behavior of teenagers, or of immature adults", + "Answer": "Adolescent" + }, + { + "Category": "EXPLORERS", + "Question": "Speke stopped speaking to Burton after their trip to find the source of this river", + "Answer": "Nile" + }, + { + "Category": "STOCK SYMBOLS", + "Question": "The annual report of this company, PRD, is as pretty as an instant picture", + "Answer": "Polaroid" + }, + { + "Category": "IN THE GOOD OLD SUMER TIME", + "Question": "Hammurabi was famous for his, but Ur-Nammu enforced one of these centuries earlier", + "Answer": "Code of law" + }, + { + "Category": "BRITISH BANDS & SINGERS", + "Question": "In 1990 Roger Waters of this group gave a performance of \"The Wall\" at the former site of the Berlin Wall", + "Answer": "Pink Floyd" + }, + { + "Category": "THEY REST IN NEBRASKA", + "Question": "Many \"Our Fathers\" must have been said when he died May 15, 1948 & was interred in Boys Town", + "Answer": "Father Flanagan" + }, + { + "Category": "\"AD\"JECTIVES", + "Question": "Fatty, like some \"tissue\"", + "Answer": "Adipose" + }, + { + "Category": "EXPLORERS", + "Question": "A book by Thomas James, who searched for the Northwest Passage, inspired this Coleridge poem", + "Answer": "\"The Rime of the Ancient Mariner\"" + }, + { + "Category": "STOCK SYMBOLS", + "Question": "Add \"YBOY\" to this 3-letter symbol to get the full name of a big media company", + "Answer": "PLA" + }, + { + "Category": "IN THE GOOD OLD SUMER TIME", + "Question": "Sumerians scratched this writing system into stone & wax in addition to clay tablets", + "Answer": "Cuneiform" + }, + { + "Category": "BRITISH BANDS & SINGERS", + "Question": "In 1998 this group seen here reunited for a VH1 special & a concert tour (\"I'll Tumble 4 Ya\")", + "Answer": "Culture Club" + }, + { + "Category": "THEY REST IN NEBRASKA", + "Question": "Though he starred in \"Oklahoma!\" this husband of Sheila is buried in Nebraska", + "Answer": "Gordon MacRae" + }, + { + "Category": "\"AD\"JECTIVES", + "Question": "It means \"sufficient or good enough\" & can imply \"but just barely\"", + "Answer": "Adequate" + }, + { + "Category": "EXPLORERS", + "Question": "Hillary said this man left some offerings to the gods of Chomolungma atop Everest in 1953", + "Answer": "Tenzing Norgay" + }, + { + "Category": "STOCK SYMBOLS", + "Question": "In the mall you may fall into this store, GPS", + "Answer": "The Gap" + }, + { + "Category": "IN THE GOOD OLD SUMER TIME", + "Question": "These Sumerian pyramids were topped by temples", + "Answer": "Ziggurats" + }, + { + "Category": "BRITISH BANDS & SINGERS", + "Question": "In 1995 this founder of Cream & Derek & the Dominos was named an Officer of the British Empire", + "Answer": "Eric Clapton" + }, + { + "Category": "THEY REST IN NEBRASKA", + "Question": "Long-time Nebraska senator George Norris, who helped create this project, the TVA, is buried in McCook", + "Answer": "Tennessee Valley Authority" + }, + { + "Category": "\"AD\"JECTIVES", + "Question": "Unfavorable, like some circumstances, or the last name of Anthony in a 1933 novel", + "Answer": "Adverse" + }, + { + "Category": "EXPLORERS", + "Question": "In 1828 Rene Caille reached this remote African city, \"an object of curiosity\" to Europeans", + "Answer": "Timbuktu" + }, + { + "Category": "STOCK SYMBOLS", + "Question": "You don't need a Visa to visit this bank's stock symbol, CMB", + "Answer": "Chase Manhattan Bank" + }, + { + "Category": "BRITISH BANDS & SINGERS", + "Question": "(Hi, I'm Graham Nash) As a member of this group in the 1960s, I co-wrote their hits \"Carrie-Anne\" & \"Stop, Stop, Stop\"", + "Answer": "The Hollies" + }, + { + "Category": "\"AD\"JECTIVES", + "Question": "Latin term for a type of argument based on emotion or on another person's character", + "Answer": "Ad hominem" + }, + { + "Category": "WORD ORIGINS", + "Question": "Today meaning a self-employed person, this term derives from medieval knights who sold their skills", + "Answer": "Freelancer" + }, + { + "Category": "ANCIENT TIMES", + "Question": "The ancient Ban Chiang poetry of Thailand resembles that of this country's neolithic Yang-Shao period", + "Answer": "China" + }, + { + "Category": "SPORTS EVOLUTION", + "Question": "In the 1750s the original golf course here had 11 holes & you played each of them twice", + "Answer": "St. Andrews" + }, + { + "Category": "A BUG'S LIFE", + "Question": "Known as Wandermeisen in German, these conspicuously mobile ants move about in long, orderly columns", + "Answer": "army ants" + }, + { + "Category": "ASTRONOMY ADD A LETTER", + "Question": "Add this letter to Earth & you get a scarcity", + "Answer": "D" + }, + { + "Category": "RICHARD", + "Question": "One man who had this name discovered Lake Tanganyika; the other played Becket & Trotsky on film", + "Answer": "Richard Burton" + }, + { + "Category": "THE SECOND...", + "Question": "...son born to Barbara Bush", + "Answer": "Jeb" + }, + { + "Category": "ANCIENT TIMES", + "Question": "Ancient Greeks believed that wine was a gift from this god, the Greek equivalent of Bacchus", + "Answer": "Dionysus" + }, + { + "Category": "A BUG'S LIFE", + "Question": "The chigoe is a sand-dwelling variety of this insect", + "Answer": "a flea" + }, + { + "Category": "ASTRONOMY ADD A LETTER", + "Question": "Add this letter to Mars & you get a fen", + "Answer": "H" + }, + { + "Category": "RICHARD", + "Question": "In 1886 Richard Sears began selling pocket watches & in 1887 hired this man as his watch repairman", + "Answer": "Roebuck" + }, + { + "Category": "THE SECOND...", + "Question": "...franchise to win the Super Bowl", + "Answer": "New York Jets" + }, + { + "Category": "ANCIENT TIMES", + "Question": "Because of his work there, you could call the astronomer Hipparchus \"the colossus of\" this island", + "Answer": "Rhodes" + }, + { + "Category": "SPORTS EVOLUTION", + "Question": "By the time the British discovered this sport in India around 1860, it used a ball, no longer a goat's or enemy's head", + "Answer": "polo" + }, + { + "Category": "A BUG'S LIFE", + "Question": "The field & house types of this insect are sold as laboratory subjects, frog food & bait", + "Answer": "crickets" + }, + { + "Category": "ASTRONOMY ADD A LETTER", + "Question": "Add this letter to Saturn's moon Titan & you get a Renaissance guy who liked to paint Venus", + "Answer": "I" + }, + { + "Category": "RICHARD", + "Question": "Either of the 2 parents of Richard the Lion-Hearted", + "Answer": "Henry II & Eleanor of Aquitaine" + }, + { + "Category": "THE SECOND...", + "Question": "...U.S. manned space program", + "Answer": "the Gemini program" + }, + { + "Category": "ANCIENT TIMES", + "Question": "Horrified by the carnage of war, Asoka, a 3rd century B.C. ruler in India, embraced this peaceful religion", + "Answer": "Buddhism" + }, + { + "Category": "A BUG'S LIFE", + "Question": "This garden pest controller is the state insect of Delaware & Massachusetts", + "Answer": "ladybug" + }, + { + "Category": "ASTRONOMY ADD A LETTER", + "Question": "Add this letter to Jupiter's moon Io & you get an acronym that's a ground-floor stock offer for regular guys", + "Answer": "P" + }, + { + "Category": "RICHARD", + "Question": "He shot the famous photo of Nastassja Kinski & the serpent", + "Answer": "Richard Avedon" + }, + { + "Category": "THE SECOND...", + "Question": "...to become Secretary of Homeland Security", + "Answer": "Michael Chertoff" + }, + { + "Category": "ANCIENT TIMES", + "Question": "Hetepheres was the mother of this Great Pyramid king; when her tomb was found, Mummy's mummy was missing", + "Answer": "Cheops" + }, + { + "Category": "SPORTS EVOLUTION", + "Question": "The 18th century Broughton rules were intended to lessen the brutality of this sport", + "Answer": "boxing" + }, + { + "Category": "A BUG'S LIFE", + "Question": "Used by scientists to clean flesh off bones being prepared for research, dermestids are a type of this insect", + "Answer": "a beetle" + }, + { + "Category": "ASTRONOMY ADD A LETTER", + "Question": "Add this letter to star & get something harsh or grim", + "Answer": "K" + }, + { + "Category": "RICHARD", + "Question": "He was actually in prison when he wrote, \"Stone walls do not a prison make, nor iron bars a cage\"", + "Answer": "Richard Lovelace" + }, + { + "Category": "THE SECOND...", + "Question": "...Sherlock Holmes novel published", + "Answer": "The Sign of Four" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "His second inaugural address began, \"At this last presidential inauguration of the twentieth century...\"", + "Answer": "Bill Clinton" + }, + { + "Category": "\"DON'T\" YOU KNOW THIS SONG?", + "Question": "Buenos Aires held back a sniffle when this Madonna hit went to No. 8 in 1997", + "Answer": "\"Don't Cry For Me Argentina\"" + }, + { + "Category": "TITLES FROM SHAKESPEARE", + "Question": "Beware Thornton Wilder's \"The Ides of March\" & this play where you'll find the phrase", + "Answer": "Julius Caesar" + }, + { + "Category": "FOR THE FASHIONISTA", + "Question": "Style.com stated that your spring 2006 wardrobe must include a baby-doll dress in the style of this decade", + "Answer": "the '60s" + }, + { + "Category": "FRANCE", + "Question": "Liberation & Le Petit Journal are leading ones of these in France", + "Answer": "newspapers" + }, + { + "Category": "4-LETTER FRIENDS", + "Question": "You were a fool to move that bishop! This 4-letter term in 3 moves", + "Answer": "mate" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "Subpoenaed for documents in Burr's treason trial, he cited executive privilege; didn't work", + "Answer": "Thomas Jefferson" + }, + { + "Category": "\"DON'T\" YOU KNOW THIS SONG?", + "Question": "It was Elvis' third No. 1 hit of 1956", + "Answer": "\"Don't Be Cruel\"" + }, + { + "Category": "TITLES FROM SHAKESPEARE", + "Question": "Faulkner's \"The Sound and the Fury\" as well as Steinbeck's \"The Moon Is Down\" come from this play", + "Answer": "Macbeth" + }, + { + "Category": "FOR THE FASHIONISTA", + "Question": "Of Elie Saab, Elie Saturn or Elie Subaru, the one who designed the gown Halle Berry wore when she won her Oscar", + "Answer": "Elie Saab" + }, + { + "Category": "FRANCE", + "Question": "With its team led by Zinedine Zidane, France won this prestigious contest in July 1998", + "Answer": "the World Cup" + }, + { + "Category": "4-LETTER FRIENDS", + "Question": "In \"Jaws\", it's what Roy Scheider threw overboard to lure the shark", + "Answer": "chum" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "His will gave a total of $110,000 to grandchildren Alexander & Melanie Eisenhower & Christopher Cox", + "Answer": "Nixon" + }, + { + "Category": "\"DON'T\" YOU KNOW THIS SONG?", + "Question": "No doubt you know this \"Tragic Kingdom\" tune was No. 1 for 16 weeks on the airplay chart in 1996 & '97", + "Answer": "\"Don't Speak\"" + }, + { + "Category": "TITLES FROM SHAKESPEARE", + "Question": "Aldous Huxley's \"Brave New World\" comes from a speech of Miranda's in this play", + "Answer": "The Tempest" + }, + { + "Category": "FOR THE FASHIONISTA", + "Question": "The sex-symbol look of films like \"La Dolce Vita\" has long insired Domenico Dolce & this partner", + "Answer": "Gabana" + }, + { + "Category": "FRANCE", + "Question": "In 1992, 200 years after it was written, 40% of the French found it excessively bloody & 25% wanted it changed", + "Answer": "the French National Anthem" + }, + { + "Category": "4-LETTER FRIENDS", + "Question": "The first name of actress Sheedy, pronounced differently", + "Answer": "ally" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "In November 1910 he was elected governor of New Jersey", + "Answer": "Wilson" + }, + { + "Category": "\"DON'T\" YOU KNOW THIS SONG?", + "Question": "Elton John saw the light of the Top 5 with this song twice, in 1974 & 1992", + "Answer": "\"Don't Let The Sun Go Down On Me\"" + }, + { + "Category": "TITLES FROM SHAKESPEARE", + "Question": "This long-running Agatha Christie drama references the play-within-a-play in \"Hamlet\"", + "Answer": "The Mousetrap" + }, + { + "Category": "FOR THE FASHIONISTA", + "Question": "Launched by her brother in the '90s, a fragrance called Blonde was inspired by this Italian designer's long blonde hair", + "Answer": "Donnatella Versace" + }, + { + "Category": "FRANCE", + "Question": "Just south of Champagne is this other potent potable-named region, a former duchy", + "Answer": "Burgundy" + }, + { + "Category": "4-LETTER FRIENDS", + "Question": "A nobleman, or to look intently", + "Answer": "peer" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "On June 28, 1919 he married Elizabeth Wallace", + "Answer": "Harry Truman" + }, + { + "Category": "\"DON'T\" YOU KNOW THIS SONG?", + "Question": "If you've given up, stop! & tell us this Tom Petty song that won the Best Special Effects MTV Music Video Award in '85", + "Answer": "\"Don't Come Around Here No More\"" + }, + { + "Category": "TITLES FROM SHAKESPEARE", + "Question": "Peter Straub & Danielle Steel both came \"Full Circle\", spoken by Edmund in this Shakespearean tragedy", + "Answer": "King Lear" + }, + { + "Category": "FOR THE FASHIONISTA", + "Question": "Flowing fabric defines this fashion house founded by Tanya Sarne; its name is a synonym for \"phantom\"", + "Answer": "Ghost" + }, + { + "Category": "FRANCE", + "Question": "\"Jet\" over to this largest Paris place, site of the guillotine during the French Revolution", + "Answer": "the Place de la Concorde" + }, + { + "Category": "4-LETTER FRIENDS", + "Question": "The sport of rowing", + "Answer": "crew" + }, + { + "Category": "FAMOUS OBJECTS", + "Question": "Shah Jahan, Ranjit Singh & Queen Victoria all possessed a famous one whose name means \"mountain of light\"", + "Answer": "a diamond" + }, + { + "Category": "SLIM VOLUMES", + "Question": "This doctor's \"Diet Revolution\" promised weight loss with a high-protein/low-carb diet (pass the steaki)", + "Answer": "Dr. Atkins" + }, + { + "Category": "STATE OF THE UNION", + "Question": "This union state's 6th regiment was nicknamed the Minutemen; its 20th was the Harvard regiment", + "Answer": "Massachusetts" + }, + { + "Category": "GOING TOO \"FUR\"", + "Question": "These electronic toys were a must-have item during the Christmas season of 1998", + "Answer": "the Furby" + }, + { + "Category": "IT MIGHT SURPRISE YOU", + "Question": "The actual quote from this star of gangster films was \"you dirty yellow-bellied rat!\"", + "Answer": "Jimmy Cagney" + }, + { + "Category": "JONATHAN SWIFTIES", + "Question": "\"He was a bold man that first ate\" this bivalve mollusk", + "Answer": "an oyster" + }, + { + "Category": "COMIC STRIPS", + "Question": "Aaugh! This comic strip character was torn between a summer camp flame named Peggy Jean & the little red-haired girl", + "Answer": "Charlie Brown" + }, + { + "Category": "SLIM VOLUMES", + "Question": "Recent diet books: \"The Paleo Diet\" & \"Neanderthin: Eat Like\" one of these \"to achieve a lean, strong, healthy body\"", + "Answer": "a Caveman" + }, + { + "Category": "STATE OF THE UNION", + "Question": "The westernmost states to stay loyal to the union were California & this one that had just been admitted in 1859", + "Answer": "Oregon" + }, + { + "Category": "GOING TOO \"FUR\"", + "Question": "Rolled up, like a flag or a boat's sails", + "Answer": "furled" + }, + { + "Category": "IT MIGHT SURPRISE YOU", + "Question": "Despite the opportunity, this November 1965 event in NYC did not result in a mini baby boom 9 months later", + "Answer": "a blackout" + }, + { + "Category": "JONATHAN SWIFTIES", + "Question": "\"Every man desires to live long, but no man would be\" this", + "Answer": "old" + }, + { + "Category": "COMIC STRIPS", + "Question": "Ack! In 2010 Ms. Guisewite said her \"creative biological clock\" was ticking & ended this strip after 34 years", + "Answer": "Cathy" + }, + { + "Category": "SLIM VOLUMES", + "Question": "You may want to enter this, a diet book & program by Barry Sears, who clarified with \"Mastering\" it", + "Answer": "The Zone" + }, + { + "Category": "STATE OF THE UNION", + "Question": "Turnabout is fair play--it seceded from a confederate state & joined the union in June 1863", + "Answer": "West Virginia" + }, + { + "Category": "GOING TOO \"FUR\"", + "Question": "To provide & install housewares to a dwelling", + "Answer": "furnish" + }, + { + "Category": "JONATHAN SWIFTIES", + "Question": "\"Proper words in proper places make the true definition of\" this--it's elementary, according to Strunk & White", + "Answer": "style" + }, + { + "Category": "COMIC STRIPS", + "Question": "This Scott Adams title guy with a gravity-defying tie accidentally invented a death ray that interested North Korea", + "Answer": "Dilbert" + }, + { + "Category": "SLIM VOLUMES", + "Question": "This chef followed up his \"Now Eat This!\" cookbook with \"Now Eat This! Diet\"", + "Answer": "DiSpirito" + }, + { + "Category": "STATE OF THE UNION", + "Question": "A senator from this state said, \"having been the first...to enter the union\", it would be \"the last to abandon it\"", + "Answer": "Delaware" + }, + { + "Category": "GOING TOO \"FUR\"", + "Question": "A smelter, for example", + "Answer": "a furnace" + }, + { + "Category": "IT MIGHT SURPRISE YOU", + "Question": "This exhaustive reference work first published in 1768 is not British: it has been American-owned for over 100 years", + "Answer": "the Encyclopedia Britannica" + }, + { + "Category": "JONATHAN SWIFTIES", + "Question": "These, made by parliament, \"are like cobwebs, which may catch small flies, but let wasps and hornets break through\"", + "Answer": "laws" + }, + { + "Category": "COMIC STRIPS", + "Question": "Duke has been Gov. of American Samoa, GM of the Redskins & a lobbyist for the NRA in this comic strip", + "Answer": "Doonesbury" + }, + { + "Category": "STATE OF THE UNION", + "Question": "It stayed in the union, but the confederacy also admitted it in 1861; it was in a \"compromising\" position, after all", + "Answer": "Missouri" + }, + { + "Category": "JONATHAN SWIFTIES", + "Question": "\"A flea / hath smaller fleas that on him prey; / and these have smaller still to bite 'em; / and so proceed\" this endless way", + "Answer": "ad infinitum" + }, + { + "Category": "COMIC STRIPS", + "Question": "On December 8, 1980 Berkeley Breathed began his magnum opus with the debut of this strip", + "Answer": "Bloom County" + }, + { + "Category": "ARCHITECTURE", + "Question": "The caldarium, the tepidarium & the frigidarium were chambers in these, where olden Romans refreshed themselves", + "Answer": "the baths" + }, + { + "Category": "SOUNDS LIKE A CAPITAL CITY", + "Question": "To cause to undergo combustion", + "Answer": "burn" + }, + { + "Category": "MOTORCYCLE MAKERS", + "Question": "Time to get high on this hyphenated maker's hog, specifically the Fat Bob, which gets a fat 53 mpg on the highway", + "Answer": "Harley-Davidson" + }, + { + "Category": "MISSING LINKS", + "Question": "Guilt by ____ Football", + "Answer": "association" + }, + { + "Category": "PLATE TECTONICS", + "Question": "Formed by plate tectonics, these mid-ocean uplifts are actually underwater mountain chains", + "Answer": "ridges" + }, + { + "Category": "COMICS STRIP", + "Question": "This Monty Python stalwart went the full monty in \"A Fish Called Wanda\"", + "Answer": "Cleese" + }, + { + "Category": "ARCHITECTURE", + "Question": "Virginia's Shirley plantation has a \"hanging\" one of these that climbs 3 stories without any visible means of support", + "Answer": "a staircase" + }, + { + "Category": "SOUNDS LIKE A CAPITAL CITY", + "Question": "A light yellow-brown; perfect color for an envelope, I say", + "Answer": "manila" + }, + { + "Category": "MOTORCYCLE MAKERS", + "Question": "Baseball's Ichiro must be aware that this maker's B-King is the \"rowdy alter ego\" to its Hayabusa", + "Answer": "Suzuki" + }, + { + "Category": "MISSING LINKS", + "Question": "A good ____ Havoc", + "Answer": "cry" + }, + { + "Category": "PLATE TECTONICS", + "Question": "In 2006 scientists argued that the westward trend of continents was due partly to these shifts in sea levels caused by the moon", + "Answer": "the tides" + }, + { + "Category": "COMICS STRIP", + "Question": "In \"Get Him to the Greek\", this Brit took a trip in the buff in a toy car", + "Answer": "Russell Brand" + }, + { + "Category": "SOUNDS LIKE A CAPITAL CITY", + "Question": "You'll find one on any shoe", + "Answer": "sole" + }, + { + "Category": "MOTORCYCLE MAKERS", + "Question": "\"Let the good times roll\" with this company's supersport cycle, the Ninja ZX-14", + "Answer": "Kawasaki" + }, + { + "Category": "MISSING LINKS", + "Question": "Mobile ____ Economics", + "Answer": "home" + }, + { + "Category": "COMICS STRIP", + "Question": "Borat, played by this British comic, had a naked tussle with his portly Kazakh TV producer", + "Answer": "Cohen" + }, + { + "Category": "ARCHITECTURE", + "Question": "This type of window that opens by means of a crank rhymes with a lower story of a building", + "Answer": "casement" + }, + { + "Category": "SOUNDS LIKE A CAPITAL CITY", + "Question": "Almost half of north Americans have this kind of blood", + "Answer": "Type A" + }, + { + "Category": "MISSING LINKS", + "Question": "Curry ____ Keg", + "Answer": "powder" + }, + { + "Category": "COMICS STRIP", + "Question": "Jason Segel's real-life split was the basis of his naked break-up with this 2008 title movie gal", + "Answer": "Sarah Marshall" + }, + { + "Category": "ARCHITECTURE", + "Question": "After WWI he became director of the Grand Ducal art school in Weimar; in 1925 he moved the school to Dessau", + "Answer": "Walter Gropius" + }, + { + "Category": "SOUNDS LIKE A CAPITAL CITY", + "Question": "Is old-time ballplayer Yogi able to?", + "Answer": "Canberra" + }, + { + "Category": "MISSING LINKS", + "Question": "Near ____ South Dakota pageant", + "Answer": "miss" + }, + { + "Category": "COMICS STRIP", + "Question": "Ken Jeong bared all as crime lord Mr. Chow in this 2009 Vegas comedy", + "Answer": "The Hangover" + }, + { + "Category": "RULERS IN HISTORY", + "Question": "Born in 1672 & named for a saint, in 1703 he founded a city whose name represents both of them", + "Answer": "Peter the Great" + }, + { + "Category": "EDGAR AWARD WINNERS", + "Question": "He won in 1955 for his novel \"The Long Goodbye\"", + "Answer": "Raymond Chandler" + }, + { + "Category": "MOVIE TAG LINES", + "Question": "This film gave us \"The holiest event of our time. Perfect for their return\" (& Tom Hanks')", + "Answer": "Angels and Demons" + }, + { + "Category": "PITCHING HORRIBLE, HORRIBLE WOO", + "Question": "A pet for my pet! This can spray its odoriferous musk accurately up to 12 feet; worry not! It'll stamp its feet to warn thee first", + "Answer": "a skunk" + }, + { + "Category": "ASTRONOMY", + "Question": "A crossing of the celestial equator by the sun, it happens twice a year", + "Answer": "an equinox" + }, + { + "Category": "SPELL CHECK HELL", + "Question": "Confound it! Spell check just changed chancre into this 14th c. author of some \"Tales\"", + "Answer": "Chaucer" + }, + { + "Category": "GETTING TICKED OFF", + "Question": "When this Bible guy came down from the mountain & saw his people dancing before the golden calf, boy, was he upset!", + "Answer": "Moses" + }, + { + "Category": "EDGAR AWARD WINNERS", + "Question": "\"The Spy Who Came in from the Cold\" got him the Edgar", + "Answer": "John le Carré" + }, + { + "Category": "MOVIE TAG LINES", + "Question": "This 2009 comedy proclaimed, \"Some guys just can't handle Vegas\"", + "Answer": "The Hangover" + }, + { + "Category": "PITCHING HORRIBLE, HORRIBLE WOO", + "Question": "Drink (or eat) deep, my dear, for I have brought deep-fried this drink, \"the real thing\", from the state fair of Texas", + "Answer": "Coke" + }, + { + "Category": "ASTRONOMY", + "Question": "These long distance travelers may be dirty ice balls or icy dirt balls", + "Answer": "comets" + }, + { + "Category": "SPELL CHECK HELL", + "Question": "Spell check keeps trying to change Antietam into this long-snouted insectivore that comes in giant & 3 other species", + "Answer": "an anteater" + }, + { + "Category": "GETTING TICKED OFF", + "Question": "He gave his kids by Cleopatra much of the land once ruled by Alexander the Great; his co-rulers & rivals were not pleased", + "Answer": "Mark Antony" + }, + { + "Category": "EDGAR AWARD WINNERS", + "Question": "He won for his novel \"The Day of the Jackal\" & the short story \"There Are No Snakes in Ireland\"", + "Answer": "Forsyth" + }, + { + "Category": "MOVIE TAG LINES", + "Question": "\"Lather. Rinse. Save the world\" advertised this Adam Sandler comedy", + "Answer": "You Don't Mess with the Zohan" + }, + { + "Category": "PITCHING HORRIBLE, HORRIBLE WOO", + "Question": "From this author's \"The Jungle\" I shall read lines like \"On the killing beds you were apt to be covered with blood\"", + "Answer": "Upton Sinclair" + }, + { + "Category": "ASTRONOMY", + "Question": "Undetected murky stuff in the universe presumed to exist because of its gravitational effects", + "Answer": "dark matter" + }, + { + "Category": "SPELL CHECK HELL", + "Question": "Tried to put in the first name of Colts quarterback Manning & it turned him into this hallucinogenic cactus", + "Answer": "peyote" + }, + { + "Category": "GETTING TICKED OFF", + "Question": "In 2005 this ex-diplomat wasn't so diplomatic, saying, \"I believe Karl Rove should be fired\" for outing his CIA wife, Valerie Plame", + "Answer": "Wilson" + }, + { + "Category": "EDGAR AWARD WINNERS", + "Question": "Writing about the world of horse racing, he's won for \"Forfeit\" & \"Come to Grief\"", + "Answer": "Dick Francis" + }, + { + "Category": "MOVIE TAG LINES", + "Question": "This WWII film from 2008 had the tag \"Many saw evil. They dared to stop it\"", + "Answer": "Valkyrie" + }, + { + "Category": "PITCHING HORRIBLE, HORRIBLE WOO", + "Question": "Tonight we sup on this animal's jowls, used to flavor stews as a southern delicacy; it's a motorcycle term, too, my love", + "Answer": "a hog" + }, + { + "Category": "SPELL CHECK HELL", + "Question": "Ay, caramba! Spell check changed the last name of a 16th c. conquistador into this, an old-fashioned girdle", + "Answer": "a corset" + }, + { + "Category": "GETTING TICKED OFF", + "Question": "Jealous of this Prussian chancellor's fame, Wilhelm II sank him by forcing his resignation in 1890", + "Answer": "Bismarck" + }, + { + "Category": "EDGAR AWARD WINNERS", + "Question": "He won in the Best Fact Crime category for such works as \"Helter Skelter\" & \"Till Death Us Do Part\"", + "Answer": "Bugliosi" + }, + { + "Category": "MOVIE TAG LINES", + "Question": "1982 film that showed \"A world inside a computer where man has never been. Never before now\"", + "Answer": "Tron" + }, + { + "Category": "PITCHING HORRIBLE, HORRIBLE WOO", + "Question": "Indeed, I should've told you I had this \"kissing disease\" whose incubation period is 30-40 days; hey, where ya goi", + "Answer": "mononucleosis" + }, + { + "Category": "SPELL CHECK HELL", + "Question": "I want to call my girl \"dollpuss\", not this suggested alternative meaning large portions of sour cream", + "Answer": "dollops" + }, + { + "Category": "GETTING TICKED OFF", + "Question": "In \"The Tragedy of Pudd'nhead Wilson\", this author wrote, \"When angry, count four; when very angry, swear\"", + "Answer": "Mark Twain" + }, + { + "Category": "NO. 1 QUESTIONS", + "Question": "In a 1971 No. 1 hit the Bee Gees wanted to know \"How can you mend\" one of these", + "Answer": "a broken heart" + }, + { + "Category": "FLY ME, BUT NOT TO THE MOON", + "Question": "You are now free to move about the country on this company's New Mexico One aircraft", + "Answer": "Southwest" + }, + { + "Category": "INTERNATIONAL RHYME TIME", + "Question": "An automobile for any former Russian emperor", + "Answer": "a Czar car" + }, + { + "Category": "SHAMANISM ON YOU", + "Question": "Yikes! Among these indigenous Australians, a person is thought to become a shaman after an initiatory death", + "Answer": "the Aborigines" + }, + { + "Category": "GETTING TICKED ON", + "Question": "A brown tick named for this pet has the rare ability to complete its life cycle indoors", + "Answer": "dog" + }, + { + "Category": "NO. 1 QUESTIONS", + "Question": "In a 1995 No. 1, Bryan Adams wanted to know if you'd ever really done this", + "Answer": "loved a woman" + }, + { + "Category": "FLY ME, BUT NOT TO THE MOON", + "Question": "In April 2008 it was announced that Northwest & this Atlanta-based airline would merge", + "Answer": "Delta" + }, + { + "Category": "INTERNATIONAL RHYME TIME", + "Question": "A tiny New Zealander, or a tiny New Zealand bird", + "Answer": "a peewee Kiwi" + }, + { + "Category": "SHAMANISM ON YOU", + "Question": "In the traditional religion of this Asian peninsula, male shamans are called Paksu", + "Answer": "the Korean Peninsula" + }, + { + "Category": "GETTING TICKED ON", + "Question": "The chipping type of this common seed-eating little bird is a popular host for ticks", + "Answer": "a sparrow" + }, + { + "Category": "NO. 1 QUESTIONS", + "Question": "In this 1960 hit, Elvis wondered if you're \"sorry we drifted apart\"", + "Answer": "\"Are You Lonesome Tonight?\"" + }, + { + "Category": "FLY ME, BUT NOT TO THE MOON", + "Question": "On Dec. 19, 2008 this \"colorful\" airline became the official one for the Red Sox, though its main hub is in (gasp!) N.Y.", + "Answer": "JetBlue" + }, + { + "Category": "INTERNATIONAL RHYME TIME", + "Question": "Hotel foyer where British policemen like to gather", + "Answer": "the Bobby lobby" + }, + { + "Category": "SHAMANISM ON YOU", + "Question": "18th c. groups led by shamans fought over the Yenisey River in this 5 million-sq.-mi. area of North-Central Russia", + "Answer": "Siberia" + }, + { + "Category": "GETTING TICKED ON", + "Question": "The tick species Ixodes dammini has as its favorite hosts white-footed mice & white-tailed these", + "Answer": "deer" + }, + { + "Category": "NO. 1 QUESTIONS", + "Question": "1984 No. 1 for Tina Turner about the thrill of boy meeting girl", + "Answer": "\"What's Love Got To Do With It\"" + }, + { + "Category": "FLY ME, BUT NOT TO THE MOON", + "Question": "Logically, this Spanish airline's first flight, in 1927, was between Barcelona & Madrid", + "Answer": "Iberia" + }, + { + "Category": "INTERNATIONAL RHYME TIME", + "Question": "The forehead of a German mrs.", + "Answer": "a Frau brow" + }, + { + "Category": "SHAMANISM ON YOU", + "Question": "The Warao Indians of South America believe this noisy shamanic gourd instrument has healing properties", + "Answer": "a rattle" + }, + { + "Category": "NO. 1 QUESTIONS", + "Question": "In 1961 the Shirelles noted that \"Tonight the light of love is in your eyes\" but wanted to know this", + "Answer": "Will you still love me tomorrow?" + }, + { + "Category": "FLY ME, BUT NOT TO THE MOON", + "Question": "Hong Kong's home carrier, in 2006 it celebrated its 60th anniversary", + "Answer": "Cathay Pacific" + }, + { + "Category": "INTERNATIONAL RHYME TIME", + "Question": "Japanese kimono sash for a small, spiny-finned fish", + "Answer": "an obi goby" + }, + { + "Category": "SHAMANISM ON YOU", + "Question": "Shamans on this Southeast Asian peninsula, also called the Kra Peninsula, use quartz crystals for healing", + "Answer": "the Malay Peninsula" + }, + { + "Category": "AWARDS & HONORS", + "Question": "A trophy named for this author is awarded to anyone who breaks the record for sailing a yacht around the world", + "Answer": "Jules Verne" + }, + { + "Category": "EDS", + "Question": "Shooting down 22 planes in 1918, Eddie Rickenbacker was the USA's No. 1 flying ace in this war", + "Answer": "World War I" + }, + { + "Category": "YOU SHOULD KNOW THIS STUFF", + "Question": "The Lord's Prayer says, \"And lead us not into temptation, but deliver us from\" this", + "Answer": "evil" + }, + { + "Category": "GEORGIAN ON MY MIND", + "Question": "This \"Pretty Woman\" was born in Smyrna, Georgia on Oct. 28, 1967", + "Answer": "Julia Roberts" + }, + { + "Category": "SCIENCE", + "Question": "These electromagnetic rays used to take pictures of your insides were originally known as Roentgen rays", + "Answer": "X-rays" + }, + { + "Category": "TRADING SPACES", + "Question": "4-letter synonym for \"trade\"; the Rose Bowl has a meet where it's done", + "Answer": "swap" + }, + { + "Category": "HAVE A CONTINENTAL BREAKFAST", + "Question": "G'Day Mate! Room service hopped in with kangaroo-tail soup, your breakfast from this continent", + "Answer": "Australia" + }, + { + "Category": "EDS", + "Question": "He hosted a phenomenally successful prime-time variety show for 24 years", + "Answer": "Ed Sullivan" + }, + { + "Category": "YOU SHOULD KNOW THIS STUFF", + "Question": "In the '30s she starred in \"The Little Princess\", \"The Little Colonel\" & \"Little Miss Marker\"", + "Answer": "Shirley Temple" + }, + { + "Category": "GEORGIAN ON MY MIND", + "Question": "Dinah Shore, Sally Field & Loni Anderson were longtime loves of this hunk from Waycross", + "Answer": "Burt Reynolds" + }, + { + "Category": "SCIENCE", + "Question": "This German-born American physicist won the 1921 Nobel Prize for Physics", + "Answer": "Albert Einstein" + }, + { + "Category": "TRADING SPACES", + "Question": "This Illinois city's Board of Trade deals in futures, so less than 5% of what's traded there gets delivered", + "Answer": "Chicago" + }, + { + "Category": "EDS", + "Question": "He earned an Oscar nomination for his supporting role in \"The Hours\"", + "Answer": "Ed Harris" + }, + { + "Category": "YOU SHOULD KNOW THIS STUFF", + "Question": "Bird similes include \"Spry as a spring chicken\" & \"Proud as\" one of these", + "Answer": "peacock" + }, + { + "Category": "GEORGIAN ON MY MIND", + "Question": "This fiery actress from Conyers starred in \"Miss Firecracker\", \"Raising Arizona\" & \"Broadcast News\"", + "Answer": "Holly Hunter" + }, + { + "Category": "SCIENCE", + "Question": "When combined with oxygen, this lightest chemical element makes water", + "Answer": "hydrogen" + }, + { + "Category": "TRADING SPACES", + "Question": "Dealers seal transactions with a handshake in the 47th Street \"district\" for these gems", + "Answer": "diamonds" + }, + { + "Category": "EDS", + "Question": "In order to marry a twice-divorced American woman, King Edward VIII of this country abdicated the throne in 1936", + "Answer": "England" + }, + { + "Category": "YOU SHOULD KNOW THIS STUFF", + "Question": "If a Maori showed you a tiki, you'd be looking at one of these", + "Answer": "statue" + }, + { + "Category": "GEORGIAN ON MY MIND", + "Question": "Born in Athens, Georgia, she starred in \"9 1/2 Weeks\" & played Eminem's mom in \"8 Mile\"", + "Answer": "Kim Basinger" + }, + { + "Category": "SCIENCE", + "Question": "Also a term for someone from Warsaw, it's one of the 2 strongest points in a magnetic field", + "Answer": "Pole" + }, + { + "Category": "TRADING SPACES", + "Question": "Muriel Siebert was the first woman to hold a seat on this Wall Street body founded in 1792", + "Answer": "the New York Stock Exchange" + }, + { + "Category": "EDS", + "Question": "In 1994 Johnny Depp played this wacky director of such classic films as \"Plan 9 from Outer Space\" & \"Necromania\"", + "Answer": "Ed Wood" + }, + { + "Category": "YOU SHOULD KNOW THIS STUFF", + "Question": "Non-potent potable for which your first set of teeth is named", + "Answer": "milk teeth" + }, + { + "Category": "SCIENCE", + "Question": "The symbol of this radioactive element is Pu & it sounds like it's named after Mickey Mouse's dog", + "Answer": "plutonium" + }, + { + "Category": "TRADING SPACES", + "Question": "You must take tea before bargaining for a rug at Istanbul's \"Grand\" one of these trading spaces", + "Answer": "bazaar" + }, + { + "Category": "BOOKS & AUTHORS", + "Question": "Margaret Mitchell began this book, \"Scarlett O'Hara was not beautiful, but men seldom realized it...\"", + "Answer": "\"Gone with the Wind\"" + }, + { + "Category": "OSCAR NIGHT 2003", + "Question": "With 6 Academy Awards total, this adapted musical was the big winner on Oscar Night 2003", + "Answer": "Chicago" + }, + { + "Category": "ART & ARTISTS", + "Question": "Upon completing the ceiling of the Sistine Chapel in 1512, he wrote to his father, \"The pope is well satisfied\"", + "Answer": "Michelangelo" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Giuliani, Valentino, the Red-Nosed Reindeer", + "Answer": "Rudolph" + }, + { + "Category": "STATE: THE OBVIOUS", + "Question": "At last count, this state had about 2 1/2 times as many cars as Texas or New York", + "Answer": "California" + }, + { + "Category": "OH MY GOD! YOU'VE GOT 3 \"I\"s", + "Question": "After the taping, what say we cool off with a frozen banana one of these", + "Answer": "daiquiri" + }, + { + "Category": "BOOKS & AUTHORS", + "Question": "In 1990 he reissued \"The Stand\" with nearly 500 more pages than the original", + "Answer": "Stephen King" + }, + { + "Category": "OSCAR NIGHT 2003", + "Question": "This Best Actress Winner said that Russell Crowe told her not to cry...but she did anyway", + "Answer": "Nicole Kidman" + }, + { + "Category": "ART & ARTISTS", + "Question": "This pop artist's studio was known as \"The Factory\"", + "Answer": "Andy Warhol" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Ashcroft, Belushi, Barleycorn", + "Answer": "John" + }, + { + "Category": "STATE: THE OBVIOUS", + "Question": "Florida's in the southeast corner of the 48 contiguous states; this state is in the northwest corner", + "Answer": "Washington" + }, + { + "Category": "OH MY GOD! YOU'VE GOT 3 \"I\"s", + "Question": "Type of doctor who's most likely to give a patient a lollipop", + "Answer": "pediatrician" + }, + { + "Category": "BOOKS & AUTHORS", + "Question": "President Reagan called this man's first novel \"The Hunt for Red October\" the \"perfect yarn\"", + "Answer": "Tom Clancy" + }, + { + "Category": "OSCAR NIGHT 2003", + "Question": "Seen here, the Chub Chubs won the Oscar in this category", + "Answer": "Animated Short" + }, + { + "Category": "ART & ARTISTS", + "Question": "In 1963 this \"Christina's World\" artist became the first painter to receive the Presidential Medal of Freedom", + "Answer": "Andrew Wyeth" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Lewis, Tarkanian, Springer", + "Answer": "Jerry" + }, + { + "Category": "STATE: THE OBVIOUS", + "Question": "The Mississippi River begins at Lake Itasca in this \"M\" state (not Mississippi)", + "Answer": "Minnesota" + }, + { + "Category": "OH MY GOD! YOU'VE GOT 3 \"I\"s", + "Question": "(Sofia of the Clue Crew in Oahu, Hawaii) I'm overlooking this Oahu beach that attracts about 65,000 visitors a day", + "Answer": "Waikiki" + }, + { + "Category": "BOOKS & AUTHORS", + "Question": "This 1939 Steinbeck classic featured a lot of Joads including Ma, Pa & Tom", + "Answer": "\"The Grapes of Wrath\"" + }, + { + "Category": "OSCAR NIGHT 2003", + "Question": "For \"Talk to Her\", he became the first man in over 30 years to win with a screenplay in a foreign language", + "Answer": "Pedro Almodovar" + }, + { + "Category": "ART & ARTISTS", + "Question": "He painted \"Tahitian Women\" shortly after arriving on that island in 1891", + "Answer": "Paul Gauguin" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Henson, Morrison, Lehrer", + "Answer": "Jim" + }, + { + "Category": "STATE: THE OBVIOUS", + "Question": "It's the state whose shape is seen here", + "Answer": "Nevada" + }, + { + "Category": "OH MY GOD! YOU'VE GOT 3 \"I\"s", + "Question": "Sports Illustrated's 1997 Swimsuit Issue (the Tyra Banks cover) featured \"Nothing but\" these", + "Answer": "Bikinis" + }, + { + "Category": "OSCAR NIGHT 2003", + "Question": "Chris Cooper won his Best Supporting Actor Oscar for his work in this film seen here", + "Answer": "Adaptation" + }, + { + "Category": "ART & ARTISTS", + "Question": "On September 29, 1910, this painter known for his seascapes died in his studio in Prouts Neck, Maine", + "Answer": "Winslow Homer" + }, + { + "Category": "FIRST NAME'S THE SAME", + "Question": "Hamilton, Calder, Haig", + "Answer": "Alexander" + }, + { + "Category": "STATE: THE OBVIOUS", + "Question": "This state's name includes the name of the country that was the top destination for U.S. tourists in 2001", + "Answer": "New Mexico" + }, + { + "Category": "OH MY GOD! YOU'VE GOT 3 \"I\"s", + "Question": "Fran Lebowitz called this type of pasta with clam sauce \"mankind's crowning achievement\"", + "Answer": "linguini" + }, + { + "Category": "TRANSPORTATION", + "Question": "On December 11, 1967 it was removed from the British registry & turned over to the city of Long Beach, California", + "Answer": "the Queen Mary" + }, + { + "Category": "PUNJAB", + "Question": "Since 1947, the historic region of Punjab has been divided between these 2 countries", + "Answer": "India & Pakistan" + }, + { + "Category": "FICTIONAL BOOKS", + "Question": "This character on \"Seinfeld\" thought of \"a coffee table book about coffee tables\" that turned into a coffee table", + "Answer": "Kramer" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "Beef chili is also called \"chili con\" this, Spanish for \"meat\"", + "Answer": "carne" + }, + { + "Category": "GAMES PEOPLE PLAY", + "Question": "You don't have to buy a vowel, but you do begin this word game by drawing a gallows", + "Answer": "hangman" + }, + { + "Category": "INVENTORS & INVENTIONS", + "Question": "In the 1920s, Frank Whittle, who grew up making model airplanes, designed the first working engine of this type", + "Answer": "a jet engine" + }, + { + "Category": "\"IP\" SO FACTO", + "Question": "Landing or Gaza", + "Answer": "a strip" + }, + { + "Category": "PUNJAB", + "Question": "As part of his Easternmost conquests, this Greek's armies occupied the Punjab around 327 B.C.", + "Answer": "Alexander the Great" + }, + { + "Category": "FICTIONAL BOOKS", + "Question": "On this show, \"The Itchy & Scratchy Movie\" was novelized by Norman Mailer", + "Answer": "The Simpsons" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "\"Joy of Cooking\" gives a recipe for this beef dish but cautions that eating raw meat can be hazardous to your health", + "Answer": "steak tartare" + }, + { + "Category": "GAMES PEOPLE PLAY", + "Question": "In 2007 he became the first man since Bill Tilden to win the U.S. Open 4 years in a row", + "Answer": "Federer" + }, + { + "Category": "INVENTORS & INVENTIONS", + "Question": "Alexander Wood & Charles Pravaz are credited with developing this device in 1853 first used to inject morphine", + "Answer": "asyringe" + }, + { + "Category": "\"IP\" SO FACTO", + "Question": "Idle talk about the private affairs of others", + "Answer": "gossip" + }, + { + "Category": "PUNJAB", + "Question": "In the 1840s this European power fought 2 costly wars over the Punjab before annexing the region outright", + "Answer": "the English" + }, + { + "Category": "FICTIONAL BOOKS", + "Question": "A man is searching for the novel \"Knickerless Nickleby\" in the bookstore skit on this British Show", + "Answer": "Monty Python" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "Corned beef is cured in brine; this other deli meat is seasoned brisket that's been cured, smoked & cooked", + "Answer": "pastrami" + }, + { + "Category": "GAMES PEOPLE PLAY", + "Question": "The first important U.S. tournament in this board game took place in New York City in 1857", + "Answer": "chess" + }, + { + "Category": "INVENTORS & INVENTIONS", + "Question": "After Carrier came up with this in 1902, my 20 babes waving palm fronds idea went out the window", + "Answer": "air conditioning" + }, + { + "Category": "\"IP\" SO FACTO", + "Question": "A bon mot", + "Answer": "a quip" + }, + { + "Category": "PUNJAB", + "Question": "In this Kipling work, the title orphan's father was a sergeant in an Irish regiment in the Punjab", + "Answer": "Kim" + }, + { + "Category": "FICTIONAL BOOKS", + "Question": "This doctor from the original \"Star Trek\" series wrote \"Comparative Alien Physiology\"", + "Answer": "McCoy" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "Part of the name of this expensive boneless cut means \"dainty\" in French", + "Answer": "filet mignon" + }, + { + "Category": "GAMES PEOPLE PLAY", + "Question": "Jordan & Bird hit \"nothing but net\" playing this shot-for-shot basketball game in 1990s TV ads for McDonald's", + "Answer": "HORSE" + }, + { + "Category": "INVENTORS & INVENTIONS", + "Question": "After steamboat success, he was urged to work on submarine-launched torpedoes by Pres. Jefferson", + "Answer": "Robert Fulton" + }, + { + "Category": "\"IP\" SO FACTO", + "Question": "Mating rituals, perhaps for Miles Standish?", + "Answer": "courtship" + }, + { + "Category": "PUNJAB", + "Question": "Predominant in the Punjab, this religion has origins in both Hinduism & Islam", + "Answer": "Sikhism" + }, + { + "Category": "FICTIONAL BOOKS", + "Question": "Jose Chung speaks to FBI agents before writing \"From Outer Space\" about an alien abduction on this show", + "Answer": "The X-Files" + }, + { + "Category": "WHAT'S YOUR BEEF?", + "Question": "It's the French name for boeuf braised in red wine, usually garnished with mushrooms & white onions", + "Answer": "bœuf bourguignon" + }, + { + "Category": "GAMES PEOPLE PLAY", + "Question": "From before 3000 B.C., the game Senet of these people used a board & pieces to depict an afterlife journey", + "Answer": "the Egyptians" + }, + { + "Category": "INVENTORS & INVENTIONS", + "Question": "In 1868, 9 years after developing the railway sleeping car, he introduced the first railway car for dining", + "Answer": "Pullman" + }, + { + "Category": "\"PUN\" JAB", + "Question": "Colons & commas & hyphens, oh my!", + "Answer": "punctuation" + }, + { + "Category": "WOMEN OF ACHIEVEMENT", + "Question": "Around 46 B.C, Julius Caesar offended his countrymen by dedicating a statue to her", + "Answer": "Cleopatra" + }, + { + "Category": "OSCARDS WILD", + "Question": "We liked her, we really liked her when this actress won for \"Places in the Heart\" in 1985", + "Answer": "Sally Field" + }, + { + "Category": "ART", + "Question": "Georges Rouault liked to include some tragic ones of these in his works; Red Skelton specialized in them", + "Answer": "clowns" + }, + { + "Category": "THEATRE AROUND THE WORLD", + "Question": "The musical \"Les Mis\" didn't debut on Broadway but in this city, its setting", + "Answer": "Paris" + }, + { + "Category": "\"PUN\" JAB", + "Question": "Furry Phil's Pennsylvania place for fanciful February forecasting", + "Answer": "Punxsutawney" + }, + { + "Category": "WOMEN OF ACHIEVEMENT", + "Question": "As an example to her Russian subjects, she & her son Paul had themselves inoculated against smallpox in 1768", + "Answer": "Catherine" + }, + { + "Category": "OSCARDS WILD", + "Question": "In 1992, proving he could keep up with the younger crowd, he did one-armed pushups accepting his \"City Slickers\" Oscar", + "Answer": "Jack Palance" + }, + { + "Category": "ART", + "Question": "A Gerrit Dou work is sometimes known as \"The Mother of\" this painter with whom Dou studied in 17th century Leiden", + "Answer": "Rembrandt" + }, + { + "Category": "THEATRE AROUND THE WORLD", + "Question": "He directed a landmark Chinese production of his play \"Death of a Salesman\" at the People's Art Theatre in Beijing", + "Answer": "Arthur Miller" + }, + { + "Category": "WOMEN OF ACHIEVEMENT", + "Question": "In 1616 she & her husband John Rolfe traveled to England to help raise funds for the Virginia colonists", + "Answer": "Pocahontas" + }, + { + "Category": "OSCARDS WILD", + "Question": "He's the \"SNL\" guy (& you're not) who opened the 1988 show with, \"Good evening Hollywood phonies\"; he never hosted again", + "Answer": "Chevy Chase" + }, + { + "Category": "ART", + "Question": "19th c. painter Thomas Cole lived in Catskill, N.Y. on this river, whose \"School\" he helped found", + "Answer": "the Hudson River" + }, + { + "Category": "THEATRE AROUND THE WORLD", + "Question": "A Dutch TV reality show picked the muscular \"swinger\" for the European run of this Disney musical", + "Answer": "Tarzan" + }, + { + "Category": "\"PUN\" JAB", + "Question": "William Gibson pioneered this sci-fi genre of characters in a dark, futuristic world dominated by computers", + "Answer": "cyberpunk" + }, + { + "Category": "WOMEN OF ACHIEVEMENT", + "Question": "In November 1988 she was elected Prime Minister of Pakistan, becoming the first woman to head a modern Islamic nation", + "Answer": "Bhutto" + }, + { + "Category": "OSCARDS WILD", + "Question": "Disney sued the Academy for \"unflattering\" use of this character after a 1989 duet with her & Rob Lowe", + "Answer": "Snow White" + }, + { + "Category": "ART", + "Question": "A note formerly on the back of \"Figure de fantasie\" by this Rococo painter says it was done in one hour", + "Answer": "Fragonard" + }, + { + "Category": "THEATRE AROUND THE WORLD", + "Question": "There's a \"method\" behind his founding of the Moscow Art Theatre with Nemirovich-Danchenko", + "Answer": "Stanislavski" + }, + { + "Category": "\"PUN\" JAB", + "Question": "From the Latin for \"mark for deletion\", it's to erase something from official records", + "Answer": "expunge" + }, + { + "Category": "WOMEN OF ACHIEVEMENT", + "Question": "To further the ambitions of her brother, her father, Pope Alexander VI, arranged several marriages for her", + "Answer": "Lucrezia Borgia" + }, + { + "Category": "OSCARDS WILD", + "Question": "This \"American Beauty\" nominee nearly had a pregnant pause at the 2000 show; she was due with her 4th at any moment", + "Answer": "Annette Bening" + }, + { + "Category": "ART", + "Question": "This Venetian, said his pupil Palma Giovane, \"used his fingers more than his brush\" to finish his lush works", + "Answer": "Titian" + }, + { + "Category": "THEATRE AROUND THE WORLD", + "Question": "If you get to put \"RSC\" on your resume, you were part of this British troupe", + "Answer": "the Royal Shakespeare Company" + }, + { + "Category": "STRUCTURES", + "Question": "When completed, it stretched for 73 1/2 miles from Bowness to Wallsend", + "Answer": "Hadrian's Wall" + }, + { + "Category": "\"FOR\" WORDS", + "Question": "In a common saying, it's what some people can't see for the trees", + "Answer": "the forest" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "You can visit this sport's hall of fame on PGA Blvd. in Pinehurst, North Carolina", + "Answer": "golf" + }, + { + "Category": "COUNTRY & WESTERN MUSIC", + "Question": "In Cole Porter's song, these words follow \"can't look at hobbles and I can't stand fences\"", + "Answer": "don't fence me in" + }, + { + "Category": "MEDICINE", + "Question": "Device that's implanted to control irregular heart beats", + "Answer": "a pacemaker" + }, + { + "Category": "TELEVISION", + "Question": "Ray Walston was the Martian while the \"my\" in \"My Favorite Martian\" referred to him", + "Answer": "Bill Bixby" + }, + { + "Category": "SKUNKS", + "Question": "With a favorable wind, skunks can do this for up to about 23 feet", + "Answer": "spray" + }, + { + "Category": "\"FOR\" WORDS", + "Question": "A college team might have to do this for games played with ineligible team members", + "Answer": "forfeit" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "Except when it's on tour, the most important King Tut collection is housed in this city", + "Answer": "Cairo" + }, + { + "Category": "COUNTRY & WESTERN MUSIC", + "Question": "Hey, good looki", + "Answer": "Hank Williams" + }, + { + "Category": "MEDICINE", + "Question": "The term \"strep\", as in strep throat, is short for this type of bacteria", + "Answer": "Streptococcus" + }, + { + "Category": "TELEVISION", + "Question": "Before playing the principal at \"The Bronx Zoo\", he played the city editor of the L.A. Tribune", + "Answer": "Ed Asner" + }, + { + "Category": "SKUNKS", + "Question": "The skunk lends its name to this foul-smelling \"vegetable\" found in swamps", + "Answer": "skunk cabbage" + }, + { + "Category": "\"FOR\" WORDS", + "Question": "Jewelers as well as surgeons use this tool for grasping & holding", + "Answer": "forceps" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "Type of place you'd be visiting if you were in Wind Cave, Lassen or Zion", + "Answer": "a national park" + }, + { + "Category": "COUNTRY & WESTERN MUSIC", + "Question": "In \"Red River Valley\", cowboys sing, \"come and\" do this \"if you love me\"", + "Answer": "sit by my side" + }, + { + "Category": "MEDICINE", + "Question": "He was a world authority on the gall wasp in the '20s before turning to sex research", + "Answer": "Kinsey" + }, + { + "Category": "TELEVISION", + "Question": "In 1977 her own show aired on CBS just before \"Maude\"; now she's a \"Golden Girl\" with Bea Arthur", + "Answer": "Betty White" + }, + { + "Category": "SKUNKS", + "Question": "Name of zee skunk in zee popular Warner Brothers cartoons", + "Answer": "Pepé Le Pew" + }, + { + "Category": "\"FOR\" WORDS", + "Question": "Usually it's the last thing you're served in a Chinese restaurant", + "Answer": "a fortune cookie" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "1 of 2 famous Danish breweries you can tour in Copenhagen", + "Answer": "Tuborg" + }, + { + "Category": "MEDICINE", + "Question": "For an upper GI you drink this; for a lower GI... well, we won't talk about that", + "Answer": "barium" + }, + { + "Category": "TELEVISION", + "Question": "The pilot of this show, set in North Carolina, played as part of \"The Danny Thomas Show\" in 1960", + "Answer": "The Andy Griffith Show" + }, + { + "Category": "\"FOR\" WORDS", + "Question": "This word on the label signifies that vitamins have been added to milk", + "Answer": "fortified" + }, + { + "Category": "TRAVEL & TOURISM", + "Question": "You can spend the night in a Victorian style railroad car at the Choo Choo Hilton in this city", + "Answer": "Chattanooga" + }, + { + "Category": "MEDICINE", + "Question": "To test for this, the eyeball is anesthetized & a pressure gauge is placed on the front of the eye", + "Answer": "glaucoma" + }, + { + "Category": "TELEVISION", + "Question": "He was a regular on Danny Kaye's, Carol Burnett's & Tim Conway's variety shows", + "Answer": "Harvey Korman" + }, + { + "Category": "SKUNKS", + "Question": "Skunks are the major carriers of this disease in the continental U.S.", + "Answer": "rabies" + }, + { + "Category": "U.S. STATES", + "Question": "The 2 states that border no other states", + "Answer": "Alaska & Hawaii" + }, + { + "Category": "ENGLISH LIT", + "Question": "In 1772 James Boswell told this author he intended to write his biography", + "Answer": "Doctor Samuel Johnson" + }, + { + "Category": "TECHNOLOGY", + "Question": "Count Rumford, who died in 1814, invented the drip version of this", + "Answer": "the coffee maker" + }, + { + "Category": "CELEBRITY MARRIAGES", + "Question": "Carrie Leigh hopped out of this man's mansion & married an antique dealer, quick as a bunny", + "Answer": "Hugh Hefner" + }, + { + "Category": "THE CIVIL WAR", + "Question": "Heavy casualties at Shiloh led to calls for his firing, but Lincoln said, \"I can't spare this man; he fights\"", + "Answer": "Grant" + }, + { + "Category": "PERFUME", + "Question": "Late designer whose perfumes are sold by the numbers: No. 5. No. 19 & No. 22", + "Answer": "Chanel" + }, + { + "Category": "U.S. STATES", + "Question": "Of Colorado, New Mexico or Arizona, the state where the Rio Grande begins", + "Answer": "Colorado" + }, + { + "Category": "ENGLISH LIT", + "Question": "The Baconian theory expounds this", + "Answer": "that Francis Bacon wrote Shakespeare's plays" + }, + { + "Category": "TECHNOLOGY", + "Question": "Eli Whitney's nephew invented a crusher used to grind up rock for surfacing these", + "Answer": "roads" + }, + { + "Category": "CELEBRITY MARRIAGES", + "Question": "This \"Bewitch\"ing actress was the 3rd wife of Oscar winner Gig Young", + "Answer": "Elizabeth Montgomery" + }, + { + "Category": "THE CIVIL WAR", + "Question": "This battle was Lee's last major offensive", + "Answer": "Gettysburg" + }, + { + "Category": "PERFUME", + "Question": "Mimosa, mayflower & musk mingle in this, Yves St. Laurent's \"capital\" perfume", + "Answer": "Paris" + }, + { + "Category": "U.S. STATES", + "Question": "Besides X,Y & Z, 2 of the 3 consonants that don't begin a state's name", + "Answer": "J & Q" + }, + { + "Category": "ENGLISH LIT", + "Question": "Among his historical novels are \"I, Claudius\" & \"Claudius the God\"", + "Answer": "Robert Graves" + }, + { + "Category": "TECHNOLOGY", + "Question": "A fault in the rotation speed of this device produces a sound called a \"wow\"", + "Answer": "a turntable" + }, + { + "Category": "CELEBRITY MARRIAGES", + "Question": "Drama coach Uta Hagen was his 1st wife & singer Rosemary Clooney his 3rd", + "Answer": "José Ferrer" + }, + { + "Category": "THE CIVIL WAR", + "Question": "Northerners who sought advantage in the post-war South were said to tote their belongings in these", + "Answer": "carpetbags" + }, + { + "Category": "PERFUME", + "Question": "Though it has the same name, Benetton's perfume wasn't named for this controversial Sean Penn film", + "Answer": "Colors" + }, + { + "Category": "U.S. STATES", + "Question": "The last major land battle of the Revolutionary War took place in this state", + "Answer": "Virginia" + }, + { + "Category": "ENGLISH LIT", + "Question": "Since the beadle named his waifs alphabetically, this character came between Swubble & Unwin", + "Answer": "Twist" + }, + { + "Category": "TECHNOLOGY", + "Question": "The \"D\" in radar stands for this", + "Answer": "detection" + }, + { + "Category": "CELEBRITY MARRIAGES", + "Question": "Of the original stars of \"Mission: Impossible\", the 2 who were married to each other", + "Answer": "Bain &Landau" + }, + { + "Category": "THE CIVIL WAR", + "Question": "In Sherman's famous \"march to the sea\", this seaport city was his goal", + "Answer": "Savannah, Georgia" + }, + { + "Category": "PERFUME", + "Question": "The 2 perfumes mentioned in Matthew 2:11", + "Answer": "frankincense & myrrh" + }, + { + "Category": "U.S. STATES", + "Question": "This state got its nickname, \"Badger State\", from the 1820s miners who dug into its hillsides", + "Answer": "Wisconsin" + }, + { + "Category": "ENGLISH LIT", + "Question": "In an Oliver Goldsmith work, Dr. Primrose is the vicar of this parish", + "Answer": "Wakefield" + }, + { + "Category": "TECHNOLOGY", + "Question": "Name given to the simplest electron tubes, as they have just 2 main parts, a plate & an emitter", + "Answer": "a diode" + }, + { + "Category": "THE CIVIL WAR", + "Question": "1 of the 3 men whom Lincoln defeated in the 1860 presidential election", + "Answer": "Breckenridge" + }, + { + "Category": "PERFUME", + "Question": "Bulgaria is the chief producer of this perfume oil obtained by passing steam thru rose petals", + "Answer": "attar" + }, + { + "Category": "THE SPACE RACE", + "Question": "Sputnik was the Soviet's 1st satellite, while this was ours", + "Answer": "Explorer" + }, + { + "Category": "SOCIOLOGY", + "Question": "This term for a rural white southerner was originally applied to sunburned agricultural workers", + "Answer": "a redneck" + }, + { + "Category": "RADIO PERSONALITIES", + "Question": "The fans of this radio personality call themselves dittoheads to signify that they agree with his opinion", + "Answer": "Rush Limbaugh" + }, + { + "Category": "HEADQUARTERS", + "Question": "Surprisingly, in the 1990s, this retailer moved its HQ from its tall tower in Chicago to a lowrise in the suburbs", + "Answer": "Sears Roebuck" + }, + { + "Category": "BERMUDA SHORTS", + "Question": "Bermuda's almost due east of this state's Cape Hatteras", + "Answer": "North Carolina" + }, + { + "Category": "MILLIONS OF REASONS", + "Question": "Metallic distinction of a CD that's sold 1 million copies", + "Answer": "platinum" + }, + { + "Category": "SOUNDS LIKE A RAPPER", + "Question": "This type of \"domain\" could lose you your house if the government needs your land, yo", + "Answer": "eminent" + }, + { + "Category": "SOCIOLOGY", + "Question": "Robert & Helen Lynd based their \"Middletown\" studies on Muncie in this state", + "Answer": "Indiana" + }, + { + "Category": "HEADQUARTERS", + "Question": "Since 1988 J.C. Penney has been firmly planted in Plano in this state", + "Answer": "Texas" + }, + { + "Category": "BERMUDA SHORTS", + "Question": "The cahow, or Bermuda petrel, a type of this, breeds only in Bermuda", + "Answer": "a bird" + }, + { + "Category": "MILLIONS OF REASONS", + "Question": "Of 2 million, 20 million or 200 million, the length in years of one trip around the galaxy's center by our sun", + "Answer": "200 million" + }, + { + "Category": "SOUNDS LIKE A RAPPER", + "Question": "\"It's\" one of these \"that blows nobody any good\"", + "Answer": "an ill wind" + }, + { + "Category": "SOCIOLOGY", + "Question": "The sum of the customs & beliefs that distinguish one group from another; the hippies formed a \"counter\" one", + "Answer": "a culture" + }, + { + "Category": "RADIO PERSONALITIES", + "Question": "She's from Brooklyn, has a Ph.D. in physiology & is Deryk's mom", + "Answer": "Dr. Laura" + }, + { + "Category": "HEADQUARTERS", + "Question": "First the \"E\"s were sold, then its Houston HQ building was auctioned off in December 2003 for $55.5 million", + "Answer": "Enron" + }, + { + "Category": "BERMUDA SHORTS", + "Question": "Bermuda uses this basic unit of currency", + "Answer": "the dollar" + }, + { + "Category": "MILLIONS OF REASONS", + "Question": "Like Chico in \"Animal Crackers\", who got paid more for not performing, she got millions from Virgin not to sing", + "Answer": "Mariah Carey" + }, + { + "Category": "SOUNDS LIKE A RAPPER", + "Question": "It's wack but ESPN dropped the downhill racing style of this type of bicycle from its X Games in 2004", + "Answer": "BMX" + }, + { + "Category": "SOCIOLOGY", + "Question": "10,000 years ago all societies were these, named from the way they collected animals, fruit, etc. for food", + "Answer": "hunter-gatherers" + }, + { + "Category": "RADIO PERSONALITIES", + "Question": "This \"idol\" worshipper replaced Casey Kasem as host of \"American Top 40\"", + "Answer": "Ryan Seacrest" + }, + { + "Category": "HEADQUARTERS", + "Question": "The Ford Motor Company has long been headquartered in this city that adjoins Detroit", + "Answer": "Dearborn" + }, + { + "Category": "BERMUDA SHORTS", + "Question": "The first settlement in 1609 resulted from this event, maybe the one depicted in the first scene of \"The Tempest\"", + "Answer": "a shipwreck" + }, + { + "Category": "MILLIONS OF REASONS", + "Question": "It was the \"grateful\" title of philanthropist Percy Ross' syndicated radio show & newspaper column", + "Answer": "Thanks a Million" + }, + { + "Category": "SOUNDS LIKE A RAPPER", + "Question": "Lack of movement in traffic--especially at an intersection or in politics", + "Answer": "gridlock" + }, + { + "Category": "SOCIOLOGY", + "Question": "Someone who hates humanity; Moliere's Alceste turned into a title one", + "Answer": "a misanthrope" + }, + { + "Category": "RADIO PERSONALITIES", + "Question": "Tavis Smiley launched this network's first national show to originate from Los Angeles", + "Answer": "NPR" + }, + { + "Category": "HEADQUARTERS", + "Question": "Where on earth is Earthlink headquartered? In this city, same as Coca-Cola", + "Answer": "Atlanta" + }, + { + "Category": "BERMUDA SHORTS", + "Question": "Alexander or Linda could help you with the name of this capital", + "Answer": "Hamilton" + }, + { + "Category": "MILLIONS OF REASONS", + "Question": "\"What Are You Doing After the Orgy?\" is a book by this man who played a millionaire on \"Gilligan's Island\"", + "Answer": "Jim Backus" + }, + { + "Category": "SOUNDS LIKE A RAPPER", + "Question": "Completed in 1955, this bridge crosses the Hudson near Nyack", + "Answer": "the Tappan Zee" + }, + { + "Category": "THE FABULOUS '50s", + "Question": "In 1953 Eisenhower proposed to the U.N. a plan of \"Atoms for\" this", + "Answer": "Peace" + }, + { + "Category": "SNOWBOARDING", + "Question": "Snowboarding is often featured in ads for this Pepsico soda with a lofty name", + "Answer": "Mountain Dew" + }, + { + "Category": "TOM WOLFE", + "Question": "It was Wolfe who first predicted that the 1970s \"Will come to be known as\" this \"decade\"", + "Answer": "the Me Decade" + }, + { + "Category": "MED. ABBREV.", + "Question": "2 of the 3 illnesses for which a DPT vaccination provides immunity", + "Answer": "diphtheria and pertussis" + }, + { + "Category": "THOSE CRAZY GUGGENHEIMS", + "Question": "Benjamin Guggenheim made sure to dress in his evening clothes before going down with this ship in 1912", + "Answer": "the Titanic" + }, + { + "Category": "\"E\" CHANNEL", + "Question": "This South American country does not border Brazil", + "Answer": "Ecuador" + }, + { + "Category": "SNOWBOARDING", + "Question": "An off-balance rider is said to be \"rolling down\" these, from the flailing motion of the arms", + "Answer": "windows" + }, + { + "Category": "TOM WOLFE", + "Question": "In a piece of stock car racing, Wolfe introduced to written English this 3-word phrase for a solid Southern male", + "Answer": "a good old boy" + }, + { + "Category": "MED. ABBREV.", + "Question": "HRT is this kind of therapy; the use of it by menopausal women has recently been questioned", + "Answer": "hormone replacement therapy" + }, + { + "Category": "THOSE CRAZY GUGGENHEIMS", + "Question": "Patriarch Meyer moved from Switzerland to the U.S. in 1847 & set up shop in this Pennsylvania city", + "Answer": "Philadelphia" + }, + { + "Category": "\"E\" CHANNEL", + "Question": "Before going bankrupt in 1989, this airline tried selling $12 plane tickets between Boston & New York", + "Answer": "Eastern" + }, + { + "Category": "THE FABULOUS '50s", + "Question": "A 1954 code trying to stop juvenile delinquency said \"horror\" or \"terror\" could not be used in titles of these", + "Answer": "comics" + }, + { + "Category": "TOM WOLFE", + "Question": "\"The Right Stuff\" tells of how this man broke the sound barrier with 2 broken ribs from a drunken horseback ride", + "Answer": "Chuck Yeager" + }, + { + "Category": "MED. ABBREV.", + "Question": "CTS, carpal tunnel syndrome, can be an RSI, this kind of injury", + "Answer": "repetitive stress injury" + }, + { + "Category": "THOSE CRAZY GUGGENHEIMS", + "Question": "For Daniel, it was all mine, mine, mine; tin in Bolivia & this in Alaska", + "Answer": "gold" + }, + { + "Category": "\"E\" CHANNEL", + "Question": "Alexander Pope once cracked, \"The vulgar boil, the learned roast\" one of these, maybe for breakfast", + "Answer": "an egg" + }, + { + "Category": "THE FABULOUS '50s", + "Question": "In early 1951 TV viewers were riveted watching the Kefauver committee's look into this in America", + "Answer": "organized crime" + }, + { + "Category": "SNOWBOARDING", + "Question": "Like skateboarders, snowboarders perform in a U-shaped structure called this", + "Answer": "a half-pipe" + }, + { + "Category": "TOM WOLFE", + "Question": "Wolfe coined the term \"radical\" this in a story on a party for the Black Panthers thrown by Leonard Bernstein", + "Answer": "chic" + }, + { + "Category": "MED. ABBREV.", + "Question": "I.D. stands for this specialty that focuses on illnesses like viral hepatitis", + "Answer": "infectious disease" + }, + { + "Category": "THOSE CRAZY GUGGENHEIMS", + "Question": "In the 2000 film \"Pollock\", Amy Madigan played this art patron", + "Answer": "Peggy Guggenheim" + }, + { + "Category": "\"E\" CHANNEL", + "Question": "In 1974 Spokane's Cannon Island was the site of this, which featured an environmental theme", + "Answer": "an expo" + }, + { + "Category": "THE FABULOUS '50s", + "Question": "The accuracy of the Quartz clock was surpassed in 1955 by one using this element, Cs", + "Answer": "Cesium" + }, + { + "Category": "SNOWBOARDING", + "Question": "Stances include regular, goofy foot & this one that angles the toes of both feet in opposite directions", + "Answer": "duck foot" + }, + { + "Category": "TOM WOLFE", + "Question": "It's Wolfe's 1968 book about Ken Kesey & friends' cross-country journey", + "Answer": "The Electric Kool-Aid Acid Test" + }, + { + "Category": "MED. ABBREV.", + "Question": "A CAT scan is computerized axial this kind of imaging", + "Answer": "tomography" + }, + { + "Category": "THOSE CRAZY GUGGENHEIMS", + "Question": "The Guggenheim Foundation is the assignee of the patents of this rocket pioneer; it had financed him in the 1940s", + "Answer": "Robert Goddard" + }, + { + "Category": "\"E\" CHANNEL", + "Question": "Philosophy branch that studies the nature & foundations of knowledge", + "Answer": "epistemology" + }, + { + "Category": "AWARD-WINNING AUTHORS", + "Question": "The only Oscar winner also to win a Nobel Prize, this European won a 1938 Oscar for adapting his own play", + "Answer": "George Bernard Shaw" + }, + { + "Category": "WORLD CAPITALS", + "Question": "\"The Rome of the North\" is how famed sculptor Rodin described this Czech capital", + "Answer": "Prague" + }, + { + "Category": "APOLLO 11", + "Question": "Some 1 million spectators surrounded this space center to watch the lift-off", + "Answer": "Cape Kennedy" + }, + { + "Category": "STORYTELLERS", + "Question": "\"Call him\" the narrator of \"Moby Dick\"", + "Answer": "Ishmael" + }, + { + "Category": "MR. MOVIES", + "Question": "In 1962, \"Mr. Hobbs Took\" this", + "Answer": "A Vacation" + }, + { + "Category": "MEATS", + "Question": "This cut is a pig's hind leg above the hock", + "Answer": "ham" + }, + { + "Category": "ANCIENT VIP's", + "Question": "Books about him were written by Plato & Xenophon, both students of his", + "Answer": "Socrates" + }, + { + "Category": "WORLD CAPITALS", + "Question": "Foreign embassies are located in Jiddah, some 500 miles from this country's capital, Riyadh", + "Answer": "Saudi Arabia" + }, + { + "Category": "APOLLO 11", + "Question": "\"Peaceful\" site on the moon where the lunar module touched down", + "Answer": "the Sea of Tranquility" + }, + { + "Category": "STORYTELLERS", + "Question": "ABC radio commentator who tells \"The Rest of the Story\"", + "Answer": "Paul Harvey" + }, + { + "Category": "MR. MOVIES", + "Question": "Though Diane Keaton never found the title character in this 1977 film, she found someone really nuts", + "Answer": "Looking for Mr. Goodbar" + }, + { + "Category": "MEATS", + "Question": "A long-standing tradition in France, hippophagy is the consumption of this", + "Answer": "horse" + }, + { + "Category": "ANCIENT VIP's", + "Question": "This Hebrew king taxed his people into rebellion, which may not have been too wise", + "Answer": "Solomon" + }, + { + "Category": "WORLD CAPITALS", + "Question": "\"From the halls of Montezuma to the shores of Tripoli\" refers to the capitals of these two countries", + "Answer": "Mexico & Libya" + }, + { + "Category": "APOLLO 11", + "Question": "Astronomic name for the booster rocket used to power the launch", + "Answer": "Saturn" + }, + { + "Category": "STORYTELLERS", + "Question": "Some sources say it was Carnegie Hall; others say it was the '67 Newport Festival where he first sang \"Alice's Restaurant\"", + "Answer": "Arlo Guthrie" + }, + { + "Category": "MR. MOVIES", + "Question": "Of James Cagney, Henry Fonda or Jack Lemmon, the one who won an Oscar for \"Mr. Roberts\"", + "Answer": "Jack Lemmon" + }, + { + "Category": "MEATS", + "Question": "These gastropods are sometimes fed aromatic herbs to give them a special savor", + "Answer": "snail" + }, + { + "Category": "ANCIENT VIP's", + "Question": "The period during which he ruled is often referred to as \"The Golden Age of Athens\"", + "Answer": "Pericles" + }, + { + "Category": "WORLD CAPITALS", + "Question": "Founded in 1496 by Columbus's brother, this Dominican capitol is the oldest European city in the new world", + "Answer": "Santo Domingo" + }, + { + "Category": "APOLLO 11", + "Question": "The three crew members of Apollo 11", + "Answer": "Neil Armstrong, Buzz Aldrin, and Michael Collins" + }, + { + "Category": "STORYTELLERS", + "Question": "In addition to her \"Fairie Tale Theatre\", she now has \"Tall Tales and Legends\" playing on cable", + "Answer": "Shelly Duvall" + }, + { + "Category": "MR. MOVIES", + "Question": "Of this 1939 film, the \"New York Times\" said \"More fun even than the Senate itself!\"", + "Answer": "Mr. Smith Goes to Washington" + }, + { + "Category": "MEATS", + "Question": "One of the largest edible fish, these huge flatfish can measure over 5 X 10 feet and can exceed 700 pounds", + "Answer": "halibut" + }, + { + "Category": "ANCIENT VIP's", + "Question": "Uncle of Caligula and stepfather of Nero, this Roman emperor was poisoned by his wife, Nero's mother", + "Answer": "Claudius" + }, + { + "Category": "WORLD CAPITALS", + "Question": "Construction of this planned Asian capital began in 1912; the government was moved there in 1931", + "Answer": "New Delhi, India" + }, + { + "Category": "APOLLO 11", + "Question": "While the lunar lander was code-named \"Eagle\", the command module was code-named this", + "Answer": "Columbia" + }, + { + "Category": "STORYTELLERS", + "Question": "He wrote two collections of modern fables, several fairytales, and \"My World and Welcome to It\"", + "Answer": "James Thurber" + }, + { + "Category": "MR. MOVIES", + "Question": "\"Mr. Pennypacker\", \"Mr. Scoutmaster\", and \"Mr. Belvedere\" are some of his title characters", + "Answer": "Clifton Webb" + }, + { + "Category": "MEATS", + "Question": "Used to cure many meats including bacon, its the creosote and formaldehyde in this that help preserve things", + "Answer": "smoke" + }, + { + "Category": "ANCIENT VIP's", + "Question": "In the 6th century B.C., he conquered Babylon and made Persia the greatest empire in the world", + "Answer": "Cyrus the Great" + }, + { + "Category": "PHYSICS", + "Question": "A shotgun's powerful recoil is an example of his third law of motion", + "Answer": "Isaac Newton" + }, + { + "Category": "PRESIDENTS", + "Question": "General whose Presidential campaign song was written by Irving Berlin", + "Answer": "Dwight Eisenhower" + }, + { + "Category": "STARTS WITH \"P\"", + "Question": "The word \"pram\" is short for this", + "Answer": "parambulator" + }, + { + "Category": "POETIC TERMS", + "Question": "The sonnet originated in this country with such poets as Guitoni D'Arretzo", + "Answer": "Italy" + }, + { + "Category": "NEPAL", + "Question": "It consists of two red triangles outlined in blue with white symbols of the sun and the moon", + "Answer": "the flag of Nepal" + }, + { + "Category": "GREAT DAMES", + "Question": "In 1952, she sprang her \"Mousetrap\"", + "Answer": "Agatha Christie" + }, + { + "Category": "PHYSICS", + "Question": "The term horsepower came about when James Watt compared work done by a horse to work done by this", + "Answer": "steam engine" + }, + { + "Category": "PRESIDENTS", + "Question": "All elected Presidents who are members of this party died in office", + "Answer": "Whig" + }, + { + "Category": "STARTS WITH \"P\"", + "Question": "Movie that featured the following music", + "Answer": "Picnic" + }, + { + "Category": "POETIC TERMS", + "Question": "These funny five-line verses often end with the name of a place; or, a place in Ireland", + "Answer": "Limerick" + }, + { + "Category": "NEPAL", + "Question": "At Lumbini, you can visit the birthplace of this \"Enlightened One\"", + "Answer": "Buddha" + }, + { + "Category": "GREAT DAMES", + "Question": "She played \"Hamlet\" at the age of 73 and a Vulcan high priestess in \"Star Trek III\"", + "Answer": "Dame Judith Anderson" + }, + { + "Category": "PHYSICS", + "Question": "If it were not for the retarding influence of this, raindrops would attain bullet-like speeds", + "Answer": "the atmosphere" + }, + { + "Category": "PRESIDENTS", + "Question": "This Iowan was the first President born west of the Mississippi", + "Answer": "Herbert Hoover" + }, + { + "Category": "STARTS WITH \"P\"", + "Question": "This extinct early man is known from fossils found at Chukutien", + "Answer": "Peking Man " + }, + { + "Category": "POETIC TERMS", + "Question": "A deliberate violation of the rules of rhyming or grammar, not a little piece of paper from the DMV", + "Answer": "poetic license" + }, + { + "Category": "NEPAL", + "Question": "This Sherpa who went to the top of the world with Edmund Hillary died in 1986 at the age of 72", + "Answer": "Tenzing Norgay" + }, + { + "Category": "GREAT DAMES", + "Question": "She helped her husband survive an attempted assassination & was Nureyev's partner for over fifteen years", + "Answer": "Dame Margot Fonteyn" + }, + { + "Category": "PHYSICS", + "Question": "Pulling the cloth off a table without disturbing the dishes is the principle of this", + "Answer": "inertia" + }, + { + "Category": "PRESIDENTS", + "Question": "The last President to sport a moustache or beard while in office", + "Answer": "William Howard Taft" + }, + { + "Category": "STARTS WITH \"P\"", + "Question": "As being of great price purchased with all she had, Hester Prynne named her child this", + "Answer": "Pearl" + }, + { + "Category": "POETIC TERMS", + "Question": "16th century poet who perfected in \"The Faerie Queene\" the stanza named for him", + "Answer": "Edmund Spenser" + }, + { + "Category": "NEPAL", + "Question": "\"Wooden temple\", the meaning of this city's name, refers to the 400-year old one in its central square", + "Answer": "Katmandu" + }, + { + "Category": "GREAT DAMES", + "Question": "She starred as Cleopatra and Olivier's Juliet, long before booking \"A Passage to India\"", + "Answer": "Dame Peggy Ashcroft" + }, + { + "Category": "PHYSICS", + "Question": "Term for the speed of a body in a specified direction", + "Answer": "velocity" + }, + { + "Category": "PRESIDENTS", + "Question": "The \"54º40' or Fight\" fever over Oregon helped elect this president, the only one ever to be speaker of the U.S. House", + "Answer": "James K. Polk" + }, + { + "Category": "STARTS WITH \"P\"", + "Question": "The small cogwheel that engages a larger cogwheel", + "Answer": "pinion" + }, + { + "Category": "POETIC TERMS", + "Question": "It's an echoic term for words like hiss that imitate an actual sound", + "Answer": "onomatopeia" + }, + { + "Category": "NEPAL", + "Question": "Told to jump from 600 feet, these tough Nepalese soldiers, not knowing they'd get chutes, said 300 feet was easier", + "Answer": "Gurkhas" + }, + { + "Category": "GREAT DAMES", + "Question": "This Maori diva from New Zealand sang with Nelson Riddle and at Prince Charles's wedding", + "Answer": "Kiri Te Kanawa" + }, + { + "Category": "THE BIBLE", + "Question": "The first verse of this book says, \"There was a man in the land of Uz that feared God and eschewed evil\"", + "Answer": "Job" + }, + { + "Category": "AH, SWEET MYTHTERY", + "Question": "Telemachus was this long lost traveler's faithful son", + "Answer": "Odysseus" + }, + { + "Category": "HIP-HOP & RAP", + "Question": "Yo, this notorious rapper's second posthumous No. 1 hit single was 1997's \"Mo Money Mo Problems\"", + "Answer": "Notorious B.I.G." + }, + { + "Category": "SEXPERTISE", + "Question": "Stevie Winwood, Stevie Nicks, Stevie Wonder", + "Answer": "Stevie Nicks" + }, + { + "Category": "THOSE AMAZING ANIMALS", + "Question": "Newly born calves of this \"colorful\" mammal can measure 28 feet in length & weigh up to 3 tons", + "Answer": "the blue whale" + }, + { + "Category": "A FASHIONABLE CATEGORY", + "Question": "Romance is a perfume from this designer whom you might call a major \"polo\" player", + "Answer": "Ralph Lauren" + }, + { + "Category": "2-LETTER WORDS", + "Question": "Before the grand jury, Bill Clinton said, \"It depends on...your definition of\" this word", + "Answer": "\"is\"" + }, + { + "Category": "AH, SWEET MYTHTERY", + "Question": "Of a dryad, a naiad or an oread, she's the water nymph", + "Answer": "a naiad" + }, + { + "Category": "HIP-HOP & RAP", + "Question": "This huge hit by Jay-Z samples a song from the musical \"Annie\"", + "Answer": "\"Hard Knock Life\"" + }, + { + "Category": "SEXPERTISE", + "Question": "Robin Leach, Robin Givens, Robin Cook", + "Answer": "Robin Givens" + }, + { + "Category": "THOSE AMAZING ANIMALS", + "Question": "No longer used in Thailand to haul teak from the jungle, these animals are being trained to paint", + "Answer": "an elephant" + }, + { + "Category": "A FASHIONABLE CATEGORY", + "Question": "Wallace might know this term for a metal eyelet mainly used on belts but also seen on hems & cuffs", + "Answer": "a grommet" + }, + { + "Category": "2-LETTER WORDS", + "Question": "\"Ut\" used to be used for the first or key note of the musical scale; this has replaced it", + "Answer": "do" + }, + { + "Category": "AH, SWEET MYTHTERY", + "Question": "Hard-partyin' half-man, half-goat creatures of Greek mythology", + "Answer": "a satyr" + }, + { + "Category": "HIP-HOP & RAP", + "Question": "This \"King of Crunk\" is not to be confused with Lil' Wayne", + "Answer": "Lil Jon" + }, + { + "Category": "SEXPERTISE", + "Question": "Pat Leahy, Pat Buchanan, Pat Nixon", + "Answer": "Pat Nixon" + }, + { + "Category": "THOSE AMAZING ANIMALS", + "Question": "High in Omega-3 fatty acids, oils from these creatures have been shown to reduce high levels of triglycerides", + "Answer": "fish" + }, + { + "Category": "A FASHIONABLE CATEGORY", + "Question": "The length of these ladylike accessories is denoted by buttons; 16-button ones are formal length", + "Answer": "gloves" + }, + { + "Category": "2-LETTER WORDS", + "Question": "An Italian river, or the red Teletubby", + "Answer": "Po" + }, + { + "Category": "AH, SWEET MYTHTERY", + "Question": "The Myrmidons were this great hero's brutal cohorts in the Trojan War", + "Answer": "Achilles" + }, + { + "Category": "HIP-HOP & RAP", + "Question": "A TV show on E! chronicles the \"Father Hood\" of this rap star", + "Answer": "Snoop Dogg" + }, + { + "Category": "SEXPERTISE", + "Question": "Kim Campbell, Kim Philby, Kim Jong Il", + "Answer": "Kim Campbell" + }, + { + "Category": "THOSE AMAZING ANIMALS", + "Question": "Because hippo teeth are made of this, they won't yellow & were once a popular source for false teeth", + "Answer": "ivory" + }, + { + "Category": "A FASHIONABLE CATEGORY", + "Question": "Feline name for the full-body stocking made popular by Diana Rigg on \"The Avengers\"", + "Answer": "a catsuit" + }, + { + "Category": "2-LETTER WORDS", + "Question": "Don't have a cow, man, it's just the 12th letter of the Greek alphabet", + "Answer": "mu" + }, + { + "Category": "AH, SWEET MYTHTERY", + "Question": "This mythological sculptor tragically fell in love with a beautiful statue he had carved", + "Answer": "Pygmalion" + }, + { + "Category": "HIP-HOP & RAP", + "Question": "Group that includes members Krayzie Bone, Layzie Bone & Wish Bone", + "Answer": "Bone Thugs-n-Harmony" + }, + { + "Category": "SEXPERTISE", + "Question": "P.D. James, G.K. Chesterton, A.A. Milne", + "Answer": "P.D. James" + }, + { + "Category": "THOSE AMAZING ANIMALS", + "Question": "This clam named for a sharp instrument can burrow almost as fast as you can shovel", + "Answer": "a razor clam" + }, + { + "Category": "A FASHIONABLE CATEGORY", + "Question": "In the 1800s, it was fashionable to wear a cap named for this woman who stabbed Jean-Paul Marat", + "Answer": "Charlotte Corday" + }, + { + "Category": "2-LETTER WORDS", + "Question": "In British slang this word alone means thank you; 2 together means good-bye", + "Answer": "ta" + }, + { + "Category": "20th CENTURY WORLD LEADERS", + "Question": "Like mom like son: sadly, her son Rajiv was also assassinated", + "Answer": "Indira Gandhi" + }, + { + "Category": "WESTERNS", + "Question": "This singer's films include the westerns \"Flaming Star\", \"Charro!\" & \"Love Me Tender\"", + "Answer": "Elvis Presley" + }, + { + "Category": "ART", + "Question": "This Chinese dynasty that reigned from 1368 to 1644 was known for beautiful vases", + "Answer": "Ming" + }, + { + "Category": "COMPUTER TERMS", + "Question": "It can mean any computer used by an individual, or an IBM-type machine as opposed to a Mac", + "Answer": "a P.C." + }, + { + "Category": "WORLD UP!", + "Question": "In May 1988, after 8 years of fighting there, the Soviet army began withdrawing from this country", + "Answer": "Afghanistan" + }, + { + "Category": "IT HAD TO \"BU\"", + "Question": "Any dry red table wine may be called this even if it doesn't come from the French region of the same name", + "Answer": "Burgundy" + }, + { + "Category": "20th CENTURY WORLD LEADERS", + "Question": "In 1958 he launched his Great Leap Forward program; it was a great disaster", + "Answer": "Mao" + }, + { + "Category": "WESTERNS", + "Question": "It's the type of transport in the title of John Wayne's 1939 breakout film", + "Answer": "a stagecoach" + }, + { + "Category": "ART", + "Question": "Dante Gabriel Rossetti wanted to take art back to \"pre-\" this Renaissance master born in 1483", + "Answer": "Raphael" + }, + { + "Category": "COMPUTER TERMS", + "Question": "You can't have too much RAM, which stands for this", + "Answer": "random-access memory" + }, + { + "Category": "WORLD UP!", + "Question": "This island that gained independence from Denmark in 1944 is below the Arctic Circle", + "Answer": "Iceland" + }, + { + "Category": "IT HAD TO \"BU\"", + "Question": "In 1403 Venice established the first maritime quarantine station to prevent this deadly disease", + "Answer": "the bubonic plague" + }, + { + "Category": "WESTERNS", + "Question": "He won his first Oscar for directing \"Unforgiven\"", + "Answer": "Clint Eastwood" + }, + { + "Category": "ART", + "Question": "We're not joshing--in 1769 this portrait painter got knighted", + "Answer": "Reynolds" + }, + { + "Category": "COMPUTER TERMS", + "Question": "This unit equals about 1,000 megabytes, or about half a million pages of text", + "Answer": "a gigabyte" + }, + { + "Category": "IT HAD TO \"BU\"", + "Question": "Government ones of these include of Indian Affairs & of the Census", + "Answer": "Bureaus" + }, + { + "Category": "20th CENTURY WORLD LEADERS", + "Question": "Wearing the hat of Chancellor for over 15 years, he was Germany's longest-serving leader since Bismarck", + "Answer": "Helmut Kohl" + }, + { + "Category": "WESTERNS", + "Question": "This Dustin Hoffman title character was also known as Jack Crabb & the Soda Pop Kid", + "Answer": "Little Big Man" + }, + { + "Category": "ART", + "Question": "Roger Fry of the Met coined this term for the works of artists like Cezanne & Gauguin", + "Answer": "Postimpressionist" + }, + { + "Category": "COMPUTER TERMS", + "Question": "In the acronym BIOS, these 2 words come between \"basic\" & \"system\"", + "Answer": "input & output" + }, + { + "Category": "WORLD UP!", + "Question": "Russia's longest border is not with China but with this \"stan\"", + "Answer": "Kazakhstan" + }, + { + "Category": "IT HAD TO \"BU\"", + "Question": "Established in 1881, The Wharton School at the U. of Pennsylvania was the world's first collegiate school of this", + "Answer": "business" + }, + { + "Category": "ART", + "Question": "\"The Regatta at Argenteuil\" shows this Frenchman's love of water subjects, like lilies", + "Answer": "Monet" + }, + { + "Category": "WORLD UP!", + "Question": "In 1980 Luis Garcia Meza took power in this landlocked S. Amer. country that's had more than 180 coups in its history", + "Answer": "Bolivia" + }, + { + "Category": "IT HAD TO \"BU\"", + "Question": "From the Greek for \"herdsman\", it means pastoral or idyllic", + "Answer": "bucolic" + }, + { + "Category": "THE BILLBOARD HOT 100", + "Question": "A song by this artist hit No. 1 in 1999, making her at age 52 the oldest female to have a Billboard No. 1 single", + "Answer": "Cher" + }, + { + "Category": "BOTANY", + "Question": "The flowers of this lawn weed, Taraxacum oficinale, are sometimes used to make wine", + "Answer": "dandelions" + }, + { + "Category": "FLY COUNTRIES", + "Question": "Iberia Airlines", + "Answer": "Spain" + }, + { + "Category": "FUN WITH BALLET", + "Question": "In \"La Boutique Fantasque\", dolls come to life & perform this high-kicking, skirt-swooshing dance", + "Answer": "Can-can" + }, + { + "Category": "LETTER MEN", + "Question": "At his death in 1971, there were more than 1,600 department stores bearing his name", + "Answer": "J.C. Penney" + }, + { + "Category": "ONE-WORD RHYMES", + "Question": "An important person, perhaps with an elaborate toupee", + "Answer": "bigwig" + }, + { + "Category": "BOTANY", + "Question": "The common species of this prairie flower, Helianthus annuus, can reach a height of 15 feet", + "Answer": "sunflower" + }, + { + "Category": "FLY COUNTRIES", + "Question": "Aer Lingus", + "Answer": "Ireland" + }, + { + "Category": "FUN WITH BALLET", + "Question": "Every \"Psycho\" knows that Matthew Bourne's ballet \"Deadly Serious\" is an homage to this film director", + "Answer": "Alfred Hitchcock" + }, + { + "Category": "LETTER MEN", + "Question": "He's the taller of the two gentlemen in the photo seen here", + "Answer": "P.T. Barnum" + }, + { + "Category": "ONE-WORD RHYMES", + "Question": "I've come to the ashram so this person can show me the unreality of material things -- oops, I scratched his Mercedes", + "Answer": "guru" + }, + { + "Category": "BOTANY", + "Question": "About 3/4 of U.S. plantings of this palm fruit are of the Deglet Noor, a semidry variety", + "Answer": "dates" + }, + { + "Category": "FLY COUNTRIES", + "Question": "Olympic Airlines", + "Answer": "Greece" + }, + { + "Category": "FUN WITH BALLET", + "Question": "The Roanoke Ballet's dancers raced around with logos on their unitards in a ballet named for this auto assoc.", + "Answer": "NASCAR" + }, + { + "Category": "LETTER MEN", + "Question": "In 1930 he directed his first talkie, \"Abraham Lincoln\", starring Walter Huston", + "Answer": "D.W. Griffith" + }, + { + "Category": "ONE-WORD RHYMES", + "Question": "Nicole Kidman is one; so was Lucille Ball & Vincent Van Gogh", + "Answer": "redhead" + }, + { + "Category": "BOTANY", + "Question": "Reproducing by means of spores, the only tree with no flowers, fruits or seeds is called the tree type of this", + "Answer": "fern" + }, + { + "Category": "FLY COUNTRIES", + "Question": "Belavia (Its first terminal was in Minsk)", + "Answer": "Belarus" + }, + { + "Category": "FUN WITH BALLET", + "Question": "The music of film composer Alex North drives the ballet based on this play about Stanley Kowalski", + "Answer": "\"A Streetcar Named Desire\"" + }, + { + "Category": "LETTER MEN", + "Question": "He designed the building for the Rock & Roll Hall of Fame", + "Answer": "I.M. Pei" + }, + { + "Category": "ONE-WORD RHYMES", + "Question": "In Manhattan, going from Central Park to Chelsea is heading this way", + "Answer": "downtown" + }, + { + "Category": "BOTANY", + "Question": "Prized for its oil, this evergreen shrub of the American southwest is also known as the goat nut", + "Answer": "Jojoba" + }, + { + "Category": "FLY COUNTRIES", + "Question": "Koninklijke Luchtvaart Maatshappij (you might know it by its abbreviation)", + "Answer": "The Netherlands" + }, + { + "Category": "FUN WITH BALLET", + "Question": "Dizzy Gillespie's music is also featured in it, but the ballet \"For 'Bird' - With Love\" is a tribute to him", + "Answer": "Charlie Parker" + }, + { + "Category": "LETTER MEN", + "Question": "A visit to the Marabar Caves is a turning point in his novel \"A Passage to India\"", + "Answer": "E.M. Forster" + }, + { + "Category": "ONE-WORD RHYMES", + "Question": "This term for empty words or nonsense was originally a trick to gain applause", + "Answer": "claptrap" + }, + { + "Category": "BIBLICAL GEOGRAPHY", + "Question": "Genesis calls it \"the salt sea\" perhaps because its salinity reaches 4 times that of ocean water", + "Answer": "the Dead Sea" + }, + { + "Category": "WHO'S YOUR MOMMY?", + "Question": "Liza Minnelli", + "Answer": "Judy Garland" + }, + { + "Category": "AROUND WASHINGTON, D.C.", + "Question": "You might see Bob Woodward during your walking tour of this publication's building on 15th Street N.W.", + "Answer": "the Washington Post" + }, + { + "Category": "GRAPES", + "Question": "Ths underwear maker's logo contains fig leaves, an apple & different types of grapes", + "Answer": "Fruit of the Loom" + }, + { + "Category": "OF \"RATH\"", + "Question": "It's an adjective meaning really, really angry", + "Answer": "wrathful" + }, + { + "Category": "BIBLICAL GEOGRAPHY", + "Question": "This mount \"as altogether on a smoke, because the Lord descended upon it in fire\"", + "Answer": "Sinai" + }, + { + "Category": "WHO'S YOUR MOMMY?", + "Question": "Kate Hudson", + "Answer": "Goldie Hawn" + }, + { + "Category": "AROUND WASHINGTON, D.C.", + "Question": "The Peacock room at the Freer Gallery shows the fun-loving side of this artist known for that dour depiction of mama", + "Answer": "Whistler" + }, + { + "Category": "NAME THE POET", + "Question": "\"Do not go gentle into that good night, old age should burn and rave at close of day\"", + "Answer": "Dylan Thomas" + }, + { + "Category": "GRAPES", + "Question": "A wine known as Lacrima Christi, or \"tears of Christ\" is made from grapes grown on the slopes of this Italian volcano", + "Answer": "Vesuvius" + }, + { + "Category": "OF \"RATH\"", + "Question": "On election night 2000, this newsman spouted lines like \"Bush will be madder than a rained-on rooster\"", + "Answer": "Dan Rather" + }, + { + "Category": "BIBLICAL GEOGRAPHY", + "Question": "Lying at the foot of the mount of olives, this garden was the site where Jesus was betrayed & arrested", + "Answer": "Gethsemane" + }, + { + "Category": "WHO'S YOUR MOMMY?", + "Question": "Gwyneth Paltrow", + "Answer": "Blythe Danner" + }, + { + "Category": "AROUND WASHINGTON, D.C.", + "Question": "The museum that's now the Smithsonian's Arts & Industries Bldg. was the site of this man's 1881 inaugural ball", + "Answer": "Garfield" + }, + { + "Category": "NAME THE POET", + "Question": "\"I hear American singing, the varied carols I hear\"", + "Answer": "Walt Whitman" + }, + { + "Category": "GRAPES", + "Question": "In an Aesop fable, this animal decides the grapes he can't reach must therefore be sour", + "Answer": "a fox" + }, + { + "Category": "OF \"RATH\"", + "Question": "For many, this Johannesburg-born actor will forever be the definitive Sherlock Holmes", + "Answer": "Basil Rathbone" + }, + { + "Category": "BIBLICAL GEOGRAPHY", + "Question": "In Ezekiel this capital of Egypt is called Noph, & the Lord promises to \"destroy the idols\" there (he didn't mean Elvis)", + "Answer": "Memphis" + }, + { + "Category": "WHO'S YOUR MOMMY?", + "Question": "Melanie Griffith", + "Answer": "Tippi Hedren" + }, + { + "Category": "AROUND WASHINGTON, D.C.", + "Question": "It was once known as \"Presidents Park\" but perhaps this name for it looks better on a \"Marquis\"", + "Answer": "Lafayette Park" + }, + { + "Category": "NAME THE POET", + "Question": "\"So long as men can breathe or eyes can see, so long lives this, and this gives life to thee\"", + "Answer": "Shakespeare" + }, + { + "Category": "GRAPES", + "Question": "In 1962 this man organized migrant grape pickers into what became known as the United Farm Workers", + "Answer": "Cesar Chavez" + }, + { + "Category": "OF \"RATH\"", + "Question": "Persian religious leader AKA Zoroaster", + "Answer": "Zarathustra" + }, + { + "Category": "BIBLICAL GEOGRAPHY", + "Question": "In the Song of Solomon, a bride refers to herself as \"the rose of\" this plain between Joppa & Mount Carmel", + "Answer": "Sharon" + }, + { + "Category": "WHO'S YOUR MOMMY?", + "Question": "Mariska Hargitay", + "Answer": "Jayne Mansfield" + }, + { + "Category": "AROUND WASHINGTON, D.C.", + "Question": "This Frenchman who planned D.C. had such a \"terrible\" temperament that he was dismissed in 1792", + "Answer": "Pierre L'Enfant" + }, + { + "Category": "NAME THE POET", + "Question": "\"Hope is the thing with feathers that perches in the soul and sings the tune without the words\"", + "Answer": "Emily Dickinson" + }, + { + "Category": "GRAPES", + "Question": "A popular grape used in making raisins is this variety that shares its name with the capital of Oman", + "Answer": "Muscat" + }, + { + "Category": "OF \"RATH\"", + "Question": "Basement beerhall in Bavaria", + "Answer": "rathskeller" + }, + { + "Category": "ORGANIZATIONS", + "Question": "The C.A.P., or Common Agricultural Policy, accounts for almost half the budget of this 25-nation organization", + "Answer": "the European Union" + }, + { + "Category": "\"N\"ATIONS OF THE WORLD", + "Question": "Make a trek to Utrecht & you'll find yourself in this country", + "Answer": "Netherlands" + }, + { + "Category": "ALL GOD'S CRITTERS", + "Question": "Widely hunted for their hides, the American, Cuban & Nile species of this reptile are now in danger", + "Answer": "Crocodile" + }, + { + "Category": "ESOTERIC KNOWLEDGE", + "Question": "The Houses of Lancaster & York used different colored types of these flowers as their symbols", + "Answer": "Roses" + }, + { + "Category": "MOVIE DEBUTS", + "Question": "She debuted in a bit part as Woody Allen's date in \"Annie Hall\" 2 years before \"Alien\" made her a star", + "Answer": "Sigourney Weaver" + }, + { + "Category": "CONVENTIONS", + "Question": "On \"Saturday Night Live\", William Shatner told attendees at this type of convention, \"Get a life!\"", + "Answer": "Star Trek" + }, + { + "Category": "PROVERBS", + "Question": "It \"makes a man healthy, wealthy, and wise\"", + "Answer": "\"Early to bed and early to rise\"" + }, + { + "Category": "\"N\"ATIONS OF THE WORLD", + "Question": "On the first Monday in June, this Kiwi country celebrates the Queen's birthday, the queen being Elizabeth", + "Answer": "New Zealand" + }, + { + "Category": "ALL GOD'S CRITTERS", + "Question": "Because it dips its food in water, it has the scientific name Lotor, which means \"washer\"", + "Answer": "Raccoon" + }, + { + "Category": "ESOTERIC KNOWLEDGE", + "Question": "He was thick-skulled, heavy-browed, about 5 feet tall & lived in Germany about 80,000 years ago", + "Answer": "Neanderthal Man" + }, + { + "Category": "MOVIE DEBUTS", + "Question": "This half-sister of country singer Wynonna first hit the big screen in the 1992 comedy \"Kuffs\"", + "Answer": "Ashley Judd" + }, + { + "Category": "CONVENTIONS", + "Question": "New England Federalists convened in Hartford in 1814 to denounce this war", + "Answer": "War of 1812" + }, + { + "Category": "PROVERBS", + "Question": "In \"The Wizard of Oz\", Dorothy clicks her heels & repeats this before she's whisked back to Kansas", + "Answer": "\"There's no place like home\"" + }, + { + "Category": "\"N\"ATIONS OF THE WORLD", + "Question": "There are thousands of temples & shrines in this country's Katmandu Valley", + "Answer": "Nepal" + }, + { + "Category": "ALL GOD'S CRITTERS", + "Question": "Males of this duck-billed mammal have poison spurs on each hind foot that can kill small animals", + "Answer": "Platypus" + }, + { + "Category": "ESOTERIC KNOWLEDGE", + "Question": "The number of different hexagrams in the I Ching, or the number of squares on a checkerboard", + "Answer": "64" + }, + { + "Category": "MOVIE DEBUTS", + "Question": "At 13 this actress with a weekday in her name starred in the 1956 classic \"Rock, Rock, Rock!\"", + "Answer": "Tuesday Weld" + }, + { + "Category": "CONVENTIONS", + "Question": "In the film \"Chasing Amy\", boy meets girl at a convention for artists & fans of these", + "Answer": "Comic books" + }, + { + "Category": "PROVERBS", + "Question": "It \"seldom knocks twice\", so make the most of it", + "Answer": "Opportunity" + }, + { + "Category": "\"N\"ATIONS OF THE WORLD", + "Question": "Homeland of Edvards Munch & Grieg", + "Answer": "Norway" + }, + { + "Category": "ALL GOD'S CRITTERS", + "Question": "The barn species of this bird is sometimes called monkey-faced due to its simian features", + "Answer": "Owl" + }, + { + "Category": "ESOTERIC KNOWLEDGE", + "Question": "When his friend became Pope in 1623, he thought he'd be allowed to discuss his heliocentric theory", + "Answer": "Galileo" + }, + { + "Category": "MOVIE DEBUTS", + "Question": "The Al Pacino legal drama \"...And Justice for All\" marked the screen debut of this actor, later TV's \"Coach\"", + "Answer": "Craig T. Nelson" + }, + { + "Category": "CONVENTIONS", + "Question": "(Hi, I'm Paula Poundstone) I heard stories of Bob Dole in a towel at the 1996 Republican Convention in this California city", + "Answer": "San Diego" + }, + { + "Category": "PROVERBS", + "Question": "\"Better the foot slip than\" this body part", + "Answer": "Tongue/lip" + }, + { + "Category": "\"N\"ATIONS OF THE WORLD", + "Question": "It became fully independent of South Africa March 21, 1990", + "Answer": "Namibia" + }, + { + "Category": "ALL GOD'S CRITTERS", + "Question": "The \"great\" species of this slender predatory fish seen here has been called the \"Tiger of the Sea\"", + "Answer": "Barracuda" + }, + { + "Category": "ESOTERIC KNOWLEDGE", + "Question": "Native Americans grew these together with corn & at harvest time combined them into \"M'sickquatash\"", + "Answer": "Lima beans" + }, + { + "Category": "MOVIE DEBUTS", + "Question": "This son of Colleen Dewhurst & George C. Scott debuted in the 1988 film \"Five Corners\"", + "Answer": "Campbell Scott" + }, + { + "Category": "CONVENTIONS", + "Question": "The Annapolis Convention of 1786 did nothing but suggest holding this convention in Philadelphia", + "Answer": "Constitutional Convention" + }, + { + "Category": "PROVERBS", + "Question": "\"Manus manum lavat\" is the Latin equivalent of this proverb", + "Answer": "\"One hand washes the other\"" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "British commander Sir Edward Pakenham was killed in this battle fought 2 weeks after the War of 1812", + "Answer": "Battle of New Orleans" + }, + { + "Category": "THE BIG APPLE", + "Question": "Sheep Meadow & the Turtle Pond can be found in this 843-acre public playground", + "Answer": "Central Park" + }, + { + "Category": "SPORTS", + "Question": "The ball used in this sport is about 11 inches long & about 7 inches wide at the center", + "Answer": "Football" + }, + { + "Category": "LITERARY OPENINGS", + "Question": "\"Every Who down in Who-ville liked Christmas a lot...\"", + "Answer": "How the Grinch Stole Christmas!" + }, + { + "Category": "HEY, \"U\"!", + "Question": "It precedes label, suit & Jack", + "Answer": "Union" + }, + { + "Category": "PASS THE CHEESE, PLEASE", + "Question": "It's also called Chester cheese, & some people think it's the cat's meow", + "Answer": "Cheshire cheese" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "To reach eastern markets in the 1800s, Texas drovers brought their cattle to Kansas via this trail", + "Answer": "the Chisholm Trail" + }, + { + "Category": "THE BIG APPLE", + "Question": "One World Trade Center is the tallest building in the city; this is the second tallest", + "Answer": "Two World Trade Center" + }, + { + "Category": "SPORTS", + "Question": "On Sept. 23, 1926 this heavyweight boxing champ lost his title to Gene Tunney in a decision", + "Answer": "Jack Dempsey" + }, + { + "Category": "LITERARY OPENINGS", + "Question": "\"True!-Nervous-very, very dreadfully nervous I had been and am; but why will you say that I am mad?\"", + "Answer": "\"The Tell-Tale Heart\"" + }, + { + "Category": "HEY, \"U\"!", + "Question": "It may be a mischievous scamp, or a \"sea\" creature", + "Answer": "Urchin" + }, + { + "Category": "PASS THE CHEESE, PLEASE", + "Question": "Parmesan is named for Parma, & this other grated cheese is named for Italy's capital", + "Answer": "Romano" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "On November 14, 1889, the New York World called her trip, \"The Longest Journey Known to Mankind\"", + "Answer": "Nellie Bly" + }, + { + "Category": "THE BIG APPLE", + "Question": "A mast to moor dirigibles was added to this skyscraper, but only one ever moored successfully", + "Answer": "Empire State Building" + }, + { + "Category": "SPORTS", + "Question": "Named for a U.S. doubles champ, this cup is presented to the winner of a 16-team men's tennis tourney", + "Answer": "Davis Cup" + }, + { + "Category": "LITERARY OPENINGS", + "Question": "\"It was a pleasure to burn.\"", + "Answer": "\"Fahrenheit 451\"" + }, + { + "Category": "HEY, \"U\"!", + "Question": "In legend, this mythical beast could purify poisoned water with its single horn", + "Answer": "Unicorn" + }, + { + "Category": "PASS THE CHEESE, PLEASE", + "Question": "The \"baby\" type of this Dutch cheese, that's similar to Edam, is usually encased in red wax", + "Answer": "Gouda" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "On Mar. 27, 1964 this largest Alaska city was hit by an 8.4 earthquake", + "Answer": "Anchorage" + }, + { + "Category": "THE BIG APPLE", + "Question": "He was inaugurated for his second time as mayor of New York City January 1, 1998", + "Answer": "Rudolph Giuliani" + }, + { + "Category": "SPORTS", + "Question": "(Hi, I'm Greg Gumbel) During his 26-year career Sparky Anderson managed the Cincinnati Reds to 4 NL titles & this team to 1 AL championship", + "Answer": "Detroit Tigers" + }, + { + "Category": "LITERARY OPENINGS", + "Question": "\"All happy families are alike but an unhappy family is unhappy after its own fashion.\"", + "Answer": "\"Anna Karenina\"" + }, + { + "Category": "HEY, \"U\"!", + "Question": "An entrepreneur who's launching a new enterprise, or a funeral director", + "Answer": "Undertaker" + }, + { + "Category": "PASS THE CHEESE, PLEASE", + "Question": "This most famous Greek cheese is sometimes described as \"pickled\" because it's cured in brine", + "Answer": "Feta" + }, + { + "Category": "AMERICAN HISTORY", + "Question": "In 1787 Arthur St. Clair became the first governor of this vast territory north of the Ohio River", + "Answer": "Northwest Territory" + }, + { + "Category": "THE BIG APPLE", + "Question": "\"Give My Regards to\" this Broadway legend whose statue in Times Square is seen here:", + "Answer": "George M. Cohan" + }, + { + "Category": "SPORTS", + "Question": "In 1973 Ron Turcotte rode this horse to the first Triple Crown victory in 25 years", + "Answer": "Secretariat" + }, + { + "Category": "LITERARY OPENINGS", + "Question": "\"My mother died. Today, or maybe it was yesterday.\"", + "Answer": "\"The Stranger\"" + }, + { + "Category": "HEY, \"U\"!", + "Question": "This citrus fruit from Jamaica is named for its lack of physical beauty", + "Answer": "Ugli fruit" + }, + { + "Category": "PASS THE CHEESE, PLEASE", + "Question": "Samsoe is a Swiss-style cow's milk cheese named for an island in this Scandinavian country", + "Answer": "Denmark" + }, + { + "Category": "MACBETH", + "Question": "Macbeth says to this character, \"Thy bones are marrowless, thy blood is cold\"", + "Answer": "Banquo's ghost" + }, + { + "Category": "AMERICANA", + "Question": "On December 19 the people of this U.S. state celebrate Princess Bernice Pauahi Bishop's birthday", + "Answer": "Hawaii" + }, + { + "Category": "SPORTS", + "Question": "In 1967 this New York Jets quarterback became the first pro to pass for more than 4,000 yards in a season", + "Answer": "Joe Namath" + }, + { + "Category": "GRAINS & STAPLES", + "Question": "The name of this food, not a true grain, comes from the Dutch meaning \"beech wheat\"", + "Answer": "buckwheat" + }, + { + "Category": "HISTORIC WOMEN", + "Question": "On April 5, 1614, in Jamestown, she married John Rolfe", + "Answer": "Pocahontas" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Since 1908 this group has distributed over 26 million Bibles to hotels & other institutions", + "Answer": "Gideon" + }, + { + "Category": "PROVERBS", + "Question": "It's the 4-letter word that \"makes the world go round\"", + "Answer": "love" + }, + { + "Category": "AMERICANA", + "Question": "In 1986 this New York capital celebrated the 300th anniversary of its charter as a city", + "Answer": "Albany" + }, + { + "Category": "SPORTS", + "Question": "Founded in 1897, it's the world's oldest annual marathon", + "Answer": "the Boston Marathon" + }, + { + "Category": "GRAINS & STAPLES", + "Question": "The rolled form of this grain cooks in about 5 minutes; the steel-cut takes much longer", + "Answer": "oats" + }, + { + "Category": "HISTORIC WOMEN", + "Question": "Anna Ivanovna, empress of Russia from 1730 to 1740, was the niece of this great ruler", + "Answer": "Peter the Great" + }, + { + "Category": "ORGANIZATIONS", + "Question": "It's what the R stands for in AARP", + "Answer": "retired" + }, + { + "Category": "PROVERBS", + "Question": "There's \"no time like\" this", + "Answer": "the present" + }, + { + "Category": "AMERICANA", + "Question": "This U.S. first lady once taught dance in Grand Rapids", + "Answer": "Betty Ford" + }, + { + "Category": "SPORTS", + "Question": "In 1991, after 12 seasons at the Salt Palace, this NBA team moved its home games to the Delta Center", + "Answer": "the Utah Jazz" + }, + { + "Category": "GRAINS & STAPLES", + "Question": "Basmati, an aromatic type of this grain, is grown in India", + "Answer": "rice" + }, + { + "Category": "HISTORIC WOMEN", + "Question": "After 5 years in office, she resigned as Israeli prime minister in 1974", + "Answer": "Golda Meir" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Not surprisingly, this organization, founded in 1884, maintains one of the world's finest reference libraries on dogs", + "Answer": "the American Kennel Club" + }, + { + "Category": "PROVERBS", + "Question": "It's the type of pot that \"never boils\"", + "Answer": "a watched pot" + }, + { + "Category": "AMERICANA", + "Question": "Lancaster, which has the largest stockyards east of Chicago, was this state's capital from 1799 to 1812", + "Answer": "Pennsylvania" + }, + { + "Category": "SPORTS", + "Question": "In 1992 Viktor Petrenko won the world championship in this sport", + "Answer": "ice skating" + }, + { + "Category": "GRAINS & STAPLES", + "Question": "Millet seed, an important food for North Africans, is most often fed to these pets in the U.S.", + "Answer": "birds" + }, + { + "Category": "HISTORIC WOMEN", + "Question": "The proceeds from some of her souvenir hatchets helped fund a home for wives of alcoholics", + "Answer": "Carrie Nation" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Members of this volunteer crime-fighting organization are famous for wearing red berets", + "Answer": "the Guardian Angels" + }, + { + "Category": "PROVERBS", + "Question": "It \"comes not alone\" & \"makes waste\"", + "Answer": "haste" + }, + { + "Category": "AMERICANA", + "Question": "This Connecticut city famous for its university is nicknamed \"Elm City\" because it once had many elm-lined streets", + "Answer": "New Haven" + }, + { + "Category": "SPORTS", + "Question": "During his 1955-1966 career, this Dodger pitcher averaged 9.28 strikeouts per 9 innings", + "Answer": "Koufax" + }, + { + "Category": "GRAINS & STAPLES", + "Question": "The pot type of this grain retains more of the bran than the pearl type", + "Answer": "barley" + }, + { + "Category": "HISTORIC WOMEN", + "Question": "In 1813 this mistress of the late Lord Nelson was imprisoned for debt", + "Answer": "Lady Hamilton" + }, + { + "Category": "ORGANIZATIONS", + "Question": "During Egypt's suspension from this group, 1979-1989, its headquarters was located in Tunisia", + "Answer": "the Arab League" + }, + { + "Category": "PROVERBS", + "Question": "\"Every\" one of these \"fits not every foot\"", + "Answer": "a shoe" + }, + { + "Category": "GEOGRAPHY", + "Question": "A smaller canal connecting to this river brings fresh water to the Suez Canal", + "Answer": "the Nile" + }, + { + "Category": "AUTHORS", + "Question": "This author of \"The Time Machine\" coined the phrase \"the war that will end war\"", + "Answer": "H.G. Wells" + }, + { + "Category": "1938", + "Question": "On December 10 he announced he'd leave his Hyde Park estate & its papers & books to the U.S. government", + "Answer": "FDR" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "Barbra Streisand introduced the song \"People\" in this musical", + "Answer": "Funny Girl" + }, + { + "Category": "GEOGRAPHY", + "Question": "Many things in Hong Kong are named for this queen, including the mountain peak on Hong Kong island", + "Answer": "Victoria" + }, + { + "Category": "AUTHORS", + "Question": "This author gave us the line \"I'll make him an offer he can't refuse\"", + "Answer": "Puzo" + }, + { + "Category": "1938", + "Question": "By accepting his membership dues, the League of Nations recognized him as emperor of Ethiopia", + "Answer": "Haile Selassie" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "In 1994 Brooke Shields made her Broadway debut as Betty Rizzo in this musical", + "Answer": "Grease" + }, + { + "Category": "GEOGRAPHY", + "Question": "Lake Avernus in Campania in this country was believed by the ancients to be the entrance to Hades", + "Answer": "Italy" + }, + { + "Category": "20th CENTURY DESIGN", + "Question": "The U.S. pavilion at Montreal's Expo 67 was covered by one of these", + "Answer": "a geodesic dome" + }, + { + "Category": "AUTHORS", + "Question": "This \"Return of the Native\" author's first novel, \"Desperate Remedies\", was published in 1871", + "Answer": "Thomas Hardy" + }, + { + "Category": "1938", + "Question": "17 acres surrounding her cottage were transferred to the Shakespeare Birthplace Trust", + "Answer": "Anne Hathaway" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "1992's \"Hello Muddah, Hello Fadduh!\" was inspired by the comic songs of this man", + "Answer": "Allan Sherman" + }, + { + "Category": "MIDDLE INITIAL C.", + "Question": "This father of Andrew Wyeth illustrated more than 20 juvenile classics, including \"Treasure Island\"", + "Answer": "N.C. Wyeth" + }, + { + "Category": "GEOGRAPHY", + "Question": "The western portion of the Baltic island of Usedom belongs to Germany; the eastern, to this country", + "Answer": "Poland" + }, + { + "Category": "20th CENTURY DESIGN", + "Question": "Lighter than steel, this metal is also associated with the modernist style of the '20s & '30s", + "Answer": "aluminum" + }, + { + "Category": "AUTHORS", + "Question": "This Dr. Dolittle creator studied civil engineering at M.I.T.", + "Answer": "Hugh Lofting" + }, + { + "Category": "1938", + "Question": "Returning from Ireland to NYC in August, this aviator was given a parade down…er, up Broadway", + "Answer": "\"Wrong Way\" Corrigan" + }, + { + "Category": "MIDDLE INITIAL C.", + "Question": "Born in South Carolina in 1782, he was known as a \"war hawk\" because he supported the War of 1812", + "Answer": "John C. Calhoun" + }, + { + "Category": "GEOGRAPHY", + "Question": "Boothia Peninsula in this country is the former location of the north magnetic pole", + "Answer": "Canada" + }, + { + "Category": "20th CENTURY DESIGN", + "Question": "The firm of Piano & Rogers is famous for this high-tech Paris landmark built 1971-77", + "Answer": "the Pompidou Centre" + }, + { + "Category": "AUTHORS", + "Question": "1 of only 3 authors to win 2 Pulitzer Prizes for Fiction", + "Answer": "Faulkner, Tarkington & John Updike" + }, + { + "Category": "1938", + "Question": "On April 27, 1938 Countess Geraldine Apponyi of Hungary married King Zog of this country", + "Answer": "Albania" + }, + { + "Category": "MUSICAL THEATRE", + "Question": "\"Cabaret\" was based partly on this 1951 play by John Van Druten", + "Answer": "I Am a Camera" + }, + { + "Category": "MIDDLE INITIAL C.", + "Question": "When the parents of this \"pathfinder\" ran off together, his mother was still legally married to another man", + "Answer": "John C. Fremont" + }, + { + "Category": "NOTORIOUS", + "Question": "Oscar Collazo, serving a life sentence for his assassination attempt on this president, was released in 1979", + "Answer": "Harry Truman" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "In January 1970 Boeing introduced this first wide-bodied jumbo jet; it could seat up to 452 passengers", + "Answer": "747" + }, + { + "Category": "HOW NOVEL", + "Question": "Gregory Maguire's novel \"Confessions of an Ugly Stepsister\" is a revision of this fairy tale", + "Answer": "\"Cinderella\"" + }, + { + "Category": "CLASSIC NICHOLSON MOVIE LINES", + "Question": "1975: \"I must be crazy to be in a looney bin like this\"", + "Answer": "One Flew Over the Cuckoo's Nest" + }, + { + "Category": "\"H\" CITIES", + "Question": "This city's Atomic Bomb Dome, a structure left unrebuilt after WWII, has become a symbol of the peace movement", + "Answer": "Hiroshima" + }, + { + "Category": "HERBS & SPICES", + "Question": "This pizza herb was virtually unknown to Americans until WWII soldiers came home & raved about it", + "Answer": "oregano" + }, + { + "Category": "____ OF THE ____", + "Question": "A Baskin-Robbins program, or an expression meaning \"popular for right now\"", + "Answer": "flavor of the month" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "BUD is the New York Stock Exchange symbol for this brewing company", + "Answer": "Anheuser-Busch" + }, + { + "Category": "HOW NOVEL", + "Question": "He not only appeared on the cover of some 350 romance novels, he's written ones like \"Rogue\" & \"Mysterious\"", + "Answer": "Fabio" + }, + { + "Category": "CLASSIC NICHOLSON MOVIE LINES", + "Question": "1980: \"He-e-e-e-re's Johnny!\"", + "Answer": "The Shining" + }, + { + "Category": "\"H\" CITIES", + "Question": "The racing schooner Bluenose, depicted on Canada's 10-cent coin, has a replica in this Nova Scotian port", + "Answer": "Halifax" + }, + { + "Category": "HERBS & SPICES", + "Question": "A popular soft drink \"ale\" is flavored with this spice whose name is from the Sanskrit for \"horn root\"", + "Answer": "ginger" + }, + { + "Category": "____ OF THE ____", + "Question": "In response to this Irish greeting, you can say, \"And the rest of the day to yourself\"", + "Answer": "top of the morning" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "This Dallas-based electronics firm started out as Geophysical Service, an oil exploration company", + "Answer": "Texas Instruments" + }, + { + "Category": "HOW NOVEL", + "Question": "Agatha Christie mystery in which an heiress is murdered on an Egyptian cruise", + "Answer": "\"Death on the Nile\"" + }, + { + "Category": "CLASSIC NICHOLSON MOVIE LINES", + "Question": "1992: \"You can't handle the truth!\"", + "Answer": "A Few Good Men" + }, + { + "Category": "\"H\" CITIES", + "Question": "Crossed by numerous canals, it's said that this German port has more bridges than Amsterdam & Venice combined", + "Answer": "Hamburg" + }, + { + "Category": "HERBS & SPICES", + "Question": "The dried pods of a certain climbing orchid provide this flavoring", + "Answer": "vanilla" + }, + { + "Category": "____ OF THE ____", + "Question": "Quoting \"Titanic\", in 1998 Oscar-winning James Cameron exulted, \"I'm\" this", + "Answer": "king of the world" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "For over 75 years, Wrigley made only these 3 gums", + "Answer": "Spearmint, Doublemint & Juicy Fruit" + }, + { + "Category": "HOW NOVEL", + "Question": "Title that completes the line \"Shoot all the bluejays you want, if you can hit 'em, but remember it's a sin...\"", + "Answer": "\"To Kill A Mockingbird\"" + }, + { + "Category": "CLASSIC NICHOLSON MOVIE LINES", + "Question": "1974: \"What makes you certain that your husband is, um, involved with someone?\"", + "Answer": "Chinatown" + }, + { + "Category": "\"H\" CITIES", + "Question": "This capital was founded by Sweden's King Gustav I Vasa in 1550", + "Answer": "Helsinki, Finland" + }, + { + "Category": "HERBS & SPICES", + "Question": "In medieval Europe this poultry stuffing herb of the genus Salvia was thought to stimulate the mind", + "Answer": "sage" + }, + { + "Category": "____ OF THE ____", + "Question": "To make a favorable judgment when you're uncertain is to give someone this", + "Answer": "benefit of the doubt" + }, + { + "Category": "BUSINESS & INDUSTRY", + "Question": "In 1973 this then Memphis-based hotel chain opened its own university in Mississippi to train personnel", + "Answer": "Holiday Inn" + }, + { + "Category": "HOW NOVEL", + "Question": "This Ayn Rand novel tells the story of architect Howard Roark & Dominique Francon, the woman he loves", + "Answer": "\"The Fountainhead\"" + }, + { + "Category": "CLASSIC NICHOLSON MOVIE LINES", + "Question": "1994: \"Just marking my territory\"", + "Answer": "Wolf" + }, + { + "Category": "\"H\" CITIES", + "Question": "It served as a dynastic capital in the 1800s & continued as the royal capital of Vietnam until 1945", + "Answer": "Hue" + }, + { + "Category": "HERBS & SPICES", + "Question": "This spice that is sold in 2 varieties, Ceylon & Cassia, was once used in love potions", + "Answer": "cinnamon" + }, + { + "Category": "____ OF THE ____", + "Question": "In 1961 British critic Martin Esslin used this phrase to describe the plays of Beckett & Ionesco", + "Answer": "theatre of the absurd" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "The Einheriar were the dead warriors the Valkyries picked up & brought back to this hall where they were revived", + "Answer": "Valhalla" + }, + { + "Category": "AGRICULTURE", + "Question": "In 1981 the U.S. government, with 560 million lbs. of this dairy food in storage, released 30 million lbs. to the needy", + "Answer": "cheese" + }, + { + "Category": "18th CENTURY AMERICANS", + "Question": "In 1775 he & a group of axmen cleared & marked the Wilderness Road for the Transylvania Company", + "Answer": "Daniel Boone" + }, + { + "Category": "MATH TERMS", + "Question": "5th, 50th & 500th are this type of number, as opposed to cardinal", + "Answer": "ordinal" + }, + { + "Category": "\"P.B.\"", + "Question": "In New Orleans a hero sandwich is called this", + "Answer": "po boy" + }, + { + "Category": "JAY", + "Question": "He drafted the constitution of New York state & was appointed chief justice of the state in 1777", + "Answer": "John Jay" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "Roskva, the farmer's daughter, was always under the hammer as a personal assistant to this god", + "Answer": "Thor" + }, + { + "Category": "AGRICULTURE", + "Question": "Generally, a steer is a castrated bull used for food; this shorter word refers to one used as a draft animal", + "Answer": "ox" + }, + { + "Category": "18th CENTURY AMERICANS", + "Question": "In the 1770s, this pamphleteer wrote \"African Slavery in America\", an article condemning slavery", + "Answer": "Thomas Paine" + }, + { + "Category": "MATH TERMS", + "Question": "A theorem includes this series of steps, starting with a given & ending with a justified conclusion", + "Answer": "proof" + }, + { + "Category": "\"P.B.\"", + "Question": "It's the state flower of Delaware (not Georgia)", + "Answer": "peach blossom" + }, + { + "Category": "JAY", + "Question": "He's the \"Picture Perfect\" actor seen here", + "Answer": "Jay Mohr" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "A never-ending supply of this better-than-beer drink was made by Heidrum, oddly a goat, not a bee", + "Answer": "mead" + }, + { + "Category": "AGRICULTURE", + "Question": "Spain, Italy & Greece are the leading producers of this liquid from the fruit of Olea europaea", + "Answer": "olive oil" + }, + { + "Category": "18th CENTURY AMERICANS", + "Question": "In \"The Federalist\" No. 51, this future president put forth an argument for the separation of powers", + "Answer": "James Madison" + }, + { + "Category": "MATH TERMS", + "Question": "(Cheryl of the Clue Crew standing in front of a chalkboard) From the Latin for \"to turn upside down\", the function g is described as this of the function f", + "Answer": "inverse" + }, + { + "Category": "\"P.B.\"", + "Question": "You can use this utensil to apply a glaze to breads & sweets before or after baking", + "Answer": "pastry brush" + }, + { + "Category": "JAY", + "Question": "It's the magical group heard here [\"This Magic Moment\"]", + "Answer": "Jay and the Americans" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "Odin learned the secrets of these alphabetic symbols while hanging for 9 days on Yggdrasil, the world tree", + "Answer": "runes" + }, + { + "Category": "AGRICULTURE", + "Question": "The type of irrigation seen here, it was used in Israel to make the desert bloom", + "Answer": "drip irrigation" + }, + { + "Category": "18th CENTURY AMERICANS", + "Question": "This Pennsylvanian's son William served as royal governor of New Jersey & remained loyal to the crown", + "Answer": "Ben Franklin" + }, + { + "Category": "MATH TERMS", + "Question": "The term surd refers to irrational numbers like this number's square root, 1.7320508...", + "Answer": "3" + }, + { + "Category": "\"P.B.\"", + "Question": "Anna Pavlova or Dame Margot Fonteyn, for example", + "Answer": "prima ballerina" + }, + { + "Category": "JAY", + "Question": "This child actor played Dennis the Menace on TV in the early '60s", + "Answer": "Jay North" + }, + { + "Category": "NORSE MYTHOLOGY", + "Question": "Norse myth is big on trees; the first man & woman -- Ask & Embla -- were created out of these 2 species", + "Answer": "ash & elm" + }, + { + "Category": "AGRICULTURE", + "Question": "What do you do to wheat to get flour? The answer is the name of this grain", + "Answer": "millet" + }, + { + "Category": "18th CENTURY AMERICANS", + "Question": "Mary Hays received this pseudonym for aiding her husband & other soldiers during the Battle of Monmouth", + "Answer": "Molly Pitcher" + }, + { + "Category": "MATH TERMS", + "Question": "A function's domain is the set of possible values of x; this is the set of possible values of y", + "Answer": "range" + }, + { + "Category": "\"P.B.\"", + "Question": "This Latin term used for some legal services means \"for the good\"", + "Answer": "pro bono" + }, + { + "Category": "JAY", + "Question": "Born on the Six Nations Indian Reservation in Ontario, he played Tonto to Clayton Moore's Lone Ranger", + "Answer": "Jay Silverheels" + }, + { + "Category": "AUTHORS", + "Question": "In September 1941 this author christened the warship Atlanta, also known as \"The Mighty A\"", + "Answer": "Margaret Mitchell" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Dating back at least 100 years, \"drowning the shamrock\", or going drinking, is a tradition on this holiday", + "Answer": "St. Patrick's Day" + }, + { + "Category": "SCIENTIFIC AMERICAN", + "Question": "In 1998 the magazine told of efforts to liquify this \"cleanest of fossil fuels\" for use in cars", + "Answer": "natural gas" + }, + { + "Category": "CLASSIC DISNEY FILMS", + "Question": "This film about a flying elephant inspired a ride at Disneyland", + "Answer": "Dumbo" + }, + { + "Category": "NAME THE SHAKESPEARE PLAY", + "Question": "\"Friends, Romans, countrymen, lend me your ears\"", + "Answer": "Julius Caesar" + }, + { + "Category": "MILITARY UNITS", + "Question": "Oliver Stone won an Oscar for his story about one of these title units in which he served in Vietnam", + "Answer": "a platoon" + }, + { + "Category": "THAT OLD \"BLACK\" MAGIC", + "Question": "It's the casino game in which you'd hear someone say \"Hit me\"", + "Answer": "blackjack" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Secretary of State William H. Seward is honored on the last Monday in March in this state", + "Answer": "Alaska" + }, + { + "Category": "SCIENTIFIC AMERICAN", + "Question": "SA's website's \"Ask the Experts\" column answers key questions like \"Why does bruised fruit turn\" this color", + "Answer": "brown" + }, + { + "Category": "CLASSIC DISNEY FILMS", + "Question": "Chim-Chim Cheree! This film featuring chimney sweeps swept up 13 Oscar nominations", + "Answer": "Mary Poppins" + }, + { + "Category": "NAME THE SHAKESPEARE PLAY", + "Question": "\"Good-night, good-night! Parting is such sweet sorrow that I shall say good-night till it be morrow\"", + "Answer": "Romeo and Juliet" + }, + { + "Category": "MILITARY UNITS", + "Question": "From the medieval Latin for \"army\", it's a large fleet like the one Admiral Howard faced in 1588", + "Answer": "an armada" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "Called the greatest 2 minutes in sports, it takes place on the first Saturday in May", + "Answer": "the Kentucky Derby" + }, + { + "Category": "SCIENTIFIC AMERICAN", + "Question": "Magazine contributor Steven Chu won a Nobel Prize for slowing atoms with these light beams", + "Answer": "lasers" + }, + { + "Category": "CLASSIC DISNEY FILMS", + "Question": "This 1961 film was the first to feature a magical substance called Flubber", + "Answer": "The Absent-Minded Professor" + }, + { + "Category": "NAME THE SHAKESPEARE PLAY", + "Question": "\"Eye of newt and toe of frog, wool of bat and tongue of dog\"", + "Answer": "Macbeth" + }, + { + "Category": "MILITARY UNITS", + "Question": "3 brigades under 1 headquarters, or a math function", + "Answer": "a division" + }, + { + "Category": "THAT OLD \"BLACK\" MAGIC", + "Question": "The Green Hornet's car, or Anna Sewell's horse", + "Answer": "Black Beauty" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "An ancient symbol of abundance, the cornucopia is often attached to this American holiday", + "Answer": "Thanksgiving" + }, + { + "Category": "SCIENTIFIC AMERICAN", + "Question": "A steamy 1998 issue reports on sexual attraction in the orange sulphur species of this colorful insect", + "Answer": "butterflies" + }, + { + "Category": "CLASSIC DISNEY FILMS", + "Question": "Much of the music for this 1959 film, including the song \"Once Upon A Dream\" was adapted from an 1890 ballet", + "Answer": "Sleeping Beauty" + }, + { + "Category": "NAME THE SHAKESPEARE PLAY", + "Question": "\"Neither a borrower nor a lender be\"", + "Answer": "Hamlet" + }, + { + "Category": "MILITARY UNITS", + "Question": "A group of cavalry, whether A, B, or \"F\"", + "Answer": "a troop" + }, + { + "Category": "THAT OLD \"BLACK\" MAGIC", + "Question": "Early in his career, Burt Reynolds played Quint Asper, one of these on \"Gunsmoke\"", + "Answer": "Blacksmith" + }, + { + "Category": "ANNUAL EVENTS", + "Question": "This city's Mississippi River Art Fair is held in the Mark Twain Historic District", + "Answer": "Hannibal, Missouri" + }, + { + "Category": "SCIENTIFIC AMERICAN", + "Question": "To physicists, SOHO isn't a neighborhood but an observatory orbiting this body", + "Answer": "the sun" + }, + { + "Category": "CLASSIC DISNEY FILMS", + "Question": "Among the babes in \"Babes in Toyland\" are Ann Jillian as Bo Peep & this Mouseketeer as Mary Contrary", + "Answer": "Annette Funicello" + }, + { + "Category": "NAME THE SHAKESPEARE PLAY", + "Question": "\"The quality of mercy is not strained, it droppeth as the gentle rain from heaven upon the place beneath\"", + "Answer": "The Merchant of Venice" + }, + { + "Category": "MILITARY UNITS", + "Question": "Mod or not, it's usually 10 infantrymen headed by a staff sergeant", + "Answer": "a squad" + }, + { + "Category": "THAT OLD \"BLACK\" MAGIC", + "Question": "Yo-ho, yo-ho! His real name was believed to be Edward Teach", + "Answer": "Blackbeard" + }, + { + "Category": "LET'S VISIT AUSTRIA", + "Question": "Preferring to go where the rain turns to snow, he wintered in Schruns while writing \"The Sun Also Rises\"", + "Answer": "Ernest Hemingway" + }, + { + "Category": "CREATION STORIES", + "Question": "Scholars link Egyptian creation myths to the sun apparently fertilizing this river's slime", + "Answer": "the Nile" + }, + { + "Category": "TURNING 40 IN '98", + "Question": "This pitcher's \"Orel\" history continued in '98 with a new team, the Giants", + "Answer": "Orel Hershiser" + }, + { + "Category": "HERBS & SPICES", + "Question": "Though derived from the same plant as opium, these seeds are non-narcotic", + "Answer": "poppyseeds" + }, + { + "Category": "PIANO KEYS", + "Question": "It's the only letter in \"piano\" that corresponds to a piano key", + "Answer": "A" + }, + { + "Category": "SPOOKS", + "Question": "This spy came a long way from her origins as the daughter of a Dutch hatter", + "Answer": "Mata Hari" + }, + { + "Category": "LET'S VISIT AUSTRIA", + "Question": "Capital of Tyrol, it has hosted 2 Winter Olympics", + "Answer": "Innsbruck" + }, + { + "Category": "CREATION STORIES", + "Question": "According to the King James Version, God's first words quoted in the book of Genesis", + "Answer": "\"Let there be light\"" + }, + { + "Category": "TURNING 40 IN '98", + "Question": "In 1998 she turned 40 & played a 40-year-old in \"How Stella Got Her Groove Back\"", + "Answer": "Angela Bassett" + }, + { + "Category": "HERBS & SPICES", + "Question": "The scientific name of this herb is Mentha piperita", + "Answer": "peppermint" + }, + { + "Category": "PIANO KEYS", + "Question": "Of the 2 types of piano keys in a Paul McCartney-Stevie Wonder hit, it's what G-flat is", + "Answer": "ebony" + }, + { + "Category": "SPOOKS", + "Question": "Teddy Roosevelt's grandson, CIA man Kermit, kept the Shah of this country on his throne in 1953", + "Answer": "Iran" + }, + { + "Category": "LET'S VISIT AUSTRIA", + "Question": "This English king was held prisoner in 1193 in a castle above Durnstein, Austria", + "Answer": "Richard the Lionhearted" + }, + { + "Category": "CREATION STORIES", + "Question": "In some Native American myths, this animal helps a deity create the world, with no help from the Acme Co.", + "Answer": "a coyote" + }, + { + "Category": "HERBS & SPICES", + "Question": "This aromatic leaf, used to flavor meat, soups & stews, comes from a laurel tree", + "Answer": "a bay leaf" + }, + { + "Category": "PIANO KEYS", + "Question": "A 6-string guitar has 2 strings tuned to this note, each corresponding to a piano key", + "Answer": "E" + }, + { + "Category": "SPOOKS", + "Question": "Cuban refugee Antonio Prohias drew this MAD Magazine comic strip for 29 years", + "Answer": "Spy vs. Spy" + }, + { + "Category": "CREATION STORIES", + "Question": "Africa's Fulani people, who are cattle herders, say everything came from a drop of this", + "Answer": "milk" + }, + { + "Category": "TURNING 40 IN '98", + "Question": "A short called \"Frankenweenie\" helped launch the career of this \"Edward Scissorhands\" director", + "Answer": "Tim Burton" + }, + { + "Category": "HERBS & SPICES", + "Question": "During the Middle Ages, merchants who adulterated this expensive yellow spice were burnt at the stake", + "Answer": "saffron" + }, + { + "Category": "PIANO KEYS", + "Question": "They're adjacent on the keyboard as well as in an abbreviation for a popular format of recorded music", + "Answer": "C & D" + }, + { + "Category": "SPOOKS", + "Question": "Spy Richard Sorge warned this Russian leader of Germany's WWII invasion but was ignored", + "Answer": "Josef Stalin" + }, + { + "Category": "CREATION STORIES", + "Question": "To the ancient Greeks, it was a void from which Nyx & Erebus emerged; in English it's a disordered mess", + "Answer": "chaos" + }, + { + "Category": "TURNING 40 IN '98", + "Question": "Damon, Marlon & Kim's big brother, he turned 40 on June 8", + "Answer": "Keenan Ivory Wayans" + }, + { + "Category": "HERBS & SPICES", + "Question": "Referring to their shape, these fragrant buds take their name from the Latin word for \"nail\"", + "Answer": "cloves" + }, + { + "Category": "PIANO KEYS", + "Question": "It's the key the French call \"Le do du milieu du piano\"", + "Answer": "middle C" + }, + { + "Category": "SPOOKS", + "Question": "In the early '70s East German spy Gunter Guillaume infiltrated the office of this West German chancellor", + "Answer": "Willy Brandt" + }, + { + "Category": "BEFORE THEY WERE FIRST LADIES", + "Question": "Her daughter Julie says this future first lady was offered a movie contract in the 1930s when she was a USC student", + "Answer": "Mrs. Nixon" + }, + { + "Category": "PRIMETIME TV REUNIONS", + "Question": "1983: \"Still the Beaver\"", + "Answer": "Leave it to Beaver" + }, + { + "Category": "MYSPACE.MAN", + "Question": "He became a licensed pilot on his 16th birthday long before his one small step on the Sea on Tranquility", + "Answer": "Armstrong" + }, + { + "Category": "POET'S GLOSSARY", + "Question": "Japanese style / Always syllable counting / This type of poem", + "Answer": "haiku" + }, + { + "Category": "CONTAINERS", + "Question": "A sink, or the area drained by a single river system", + "Answer": "a basin" + }, + { + "Category": "FROM THE GREEK", + "Question": "This synonym for \"drugstore\" comes from the Greek for \"druggist's work\"", + "Answer": "pharmacy" + }, + { + "Category": "PRIMETIME TV REUNIONS", + "Question": "2000: \"Mary and Rhoda\"", + "Answer": "The Mary Tyler Moore Show" + }, + { + "Category": "MYSPACE.MAN", + "Question": "He elected to join the Mercury program in 1959; 15 years later, he'd be elected to join the Senate", + "Answer": "Glenn" + }, + { + "Category": "CONTAINERS", + "Question": "Port wines are separated into 2 types based on these 2 possible places where they do most of their aging", + "Answer": "barrels & bottles" + }, + { + "Category": "FROM THE GREEK", + "Question": "The name of this solid figure used to disperse light into a spectrum is from the Greek for \"something sawed\"", + "Answer": "a prism" + }, + { + "Category": "BEFORE THEY WERE FIRST LADIES", + "Question": "As a young wife in the 1950s, she managed the accounts for the family agricultural business", + "Answer": "Mrs. Carter" + }, + { + "Category": "PRIMETIME TV REUNIONS", + "Question": "2004: \"Return to Southfork\"", + "Answer": "Dallas" + }, + { + "Category": "MYSPACE.MAN", + "Question": "On April 12, 1961, he took his 5 1/4-ton Vostok 1 for a spin at 9:07 A.M. Moscow time; he had it back by 10:55", + "Answer": "Gagarin" + }, + { + "Category": "POET'S GLOSSARY", + "Question": "This basic metrical unit of poetry sounds like a body part", + "Answer": "a foot" + }, + { + "Category": "CONTAINERS", + "Question": "\"Amorous\" name of a 2-handled wine vessel or sporting trophy", + "Answer": "loving cup" + }, + { + "Category": "FROM THE GREEK", + "Question": "When food is swallowed, it goes down this tube, the Greek word for \"gullet\"", + "Answer": "the esophagus" + }, + { + "Category": "BEFORE THEY WERE FIRST LADIES", + "Question": "Bloomer was the maiden name of this first lady who blossomed as a fashion model in pre-WWII NYC", + "Answer": "Betty Ford" + }, + { + "Category": "PRIMETIME TV REUNIONS", + "Question": "1987: \"Return to Dodge\"", + "Answer": "Gunsmoke" + }, + { + "Category": "MYSPACE.MAN", + "Question": "With the return of Apollo 13, this commander had completed over 715 hours of space travel", + "Answer": "Lovell" + }, + { + "Category": "POET'S GLOSSARY", + "Question": "The \"heroic\" variety of this pair of rhyming lines is written in iambic pentameter", + "Answer": "a couplet" + }, + { + "Category": "CONTAINERS", + "Question": "The American Heritage Dict.'s 1st pronunciation for this word rhymes it with \"lace\"; another with, with \"bras\"", + "Answer": "vase" + }, + { + "Category": "FROM THE GREEK", + "Question": "From the Greek for \"primary\", these are made of amino acids", + "Answer": "proteins" + }, + { + "Category": "BEFORE THEY WERE FIRST LADIES", + "Question": "She was president (Natl. Pres. of the Girl Scouts, that is) in the 1920s while her husband was merely Secy. of Commerce", + "Answer": "Hoover" + }, + { + "Category": "PRIMETIME TV REUNIONS", + "Question": "1997: \"Back to the Cul-de-sac\"", + "Answer": "Knots Landing" + }, + { + "Category": "MYSPACE.MAN", + "Question": "Freedom 7's pilot in 1961, he also commanded Apollo 14, the 1st mission to land on the Moon & not on the lunar seas", + "Answer": "Shepard" + }, + { + "Category": "POET'S GLOSSARY", + "Question": "From the Latin for \"stopping place\", it's 2 or more lines of poetry that form a division within a poem", + "Answer": "a stanza" + }, + { + "Category": "CONTAINERS", + "Question": "It's what's normally carried in a metal pail called a scuttle", + "Answer": "coal" + }, + { + "Category": "& NOW THE \"END\" IS NEAR", + "Question": "Poe knows this swinging lever regulates the speed of a clock mechanism", + "Answer": "pendulum" + }, + { + "Category": "& SO I FACE THE FINAL CURTAIN", + "Question": "This musical dreamed \"The Impossible Dream\", playing 2,328 performances before closing in 1971", + "Answer": "Man of La Mancha" + }, + { + "Category": "I BIT OFF MORE THAN I COULD CHEW", + "Question": "Richard Lefevre could eat only 1 1/2 gallons of this \"bowl of red\" Stagg product in 10 minutes", + "Answer": "chili" + }, + { + "Category": "I'VE TRAVELED EACH & EVERY HIGHWAY", + "Question": "This highway that Bob Dylan \"Revisited\" begins in Thunder Bay, Ontario", + "Answer": "Highway 61" + }, + { + "Category": "THE RECORD SHOWS I TOOK THE BLOWS", + "Question": "Before becoming a world leader, this Frenchman was wounded 3 times in WWI & was captured at Verdun in 1916", + "Answer": "de Gaulle" + }, + { + "Category": "I DID IT NORWAY", + "Question": "On the scenic Lofoten Islands, you can stay in Rorbuer, cottages traditionally used by those in this profession", + "Answer": "fishing" + }, + { + "Category": "& NOW THE \"END\" IS NEAR", + "Question": "The opposite of diminuendo is this music term, a gradual increase in loudness", + "Answer": "crescendo" + }, + { + "Category": "& SO I FACE THE FINAL CURTAIN", + "Question": "This musical about 18 dancers trying out for 8 spots in a Broadway show ended its original 15-year Broadway run in April 1990", + "Answer": "A Chorus Line" + }, + { + "Category": "I BIT OFF MORE THAN I COULD CHEW", + "Question": "Oleg Zhornitskiy turned this sandwich spread into a meal by gulping down 4 32-ounce bowls in 8 minutes", + "Answer": "mayonnaise" + }, + { + "Category": "THE RECORD SHOWS I TOOK THE BLOWS", + "Question": "This ex-NATO commander & presidential candidate was wounded in Vietnam", + "Answer": "Clark" + }, + { + "Category": "I DID IT NORWAY", + "Question": "The city of Alta, well above the Arctic Circle, has renamed itself the Nordlysbyen Alta, after this display", + "Answer": "the northern lights" + }, + { + "Category": "& NOW THE \"END\" IS NEAR", + "Question": "This type of gland secretes substances directly into the bloodstream", + "Answer": "endocrine" + }, + { + "Category": "& SO I FACE THE FINAL CURTAIN", + "Question": "This Lerner & Loewe musical had its \"loverly\" farewell in 1962, after 2,717 shows", + "Answer": "My Fair Lady" + }, + { + "Category": "I BIT OFF MORE THAN I COULD CHEW", + "Question": "Cookie Jarvis gave 10 minutes of lip service to 6 2/3 pounds of this pasta, from the Italian for \"tongue\"", + "Answer": "linguini" + }, + { + "Category": "I'VE TRAVELED EACH & EVERY HIGHWAY", + "Question": "Part of U.S. 40 follows the route of this early 19th century road that began in Maryland", + "Answer": "the Cumberland Road" + }, + { + "Category": "THE RECORD SHOWS I TOOK THE BLOWS", + "Question": "In 1775 his leg was severely wounded in an assault on Quebec & he was promoted to brig. gen.; 5 years later, he'd be in disgrace", + "Answer": "Benedict Arnold" + }, + { + "Category": "I DID IT NORWAY", + "Question": "Winter sports lovers benefit from the 2-billion-kroner upgrade of this 1994 Olympic city", + "Answer": "Lillehammer" + }, + { + "Category": "& NOW THE \"END\" IS NEAR", + "Question": "If I said a clue about a stripper had really nice pair of facts, it'd be an example of this 2-word French term", + "Answer": "a double entendre" + }, + { + "Category": "& SO I FACE THE FINAL CURTAIN", + "Question": "With more than 7,400 performances, this musical became a \"Memory\" after its Sept. 10, 2000 finale", + "Answer": "Cats" + }, + { + "Category": "I BIT OFF MORE THAN I COULD CHEW", + "Question": "In 9 minutes, Sonya Thomas dined on 11 pounds of this cheesy dessert from a Brooklyn restaurant", + "Answer": "cheesecake" + }, + { + "Category": "I'VE TRAVELED EACH & EVERY HIGHWAY", + "Question": "The 42 bridges of the Overseas Highway link many of this state's islands to the mainland", + "Answer": "Florida" + }, + { + "Category": "I DID IT NORWAY", + "Question": "Norwegian poet Arne Garborg pushed for a literary language based on this \"old\" one of sagas & eddas", + "Answer": "Old Norse" + }, + { + "Category": "& NOW THE \"END\" IS NEAR", + "Question": "Shakespeare's Puck: If we have\" done this, \"think but this, and all is mended\"", + "Answer": "offended" + }, + { + "Category": "& SO I FACE THE FINAL CURTAIN", + "Question": "It was nice to see this musical \"Looking Swell\" & \"Still Goin' Strong\", but after 2,844 shows, it bowed out in 1970", + "Answer": "Hello, Dolly!" + }, + { + "Category": "I BIT OFF MORE THAN I COULD CHEW", + "Question": "Jim Reeves was top-\"seeded\" after he chomped 13 pounds of this gourd in 15 minutes", + "Answer": "watermelon" + }, + { + "Category": "I'VE TRAVELED EACH & EVERY HIGHWAY", + "Question": "Domine Quo Vadis Church stands on this road, where tradition says Peter asked Jesus, \"Lord, where are you going?\"", + "Answer": "the Appian Way" + }, + { + "Category": "I DID IT NORWAY", + "Question": "A summer festival at Vinstra honors this Ibsen & Grieg character based on folklore", + "Answer": "Peer Gynt" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "He first appeared in Kipling's 1892 story \"In the Rukh\" as an adult who now & then refers to his very odd childhood", + "Answer": "Mowgli" + }, + { + "Category": "DOUGH", + "Question": "Chile uses this basic unit of currency", + "Answer": "a peso" + }, + { + "Category": "CHEESE", + "Question": "Christopher Lee, later of \"Lord of the Rings\", sucked blood in 1968's he \"Has Risen from the Grave\"", + "Answer": "Dracula" + }, + { + "Category": "THE UPPER CRUST", + "Question": "Athina Roussel, granddaughter of this Greek tycoon, inherited billions when she turned 18 in 2003", + "Answer": "Onassis" + }, + { + "Category": "\"DEEP\" DISH", + "Question": "You can cook the Thanksgiving turkey this way so the outside is crispy & the inside juicy (just beware of splattered oil)", + "Answer": "deep fry" + }, + { + "Category": "WE WANT PISA!", + "Question": "The Italian city of Pisa is located at the mouth of the Arno River, where it flows into this body of water", + "Answer": "the Mediterranean Sea" + }, + { + "Category": "FLOWER", + "Question": "Seeing the English Gardens at Mottisfont Abbey made Martha Stewart laugh at her own efforts to grow these", + "Answer": "roses" + }, + { + "Category": "DOUGH", + "Question": "No peeking! This building is portrayed on the back of the $20 bill", + "Answer": "the White House" + }, + { + "Category": "CHEESE", + "Question": "Sonny Chiba, star of such memorable films as \"The Bushido Blade\", appeared in \"Volume One\" of this Tarantino epic", + "Answer": "Kill Bill" + }, + { + "Category": "\"DEEP\" DISH", + "Question": "This region of the U.S. includes Mississippi & Alabama", + "Answer": "the Deep South" + }, + { + "Category": "WE WANT PISA!", + "Question": "In Italian it's known as \"La Torre Pendente\"", + "Answer": "the Leaning Tower" + }, + { + "Category": "DOUGH", + "Question": "Italy has issued Euro coins with part of this painter's \"Birth of Venus\" on the reverse", + "Answer": "Botticelli" + }, + { + "Category": "CHEESE", + "Question": "\"To Kiss in Shadows\" & \"Stealing Heaven\" won 2003 Rita Awards for this type of novel", + "Answer": "romance" + }, + { + "Category": "THE UPPER CRUST", + "Question": "Ulysses Grant's granddaughter Julia married a prince from this country & had to flee its revolution in 1917", + "Answer": "Russia" + }, + { + "Category": "WE WANT PISA!", + "Question": "At the head of his own militia, this medieval author of \"The Prince\" helped conquer Pisa for Florence in 1509", + "Answer": "Machiavelli" + }, + { + "Category": "FLOWER", + "Question": "Bergamot is also called the \"balm\" of these creatures to which it's highly attractive", + "Answer": "bees" + }, + { + "Category": "DOUGH", + "Question": "Cherry blossoms are featured on the back of the coin worth 100 of these", + "Answer": "Yen" + }, + { + "Category": "CHEESE", + "Question": "This 2004 Fox show featured the line \"I'm going to Waikiki to get a bikini wax... want to meet me after your shift's over?\"", + "Answer": "North Shore" + }, + { + "Category": "THE UPPER CRUST", + "Question": "Oralando Montagu is making a lot of \"bread\" selling this lunch item (he's descended from the Earl who invented it)", + "Answer": "a sandwich" + }, + { + "Category": "\"DEEP\" DISH", + "Question": "Oprah's first selection for her book club, in 1996, was this book by Jacquelyn Mitchard about a kidnapping", + "Answer": "The Deep End of the Ocean" + }, + { + "Category": "WE WANT PISA!", + "Question": "Born in Pisa in the 16th century, he studied the laws of falling bodies & the motions of projectiles", + "Answer": "Galileo" + }, + { + "Category": "FLOWER", + "Question": "A 1971 New Jersey law made the common meadow type of this, not the African type, the state flower", + "Answer": "a violet" + }, + { + "Category": "DOUGH", + "Question": "The name of this unit of currency used in Libya is from the Latin for \"ten\"", + "Answer": "Dinar" + }, + { + "Category": "CHEESE", + "Question": "A song from \"Dirty Dancing\" says, \"Now I've had\" this; \"Yes, I swear it's the truth and I owe it all to you\"", + "Answer": "\"The Time Of My Life\"" + }, + { + "Category": "\"DEEP\" DISH", + "Question": "People on bed rest are at risk for a serious blood clot in the legs known as DVT, short for this", + "Answer": "deep vein thrombosis" + }, + { + "Category": "WE WANT PISA!", + "Question": "This island off the Italian coast where Napoleon was first exiled was controlled for many years by Pisa", + "Answer": "Elba" + }, + { + "Category": "THE 20th CENTURY", + "Question": "On Feb. 11, 1993 this Florida prosecutor was nominated Attorney General of the U.S.", + "Answer": "Janet Reno" + }, + { + "Category": "ALBUMS", + "Question": "In 1997 Celine Dion's \"My Heart Will Go On\" appeared on her album \"Let's Talk About Love\" & on this soundtrack", + "Answer": "Titanic" + }, + { + "Category": "FOREIGN TRAVEL", + "Question": "In estimating the time to recover from this, figure one day for every hour of the time change", + "Answer": "jet lag" + }, + { + "Category": "THEIR ALMA MATERS", + "Question": "Sir Isaac Newton", + "Answer": "Cambridge" + }, + { + "Category": "HOUSES OF WORSHIP", + "Question": "The last British sovereign buried at this church was George II in 1760; since then, they've been buried at Windsor", + "Answer": "Westminster Abbey" + }, + { + "Category": "COMPUTER JARGON", + "Question": "P2P means this type of file sharing, like Kazaa or Limewire", + "Answer": "peer-to-peer" + }, + { + "Category": "THE 20th CENTURY", + "Question": "In 1940, at age 5, Tenzin Gyatso was enthroned as the 14th one of these spiritual leaders", + "Answer": "Dalai Lama" + }, + { + "Category": "ALBUMS", + "Question": "'N Sync's \"No Strings Attached\" was the No. 1 album of 2000; this Santana album was No. 2", + "Answer": "Supernatural" + }, + { + "Category": "FOREIGN TRAVEL", + "Question": "Though its slangy name suggests it goes behind, wear this in front to guard your valuables against theft", + "Answer": "a fanny pack" + }, + { + "Category": "THEIR ALMA MATERS", + "Question": "JFK (John Fitzgerald Kennedy)", + "Answer": "Harvard" + }, + { + "Category": "HOUSES OF WORSHIP", + "Question": "The world's largest mosque is Shah Faisal Mosque near this Pakistani capital; it can hold 100,000 worshippers", + "Answer": "Islamabad" + }, + { + "Category": "COMPUTER JARGON", + "Question": "\"Treeware\" is this; it comes with software programs", + "Answer": "an instruction manual" + }, + { + "Category": "THE 20th CENTURY", + "Question": "This term, German for \"lightning war,\" was used to describe the rapid capture of Poland by Germany in 1939", + "Answer": "blitzkrieg" + }, + { + "Category": "ALBUMS", + "Question": "\"The Diary of\" this songstress included \"Diary\", a haunting duet with Tony! Toni! Tone!", + "Answer": "Alicia Keys" + }, + { + "Category": "FOREIGN TRAVEL", + "Question": "Jamaica's Rock House Hotel advertises four-poster beds with this protective material over them", + "Answer": "a mosquito net" + }, + { + "Category": "THEIR ALMA MATERS", + "Question": "JFK (John Forbes Kerry)", + "Answer": "Yale" + }, + { + "Category": "HOUSES OF WORSHIP", + "Question": "The Episcopal Church at 193 Salem Street in Boston has been holding services continually since December 29, 1723", + "Answer": "The Old North Church" + }, + { + "Category": "COMPUTER JARGON", + "Question": "Common fiery name for a nasty or insulting email or newsgroup message", + "Answer": "a flame" + }, + { + "Category": "THE 20th CENTURY", + "Question": "On Feb. 20, 1962 the destroyer USS Noa found him floating in the Atlantic after a journey of 75,679 miles", + "Answer": "John Glenn" + }, + { + "Category": "ALBUMS", + "Question": "Their 1999 CD \"Californication\" reunited guitarist John Frusciante with the group", + "Answer": "The Red Hot Chili Peppers" + }, + { + "Category": "FOREIGN TRAVEL", + "Question": "In part to prevent child abductions, the State Dept. now requires that minors appear in person to get this", + "Answer": "a passport" + }, + { + "Category": "THEIR ALMA MATERS", + "Question": "Radio's Garrison Keillor", + "Answer": "The University of Minnesota" + }, + { + "Category": "HOUSES OF WORSHIP", + "Question": "The seat of New York's Roman Catholic Archdiocese, it's a great example of Gothic Revival architecture", + "Answer": "St. Patrick's Cathedral" + }, + { + "Category": "COMPUTER JARGON", + "Question": "\"Egosurfing\" means searching the net for this", + "Answer": "your own name" + }, + { + "Category": "THE 20th CENTURY", + "Question": "In 1974 the military overthrew this African leader who claimed to be descended from Solomon & the Queen of Sheba", + "Answer": "Haile Selassie" + }, + { + "Category": "ALBUMS", + "Question": "\"All I Have\" with LL Cool J was a last-minute addition to this Jennifer Lopez CD", + "Answer": "This Is Me... Then" + }, + { + "Category": "FOREIGN TRAVEL", + "Question": "On entering the U.K., if you have anything to declare (besides \"They talk funny here\"), see one of these officers", + "Answer": "customs" + }, + { + "Category": "THEIR ALMA MATERS", + "Question": "Author Ralph Ellison", + "Answer": "Tuskegee" + }, + { + "Category": "HOUSES OF WORSHIP", + "Question": "The Church of this in Jerusalem is said to be built over the site where Jesus was entombed after his crucifixion", + "Answer": "Holy Sepulchre" + }, + { + "Category": "COMPUTER JARGON", + "Question": "\"VoIP\" means this type of \"Internet protocol\" to make phone calls over the web", + "Answer": "voice" + }, + { + "Category": "BRITISH NOVEL CHARACTERS", + "Question": "W.E. Henley, the amputee who wrote the brave poem \"Invictus\", inspired this character in an 1883 book", + "Answer": "Long John Silver" + }, + { + "Category": "MEN OF MUSIC", + "Question": "100,000 people of this city turned out for the 1849 funeral of beloved bandleader Johann Strauss Sr.", + "Answer": "Vienna" + }, + { + "Category": "BIOPIC-NIC", + "Question": "1970 George C. Scott as this general", + "Answer": "Patton" + }, + { + "Category": "NICE TO MEAT YOU", + "Question": "We give thanks that toms, the males of these birds, can reach 70 lbs.", + "Answer": "turkeys" + }, + { + "Category": "MIDDLE \"C\"", + "Question": "Define-A-Lash from Maybelline is a line of this", + "Answer": "mascara" + }, + { + "Category": "WAR", + "Question": "Of all the USA's wars, this one claimed the most American lives", + "Answer": "the Civil War" + }, + { + "Category": "GAMES", + "Question": "An explorer lends his name to this call & response swimming pool game", + "Answer": "Marco Polo" + }, + { + "Category": "MEN OF MUSIC", + "Question": "\"King of the Waltz\" Johann Strauss Jr. wrote in other dance forms too, like the \"Tritsch-Tratsch\" this", + "Answer": "the polka" + }, + { + "Category": "BIOPIC-NIC", + "Question": "1983: Meryl Streep as this nuclear power technician", + "Answer": "Silkwood" + }, + { + "Category": "NICE TO MEAT YOU", + "Question": "This meat comes before \"fried steak\" in a dish popular in the South", + "Answer": "chicken" + }, + { + "Category": "MIDDLE \"C\"", + "Question": "Traditionally at graduation, this student with the highest grades makes a speech", + "Answer": "valedictorian" + }, + { + "Category": "WAR", + "Question": "It was known as \"the war to end all wars\"", + "Answer": "World War I" + }, + { + "Category": "GAMES", + "Question": "In other words, this summer camp game could be called \"Seize Your Enemy's Banner\"", + "Answer": "Capture the Flag" + }, + { + "Category": "MEN OF MUSIC", + "Question": "In 1908 Oscar Strauss turned this playwright's \"Arms and the Man\" into the operetta \"The Chocolate Soldier\"", + "Answer": "Shaw" + }, + { + "Category": "BIOPIC-NIC", + "Question": "1992: Jack Nicholson as this labor leader", + "Answer": "Jimmy Hoffa" + }, + { + "Category": "NICE TO MEAT YOU", + "Question": "USDA grades of this \"other white meat\" are 1, 2, 3, 4 & utility; mmm... utility this", + "Answer": "pork" + }, + { + "Category": "MIDDLE \"C\"", + "Question": "In 1923, John Deere launched it's Model D, the first of these to bear the Deere name", + "Answer": "a tractor" + }, + { + "Category": "WAR", + "Question": "During this 1967 war, Israeli troops under Moshe Dayan came within a stone's throw of Damascus, Syria", + "Answer": "the Six-Days War" + }, + { + "Category": "GAMES", + "Question": "They'll treat you like a \"king\" in Petal, Mississippi, home to the International Hall of Fame for this board game", + "Answer": "checkers" + }, + { + "Category": "MEN OF MUSIC", + "Question": "Richard Strauss used double basses for Jokanaan's beheading in the opera about this princess", + "Answer": "Salomé" + }, + { + "Category": "BIOPIC-NIC", + "Question": "2001: Will Smith as this poet/pugilist", + "Answer": "Muhammad Ali" + }, + { + "Category": "NICE TO MEAT YOU", + "Question": "Be vewy quiet; the most common small game animal is this, which is mostly white meat & can be grilled, fried or roasted", + "Answer": "rabbit" + }, + { + "Category": "MIDDLE \"C\"", + "Question": "It means of or pertaining to the sense of smell", + "Answer": "olfactory" + }, + { + "Category": "WAR", + "Question": "\"Operation Rolling Thunder\" was the 1965 U.S. bombing campaign designed in part to stop men & supplies coming south on this road", + "Answer": "the Ho Chi Minh Trail" + }, + { + "Category": "GAMES", + "Question": "This lawn game was once called Pall Mall, from Italian words meaning \"ball\" & \"mallet\"", + "Answer": "croquet" + }, + { + "Category": "MEN OF MUSIC", + "Question": "Horn virtuoso Franz Strauss was consulted by Wagner in devising this hero's horn call", + "Answer": "Siegfried" + }, + { + "Category": "BIOPIC-NIC", + "Question": "2004: Liam Neeson as this behavioral researcher", + "Answer": "Kinsey" + }, + { + "Category": "NICE TO MEAT YOU", + "Question": "A western N.Y. city knows cuts of this humped cattle family member are lower in fat & cholesterol than most cuts of beef", + "Answer": "buffalo" + }, + { + "Category": "MIDDLE \"C\"", + "Question": "For a nice chianti, visit this wine-making region of Italy that's famous for it", + "Answer": "Tuscany" + }, + { + "Category": "WAR", + "Question": "During this war, Major George Armistead wanted \"a flag so large the British will have no difficulty seeing it\"", + "Answer": "the War of 1812" + }, + { + "Category": "GAMES", + "Question": "In terms of the use of fingers, it's the game in which 0 beats 2, 2 beats 5 & 5 beats 0", + "Answer": "Rock, Paper, Scissors" + }, + { + "Category": "TV THEME LYRICS", + "Question": "\"It's time to play the music, it's time to light the lights\"", + "Answer": "The Muppet Show" + }, + { + "Category": "DEATH BY...", + "Question": "Hanging, December 30, 2006 in Baghdad", + "Answer": "Saddam Hussein" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Thermostat control, egg tray, crisper", + "Answer": "refrigerator" + }, + { + "Category": "TITLE WAVE", + "Question": "Jon Krakauer: \"Into ____ Air\"", + "Answer": "Thin" + }, + { + "Category": "ANIMAL TERMS", + "Question": "This expression meaning to crease a page in a book for later reference dates back to 1659", + "Answer": "dog-ear" + }, + { + "Category": "TV THEME LYRICS", + "Question": "\"It's like you're always stuck in second gear, well it hasn't been your day, your week, your month, or even your year\"", + "Answer": "Friends" + }, + { + "Category": "DEATH BY...", + "Question": "Air crash of his MiG fighter plane while on a training mission near Moscow, March 27, 1968", + "Answer": "Yuri Gagarin" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Grip, shaft, a head made of stainless steel, titanium, carbon graphite...", + "Answer": "golf club" + }, + { + "Category": "TITLE WAVE", + "Question": "Malcolm Gladwell: \"The ____ Point: How Little Things Can Make a Big Difference\"", + "Answer": "Tipping" + }, + { + "Category": "ANIMAL TERMS", + "Question": "If you've been beaten 72-0 in football, you've gotten this, from the name of a smelly critter, Mephitis mephitis", + "Answer": "skunked" + }, + { + "Category": "TV THEME LYRICS", + "Question": "\"Believe it or not, I'm walking on air, never thought I could feel so free\"", + "Answer": "Greatest American Hero" + }, + { + "Category": "DEATH BY...", + "Question": "An overdose of barbiturates, August 5, 1962, at her L.A. home", + "Answer": "Marilyn Monroe" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Reservoir, filter basket, carafe", + "Answer": "a coffee maker" + }, + { + "Category": "TITLE WAVE", + "Question": "Kate Jacobs: \"The ____ Night Knitting Club\"", + "Answer": "Friday" + }, + { + "Category": "ANIMAL TERMS", + "Question": "To \"go whole\" this animal means to indulge completely", + "Answer": "hog" + }, + { + "Category": "TV THEME LYRICS", + "Question": "\"I don't know who you think you are but before the night is through, I wanna do bad things with you\"", + "Answer": "True Blood" + }, + { + "Category": "DEATH BY...", + "Question": "Firing squad, at the Utah State Prison, January 17, 1977", + "Answer": "Gary Gilmore" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Eyepiece, declination setting scale, azimuth fine adjustment", + "Answer": "a telescope" + }, + { + "Category": "TITLE WAVE", + "Question": "Jane Austen & Ben Winters: \"Sense and Sensibility and ____ ____\"", + "Answer": "Sea Monsters" + }, + { + "Category": "ANIMAL TERMS", + "Question": "This \"scaly\" alliterative term originally referred to men who flirted in tea rooms", + "Answer": "lounge lizards" + }, + { + "Category": "TV THEME LYRICS", + "Question": "\"Movin' movin' movi", + "Answer": "Rawhide" + }, + { + "Category": "DEATH BY...", + "Question": "Possible dropping of a tortoise on his head by an eagle, in 456 B.C.", + "Answer": "Aeschylus" + }, + { + "Category": "PARTS OF THE WHOLE", + "Question": "Mars light, tower ladder, water pressure gauge, hydrant intake", + "Answer": "a fire truck" + }, + { + "Category": "TITLE WAVE", + "Question": "Sara Gruen: \"Water for ____\"", + "Answer": "Elephants" + }, + { + "Category": "ANIMAL TERMS", + "Question": "Teens who frequent shopping centers are called these, the title of a Kevin Smith film", + "Answer": "mall rats" + }, + { + "Category": "THE OLD TESTAMENT", + "Question": "In the Book of Job, this name means \"accuser\", & that was his role in God's court", + "Answer": "Satan" + }, + { + "Category": "INVENTIVE MINDS", + "Question": "This peanut guy devised some 118 byproducts for the sweet potato", + "Answer": "George Washington Carver" + }, + { + "Category": "THAT'S WHERE IT'S AT, MAN!", + "Question": "It's borders are the Atlantic Ocean to the south & west & Spain to the north & east", + "Answer": "Portugal" + }, + { + "Category": "MOTTOES", + "Question": "This international sports competition's motto is \"Faster, higher, stronger\"", + "Answer": "the Olympics" + }, + { + "Category": "NOT A POPE", + "Question": "Urban VII, Julius II, Irving III", + "Answer": "Irving III" + }, + { + "Category": "STARTS WITH A PRONOUN", + "Question": "The laying on of hands is a key part of the practice of \"faith\" this", + "Answer": "healing" + }, + { + "Category": "INVENTIVE MINDS", + "Question": "Around 1930 William Lear invented one of these for the car, marketed under tha name Motorola", + "Answer": "a radio" + }, + { + "Category": "THAT'S WHERE IT'S AT, MAN!", + "Question": "India to the north, east & west & Burma to the southeast", + "Answer": "Bangladesh" + }, + { + "Category": "MOTTOES", + "Question": "You've got security with \"My word is my bond\", the motto of this London financial institution", + "Answer": "the London Stock Exchange" + }, + { + "Category": "STARTS WITH A PRONOUN", + "Question": "In this job, at a wedding, you'll be called upon to ask, \"Friend of the bride or groom?\"", + "Answer": "usher" + }, + { + "Category": "INVENTIVE MINDS", + "Question": "He's on the 4th floor in the Inventors Hall of Fame for his \"improvement in hoisting apparatus\"", + "Answer": "Otis" + }, + { + "Category": "THAT'S WHERE IT'S AT, MAN!", + "Question": "Colombia to the north, Peru to the west, Paraguay to the south & the Atlantic Ocean to the east", + "Answer": "Brazil" + }, + { + "Category": "MOTTOES", + "Question": "\"All power to the people\" was the motto of this African-American political organization of the 1960s", + "Answer": "the Black Panthers" + }, + { + "Category": "NOT A POPE", + "Question": "Romanus I, Julius I, Caesar III", + "Answer": "Caesar III" + }, + { + "Category": "STARTS WITH A PRONOUN", + "Question": "One who interlaces cloth, or an African bird that interlaces grass to make its elaborate nest", + "Answer": "a weaver" + }, + { + "Category": "INVENTIVE MINDS", + "Question": "In 1948, Rene Bussoz sold the USA's first Aqua Lung, invented by this Frenchman", + "Answer": "Cousteau" + }, + { + "Category": "THAT'S WHERE IT'S AT, MAN!", + "Question": "Syria to the north & east, Israel to the south & the Mediterranean Sea to the west", + "Answer": "Lebanon" + }, + { + "Category": "MOTTOES", + "Question": "\"Honi soit qui mal y pense\" (Evil to him who evil thinks) is the motto of this British Chivalric order", + "Answer": "Order of the Garter" + }, + { + "Category": "NOT A POPE", + "Question": "Stephen IX, John XXIV, Clement VIII", + "Answer": "John XXIV" + }, + { + "Category": "STARTS WITH A PRONOUN", + "Question": "It can mean transparently thin, or perfectly vertical, like a cliff", + "Answer": "sheer" + }, + { + "Category": "INVENTIVE MINDS", + "Question": "30 years after inventing an instant camera, he invented Polavision, instant movies", + "Answer": "Edwin Land" + }, + { + "Category": "THAT'S WHERE IT'S AT, MAN!", + "Question": "Thailand to the west, Laos to the north & Vietnam to the east", + "Answer": "Cambodia" + }, + { + "Category": "MOTTOES", + "Question": "Strangely, \"Blood & fire\" is the motto of this Christian charitable organization", + "Answer": "the Salvation Army" + }, + { + "Category": "NOT A POPE", + "Question": "Dominicus I, Honorius I, Innocent I", + "Answer": "Dominicus I" + }, + { + "Category": "STARTS WITH A PRONOUN", + "Question": "It's a printed-out schedule or outline of one's travel plans", + "Answer": "an itinerary" + }, + { + "Category": "LITERATURE", + "Question": "\"Tai-Pan\" was a \"Novel of Hong Kong\" by James Clavell, & this was his 1975 \"Novel of Japan\"", + "Answer": "Shogun" + }, + { + "Category": "WHO PLAYED 'EM", + "Question": "2003 & 2004: The bride who's trying to kill Bill", + "Answer": "Uma Thurman" + }, + { + "Category": "CONGRESSIONAL MISDEMEANORS", + "Question": "In 1954 this Wisconsin senator ws condemned for insulting other senators & obstructing investigations", + "Answer": "McCarthy" + }, + { + "Category": "I READ THE NEWS TODAY", + "Question": "This \"Post\" is one of Israel's largest English-language daily newspapers", + "Answer": "Jerusalem" + }, + { + "Category": "OH, \"BOY\"", + "Question": "It was founded by Baden-Powell in 1907", + "Answer": "the Boy Scouts" + }, + { + "Category": "LITERATURE", + "Question": "In Pierre Boulle's \"Planet of the Apes\", Zira & Cornelius are this species of ape", + "Answer": "chimpanzees" + }, + { + "Category": "WHO PLAYED 'EM", + "Question": "2004: Monster hunter Dr. Gabriel Van Helsing", + "Answer": "Jackman" + }, + { + "Category": "CONGRESSIONAL MISDEMEANORS", + "Question": "This former house speaker was reprimanded in 1997 for misuse of tax-exempt funds & submitting false informaiton", + "Answer": "Newt Gingrich" + }, + { + "Category": "I READ THE NEWS TODAY", + "Question": "Political theorist Nikolai Bukharin edited this \"truthful\" Soviet newspaper from 1917 to 1929", + "Answer": "Pravda" + }, + { + "Category": "OH, \"BOY\"", + "Question": "In this 2002 film, single guy Hugh Grant's life is changed by a 12-year old", + "Answer": "About a Boy" + }, + { + "Category": "LITERATURE", + "Question": "Milan Kundera's \"Immortality\" read in this, its original language, may be unbearably light reading", + "Answer": "Czech" + }, + { + "Category": "WHO PLAYED 'EM", + "Question": "2004: Cady Heron, who loves & hates the \"Mean Girls\" at her high school", + "Answer": "Lohan" + }, + { + "Category": "CONGRESSIONAL MISDEMEANORS", + "Question": "In 1811 Senator Thomas Pickering was censured for reading aloud from secret documents about this purchase", + "Answer": "Louisiana" + }, + { + "Category": "OH, \"BOY\"", + "Question": "Viiolinist-turned-boxer Joe Bonaparte dies in a car crash at the end of this tragic Odets play", + "Answer": "Golden Boy" + }, + { + "Category": "LITERATURE", + "Question": "Goethe called him Faust; Marlowe dubbed him this", + "Answer": "Dr. Faustus" + }, + { + "Category": "WHO PLAYED 'EM", + "Question": "2004: Sirius Black, the prisioner of Azkaban", + "Answer": "Gary Oldman" + }, + { + "Category": "CONGRESSIONAL MISDEMEANORS", + "Question": "In 1921 Congress censured Rep. Thomas Blanton for inserting \"obscene matter\" into this publication", + "Answer": "the Congressional Record" + }, + { + "Category": "I READ THE NEWS TODAY", + "Question": "At the time JFK was shot, Jack Ruby was placing some ads in this \"morning\" publication", + "Answer": "the Dallas Morning News" + }, + { + "Category": "OH, \"BOY\"", + "Question": "This law states that at a constant temp., the volume of a gas in inversely proportional to the pressure", + "Answer": "Boyle's" + }, + { + "Category": "LITERATURE", + "Question": "Completes the title of Eldridge Cleaver's 1968 memoir \"Soul on...\"", + "Answer": "Ice" + }, + { + "Category": "WHO PLAYED 'EM", + "Question": "1999 & 2002: Mini-Me", + "Answer": "Verne Troyer" + }, + { + "Category": "CONGRESSIONAL MISDEMEANORS", + "Question": "Senator Benjamin Tappan was censured in 1844 for leaking information about the annexation of this to the Union", + "Answer": "Texas" + }, + { + "Category": "I READ THE NEWS TODAY", + "Question": "Florida's highest circulation newspaper is this Gulf Coast city's Times, with about 350,000 daily copies sold", + "Answer": "St. Petersburg" + }, + { + "Category": "OH, \"BOY\"", + "Question": "The Marine Corps' \"Black Sheep\" squadron was commanded this famed major", + "Answer": "Pappy Boyington" + }, + { + "Category": "MUSICAL THEATER", + "Question": "In Act II of this musical, an election victory is announced \"on the balcony of the Casa Rosada\"", + "Answer": "Evita" + }, + { + "Category": "WORLD CITIES", + "Question": "From Bei Hai Park in this city, pass the Great Hall of the People, bear left, & then it's straight on to Mao's mausoleum", + "Answer": "Beijing" + }, + { + "Category": "SHOTS HEARD AROUND THE WORLD", + "Question": "His \"called shot\" home run off Charlie Root in the 1932 World Series is baseball legend", + "Answer": "Babe Ruth" + }, + { + "Category": "MODES OF TRANSPORT", + "Question": "3 types of these are rescue trucks, pumpers & ladder trucks", + "Answer": "fire trucks" + }, + { + "Category": "TIME TO GET SIMON-IZED", + "Question": "His autobiography was called \"I Don't Mean To Be Rude, But...\"", + "Answer": "Simon Cowell" + }, + { + "Category": "ON THE STAGE", + "Question": "Title of a Jonathan Larson musical, or what the East Village residents in it have trouble coming up with", + "Answer": "Rent" + }, + { + "Category": "ON THE \"WAR\"PATH", + "Question": "Pop art poster boy who was famous much longer than 15 minutes", + "Answer": "Andy Warhol" + }, + { + "Category": "WORLD CITIES", + "Question": "This Sudanese capital lies on a narrow piece of land bounded by the White & Blue Nile Rivers", + "Answer": "Khartoum" + }, + { + "Category": "SHOTS HEARD AROUND THE WORLD", + "Question": "Maybe...Yes, sir! Nailing an 11-foot putt on 17 helped seal the 1986 Masters for this Golden Bear", + "Answer": "Jack Nicklaus" + }, + { + "Category": "MODES OF TRANSPORT", + "Question": "The Triton was the first one of these to travel around the world underwater", + "Answer": "asubmarine" + }, + { + "Category": "TIME TO GET SIMON-IZED", + "Question": "He was \"Feelin' Groovy\" as an Illinois senator from 1985 to 1997", + "Answer": "Paul Simon" + }, + { + "Category": "ON THE STAGE", + "Question": "On Skid Row, love blooms for Seymour while Audrey II has a feeding frenzy in this play", + "Answer": "Little Shop of Horrors" + }, + { + "Category": "ON THE \"WAR\"PATH", + "Question": "Homeothermic, like mammals", + "Answer": "warm-blooded" + }, + { + "Category": "WORLD CITIES", + "Question": "The Tsarina's Stone is the oldest monument in this city that was made Finland's capital by Russian insistence", + "Answer": "Helsinki" + }, + { + "Category": "SHOTS HEARD AROUND THE WORLD", + "Question": "His prestidigitation (or in this case a \"Jr. Skyhook\") won Game 4 of the 1987 NBA Finals for the Lakers", + "Answer": "Magic Johnson" + }, + { + "Category": "MODES OF TRANSPORT", + "Question": "These ships were nicknamed \"blubber ships\"", + "Answer": "whaling ships" + }, + { + "Category": "TIME TO GET SIMON-IZED", + "Question": "In an 1852 novel, he's the plantation owner & slave master", + "Answer": "Simon Legree" + }, + { + "Category": "ON THE STAGE", + "Question": "Their first commission was \"Thespis\" for London's Gaiety Theatre in 1871", + "Answer": "Gilbert & Sullivan" + }, + { + "Category": "ON THE \"WAR\"PATH", + "Question": "In Super Bowl XXXIV, this Rams QB passed for a record 414 yards, beating Joe Montana's record by 57 yards", + "Answer": "Kurt Warner" + }, + { + "Category": "WORLD CITIES", + "Question": "This Caribbean island's capital, Fort-de-France, lies about 15 miles southeast of Mt. Pelee volcano", + "Answer": "Martinique" + }, + { + "Category": "SHOTS HEARD AROUND THE WORLD", + "Question": "In 1994 this 45-year-old won the title with a 1-2 punch that sent Michael Moorer to Horizontal Land", + "Answer": "George Foreman" + }, + { + "Category": "MODES OF TRANSPORT", + "Question": "This nickname for early cars pointed out that they were not pulled by equines", + "Answer": "horseless carriages" + }, + { + "Category": "TIME TO GET SIMON-IZED", + "Question": "This playwright won a Pulitzer in 1991 with \"Lost in Yonkers\"", + "Answer": "Neil Simon" + }, + { + "Category": "ON THE STAGE", + "Question": "This playwright hit the right note with \"Amadeus\" & then horsed around with \"Equus\"", + "Answer": "Peter Shaffer" + }, + { + "Category": "ON THE \"WAR\"PATH", + "Question": "The 14th Chief Justice of the United States", + "Answer": "Earl Warren" + }, + { + "Category": "WORLD CITIES", + "Question": "Construction began on this German city's Gothic cathedral near the Rhine in 1248 & lasted 632 years", + "Answer": "Cologne" + }, + { + "Category": "SHOTS HEARD AROUND THE WORLD", + "Question": "In 1999 she wasn't shirtless in Seattle but rather in Pasadena after her kick won the Women's World Cup for the U.S.", + "Answer": "Brandi Chastain" + }, + { + "Category": "MODES OF TRANSPORT", + "Question": "He named the first Bell X-1 rocket plane for his wife, Glennis", + "Answer": "Chuck Yeager" + }, + { + "Category": "TIME TO GET SIMON-IZED", + "Question": "He was the head of Vienna's Jewish Documentation Center from 1961 to 2003", + "Answer": "Simon Wiesenthal" + }, + { + "Category": "ON THE STAGE", + "Question": "All the original B'way cast, except Diane Keaton, bared all in a group nude scene in this musical about hippies", + "Answer": "Hair" + }, + { + "Category": "ON THE \"WAR\"PATH", + "Question": "In response to NATO, Eastern European nations including Poland & the USSR signed this 1955 treaty", + "Answer": "the Warsaw Pact" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "This alliterative event happened 14 billion years ago", + "Answer": "the Big Bang" + }, + { + "Category": "GET YOUR MOVIE FACTS STRAIGHT", + "Question": "Peter Fonda was in \"Ulee's Gold\"; \"Fool's Gold\" stars this daughter of Goldie Hawn", + "Answer": "Kate Hudson" + }, + { + "Category": "SHAKESPEAREAN PHRASES", + "Question": "In this play, Casca says Cicero's speech \"was Greek to me\"", + "Answer": "Julius Caesar" + }, + { + "Category": "A WHITE CATEGORY", + "Question": "The London district of Whitechapel is associated with this infamous killer", + "Answer": "Jack the Ripper" + }, + { + "Category": "MAMMALS", + "Question": "It makes sense that these proud & powerful mammals live in groups called prides", + "Answer": "lions" + }, + { + "Category": "\"T\" TIME", + "Question": "Lay-deez annnd gentlemen! To \"walk\" this slender item means to tread carefully", + "Answer": "tightrope" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "A hydrate contains this compound weakly bound in its crystals", + "Answer": "water" + }, + { + "Category": "GET YOUR MOVIE FACTS STRAIGHT", + "Question": "\"First Blood\" was a Rambo movie; this 2007 film had Daniel Day-Lewis searching for oil", + "Answer": "There Will Be Blood" + }, + { + "Category": "SHAKESPEAREAN PHRASES", + "Question": "\"She speaks yet she says nothing\", pines one character for his unattainable love in this tragedy", + "Answer": "Romeo & Juliet" + }, + { + "Category": "A WHITE CATEGORY", + "Question": "The mass of a typical one of these stars is about 70% that of the sun", + "Answer": "white dwarf" + }, + { + "Category": "MAMMALS", + "Question": "Common in Dixie, a razorback is a wild one of these", + "Answer": "hog" + }, + { + "Category": "\"T\" TIME", + "Question": "Left pinky makes \"A\" & right index makes \"J\" in this activity", + "Answer": "typing" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "Of the 3 main classes of rock, this one is further divided into plutonic & volcanic types", + "Answer": "igneous" + }, + { + "Category": "GET YOUR MOVIE FACTS STRAIGHT", + "Question": "Ian McKellen was Gandalf in \"LOTR\"; Ian McEwan wrote the novel on which this 2007 Keira Knightley film was based", + "Answer": "Atonement" + }, + { + "Category": "SHAKESPEAREAN PHRASES", + "Question": "It was actually Christopher Sly, not Kate, who says, \"I'll not budge an inch\" in this comedy", + "Answer": "The Taming of the Shrew" + }, + { + "Category": "MAMMALS", + "Question": "The name of this order of mammals comes from the Latin verb \"rodere\", meaning to gnaw", + "Answer": "rodent" + }, + { + "Category": "\"T\" TIME", + "Question": "A synonym for \"journey\", it's also an upper-crust nickname for a guy with Roman numeral III in his name", + "Answer": "trip" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "The IRAS telescope, which revealed 5 new comets, made its observations in this part of the light spectrum", + "Answer": "infra-red" + }, + { + "Category": "GET YOUR MOVIE FACTS STRAIGHT", + "Question": "\"North Country\" starred Charlize Theron; \"No Country for Old Men\" featured this Spaniard as a relentless killer", + "Answer": "Javier Bardem" + }, + { + "Category": "SHAKESPEAREAN PHRASES", + "Question": "A wife tries to console her husband in this tragedy by telling him, \"What's done is done\"", + "Answer": "Macbeth" + }, + { + "Category": "A WHITE CATEGORY", + "Question": "This black & white dairy cow originated in an area of Holland", + "Answer": "Holstein" + }, + { + "Category": "MAMMALS", + "Question": "The giant species of this \"armor-plated\" animal has more teeth than any other land mammal", + "Answer": "armadillo" + }, + { + "Category": "GENERAL SCIENCE", + "Question": "This branch of medicine is devoted to the care & diseases of the elderly", + "Answer": "geriatrics" + }, + { + "Category": "GET YOUR MOVIE FACTS STRAIGHT", + "Question": "Everyone knows the \"Chronicles of Narnia\"; this 2008 film \"Chronicles\" the Grace family stumbling onto a world of fairies", + "Answer": "The Spiderwick Chronicles" + }, + { + "Category": "SHAKESPEAREAN PHRASES", + "Question": "In this comedy, Thurio says to Valentine, \"If you spend word for word with me, I shall make your wit bankrupt\"", + "Answer": "The Two Gentlemen of Verona" + }, + { + "Category": "A WHITE CATEGORY", + "Question": "Anne Catherick is all dressed up as the title character of this Wilkie Collins novel", + "Answer": "The Woman in White" + }, + { + "Category": "MAMMALS", + "Question": "The African & Sumatran species of this animal have 2 horns; the Indian & Javan species have one", + "Answer": "rhinoceros" + }, + { + "Category": "CHILDREN'S AUTHORS", + "Question": "In 1896 he said his mother had lost her childhood at 8; he \"knew a time would come when I also must give up the games\"", + "Answer": "J.M. Barrie" + }, + { + "Category": "U.S. PORT CITIES", + "Question": "Pull into this port city & you'll find Fort Sumter guarding its harbor", + "Answer": "Charleston" + }, + { + "Category": "HOLLYWOOD LEFTIES", + "Question": "Tom Cruise jumped up & down on this left-hander's couch", + "Answer": "Oprah Winfrey" + }, + { + "Category": "ARTS & CRAFTS", + "Question": "It's the oven or furnace in which pottery is fired", + "Answer": "a kiln" + }, + { + "Category": "QUOTATIONS", + "Question": "John Kenneth Galbraith said these \"are indispensable when you don't want to do anything\"--there's one in the boardroom at 2:30", + "Answer": "meetings" + }, + { + "Category": "HEY, \"BABY\"", + "Question": "Smallest form of a large piano", + "Answer": "a baby grand" + }, + { + "Category": "AFRICAN-AMERICANA", + "Question": "In 1964 Martin Luther King became the first African American named this magazine's \"Man of the Year\"", + "Answer": "Time" + }, + { + "Category": "U.S. PORT CITIES", + "Question": "Among the busiest ports with \"port\" in their names are Port Everglades in Florida & Port Arthur in this state", + "Answer": "Texas" + }, + { + "Category": "HOLLYWOOD LEFTIES", + "Question": "This left-handed honey socked it to 'em on \"Laugh-In\" in the 1960s & as Private Benjamin in the 1980s", + "Answer": "Goldie Hawn" + }, + { + "Category": "ARTS & CRAFTS", + "Question": "A mosaic needs this mortar between the pieces, just like in a tiled bathroom", + "Answer": "grout" + }, + { + "Category": "QUOTATIONS", + "Question": "Antoine de Rivarol said, \"What is not clear is not\" this language", + "Answer": "French" + }, + { + "Category": "AFRICAN-AMERICANA", + "Question": "Frederick Douglass said this political party was the ship & everything else was the ocean", + "Answer": "the Republican Party" + }, + { + "Category": "HOLLYWOOD LEFTIES", + "Question": "We gotta hand it to this left-handed actress for winning an Oscar for \"Erin Brockovich\"", + "Answer": "Julia Roberts" + }, + { + "Category": "ARTS & CRAFTS", + "Question": "In this craft, you may use corn husks for the core & raffia for the binder", + "Answer": "basket weaving" + }, + { + "Category": "QUOTATIONS", + "Question": "In a saying attributed to the Duke of Wellington, this battle \"was won on the playing fields of Eton\"", + "Answer": "Waterloo" + }, + { + "Category": "HEY, \"BABY\"", + "Question": "Nickname of Haiti's Jean-Claude Duvalier", + "Answer": "\"Baby Doc\"" + }, + { + "Category": "AFRICAN-AMERICANA", + "Question": "This military man won the NAACP's Spingarn Medal for 1991", + "Answer": "Colin Powell" + }, + { + "Category": "U.S. PORT CITIES", + "Question": "By containers handled, Los Angeles is the busiest U.S. port; the second-busiest is in this city just a few miles south", + "Answer": "Long Beach" + }, + { + "Category": "HOLLYWOOD LEFTIES", + "Question": "The Brad jumped the Jen for this left-handed hottie", + "Answer": "Angelina Jolie" + }, + { + "Category": "QUOTATIONS", + "Question": "Jean-Luc Godard said, \"Photography is truth, and\" this \"is truth 24 times a second\"", + "Answer": "film" + }, + { + "Category": "HEY, \"BABY\"", + "Question": "This sticky figure of folklore gave its name to a Toni Morrison novel", + "Answer": "the tar baby" + }, + { + "Category": "AFRICAN-AMERICANA", + "Question": "This southern city's convention center is named for Ernest Morial, the city's first African-American mayor", + "Answer": "New Orleans" + }, + { + "Category": "U.S. PORT CITIES", + "Question": "Among the top 40 busiest ports in the U.S. are these Northeast & Northwest cities with the same name", + "Answer": "Portland" + }, + { + "Category": "HOLLYWOOD LEFTIES", + "Question": "This left-handed lady was positively \"Bewitching\" in a 2005 Nora Ephron film", + "Answer": "Nicole Kidman" + }, + { + "Category": "ARTS & CRAFTS", + "Question": "The name of this knotty craft comes from a word that means \"embroidered veil\"", + "Answer": "macramé" + }, + { + "Category": "QUOTATIONS", + "Question": "\"Dulce et decorum est pro patria mori\", wrote Horace, \"It is a sweet and seemly thing to die for\" this", + "Answer": "one's country" + }, + { + "Category": "AFRICAN-AMERICANA", + "Question": "Mari Evans adapted this Zora Neale Hurston work as a musical titled \"Eyes\"", + "Answer": "Their Eyes Were Watching God" + }, + { + "Category": "TV DRAMAS BY EPISODE", + "Question": "\"Custom K.I.T.T.\"", + "Answer": "Knight Rider" + }, + { + "Category": "ARCHITECTURE", + "Question": "A kite winder is the central of 3 winders that help make a 90-degree turn in a flight of these", + "Answer": "stairs" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "This state insect of Vermont is just as sweet as its state tree the sugar maple", + "Answer": "the honey bee" + }, + { + "Category": "MY NAME IS EARL WARREN", + "Question": "In Reynolds v. Sims I said that representation in legislatures must be based mostly on population: one man, one this", + "Answer": "vote" + }, + { + "Category": "I JUST LIKE SAYING THESE WORDS", + "Question": "As I reflect on the word \"genuflect\", I remember it means to bend this", + "Answer": "one's knee" + }, + { + "Category": "ROYAL BRITANNIA", + "Question": "In 1707 her title changed to Queen of Great Britain & Ireland (it used to be Queen of England, Scotland & Ireland)", + "Answer": "Queen Anne" + }, + { + "Category": "TV DRAMAS BY EPISODE", + "Question": "\"Angels in Chains\"", + "Answer": "Charlie's Angels" + }, + { + "Category": "ARCHITECTURE", + "Question": "This 6-letter part of a house is also called an eaves trough", + "Answer": "gutter" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "Who was that masked animal? Oklahoma's official state furbearer, that's who", + "Answer": "a raccoon" + }, + { + "Category": "MY NAME IS EARL WARREN", + "Question": "I am interred at this national cemetery", + "Answer": "Arlington" + }, + { + "Category": "I JUST LIKE SAYING THESE WORDS", + "Question": "Alfred E. Neuman could tell you that a fernticle is another name for one of these on the surface of the skin", + "Answer": "a freckle" + }, + { + "Category": "TV DRAMAS BY EPISODE", + "Question": "\"Warrior... Princess... Tramp\"", + "Answer": "Xena Warrior Princess" + }, + { + "Category": "ARCHITECTURE", + "Question": "The Coonley Estate & the Robie House are examples of this midwestern style created by Frank Lloyd Wright", + "Answer": "the Prairie Style" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "Hot-cha-cha! New Mexico's official state question is \"red or\" this?", + "Answer": "green" + }, + { + "Category": "MY NAME IS EARL WARREN", + "Question": "I was a 3-term governor of this state, 1943-1953", + "Answer": "California" + }, + { + "Category": "I JUST LIKE SAYING THESE WORDS", + "Question": "To lapidate someone is to execute him by this method", + "Answer": "stoning" + }, + { + "Category": "ROYAL BRITANNIA", + "Question": "He succeeded his mother & was succeeded in 1910 by his son George V", + "Answer": "Edward VII" + }, + { + "Category": "TV DRAMAS BY EPISODE", + "Question": "\"The Path to the Black Lodge\"", + "Answer": "Twin Peaks" + }, + { + "Category": "ARCHITECTURE", + "Question": "In the English bond style, these are laid in alternate courses of headers & stretchers", + "Answer": "bricks" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "Florida's state shell is the \"horse\" type of this (Wow! I can hear the ocean!)", + "Answer": "a conch" + }, + { + "Category": "MY NAME IS EARL WARREN", + "Question": "On June 23, 1969 I swore in this man as Chief Justice of the U.S.", + "Answer": "Warren Burger" + }, + { + "Category": "I JUST LIKE SAYING THESE WORDS", + "Question": "Used to mean a vulnerable weak point in an enemy's defenses, it means the lower abdomen", + "Answer": "underbelly" + }, + { + "Category": "TV DRAMAS BY EPISODE", + "Question": "\"I, Borg\"", + "Answer": "Star Trek: The Next Generation" + }, + { + "Category": "ARCHITECTURE", + "Question": "From 1617 to 1642 everyone was keeping up with this Jones, surveyor of works to the British Crown", + "Answer": "Inigo" + }, + { + "Category": "OFFICIAL STATE THINGS", + "Question": "Extinct? You bet. But this \"3-lobed\" arthropod has crawled into history as Wisconsin's state fossil", + "Answer": "trilobite" + }, + { + "Category": "MY NAME IS EARL WARREN", + "Question": "I ruled that public school segregation was unconstitutional in this landmark 1954 case", + "Answer": "Brown v. Board of Education" + }, + { + "Category": "I JUST LIKE SAYING THESE WORDS", + "Question": "Enjoy this $2000 quanswer--see, I'm one of these, a creator of new words", + "Answer": "neologist" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "An epigraph he used on one story says, \"our hearts though stout and brave, still, like muffled drums are beating\"", + "Answer": "Edgar Allan Poe" + }, + { + "Category": "SUPERHEROES", + "Question": "In a 2002 movie this hero got an upside-down kiss from Mary Jane", + "Answer": "Spider-Man" + }, + { + "Category": "KIDS IN BOOKS", + "Question": "Based on a real child, a kid named Christopher Robin hangs out with this literary bear", + "Answer": "Winnie the Pooh" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "In February 1999 Maine residents built a 10-story one of these named Angus; he melted 15 weeks later", + "Answer": "snowman" + }, + { + "Category": "BRAND NAMES", + "Question": "It's the rhyming name of a brand of pretzels made by Frito-Lay", + "Answer": "Rold Gold" + }, + { + "Category": "THE 1990s", + "Question": "Pierce Brosnan played this superspy for the first time in \"GoldenEye\"", + "Answer": "James Bond" + }, + { + "Category": "A TRIP TO OUTER SPACE", + "Question": "The mission of the Apollo space program of the 1960s & '70s was to land men on this celestial body", + "Answer": "the moon" + }, + { + "Category": "SUPERHEROES", + "Question": "For a while the Hulk was gray, but now he's this color", + "Answer": "green" + }, + { + "Category": "KIDS IN BOOKS", + "Question": "This collie was the faithful friend of a kid named Joe in a book by British novelist Eric Knight", + "Answer": "Lassie" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "9,360 graham crackers, 9,312 marshmallows & 4,128 chocolate bars went into one of these made at a campground", + "Answer": "s'more" + }, + { + "Category": "BRAND NAMES", + "Question": "Reynolds Guyer, inventor of Twister, also created the 4-inch foam ball later sold under this brand name", + "Answer": "Nerf ball" + }, + { + "Category": "THE 1990s", + "Question": "Jacques Chirac of the Rally for the Republic Party won a 7-year term as this country's president", + "Answer": "France" + }, + { + "Category": "A TRIP TO OUTER SPACE", + "Question": "This planet's famous rings were first seen by the Italian scientist Galileo in 1610", + "Answer": "Saturn" + }, + { + "Category": "SUPERHEROES", + "Question": "In a 1940 comic book Batman & this sidekick take an undying oath to fight crime & corruption", + "Answer": "Robin" + }, + { + "Category": "KIDS IN BOOKS", + "Question": "Mowgli is the human kid hanging out in the woods with wolves & tigers in this Rudyard Kipling \"Book\"", + "Answer": "\"The Jungle Book\"" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "He holds the record for all-time career earnings on the U.S. PGA circuit (over $26 million from 1996 to 2001)", + "Answer": "Tiger Woods" + }, + { + "Category": "BRAND NAMES", + "Question": "\"Share Moments, Share Life\" is a slogan of this brand of film & cameras", + "Answer": "Kodak" + }, + { + "Category": "THE 1990s", + "Question": "In 1997 the Marlins won the Major League, Mexico the Little League & LSU the college version of this event", + "Answer": "the World Series" + }, + { + "Category": "A TRIP TO OUTER SPACE", + "Question": "Kohoutek, Shoemaker-Levy & Halley's are all names for these astronomic objects", + "Answer": "comets" + }, + { + "Category": "SUPERHEROES", + "Question": "The dude seen here is the \"Silver\" one of this type of athletes", + "Answer": "surfers" + }, + { + "Category": "KIDS IN BOOKS", + "Question": "She's Beezus Quimby's pesky young sister", + "Answer": "Ramona" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "The largest mammal is the blue type of this; it also has the largest offspring, with 4,400-6,600 pound newborns", + "Answer": "whale" + }, + { + "Category": "BRAND NAMES", + "Question": "This athletic brand is named for the Greek goddess of victory", + "Answer": "Nike" + }, + { + "Category": "THE 1990s", + "Question": "On 2 votes, the House of Representatives did this to President Clinton on Dec. 19, 1998", + "Answer": "impeached him" + }, + { + "Category": "A TRIP TO OUTER SPACE", + "Question": "Many beautiful images like the one seen here have been given to us by this famous space telescope", + "Answer": "Hubble Space Telescope" + }, + { + "Category": "SUPERHEROES", + "Question": "When Doug Funnie's in a tough spot, he wears his underwear on the outside & becomes this man", + "Answer": "Quailman" + }, + { + "Category": "KIDS IN BOOKS", + "Question": "\"The Sword in the Stone\" is a book about a kid who grows up to be this king", + "Answer": "King Arthur" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "Siberia in this country has had the greatest range in temperatures -- from 98 degrees F. to -90 degrees F.", + "Answer": "Russia" + }, + { + "Category": "BRAND NAMES", + "Question": "The bird's nest logo of this chocolate brand comes from its founder's coat of arms", + "Answer": "Nestle" + }, + { + "Category": "THE 1990s", + "Question": "The Persian Gulf War of 1991 was fought mainly in Iraq & this oil-rich nation next door", + "Answer": "Kuwait" + }, + { + "Category": "A TRIP TO OUTER SPACE", + "Question": "Many astronomers believe the Great Andromeda spiral galaxy has one of these \"dark\" collapsed stars at its center", + "Answer": "black hole" + }, + { + "Category": "STATE CAPITALS", + "Question": "No beans about it, this capital is the largest city in New England", + "Answer": "Boston" + }, + { + "Category": "AROUND THE APARTMENT BUILDING", + "Question": "Around July your building's superintendent will be your hero when he fixes the A/C, short for this", + "Answer": "air conditioning" + }, + { + "Category": "TV STARS", + "Question": "Taylor Negron plays nanny to these twins on \"So Little Time\"", + "Answer": "the Olsen twins" + }, + { + "Category": "ELEMENT-ARY SCHOOL", + "Question": "One of the noble gases, it's the lightest of all gases after hydrogen", + "Answer": "helium" + }, + { + "Category": "ABRAHAM LINCOLN", + "Question": "It was an 11-year-old girl who first suggested that Lincoln do this to improve his appearance", + "Answer": "grow a beard" + }, + { + "Category": "ATTACK OF THE THESAURUS", + "Question": "Outsmart or outwit someone & you also out- this \"sly\" animal them", + "Answer": "fox" + }, + { + "Category": "STATE CAPITALS", + "Question": "This twin city is the capital of Minnesota", + "Answer": "St. Paul" + }, + { + "Category": "AROUND THE APARTMENT BUILDING", + "Question": "Be careful not to drop your key down this vertical passage in which the elevator moves up & down", + "Answer": "shaft" + }, + { + "Category": "TV STARS", + "Question": "Coming to TV in 2002, this star of an Oscar-nominated movie was once known as Johnny Quasar", + "Answer": "Jimmy Neutron" + }, + { + "Category": "ELEMENT-ARY SCHOOL", + "Question": "This element is essential for the clotting of blood, as well as healthy teeth & bones", + "Answer": "calcium" + }, + { + "Category": "ABRAHAM LINCOLN", + "Question": "This speech that Lincoln delivered on a battlefield in 1863 lasted only 2 minutes but its impact was huge", + "Answer": "the Gettysburg Address" + }, + { + "Category": "ATTACK OF THE THESAURUS", + "Question": "In kiddy lit Jack didn't kill the titan or the colossus, he killed this", + "Answer": "the giant" + }, + { + "Category": "STATE CAPITALS", + "Question": "It's nicknamed the \"Center of the Pineapple Industry\"", + "Answer": "Honolulu" + }, + { + "Category": "AROUND THE APARTMENT BUILDING", + "Question": "(Sofia of the Clue Crew) You can save lives & earn firemen's gratitude if you keep this in good working order", + "Answer": "smoke detector" + }, + { + "Category": "TV STARS", + "Question": "Putting the Goth in \"American Gothic\", this rocker & his family starred in a hit MTV reality show in 2002", + "Answer": "Ozzy Osbourne" + }, + { + "Category": "ELEMENT-ARY SCHOOL", + "Question": "Diamonds & graphite are both forms of this element", + "Answer": "carbon" + }, + { + "Category": "ABRAHAM LINCOLN", + "Question": "Illinois is the \"Land of Lincoln\", but the birthplace of Lincoln is this state just to the south", + "Answer": "Kentucky" + }, + { + "Category": "ATTACK OF THE THESAURUS", + "Question": "I cannot tell a prevarication: it has this 3-letter synonym", + "Answer": "lie" + }, + { + "Category": "STATE CAPITALS", + "Question": "A 150-foot-high battle monument in this New Jersey capital marks the site of a famous Revolutionary War battle", + "Answer": "Trenton" + }, + { + "Category": "AROUND THE APARTMENT BUILDING", + "Question": "These common, crawly apartment insects have German, brown-banded & American species", + "Answer": "cockroaches" + }, + { + "Category": "TV STARS", + "Question": "Inspired by Sydney, her character on \"Alias\", this actress enjoys kickboxing", + "Answer": "Jennifer Garner" + }, + { + "Category": "ELEMENT-ARY SCHOOL", + "Question": "Bananas are an excellent source of this element whose symbol is K", + "Answer": "potassium" + }, + { + "Category": "ABRAHAM LINCOLN", + "Question": "In April 1865 while attending a play at this man's theater, Lincoln was shot by John Wilkes Booth", + "Answer": "Ford's Theatre" + }, + { + "Category": "STATE CAPITALS", + "Question": "Every Memorial Day weekend, this city hosts its famous 500 auto race", + "Answer": "Indianapolis" + }, + { + "Category": "AROUND THE APARTMENT BUILDING", + "Question": "When painting a room, put this on as the first coat; it's spelled like a book that teaches reading", + "Answer": "primer" + }, + { + "Category": "TV STARS", + "Question": "In 2001 this actress, Borg babe Seven of Nine on \"Voyager\", joined the cast of \"Boston Public\"", + "Answer": "Jeri Ryan" + }, + { + "Category": "ELEMENT-ARY SCHOOL", + "Question": "This element, Na, combines with chlorine to form ordinary table salt", + "Answer": "sodium" + }, + { + "Category": "ABRAHAM LINCOLN", + "Question": "In the painting seen here, Lincoln is reading this historic document that led to the end of slavery", + "Answer": "the Emancipation Proclamation" + }, + { + "Category": "ON THE CALENDAR", + "Question": "In 1974, to save energy, it began in January instead of April & ended on October 27", + "Answer": "Daylight saving time" + }, + { + "Category": "IT COMES WITH THE TERRITORY", + "Question": "Tokelau, a territory of this country, is over 1,000 miles north of its Noeth Island", + "Answer": "New Zealand" + }, + { + "Category": "DISNEY VILLAINS", + "Question": "Jafar", + "Answer": "Aladdin" + }, + { + "Category": "A BUNCH OF \"GREAT\" LEADERS", + "Question": "His forces defeated the Persian Army under Darius III in 333 B.C.", + "Answer": "Alexander the Great" + }, + { + "Category": "PULL", + "Question": "You \"pull a few\" of these to get a favor done", + "Answer": "Strings" + }, + { + "Category": "SHIRLEY", + "Question": "This Oscar winner played the matriarch of the Partridge Family", + "Answer": "Shirley Jones" + }, + { + "Category": "YOU MUST BE JOKING", + "Question": "Steven Wright joked, \"I put instant coffee in\" this type of \"oven and nearly went back in time\"", + "Answer": "Microwave" + }, + { + "Category": "IT COMES WITH THE TERRITORY", + "Question": "In 1896 George Carmack, Skookum Jim & Tagish Charlie found gold in this territory", + "Answer": "Yukon Territory" + }, + { + "Category": "DISNEY VILLAINS", + "Question": "Ursula", + "Answer": "The Little Mermaid" + }, + { + "Category": "A BUNCH OF \"GREAT\" LEADERS", + "Question": "In the 18th century she founded a medical college & the first Russian school for girls", + "Answer": "Catherine the Great" + }, + { + "Category": "PULL", + "Question": "From the idea of breaking camp comes this phrase for moving on", + "Answer": "Pull up stakes" + }, + { + "Category": "SHIRLEY", + "Question": "She played Shirley Feeney on \"Laverne & Shirley\"", + "Answer": "Cindy Williams" + }, + { + "Category": "YOU MUST BE JOKING", + "Question": "It's the classic response to the request \"Call me a cab!\"", + "Answer": "\"OK, you're a cab!\"" + }, + { + "Category": "IT COMES WITH THE TERRITORY", + "Question": "In 1858 the British established this type of colony on India's Andaman Islands", + "Answer": "Penal colony" + }, + { + "Category": "DISNEY VILLAINS", + "Question": "Scar", + "Answer": "The Lion King" + }, + { + "Category": "A BUNCH OF \"GREAT\" LEADERS", + "Question": "This 9th century king of Wessex repeatedly repelled the Danes with great success", + "Answer": "Alfred the Great" + }, + { + "Category": "PULL", + "Question": "Since the 8th century, it's what churchmen have pulled to ring their bells", + "Answer": "Ropes" + }, + { + "Category": "SHIRLEY", + "Question": "Shirley Manson is the lead singer of this \"trashy\" alternative band", + "Answer": "Garbage" + }, + { + "Category": "YOU MUST BE JOKING", + "Question": "When this gastropod in a shell rode on the turtle's back, it said, \"Whee!\"", + "Answer": "Snail" + }, + { + "Category": "IT COMES WITH THE TERRITORY", + "Question": "The price paid for these Caribbean islands in 1917 was $25 million, over 3 times what Alaska cost", + "Answer": "Virgin Islands" + }, + { + "Category": "DISNEY VILLAINS", + "Question": "Clayton", + "Answer": "Tarzan" + }, + { + "Category": "A BUNCH OF \"GREAT\" LEADERS", + "Question": "From 1682 to 1689 he shared the throne with his half-brother Ivan V", + "Answer": "Peter the Great" + }, + { + "Category": "PULL", + "Question": "Word on the 2 buttons that preceded this one: (Curly in a \"Three Stooges\" clip showing a button marked \"Pull\")", + "Answer": "Press" + }, + { + "Category": "SHIRLEY", + "Question": "The 1999 movie \"The Haunting\" was based on her novel \"The Haunting of Hill House\"", + "Answer": "Shirley Jackson" + }, + { + "Category": "YOU MUST BE JOKING", + "Question": "When singing \"The Star-Spangled Banner\", Pavarotti & Domingo could change the first line to this for Mr. Carreras", + "Answer": "Jose, can you see by the dawn's early light" + }, + { + "Category": "IT COMES WITH THE TERRITORY", + "Question": "Australia has an uninhabited territory named for this sea off its northeast coast", + "Answer": "Coral Sea" + }, + { + "Category": "DISNEY VILLAINS", + "Question": "Kaa & Shere Khan", + "Answer": "The Jungle Book" + }, + { + "Category": "A BUNCH OF \"GREAT\" LEADERS", + "Question": "During the Seven Years' War, this king gained great military prestige & land for Prussia", + "Answer": "Frederick the Great" + }, + { + "Category": "PULL", + "Question": "Ermal Fraze holds the 1963 patent for part of the \"tear strip opener\" better known to pop drinkers as this", + "Answer": "Pull tab" + }, + { + "Category": "SHIRLEY", + "Question": "\"Moonraker\" is one of the 3 James Bond movies that have featured her singing over the title sequence", + "Answer": "Shirley Bassey" + }, + { + "Category": "YOU MUST BE JOKING", + "Question": "Completes Groucho's \"One morning I shot an elephant in my pajamas...\"", + "Answer": "\"How he got in my pajamas, I'll never know!\"" + }, + { + "Category": "FUN WITH OPERA", + "Question": "Pride! Envy! Gluttony! Lust! All that & more are dramatized in a 1933 opera named for this septet of vices", + "Answer": "\"The Seven Deadly Sins\"" + }, + { + "Category": "AUDIO BOOKS", + "Question": "Julie Harris reads the diary this girl wrote while in hiding in WWII Amsterdam", + "Answer": "Anne Frank" + }, + { + "Category": "TELEVISION", + "Question": "He was \"X\"-static when the first \"X-Files\" episode he directed aired 1 day after the birth of his baby.", + "Answer": "David Duchovny" + }, + { + "Category": "CAMBRIDGE UNIVERSITY", + "Question": "While studying at Cambridge in the late 1960s, this prince showed a flair for acting in comedy revues", + "Answer": "Prince Charles" + }, + { + "Category": "LITERARY EPITAPHS", + "Question": "Beloved father of Cordelia, less beloved father of Goneril & Regan", + "Answer": "King Lear" + }, + { + "Category": "\"CAR\" PARK", + "Question": "Title of Oliver Goldsmith's title man \"of Wakefield\"", + "Answer": "The Vicar" + }, + { + "Category": "FUN WITH OPERA", + "Question": "Of a woman, an evil twin or a circus ape, what Sir Edgar's nephew turns out to be in \"Der Junge Lord\"", + "Answer": "A circus ape" + }, + { + "Category": "TELEVISION", + "Question": "This sitcom's last show of the '98-'99 season ended with the cast singing & dancing to \"Brotherhood of Man\"", + "Answer": "The Drew Carey Show" + }, + { + "Category": "CAMBRIDGE UNIVERSITY", + "Question": "This Tudor king founded Cambridge's Trinity College in 1546", + "Answer": "Henry VIII" + }, + { + "Category": "LITERARY EPITAPHS", + "Question": "\"Run\", \"Redux\", \"Rich\", finally \"At Rest\"", + "Answer": "Harry \"Rabbit\" Angstrom" + }, + { + "Category": "\"CAR\" PARK", + "Question": "He traveled the Yellow Brick Road", + "Answer": "Scarecrow" + }, + { + "Category": "FUN WITH OPERA", + "Question": "In \"Susannah\", a Bible-inspired opera, the elders are scandalized when they see the nude Susannah doing this outside", + "Answer": "Bathing in a creek" + }, + { + "Category": "TELEVISION", + "Question": "\"Matlock\" & \"Designing Women\" were both set in this state capital", + "Answer": "Atlanta" + }, + { + "Category": "CAMBRIDGE UNIVERSITY", + "Question": "The 2 parts of St. John's college are connected by a copy of this Venetian bridge", + "Answer": "Bridge of Sighs" + }, + { + "Category": "LITERARY EPITAPHS", + "Question": "Devoted salesman & husband to Linda. \"Attention must be paid.\"", + "Answer": "Willy Loman" + }, + { + "Category": "FUN WITH OPERA", + "Question": "Lord Lechery, Madam Wanton & Madam Bubble are all characters in the 1951 opera based on this John Bunyan work", + "Answer": "\"Pilgrim's Progress\"" + }, + { + "Category": "TELEVISION", + "Question": "\"Cosmetic\" name of the magazine that's the focus of \"Just Shoot Me\", or what its racier episodes may make you do", + "Answer": "Blush" + }, + { + "Category": "CAMBRIDGE UNIVERSITY", + "Question": "This author of \"Vanity Fair\" studied at Cambridge but left without a degree", + "Answer": "William Makepeace Thackeray" + }, + { + "Category": "LITERARY EPITAPHS", + "Question": "Fondly remembered by the boys of The Brookfield School. Goodbye...", + "Answer": "Mr. Chips" + }, + { + "Category": "\"CAR\" PARK", + "Question": "In this casino game the winner is the one whose hand totals closest to 9", + "Answer": "Baccarat" + }, + { + "Category": "FUN WITH OPERA", + "Question": "A singing sofa & a chorus of frogs are featured in \"L'Enfant et les Sortileges\" by this \"Bolero\" composer", + "Answer": "Maurice Ravel" + }, + { + "Category": "TELEVISION", + "Question": "Like Burton & Taylor, Billy Zane & Leonor Varela had a romance when they played these lovers (in a 1999 miniseries)", + "Answer": "Antony & Cleopatra" + }, + { + "Category": "CAMBRIDGE UNIVERSITY", + "Question": "This great Flemish artist's \"Adoration of the Magi\" adorns King's College chapel", + "Answer": "Peter Paul Rubens" + }, + { + "Category": "LITERARY EPITAPHS", + "Question": "Died on safari after a short happy life. Placed here by his wife", + "Answer": "Francis Macomber" + }, + { + "Category": "\"CAR\" PARK", + "Question": "It's a swine-like hoofed animal of the Western Hemisphere", + "Answer": "Peccary" + }, + { + "Category": "FAMOUS WEDDINGS", + "Question": "In 1998 a 61-year-old piece of this couple's wedding cake sold for $26,000 at Sotheby's", + "Answer": "The Duke of Windsor& Wallis Simpson" + }, + { + "Category": "NICKNAMES", + "Question": "\"The Father of Pennsylvania\"", + "Answer": "William Penn" + }, + { + "Category": "SONG LYRICS", + "Question": "Evita sang, \"Don't\" do this \"for me Argentina -- the truth is I never left you\"", + "Answer": "Cry" + }, + { + "Category": "TRANSPORTATION", + "Question": "In 1830 England's Manchester & Liverpool Railway became the 1st to have all trains powered by this", + "Answer": "Steam" + }, + { + "Category": "CITY FLAGS", + "Question": "This Spanish mission & a star are depicted on San Antonio's flag", + "Answer": "The Alamo" + }, + { + "Category": "FANTASTIC FILMS", + "Question": "Marty McFly traveled back to 1955 in a souped-up DeLorean in this 1985 film", + "Answer": "\"Back To The Future\"" + }, + { + "Category": "\"TABLE\"S", + "Question": "Ping-Pong", + "Answer": "Table Tennis" + }, + { + "Category": "NICKNAMES", + "Question": "\"The King of Ragtime\"", + "Answer": "Scott Joplin" + }, + { + "Category": "SONG LYRICS", + "Question": "When he's \"Hoppin' down the bunny trail, hippity hoppin' Easter's on its way\"", + "Answer": "Peter Cottontail" + }, + { + "Category": "TRANSPORTATION", + "Question": "This light Russian sleigh is pulled by 3 horses", + "Answer": "Troika" + }, + { + "Category": "CITY FLAGS", + "Question": "The 4 stars appearing on this city's flag stand for Fort Dearborn, a fire & 2 World's Fairs", + "Answer": "Chicago" + }, + { + "Category": "FANTASTIC FILMS", + "Question": "This huge creature 1st waddled through Tokyo & its suburbs in 1956", + "Answer": "Godzilla" + }, + { + "Category": "\"TABLE\"S", + "Question": "A menu for the subject matter of a book usually placed before the text", + "Answer": "Table of Contents" + }, + { + "Category": "NICKNAMES", + "Question": "\"Schnozzola\"", + "Answer": "Jimmy Durante" + }, + { + "Category": "SONG LYRICS", + "Question": "The woman who \"cries the whole night long; he was my man but he done me wrong' \"", + "Answer": "Frankie" + }, + { + "Category": "TRANSPORTATION", + "Question": "The 1st of these high-speed German highways was opened between Cologne & Bonn in 1932", + "Answer": "Autobahn" + }, + { + "Category": "CITY FLAGS", + "Question": "The Y-shaped design on this city's flag represents the convergence of the Mississippi & Missouri rivers", + "Answer": "St. Louis" + }, + { + "Category": "FANTASTIC FILMS", + "Question": "Steve Martin is a scientist who falls in love with a brain -- hence this title", + "Answer": "\"The Man With Two Brains\"" + }, + { + "Category": "\"TABLE\"S", + "Question": "Moving around a restaurant to hobnob & exchange gossip with friends & acquaintances", + "Answer": "Table Hopping" + }, + { + "Category": "NICKNAMES", + "Question": "\"The Handcuff King\"", + "Answer": "Harry Houdini" + }, + { + "Category": "SONG LYRICS", + "Question": "\"When I dream about the moonlight on\" this river, \"then I long for my Indiana home\"", + "Answer": "The Wabash" + }, + { + "Category": "TRANSPORTATION", + "Question": "Smaller than a junk, this Oriental boat usually has a cabin with a roof made of mats", + "Answer": "Sampan" + }, + { + "Category": "CITY FLAGS", + "Question": "A steamboat & a cotton plant appear on this Tennessee's city flag", + "Answer": "Memphis" + }, + { + "Category": "FANTASTIC FILMS", + "Question": "Means by which Jack the Ripper & H.G. Wells get to 1970s San Francisco in \"Time After Time\"", + "Answer": "Time Machine" + }, + { + "Category": "\"TABLE\"S", + "Question": "To reverse the situation & gain the upper hand", + "Answer": "Turn the Tables" + }, + { + "Category": "NICKNAMES", + "Question": "\"The Belle of Amherst\"", + "Answer": "Emily Dickinson" + }, + { + "Category": "SONG LYRICS", + "Question": "John Denver's 2-word description of West Virginia in the 1st line of \"Take Me Home, Country Roads\"", + "Answer": "Almost Heaven" + }, + { + "Category": "TRANSPORTATION", + "Question": "Surprisingly, the Cadillac Motor Car Co. was founded by & originally named for this man", + "Answer": "Henry Ford" + }, + { + "Category": "CITY FLAGS", + "Question": "Its flag features a pioneer family, a covered wagon & 2 sea gulls", + "Answer": "Salt Lake City" + }, + { + "Category": "FANTASTIC FILMS", + "Question": "Futuristic S. Kubrick film starring M. McDowell as Alex, a psychopathic gang leader", + "Answer": "\"A Clockwork Orange\"" + }, + { + "Category": "\"TABLE\"S", + "Question": "If you can still walk while your buddy is falling down intoxicated, you have done this to him", + "Answer": "Drink him under the table" + }, + { + "Category": "PRESIDENTIAL TRIVIA", + "Question": "He was our country's 1st blue-eyed president", + "Answer": "George Washington" + }, + { + "Category": "1984", + "Question": "After a lengthy hiatus, Garry Trudeau brought this strip back to 810 daily papers", + "Answer": "\"Doonesbury\"" + }, + { + "Category": "AMERICAN PLAYS", + "Question": "\"I'm Not Rappaport\" takes place on a battered bench near the lake in this famous park", + "Answer": "Central Park" + }, + { + "Category": "MAGAZINES", + "Question": "It's published by Gruner & Jahr, not by mom & dad as its name implies", + "Answer": "Parents' Magazine" + }, + { + "Category": "MUSICAL INSTRUMENTS", + "Question": "A little larger than the violin, it's the alto or tenor of the family", + "Answer": "Viola" + }, + { + "Category": "CHAIRS", + "Question": "The French version of a day bed, the chaise longue, literallly means this", + "Answer": "Long Chair" + }, + { + "Category": "PRESIDENTIAL TRIVIA", + "Question": "He won the presidency with help from a song called \"Grandfather's Hat Fits Ben\"", + "Answer": "Benjamin Harrison" + }, + { + "Category": "1984", + "Question": "This science fact & fiction writer published his 300th book which he called \"Opus 300\"", + "Answer": "Isaac Asimov" + }, + { + "Category": "AMERICAN PLAYS", + "Question": "The play in which Amanda says, \"I want you to stay fresh and pretty -- for gentleman callers.\"", + "Answer": "\"The Glass Menagerie\"" + }, + { + "Category": "MAGAZINES", + "Question": "Final Frontier is \"The magazine of\" this kind of \"exploration\"", + "Answer": "Space" + }, + { + "Category": "MUSICAL INSTRUMENTS", + "Question": "Phil Collins once said, \"Whatever else I am, I'm\" one of these \"first\"", + "Answer": "A Drummer" + }, + { + "Category": "CHAIRS", + "Question": "A collapsible chair intended for outdoor use, especially aboard a ship", + "Answer": "Deck Chair" + }, + { + "Category": "PRESIDENTIAL TRIVIA", + "Question": "One of Reagan's last official acts as president was writing a thank-you note to this world leader", + "Answer": "Margaret Thatcher" + }, + { + "Category": "1984", + "Question": "The Boston Symphony had to pay this actress $100,000 for canceling her contract due to her PLO support", + "Answer": "Vanessa Redgrave" + }, + { + "Category": "AMERICAN PLAYS", + "Question": "Lee Strasberg played the original peddler in this 1931 play which inspired \"Oklahoma!\"", + "Answer": "\"Green Grow The Lilacs\"" + }, + { + "Category": "MAGAZINES", + "Question": "Comparing itself to People, this magazine says it reaches \"A better class of people\"", + "Answer": "Us" + }, + { + "Category": "MUSICAL INSTRUMENTS", + "Question": "You insert a roll into this instrument for it to tickle its own ivories", + "Answer": "Player Piano" + }, + { + "Category": "PRESIDENTIAL TRIVIA", + "Question": "2 of the 7 men who were under 50 years old when they became president", + "Answer": "Cleveland, Garfield, Grant, JFK, Pierce, Polk & Teddy Roosevelt" + }, + { + "Category": "1984", + "Question": "98% of voters in Pakistan elected this leader killed 4 years later in a plane crash", + "Answer": "Zia Ul-Haq" + }, + { + "Category": "AMERICAN PLAYS", + "Question": "This playwright dedicated \"A Delicate Balance\" to J. Steinbeck with \"affection and admiration\"", + "Answer": "Edward Albee" + }, + { + "Category": "MAGAZINES", + "Question": "This magazine's \"Transition\" column features birth, marriage, divorce & death announcements", + "Answer": "Newsweek" + }, + { + "Category": "MUSICAL INSTRUMENTS", + "Question": "From the Greek \"psallein\", to pluck, we get this plucked type of zither that's mentioned in the Bible", + "Answer": "Psalterion" + }, + { + "Category": "CHAIRS", + "Question": "Also called a slat-back chair, this chair is named for an object you might climb", + "Answer": "Ladder-Back Chair" + }, + { + "Category": "PRESIDENTIAL TRIVIA", + "Question": "1 of the 2 presidents who could have used the Pony Express while in office", + "Answer": "Buchanan & Lincoln" + }, + { + "Category": "1984", + "Question": "In December this founder of est announced that he was giving last of his weekend transformation sessions", + "Answer": "Werner Erhardt" + }, + { + "Category": "AMERICAN PLAYS", + "Question": "He revised his 1st play, \"Farther Off From Heaven\", & retitled it \"The Dark At The Top Of The Stairs\"", + "Answer": "William Inge" + }, + { + "Category": "MAGAZINES", + "Question": "This founder of Weight Watchers is a cosulting editor of Weight Watchers magazine", + "Answer": "Jean Nidetch" + }, + { + "Category": "MUSICAL INSTRUMENTS", + "Question": "For his set of pipes, the god Pan cut this into different lengths & strapped them in a row", + "Answer": "Reeds" + }, + { + "Category": "CHAIRS", + "Question": "He not only designed the Gateway Arch, he created furniture such as the sculptured \"Womb\" chair", + "Answer": "Eero Saarinen" + }, + { + "Category": "WORLD HISTORY", + "Question": "City that was the seat of government of the viceroyalty of New Spain", + "Answer": "Mexico City" + }, + { + "Category": "LITERARY ANIMALS", + "Question": "Cadpig was the smallest & prettiest of Pongo's 15 puppies in this 1956 Dodie Smith novel", + "Answer": "\"101 Dalmatians\"" + }, + { + "Category": "NO. 3 SONGS", + "Question": "The Beatles sang that he \"doesn't have a point of view, knows not where he's going to\"", + "Answer": "\"Nowhere Man\"" + }, + { + "Category": "HOTELS", + "Question": "Le Champollion is the gourmet restaurant of this city's Le Meridien Hotel, on an island in the Nile", + "Answer": "Cairo" + }, + { + "Category": "BERRIES", + "Question": "It's \"hound\"ed by its resemblance to the blueberry, but it has fewer seeds", + "Answer": "Huckleberry" + }, + { + "Category": "PSYCHOLOGICAL PROBLEMS", + "Question": "Just because you have this pervasive suspicion of others, doesn't mean they're not out to get you", + "Answer": "Paranoia" + }, + { + "Category": "THE SHORT VERSION", + "Question": "A translation of the Bible: KJV", + "Answer": "King James Version" + }, + { + "Category": "LITERARY ANIMALS", + "Question": "Cottontail & these 2 \"went down the lane to gather blackberries\" in \"The Tale of Peter Rabbit\"", + "Answer": "Flopsy & Mopsy" + }, + { + "Category": "NO. 3 SONGS", + "Question": "Her \"True Blue\" peaked at No. 3 just a few weeks after \"Papa Don't Preach\" topped the charts", + "Answer": "Madonna" + }, + { + "Category": "HOTELS", + "Question": "(Hi, I'm Brad Garrett of \"Everybody Loves Raymond\") I opened for Frank Sinatra at this Vegas hotel, now closed, where the Rat Pack held a \"summit\" in 1960", + "Answer": "Sands" + }, + { + "Category": "BERRIES", + "Question": "The berry of this unassuming shrub produces the oil commonly used to flavor gin", + "Answer": "Juniper/sloe" + }, + { + "Category": "PSYCHOLOGICAL PROBLEMS", + "Question": "Maybe Alfred Adler didn't think he was good enough when he identified & named this complex", + "Answer": "Inferiority complex" + }, + { + "Category": "THE SHORT VERSION", + "Question": "To a dog lover: ASPCA", + "Answer": "American Society for the Prevention of Cruelty to Animals" + }, + { + "Category": "LITERARY ANIMALS", + "Question": "This old grey donkey was Winnie-the-Pooh's friend who always saw things in a gloomy light", + "Answer": "Eeyore" + }, + { + "Category": "NO. 3 SONGS", + "Question": "Singer of the No. 3 hit heard here: (\"I Feel Good\")", + "Answer": "James Brown" + }, + { + "Category": "HOTELS", + "Question": "We'll tell you \"diplomatically\" that this L.A. hotel was the home of the Coconut Grove nightclub", + "Answer": "The Ambassador Hotel" + }, + { + "Category": "BERRIES", + "Question": "The tart, red cowberry is also called the \"mountain\" type of this berry, it is likewise used for sauce", + "Answer": "Cranberry" + }, + { + "Category": "PSYCHOLOGICAL PROBLEMS", + "Question": "This self-absorbed personality disorder is named for a mythical youth who loved his reflection", + "Answer": "Narcissism" + }, + { + "Category": "THE SHORT VERSION", + "Question": "A women's society: DAR", + "Answer": "Daughters of the American Revolution" + }, + { + "Category": "LITERARY ANIMALS", + "Question": "This brown bear in Kipling's \"The Jungle Book\" taught the wolf cubs the law of the jungle & was later Mowgli's teacher", + "Answer": "Baloo" + }, + { + "Category": "NO. 3 SONGS", + "Question": "In 1985 David Lee Roth reached No. 3 with \"California Girls\", 20 years after this group did the same", + "Answer": "The Beach Boys" + }, + { + "Category": "HOTELS", + "Question": "The most famous hotel of this Canadian city is seen here: (Chateau Frontenac)", + "Answer": "Quebec City" + }, + { + "Category": "BERRIES", + "Question": "A judge crossed California & Texas blackberries & created these which bear his name", + "Answer": "Loganberries" + }, + { + "Category": "PSYCHOLOGICAL PROBLEMS", + "Question": "Logorrhea, also called verbomania, is doing this excessively or uncontrollably", + "Answer": "Speaking/talking" + }, + { + "Category": "THE SHORT VERSION", + "Question": "A paranormal \"experience\": OBE", + "Answer": "Out-of-body experience" + }, + { + "Category": "LITERARY ANIMALS", + "Question": "Anna Sewell wrote her only novel about this title animal as a plea for the proper care of horses", + "Answer": "\"Black Beauty\"" + }, + { + "Category": "NO. 3 SONGS", + "Question": "No. 3 Simon & Garfunkel hit that ends, \"And an island never cries\"", + "Answer": "\"I Am a Rock\"" + }, + { + "Category": "HOTELS", + "Question": "He opened his own hotel in Paris in 1898 & soon started running the Carlton in London", + "Answer": "Cesar Ritz" + }, + { + "Category": "BERRIES", + "Question": "This small berry shares its name with a dried fruit once shipped from Corinth", + "Answer": "Currant" + }, + { + "Category": "PSYCHOLOGICAL PROBLEMS", + "Question": "Washers & hoarders are types of people with OCD, which stands for this", + "Answer": "Obsessive compulsive disorder" + }, + { + "Category": "THE SHORT VERSION", + "Question": "To an infantryman: APC", + "Answer": "Armored personnel carrier" + }, + { + "Category": "WORLD CITIES", + "Question": "About 1 out of every 10 Japanese people lives in this city's metropolitan area", + "Answer": "Tokyo" + }, + { + "Category": "CONTESTS", + "Question": "134-pound Hirofumi Nakajima holds the record of eating 24 1/2 of these in 12 minutes at the Nathan's July 4th contest", + "Answer": "Hot dogs" + }, + { + "Category": "THE ASSASSIN'S VICTIM", + "Question": "44 B.C.: Casca & company", + "Answer": "Julius Caesar" + }, + { + "Category": "CHARLIE CHAPLIN", + "Question": "A 1915 film named for Charlie's most famous character was called simply this (no \"Little\")", + "Answer": "Tramp" + }, + { + "Category": "GOLD RUSH", + "Question": "In 1880 Joseph Juneau & Richard T. Harris found gold in the Gastineau Channel of this U.S. territory", + "Answer": "Alaska" + }, + { + "Category": "MODERN \"TIME\"S", + "Question": "Eastern, Central, Mountain, Pacific", + "Answer": "Time zones" + }, + { + "Category": "WORLD CITIES", + "Question": "In 1973 a highway bridge opened connecting the European & Asian parts of this Turkish city", + "Answer": "Istanbul" + }, + { + "Category": "CONTESTS", + "Question": "This cruise ship favorite played on a 52-foot court is an event at the National Senior Games", + "Answer": "Shuffleboard" + }, + { + "Category": "THE ASSASSIN'S VICTIM", + "Question": "1881: Charles Guiteau", + "Answer": "James Garfield" + }, + { + "Category": "CHARLIE CHAPLIN", + "Question": "Chaplin went on stage at age 5 in this type of \"hall\", the British equivalent of Vaudeville", + "Answer": "Music Hall" + }, + { + "Category": "GOLD RUSH", + "Question": "The Black Hills Gold Rush of 1874 spilled over into territory claimed by this Native American tribe", + "Answer": "Sioux" + }, + { + "Category": "MODERN \"TIME\"S", + "Question": "It's the \"Fox\"y TV spinoff seen here:", + "Answer": "The Time of Your Life" + }, + { + "Category": "WORLD CITIES", + "Question": "It served as Australia's capital from 1901 to 1927", + "Answer": "Melbourne" + }, + { + "Category": "CONTESTS", + "Question": "Theta Tau at Purdue holds a contest for convoluted machines in the spirit of this cartoonist", + "Answer": "Rube Goldberg" + }, + { + "Category": "THE ASSASSIN'S VICTIM", + "Question": "1984: Beant Singh & Satwant Singh", + "Answer": "Indira Gandhi" + }, + { + "Category": "CHARLIE CHAPLIN", + "Question": "Nigel Bruce of Dr. Watson fame played an impresario in this \"glowing\" 1952 Chaplin film", + "Answer": "Limelight" + }, + { + "Category": "GOLD RUSH", + "Question": "Tourists now rush to this man's 1839 Adobe Fort in Sacramento, California", + "Answer": "John Sutter" + }, + { + "Category": "MODERN \"TIME\"S", + "Question": "It's the parent company of CNN", + "Answer": "Time Warner" + }, + { + "Category": "WORLD CITIES", + "Question": "This Cairo suburb, near the Pyramids, is home to most of Egypt's motion picture industry", + "Answer": "Giza" + }, + { + "Category": "CONTESTS", + "Question": "In 1999 'N Sync performed at the 17th annual pageant to crown Miss this", + "Answer": "Miss Teen USA" + }, + { + "Category": "THE ASSASSIN'S VICTIM", + "Question": "1901: Leon Czolgosz", + "Answer": "William McKinley" + }, + { + "Category": "CHARLIE CHAPLIN", + "Question": "The last of Chaplin's 4 teenage brides was Oona, this playwright's daughter", + "Answer": "Eugene O'Neill" + }, + { + "Category": "GOLD RUSH", + "Question": "An 1859 gold strike brought miners to Cherry Creek, the site of this future state capital", + "Answer": "Denver" + }, + { + "Category": "MODERN \"TIME\"S", + "Question": "To own a property jointly with others & use it in common but at different times", + "Answer": "Time-share" + }, + { + "Category": "WORLD CITIES", + "Question": "Recife is called \"The Venice of\" this South American country", + "Answer": "Brazil" + }, + { + "Category": "CONTESTS", + "Question": "At the 1999 Westminster Dog Show, CH Loteki Supernatural Being won this award for matching the breed standard", + "Answer": "Best in Show" + }, + { + "Category": "THE ASSASSIN'S VICTIM", + "Question": "1170: Reginald Fitzurse & 3 other knights", + "Answer": "Thomas Becket" + }, + { + "Category": "CHARLIE CHAPLIN", + "Question": "Charlie made 35 films in about a year at this Mack Sennett studio", + "Answer": "Keystone Studios" + }, + { + "Category": "GOLD RUSH", + "Question": "Forty-niners from this European country were called Keskydees, a corruption of an oft-used phrase", + "Answer": "France" + }, + { + "Category": "MODERN \"TIME\"S", + "Question": "Bob Dylan's 1964 hit song about the inevitable passing of the years", + "Answer": "\"The Times They Are a-Changin'\"" + }, + { + "Category": "THE TONY AWARDS", + "Question": "(Hi, I'm Brian Dennehy) This man won a Tony for writing the Best Play of 1949 and I had the honor of presenting him with a Lifetime Achievement Tony in 1999", + "Answer": "Arthur Miller" + }, + { + "Category": "ENGLISH CLASS", + "Question": "When \"do not\" and \"should not\" are contracted, this mark of punctuation is used to show missing letters", + "Answer": "apostrophe" + }, + { + "Category": "I KNOW THAT SONG", + "Question": "\"Ding-Dong! The Witch is Dead!\" is a song from this famous movie", + "Answer": "The Wizard of Oz" + }, + { + "Category": "1999", + "Question": "In January 1999, 100 people in this job were sworn in as jurors at the president's impeachment trial", + "Answer": "U.S. senators" + }, + { + "Category": "BREAKFAST CEREALS", + "Question": "This \"fortunate\" cereal is \"magically delicious\"", + "Answer": "Lucky Charms" + }, + { + "Category": "A REALLY BIG CATEGORY", + "Question": "In 1934, a giant clam had yielded one of these gems with a diameter of 5 1/2 inches, weighing over 14 pounds", + "Answer": "pearl" + }, + { + "Category": "ENGLISH CLASS", + "Question": "This part of speech doesn't always end in \"ly\"; once, there & often are other examples", + "Answer": "adverb" + }, + { + "Category": "I KNOW THAT SONG", + "Question": "\"Whenever we go out, the people always shout, there goes\" this man", + "Answer": "John Jacob Jingleheimer Schmidt" + }, + { + "Category": "BREAKFAST CEREALS", + "Question": "This whole grain cereal from General Mills makes the rounds in frosted & honey nut as well as the original", + "Answer": "Cheerios" + }, + { + "Category": "HAT'S ALL, FOLKS", + "Question": "Proverbially, if you're crazy, you might be as \"mad as\" one of these makers of men's headwear", + "Answer": "hatter" + }, + { + "Category": "ENGLISH CLASS", + "Question": "Capt. Kirk's mission was \"to boldly go\" where no man had gone before, but he split one of these along the way", + "Answer": "an infinitive" + }, + { + "Category": "BREAKFAST CEREALS", + "Question": "Babe Ruth was one of the first athletes to endorse this \"Breakfast of Champions\"", + "Answer": "Wheaties" + }, + { + "Category": "A REALLY BIG CATEGORY", + "Question": "The Great Red Spot is a great big storm on this great big planet", + "Answer": "Jupiter" + }, + { + "Category": "ENGLISH CLASS", + "Question": "It's the indirect object of the sentence \"Carmen gave Jose a cookie\"", + "Answer": "Jose" + }, + { + "Category": "I KNOW THAT SONG", + "Question": "It's the title of the Christmas carol and the line that precedes \"sweetly singing o'er the plains\"", + "Answer": "\"Angels We Have Heard on High\"" + }, + { + "Category": "BREAKFAST CEREALS", + "Question": "If you pour it just right, you'll have \"26 tasty little letters in every bowl\" of this Post cereal", + "Answer": "Alpha-bits" + }, + { + "Category": "A REALLY BIG CATEGORY", + "Question": "At 3 1/2 million square miles, this largest desert could just about cover the United States", + "Answer": "Sahara" + }, + { + "Category": "HAT'S ALL, FOLKS", + "Question": "The ever-popular Bowler hat is named for William Bowler, the man who created it in 1850 in this country", + "Answer": "England" + }, + { + "Category": "ENGLISH CLASS", + "Question": "It's the third person plural objective case pronoun", + "Answer": "them" + }, + { + "Category": "I KNOW THAT SONG", + "Question": "Glory, hallelujah! \"His truth is marching on\" in this patriotic hymn", + "Answer": "\"Battle Hymn of the Republic\"" + }, + { + "Category": "1999", + "Question": "The native Inuit in this country got a new territory--Nunavut", + "Answer": "Canada" + }, + { + "Category": "BREAKFAST CEREALS", + "Question": "Watch \"dinosaur eggs\" hatch or hunt for \"treasure\" while warming your tummy with a bowl of this", + "Answer": "oatmeal" + }, + { + "Category": "A REALLY BIG CATEGORY", + "Question": "Until it met disaster in 1912, it was the largest & most luxurious passenger ship afloat", + "Answer": "Titanic" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "In \"Charlie and the Chocolate Factory\", he's the reclusive owner of the factory", + "Answer": "Willy Wonka" + }, + { + "Category": "BROADWAY", + "Question": "The musical \"Into the Woods\" is based on several fairy tales, including the one about this boy and his beanstalk", + "Answer": "Jack" + }, + { + "Category": "UP & ATOM", + "Question": "To study atoms you might use a scanning tunneling one of these", + "Answer": "microscope" + }, + { + "Category": "NATIONAL GEOGRAPHIC \"B\"", + "Question": "This city that served as capital of a united Germany in 1871 became the capital of a reunited Germayny in 1990", + "Answer": "Berlin" + }, + { + "Category": "HISTORY OLDER THAN YOU", + "Question": "Julius Caesar became the leader of this empire in 45 B.C. but was killed just one year later", + "Answer": "Roman" + }, + { + "Category": "LANGUAGE QUESTIONS", + "Question": "If you're in Naples & don't know Italian, ask \"Parla inglese?\" which means this", + "Answer": "\"Do you speak English?\"" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "He pretty much stopped treating people after his parrot Polynesia taught him how to talk to animals", + "Answer": "Dr. Dolittle" + }, + { + "Category": "BROADWAY", + "Question": "Inspired by classical myths, \"Metamorphosis\" tells of Orpheus, Alcyone & this king with the \"golden touch\"", + "Answer": "Midas" + }, + { + "Category": "UP & ATOM", + "Question": "In 1932 James Chadwick discovered these non-charged particles", + "Answer": "neutrons" + }, + { + "Category": "NATIONAL GEOGRAPHIC \"B\"", + "Question": "The northern terminus of China's Grand Canal is located in this major city", + "Answer": "Beijing" + }, + { + "Category": "HISTORY OLDER THAN YOU", + "Question": "Around 1200 B.C. this Biblical man led his people to Canaan after their escape from slavery", + "Answer": "Moses" + }, + { + "Category": "LANGUAGE QUESTIONS", + "Question": "\"Donde está el baño?\" is Spanish for \"where is\" this, sometimes discreetly called \"the facilities\"", + "Answer": "bathroom" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "Robinson Crusoe gave this name to a native he saved from cannibals on a certain day of the week", + "Answer": "Friday" + }, + { + "Category": "BROADWAY", + "Question": "Characters in this musical include a teacup called Chip & a clock named Cogsworth", + "Answer": "Beauty and the Beast" + }, + { + "Category": "UP & ATOM", + "Question": "Rather than in fixed orbits, these particles travel in shells or layers around the nucleus", + "Answer": "electrons" + }, + { + "Category": "NATIONAL GEOGRAPHIC \"B\"", + "Question": "This small western European country is known for quality carpets, cut diamonds & fine chocolates", + "Answer": "Belgium" + }, + { + "Category": "HISTORY OLDER THAN YOU", + "Question": "In 1347, this \"bubonic\" disease began in Europe; as many as one-third of the population would perish", + "Answer": "plague" + }, + { + "Category": "LANGUAGE QUESTIONS", + "Question": "If you see a cool t-shirt in a store in Poland, \"Kosztuje?\" is how you ask this", + "Answer": "\"How much does this cost?\"" + }, + { + "Category": "BROADWAY", + "Question": "The Phantom of the Opera wears a partial one of these on his face, probably because a full one is hard to sing through", + "Answer": "mask" + }, + { + "Category": "UP & ATOM", + "Question": "When a nucleus is split, it's called fission; when 2 nuclei combine, it's called this", + "Answer": "fusion" + }, + { + "Category": "NATIONAL GEOGRAPHIC \"B\"", + "Question": "The Vistula River flows north through Poland into this sea", + "Answer": "Baltic" + }, + { + "Category": "LANGUAGE QUESTIONS", + "Question": "In Latin, the \"5 W's\" are mostly Q's; quid means what, quare means why and quando means this", + "Answer": "when" + }, + { + "Category": "FICTIONAL CHARACTERS", + "Question": "In a 2001 tale by Alice Hoffman, Aquamarine is a beautiful & brokenhearted one of these creatures", + "Answer": "a mermaid" + }, + { + "Category": "BROADWAY", + "Question": "\"Thoroughly Modern Millie\" takes place during this \"roaring\" decade when flappers bobbed their hair", + "Answer": "1920s" + }, + { + "Category": "UP & ATOM", + "Question": "No matter what element they are in, they weigh the same & their total is an element's atomic number", + "Answer": "protons" + }, + { + "Category": "NATIONAL GEOGRAPHIC \"B\"", + "Question": "At the finals in 1999, I asked about a bridge linking the European & Asian parts of Turkey across this strait", + "Answer": "Bosporus" + }, + { + "Category": "HISTORY OLDER THAN YOU", + "Question": "Around 336 B.C., this \"great\" king of Macedonia began building an empire from Africa to India", + "Answer": "Alexander" + }, + { + "Category": "ANIMALS", + "Question": "What the Germans call a Bambusbar, we generally call this", + "Answer": "a panda bear" + }, + { + "Category": "1933", + "Question": "On February 15 this president-elect survived an assassination attempt by Giuseppe Zangara", + "Answer": "Franklin D. Roosevelt" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "To audition for this musical, Yul Brynner sang while sitting cross-legged on the floor", + "Answer": "\"The King And I\"" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "Autumn brings Choyo-No-Sekku or Chrysanthemum Day in this country", + "Answer": "Japan" + }, + { + "Category": "THE BODY HUMAN", + "Question": "Abbreviated TB, this disease is characterized by lesions in the lung tissue", + "Answer": "Tuberculosis" + }, + { + "Category": "CARDS & DICE", + "Question": "The winner of a game of War winds up with this many cards", + "Answer": "52" + }, + { + "Category": "BIBLICAL WORDS & PHRASES", + "Question": "\"Can the leopard change\" these? means \"it's impossible\"", + "Answer": "Its Spots" + }, + { + "Category": "1933", + "Question": "Federal judge John Woolsey lifted the ban on the importation & sale of this James Joyce book", + "Answer": "\"Ulysses\"" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "Their 1955 show, \"Pipe Dream\", about the people of Cannery Row, was based on this author's \"Sweet Thursday\"", + "Answer": "John Steinbeck" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "On this date Denmark's Rebild Park holds the largest foreign celebration of American independence", + "Answer": "4-Jul" + }, + { + "Category": "THE BODY HUMAN", + "Question": "The human body contains many of these: some are hinge, some are saddle, some are pivot types", + "Answer": "Joints" + }, + { + "Category": "CARDS & DICE", + "Question": "Instead of pips, poker dice have 6 card values on them that run 9 through this", + "Answer": "Ace" + }, + { + "Category": "BIBLICAL WORDS & PHRASES", + "Question": "To \"pass over\" this river means to reach the promised land", + "Answer": "Jordan River" + }, + { + "Category": "1933", + "Question": "The Glass-Steagall Act of 1933 established this corporation that guarantees the savings of bank customers", + "Answer": "FDIC" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "In 1994 this show about a carnival barker won 5 Tonys, including Best Musical Revival", + "Answer": "\"Carousel\"" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "National Freedom Day, February 1, celebrates the 13th Amendment, which abolished this", + "Answer": "Slavery" + }, + { + "Category": "THE BODY HUMAN", + "Question": "Blood leaves the heart from ventricles & enters the heart through these chambers", + "Answer": "Atria" + }, + { + "Category": "CARDS & DICE", + "Question": "It's a form of Authors for kids; playing it you may ask another player, \"Do you have any twos?\"", + "Answer": "Go Fish" + }, + { + "Category": "BIBLICAL WORDS & PHRASES", + "Question": "Unworthy or sinful people are known as a \"generation of\" these poisonous creatures", + "Answer": "Vipers" + }, + { + "Category": "1933", + "Question": "Known as the \"Little Flower\", he left the House of Representatives in 1933 & became mayor of NYC", + "Answer": "Fiorello LaGuardia" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "For 15 years, 1946-1961, this show set in Indian Territory was Broadway's longest-running musical", + "Answer": "\"Oklahoma!\"" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "Ecuador & Venezuela observe the birth of this \"George Washington of South America\" each July 24", + "Answer": "Simon Bolivar" + }, + { + "Category": "THE BODY HUMAN", + "Question": "This vitamin produced when the skin is exposed to sunlight is toxic in excess", + "Answer": "Vitamin D" + }, + { + "Category": "CARDS & DICE", + "Question": "The 4 players in bridge are given these directional titles", + "Answer": "North, South, East & West" + }, + { + "Category": "BIBLICAL WORDS & PHRASES", + "Question": "Robert Heinlein used this phrase from Exodus 2:22 as the title of one of his novels", + "Answer": "\"Stranger In A Strange Land\"" + }, + { + "Category": "1933", + "Question": "On March 23 this German parliament relinquished its power to Adolf Hitler", + "Answer": "Reichstag" + }, + { + "Category": "RODGERS & HAMMERSTEIN", + "Question": "Characters in this musical include Mei Li, Linda Low & Sammy Fong", + "Answer": "\"Flower Drum Song\"" + }, + { + "Category": "HOLIDAYS & OBSERVANCES", + "Question": "September 10 is St. George's Cay Day in this Central American country", + "Answer": "Belize" + }, + { + "Category": "THE BODY HUMAN", + "Question": "These corpuscles are named for their shape rather than for their color", + "Answer": "Platelets" + }, + { + "Category": "CARDS & DICE", + "Question": "It's the number of dice you toss on your first roll of Yahtzee", + "Answer": "5" + }, + { + "Category": "BIBLICAL WORDS & PHRASES", + "Question": "\"Pale Horse\" is a metaphor for the approach of this", + "Answer": "Death" + }, + { + "Category": "ROYALTY", + "Question": "This \"bonnie\" prince had a daughter by his mistress Clementina Walkinshaw", + "Answer": "\"Bonnie\" Prince Charlie" + }, + { + "Category": "FOOD", + "Question": "Some say these dried treats are tastier made from seeded grapes than from seedless ones", + "Answer": "Raisins" + }, + { + "Category": "BRITISH POETS & POETRY", + "Question": "Elizabeth Barrett mentioned this future husband in her poem \"Lady Geraldine's Courtship\" before they met", + "Answer": "Robert Browning" + }, + { + "Category": "BOXING MOVIES", + "Question": "Before starring on TV's \"Thunder In Paradise\", this \"Hulkster\" played Thunderlips in \"Rocky III\"", + "Answer": "Hulk Hogan" + }, + { + "Category": "NATIONAL PARKS OF THE WORLD", + "Question": "You can see this North American country's highest volcano, Volcan Citlaltepetl, in Pico de Orizaba National Park", + "Answer": "Mexico" + }, + { + "Category": "BEGINS & ENDS WITH \"T\"", + "Question": "A male feline", + "Answer": "Tomcat" + }, + { + "Category": "ROYALTY", + "Question": "In 1949 he succeeded his grandfather Prince Louis II as ruler of Monaco", + "Answer": "Prince Rainier" + }, + { + "Category": "FOOD", + "Question": "Chop Suey, cioppini & vichyssoise were all invented in this country", + "Answer": "U.S.A." + }, + { + "Category": "BRITISH POETS & POETRY", + "Question": "Prince Albert sent his copy of \"Idylls Of The King\" to this poet & asked him to autograph it", + "Answer": "Alfred Lord Tennyson" + }, + { + "Category": "BOXING MOVIES", + "Question": "He played Elvis' trainer in \"Kid Galahad\" a \"Dirty Dozen\" years before he starred in \"Death Wish\"", + "Answer": "Charles Bronson" + }, + { + "Category": "NATIONAL PARKS OF THE WORLD", + "Question": "This snowcapped mountain provides the backdrop for Kenya's Amboseli National Park", + "Answer": "Mt. Kilimanjaro" + }, + { + "Category": "BEGINS & ENDS WITH \"T\"", + "Question": "The name of this device used to stop bleeding may come from a French word for \"turn\"", + "Answer": "Tourniquet" + }, + { + "Category": "ROYALTY", + "Question": "In 1599, Albert, Archduke of Austria, married the Infanta of this country", + "Answer": "Spain" + }, + { + "Category": "FOOD", + "Question": "Juniper is used to smoke Germany's Westphalian form of this meat", + "Answer": "Ham" + }, + { + "Category": "BRITISH POETS & POETRY", + "Question": "Written in 1811, this lord's poem \"Farewell To Malta\" begins, \"Adieu, ye joys of La Valette!\"", + "Answer": "Lord Byron" + }, + { + "Category": "BOXING MOVIES", + "Question": "This platinum blonde was a real knockout as a prizefighter's scheming wife in the 1931 film \"Iron Man\"", + "Answer": "Jean Harlow" + }, + { + "Category": "NATIONAL PARKS OF THE WORLD", + "Question": "One of this country's major recreational areas is Vitosha National Park near Sofia", + "Answer": "Bulgaria" + }, + { + "Category": "BEGINS & ENDS WITH \"T\"", + "Question": "One who plays hooky from school might find himself pursued by this type of officer", + "Answer": "Truant officer" + }, + { + "Category": "ROYALTY", + "Question": "This dreaded czar who died in 1584 was probably the most famous member of the Rurik dynasty", + "Answer": "Ivan The Terrible" + }, + { + "Category": "FOOD", + "Question": "Riz A L'Imperatrice is an elegant version of this homey dessert", + "Answer": "Rice Pudding" + }, + { + "Category": "BRITISH POETS & POETRY", + "Question": "In \"I Wandered Lonely as a Cloud\", Wordsworth wrote about \"A crowd, a host of golden\" ones", + "Answer": "daffodils" + }, + { + "Category": "BOXING MOVIES", + "Question": "Jack Palance starred in the TV version of this \"heavy\" Rod Serling drama; Anthony Quinn, in the film version", + "Answer": "\"Requiem For A Heavyweight\"" + }, + { + "Category": "NATIONAL PARKS OF THE WORLD", + "Question": "In Alberta the scenic Icefields Parkway connects Jasper National Park with this other one", + "Answer": "Banff" + }, + { + "Category": "BEGINS & ENDS WITH \"T\"", + "Question": "It's the period between sunset & dark when the sun is just below the horizon", + "Answer": "Twilight" + }, + { + "Category": "ROYALTY", + "Question": "After this emperor died in 14 A.D., his relatives, the Julio-Claudian dynasty, ruled until 68", + "Answer": "Augustus" + }, + { + "Category": "FOOD", + "Question": "The Bismarck type of this fish is made of fillets cured in vinegar, salt & onions", + "Answer": "Herring" + }, + { + "Category": "BRITISH POETS & POETRY", + "Question": "He called \"Prometheus Unbound\" \"The best thing I ever wrote\"", + "Answer": "Percy B. Shelley" + }, + { + "Category": "BOXING MOVIES", + "Question": "Based on Clifford Odets' play, this \"colorful\" 1939 film made William Holden a star", + "Answer": "Golden Boy" + }, + { + "Category": "NATIONAL PARKS OF THE WORLD", + "Question": "Argentina & Brazil have national parks to preserve the wildlife & beauty of these extensive waterfalls", + "Answer": "Iguazu Falls" + }, + { + "Category": "BEGINS & ENDS WITH \"T\"", + "Question": "The Roman god Jupiter used this weather phenomenon as a weapon, by jove", + "Answer": "Thunderbolt" + }, + { + "Category": "FAMOUS TEACHERS", + "Question": "In 1967 this former teacher published a memoir entitled \"Center of the Storm\"", + "Answer": "John Scopes" + }, + { + "Category": "LET'S MESS WITH TEXAS", + "Question": "Educated at Phillips Academy, Yale & Harvard, this part-time Crawford resident was born in Connecticut in 1946", + "Answer": "George W. Bush" + }, + { + "Category": "\"R\"OCK MUSIC", + "Question": "Title adjective describing Dion's \"Sue\"", + "Answer": "Runaround" + }, + { + "Category": "FEMINISM", + "Question": "Elizabeth Cady Stanton's cousin Elizabeth Smith Miller first wore these trousers named for another woman", + "Answer": "bloomers" + }, + { + "Category": "KHOMEINI, KHAMENEI OR KHATAMI", + "Question": "Exiled from Iran in 1964", + "Answer": "Khomeini" + }, + { + "Category": "A FLY CATEGORY", + "Question": "To WWI British aviators, the Red Baron's group with its colorful planes was one of these, like Monty Python's", + "Answer": "a Flying Circus" + }, + { + "Category": "2-LETTER ABBREV.", + "Question": "Your DL is a form of this; it shows who you are & how old you are", + "Answer": "ID" + }, + { + "Category": "LET'S MESS WITH TEXAS", + "Question": "Since 1935 this agency that originated in the 1820s has operated as a branch of the Texas Dept. of Public Safety", + "Answer": "the Texas Rangers" + }, + { + "Category": "\"R\"OCK MUSIC", + "Question": "The subject of this 1973 Allman Brothers hit was \"tryin' to make a livin' and doin' the best I can\"", + "Answer": "\"Ramblin' Man\"" + }, + { + "Category": "FEMINISM", + "Question": "Of 76, 86 or 96 cents, what U.S. women working full-time earn for every dollar their male counterparts make", + "Answer": "76 cents" + }, + { + "Category": "KHOMEINI, KHAMENEI OR KHATAMI", + "Question": "Died in 1989", + "Answer": "Khomeini" + }, + { + "Category": "A FLY CATEGORY", + "Question": "These BF Goodrich sneakers were said to make you \"run faster and jump higher\"", + "Answer": "PF Flyers" + }, + { + "Category": "2-LETTER ABBREV.", + "Question": "Randy Newman sang, \"Looks like another perfect day, I love\" this place", + "Answer": "L.A." + }, + { + "Category": "LET'S MESS WITH TEXAS", + "Question": "This state bird of Texas belongs to the family Mimidae", + "Answer": "the mockingbird" + }, + { + "Category": "\"R\"OCK MUSIC", + "Question": "UB40 sang that this makes me \"feel so fine, you keep me rocking all of the time\"", + "Answer": "Red Red Wine" + }, + { + "Category": "FEMINISM", + "Question": "Emmeline & Christabel Pankhurst were a mother-daughter team of these activists for the vote", + "Answer": "suffragettes" + }, + { + "Category": "KHOMEINI, KHAMENEI OR KHATAMI", + "Question": "Elected president in 1997", + "Answer": "Khatami" + }, + { + "Category": "A FLY CATEGORY", + "Question": "During World War II, a famous American volunteeer air corps in Asia was nicknamed this", + "Answer": "the Flying Tigers" + }, + { + "Category": "LET'S MESS WITH TEXAS", + "Question": "From 1846 to 1859 this ex-Tennessee governor was a U.S. senator from Texas", + "Answer": "Sam Houston" + }, + { + "Category": "\"R\"OCK MUSIC", + "Question": "This alternative rock band's \"Stand\" served as the theme song to the sitcom \"Get a Life\"", + "Answer": "R.E.M." + }, + { + "Category": "FEMINISM", + "Question": "The work of Laura X (no relation to Malcolm) led to March being designated this every year", + "Answer": "Women's History Month" + }, + { + "Category": "KHOMEINI, KHAMENEI OR KHATAMI", + "Question": "Supreme religious & political leader since 1990", + "Answer": "Khamenei" + }, + { + "Category": "A FLY CATEGORY", + "Question": "This rotating device attached to a shaft keeps an engine's speed steady", + "Answer": "a flywheel" + }, + { + "Category": "2-LETTER ABBREV.", + "Question": "Sadly, what Keats & Chopin died of", + "Answer": "TB" + }, + { + "Category": "LET'S MESS WITH TEXAS", + "Question": "Born in 1921, this Mission, Tex.-born senator served with Jack Kennedy, knew Jack Kennedy & hey! you're not Jack Kennedy!", + "Answer": "Lloyd Bentsen" + }, + { + "Category": "\"R\"OCK MUSIC", + "Question": "4 of this Swedish pop duo's first Top 40 hits reached No. 1, including \"It Must Have Been Love\"", + "Answer": "Roxette" + }, + { + "Category": "FEMINISM", + "Question": "The profession of Mary Prance in Henry James' 1886 \"The Bostonians\", it was about 1/5 female in Boston at the time", + "Answer": "a physician" + }, + { + "Category": "KHOMEINI, KHAMENEI OR KHATAMI", + "Question": "Published \"Fear of the Wave\" in 1993", + "Answer": "Khatami" + }, + { + "Category": "A FLY CATEGORY", + "Question": "Airborne nickname of 1920s Olympic gold medalist Paavo Nurmi", + "Answer": "the Flying Finn" + }, + { + "Category": "2-LETTER ABBREV.", + "Question": "It's the famous apparel company founded by surfboard maker Jim Jenks in 1972", + "Answer": "OP" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "In Kazakhstan: Kazakh & this", + "Answer": "Russian" + }, + { + "Category": "CHEKHOV, PLEASE", + "Question": "The title characters of this Chekhov play also have a brother named Andrey", + "Answer": "The Three Sisters" + }, + { + "Category": "METALLICA", + "Question": "To buy this precious metal, visit Taxco, Mexico; it's the city's best-known product", + "Answer": "silver" + }, + { + "Category": "MASTER OF PUPPETS", + "Question": "Named for its early 19th century creator, bunraku is the traditional puppet theater of this country", + "Answer": "Japan" + }, + { + "Category": "FOR WHOM THE \"BELL\" TOLLS", + "Question": "Your occupation if you're a carillonneur", + "Answer": "a bell ringer" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "In San Marino: this", + "Answer": "Italian" + }, + { + "Category": "CHEKHOV, PLEASE", + "Question": "Chekhov's grandfather was one of these who had purchased the freedom of his family for 3,500 rubles", + "Answer": "a serf" + }, + { + "Category": "METALLICA", + "Question": "In 1984 the album \"Ride the Lightning\" by Metallica achieved this status of 500,000 copies sold", + "Answer": "gold" + }, + { + "Category": "MASTER OF PUPPETS", + "Question": "This 2004 Matt Stone & Trey Parker film featured risque marionettes", + "Answer": "Team America" + }, + { + "Category": "FOR WHOM THE \"BELL\" TOLLS", + "Question": "It's an Italian city about 40 miles north of Milan, or about 9,000 miles east of Las Vegas", + "Answer": "Bellagio" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "In Togo: this", + "Answer": "French" + }, + { + "Category": "CHEKHOV, PLEASE", + "Question": "The plot shows Mme. Ranevsky is the owner of this title Chekhov plot", + "Answer": "The Cherry Orchard" + }, + { + "Category": "METALLICA", + "Question": "This metal was discovered in 1789; it took until 1896 to find out that it was radioactive", + "Answer": "uranium" + }, + { + "Category": "MASTER OF PUPPETS", + "Question": "Dr. Bunsen Honeydew & this lab assistant were on \"The Muppet Show\"", + "Answer": "Beaker" + }, + { + "Category": "FOR WHOM THE \"BELL\" TOLLS", + "Question": "Doing this, you'll hold pairs of small cymbals called zills", + "Answer": "belly dancing" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "In Sri Lanka: Sinhala & this", + "Answer": "Tamil" + }, + { + "Category": "CHEKHOV, PLEASE", + "Question": "An 1888 collection of Chekhov's stories won him the prize named for this writer & compatriot", + "Answer": "Pushkin" + }, + { + "Category": "METALLICA", + "Question": "A policeman could tell you the U.S. half dollar today is about 92% this metal", + "Answer": "copper" + }, + { + "Category": "MASTER OF PUPPETS", + "Question": "This evil puppet master from \"Pinocchio\" shared his name with a volcanic island near Sicily", + "Answer": "Stromboli" + }, + { + "Category": "FOR WHOM THE \"BELL\" TOLLS", + "Question": "Facial nerve paralysis on one side", + "Answer": "Bell's palsy" + }, + { + "Category": "OFFICIAL LANGUAGES", + "Question": "In Guinea-Bissau: this", + "Answer": "Portuguese" + }, + { + "Category": "CHEKHOV, PLEASE", + "Question": "He's known more formally as Ivan Voynitsky", + "Answer": "Uncle Vanya" + }, + { + "Category": "METALLICA", + "Question": "Among coinage metals, this one, atomic number 28, is only a fair conductor of electricity", + "Answer": "nickel" + }, + { + "Category": "MASTER OF PUPPETS", + "Question": "Set in a Washington bar, this satirical political TV show was populated by puppets from Sid & Marty Krofft", + "Answer": "D.C. Follies" + }, + { + "Category": "FOR WHOM THE \"BELL\" TOLLS", + "Question": "Nobel-winning creator of Herzog & Sammler", + "Answer": "Saul Bellow" + }, + { + "Category": "20th CENTURY AMERICANS", + "Question": "He was alive for the Wright Brothers' historic flight & was John Glenn's Senate colleague when Glenn returned to space", + "Answer": "Strom Thurmond" + }, + { + "Category": "AFRICANA", + "Question": "The southern part of Africa is often called \"Sub-\" this 3 1/2-million-square-mile area", + "Answer": "Sahara" + }, + { + "Category": "BIBLICAL CRIME BLOTTER", + "Question": "This woman is wanted in connection with stolen hair & the kidnapping of her boyfriend by Philistines", + "Answer": "Delilah" + }, + { + "Category": "ARCHITECTS", + "Question": "In 1805 Charles Bulfinch enlarged this city's Faneuil Hall", + "Answer": "Boston" + }, + { + "Category": "SELLERS", + "Question": "Founded in 1957, Dialamerica, Inc. is the USA's largest private company in this type of marketing", + "Answer": "Telemarketing" + }, + { + "Category": "THE DAY THE MUSIC DIED", + "Question": "August 16, 1977 in Memphis, Tennessee", + "Answer": "Elvis Presley" + }, + { + "Category": "\"LAP\" DANCE", + "Question": "It's the continuation of the suit coat's collar", + "Answer": "Lapel" + }, + { + "Category": "AFRICANA", + "Question": "The country's name is properly pronounced \"Luh-Soo-Too\", but is spelled this way", + "Answer": "L-E-S-O-T-H-O" + }, + { + "Category": "BIBLICAL CRIME BLOTTER", + "Question": "Wanted in the case of fruit missing from the forbidden tree, this animal is considered long & dangerous", + "Answer": "Snake/serpent" + }, + { + "Category": "ARCHITECTS", + "Question": "Canberra designer Walter Burley Griffin served as this American architect's assistant from 1901 to 1906", + "Answer": "Frank Lloyd Wright" + }, + { + "Category": "SELLERS", + "Question": "Harry Bogen is the dressmaker hero of the musical \"I Can Get It for You\" this way", + "Answer": "Wholesale" + }, + { + "Category": "THE DAY THE MUSIC DIED", + "Question": "December 8, 1980 in New York City", + "Answer": "John Lennon" + }, + { + "Category": "\"LAP\" DANCE", + "Question": "A region of northern Scandinavia or Russia", + "Answer": "Lapland" + }, + { + "Category": "AFRICANA", + "Question": "In 2000 Durban in this country hosted the 13th International AIDS Conference & the first held on the continent", + "Answer": "South Africa" + }, + { + "Category": "BIBLICAL CRIME BLOTTER", + "Question": "This Egyptian crime boss is wanted in connection with ordering the death of all male Jewish children", + "Answer": "Pharaoh" + }, + { + "Category": "ARCHITECTS", + "Question": "Richard Hunt, the first American to attend the Ecole des Beaux-Arts, designed this statue's stone-&-concrete pedestal", + "Answer": "Statue of Liberty" + }, + { + "Category": "SELLERS", + "Question": "[Hi, I'm Jeff Bezos, founder & CEO of Amazon.com] It's estimated that 60% of net shoppers flag an average of 7 sites with one of these, also used in products we sell", + "Answer": "Bookmarks" + }, + { + "Category": "THE DAY THE MUSIC DIED", + "Question": "September 18, 1970 in London", + "Answer": "Jimi Hendrix" + }, + { + "Category": "\"LAP\" DANCE", + "Question": "The type of filmmaking seen here", + "Answer": "Time-lapse photography" + }, + { + "Category": "AFRICANA", + "Question": "A lion subspecies shares its name with these nomadic people of Tanzania & Kenya", + "Answer": "Masai" + }, + { + "Category": "BIBLICAL CRIME BLOTTER", + "Question": "Wife of Ahab, this Baal worshiper & harlot was last seen in Jezreel", + "Answer": "Jezebel" + }, + { + "Category": "ARCHITECTS", + "Question": "Cass Gilbert designed this merchant's NYC skyscraper for 270,000,000 nickels or 135,000,000 dimes", + "Answer": "F.W. Woolworth" + }, + { + "Category": "SELLERS", + "Question": "In 1978 Campbell Soup bought this pickle producer famous for its stork symbol", + "Answer": "Vlasic Foods" + }, + { + "Category": "THE DAY THE MUSIC DIED", + "Question": "July 3, 1971 in Paris", + "Answer": "Jim Morrison" + }, + { + "Category": "\"LAP\" DANCE", + "Question": "Perry Farrell of Jane's Addiction & Porno for Pyros founded this mega-concert event", + "Answer": "Lollapalooza" + }, + { + "Category": "AFRICANA", + "Question": "Meaning \"guided one\", it was the title of the 1880s Sudanese leader whose forces defeated General Gordon", + "Answer": "The Mahdi" + }, + { + "Category": "BIBLICAL CRIME BLOTTER", + "Question": "Wanted for treason against King David, he's known to have killed his half-brother for raping Tamar", + "Answer": "Absalom" + }, + { + "Category": "ARCHITECTS", + "Question": "Albert Speer, who designed a stadium for this city, was convicted of war crimes in trials there", + "Answer": "Nuremberg" + }, + { + "Category": "SELLERS", + "Question": "Strangely, this \"colorful\" German company sells its classic travel alarm clocks only in black & white", + "Answer": "Braun" + }, + { + "Category": "THE DAY THE MUSIC DIED", + "Question": "August 9, 1995 in Forest Knolls, California", + "Answer": "Jerry Garcia" + }, + { + "Category": "\"LAP\" DANCE", + "Question": "Take your gemstones to this specialist to have them cut & polished", + "Answer": "Lapidary" + }, + { + "Category": "THE KOREAN WAR", + "Question": "The first division of this U.S. fighting force spearheaded the landing at Inchon", + "Answer": "Marines" + }, + { + "Category": "TUBE TEST", + "Question": "David Janssen had a 4-year \"run\" in this series; Tim Daly hopes for at least that in the remake", + "Answer": "The Fugitive" + }, + { + "Category": "HOLD THE MAYO CLINIC", + "Question": "The Mayo Clinic was started in Rochester in this state", + "Answer": "Minnesota" + }, + { + "Category": "TRAIN STATIONS", + "Question": "In the movie \"The Clock\", Judy Garland finds love in this \"stately\" NYC station", + "Answer": "Penn Station" + }, + { + "Category": "MEDIEVAL MUSIC", + "Question": "In 950 this instrument in Winchester Cathedral needed 70 men to work the bellows", + "Answer": "Organ" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Singer of \"My Cherie Amour\" whose secret identity is Diana Prince", + "Answer": "Stevie Wonder Woman" + }, + { + "Category": "THE KOREAN WAR", + "Question": "His reaction to the North's invasion was \"Dean, we've got to stop the blanks of blanks no matter what\"", + "Answer": "Harry S. Truman" + }, + { + "Category": "TUBE TEST", + "Question": "This spin-off spun off a show of its own, \"Checking In\", with Marla Gibbs continuing as Florence Johnston", + "Answer": "The Jeffersons" + }, + { + "Category": "HOLD THE MAYO CLINIC", + "Question": "In 1914 Mayo isolated the pure hormone thyroxin, made by this gland", + "Answer": "Thyroid gland" + }, + { + "Category": "TRAIN STATIONS", + "Question": "St. Petersburg's Finland Station is famous as the site of this leader's return to Russia in 1917", + "Answer": "Lenin" + }, + { + "Category": "MEDIEVAL MUSIC", + "Question": "The Minnesingers were this present-day country's counterpart of France's troubadours", + "Answer": "Germany" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Morticia gets a big wet one from Richard Dawson on this ooky game show", + "Answer": "The Addams Family Feud" + }, + { + "Category": "THE KOREAN WAR", + "Question": "In 1950 Gen. Walton Walker, the main U.S. field commander, was killed riding in this type of vehicle", + "Answer": "Jeep" + }, + { + "Category": "TUBE TEST", + "Question": "He provides the voice for Thurgood Stubbs on \"The P.J.s\"", + "Answer": "Eddie Murphy" + }, + { + "Category": "HOLD THE MAYO CLINIC", + "Question": "In 1950 Mayo doctors Edward Kendall & Philip Hench won the Nobel Prize for their work with this steroid", + "Answer": "Cortizone" + }, + { + "Category": "TRAIN STATIONS", + "Question": "This capital city's main train station is known as Bahnhof Zoo, & not just at rush hour", + "Answer": "Berlin" + }, + { + "Category": "MEDIEVAL MUSIC", + "Question": "Guido D'Arezzo established the series of lines now called this as the basis of musical notation", + "Answer": "Staff" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Star of \"The Exorcist\" who disappears from the Maryland woods in a scary 1999 film", + "Answer": "Linda Blair Witch Project" + }, + { + "Category": "THE KOREAN WAR", + "Question": "In bitter battles of 1951, Pork Chop was a hill & Heartbreak was one of these", + "Answer": "Ridge" + }, + { + "Category": "TUBE TEST", + "Question": "\"Happy Days\" was spun off from a segment on this \"Love\"ly comedy anthology show of the '70s", + "Answer": "Love, American Style" + }, + { + "Category": "HOLD THE MAYO CLINIC", + "Question": "The Mayo-Gibbon bypass machine assumes the functions of these 2 different organs", + "Answer": "Heart & lung" + }, + { + "Category": "TRAIN STATIONS", + "Question": "Sherlock Holmes often left London from this station that shares its name with a battle", + "Answer": "Waterloo Station" + }, + { + "Category": "MEDIEVAL MUSIC", + "Question": "From 590 to 604 this type of music would have gotten a Papal Choice Award", + "Answer": "Gregorian Chant" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Louisa May Alcott & relationship guru John Gray collaborated on this book sequel", + "Answer": "Little Men are from Mars, Women are from Venus" + }, + { + "Category": "THE KOREAN WAR", + "Question": "The sound of a Commie submachine gun as it \"belched\" out bullets gave it this nickname", + "Answer": "\"Burp Gun\"" + }, + { + "Category": "TUBE TEST", + "Question": "We have to cop to the fact he created \"Police Story\"; \"The Blue Knight\" was based on one of his books", + "Answer": "Joseph Wambaugh" + }, + { + "Category": "HOLD THE MAYO CLINIC", + "Question": "In 1973 Mayo introduced to North America this scanner that uses a computer & X-rays", + "Answer": "CT scanner" + }, + { + "Category": "TRAIN STATIONS", + "Question": "A real depot inspired the symbol of this Wisconsin insurance company, seen here", + "Answer": "Wausau" + }, + { + "Category": "MEDIEVAL MUSIC", + "Question": "A 13th century hit tells us this \"is icumen in\"", + "Answer": "Summer" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Dystopian Anthony Burgess novel that's a New Zealand fish", + "Answer": "A Clockwork Orange Roughy" + }, + { + "Category": "CONTEMPORARY BRITISH AUTHORS", + "Question": "In May 1973 Sports Illustrated ran one of his short stories under the title \"A Day of Wine and Roses\"", + "Answer": "Dick Francis" + }, + { + "Category": "THE UNIVERSE", + "Question": "This planet's atmosphere is 99% nitrogen & oxygen", + "Answer": "Earth" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Diaphanous or sheer, as in clothing, or flimsy & obvious, as in a lie", + "Answer": "Transparent" + }, + { + "Category": "FOOD FACTS", + "Question": "The name of this meat is from the Latin \"venatus\", hunt", + "Answer": "Venison" + }, + { + "Category": "BASEBALL", + "Question": "Though he's had 5 no-hitters & the most career strikeouts of any pitcher, he's never won the Cy Young Award", + "Answer": "Nolan Ryan" + }, + { + "Category": "MOVIE MUSICALS", + "Question": "As the master of ceremonies, this actor was the only one to reprise his stage role in 1972's \"Cabaret\"", + "Answer": "Joel Grey" + }, + { + "Category": "DON'T TRY THIS AT HOME", + "Question": "Elizabeth I reportedly whitened this with a mixture of eggshell, poppy seeds, borax & lead", + "Answer": "Her Complexion" + }, + { + "Category": "THE UNIVERSE", + "Question": "It wasn't until 1959 that the \"far side\" of this body was seen", + "Answer": "The Moon" + }, + { + "Category": "11-LETTER WORDS", + "Question": "Breathing in & out", + "Answer": "Respiration" + }, + { + "Category": "FOOD FACTS", + "Question": "Known botanically as \"citrullus lanatus\", this huge fruit grows on vines as long as 15 ft.", + "Answer": "Watermelon" + }, + { + "Category": "BASEBALL", + "Question": "The \"Black Sox\" team that threw the 1919 World Series lost to this Ohio team", + "Answer": "Cincinnati Reds" + }, + { + "Category": "MOVIE MUSICALS", + "Question": "Actor who sang \"If I Only Had The Nerve\" & \"If I Were King Of The Forest\" in \"The Wizard Of Oz\"", + "Answer": "Bert Lahr" + }, + { + "Category": "DON'T TRY THIS AT HOME", + "Question": "Houdini was famous for hanging upside-down wearing one of these restrictive overgarments", + "Answer": "Straitjacket" + }, + { + "Category": "THE UNIVERSE", + "Question": "William Herschel thought he saw these around Uranus in 1787; in 1977 they were really seen", + "Answer": "Rings" + }, + { + "Category": "11-LETTER WORDS", + "Question": "The scientific study of birds", + "Answer": "Ornithology" + }, + { + "Category": "FOOD FACTS", + "Question": "Veal cutlets dipped in bread crumbs & cheese, then fried & covered with tomato sauce", + "Answer": "Veal Parmigiana" + }, + { + "Category": "BASEBALL", + "Question": "In Los Angeles, the Dodgers have had only these 2 managers", + "Answer": "Walter Alston & Tommy Lasorda" + }, + { + "Category": "MOVIE MUSICALS", + "Question": "The only Ginger Rogers-Fred Astaire film for which these 2 brothers wrote songs was 1937's \"Shall We Dance\"", + "Answer": "George & Ira Gershwin" + }, + { + "Category": "DON'T TRY THIS AT HOME", + "Question": "You have to have permission to do this in a barrel since someone died doing it in 1951", + "Answer": "Going over Niagara Falls" + }, + { + "Category": "THE UNIVERSE", + "Question": "It's known for its prominences which are clouds, tubes & tongues of gasses", + "Answer": "The Sun" + }, + { + "Category": "11-LETTER WORDS", + "Question": "A fashion or fad maker", + "Answer": "Trendsetter" + }, + { + "Category": "FOOD FACTS", + "Question": "German sausage named for the crackling sound the skin of the sausage makes when bitten into", + "Answer": "Knockwurst" + }, + { + "Category": "BASEBALL", + "Question": "In 1961 owner Calvin Griffith moved this team to Minneapolis where it became the Minnesota Twins", + "Answer": "Washington Senators" + }, + { + "Category": "MOVIE MUSICALS", + "Question": "This actress who played Mary Stone on \"The Donna Reed Show\" was the only 1 to co-star in 3 Elvis films", + "Answer": "Shelly Fabares" + }, + { + "Category": "DON'T TRY THIS AT HOME", + "Question": "Icarus could have told you it's not a good idea to fly if your wings are held together with this", + "Answer": "Wax" + }, + { + "Category": "11-LETTER WORDS", + "Question": "British weight system based on a pound equal to 453.59 grams or 16 ounces", + "Answer": "Avoirdupois" + }, + { + "Category": "FOOD FACTS", + "Question": "The Atlantic variety of this popular fish is the largest of all flatfish", + "Answer": "Halibut" + }, + { + "Category": "BASEBALL", + "Question": "In 1972 owner Bob Short moved this team to Arlington, TX . where it became the Texas Rangers", + "Answer": "Washington Senators" + }, + { + "Category": "MOVIE MUSICALS", + "Question": "This Russian composer was portrayed by Jean-Pierre Aumont in 1947's \"Song Of Scheherazade\"", + "Answer": "Rimsky-Korsakov" + }, + { + "Category": "DON'T TRY THIS AT HOME", + "Question": "This late, great circus star once performed an act with 40 -- count 'em, 40 -- lions & tigers", + "Answer": "Clyde Beatty" + }, + { + "Category": "THE RENAISSANCE", + "Question": "The name of this musical form probably came from the Latin \"matricale\", meaning in the mother tongue", + "Answer": "Madrigal" + }, + { + "Category": "PEOPLE", + "Question": "She got into the advice business before her twin sister, Dear Abby", + "Answer": "Ann Landers" + }, + { + "Category": "PLANTS", + "Question": "Britannica defines it as \"any plant growing where it is not wanted\"", + "Answer": "Weed" + }, + { + "Category": "ORGANIZATIONS", + "Question": "In 1987 Molly Yard replaced Eleanor Smeal as president of this organization", + "Answer": "National Organization for Women" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "The U.S. borders these 3 oceans", + "Answer": "Arctic, Atlantic & Pacific" + }, + { + "Category": "LITERARY QUOTES", + "Question": "Terence, a Roman poet-playwright who lived in the second century B.C., said, \"Charity begins\" here", + "Answer": "At Home" + }, + { + "Category": "THE RENAISSANCE", + "Question": "The ruthless Cesare Borgia was the model for this book by Machiavelli", + "Answer": "\"The Prince\"" + }, + { + "Category": "PEOPLE", + "Question": "Evicted from his Oregon ashram, he now lives in Bombay & is called \"Zorba The Buddha\"", + "Answer": "Bhagwan Shree Rajneesh" + }, + { + "Category": "PLANTS", + "Question": "A member of the sundew family, it requires about 10 days to fully digest an insect", + "Answer": "Venus Flytrap" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Int'l club that \"promotes putting off until later those things that needn't be done today\"", + "Answer": "Procrastinator's Club" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "There's a national park on the island of St. John in this U.S. possession", + "Answer": "U.S. Virgin Islands" + }, + { + "Category": "LITERARY QUOTES", + "Question": "Robert Louis Stevenson said, \"Marriage is ..... a field of battle, and not a bed of\" these", + "Answer": "Roses" + }, + { + "Category": "THE RENAISSANCE", + "Question": "In his notebooks this Renaissance artist claimed, \"The Medici created and destroyed me\"", + "Answer": "Leonardo Da Vinci" + }, + { + "Category": "PEOPLE", + "Question": "Herbert Ross, who directed the film \"Steel Magnolias\", is married to this sister of Jackie Onassis", + "Answer": "Lee Radziwill" + }, + { + "Category": "PLANTS", + "Question": "Plant whose twigs are used for dowsing & whose leaves & bark are used to make an astringent", + "Answer": "Witch Hazel" + }, + { + "Category": "ORGANIZATIONS", + "Question": "One must be a member of this fraternal group in order to belong to the Shriners", + "Answer": "Masons" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "North Dakota has its Devils Lake & Wyoming its Devils one of these", + "Answer": "Devils Tower" + }, + { + "Category": "LITERARY QUOTES", + "Question": "In \"A Study in Scarlet\" this author called London \"that great cesspool\"", + "Answer": "Arthur Conan Doyle" + }, + { + "Category": "THE RENAISSANCE", + "Question": "Plays were either comedies, tragedies or these love tales about woodland goddesses & shepherds", + "Answer": "Pastorals" + }, + { + "Category": "PEOPLE", + "Question": "William J. McCarthy is president of this union", + "Answer": "Teamsters" + }, + { + "Category": "PLANTS", + "Question": "Name for a low, enclosed bed covered with glass or plastic for starting plants before the season", + "Answer": "Cold Frame" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Arm of Al-Anon that's specifically for young people between the ages of 12 & 20", + "Answer": "Al-Ateen" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "The Raritan is the longest river wholly within this state", + "Answer": "New Jersey" + }, + { + "Category": "LITERARY QUOTES", + "Question": "Poet who wrote, \"The woods are lovely, dark & deep, but I have promises to keep...\"", + "Answer": "Robert Frost" + }, + { + "Category": "THE RENAISSANCE", + "Question": "Boccaccio work narrated by 3 men & 7 women fleeing the plague in Florence", + "Answer": "\"The Decameron\"" + }, + { + "Category": "PEOPLE", + "Question": "This historian & former Librarian of Congress was teaching history at Harvard while studying law at Yale", + "Answer": "Daniel Boorstein" + }, + { + "Category": "PLANTS", + "Question": "This climbing tropical shrub was named for a French South Seas explorer", + "Answer": "Bouganvillea" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Social welfare organization founded in the 19th century, whose bimonthly publication is \"The War Cry\"", + "Answer": "The Salvation Army" + }, + { + "Category": "U.S. GEOGRAPHY", + "Question": "One of the largest of these shallow channels in the U.S. is the Bartholomew in N. Louisiana", + "Answer": "Bayou" + }, + { + "Category": "LITERARY QUOTES", + "Question": "\"Always do right.\" he wrote; \"This will gratify some people and astonish the rest\"", + "Answer": "Mark Twain" + }, + { + "Category": "COUNTRIES OF THE WORLD", + "Question": "The world's most populous democracy", + "Answer": "India" + }, + { + "Category": "EARTH", + "Question": "As well as trash & absorbent pet material, it can also mean the organic surface layer of the forest floor", + "Answer": "litter" + }, + { + "Category": "HEIR", + "Question": "Since 1301 this title has belonged to the heir apparent to the British throne", + "Answer": "the Prince of Wales" + }, + { + "Category": "FIRE!", + "Question": "Though the 1871 Chicago fire began in this family's barn, their house suffered only minor damages", + "Answer": "the O'Learys" + }, + { + "Category": "WAITER!", + "Question": "To get us started, a serving of this dish named for an oilman: oysters topped with spinach & then baked", + "Answer": "Oysters Rockefeller" + }, + { + "Category": "ANGELS", + "Question": "Arte Moreno bought the baseball team in 2003 & renamed it the Los Angeles Angels of this place", + "Answer": "Anaheim" + }, + { + "Category": "\"DEM\"-ONS", + "Question": "A formal reduction in rank, status or position", + "Answer": "demotion" + }, + { + "Category": "EARTH", + "Question": "Formed at the Earth's surface, basalt is the extrusive type of this \"Big 3\" type of rock", + "Answer": "igneous" + }, + { + "Category": "HEIR", + "Question": "Heirs want to stay on the good side of this, the person mainly charged with carrying out a will's provisions", + "Answer": "the executor" + }, + { + "Category": "FIRE!", + "Question": "The first successful print of this future partner of James Ives was of a fire in Manhattan", + "Answer": "Currier" + }, + { + "Category": "WAITER!", + "Question": "Waiter, we'd like 2 services of this chilled cream-potato-leek soup", + "Answer": "vichyssoise" + }, + { + "Category": "ANGELS", + "Question": "The address of Angel Stadium is on a street named for this singing cowboy", + "Answer": "Gene Autry" + }, + { + "Category": "\"DEM\"-ONS", + "Question": "The DM in Korea's DMZ", + "Answer": "demilitarized" + }, + { + "Category": "EARTH", + "Question": "Heat rising from within the Earth is mostly from this type of decay of elements like uranium & thorium", + "Answer": "radioactive decay" + }, + { + "Category": "HEIR", + "Question": "Peter Faneuil, who gave this city its hall, inherited his uncle's fortune after another nephew was cut off for marrying", + "Answer": "Boston" + }, + { + "Category": "FIRE!", + "Question": "Maria Theresa ordered this Italian opera house built after a fire destroyed the Royal Ducal Theatre in 1776", + "Answer": "La Scala" + }, + { + "Category": "WAITER!", + "Question": "To heat up my chilly bones, bring out a large bottle of this warmed & fermented rice drink from Japan", + "Answer": "sake" + }, + { + "Category": "ANGELS", + "Question": "\"Vlad's Pad\" at Angel Stadium is named for this right fielder & 2004 league MVP", + "Answer": "Vladimir Guerrero" + }, + { + "Category": "\"DEM\"-ONS", + "Question": "Cognitive deterioration, sometimes \"senile\"", + "Answer": "dementia" + }, + { + "Category": "EARTH", + "Question": "Immense boulders in random & odd places were some of the first evidence that these \"Ages\" happened", + "Answer": "Ice Ages" + }, + { + "Category": "HEIR", + "Question": "Charlene, sole heir of the late Alfred of this Dutch brewing giant, is worth $4.9 billion", + "Answer": "Heineken" + }, + { + "Category": "FIRE!", + "Question": "The Bank of America is around today because A.P. Giannini saved its currency from this city's 1906 fire", + "Answer": "San Francisco" + }, + { + "Category": "WAITER!", + "Question": "I'm in the mood for a little Italian: how 'bout an order of anitra all'aranci, this fowl cooked in orange sauce", + "Answer": "duck" + }, + { + "Category": "ANGELS", + "Question": "Sportswriters refer to the Angels as these appropriate circular items, like the one in the team's logo", + "Answer": "the Halos" + }, + { + "Category": "\"DEM\"-ONS", + "Question": "To object or voice opposition", + "Answer": "demur" + }, + { + "Category": "EARTH", + "Question": "1 of the 3 Cs in the geological-period mnemonic \"camels often sit down carefully--perhaps their joints creak...\"", + "Answer": "Cretaceous" + }, + { + "Category": "HEIR", + "Question": "If Richie Rich's father dies, his legacy is managed by one of these, from the Latin for \"guard\"", + "Answer": "a custodian" + }, + { + "Category": "FIRE!", + "Question": "After a 1624 fire Christian IV replanned this Northern European city & renamed it Christiania", + "Answer": "Oslo" + }, + { + "Category": "WAITER!", + "Question": "For dessert, bring me some of this apple-filled rolled pastry whose name is from the German for \"whirlpool\"", + "Answer": "strudel" + }, + { + "Category": "ANGELS", + "Question": "This Angel manager spent 13 years catching for the Dodgers", + "Answer": "Mike Scioscia" + }, + { + "Category": "\"DEM\"-ONS", + "Question": "The young women \"d'Avignon\" in the title of a painting by Picasso", + "Answer": "Demoiselles" + }, + { + "Category": "THAT'S MY BUSINESS", + "Question": "Meg Whitman heads up this Internet company where you can bid on items & sell them, too", + "Answer": "eBay" + }, + { + "Category": "U.S. CABINET DEPARTMENTS IN OTHER WORDS", + "Question": "Instruction", + "Answer": "Education" + }, + { + "Category": "BESTSELLERS", + "Question": "This author's \"The Secret Man\" detailed the history of his interactions with Deep Throat", + "Answer": "Bob Woodward" + }, + { + "Category": "THE \"L\" WORLD", + "Question": "Like Rome, this capital of Portugal is built on 7 hills", + "Answer": "Lisbon" + }, + { + "Category": "A VIOLENT CATEGORY", + "Question": "In hockey this shot is always taken with a full swinging stroke", + "Answer": "slap" + }, + { + "Category": "THAT'S MY BUSINESS", + "Question": "Henry's great-grandson William runs this car company which was started in 1903", + "Answer": "the Ford Motor Company" + }, + { + "Category": "U.S. CABINET DEPARTMENTS IN OTHER WORDS", + "Question": "Giving birth", + "Answer": "Labor" + }, + { + "Category": "BESTSELLERS", + "Question": "This writer got her bestselling groove back with \"The Interruption of Everything\"", + "Answer": "McMillan" + }, + { + "Category": "THE \"L\" WORLD", + "Question": "This beautiful lake in Banff National Park is named for a British princess", + "Answer": "Louise" + }, + { + "Category": "A VIOLENT CATEGORY", + "Question": "It means \"to strike with a whip\" & also follows \"whip\" in a word for an injury", + "Answer": "lash" + }, + { + "Category": "U.S. CABINET DEPARTMENTS IN OTHER WORDS", + "Question": "A person's condition or disposition", + "Answer": "State" + }, + { + "Category": "BESTSELLERS", + "Question": "As of Dec. 4, 2005 this pregnancy prep book had spent 247 weeks on the N.Y. Times Bestseller List", + "Answer": "What To Expect When You're Expecting" + }, + { + "Category": "THE \"L\" WORLD", + "Question": "This highest capital in the Andes was founded on the site of an earlier settlement in 1548", + "Answer": "La Paz" + }, + { + "Category": "A VIOLENT CATEGORY", + "Question": "As a noun it includes the cerebrum; as a verb it means \"to smash on the head\"", + "Answer": "brain" + }, + { + "Category": "THAT'S MY BUSINESS", + "Question": "With a \"familial\" English name, this Japanese maker of office equipment started out selling sewing machines", + "Answer": "Brother" + }, + { + "Category": "U.S. CABINET DEPARTMENTS IN OTHER WORDS", + "Question": "mc2", + "Answer": "Energy" + }, + { + "Category": "BESTSELLERS", + "Question": "This author's Dr. Kay Scarpetta returned to the scene of the crime with \"Trace\"", + "Answer": "Patricia Cornwell" + }, + { + "Category": "THE \"L\" WORLD", + "Question": "In 1994 this Norwegian town played host to the Winter Olympics", + "Answer": "Lillehammer" + }, + { + "Category": "A VIOLENT CATEGORY", + "Question": "To hit with a fist, or to herd cattle like a cowboy", + "Answer": "punch" + }, + { + "Category": "THAT'S MY BUSINESS", + "Question": "A brother of one of the rappers in Run-DMC, this entrepreneur runs Phat Farm", + "Answer": "Russell Simmons" + }, + { + "Category": "U.S. CABINET DEPARTMENTS IN OTHER WORDS", + "Question": "Ex-soldiers' financial arrangements", + "Answer": "Veterans' Affairs" + }, + { + "Category": "BESTSELLERS", + "Question": "This NPR guy make list with \"Me Talk Pretty One Day\"", + "Answer": "David Sedaris" + }, + { + "Category": "THE \"L\" WORLD", + "Question": "Fodor's Travel Guide to France calls this town \"the porcelain collector's mecca\"", + "Answer": "Limoges" + }, + { + "Category": "A VIOLENT CATEGORY", + "Question": "A suit of cards represented by a trefoil", + "Answer": "club" + }, + { + "Category": "AMERICAN WOMEN", + "Question": "She gave herself the third-person name \"Phantom\", the \"no-person\" she was from 19 months until she was almost 7", + "Answer": "Helen Keller" + }, + { + "Category": "LITERARY COLLABORATORS", + "Question": "These brothers first published their \"Fairy Tales\" in 1812 as \"Kinderund Hausmarchen\"", + "Answer": "the Brothers Grimm" + }, + { + "Category": "POUR ME A STIFF ONE", + "Question": "Nonpotent potable in common to a fuzzy navel & a screwdriver", + "Answer": "orange juice" + }, + { + "Category": "\"COURT\" BRIEFS", + "Question": "A stenographer employed to transcribe an official verbatim record of legal proceedings", + "Answer": "a court reporter" + }, + { + "Category": "TALK LIKE A BRIT", + "Question": "If you're right on queue for a movie in Piccadilly, you're in one of these", + "Answer": "a line" + }, + { + "Category": "'ALLO, GOVERNOR!", + "Question": "Al Smith, Mario Cuomo", + "Answer": "New York" + }, + { + "Category": "LITERARY COLLABORATORS", + "Question": "She & her tres cher ami Jean-Paul Sartre collaborated on the political & literary journal Modern Times", + "Answer": "Simone de Beauvoir" + }, + { + "Category": "POUR ME A STIFF ONE", + "Question": "Stolichanya, or stoli to its friends, is a brand of this", + "Answer": "vodka" + }, + { + "Category": "\"COURT\" BRIEFS", + "Question": "Marsupial term for a self-appointed tribunal that parodies existing principles of law", + "Answer": "a kangaroo court" + }, + { + "Category": "TALK LIKE A BRIT", + "Question": "Of stay in bed, hit someone on the head or rub till it's red, what you do if you cosh", + "Answer": "hit someone on the head" + }, + { + "Category": "'ALLO, GOVERNOR!", + "Question": "Calvin Coolidge, Michael Dukakis", + "Answer": "Massachusetts" + }, + { + "Category": "LITERARY COLLABORATORS", + "Question": "For \"The Autobiography of Malcolm X\", Malcolm collaborated with this author", + "Answer": "Alex Haley" + }, + { + "Category": "POUR ME A STIFF ONE", + "Question": "Invented in Cuba, a mojito is made with lime juice, club soda, sugar, ice, mint leaves & this kind of alcohol", + "Answer": "rum" + }, + { + "Category": "\"COURT\" BRIEFS", + "Question": "It's a special judicial assembly with power over the administration of estates & wills of deceased people", + "Answer": "probate court" + }, + { + "Category": "TALK LIKE A BRIT", + "Question": "On British TV's \"Top of the Pops\" this Booker T. & the MGs hit might be titled \"Spring Onions\"", + "Answer": "\"Green Onions\"" + }, + { + "Category": "'ALLO, GOVERNOR!", + "Question": "Beauford Jester, John B. Connally, Jr.", + "Answer": "Texas" + }, + { + "Category": "LITERARY COLLABORATORS", + "Question": "Sidney Howard helped this author dramatize \"Dodsworth\"", + "Answer": "Sinclair Lewis" + }, + { + "Category": "POUR ME A STIFF ONE", + "Question": "This brand of liqueur made its debut in Dublin on November 26, 1974", + "Answer": "Bailey's" + }, + { + "Category": "\"COURT\" BRIEFS", + "Question": "AKA amicus curiae, it's someone not party to the litigation but who offers information pertinent to the case", + "Answer": "a friend of the court" + }, + { + "Category": "TALK LIKE A BRIT", + "Question": "If you're a British secret agent, you may have a license to kill, but you spell license this way", + "Answer": "L-I-C-E-N-C-E" + }, + { + "Category": "'ALLO, GOVERNOR!", + "Question": "Henry S. Thibodaux, P.B.S. Pinchback", + "Answer": "Louisiana" + }, + { + "Category": "LITERARY COLLABORATORS", + "Question": "George S Kaufman died in June 1961; this man, his frequent collaborator, in December of that year", + "Answer": "Moss Hart" + }, + { + "Category": "POUR ME A STIFF ONE", + "Question": "Mon Dieu! This French liqueur was originally made at the Abbey of Fecamp by the monks for which it is named", + "Answer": "Benedictine" + }, + { + "Category": "\"COURT\" BRIEFS", + "Question": "Law students try mock hypothetical legal cases in this kind of court", + "Answer": "moot court" + }, + { + "Category": "TALK LIKE A BRIT", + "Question": "If you can't get through to your friend in Brighton, you wouldn't say the telephone is busy, you'd say it's this", + "Answer": "engaged" + }, + { + "Category": "'ALLO, GOVERNOR!", + "Question": "Karl F. Rulvagg, Floyd Bjornsterne Olson, Jacob Aall Ottesen Preus", + "Answer": "Minnesota" + }, + { + "Category": "SCIENCE BRIEFS", + "Question": "It's a vital sign: BP", + "Answer": "blood pressure" + }, + { + "Category": "SHAKESPEAREAN WORDS", + "Question": "Polonius uses the word \"outbreak\" about Laertes' fiery mind, not this title character", + "Answer": "Hamlet" + }, + { + "Category": "THE \"CAPTAIN\"", + "Question": "This enigmatic seafarer in 1954's \"20,000 Leagues Under the Sea\" was portrayed by James Mason", + "Answer": "Captain Nemo" + }, + { + "Category": "TO NEIL", + "Question": "On board Gemini 8, he performed the first successful docking of 2 vehicles in space", + "Answer": "Neil Armstrong" + }, + { + "Category": "MUSCAT LOVE", + "Question": "Muscat is its capital city", + "Answer": "Oman" + }, + { + "Category": "SCIENCE BRIEFS", + "Question": "It's elemental: Zn", + "Answer": "zinc" + }, + { + "Category": "THE \"CAPTAIN\"", + "Question": "Hans Conried voiced this villain in a 1953 Disney classic", + "Answer": "Captain Hook" + }, + { + "Category": "TO NEIL", + "Question": "A star of D.W. Griffith's \"America\", Neil Hamilton played Commissioner Gordon on this TV show", + "Answer": "Batman" + }, + { + "Category": "MUSCAT LOVE", + "Question": "The 3 main forts in Muscat date from the 1580s when this small Iberian nation conquered & occupied it", + "Answer": "Portugal" + }, + { + "Category": "SCIENCE BRIEFS", + "Question": "For water, it's 0 degrees Celsius: F.P.", + "Answer": "freezing point" + }, + { + "Category": "SHAKESPEAREAN WORDS", + "Question": "From Latin for \"indecent\", this word in \"Love's Labour's Lost\" is the type of book banned by the Comstock Law", + "Answer": "obscene" + }, + { + "Category": "THE \"CAPTAIN\"", + "Question": "For his role as Manuel, Spencer Tracy won an Oscar for this 1937 fish story", + "Answer": "Captains Courageous" + }, + { + "Category": "TO NEIL", + "Question": "From 1979 to 1981, Neil Goldschmidt was Secretary of this department abbreviated D.O.T.", + "Answer": "the Department of Transportation" + }, + { + "Category": "MUSCAT LOVE", + "Question": "Completed in 2001, the \"Grand\" one of these in Muscat is the 1st in the country to be open to non-Muslims", + "Answer": "a mosque" + }, + { + "Category": "THE NAACP", + "Question": "This future Supreme Court justice won 29 of the 32 cases he argued before the court as a lawyer for the NAACP", + "Answer": "Thurgood Marshall" + }, + { + "Category": "SCIENCE BRIEFS", + "Question": "Used of radio waves: MHz", + "Answer": "megahertz" + }, + { + "Category": "SHAKESPEAREAN WORDS", + "Question": "This word in \"Henry VI Part 2\" meant blase & world-weary, not having to do with nephrite", + "Answer": "jaded" + }, + { + "Category": "THE \"CAPTAIN\"", + "Question": "Hooray for this Groucho Marx character from \"Animal Crackers\"", + "Answer": "Captain Spaulding" + }, + { + "Category": "TO NEIL", + "Question": "In the '50s, Neil H. McElroy was this man's Secretary of Defense", + "Answer": "President Eisenhower" + }, + { + "Category": "MUSCAT LOVE", + "Question": "Qaboos bin Said al Said rules from his palace in Muscat under this title that means \"ruler\" in Arabic", + "Answer": "sultan" + }, + { + "Category": "SCIENCE BRIEFS", + "Question": "When the stork won't come: IVF", + "Answer": "in vitro fertilization" + }, + { + "Category": "SHAKESPEAREAN WORDS", + "Question": "The word \"fashionable\" came into vogue with Ulysses' speech to Achilles in this play", + "Answer": "Troilus and Cressida" + }, + { + "Category": "THE \"CAPTAIN\"", + "Question": "Errol Flynn is a doctor who is forced to become a pirate in this 1935 action fest", + "Answer": "Captain Blood" + }, + { + "Category": "TO NEIL", + "Question": "In 1989, this \"bright\" Neil Sheehan work about the Vietnam War won the Pulitzer Prize for general nonfiction", + "Answer": "A Bright Shining Lie" + }, + { + "Category": "MUSCAT LOVE", + "Question": "A main strategic value of Muscat stems from its position at the entranceway to this 90,000 sq. mi. body of water", + "Answer": "the Persian Gulf" + }, + { + "Category": "BEATLES MUSIC", + "Question": "Chauffeur Alf Bicknell was the inspiration for this 1965 song", + "Answer": "\\\"Drive My Car\\\"" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "The Florida wild black type of this carnivore is down to about 3,000 animals & needs its habitat protected", + "Answer": "a bear" + }, + { + "Category": "CELEBRITY FACTS", + "Question": "In 2010 she got engaged to a choreographer she met on the set of \"Black Swan\"", + "Answer": "Natalie Portman" + }, + { + "Category": "LET'S HAVE ITALIAN TONIGHT!", + "Question": "About 635 violins still exist among the 1,100 instruments this 17th century man constructed", + "Answer": "Stradivarius" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "This item on a bicycle lets drivers see cyclists at night", + "Answer": "taillight" + }, + { + "Category": "HOME FURNISHINGS", + "Question": "Four-poster is a type of this, sometimes with a canopy", + "Answer": "a bed" + }, + { + "Category": "FATHERS-IN-LAW", + "Question": "United Farm Workers president Arturo Rodriguez' father-in-law was this man who died in 1993", + "Answer": "César Chávez" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "A New York Times article said this, falling in winter in the Adirondacks, may be more toxic for fish than its liquid counterpart", + "Answer": "acid snow" + }, + { + "Category": "CELEBRITY FACTS", + "Question": "Alice Cooper's Phoenix eatery has dishes named for ballplayers & is named this, like the Hall of Fame site", + "Answer": "Cooperstown" + }, + { + "Category": "LET'S HAVE ITALIAN TONIGHT!", + "Question": "Message for you, sir...! In 1897 he founded his wireless telegraph & signal company in London", + "Answer": "Marconi" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "This 5-letter word can mean \"overweight\"", + "Answer": "plump" + }, + { + "Category": "FATHERS-IN-LAW", + "Question": "German emperor Frederick III's was this German-born British prince consort", + "Answer": "Prince Albert" + }, + { + "Category": "THE ENVIRONMENT", + "Question": "As you know from the movie \"Medicine Man\", the rain forests hold essential plants for treating this disease", + "Answer": "cancer" + }, + { + "Category": "LET'S HAVE ITALIAN TONIGHT!", + "Question": "This food network personality grew up in her film producer grandfather's restaurant, DDL Foodshow", + "Answer": "Giada De Laurentiis" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "Like a horse", + "Answer": "equine" + }, + { + "Category": "HOME FURNISHINGS", + "Question": "A jardiniere is a decorative stand for holding these", + "Answer": "plants" + }, + { + "Category": "FATHERS-IN-LAW", + "Question": "Catherine Zeta-Jones' is this legendary actor", + "Answer": "Kirk Douglas" + }, + { + "Category": "CELEBRITY FACTS", + "Question": "Jake Gyllenhaal got his first driving lesson from this late movie star & auto racer", + "Answer": "Paul Newman" + }, + { + "Category": "LET'S HAVE ITALIAN TONIGHT!", + "Question": "This Italian-born man began his brief tenure as pope on August 26, 1978", + "Answer": "John Paul I" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "The part of an atom's nucleus that fits the category", + "Answer": "a neutron" + }, + { + "Category": "FATHERS-IN-LAW", + "Question": "Jefferson Davis' was this U.S. president", + "Answer": "Zachary Taylor" + }, + { + "Category": "CELEBRITY FACTS", + "Question": "Angelina Jolie's uncle, Chip Taylor, wrote this song that says, \"you make my heart sing\"", + "Answer": "\"Wild Thing\"" + }, + { + "Category": "LET'S HAVE ITALIAN TONIGHT!", + "Question": "In 2002 he wrote \"Baudolino\", a historial novel set in 12th century Europe; what an author ... author ... author", + "Answer": "Umberto Ecco" + }, + { + "Category": "SAME FIRST & LAST LETTER", + "Question": "Pertaining to the scientific use & study of very low temperatures", + "Answer": "cryogenic" + }, + { + "Category": "HOME FURNISHINGS", + "Question": "By definition, this type of china cabinet has a slightly projecting middle section", + "Answer": "breakfront" + }, + { + "Category": "FATHERS-IN-LAW", + "Question": "Daniel Day-Lewis' was this dramatist", + "Answer": "Arthur Miller" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "His \"Heroic\" Period, from about 1803 to 1812, produced his \"Eroica\" Symphony", + "Answer": "Beethoven" + }, + { + "Category": "THEY'RE ON CABLE", + "Question": "He plays novelist Hank Moody, a New Yorker transplanted to L.A., on \"Californication\"", + "Answer": "David Duchovny" + }, + { + "Category": "POETIC TITLE VERBS", + "Question": "\"_____ By Woods On A Snowy Evening\"", + "Answer": "Stopping" + }, + { + "Category": "IT'S A COUP D'ETAT", + "Question": "After his murder, the conspirators did not gain control, as power was passed on to the Second Triumvirate", + "Answer": "Julius Caesar" + }, + { + "Category": "COMPOUND WORDS", + "Question": "A student's may be 3-ring or spiral bound", + "Answer": "a notebook" + }, + { + "Category": "FATHER'S IN LAW", + "Question": "Father was quite the cutup in Prof. Charles Fried's class at this Massachusetts law school founded in 1817", + "Answer": "Harvard" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "One of Verdi's first masterpieces was this Shakespearean opera with an intense sleepwalking scene", + "Answer": "Macbeth" + }, + { + "Category": "THEY'RE ON CABLE", + "Question": "James Roday is Shawn Spencer, a police consultant who pretends to have otherworldly powers, on this comedic series", + "Answer": "Psych" + }, + { + "Category": "POETIC TITLE VERBS", + "Question": "\"I _____ Lonely As A Cloud\"", + "Answer": "Wandered" + }, + { + "Category": "IT'S A COUP D'ETAT", + "Question": "Carl Henrik Anckarsvard was the leader of the coup that overthrew King Gustav IV of this country", + "Answer": "Sweden" + }, + { + "Category": "COMPOUND WORDS", + "Question": "Common name for the patella", + "Answer": "the kneecap" + }, + { + "Category": "FATHER'S IN LAW", + "Question": "Father has rooms near the Court of Chancery in this state where half of Fortune 500 companies are incorporated", + "Answer": "Delaware" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "Charles Gounod's mother thought he might become a priest, & one of his best-known works is this setting of a Catholic prayer", + "Answer": "Ave Maria" + }, + { + "Category": "POETIC TITLE VERBS", + "Question": "\"She _____ In Beauty\"", + "Answer": "Walks" + }, + { + "Category": "IT'S A COUP D'ETAT", + "Question": "In 1921 Reza Pahlavi helped with a coup that eventually brought his son to power in this country", + "Answer": "Iran" + }, + { + "Category": "COMPOUND WORDS", + "Question": "It's often said, \"Build a better\" this \"and the world will beat a path to your door\"", + "Answer": "a mousetrap" + }, + { + "Category": "FATHER'S IN LAW", + "Question": "Coincidentally, today father's squash opponent was also his deponent, as father was taking this", + "Answer": "a deposition" + }, + { + "Category": "CLASSICAL COMPOSERS", + "Question": "He was 24 years older than his friend Mozart, but outlived him by almost 20 years", + "Answer": "Franz Joseph Haydn" + }, + { + "Category": "THEY'RE ON CABLE", + "Question": "The title pair of this TNT show is Boston detective Angie Harmon & medical examiner Sasha Alexander", + "Answer": "Rizzoli & Isles" + }, + { + "Category": "POETIC TITLE VERBS", + "Question": "\"To An Athlete _____ Young\"", + "Answer": "Dying" + }, + { + "Category": "IT'S A COUP D'ETAT", + "Question": "This S. American president was the leader of an unsuccessful coup in 1992 & was the target of a coup in 2002", + "Answer": "Hugo Chavez" + }, + { + "Category": "COMPOUND WORDS", + "Question": "Lunar term meaning mentally deranged or dreamily romantic", + "Answer": "moonstruck" + }, + { + "Category": "FATHER'S IN LAW", + "Question": "Father learned about the quaint problems of the poor at Chicago's \"Edwin F. Mandel\" this type of \"Clinic\"", + "Answer": "legal aid" + }, + { + "Category": "POETIC TITLE VERBS", + "Question": "\"On First _____ Into Chapman's Homer\"", + "Answer": "Looking" + }, + { + "Category": "IT'S A COUP D'ETAT", + "Question": "In Pakistan Nawaz Sharif tried to dismiss this military leader in 1999 but was overthrown by him instead", + "Answer": "Musharraf" + }, + { + "Category": "COMPOUND WORDS", + "Question": "It's the 9-letter name for a type of restaurant that specializes in steak & other meat on the bone", + "Answer": "chophouse" + }, + { + "Category": "FATHER'S IN LAW", + "Question": "As a non-partner who has a formal relationship with a firm, father is said to be \"of\" this to Bisbee, Pell & Bisbee", + "Answer": "Counsel" + }, + { + "Category": "BIOGRAPHERS", + "Question": "As many mourned, this minister wrote in a letter, \"Washington is gone! Millions are gasping to read ...about him\"", + "Answer": "Parson Weems" + }, + { + "Category": "THEY ALSO RAN", + "Question": "Born in Brooklyn in 1944, he was mayor of New York City from 1994 to 2002", + "Answer": "Rudy Giuliani" + }, + { + "Category": "ROCK & ROLL FRONTMEN", + "Question": "David Lee Roth, Sammy Hagar, David Lee Roth", + "Answer": "Van Halen" + }, + { + "Category": "MERGERS & ACQUISITIONS", + "Question": "In 2004 this Dutch airlines merged with Air France", + "Answer": "KLM" + }, + { + "Category": "RODENTS", + "Question": "Spaniards named these furry rodents for the Chincha Indians", + "Answer": "chinchilla" + }, + { + "Category": "\"F\"OOD", + "Question": "This, food cooked in a central pot on the table, is from the French for \"to melt\"", + "Answer": "fondue" + }, + { + "Category": "HOMOPHONES", + "Question": "A native of Copenhagen, or to stoop to do something", + "Answer": "dane/deign" + }, + { + "Category": "THEY ALSO RAN", + "Question": "He received a degree from NC State & pushed papers at his own Raleigh law firm", + "Answer": "John Edwards" + }, + { + "Category": "ROCK & ROLL FRONTMEN", + "Question": "Roger Daltrey", + "Answer": "The Who" + }, + { + "Category": "MERGERS & ACQUISITIONS", + "Question": "In 1999 Ford snatched up the auto unit of this company for 50 billion kronor", + "Answer": "Volvo" + }, + { + "Category": "RODENTS", + "Question": "Some of the quills of the Eurasian species can be 12 inches, equal to about half of its body length", + "Answer": "a porcupine" + }, + { + "Category": "\"F\"OOD", + "Question": "It's a Spanish baked custard coated with caramel", + "Answer": "flan" + }, + { + "Category": "HOMOPHONES", + "Question": "To take a quick look, or the top of a mountain", + "Answer": "peek/peak" + }, + { + "Category": "THEY ALSO RAN", + "Question": "Formerly a U.S. Secretary of Energy & U.N. Ambassador, he's now the Governor of New Mexico", + "Answer": "Richardson" + }, + { + "Category": "ROCK & ROLL FRONTMEN", + "Question": "Anthony Kiedis", + "Answer": "Red Hot Chili Peppers" + }, + { + "Category": "MERGERS & ACQUISITIONS", + "Question": "In an $80 billion deal these 2 oil companies joined forces in 1999 in the biggest merger up to that time", + "Answer": "Exxon & Mobil" + }, + { + "Category": "RODENTS", + "Question": "These rodents of the Plains received their name because they \"bark\" like canines", + "Answer": "prairie dogs" + }, + { + "Category": "\"F\"OOD", + "Question": "It's the Japanese name for certain species of puffer fish that contain lethal poison but can be eaten as a delicacy", + "Answer": "fugu" + }, + { + "Category": "HOMOPHONES", + "Question": "Antagonistic, or an inexpensive lodging place for young people abroad", + "Answer": "hostile/hostel" + }, + { + "Category": "THEY ALSO RAN", + "Question": "He played the CIA chief in \"No Way Out\" & represented Tennessee in the U.S. Senate", + "Answer": "Fred Thompson" + }, + { + "Category": "ROCK & ROLL FRONTMEN", + "Question": "Trent Reznor", + "Answer": "Nine Inch Nails" + }, + { + "Category": "MERGERS & ACQUISITIONS", + "Question": "In 2004 FedEx acquired this chain of stores, & you can copy me on that!", + "Answer": "Kinko's" + }, + { + "Category": "RODENTS", + "Question": "Contrary to popular belief, mass drownings by the Norway species of this rodent are not suicidal in nature", + "Answer": "lemmings" + }, + { + "Category": "\"F\"OOD", + "Question": "The name of these long, flat egg noodles means \"little ribbons\"", + "Answer": "fettuccine" + }, + { + "Category": "HOMOPHONES", + "Question": "It's a sausage, or the absolute least best", + "Answer": "wurst/worst" + }, + { + "Category": "THEY ALSO RAN", + "Question": "At age 31, he was Cleveland's mayor", + "Answer": "Dennis Kucinich" + }, + { + "Category": "ROCK & ROLL FRONTMEN", + "Question": "Adam Levine", + "Answer": "Maroon 5" + }, + { + "Category": "MERGERS & ACQUISITIONS", + "Question": "Despite opposition from the 2 founders' families, this company merged with Compaq in 2002", + "Answer": "Hewlett-Packard" + }, + { + "Category": "RODENTS", + "Question": "A S. Am. delicacy, this water-dwelling herbivore was declared a fish by the Vatican so it could be eaten during Lent", + "Answer": "a capybara" + }, + { + "Category": "HOMOPHONES", + "Question": "A dish, or a braid of hair", + "Answer": "plate/plait" + }, + { + "Category": "EARLY AMERICA", + "Question": "In 1610 the Spanish began building the Palace of the Governors in what is now this Southwest city", + "Answer": "Santa Fe" + }, + { + "Category": "ACTRESSES ON TV", + "Question": "On \"Fat Actress\", she poked fun at herself, playing a version of herself struggling with her weight", + "Answer": "Kirstie Alley" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "The 2 symbols seen on pirate flags & bottles of poison", + "Answer": "skull & crossbones" + }, + { + "Category": "MARK TWAIN: BOOK LOVER", + "Question": "Writing about this author's \"The Deerslayer\", Twain called its pathos \"funny\" & \"its love-scenes odious\"", + "Answer": "Cooper" + }, + { + "Category": "ROGER!", + "Question": "In 1982 he co-anchored \"NBC Nightly News\" with Tom Brokaw, & you could say his name is...", + "Answer": "Roger Mudd" + }, + { + "Category": "4-LETTER WORDS", + "Question": "Pronounced one way, it's the top of the head; pronounced another, it's French chopped liver", + "Answer": "pâté or pate" + }, + { + "Category": "EARLY AMERICA", + "Question": "In 1701 this college was founded in Conn., in part to counter the perceived liberalism of Harvard", + "Answer": "Yale" + }, + { + "Category": "ROGER!", + "Question": "The \"Roger\" to Michael Moore's \"Me\", in 1990 this GM chairman handed over the job to Robert Stempel", + "Answer": "Smith" + }, + { + "Category": "EARLY AMERICA", + "Question": "The Molasses Act of 1733 placed high duties on molasses & this potent potable from non-English possessions", + "Answer": "rum" + }, + { + "Category": "ACTRESSES ON TV", + "Question": "She portrays real-life research medium Allison DuBois", + "Answer": "Arquette" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "Baby, you're going to be a star, & we're going to put you next to this symbol on Turkey's flag", + "Answer": "a crescent" + }, + { + "Category": "MARK TWAIN: BOOK LOVER", + "Question": "One of Twain's favorite books was the \"Diary of\" this Englishman; Twain credited it as the model for his book \"1601\"", + "Answer": "Pepys" + }, + { + "Category": "ROGER!", + "Question": "I'll have a side of this 13th century English philosopher & creator of the \"Opus Majus\"", + "Answer": "Roger Bacon" + }, + { + "Category": "4-LETTER WORDS", + "Question": "It's short for one of the muscles, or a large open space on campus surrounded by buildings", + "Answer": "a quad" + }, + { + "Category": "EARLY AMERICA", + "Question": "His 1699 proposal for a permanent French trading post on the Detroit River didn't include a car dealership", + "Answer": "Cadillac" + }, + { + "Category": "ACTRESSES ON TV", + "Question": "On \"Brothers & Sisters\", she plays right-wing TV pundit Kitty Walker", + "Answer": "Calista Flockhart" + }, + { + "Category": "MARK TWAIN: BOOK LOVER", + "Question": "A copy of the New Testament in Arabic was given to Twain during the cruise that inspired this 1869 travel classic", + "Answer": "The Innocents Abroad" + }, + { + "Category": "ROGER!", + "Question": "He was to fly as lunar module pilot on the first manned Apollo mission but tragically never made it", + "Answer": "Roger Chaffee" + }, + { + "Category": "4-LETTER WORDS", + "Question": "From the Welsh, it's a steep, rugged rock, or a rough, broken projecting part of a rock", + "Answer": "a crag" + }, + { + "Category": "EARLY AMERICA", + "Question": "In the 1620s this Dutch company founded New Netherland in what later became N.Y., N.J., Delaware & Connecticut", + "Answer": "the Dutch West India Company" + }, + { + "Category": "ACTRESSES ON TV", + "Question": "Like her \"Grey's Anatomy\" character Izzie Stevens, she used to be a model", + "Answer": "Katherine Heigl" + }, + { + "Category": "SIGNS & SYMBOLS", + "Question": "At her swearing-in, Speaker Pelosi wore this color (also a longtime symbol of power) as a symbol of the Suffragettes", + "Answer": "purple" + }, + { + "Category": "MARK TWAIN: BOOK LOVER", + "Question": "\"The only poem I have ever carried about with me\", said Twain, was this classic, best enjoyed with \"a jug of wine\"", + "Answer": "the Rubaiyat of Omar Khayyam" + }, + { + "Category": "ROGER!", + "Question": "The fifth Chief Justice of the United States, he succeeded John Marshall in 1836", + "Answer": "Roger Taney" + }, + { + "Category": "4-LETTER WORDS", + "Question": "Used in linoleum & paints, linseed oil is made from the seeds of this plant", + "Answer": "flax" + }, + { + "Category": "CONSUMER PRODUCTS", + "Question": "This product was reintroduced in 1906 with trimethylxanthine as the sole remaining stimulant", + "Answer": "Coca-Cola" + }, + { + "Category": "WASHINGTON D.C.", + "Question": "What the \"D.C.\" stands for", + "Answer": "the District of Columbia" + }, + { + "Category": "COLORS", + "Question": "Color of a lucky \"letter day\"", + "Answer": "red" + }, + { + "Category": "A LA \"CART\"", + "Question": "While 2 of its wheels head toward produce, 1 goes to dairy, the other to checkout", + "Answer": "a shopping cart" + }, + { + "Category": "FOOD", + "Question": "Varieties include Chinese & Dijon", + "Answer": "mustard" + }, + { + "Category": "MOVIE TRIVIA", + "Question": "Turned down to be an \"Our Gang\" member, she became top box office star of 1935", + "Answer": "Shirley Temple" + }, + { + "Category": "WASHINGTON D.C.", + "Question": "The District's oldest neighborhood, it was named for a king", + "Answer": "Georgetown" + }, + { + "Category": "COLORS", + "Question": "Johnny Cash is known for wearing only this color on stage", + "Answer": "black" + }, + { + "Category": "SPORTS", + "Question": "Tennis serve that touches net before dropping into proper court, it's replayed", + "Answer": "a let ball" + }, + { + "Category": "A LA \"CART\"", + "Question": "A sideways handspring", + "Answer": "a cartwheel" + }, + { + "Category": "FOOD", + "Question": "Type of food that comes in shapes of bow ties, elbows & wagon wheels", + "Answer": "pasta" + }, + { + "Category": "WASHINGTON D.C.", + "Question": "287 miles long, it flows past Washington & induces \"fever\" in ambitious politicians", + "Answer": "the Potomac River" + }, + { + "Category": "COLORS", + "Question": "Baby, sky, & steel", + "Answer": "blue" + }, + { + "Category": "SPORTS", + "Question": "You win this when you pick the winners of 2 successive horse races", + "Answer": "the Daily Double" + }, + { + "Category": "A LA \"CART\"", + "Question": "You can load it in your 8-track", + "Answer": "acartridge" + }, + { + "Category": "FOOD", + "Question": "Also known as an alligator pear", + "Answer": "an avocado" + }, + { + "Category": "MOVIE TRIVIA", + "Question": "For the first time in '68, the Academy Awards were held in this auditorium, its current home", + "Answer": "the Dorothy Chandler Pavilion" + }, + { + "Category": "WASHINGTON D.C.", + "Question": "Though this mound rises only 8", + "Answer": "Capitol Hill" + }, + { + "Category": "COLORS", + "Question": "Broadway's nickname", + "Answer": "the Great White Way" + }, + { + "Category": "SPORTS", + "Question": "What the letters in \"scuba\" stand for", + "Answer": "self-contained underwater breathing apparatus" + }, + { + "Category": "A LA \"CART\"", + "Question": "The 1st graduate of the U.S. Naval Academy to become president", + "Answer": "Jimmy Carter" + }, + { + "Category": "FOOD", + "Question": "California vegetable with a crown & a heart", + "Answer": "an artichoke" + }, + { + "Category": "MOVIE TRIVIA", + "Question": "In his best English Bronx accent he cried \"Yonder lies the castle of my father\"", + "Answer": "Tony Curtis" + }, + { + "Category": "WASHINGTON D.C.", + "Question": "Former Secretary of State for whom Washington, D.C. International Airport is named", + "Answer": "John Foster Dulles" + }, + { + "Category": "COLORS", + "Question": "The 3 colors that make up the dots on a color TV screen", + "Answer": "blue, green, and red" + }, + { + "Category": "SPORTS", + "Question": "On an official archery target, it's the color of the bull's eye", + "Answer": "yellow" + }, + { + "Category": "FOOD", + "Question": "The non-chocolate version are called \"blondies\"", + "Answer": "brownies" + }, + { + "Category": "EUROPE", + "Question": "Some 40% of this country's land has been reclaimed from the sea", + "Answer": "the Netherlands" + }, + { + "Category": "BIG BANDS", + "Question": "A wunnerful, wunnerful bandleader", + "Answer": "Lawrence Welk" + }, + { + "Category": "NOTORIOUS", + "Question": "White supremacy group depicted as heroes in film classic \"Birth of a Nation\"", + "Answer": "the Ku Klux Klan" + }, + { + "Category": "BIRDS", + "Question": "This red bird is the state bird of 7 states", + "Answer": "the cardinal" + }, + { + "Category": "BEES", + "Question": "Its name comes from the Middle English word \"bumblen\"", + "Answer": "a bumblebee" + }, + { + "Category": "POLITICS", + "Question": "Baby book author who ran for president in '68", + "Answer": "Dr. Spock" + }, + { + "Category": "EUROPE", + "Question": "Both in size & population, it's largest Scandinavian country", + "Answer": "Sweden" + }, + { + "Category": "BIG BANDS", + "Question": "In 1937 he was \"in the mood\" to start a band", + "Answer": "Glenn Miller" + }, + { + "Category": "NOTORIOUS", + "Question": "Name of FBI \"sting\" operation that sent 4 former Congressmen to prison in '83", + "Answer": "Abscam" + }, + { + "Category": "BIRDS", + "Question": "Depending on the species, a bird can have 940 to 25,000 of them", + "Answer": "feathers" + }, + { + "Category": "BEES", + "Question": "Common name of an apiculturist", + "Answer": "a beekeeper" + }, + { + "Category": "POLITICS", + "Question": "Nickname of late Washington Senator Henry Jackson", + "Answer": "Scoop Jackson" + }, + { + "Category": "EUROPE", + "Question": "19th century Sardinia took the lead in unifying this country", + "Answer": "Italy" + }, + { + "Category": "BIG BANDS", + "Question": "As famous for his marriages as his music; once wed Ava Gardner & Lana Turner", + "Answer": "Artie Shaw" + }, + { + "Category": "NOTORIOUS", + "Question": "32 inmates & 11 guards were killed in '71 uprising at this NY prison", + "Answer": "Attica" + }, + { + "Category": "BIRDS", + "Question": "All 16 species of the Hawaiian honeycreeper are on this list", + "Answer": "the endangered species list" + }, + { + "Category": "BEES", + "Question": "A large crowd of bees on the move", + "Answer": "a swarm" + }, + { + "Category": "POLITICS", + "Question": "U.S. ambassadors to this country have included Anne Armstrong & Joseph Kennedy", + "Answer": "Great Britain" + }, + { + "Category": "EUROPE", + "Question": "In '67 this last king of Greece went into exile", + "Answer": "Constantine" + }, + { + "Category": "BIG BANDS", + "Question": "Benny Goodman got good \"vibes\" from him", + "Answer": "Lionel Hampton" + }, + { + "Category": "NOTORIOUS", + "Question": "Despite his \"fortunate\" nickname, this gangster was deported to Italy in '46", + "Answer": "\"Lucky\" Luciano" + }, + { + "Category": "BEES", + "Question": "The 3 classes of a honeybee colony", + "Answer": "a drone, a queen, and a worker" + }, + { + "Category": "POLITICS", + "Question": "Florida Congressman who champions the senior citizen", + "Answer": "Claude Pepper" + }, + { + "Category": "EUROPE", + "Question": "Only predominanty Muslim country entirely in Europe", + "Answer": "Albania" + }, + { + "Category": "BIG BANDS", + "Question": "\"Royal\" bandleader whose first two names were Edward Kennedy", + "Answer": "Duke Ellington" + }, + { + "Category": "NOTORIOUS", + "Question": "He wrote the Howard Hughes \"autobiography\" that sent him to jail", + "Answer": "Clifford Irving" + }, + { + "Category": "POLITICS", + "Question": "Only 4 state governors serve terms this long", + "Answer": "two years" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "President elected to 2nd term with 523 electoral votes, the greatest number in any election", + "Answer": "Franklin D. Roosevelt" + }, + { + "Category": "VOLCANOES", + "Question": "About its eruption in 79 A.D., an observer wrote that \"broad sheets of fire and leaping flames blazed at several points\"", + "Answer": "Vesuvius" + }, + { + "Category": "ALSO SOMETHING YOU WEAR", + "Question": "A hard blow or punch", + "Answer": "a sock" + }, + { + "Category": "NOVELS BY CHAPTER TITLE", + "Question": "\"The Shoulder of Athos, the Baldric of Porthos, and the Handkerchief of Aramis\"", + "Answer": "The Three Musketeers" + }, + { + "Category": "A \"TON\" OF PEOPLE", + "Question": "In 2004 the most valuable guitar, this rocker's Stratocaster \"Blackie\", sold for $959,500 at auction", + "Answer": "Clapton" + }, + { + "Category": "KAN U SPEL BIZNESS?", + "Question": "Dessert topping (the part after \"Reddi\")", + "Answer": "W-I-P" + }, + { + "Category": "VOLCANOES", + "Question": "At least 57 people died as a result of this U.S. volcano's May 18, 1980 eruption", + "Answer": "Mount St. Helens" + }, + { + "Category": "ALSO SOMETHING YOU WEAR", + "Question": "To avoid or go around the edge of", + "Answer": "a skirt" + }, + { + "Category": "NOVELS BY CHAPTER TITLE", + "Question": "\"Four Thousand Leagues Under the Pacific\"", + "Answer": "20,000 Leagues Under the Sea" + }, + { + "Category": "A \"TON\" OF PEOPLE", + "Question": "In the 1991 remake of \"Father of the Bride\", she played the mother of the bride", + "Answer": "Diane Keaton" + }, + { + "Category": "KAN U SPEL BIZNESS?", + "Question": "Mr. Potato Head maker (the part after \"Play\")", + "Answer": "S-K-O-O-L" + }, + { + "Category": "VOLCANOES", + "Question": "This youngest surface volcano on the Big Island of Hawaii has distinctive lava formations like Pele's Hair", + "Answer": "Kilauea" + }, + { + "Category": "ALSO SOMETHING YOU WEAR", + "Question": "When followed by \"down\", it means to eat voraciously", + "Answer": "scarf" + }, + { + "Category": "NOVELS BY CHAPTER TITLE", + "Question": "\"Hester and Pearl\"", + "Answer": "The Scarlet Letter" + }, + { + "Category": "KAN U SPEL BIZNESS?", + "Question": "Drugstore with 4,700 outlets (the part before \"Aid\")", + "Answer": "R-I-T-E" + }, + { + "Category": "VOLCANOES", + "Question": "In 1908 members of Ernest Shackleton's expedition became the first to climb this continent's Mount Erebus", + "Answer": "Antarctica" + }, + { + "Category": "ALSO SOMETHING YOU WEAR", + "Question": "Hard, quick gasps for air", + "Answer": "pants" + }, + { + "Category": "NOVELS BY CHAPTER TITLE", + "Question": "\"Mr. Badger\"", + "Answer": "The Wind in the Willows" + }, + { + "Category": "A \"TON\" OF PEOPLE", + "Question": "After his death in 1974, his son Mercer took over his band", + "Answer": "Duke Ellington" + }, + { + "Category": "KAN U SPEL BIZNESS?", + "Question": "\"Kid tested, mother approved\" cereal", + "Answer": "K-I-X" + }, + { + "Category": "VOLCANOES", + "Question": "This lake lies in a caldera formed when Oregon's Mount Mazama volcano collapsed 7,000 years ago", + "Answer": "Crater Lake" + }, + { + "Category": "ALSO SOMETHING YOU WEAR", + "Question": "A policy seeking to reduce pollution is referred to as this & trade", + "Answer": "cap" + }, + { + "Category": "NOVELS BY CHAPTER TITLE", + "Question": "\"The Lotus Eaters\" & \"Circe\"", + "Answer": "Ulysses" + }, + { + "Category": "A \"TON\" OF PEOPLE", + "Question": "His \"Boyz N the Hood\" earned him the first-ever best director Oscar nomination for an African American", + "Answer": "John Singleton" + }, + { + "Category": "KAN U SPEL BIZNESS?", + "Question": "Amazing, phenomenal cleaner from SC Johnson", + "Answer": "F-A-N-T-A-S-T-I-K" + }, + { + "Category": "TOP OF THE LIST", + "Question": "U.S. News & World Report calls this New Haven school the best value college, even with tuition at over $38,000 a year", + "Answer": "Yale" + }, + { + "Category": "MAGIC", + "Question": "According to tradition, this prop used by magicians should be made of hazel wood cut at sunrise", + "Answer": "a wand" + }, + { + "Category": "OLYMPIC GOLD MEDALISTS BY SPORT", + "Question": "1976: Nadia Comaneci; 2008: Nastia Liukin (champions all-around)", + "Answer": "gymnastics" + }, + { + "Category": "COME TO OUR AIDE", + "Question": "Patrick Jephson, her aide in the 1990s, doesn't aid her reputation with his book \"Shadows of a Princess\"", + "Answer": "Princess Diana" + }, + { + "Category": "POEMS ON POETS", + "Question": "To hear about \"My Highland Lassie\" / My poor heart, it yearns / For he wrote 'em, I just quote 'em / He is...", + "Answer": "Burns" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "The Union Jack (4)", + "Answer": "flag" + }, + { + "Category": "TOP OF THE LIST", + "Question": "According to the Cat Fanciers' Assoc., the top breed of pedigreed cat is this feline with a Middle Eastern name", + "Answer": "Persian" + }, + { + "Category": "MAGIC", + "Question": "This duo first teamed up in 1975; one was a clown college graduate & juggler, the other, a silent magician", + "Answer": "Penn & Teller" + }, + { + "Category": "OLYMPIC GOLD MEDALISTS BY SPORT", + "Question": "1964: Joe Frazier; 1996: Wladimir Klitschko", + "Answer": "boxing" + }, + { + "Category": "COME TO OUR AIDE", + "Question": "Vladislav Surkov, a longtime aide to this former president, is known as the Kremlin's \"Gray Cardinal\"", + "Answer": "Putin" + }, + { + "Category": "POEMS ON POETS", + "Question": "\"The Lamb\" & \"The Fly\" are far from a mess / But this man's \"The Tyger\" / Gets all the good press", + "Answer": "Blake" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Velour, velvet or tricot (6)", + "Answer": "fabric" + }, + { + "Category": "TOP OF THE LIST", + "Question": "Not only is Hartsfield-Jackson in Atlanta the world's busiest airport, this airline based there is the largest", + "Answer": "Delta" + }, + { + "Category": "MAGIC", + "Question": "This magician's feats include walking through the Great Wall of China", + "Answer": "David Copperfield" + }, + { + "Category": "OLYMPIC GOLD MEDALISTS BY SPORT", + "Question": "1924: Helen Wills; 2004: Justine Henin-Hardenne", + "Answer": "tennis" + }, + { + "Category": "POEMS ON POETS", + "Question": "Being called \"a gargoyle of a man\" / May have caused him to lose all hope / But his \"Rape of the Lock\" was good / He's...", + "Answer": "Pope" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Long crack in a rock (7)", + "Answer": "fissure" + }, + { + "Category": "TOP OF THE LIST", + "Question": "Not surprisingly, this taste sensation is rocking as Ben & Jerry's top-selling ice cream flavor", + "Answer": "Cherry Garcia" + }, + { + "Category": "MAGIC", + "Question": "This 16-letter synonym for sleight of hand comes from the Latin for \"nimble finger\"", + "Answer": "prestidigitation" + }, + { + "Category": "OLYMPIC GOLD MEDALISTS BY SPORT", + "Question": "1904: Thomas Kiely, with 6,036 points; 2000: Erki Nool, with 8,641", + "Answer": "the decathlon" + }, + { + "Category": "COME TO OUR AIDE", + "Question": "In 1948 White House aide Lauchlin Currie told this committee he wasn't a Soviet spy; today we know he was", + "Answer": "the House Un-American Activities Committee" + }, + { + "Category": "POEMS ON POETS", + "Question": "\"A hundred naked maidens\" / Danced in his \"Faerie Queene\" / Give this Elizabethan credit / He sure could set a scene", + "Answer": "Spenser" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Islamic legal opinion or directive (5)", + "Answer": "fatwa" + }, + { + "Category": "TOP OF THE LIST", + "Question": "In 2011 this Nissan model was Consumer Reports' top pick for family sedan", + "Answer": "the Altima" + }, + { + "Category": "MAGIC", + "Question": "In November 2000 this illusionist known for his street magic was encased in a block of ice for 63 hours in Times Square", + "Answer": "David Blaine" + }, + { + "Category": "OLYMPIC GOLD MEDALISTS BY SPORT", + "Question": "1896: Ellery Clark, 20' 10\"; 2000: Ivan Pedroso, 28' 3/4\"", + "Answer": "the long jump" + }, + { + "Category": "COME TO OUR AIDE", + "Question": "In 2009 an aide to the Defense Sec. was ensnared in the scandal over a couple who crashed this White House event", + "Answer": "the White House State Dinner" + }, + { + "Category": "POEMS ON POETS", + "Question": "This romantic poet was really not clairvoyant / In 1822 / He put \"Hellas\" into view / But we wish he was more buoyant", + "Answer": "Shelley" + }, + { + "Category": "CROSSWORD CLUES \"F\"", + "Question": "Smooth move in a bridge game (7)", + "Answer": "finesse" + }, + { + "Category": "U.S. CITIES", + "Question": "Of the top 10 cities in population within city limits, this one of 1.4 million is the only state capital", + "Answer": "Phoenix, Arizona" + }, + { + "Category": "PRESIDENTS IN IOWA", + "Question": "He was at radio station WHO back in the 1930s & while president, went back to Des Moines", + "Answer": "Ronald Reagan" + }, + { + "Category": "THE GRIDIRON", + "Question": "[Hi, I'm Dick Butkus, Hall of Fame linebacker of the Chicago Bears] Before moving to Soldier Field in 1971, the Bears played its home games for 50 seasons in this Cubs park", + "Answer": "Wrigley Field" + }, + { + "Category": "THE HOLLYWOOD STOCK EXCHANGE", + "Question": "One of the hottest stocks of summer 2000 was for this nautical action film starring George Clooney", + "Answer": "The Perfect Storm" + }, + { + "Category": "BIBLICAL PAIRS", + "Question": "Created by God to rule the Earth in Genesis", + "Answer": "Adam & Eve" + }, + { + "Category": "ANIMAL PLANET", + "Question": "It's the double-talk name for the tropical food fish also known as the dolphinfish", + "Answer": "Mahi-mahi" + }, + { + "Category": "WHEREFORE \"ART\" THOU", + "Question": "One of these might be thrown in an English pub or shot from a blowgun in Peru", + "Answer": "Dart" + }, + { + "Category": "PRESIDENTS IN IOWA", + "Question": "He dedicated the Rathbun Dam July 31, 1971", + "Answer": "Richard Nixon" + }, + { + "Category": "THE GRIDIRON", + "Question": "[Hi, I'm Champ Bailey, college football's top defensive player of 1998] The award for top defensive player in college football is named for Bronislaw Nagurski, whose nickname was this", + "Answer": "Bronco" + }, + { + "Category": "THE HOLLYWOOD STOCK EXCHANGE", + "Question": "With the release of \"Me, Myself, and Irene\", this actor's HSX stock shot up $125", + "Answer": "Jim Carrey" + }, + { + "Category": "BIBLICAL PAIRS", + "Question": "Jesus' Earthly parents", + "Answer": "Joseph & Mary" + }, + { + "Category": "ANIMAL PLANET", + "Question": "A bean with mottled markings shares its name with this equine", + "Answer": "Pinto" + }, + { + "Category": "WHEREFORE \"ART\" THOU", + "Question": "In a nursery rhyme, a queen makes some of these only to have them stolen by a knave", + "Answer": "Tarts" + }, + { + "Category": "PRESIDENTS IN IOWA", + "Question": "Lincoln has a monument in Council Bluffs; this other president has a grave in West Branch", + "Answer": "Herbert Hoover" + }, + { + "Category": "THE GRIDIRON", + "Question": "[Hi, I'm Franco Harris, Hall of Fame running back of the Pittsburgh Steelers] In the 1972 playoff game against the Oakland Raiders, I caught a miraculous, game-winning pass that's been nicknamed this", + "Answer": "\"The Immaculate Reception\"" + }, + { + "Category": "THE HOLLYWOOD STOCK EXCHANGE", + "Question": "Millions of HSX shares of this scary movie \"project\" were traded a full year before it was released", + "Answer": "The Blair Witch Project" + }, + { + "Category": "BIBLICAL PAIRS", + "Question": "\"Hairy\" couple from Judges 16", + "Answer": "Samson & Delilah" + }, + { + "Category": "ANIMAL PLANET", + "Question": "You'll have a leg up if you know this is the correct term for a baby hippo", + "Answer": "Calf" + }, + { + "Category": "WHEREFORE \"ART\" THOU", + "Question": "Grammatically speaking, the word \"the\" is definitely one of these", + "Answer": "Article" + }, + { + "Category": "PRESIDENTS IN IOWA", + "Question": "In 1887 Cleveland attended this city's Corn Palace (or should we say Maize Palace)", + "Answer": "Sioux City" + }, + { + "Category": "THE GRIDIRON", + "Question": "[Hi, I'm Raghib Ismail of the Dallas Cowboys] While at this school, I was named MVP of the Orange Bowl on the first day of the '90s", + "Answer": "Notre Dame" + }, + { + "Category": "THE HOLLYWOOD STOCK EXCHANGE", + "Question": "\"RBRIDE\" was the HSX designation for this hot-performing stock & movie", + "Answer": "Runaway Bride" + }, + { + "Category": "BIBLICAL PAIRS", + "Question": "The sons of Rebekah", + "Answer": "Jacob & Esau" + }, + { + "Category": "ANIMAL PLANET", + "Question": "Ethiopian feline variety seen here", + "Answer": "Abyssinian" + }, + { + "Category": "WHEREFORE \"ART\" THOU", + "Question": "They can be a city's highways or a person's blood vessels", + "Answer": "Arteries" + }, + { + "Category": "PRESIDENTS IN IOWA", + "Question": "In 1975 Ford attended this, the subject of a 1945 Rodgers & Hammerstein film musical", + "Answer": "Iowa State Fair" + }, + { + "Category": "THE GRIDIRON", + "Question": "[Hi, I'm Shannon Sharpe of the Denver Broncos] In 1995 this Cowboys running back tied Jim Brown's record by scoring his 100th career TD in his 93rd NFL game", + "Answer": "Emmitt Smith" + }, + { + "Category": "THE HOLLYWOOD STOCK EXCHANGE", + "Question": "At $4,147 a share, this star of \"Firestarter\" is one of the highest-valued actresses listed on HSX", + "Answer": "Drew Barrymore" + }, + { + "Category": "BIBLICAL PAIRS", + "Question": "God & Jesus are called by these 2 Greek letters in Revelation", + "Answer": "Alpha & Omega" + }, + { + "Category": "ANIMAL PLANET", + "Question": "Useful in long-term avian study, it's the placing of metal identification tags on the legs of wild birds", + "Answer": "Banding" + }, + { + "Category": "WHEREFORE \"ART\" THOU", + "Question": "One of these might be flip, flow or pie", + "Answer": "Chart" + }, + { + "Category": "ENGLISH LITERATURE", + "Question": "A third, more sexually explicit version of this 1928 D.H. Lawrence novel was finally published in the U.S. in 1959", + "Answer": "\"Lady Chatterley's Lover\"" + }, + { + "Category": "ANCIENT COINS", + "Question": "In 44 B.C. the senate of Rome wanted his head -- on all silver coins", + "Answer": "Julius Caesar" + }, + { + "Category": "AROUND THE WORLD", + "Question": "Completed in 1345, the Ponte Vecchio crosses over the Arno River in this European country", + "Answer": "Italy" + }, + { + "Category": "20th CENTURY NICKNAMES", + "Question": "\"Hef\"", + "Answer": "Hugh Hefner" + }, + { + "Category": "MY SUITE", + "Question": "He began composing \"The Nutcracker Suite\" in 1891", + "Answer": "Pyotr Tchaikovsky" + }, + { + "Category": "EMBRACEABLE \"U\"", + "Question": "In baseball one's behind home plate & one's behind each base", + "Answer": "Umpire" + }, + { + "Category": "ENGLISH LITERATURE", + "Question": "\"The Parson's Tale\", which deals at length with the 7 deadly sins, concludes this 14th century work", + "Answer": "\"The Canterbury Tales\"" + }, + { + "Category": "ANCIENT COINS", + "Question": "The animal featured on the electrum coin of Lydia, it got the world's coinage off to a roaring success", + "Answer": "Lion" + }, + { + "Category": "AROUND THE WORLD", + "Question": "It's the largest Scottish city on the banks of the Firth of Forth", + "Answer": "Edinburgh" + }, + { + "Category": "20th CENTURY NICKNAMES", + "Question": "Aviation's \"Mysterious Billionaire\"", + "Answer": "Howard Hughes" + }, + { + "Category": "MY SUITE", + "Question": "\"Suite Bergamasque\" contains this composer's famous piece \"Clair De Lune\"", + "Answer": "Claude Debussy" + }, + { + "Category": "EMBRACEABLE \"U\"", + "Question": "It's bordered by Kenya to the east & Sudan to the north", + "Answer": "Uganda" + }, + { + "Category": "ENGLISH LITERATURE", + "Question": "Ian Fleming introduced James Bond in this 1953 novel, which became a 1967 film starring David Niven", + "Answer": "\"Casino Royale\"" + }, + { + "Category": "ANCIENT COINS", + "Question": "Around 334 B.C. this Macedonian's stater became a world currency", + "Answer": "Alexander the Great" + }, + { + "Category": "AROUND THE WORLD", + "Question": "Granite pillars support the roof of this man's burial \"hall\" near \"The Gate of Heavenly Peace\"", + "Answer": "Mao Tse-tung" + }, + { + "Category": "20th CENTURY NICKNAMES", + "Question": "Georgia's \"Miss Lillian\"", + "Answer": "Lillian Carter" + }, + { + "Category": "MY SUITE", + "Question": "It's the title of the \"chasmic\" 1931 suite heard here", + "Answer": "\"Grand Canyon Suite\"" + }, + { + "Category": "EMBRACEABLE \"U\"", + "Question": "It's the island instrument heard here", + "Answer": "Ukulele" + }, + { + "Category": "ENGLISH LITERATURE", + "Question": "This James Joyce work is a dream sequence in the minds of the Earwicker family", + "Answer": "\"Finnegans Wake\"" + }, + { + "Category": "ANCIENT COINS", + "Question": "A Knossos coin of the 4th century B.C. had this creature on the front & a labyrinth on the reverse", + "Answer": "Minotaur" + }, + { + "Category": "AROUND THE WORLD", + "Question": "In 1995 the Pacific island of Kiribati shifted this \"line\", making it the first nation to see the morning sun each day", + "Answer": "International Date Line" + }, + { + "Category": "20th CENTURY NICKNAMES", + "Question": "Cinema's \"Man of A Thousand Faces\"", + "Answer": "Lon Chaney" + }, + { + "Category": "MY SUITE", + "Question": "Go \"trolling\" with this Edvard Grieg suite that shares its name with an Ibsen work", + "Answer": "\"Peer Gynt\"" + }, + { + "Category": "EMBRACEABLE \"U\"", + "Question": "In a hit song by the Irish Rovers, these animals didn't make it onto Noah's Ark", + "Answer": "Unicorns" + }, + { + "Category": "ENGLISH LITERATURE", + "Question": "The title of this E.M. Forster novel refers to the house that belonged to Henry Wilcox' first wife", + "Answer": "\"Howards End\"" + }, + { + "Category": "ANCIENT COINS", + "Question": "Smyrna, which claimed to be the birthplace of this poet, put him on a 2nd century B.C. coin", + "Answer": "Homer" + }, + { + "Category": "AROUND THE WORLD", + "Question": "It's the river that runs through Ludwigshafen & Mannheim", + "Answer": "Rhine" + }, + { + "Category": "20th CENTURY NICKNAMES", + "Question": "\"The People's Lawyer\" & 2000 Green Party presidential candidate", + "Answer": "Ralph Nader" + }, + { + "Category": "MY SUITE", + "Question": "\"Mars\" & \"Uranus\" are famous works within his 1916 suite \"The Planets\"", + "Answer": "Gustav Holst" + }, + { + "Category": "EMBRACEABLE \"U\"", + "Question": "This technique uses high-frequency waves & is often used to view fetuses", + "Answer": "Ultrasound" + }, + { + "Category": "NOTORIOUS", + "Question": "Using the aliases James Ryan & Harry Place, they boarded a steamer for Argentina in February 1901", + "Answer": "Butch Cassidy & The Sundance Kid" + }, + { + "Category": "MUSEUMS", + "Question": "This building in Philadelphia houses the inkstand used by the Declaration signers", + "Answer": "Independence Hall" + }, + { + "Category": "DON'T QUIT YOUR DAY JOB", + "Question": "He played outfield for the Birmingham Barons before returning to the Bulls", + "Answer": "Michael Jordan" + }, + { + "Category": "THE LAW", + "Question": "During the Civil War, Lincoln suspended this right not to be held in prison without court consent", + "Answer": "Habeas corpus" + }, + { + "Category": "REEL MOTHERS", + "Question": "Kathleen Turner is a psychopathic housewife on a killing spree in this 1994 John Waters comedy", + "Answer": "Serial Mom" + }, + { + "Category": "COMMON BONDS", + "Question": "Some chairs, A toy horse, The cradle when the wind blows", + "Answer": "Things that rock" + }, + { + "Category": "SOMETHING'S A \"FOOT\"", + "Question": "12 inches of hot dog", + "Answer": "Foot long" + }, + { + "Category": "MUSEUMS", + "Question": "The Whizstreet \"Up In Smoke\" Museum is a web site exhibiting the art of these colorful cigar items", + "Answer": "Cigar bands" + }, + { + "Category": "DON'T QUIT YOUR DAY JOB", + "Question": "This TV actor heard here is not really known for his singing: \"Picture yourself...in a boat...on a river...\"", + "Answer": "William Shatner" + }, + { + "Category": "THE LAW", + "Question": "From the Latin \"to refer\", it's the way by which laws proposed by a legislature are put to popular vote", + "Answer": "Referendum" + }, + { + "Category": "REEL MOTHERS", + "Question": "Billy Crystal is meant to kill Danny DeVito's mother according to DeVito's plan in this 1987 comedy", + "Answer": "Throw Momma From The Train" + }, + { + "Category": "COMMON BONDS", + "Question": "Thunder, Ol' Man River, White House Easter Eggs", + "Answer": "Things that are rolled" + }, + { + "Category": "SOMETHING'S A \"FOOT\"", + "Question": "To pick up a check", + "Answer": "Foot the bill" + }, + { + "Category": "MUSEUMS", + "Question": "Barry Goldwater donated his Kachina doll collection to the Heard Museum in this state capital", + "Answer": "Phoenix" + }, + { + "Category": "DON'T QUIT YOUR DAY JOB", + "Question": "This supermodel starred with William Baldwin in the film \"Fair Game\", which was fair game for critics", + "Answer": "Cindy Crawford" + }, + { + "Category": "THE LAW", + "Question": "The first of these \"colorful\" laws was enacted in 1619 to punish failure to attend church", + "Answer": "Blue laws" + }, + { + "Category": "REEL MOTHERS", + "Question": "Title of the 1981 biopic about the woman seen here: \"I wouldn't turn against you if it meant my life. You are my life.\"", + "Answer": "Mommie Dearest" + }, + { + "Category": "COMMON BONDS", + "Question": "Coconuts, Udders, Canaan", + "Answer": "Things that give milk" + }, + { + "Category": "SOMETHING'S A \"FOOT\"", + "Question": "It's a small trunk kept at the foot of a soldier's bunk", + "Answer": "Footlocker" + }, + { + "Category": "MUSEUMS", + "Question": "The Eisenhower Center in this Kansas town houses numerous mementos of the president's life & career", + "Answer": "Abilene" + }, + { + "Category": "DON'T QUIT YOUR DAY JOB", + "Question": "He quit as the Beatles' bass player to become a painter in 1961", + "Answer": "Stuart Sutcliffe" + }, + { + "Category": "THE LAW", + "Question": "Failure to pay a building contractor may result in his leaning on you with this type of lien", + "Answer": "Mechanic's lien" + }, + { + "Category": "REEL MOTHERS", + "Question": "According to the theme song, this cat \"is a bad mother\" -- shut your mouth", + "Answer": "Shaft" + }, + { + "Category": "COMMON BONDS", + "Question": "A beaten wrestler, A frat brother's girlfriend, A dead butterfly", + "Answer": "Things that are pinned" + }, + { + "Category": "SOMETHING'S A \"FOOT\"", + "Question": "In tennis, it happens when the server steps over the baseline before hitting the ball", + "Answer": "Foot fault" + }, + { + "Category": "MUSEUMS", + "Question": "A Brussels art & history museum has a giant statue from this Chilean island on exhibit", + "Answer": "Easter Island" + }, + { + "Category": "DON'T QUIT YOUR DAY JOB", + "Question": "He gave up his cushy European royalty job to become emperor of Mexico, & was executed there in 1867", + "Answer": "Maximillian" + }, + { + "Category": "THE LAW", + "Question": "Now a body of lawyers, it once referred to a rail separating spectators from courtroom proceedings", + "Answer": "Bar" + }, + { + "Category": "REEL MOTHERS", + "Question": "Bill Cosby, Raquel Welch & Harvey Keitel play this title trio in a movie about an ambulance service", + "Answer": "Mother, Jugs & Speed" + }, + { + "Category": "COMMON BONDS", + "Question": "Hair, Punch, A volleyball", + "Answer": "Things that are spiked" + }, + { + "Category": "SOMETHING'S A \"FOOT\"", + "Question": "A person near death is said to have one", + "Answer": "One foot in the grave" + }, + { + "Category": "HARRY GUYS", + "Question": "There's no doubt about it, he was born Harry, but we know him as \"Bing\"", + "Answer": "\"Bing\" Crosby" + }, + { + "Category": "WE'RE MALAYSIA-BOUND", + "Question": "This capital whose name means \"muddy estuary\" was named for the 2 rivers that wind through it", + "Answer": "Kuala Lumpur" + }, + { + "Category": "FETAL ATTRACTION", + "Question": "For the first 8 weeks after fertilization, an unborn child is called this, from the Greek for \"full\"", + "Answer": "Embryo" + }, + { + "Category": "TOP 40 BONUS", + "Question": "\"Proud Mary\"", + "Answer": "Creedence Clearwater Revival & Ike & Tina Turner" + }, + { + "Category": "FROM THE JAWS OF VICTORY", + "Question": "In the Aesop fable, he's so far ahead he takes a nap; what a loser!", + "Answer": "Hare" + }, + { + "Category": "POETS' RHYME TIME", + "Question": "Sylvia's tub times", + "Answer": "Plath's baths" + }, + { + "Category": "HARRY GUYS", + "Question": "Nickname of Robert E. Lee's dad", + "Answer": "\"Lighthorse\" Harry Lee" + }, + { + "Category": "WE'RE MALAYSIA-BOUND", + "Question": "Endau-Rompin Park is one of the last homes of the Sumatran species of this horned mammal", + "Answer": "Rhinoceros" + }, + { + "Category": "FETAL ATTRACTION", + "Question": "Named for the sac surrounding the fetus, this fluid cushions the fetus from injury", + "Answer": "Amniotic fluid" + }, + { + "Category": "TOP 40 BONUS", + "Question": "\"Live And Let Die\"", + "Answer": "Wings & Guns N' Roses" + }, + { + "Category": "FROM THE JAWS OF VICTORY", + "Question": "He was the Democratic presidential frontrunner in 1987 until his \"Monkey Business\" did him in", + "Answer": "Gary Hart" + }, + { + "Category": "POETS' RHYME TIME", + "Question": "Ezra's Afghans", + "Answer": "Pound's hounds" + }, + { + "Category": "HARRY GUYS", + "Question": "He's the Harry heard here: \"Dayyy....\"", + "Answer": "Harry Belafonte" + }, + { + "Category": "WE'RE MALAYSIA-BOUND", + "Question": "Of proton, electron or neutron, with \"Saga\", it's Malaysia's national car", + "Answer": "Proton" + }, + { + "Category": "FETAL ATTRACTION", + "Question": "Pre-natal process that created the images seen here:", + "Answer": "Ultrasound" + }, + { + "Category": "TOP 40 BONUS", + "Question": "\"California Girls\"", + "Answer": "The Beach Boys & David Lee Roth" + }, + { + "Category": "FROM THE JAWS OF VICTORY", + "Question": "By allowing rebel forces to escape after Gettysburg, this Union general may have prolonged the war 2 more years", + "Answer": "George Meade" + }, + { + "Category": "POETS' RHYME TIME", + "Question": "Alexander's expectations", + "Answer": "Pope's hopes" + }, + { + "Category": "HARRY GUYS", + "Question": "Watergate-era chief of staff, his initial \"H\" stood for Harry", + "Answer": "HR Haldeman" + }, + { + "Category": "WE'RE MALAYSIA-BOUND", + "Question": "The states of Sarawak & Sabah on this island make up about 6% of Malaysia's land area", + "Answer": "Borneo" + }, + { + "Category": "FETAL ATTRACTION", + "Question": "From the Greek for \"flat cake\", this uterine wall organ connects to the fetus via the umbilical cord", + "Answer": "Placenta" + }, + { + "Category": "TOP 40 BONUS", + "Question": "\"Blue Bayou\"", + "Answer": "Linda Ronstadt & Roy Orbison" + }, + { + "Category": "FROM THE JAWS OF VICTORY", + "Question": "She became Texas' governor in 1990 when her frontrunner opponent kept blundering in interviews", + "Answer": "Ann Richards" + }, + { + "Category": "POETS' RHYME TIME", + "Question": "William's anacondas", + "Answer": "Blake's snakes" + }, + { + "Category": "HARRY GUYS", + "Question": "This trumpet-playing band-leader helped Sinatra get started, & lost him to the Tommy Dorsey band", + "Answer": "Harry James" + }, + { + "Category": "WE'RE MALAYSIA-BOUND", + "Question": "Go \"strait\" to this port & visit St. Paul's Church where St. Francis Xavier's body was held until moved to India", + "Answer": "Malacca" + }, + { + "Category": "FETAL ATTRACTION", + "Question": "Even at birth the skull isn't fully fused, leaving these, also called \"soft spots\"", + "Answer": "Fontenelles" + }, + { + "Category": "TOP 40 BONUS", + "Question": "\"Soul Man\"", + "Answer": "The Blues Brothers & Sam & Dave" + }, + { + "Category": "FROM THE JAWS OF VICTORY", + "Question": "Heavy armor & heavy rains defeated the large French army as much as Henry V's men at this 1415 battle", + "Answer": "Agincourt" + }, + { + "Category": "POETS' RHYME TIME", + "Question": "Sir Philip's renal organs", + "Answer": "Sidney's kidneys" + }, + { + "Category": "ENGLISH LITERATURE", + "Question": "The 5th edition of this work, published in 1676, included a section on fly fishing by Charles Cotton", + "Answer": "The Compleat Angler" + }, + { + "Category": "HOW INSPIRATIONAL", + "Question": "When your prom date leaves the dance without you, recall the proverb, this \"heals all wounds\"", + "Answer": "time" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "In 2007 Marie Osmond blamed allergies & L.A. air quality for her waltz into unconsciousness on this show", + "Answer": "Dancing with the Stars" + }, + { + "Category": "FOOD FACTS", + "Question": "Carob yields a sweet pulp that is roasted, ground, & used as a substitute for this flavoring", + "Answer": "chocolate" + }, + { + "Category": "CAPITAL IDEA", + "Question": "Long before it was a capital, this city on the Thames River was a communications center", + "Answer": "London" + }, + { + "Category": "THE TEENS", + "Question": "Sounds unlucky, but there were this many books in Lemony Snicket's \"Series of Unfortunate Events\"", + "Answer": "13" + }, + { + "Category": "WORD ORIGINS", + "Question": "The name of this, also called a fireplug, is partly from a word for \"water\"", + "Answer": "a hydrant" + }, + { + "Category": "HOW INSPIRATIONAL", + "Question": "This saint of Assisi said, \"Where there is hatred, let me sow love... where there is despair, hope\"", + "Answer": "Francis" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "Simon said \"Simply dreadful... appalling\" on this show that debuted on Fox in June '02", + "Answer": "American Idol" + }, + { + "Category": "FOOD FACTS", + "Question": "Bursting with beta carotene, the melon we call this is actually a type of muskmelon", + "Answer": "the cantaloupe" + }, + { + "Category": "CAPITAL IDEA", + "Question": "Though Kyoto remained the imperial capital, Tokugawa Ieyasu made this obscure village his capital", + "Answer": "Tokyo" + }, + { + "Category": "THE TEENS", + "Question": "Sonnets are rhymed poems with this many lines", + "Answer": "14" + }, + { + "Category": "WORD ORIGINS", + "Question": "The name of this bread spread goes all the way back to bous, a Greek word for \"cow\"", + "Answer": "butter" + }, + { + "Category": "HOW INSPIRATIONAL", + "Question": "Thinking of his sins, poet Heinrich Heine said, \"Of course\" God will do this to \"me; that's his business\"", + "Answer": "forgive" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "Justin Timberlake had a rough day on this MTV show: phony \"tax agents\" said he owed $900,000 & raided his house", + "Answer": "Punk'd" + }, + { + "Category": "FOOD FACTS", + "Question": "Cannellini is a white kidney bean, cannelloni is a type of this", + "Answer": "pasta" + }, + { + "Category": "CAPITAL IDEA", + "Question": "A small village sacked by Mongol as well as Afghan invaders, it later became the largest Persian city", + "Answer": "Tehran" + }, + { + "Category": "THE TEENS", + "Question": "Rack all your pins in bowling & 10 are set up; rack your balls in a game of 8-ball & this many are set up", + "Answer": "15" + }, + { + "Category": "WORD ORIGINS", + "Question": "These sparkly fake gems are partly named for a river that flows through Germany", + "Answer": "rhinestones" + }, + { + "Category": "HOW INSPIRATIONAL", + "Question": "In 1903 Pope Pius X wrote, \"Where justice is lacking there can be no hope of\" this, pax in Latin", + "Answer": "peace" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "We're still waiting for a \"Des Moines\" version of this CBS crime show to accompany the Vegas, Miami & N.Y. ones", + "Answer": "CSI" + }, + { + "Category": "FOOD FACTS", + "Question": "This word was once used for the meat of any hunted animal; now it refers to deer meat", + "Answer": "venison" + }, + { + "Category": "CAPITAL IDEA", + "Question": "This capital was created because Rio de Janeiro was overcrowded & isolated from the rest of the country", + "Answer": "Brasilia" + }, + { + "Category": "THE TEENS", + "Question": "Including wisdom teeth, the number of teeth typically found in the fully developed adult upper jaw", + "Answer": "16" + }, + { + "Category": "WORD ORIGINS", + "Question": "The name of this type of reference work is from the Greek for \"cyclical\" (i.e., well-rounded) & \"education\"", + "Answer": "an encyclopedia" + }, + { + "Category": "HOW INSPIRATIONAL", + "Question": "This \"Candide\" author helped popularize the saying, \"The perfect is the enemy of the good\"", + "Answer": "Voltaire" + }, + { + "Category": "WHAT'S ON TV?", + "Question": "Bryan Fuller created this show about a piemaker whose touch can bring the dead to life", + "Answer": "Pushing Daisies" + }, + { + "Category": "FOOD FACTS", + "Question": "Mostly made from the whites, egg substitutes don't contain fat or this artery-clogging lipid", + "Answer": "cholesterol" + }, + { + "Category": "CAPITAL IDEA", + "Question": "One of the oldest continuously inhabited cities, it became a capital in 1946 when Syria gained independence", + "Answer": "Damascus" + }, + { + "Category": "THE TEENS", + "Question": "In \"The Sound of Music\", Liesl was \"going on\" this number", + "Answer": "17" + }, + { + "Category": "WORD ORIGINS", + "Question": "This 5-letter synonym of \"question\" comes from the Latin for \"to ask\" or \"to seek\"", + "Answer": "a query" + }, + { + "Category": "BLACK HISTORY MONTH", + "Question": "Melville said this abolitionist who was hanged in Charlestown, Va. in 1859 was \"the meteor of the war\"", + "Answer": "John Brown" + }, + { + "Category": "BALLS", + "Question": "To start your golf round, put your ball up on one of these little pegs", + "Answer": "a tee" + }, + { + "Category": "THE JEFFERSON ADMINISTRATION", + "Question": "In April 1803 Napoleon renounced this territory in America \"with the greatest regret\"; so we bought it", + "Answer": "the Louisiana Territory" + }, + { + "Category": "IT'S RAINING \"MN\"", + "Question": "Catch the flue here, where fire goes up in smoke", + "Answer": "a chimney" + }, + { + "Category": "FIRSTS", + "Question": "The Scott brothers sold rolls of this in 1890; 2-ply came later", + "Answer": "toilet paper" + }, + { + "Category": "LASTS", + "Question": "Alphabetically last of our solar system's planets", + "Answer": "Venus" + }, + { + "Category": "BLACK HISTORY MONTH", + "Question": "Jackie Robinson broke baseball's color line in 1947 when he was signed by this team", + "Answer": "the Dodgers" + }, + { + "Category": "BALLS", + "Question": "Kermit the Frog's eyeballs were originally made of these light sports balls", + "Answer": "ping pong balls" + }, + { + "Category": "THE JEFFERSON ADMINISTRATION", + "Question": "In 1807, after a trip up the Hudson, he wrote, \"The power of propelling boats by steam is now fully proved\"", + "Answer": "Fulton" + }, + { + "Category": "IT'S RAINING \"MN\"", + "Question": "If you're sleepless in Seattle you're suffering from this malady", + "Answer": "insomnia" + }, + { + "Category": "FIRSTS", + "Question": "Marie Antoinette is credited with introducing these rolls to France", + "Answer": "croissants" + }, + { + "Category": "LASTS", + "Question": "Though this book has the word \"last\" in its title, it's only the second of the 5 \"Leatherstocking Tales\"", + "Answer": "The Last of the Mohicans" + }, + { + "Category": "BLACK HISTORY MONTH", + "Question": "Harlem had one of these literary & cultural rebirths in the '20s & '30s", + "Answer": "renaissance" + }, + { + "Category": "BALLS", + "Question": "A target ball called a \"pallino\" is thrown first in this Italian ball game", + "Answer": "bocce" + }, + { + "Category": "THE JEFFERSON ADMINISTRATION", + "Question": "On July 12, 1808 this large city's Missouri Gazette became the first newspaper published west of the Mississippi", + "Answer": "St. Louis" + }, + { + "Category": "IT'S RAINING \"MN\"", + "Question": "'Tis this season (of the year)", + "Answer": "autumn" + }, + { + "Category": "FIRSTS", + "Question": "Event at which Jesus performed his first miracle, providing enough wine for a feast", + "Answer": "the wedding at Cana" + }, + { + "Category": "LASTS", + "Question": "In 1966 Congress authorized the Uniform Time Act, creating this from the last Sunday in April to the last Sunday in October", + "Answer": "daylight savings time" + }, + { + "Category": "BALLS", + "Question": "In racquetball, the ball must strike the front wall before hitting this", + "Answer": "the ground" + }, + { + "Category": "THE JEFFERSON ADMINISTRATION", + "Question": "In 1807 Jefferson tried to have this man, his first vice president, convicted of treason", + "Answer": "Aaron Burr" + }, + { + "Category": "IT'S RAINING \"MN\"", + "Question": "6-letter word meaning mirthless, sober, or grave", + "Answer": "solemn" + }, + { + "Category": "FIRSTS", + "Question": "The first meeting of this international assembly convened November 15, 1920", + "Answer": "the League of Nations" + }, + { + "Category": "LASTS", + "Question": "The Battle of Castillon in 1453 was the last battle of this war that began back in 1337", + "Answer": "the Hundred Years' War" + }, + { + "Category": "BLACK HISTORY MONTH", + "Question": "In 1957 Martin Luther King helped establish this religious organization, the SCLC", + "Answer": "Southern Christian Leadership Conference" + }, + { + "Category": "THE JEFFERSON ADMINISTRATION", + "Question": "In 1805 U.S. Marines stormed the shores of this Barbary state at Derna, helping to end the raids on American ships", + "Answer": "Tripoli" + }, + { + "Category": "IT'S RAINING \"MN\"", + "Question": "Please don't forget this word, from the Greek for \"oblivion\"", + "Answer": "amnesia" + }, + { + "Category": "FIRSTS", + "Question": "On December 7, 1787, Delaware became the 1st state to do this", + "Answer": "ratify the U.S. Constitution" + }, + { + "Category": "LASTS", + "Question": "The name of the last dynasty to rule Vietnam, it's the family name of about half Vietnam's people", + "Answer": "Nguyen" + }, + { + "Category": "CHARACTERS IN BOOKS", + "Question": "This character says, \"It's Christmas Day! I haven't missed it. The Spirits have done it all in one night\"", + "Answer": "Ebenezer Scrooge" + }, + { + "Category": "HISTORIC DATES", + "Question": "He was shot on Sept. 6, 1901 while shaking hands with a crowd of well-wishers at the Pan-American Exposition", + "Answer": "McKinley" + }, + { + "Category": "SPORTS SHORTS", + "Question": "In 2008 he swam 200 meters freestyle in a record 1 minute, 42.96 seconds", + "Answer": "Michael Phelps" + }, + { + "Category": "ONE LETTER DIFFERENT", + "Question": "A large sack", + "Answer": "a big bag" + }, + { + "Category": "THE LAND", + "Question": "This country is \"The Land of the Shamrock\"", + "Answer": "Ireland" + }, + { + "Category": "OF MILK", + "Question": "In mammals, milk is secreted by these glands", + "Answer": "mammary glands" + }, + { + "Category": "& HONEY", + "Question": "& Honey, could you pick up some of the Huggies brand of these on the way home?", + "Answer": "diapers" + }, + { + "Category": "HISTORIC DATES", + "Question": "On May 17, 1954 the Supreme Court ruled on this case, unanimously outlawing public school segregation", + "Answer": "Brown vs. the Board of Education" + }, + { + "Category": "SPORTS SHORTS", + "Question": "This manager went out on top when he called it quits Oct. 31, 2011", + "Answer": "La Russa" + }, + { + "Category": "ONE LETTER DIFFERENT", + "Question": "Excellent eats", + "Answer": "good food" + }, + { + "Category": "THE LAND", + "Question": "Victoria Land, one of its regions, lies north of the Ross Ice Shelf", + "Answer": "Antarctica" + }, + { + "Category": "OF MILK", + "Question": "Many countries have laws requiring that milk undergo this process that guards against pathogens", + "Answer": "pasteurization" + }, + { + "Category": "HISTORIC DATES", + "Question": "The Egyptian government opened his mummy case on March 6, 1924", + "Answer": "Tutankhamun" + }, + { + "Category": "SPORTS SHORTS", + "Question": "In 2011 this QB was a first-round draft pick by Carolina", + "Answer": "Newton" + }, + { + "Category": "ONE LETTER DIFFERENT", + "Question": "Humorous wordplay about a quill", + "Answer": "a pen pun" + }, + { + "Category": "THE LAND", + "Question": "Look east! Japan has long been known by this dawning nickname", + "Answer": "the Land of the Rising Sun" + }, + { + "Category": "OF MILK", + "Question": "This sugar makes up almost all the carbohydrates in milk", + "Answer": "lactose" + }, + { + "Category": "& HONEY", + "Question": "& Honey, it's May--we gotta call your mom in London for Mother's Day; don't forget it's this many hours ahead of N.Y. time", + "Answer": "five" + }, + { + "Category": "HISTORIC DATES", + "Question": "He dissolved England's Rump Parliament on April 20, 1653", + "Answer": "Cromwell" + }, + { + "Category": "SPORTS SHORTS", + "Question": "He split 2 1980 title fights with Roberto Duran", + "Answer": "Sugar Ray Leonard" + }, + { + "Category": "ONE LETTER DIFFERENT", + "Question": "A hole in the ground for your baked pastry", + "Answer": "a pie pit" + }, + { + "Category": "THE LAND", + "Question": "After killing Abel, Cain was banished to the sleepy-sounding land of this place, east of Eden", + "Answer": "Nod" + }, + { + "Category": "OF MILK", + "Question": "Canned milk that has 60% of the water removed is known by this 10-letter term", + "Answer": "evaporated" + }, + { + "Category": "& HONEY", + "Question": "& Honey, could you take the minivan to the mechanic? It's still making noise here, also called the gearbox", + "Answer": "the transmission" + }, + { + "Category": "HISTORIC DATES", + "Question": "The accident of April 25-26, 1986 at this facility was caused by a poorly designed experiment at its reactor unit 4", + "Answer": "Chernobyl" + }, + { + "Category": "SPORTS SHORTS", + "Question": "Since 2009 the Mercury, Storm & Lynx have been championship teams in this league", + "Answer": "the WNBA" + }, + { + "Category": "ONE LETTER DIFFERENT", + "Question": "A speechless minute arachnid", + "Answer": "a mute mite" + }, + { + "Category": "THE LAND", + "Question": "The name of this state is from Choctaw & means it's the land of the \"red people\"", + "Answer": "Oklahoma" + }, + { + "Category": "OF MILK", + "Question": "Mongolians cool off with airag, a slightly fermented version of this alliterative liquid", + "Answer": "mare's milk" + }, + { + "Category": "& HONEY", + "Question": "& Honey, while you're up, can you grab my copy of \"Caligula\" by this French-Algerian author? He's so existential", + "Answer": "Camus" + }, + { + "Category": "ANY FIRST WORDS?", + "Question": "Meaning \"first\", it can precede color, election or health care", + "Answer": "primary" + }, + { + "Category": "MISCELLAN\"IUM\"", + "Question": "Not just women but men over 50 also need at least 1,200 mg of this bone-building element daily", + "Answer": "calcium" + }, + { + "Category": "OLD VIRGINIA", + "Question": "He was cornered & fatally wounded by federal troops on a farm near Port Royal, Virginia on April 26, 1865", + "Answer": "John Wilkes Booth" + }, + { + "Category": "BARTLETT'S PAIRS", + "Question": "Ernest L. Thayer is represented by a pair of quotations, both from this baseball poem", + "Answer": "\"Casey at the Bat\"" + }, + { + "Category": "ANY FIRST WORDS?", + "Question": "Aussies are familiar with this term for native inhabitants that once referred to pre-Roman Italians", + "Answer": "aborigines" + }, + { + "Category": "POP CULTURE", + "Question": "Snow White & Prince Charming are characters on this TV show set in the town of Storybrooke", + "Answer": "Once Upon a Time" + }, + { + "Category": "MISCELLAN\"IUM\"", + "Question": "For many centuries this drug derived from a poppy was the main painkiller used in medicine", + "Answer": "opium" + }, + { + "Category": "OLD VIRGINIA", + "Question": "President Jefferson sent this fellow Virginian, later our 5th president, to negotiate the Louisiana Purchase", + "Answer": "Monroe" + }, + { + "Category": "BARTLETT'S PAIRS", + "Question": "Fred Allen gets 2 zingers, including \"California's a wonderful place to live--if you happen to be\" this fruit", + "Answer": "orange" + }, + { + "Category": "ANY FIRST WORDS?", + "Question": "An adjective meaning \"first\", or a letter like \"F\" in F. Murray Abraham", + "Answer": "an initial" + }, + { + "Category": "POP CULTURE", + "Question": "This man who died in 1918 was Snoopy's cursed nemesis in \"Peanuts\"", + "Answer": "the Red Baron" + }, + { + "Category": "MISCELLAN\"IUM\"", + "Question": "Once the open main court of a Roman house, it's now a skylit central court in an office building or hotel", + "Answer": "atrium" + }, + { + "Category": "OLD VIRGINIA", + "Question": "In 1699 the capital of Virginia was moved from Jamestown to this city", + "Answer": "Williamsburg" + }, + { + "Category": "BARTLETT'S PAIRS", + "Question": "Kenneth Grahame's 2 quotes both come from this children's book", + "Answer": "The Wind in the Willows" + }, + { + "Category": "ANY FIRST WORDS?", + "Question": "Something that's leading in every respect is \"first &\" this superlative adjective", + "Answer": "foremost" + }, + { + "Category": "POP CULTURE", + "Question": "In a 2011 movie comedy, the 3 title \"horrible\" these were summarized as psycho, maneater & tool", + "Answer": "bosses" + }, + { + "Category": "MISCELLAN\"IUM\"", + "Question": "The Latin name for ancient Troy, it's also a broad flat hipbone", + "Answer": "Ilium" + }, + { + "Category": "OLD VIRGINIA", + "Question": "In 1763 this gifted orator & lawyer presented the \"Parson's Cause\", an early test case of royal authority", + "Answer": "Patrick Henry" + }, + { + "Category": "BARTLETT'S PAIRS", + "Question": "The 2 quotes by Charles Evans Hughes, the USA's 11th this, include \"The Constitution is what the judges say it is\"", + "Answer": "Chief Justice" + }, + { + "Category": "ANY FIRST WORDS?", + "Question": "Jung was fond of this word, an original pattern from which all similar things are based", + "Answer": "an archetype" + }, + { + "Category": "POP CULTURE", + "Question": "This late country singer called his autobiography \"Thirty Years of Sausage, Fifty Years of Ham\"", + "Answer": "Jimmy Dean" + }, + { + "Category": "MISCELLAN\"IUM\"", + "Question": "It's the muscle tissue that forms the middle layer of the heart's walls", + "Answer": "myocardium" + }, + { + "Category": "OLD VIRGINIA", + "Question": "In 1716 Virginia's governor claimed possession of this scenic valley for England", + "Answer": "the Shenandoah Valley" + }, + { + "Category": "BARTLETT'S PAIRS", + "Question": "The first of this French playwright's 2 quotes begins, \"A great nose indicates a great man\"", + "Answer": "Edmond Rostand" + }, + { + "Category": "FATHERS & SONS", + "Question": "The island where this man's son washed ashore was later named Ikaria", + "Answer": "Daedalus" + }, + { + "Category": "BIBLICAL QUOTES", + "Question": "She commanded Samson, \"Tell me, I pray thee, wherein thy great strength lieth\"", + "Answer": "Delilah" + }, + { + "Category": "ROCK FORMATIONS", + "Question": "Kurt Cobain & Krist Novoselic met through Buzz Osborne, leader of the Melvins, & found freedom as this group in 1987", + "Answer": "Nirvana" + }, + { + "Category": "FASHIONABLE COMMON BONDS", + "Question": "Hobble, wrap, micro mini", + "Answer": "skirt" + }, + { + "Category": "FUNDRAISING", + "Question": "Keep a big donor's gifts flowing: put him on this \"of directors\" or \"of governors\"", + "Answer": "board" + }, + { + "Category": "DELAWARE", + "Question": "Home to a major U.S. Air Force base, this capital was founded in 1683", + "Answer": "Dover" + }, + { + "Category": "THE \"FIRST\" STATE", + "Question": "In 1887 Joseph Conrad gained literary material sailing as this on a ship bound for Java", + "Answer": "first mate" + }, + { + "Category": "BIBLICAL QUOTES", + "Question": "This disciple wouldn't believe Jesus' resurrection until he saw \"in his hands the print of the nails\"", + "Answer": "Thomas" + }, + { + "Category": "ROCK FORMATIONS", + "Question": "This Jimmy Page foursome first played together as part of the session group on P.J. Proby's \"Three Week Hero\"", + "Answer": "Led Zeppelin" + }, + { + "Category": "FASHIONABLE COMMON BONDS", + "Question": "Action, kid, opera", + "Answer": "gloves" + }, + { + "Category": "FUNDRAISING", + "Question": "This service's code says donors to a 501 (c)(3) organization can generally take a tax deduction", + "Answer": "the IRS" + }, + { + "Category": "DELAWARE", + "Question": "Delaware has this many representatives in the U.S. House", + "Answer": "1" + }, + { + "Category": "THE \"FIRST\" STATE", + "Question": "Ryan Howard's day job with the Phillies", + "Answer": "first baseman" + }, + { + "Category": "BIBLICAL QUOTES", + "Question": "In Exodus Moses & Aaron inform pharaoh that the lord has this very strong 4-word suggestion", + "Answer": "\"Let my people go\"" + }, + { + "Category": "ROCK FORMATIONS", + "Question": "Jack wed Meg & took her name, & in 1997 formed this band on a lark, with him on bass & her on drums", + "Answer": "The White Stripes" + }, + { + "Category": "FASHIONABLE COMMON BONDS", + "Question": "Puritan, Peter Pan, choir-boy", + "Answer": "collars" + }, + { + "Category": "FUNDRAISING", + "Question": "Chilly alliterative term for phoning someone to ask for money without any prior notice", + "Answer": "cold call" + }, + { + "Category": "DELAWARE", + "Question": "Designated in 1999, the tiger swallowtail is Delaware's official one of these insects", + "Answer": "butterfly" + }, + { + "Category": "THE \"FIRST\" STATE", + "Question": "In 1975 Donald Johanson found a group of 13 hominid fossils he dubbed this, like the Nixons or Trumans", + "Answer": "the first family" + }, + { + "Category": "BIBLICAL QUOTES", + "Question": "Herod thought that Jesus was this man \"whom I beheaded: he is risen from the dead\"", + "Answer": "John the Baptist" + }, + { + "Category": "ROCK FORMATIONS", + "Question": "This punk group was the brainchild of entrepreneur Malcolm McLaren, who asked John Lydon to be its lead singer", + "Answer": "The Sex Pistols" + }, + { + "Category": "FASHIONABLE COMMON BONDS", + "Question": "French, Cuban, wedge", + "Answer": "heels" + }, + { + "Category": "FUNDRAISING", + "Question": "Donations in the form of equipment or time instead of money are called \"in\" this 4-letter word", + "Answer": "in kind" + }, + { + "Category": "DELAWARE", + "Question": "Nicknamed \"Pete\", this former gov. of Delaware once worked in the chemical co. his ancestors founded in 1802", + "Answer": "du Pont" + }, + { + "Category": "THE \"FIRST\" STATE", + "Question": "This nuclear capability is designed to completely knock out an enemy's ability to respond to your attack", + "Answer": "first strike" + }, + { + "Category": "BIBLICAL QUOTES", + "Question": "In Proverbs this king writes, \"The fear of the Lord is the beginning of knowledge\"", + "Answer": "Solomon" + }, + { + "Category": "ROCK FORMATIONS", + "Question": "This Southern California group was originally assembled as a backup band for Linda Ronstadt", + "Answer": "The Eagles" + }, + { + "Category": "FASHIONABLE COMMON BONDS", + "Question": "Hobo, envelope, beaded", + "Answer": "purses" + }, + { + "Category": "FUNDRAISING", + "Question": "In fundraising DM stands for this mail, which aims to scare up new donors", + "Answer": "direct mail" + }, + { + "Category": "DELAWARE", + "Question": "Sailing under a Dutch flag, this English navigator & explorer discovered Delaware in 1609", + "Answer": "Henry Hudson" + }, + { + "Category": "THE \"FIRST\" STATE", + "Question": "In a symphony orchestra, the leader of this group serves as concertmaster", + "Answer": "first violin" + }, + { + "Category": "REAL TO REEL", + "Question": "This 1984 movie recounted the friendship of an American journalist & a translator in war-torn Cambodia", + "Answer": "The Killing Fields" + }, + { + "Category": "THROUGH THE 1800s WITH SARAH POLK", + "Question": "Born in 1803 in Tennessee, Sarah later attended school in this state due east, husband James' birthplace", + "Answer": "North Carolina" + }, + { + "Category": "BULL", + "Question": "John Travolta & Debra Winger demonstrated the fine art of riding a mechanical bull at Gilley's in this 1980 film", + "Answer": "Urban Cowboy" + }, + { + "Category": "COMMON ABBREVIATIONS", + "Question": "All things considered, NPR is this popular listening place", + "Answer": "National Public Radio" + }, + { + "Category": "BASIC SCIENCE", + "Question": "The name of this green pigment found in plants is partly from the Greek for \"green\"", + "Answer": "chlorophyll" + }, + { + "Category": "REAL TO REEL", + "Question": "In \"Changeling\" she plays a mom who takes on the LAPD after her son disappears & a different boy is returned to her", + "Answer": "Angelina Jolie" + }, + { + "Category": "THROUGH THE 1800s WITH SARAH POLK", + "Question": "In the 1840s First Lady Sarah, seeing James enter rooms unnoticed, made this song a regular feature of his entrances", + "Answer": "\"Hail To The Chief\"" + }, + { + "Category": "BULL", + "Question": "This energy drink was originally developed by a Thai businessman in 1962 & sold under the name Krating Daeng", + "Answer": "Red Bull" + }, + { + "Category": "THERE ARE SOME STRINGS ATTACHED", + "Question": "This guitar family member's circular body is covered in front with tightly stretched plastic or parchment", + "Answer": "a banjo" + }, + { + "Category": "COMMON ABBREVIATIONS", + "Question": "Plan for your golden years by putting money in an IRA, one of these", + "Answer": "an individual retirement account" + }, + { + "Category": "BASIC SCIENCE", + "Question": "Newton's first law, about bodies at rest & in motion, is also called the law of this", + "Answer": "the law of inertia" + }, + { + "Category": "REAL TO REEL", + "Question": "African captives revolt aboard their slave ship & then have to stand trial in this movie based on an 1839 event", + "Answer": "Amistad" + }, + { + "Category": "THROUGH THE 1800s WITH SARAH POLK", + "Question": "During the Civil War, Mrs. Polk's Tennessee home had this official status & both union & CSA leaders visited", + "Answer": "neutrality" + }, + { + "Category": "BULL", + "Question": "In 1996 Standing Rock College of Fort Yates, N.D., a Native American school, changed its name to this for a Sioux chief", + "Answer": "Sitting Bull" + }, + { + "Category": "COMMON ABBREVIATIONS", + "Question": "A PAC, one of these, might help your electoral chances", + "Answer": "a political action committee" + }, + { + "Category": "BASIC SCIENCE", + "Question": "Graphite is a soft form of this element", + "Answer": "carbon" + }, + { + "Category": "REAL TO REEL", + "Question": "In this 1990 movie Robin Williams played a doctor who roused a group of patients out of their catatonic states", + "Answer": "Awakenings" + }, + { + "Category": "THROUGH THE 1800s WITH SARAH POLK", + "Question": "In 1877 Sarah got the first one of these ever hooked up in Nashville", + "Answer": "a telephone" + }, + { + "Category": "BULL", + "Question": "In 1923 James Cummings & Earl McLeod designed the first one of these using a Model T frame & a wooden blade", + "Answer": "a bulldozer" + }, + { + "Category": "THERE ARE SOME STRINGS ATTACHED", + "Question": "On this pre-piano item played by Lurch on TV, the strings are plucked by points connected with the keys", + "Answer": "a harpsichord" + }, + { + "Category": "COMMON ABBREVIATIONS", + "Question": "Yes, sir! A PFC is one of these in the military", + "Answer": "a private first class" + }, + { + "Category": "REAL TO REEL", + "Question": "In this movie Meryl Streep as Aussie mom Lindy Chamberlain exclaimed, \"The dingo's got my baby!\"", + "Answer": "A Cry In The Dark" + }, + { + "Category": "THROUGH THE 1800s WITH SARAH POLK", + "Question": "In 1888 Mrs. Polk pushed a button in Nashville & these came on at the Cincinnati Centennial Expo", + "Answer": "the lights" + }, + { + "Category": "BULL", + "Question": "\"Bull City\", this place's nickname, is derived from a product sold by American Tobacco", + "Answer": "Durham" + }, + { + "Category": "COMMON ABBREVIATIONS", + "Question": "To a home viewer, a DVD is one of these", + "Answer": "a digital video disc" + }, + { + "Category": "AMERICAN FICTION WRITERS", + "Question": "He was also the U.S.'s best-paid sportswriter, with stories of people like Chicago O'Brien & Jack the Bookie", + "Answer": "Damon Runyon" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "In 1997 a Houston airport was renamed in honor of this recent president", + "Answer": "George H.W. Bush" + }, + { + "Category": "BUSINESS PARTNERS", + "Question": "In dessert: Burton Baskin &...", + "Answer": "Irv Robbins" + }, + { + "Category": "BORN IN THE WINDY CITY", + "Question": "This Chicago native worked as a DJ in Vietnam & a weatherman in Nashville before hosting \"Wheel of Fortune\"", + "Answer": "Pat Sajak" + }, + { + "Category": "HIT TUNES", + "Question": "\"Where The Streets Have No Name\", \"With Or Without You\"", + "Answer": "U2" + }, + { + "Category": "WHAT THE KIDS ARE CALLING IT", + "Question": "On your phone & in conversation, these numbers mean information", + "Answer": "411" + }, + { + "Category": "BUT IS IT ART?", + "Question": "It can be a gamble to hang the well-known image of dogs playing this card game", + "Answer": "Poker" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "Nearly 91 when he died the same day as Thomas Jefferson, he was the longest-lived president", + "Answer": "John Adams" + }, + { + "Category": "BUSINESS PARTNERS", + "Question": "In tools: Duncan Black &...", + "Answer": "Alonzo Decker" + }, + { + "Category": "BORN IN THE WINDY CITY", + "Question": "In the film \"Animal House\", this Chicago native played wild & crazy \"Bluto\" Blutarsky", + "Answer": "John Belushi" + }, + { + "Category": "HIT TUNES", + "Question": "\"Iris\", \"Slide\"", + "Answer": "Goo Goo Dolls" + }, + { + "Category": "WHAT THE KIDS ARE CALLING IT", + "Question": "To Grandpa it meant he'd stirred up & fed a fire; to his grandson it means happy or excited", + "Answer": "Stoked" + }, + { + "Category": "BUT IS IT ART?", + "Question": "The Mitchell, South Dakota \"palace\" seen here is built of & named for this cereal grain", + "Answer": "Corn" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "It was the last name of the 17th & 36th presidents", + "Answer": "Johnson" + }, + { + "Category": "BUSINESS PARTNERS", + "Question": "In a brokerage: William Paine &...", + "Answer": "Wallace Webber" + }, + { + "Category": "BORN IN THE WINDY CITY", + "Question": "Tarzan was the most famous creation of this Chicago-born writer", + "Answer": "Edgar Rice Burroughs" + }, + { + "Category": "HIT TUNES", + "Question": "\"Angel\", \"Building A Mystery\"", + "Answer": "Sarah McLachlan" + }, + { + "Category": "WHAT THE KIDS ARE CALLING IT", + "Question": "This brand name means to eat voraciously, or to vacuum", + "Answer": "Hoover" + }, + { + "Category": "BUT IS IT ART?", + "Question": "The work of \"Artists Barely in Control of the Brush\" is seen at Boston's MOBA, museum of this art", + "Answer": "Bad art" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "For helping to end the Russo-Japanese War, he was awarded the 1906 Nobel Peace Prize", + "Answer": "Theodore Roosevelt" + }, + { + "Category": "BUSINESS PARTNERS", + "Question": "In paint: Henry Sherwin &...", + "Answer": "Edward Williams" + }, + { + "Category": "BORN IN THE WINDY CITY", + "Question": "On the big screen, this Chicagoan has played Rick Deckard, Jack Ryan & Han Solo", + "Answer": "Harrison Ford" + }, + { + "Category": "HIT TUNES", + "Question": "\"Doo Wop (That Thing)\"", + "Answer": "Lauryn Hill" + }, + { + "Category": "WHAT THE KIDS ARE CALLING IT", + "Question": "A sports team member who sees many women at once fits 2 definitions of this word", + "Answer": "Player" + }, + { + "Category": "BUT IS IT ART?", + "Question": "Julian Schnabel won acclaim & abuse with his 1979 paintings that featured this tableware, broken in pieces", + "Answer": "Dishes" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "In the campaign slogan \"Tippecanoe and Tyler Too\", he's Tippecanoe", + "Answer": "William Henry Harrison" + }, + { + "Category": "BUSINESS PARTNERS", + "Question": "In paper products: John Kimberly &...", + "Answer": "Charles Clark" + }, + { + "Category": "BORN IN THE WINDY CITY", + "Question": "You're keeping up with the Joneses if you name this producer of \"Thriller\" who was born in Chicago in 1933", + "Answer": "Quincy Jones" + }, + { + "Category": "HIT TUNES", + "Question": "\"How's It Going to Be\", \"Semi-Charmed Life\"", + "Answer": "Third Eye Blind" + }, + { + "Category": "WHAT THE KIDS ARE CALLING IT", + "Question": "\"What An Appealing Young Lady\" can be translated to this title of a 1999 movie", + "Answer": "She's All That" + }, + { + "Category": "BUT IS IT ART?", + "Question": "Tattooed showman The Enigma had tiny versions of these embedded in his skull, perhaps for a Satanic look", + "Answer": "Horns" + }, + { + "Category": "ROAMIN' THE WORLD", + "Question": "About two-thirds of this U.K. country's area is in its highlands & islands", + "Answer": "Scotland" + }, + { + "Category": "GREEK LIFE", + "Question": "This best-known Greek cheese, from the milk of sheep & goats, has been made for thousands of years", + "Answer": "Feta" + }, + { + "Category": "CARIBBEAN TASTE TREATS", + "Question": "Sancocho, a stew made with 5 to 7 meats, is a specialty of this country, Haiti's next-door neighbor", + "Answer": "Dominican Republic" + }, + { + "Category": "THE 12 TRIBES OF ISRAEL", + "Question": "Football great Dierdorf", + "Answer": "Dan" + }, + { + "Category": "ENGLISH ROYAL HENRYS", + "Question": "Henry I's famous father was this conqueror who reigned from 1066 to 1087", + "Answer": "William the Conqueror" + }, + { + "Category": "PARDON MY \"FRENCH\"", + "Question": "Settlers began living in this section of New Orleans in the early 18th century", + "Answer": "French Quarter" + }, + { + "Category": "ROAMIN' THE WORLD", + "Question": "When Sudan takes you to a place by this river, you can sit by the Blue or White one", + "Answer": "Nile" + }, + { + "Category": "GREEK LIFE", + "Question": "98% of Greece's population belongs to this church", + "Answer": "Greek" + }, + { + "Category": "CARIBBEAN TASTE TREATS", + "Question": "Don't worry if you see this word on a Barbados menu: it refers to a fish, not the star of \"Flipper\"", + "Answer": "Dolphin" + }, + { + "Category": "THE 12 TRIBES OF ISRAEL", + "Question": "\"Law & Order\" actor Bratt", + "Answer": "Benjamin" + }, + { + "Category": "ENGLISH ROYAL HENRYS", + "Question": "Pope Leo X named Henry VIII \"Defender of the Faith\" for his written attack on this German Protestant leader", + "Answer": "Martin Luther" + }, + { + "Category": "PARDON MY \"FRENCH\"", + "Question": "In a French restaurant, they're called pommes frites", + "Answer": "French fries" + }, + { + "Category": "ROAMIN' THE WORLD", + "Question": "Pier 21, considered \"Canada's Ellis Island\", is in this Nova Scotia city", + "Answer": "Halifax" + }, + { + "Category": "GREEK LIFE", + "Question": "Greek cafe music features a lute called a bouzouki & this woodwind, the klarino", + "Answer": "Clarinet" + }, + { + "Category": "CARIBBEAN TASTE TREATS", + "Question": "If you order \"mountain chicken\" in Dominica, you won't get chicken but one of these amphibians", + "Answer": "Frogs" + }, + { + "Category": "THE 12 TRIBES OF ISRAEL", + "Question": "Jeans maker Strauss", + "Answer": "Levi" + }, + { + "Category": "ENGLISH ROYAL HENRYS", + "Question": "King Henry III extensively rebuilt this abbey where he had been formally crowned in 1220", + "Answer": "Westminster Abbey" + }, + { + "Category": "PARDON MY \"FRENCH\"", + "Question": "In France this musical instrument is called \"cor d' harmonie\"", + "Answer": "French horn" + }, + { + "Category": "ROAMIN' THE WORLD", + "Question": "Tea & coconuts are top products of this country, the \"Pearl of the Indian Ocean\"", + "Answer": "Sri Lanka" + }, + { + "Category": "GREEK LIFE", + "Question": "Crowds flock to Dodona, Philippi & Thassos to see festivals of this art performed in ancient venues", + "Answer": "Theater" + }, + { + "Category": "CARIBBEAN TASTE TREATS", + "Question": "Adventurous eaters in Grenada may dine on this burrowing mammal (it's best to remove the armor first)", + "Answer": "Armadillo" + }, + { + "Category": "THE 12 TRIBES OF ISRAEL", + "Question": "Novelist Heller", + "Answer": "Joseph" + }, + { + "Category": "ENGLISH ROYAL HENRYS", + "Question": "Victory at Agincourt in 1415 earned this king a visit from the Holy Roman Emperor", + "Answer": "Henry V" + }, + { + "Category": "PARDON MY \"FRENCH\"", + "Question": "It was waged in North America from 1754 to 1763", + "Answer": "French and Indian War" + }, + { + "Category": "ROAMIN' THE WORLD", + "Question": "In 1991 the Yanomami tribe in this country was awarded a reserve 3 times the size of Belgium", + "Answer": "Brazil" + }, + { + "Category": "GREEK LIFE", + "Question": "Patricia Storace titled her 1996 book on travels in Greece \"Dinner with\" this goddess of the underworld", + "Answer": "Persephone" + }, + { + "Category": "CARIBBEAN TASTE TREATS", + "Question": "Puerto Ricans love to drink the juice of this fruit they call parcha -- maybe it makes them feel \"amorous\"", + "Answer": "Passion fruit" + }, + { + "Category": "THE 12 TRIBES OF ISRAEL", + "Question": "Explorer Pike", + "Answer": "Zebulon" + }, + { + "Category": "ENGLISH ROYAL HENRYS", + "Question": "These 2 warring royal houses were united in 1486 when Henry VII married Elizabeth, the daughter of Edward IV", + "Answer": "Lancaster & York" + }, + { + "Category": "PARDON MY \"FRENCH\"", + "Question": "They're formed by folding back & fastening a wide band at the end of a sleeve", + "Answer": "French cuffs" + }, + { + "Category": "RENAISSANCE LITERATURE", + "Question": "This book begins, \"All states and dominions which hold or have held mankind are either republics or monarchies\"", + "Answer": "\\\"The Prince\\\"" + }, + { + "Category": "BRITISH PRIME MINISTERS", + "Question": "1940-1945, 1951-1955", + "Answer": "Winston Churchill" + }, + { + "Category": "COUNTY SEATS", + "Question": "Hilo, I love you, you're the seat of this county that's also a \"Big Island\"", + "Answer": "Hawaii" + }, + { + "Category": "\"DREAM\"Y SONGS", + "Question": "1 of 2 \"dream\"y Top 20 songs recorded by Cass Elliott with The Mamas and The Papas", + "Answer": "\"California Dreamin'\" & \"Dream a Little Dream of Me\"" + }, + { + "Category": "BILL GATES' 50 BILLION", + "Question": "If his employee's price is $50.00, Bill could buy a billion of the \"98\" version of this operating system", + "Answer": "Windows" + }, + { + "Category": "SPOUSE IN COMMON", + "Question": "Elliott Gould, James Brolin", + "Answer": "Barbra Streisand" + }, + { + "Category": "GANGSTER'S DICTIONARY", + "Question": "I hates it when the cops put these \"bracelets\" on me after a bust", + "Answer": "Handcuffs" + }, + { + "Category": "BRITISH PRIME MINISTERS", + "Question": "1990-1997", + "Answer": "John Major" + }, + { + "Category": "COUNTY SEATS", + "Question": "Paris (population 8,730) is the seat of Bourbon County in this state", + "Answer": "Kentucky" + }, + { + "Category": "\"DREAM\"Y SONGS", + "Question": "Title that follows \"When I want you in my arms, when I want you and all your charms, whenever I want you...\"", + "Answer": "\"All I Have to Do Is Dream\"" + }, + { + "Category": "BILL GATES' 50 BILLION", + "Question": "In this state where he lives, Bill could pay the governor's salary for 413,000 years", + "Answer": "Washington" + }, + { + "Category": "SPOUSE IN COMMON", + "Question": "Heather Locklear, Pamela Anderson", + "Answer": "Tommy Lee" + }, + { + "Category": "GANGSTER'S DICTIONARY", + "Question": "You mugs, I need a \"can opener\", a tool used to open one of these, not a tin can", + "Answer": "Safe" + }, + { + "Category": "BRITISH PRIME MINISTERS", + "Question": "1937-1940", + "Answer": "Neville Chamberlain" + }, + { + "Category": "COUNTY SEATS", + "Question": "This Iowa city, the seat of Black Hawk County, has a name Wellington would remember", + "Answer": "Waterloo" + }, + { + "Category": "\"DREAM\"Y SONGS", + "Question": "\"Cheer up sleepy Jean, oh what can it mean to\" one of these \"and a homecoming queen\"", + "Answer": "A daydream believer" + }, + { + "Category": "BILL GATES' 50 BILLION", + "Question": "In 1997 Americans spent about $40 billion on these, & many wanted to be in Bill's", + "Answer": "Shoes" + }, + { + "Category": "SPOUSE IN COMMON", + "Question": "Roger Vadim, Tom Hayden", + "Answer": "Jane Fonda" + }, + { + "Category": "GANGSTER'S DICTIONARY", + "Question": "Roll out these \"bones\", boys, so we can play some games of chance", + "Answer": "Dice" + }, + { + "Category": "BRITISH PRIME MINISTERS", + "Question": "The Elder, 1766-1768; The Younger, 1783-1801, 1804-1806", + "Answer": "William Pitt" + }, + { + "Category": "COUNTY SEATS", + "Question": "Quincy, Illinois is the seat of a county with this presidential name", + "Answer": "Adams" + }, + { + "Category": "\"DREAM\"Y SONGS", + "Question": "In 1959 Bobby Darin wailed, \"Every night I hope and pray\", she \"will come my way\"", + "Answer": "\"Dream Lover\"" + }, + { + "Category": "BILL GATES' 50 BILLION", + "Question": "OK, we're not allowing for inflation, but Bill could afford over 8,000 Steve Austins, this title character", + "Answer": "The Six Million Dollar Man; The \"Bionic Man\"" + }, + { + "Category": "SPOUSE IN COMMON", + "Question": "Ava Gardner, Mia Farrow", + "Answer": "Frank Sinatra" + }, + { + "Category": "GANGSTER'S DICTIONARY", + "Question": "One day I might go legit & get a cush job as a \"gumshoe\", a private one of these", + "Answer": "Detective/private eye" + }, + { + "Category": "BRITISH PRIME MINISTERS", + "Question": "1945-1951", + "Answer": "Clement Atlee" + }, + { + "Category": "COUNTY SEATS", + "Question": "As I walked out in the streets of this city, I was in the seat of Webb County, Texas", + "Answer": "Laredo" + }, + { + "Category": "\"DREAM\"Y SONGS", + "Question": "In the 1986 film \"Blue Velvet\", Dean Stockwell peerforms a lip-synched rendition of this Roy Orbison hit", + "Answer": "\"In Dreams\"" + }, + { + "Category": "BILL GATES' 50 BILLION", + "Question": "Bill could easily bid on Bolivia: their GDP, this annual figure, is less than half what he's worth", + "Answer": "Gross Domestic Product" + }, + { + "Category": "SPOUSE IN COMMON", + "Question": "Ursula Andress, Linda Evans", + "Answer": "John Derek" + }, + { + "Category": "GANGSTER'S DICTIONARY", + "Question": "Keep your head low...I just saw a \"Salt & Pepper\", one of these, go by", + "Answer": "Police car" + }, + { + "Category": "CIVIL WAR LITERATURE", + "Question": "Henry Fleming shares a tent with a loud soldier & a tall soldier in this Stephen Crane novel", + "Answer": "\"The Red Badge of Courage\"" + }, + { + "Category": "HISTORIC NAMES", + "Question": "His epitaph reads, \"Founder of Boys Town and Lover of Christ and Man\"", + "Answer": "Father Flanagan" + }, + { + "Category": "TV MINISERIES", + "Question": "You could call Henry Thomas Ishmael & Patrick Stewart Ahab in this 1998 miniseries", + "Answer": "Moby Dick" + }, + { + "Category": "TAKE A PILL", + "Question": "Bayer hailed the FDA's endorsement of this drug for use during a suspected heart attack", + "Answer": "Aspirin" + }, + { + "Category": "KNOTS TO YOU", + "Question": "The Honda is a slip knot used by cowboys to make this tool of the trade", + "Answer": "Lasso" + }, + { + "Category": "THAT'S WHAT THEY SAID", + "Question": "After her election, this British prime minister said that she owed \"everything to my father\"", + "Answer": "Margaret Thatcher" + }, + { + "Category": "CIVIL WAR LITERATURE", + "Question": "Joanna Higgins' 1998 novel \"A Soldier's Book\" tells the story of Ira Stevens, a Union P.O.W. in this notorious prison", + "Answer": "Andersonville" + }, + { + "Category": "HISTORIC NAMES", + "Question": "While rounding the tip of South America in 1520, this Portuguese explorer named Cape Virgines & Patagonia", + "Answer": "Ferdinand Magellan" + }, + { + "Category": "TV MINISERIES", + "Question": "Vanessa Williams played Calypso & Greta Scacchi was the long-suffering Penelope in this 1997 epic", + "Answer": "The Odyssey" + }, + { + "Category": "KNOTS TO YOU", + "Question": "Alexander the Great cut it with his sword after being told that whoever could undo it would rule Asia", + "Answer": "Gordian Knot" + }, + { + "Category": "THAT'S WHAT THEY SAID", + "Question": "This author's Mr. Bumble declared that \"The law is a ass, a idiot\"", + "Answer": "Charles Dickens" + }, + { + "Category": "CIVIL WAR LITERATURE", + "Question": "He drew on his wartime nursing experience for the poem \"The Wound-Dresser\"", + "Answer": "Walt Whitman" + }, + { + "Category": "HISTORIC NAMES", + "Question": "It's been said that the 1831 Russian capture of Warsaw inspired him to write his C minor etude", + "Answer": "Frederic Chopin" + }, + { + "Category": "TV MINISERIES", + "Question": "(Hi, I'm Kristoff St. John from \"The Young and the Restless\") Earlier in my career, I appeared in \"Roots: The Next Generation\", playing this author as a boy", + "Answer": "Alex Haley" + }, + { + "Category": "KNOTS TO YOU", + "Question": "It is second only to \"Gunsmoke\" as TV's longest-running primetime drama series", + "Answer": "Knots Landing" + }, + { + "Category": "THAT'S WHAT THEY SAID", + "Question": "In 1803 Jacques Delille wrote, \"Fate chooses our relatives, we choose\" these", + "Answer": "Our friends" + }, + { + "Category": "CIVIL WAR LITERATURE", + "Question": "His works about the war include the essay \"What I Saw of Shiloh\" & the story \"An Occurrence at Owl Creek Bridge\"", + "Answer": "Ambrose Bierce" + }, + { + "Category": "HISTORIC NAMES", + "Question": "This family that once controlled Nicaragua saw 2 members killed -- the father in 1956, a son in 1980", + "Answer": "Somoza" + }, + { + "Category": "TV MINISERIES", + "Question": "Robert Duvall sat tall in the saddle as Augustus McCrae in this 1989 4-part western", + "Answer": "Lonesome Dove" + }, + { + "Category": "KNOTS TO YOU", + "Question": "This South American civilization used Quipu, a system of knots, to record dates & large sums of figures", + "Answer": "Incas" + }, + { + "Category": "THAT'S WHAT THEY SAID", + "Question": "\"When the one great scorer comes to write against your name, he marks -- not that you won or lost -- but\" this", + "Answer": "How you played the game" + }, + { + "Category": "CIVIL WAR LITERATURE", + "Question": "Jeff Shaara has written a prequel & a sequel to this 1974 novel about Gettysburg by his father Michael", + "Answer": "\"The Killer Angels\"" + }, + { + "Category": "HISTORIC NAMES", + "Question": "This discoverer of Uranus thought the sun was an inhabited body with a luminous atmosphere", + "Answer": "William Herschel" + }, + { + "Category": "TV MINISERIES", + "Question": "(Hi, I'm Stephen Collins of \"7th Heaven\") In 1994 I played Ashley Wilkes in this miniseries sequel to \"Gone with the Wind\"", + "Answer": "Scarlett" + }, + { + "Category": "KNOTS TO YOU", + "Question": "From the Turkish for \"napkin\", it's the art which creates decorative items by knotting cord, rope or string", + "Answer": "Macrame" + }, + { + "Category": "THAT'S WHAT THEY SAID", + "Question": "In his 1918 poem \"Prairie\", he wrote, \"I tell you the past is a bucket of ashes\"", + "Answer": "Carl Sandburg" + }, + { + "Category": "WORLD EVENTS", + "Question": "The 3 people who did this most recently were Midori Ito, Muhammad Ali & Crown Prince Haakon of Norway", + "Answer": "Lighting the Olympic flame at the Olympic Games" + }, + { + "Category": "LITERARY FIRST LINES", + "Question": "1900: \"Dorothy lived in the midst of the great Kansas prairies...\"", + "Answer": "\"The Wizard of Oz\"" + }, + { + "Category": "ASTROLOGY", + "Question": "There are this many houses in the astrological subdivision", + "Answer": "12" + }, + { + "Category": "THAT'S SO '90s", + "Question": "Joe Brown, Greg Mathis & Mills Lane joined the ranks of these on TV", + "Answer": "TV judges" + }, + { + "Category": "HAVE A WHISKEY", + "Question": "The Maker's Mark bourbon distillery in Loretto in this state is a national historic landmark", + "Answer": "Kentucky" + }, + { + "Category": "PUT ON YOUR JAMIES", + "Question": "She was Wanda in \"A Fish Called Wanda\" & Willa in the sort-of follow-up \"Fierce Creatures\"", + "Answer": "Jamie Lee Curtis" + }, + { + "Category": "& GO TO \"BED\"", + "Question": "In math, it means raised to the third power", + "Answer": "cubed" + }, + { + "Category": "LITERARY FIRST LINES", + "Question": "1843: \"Marley was dead: to begin with\"", + "Answer": "\"A Christmas Carol\"" + }, + { + "Category": "ASTROLOGY", + "Question": "The only moon in our solar system that astrologists say has an influence circles this planet", + "Answer": "the Earth" + }, + { + "Category": "THAT'S SO '90s", + "Question": "In 1994 a flaw found in this company's new Pentium processor cost it $475 million in a recall", + "Answer": "Intel" + }, + { + "Category": "HAVE A WHISKEY", + "Question": "Whiskey is usually about 40% alcohol, which is equal to this number in proof", + "Answer": "80" + }, + { + "Category": "PUT ON YOUR JAMIES", + "Question": "Thaddaeus in the 1965 film \"The Greatest Story Ever Told\", he got his greatest role ever in 1972 as Max Klinger", + "Answer": "Jamie Farr" + }, + { + "Category": "& GO TO \"BED\"", + "Question": "Native Americans called this fence material the \"Devil's rope\"", + "Answer": "barbed wire" + }, + { + "Category": "LITERARY FIRST LINES", + "Question": "1854: \"When I wrote the following pages, or rather the bulk of them, I lived alone in the woods...\"", + "Answer": "\"Walden; or, Life in the Woods\"" + }, + { + "Category": "ASTROLOGY", + "Question": "Chinese astrology has 5 classical elements, each associated with a planet; knock this when you think Jupiter", + "Answer": "wood" + }, + { + "Category": "THAT'S SO '90s", + "Question": "His 1997 meeting with Sinn Fein leader Gerry Adams was the first for a British P.M. & an IRA leader in 76 years", + "Answer": "Tony Blair" + }, + { + "Category": "HAVE A WHISKEY", + "Question": "The world's most popular whiskey is this color Johnnie Walker", + "Answer": "Red" + }, + { + "Category": "PUT ON YOUR JAMIES", + "Question": "This comic was Bundini Brown in \"Ali\" & Steamin' Beamen in \"Any Given Sunday\"", + "Answer": "Jamie Foxx" + }, + { + "Category": "& GO TO \"BED\"", + "Question": "Kidded & teased (like Adam did to Eve, perhaps?)", + "Answer": "ribbed" + }, + { + "Category": "LITERARY FIRST LINES", + "Question": "1976: \"In our family there was no clear line between religion and fly fishing\"", + "Answer": "\"A River Runs Through It\"" + }, + { + "Category": "ASTROLOGY", + "Question": "The masculine signs are the air signs, including Gemini, & these signs, which include Leo", + "Answer": "fire signs" + }, + { + "Category": "THAT'S SO '90s", + "Question": "Hello! In May 1999 scientists found this famous sheep might be susceptible to premature aging", + "Answer": "Dolly" + }, + { + "Category": "HAVE A WHISKEY", + "Question": "In the 1880s Ontario-brewed Club whiskey got this new national name", + "Answer": "Canadian Club" + }, + { + "Category": "PUT ON YOUR JAMIES", + "Question": "In a 2002 WB show people got to view his \"experiments\" with his hidden camera practical jokes", + "Answer": "Jamie Kennedy" + }, + { + "Category": "& GO TO \"BED\"", + "Question": "If you've been clubbed, you've been made unconscious; if you've been this, you've been made a knight", + "Answer": "dubbed" + }, + { + "Category": "LITERARY FIRST LINES", + "Question": "1973: \"There were 117 psychoanalysts on the Pan Am flight to Vienna and I'd been treated by at least six of them\"", + "Answer": "\"Fear of Flying\"" + }, + { + "Category": "ASTROLOGY", + "Question": "This planet spends an average of 20 years in each sign of the Zodiac", + "Answer": "Pluto" + }, + { + "Category": "THAT'S SO '90s", + "Question": "Born Louis Eugene Walcott, he led a million man march in Washington, D.C. in 1995", + "Answer": "Louis Farrakhan" + }, + { + "Category": "HAVE A WHISKEY", + "Question": "This \"Regal\" brand assures us it's \"Without Question the Best of the Scottish Blends\"", + "Answer": "Chivas Regal" + }, + { + "Category": "PUT ON YOUR JAMIES", + "Question": "Jamie in this family that includes N.C. & Andrew said, \"Everybody in my family paints -- excluding possibly the dogs\"", + "Answer": "Wyeth" + }, + { + "Category": "& GO TO \"BED\"", + "Question": "In the Bible she was mom to Moses & Aaron", + "Answer": "Jochebed" + }, + { + "Category": "INDONESIA", + "Question": "In 1985 Sukarno-Hatta Int'l Airport was opened at Cengkareng just west of this city's center", + "Answer": "Jakarta" + }, + { + "Category": "JAZZ IT UP", + "Question": "Milt Jackson, heard here, was one of the masters of this instrument", + "Answer": "vibes" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "This scientist & author of \"2001\" wrote, 'Any...advanced technology is indistinguishable from magic\"", + "Answer": "Arthur C. Clarke" + }, + { + "Category": "SNAP", + "Question": "The snap-brim style of this accessory tuns up in the back & down in the front & has a dented crown", + "Answer": "hat" + }, + { + "Category": "HISTORIC NAMES", + "Question": "This king died in 1760, leaving it to his grandson & successor to lose the American colonies", + "Answer": "George II" + }, + { + "Category": "HOMOPHONES", + "Question": "Wan, or a bucket", + "Answer": "pale/pail" + }, + { + "Category": "INDONESIA", + "Question": "Indonesia's Molucca Islands were once called this because they were famous for growing cloves, nutmeg & mace", + "Answer": "Spice Islands" + }, + { + "Category": "JAZZ IT UP", + "Question": "We think jazzman Ron Carter is this kind of \"guy\"; we know he plays the same kind of bass", + "Answer": "stand-up guy" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "(Sofia of the Clue Crew reports from the Field Museum in Chicago) Snail shells are in a pattern usually called this; they add new coils as the snail ages", + "Answer": "spiral" + }, + { + "Category": "SNAP", + "Question": "Along with Snap, they've been appearing on boxes of Rice Krispies since the 1930s", + "Answer": "Crackle & Pop" + }, + { + "Category": "HISTORIC NAMES", + "Question": "A yearly football game is played near the NC/SC border to \"settle\" the issue of this president's birthplace in 1767", + "Answer": "Andrew Jackson" + }, + { + "Category": "HOMOPHONES", + "Question": "Sugary, or a group of hotel rooms", + "Answer": "sweet/suite" + }, + { + "Category": "INDONESIA", + "Question": "Most of the world's supply of this medicine comes from Indonesia's cinchona trees", + "Answer": "quinine" + }, + { + "Category": "JAZZ IT UP", + "Question": "Saxophonist Sonny Rollins was one of the leaders of the \"hard\" type of this style that began in the '40s", + "Answer": "bebop/bop" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "His 1947 oceanic expedition began in Callao, Peru & ended 10 days later in Polynesia", + "Answer": "Thor Heyerdahl" + }, + { + "Category": "SNAP", + "Question": "This TV series that debuted September 18, 1964 featured finger-snapping in its theme", + "Answer": "The Addams Family" + }, + { + "Category": "HISTORIC NAMES", + "Question": "This 1909 Nobel Prize winner once failed the entrance exams at the Univ. of Bologna, Italy", + "Answer": "Guglielmo Marconi" + }, + { + "Category": "HOMOPHONES", + "Question": "A negative vote, or a horse's whinny", + "Answer": "nay/neigh" + }, + { + "Category": "INDONESIA", + "Question": "On Dec. 27, 1949, after 3 years of fighting, Indonesia was granted its independence from this country", + "Answer": "the Netherlands" + }, + { + "Category": "JAZZ IT UP", + "Question": "At the 2000 Grammys the Best Boxed Recording Package was this late trumpeter's \"Complete Bitches Brew Sessions\"", + "Answer": "Miles Davis" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "(Sarah of the Clue Crew reports from the Field Museum in Chicago) This spider, named for a mammal, doesn't wait patiently for prey, but hunts it down", + "Answer": "wolf spider" + }, + { + "Category": "SNAP", + "Question": "A snap fastener is simply a ball-and-this, like your hip joint", + "Answer": "ball-and-socket" + }, + { + "Category": "HISTORIC NAMES", + "Question": "In 1961 scared villagers thought he was a downed U2 pilot until he removed his helmet & spoke Russian to them", + "Answer": "Yuri Gagarin" + }, + { + "Category": "HOMOPHONES", + "Question": "Lies in the sun, or people who live in the Pyrenees", + "Answer": "basks/Basques" + }, + { + "Category": "INDONESIA", + "Question": "An economic downturn in 1998 forced this president to resign & vice president Habibie succeeded him", + "Answer": "Suharto" + }, + { + "Category": "JAZZ IT UP", + "Question": "This Thelonious Monk composition provided the title for a 1986 jazz film starring Dexter Gordon", + "Answer": "'Round Midnight" + }, + { + "Category": "SCIENCE & NATURE", + "Question": "Light energy can be studied as these massless quantum units", + "Answer": "photons" + }, + { + "Category": "SNAP", + "Question": "Common name of the reptile Chelydra serpentina", + "Answer": "snapping turtle" + }, + { + "Category": "HISTORIC NAMES", + "Question": "AP's chief Mideast correspondent, he got a firsthand look as a Beirut hostage for nearly 7 years", + "Answer": "Terry Anderson" + }, + { + "Category": "HOMOPHONES", + "Question": "Quote an authority, or catch a glimpse of something", + "Answer": "cite/sight" + }, + { + "Category": "U.S. PRESIDENTS", + "Question": "A Civil War general, he was the last man to go directly from the House of Representatives to the presidency", + "Answer": "James A. Garfield" + }, + { + "Category": "MORE POWER TO YOU", + "Question": "2-word term for the job that takes you to homes to figure out how much people owe the power company", + "Answer": "a meter reader" + }, + { + "Category": "SMACK DAB IN THE MIDDLE", + "Question": "In Park County, 30 miles northwest of Pike's Peak", + "Answer": "Colorado" + }, + { + "Category": "FUN WITH OPERA", + "Question": "In \"Johnny Strikes Up\", a violin performance at the North Pole inspires the whole world to do this 1920s dance", + "Answer": "the Charleston" + }, + { + "Category": "READING", + "Question": "Group name for all letters other than A, E, I, O & U", + "Answer": "consonants" + }, + { + "Category": "WORDS TO THE \"Y\"s", + "Question": "A female nickname, or a fall guy", + "Answer": "a patsy" + }, + { + "Category": "VIVA ANN-MARGRET!", + "Question": "On May 29, 1963 Ann-Margret sang at this famous man's 46th, & last, birthday party", + "Answer": "John F. Kennedy" + }, + { + "Category": "SMACK DAB IN THE MIDDLE", + "Question": "In Kent County, 11 miles south of Dover", + "Answer": "Delaware" + }, + { + "Category": "FUN WITH OPERA", + "Question": "It was truly a red-letter day when an opera based on this Hawthorne novel premiered in Boston in 1896", + "Answer": "The Scarlet Letter" + }, + { + "Category": "READING", + "Question": "From the Greek for \"sound\", these sounds represented by letters might get you \"hooked on\" them", + "Answer": "phonics" + }, + { + "Category": "VIVA ANN-MARGRET!", + "Question": "Ann-Margret got her second Oscar nomination for playing Roger Daltrey's mom in this rock film", + "Answer": "Tommy" + }, + { + "Category": "MORE POWER TO YOU", + "Question": "California's 2001 energy crisis was attributed to a 1996 state law mandating this for the electricity industry", + "Answer": "deregulation" + }, + { + "Category": "SMACK DAB IN THE MIDDLE", + "Question": "In Yavapai County, 55 miles east-southeast of Prescott", + "Answer": "Arizona" + }, + { + "Category": "FUN WITH OPERA", + "Question": "\"The Jesters' Supper\" was first performed in this city where you'll find Da Vinci's \"Last Supper\"", + "Answer": "Milan" + }, + { + "Category": "READING", + "Question": "Some reading rates are gauged by wpm, which stands for this", + "Answer": "words per minute" + }, + { + "Category": "WORDS TO THE \"Y\"s", + "Question": "Collective term for domesticated fowl like turkeys & chickens", + "Answer": "poultry" + }, + { + "Category": "MORE POWER TO YOU", + "Question": "Founded in 1933, it's America's largest public power company", + "Answer": "TVA" + }, + { + "Category": "SMACK DAB IN THE MIDDLE", + "Question": "In Story County, 5 miles northeast of Ames", + "Answer": "Iowa" + }, + { + "Category": "FUN WITH OPERA", + "Question": "In an 1893 opera, the Sandman puts this young title duo to sleep & the Dew Fairy wakes them up", + "Answer": "Hansel & Gretel" + }, + { + "Category": "READING", + "Question": "From the Greek for \"bad word\", this disorder is marked by difficulty in recognizing written language", + "Answer": "dyslexia" + }, + { + "Category": "WORDS TO THE \"Y\"s", + "Question": "The last stage of a robbery, as in the McQueen-MacGraw movie", + "Answer": "a getaway" + }, + { + "Category": "VIVA ANN-MARGRET!", + "Question": "The Riviera was the site of Ann-Margret's marriage to him (not the French Riviera, the one in Las Vegas)", + "Answer": "Roger Smith" + }, + { + "Category": "SMACK DAB IN THE MIDDLE", + "Question": "In Wexford County, 5 miles north-northwest of Cadillac", + "Answer": "Michigan" + }, + { + "Category": "FUN WITH OPERA", + "Question": "In Nicolai's opera \"The Merry Wives of Windsor\", this fat, funny rogue gets dumped into the river in a laundry basket", + "Answer": "Falstaff" + }, + { + "Category": "READING", + "Question": "President Carter has been among the many users of this woman's \"Reading Dynamics\" system", + "Answer": "Evelyn Wood" + }, + { + "Category": "WORDS TO THE \"Y\"s", + "Question": "It's defined as government by many officials & administrators", + "Answer": "bureaucracy" + }, + { + "Category": "MARK TWAIN SEZ", + "Question": "Lines attributed to Twain include \"Everybody talks about\" this, \"but nobody does anything about it\"", + "Answer": "the weather" + }, + { + "Category": "IN A FESTIVAL MOOD", + "Question": "In July 1965 Bob Dylan was booed at the Newport Festival of this, for abandoning that type of music", + "Answer": "Folk Music" + }, + { + "Category": "INITIALS M.D.", + "Question": "He won an Oscar as co-writer of \"Good Will Hunting\"", + "Answer": "Matt Damon" + }, + { + "Category": "WON THE BATTLE", + "Question": "After Perry met the enemy in the September 1813 battle of this great lake, they were ours", + "Answer": "Lake Erie" + }, + { + "Category": "IN THE TREASURY DEPT.", + "Question": "In addition to protecting all of us from funny money, it protects the president", + "Answer": "the Secret Service" + }, + { + "Category": "DOUBLE-O WORDS", + "Question": "Rideshare is the program of the wise & benevolent Sony Corporation to help employees get to work this way", + "Answer": "carpooling" + }, + { + "Category": "MARK TWAIN SEZ", + "Question": "\"Thunder is good, thunder is impressive; but it is\" this \"that does the work\"", + "Answer": "the lightning" + }, + { + "Category": "IN A FESTIVAL MOOD", + "Question": "This annual event in Park City, Utah gives out the Waldo Salt Screenwriting Award", + "Answer": "the Sundance Film Festival" + }, + { + "Category": "INITIALS M.D.", + "Question": "He's broken many stories in his online \"Report\"", + "Answer": "Matt Drudge" + }, + { + "Category": "WON THE BATTLE", + "Question": "The Allies won this battle, the last Nazi offensive in the West during WWII", + "Answer": "the Battle of the Bulge" + }, + { + "Category": "IN THE TREASURY DEPT.", + "Question": "It's the bureau for booze, butts & bazookas", + "Answer": "the ATF" + }, + { + "Category": "DOUBLE-O WORDS", + "Question": "Legend says in 1652 Dutch Admiral Tromp placed this at his masthead after sweeping the English from the sea", + "Answer": "a broom" + }, + { + "Category": "IN A FESTIVAL MOOD", + "Question": "In July Deer River, Minnesota remembers its Indian heritage with a festival of the \"wild\" type of this food", + "Answer": "rice" + }, + { + "Category": "INITIALS M.D.", + "Question": "In \"Return To Me\", David Duchovny has a heart-to-heart with her", + "Answer": "Minnie Driver" + }, + { + "Category": "WON THE BATTLE", + "Question": "In the Battle of Thermopylae, the Greeks felt the heat of these people under Xerxes I", + "Answer": "the Persians" + }, + { + "Category": "IN THE TREASURY DEPT.", + "Question": "This service quarantines animals & can stop you from bringing sausages into the country", + "Answer": "Customs" + }, + { + "Category": "IN A FESTIVAL MOOD", + "Question": "2001 is the 35th season of Lincoln Center's music festival called \"Mostly\" him", + "Answer": "Mozart" + }, + { + "Category": "INITIALS M.D.", + "Question": "Like Neve & Denise, he was one of the \"Wild Things\"", + "Answer": "Matt Dillon" + }, + { + "Category": "WON THE BATTLE", + "Question": "This king of England beat the odds to trounce the French in the 1415 Battle of Agincourt", + "Answer": "Henry V" + }, + { + "Category": "IN THE TREASURY DEPT.", + "Question": "Willie Nelson's album \"Who'll Buy My Memories\" was subtitled this agency's \"Tapes\"", + "Answer": "the IRS" + }, + { + "Category": "DOUBLE-O WORDS", + "Question": "A lateral branch on a main stem", + "Answer": "an offshoot" + }, + { + "Category": "MARK TWAIN SEZ", + "Question": "In an essay, Twain said surely no language is \"so slip-shod & systemless\" as this one he called \"awful\"", + "Answer": "German" + }, + { + "Category": "INITIALS M.D.", + "Question": "Her name was Lola, she was a showgirl in \"Der Blaue Engel\"", + "Answer": "Marlene Dietrich" + }, + { + "Category": "WON THE BATTLE", + "Question": "With 1/3 the troops of his enemy, this American general beat Santa Anna in the 1847 Battle of Buena Vista", + "Answer": "Taylor" + }, + { + "Category": "IN THE TREASURY DEPT.", + "Question": "When it invites you up to see its etchings, you'll see stamps & dollar bills", + "Answer": "the Bureau of Engraving & Printing" + }, + { + "Category": "NATIONAL ANTHEMS", + "Question": "\"Land Of Two Rivers\" is the anthem of this country whose history goes back thousands of years", + "Answer": "Iraq" + }, + { + "Category": "BASIC SCIENCE", + "Question": "In North America, these tiny birds are the main birds that pollinate flowers", + "Answer": "hummingbirds" + }, + { + "Category": "HOLLYWOOD THRILLER PREVIEWS?", + "Question": "Last year it was Da Vinci; this fall it's nothing but dots & dashes with the...", + "Answer": "the Morse Code" + }, + { + "Category": "LET'S TAKE A PEAK", + "Question": "This peak in the Black Hills is 5,725 feet above sea level, or a little over 95 times the height of Washington's head", + "Answer": "Mount Rushmore" + }, + { + "Category": "MAYORS", + "Question": "The last 2 Latinos elected mayor of this huge U.S. city are Cristobal Aguilar (1872) & Antonio Villaraigosa (2005)", + "Answer": "Los Angeles" + }, + { + "Category": "IT DON'T MEAN A \"THING\"", + "Question": "Zip, nada, el zilcho", + "Answer": "nothing" + }, + { + "Category": "IF IT AIN'T GOT THAT SWING", + "Question": "An athlete who is \"swinging for the fences\" is playing this sport", + "Answer": "baseball" + }, + { + "Category": "BASIC SCIENCE", + "Question": "Nitrogen makes up around 78% of the atmosphere; this gas, only about 20%", + "Answer": "oxygen" + }, + { + "Category": "HOLLYWOOD THRILLER PREVIEWS?", + "Question": "Finally, this 1963 Betty Friedan book hits the theaters--and wait 'til you see the car chases", + "Answer": "The Feminine Mystique" + }, + { + "Category": "LET'S TAKE A PEAK", + "Question": "Venezuela's highest peak is named for this man; there's a bronze bust of him at the summit", + "Answer": "Bolivar" + }, + { + "Category": "MAYORS", + "Question": "After this 1906 disaster, Mayor Eugene Schmitz authorized the summary execution of looters", + "Answer": "the San Francisco earthquake" + }, + { + "Category": "IT DON'T MEAN A \"THING\"", + "Question": "A ring for a baby's incisors", + "Answer": "teething" + }, + { + "Category": "IF IT AIN'T GOT THAT SWING", + "Question": "It's the activity you're participating in if you're instructed to \"swing your partner, do-si-do\"", + "Answer": "square dancing" + }, + { + "Category": "BASIC SCIENCE", + "Question": "At last count, this planet in our solar system had 63 known moons", + "Answer": "Jupiter" + }, + { + "Category": "HOLLYWOOD THRILLER PREVIEWS?", + "Question": "First she was Pam Ewing on \"Dallas\"; now her name is the must-see film of the year. This summer, she is \"The...\"", + "Answer": "Victoria Principal" + }, + { + "Category": "LET'S TAKE A PEAK", + "Question": "This state's 11,031-foot-high Deseret Peak overlooks Rush Valley", + "Answer": "Utah" + }, + { + "Category": "MAYORS", + "Question": "Actress Melina Mercouri ran unsuccessfully for mayor of this foreign city, a post her Grandpa held for 30 years", + "Answer": "Athens" + }, + { + "Category": "IT DON'T MEAN A \"THING\"", + "Question": "Giving a portion of one's income, typically 10%, to one's church", + "Answer": "tithing" + }, + { + "Category": "IF IT AIN'T GOT THAT SWING", + "Question": "This rock band sang, \"We are the sultans of swing\"", + "Answer": "Dire Straits" + }, + { + "Category": "BASIC SCIENCE", + "Question": "8 years before \"The Origin of Species\" was published, this British naturalist wrote a paper on barnacles", + "Answer": "Darwin" + }, + { + "Category": "HOLLYWOOD THRILLER PREVIEWS?", + "Question": "This emotional bond to a captor by a hostage due to stress & need for survival is the psychothriller of the summer!", + "Answer": "the Stockholm Syndrome" + }, + { + "Category": "LET'S TAKE A PEAK", + "Question": "Canada's highest peak, Mount Logan, lies in the St. Elias Range in the SW corner of this territory", + "Answer": "the Yukon" + }, + { + "Category": "MAYORS", + "Question": "In New Orleans' first post-Katrina mayoral election, this man held on to his job", + "Answer": "Nagin" + }, + { + "Category": "IT DON'T MEAN A \"THING\"", + "Question": "Raiment or apparel", + "Answer": "clothing" + }, + { + "Category": "IF IT AIN'T GOT THAT SWING", + "Question": "\"Swing Time\" was the sixth film to team this pair of legendary dancers", + "Answer": "Fred Astaire & Ginger Rogers" + }, + { + "Category": "BASIC SCIENCE", + "Question": "At the Earth's surface, this force produces acceleration of about 32 feet per second per second", + "Answer": "gravity" + }, + { + "Category": "HOLLYWOOD THRILLER PREVIEWS?", + "Question": "In Australia, water is going down drains backwards (to us). This fall, Mel Gibson takes on the reason why--this \"Effect\"", + "Answer": "Coriolis" + }, + { + "Category": "LET'S TAKE A PEAK", + "Question": "The name of this volcano in Martinique is from the French for \"bald mountain\"", + "Answer": "Mount Pelee" + }, + { + "Category": "IT DON'T MEAN A \"THING\"", + "Question": "\"In olden days a glimpse of stocking was looked on as something shocking\", now heaven knows, this", + "Answer": "\"Anything Goes\"" + }, + { + "Category": "IF IT AIN'T GOT THAT SWING", + "Question": "Cool, Daddy-O! The 1939 autobiography by this bandleader was titled \"The Kingdom of Swing\"", + "Answer": "Benny Goodman" + }, + { + "Category": "PULITZER PRIZE-WINNING DRAMAS", + "Question": "The Pulitzer folks gave \"A Delicate Balance\" by thIs playwright a 1967 \"Woolf\" whistle", + "Answer": "Albee" + }, + { + "Category": "1807", + "Question": "Following his victory in the Battle of Friedland in June, he forced the capitulation of the Russian Empire", + "Answer": "Napoleon" + }, + { + "Category": "FOR THE BIRDS", + "Question": "The canvasback is a wild North American variety of this bird", + "Answer": "a duck" + }, + { + "Category": "BACH IN THE SADDLE", + "Question": "In his youth, Bach played this instrument in church & later was a virtuoso consulted in their crafting", + "Answer": "an organ" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "One who gives blood (5)", + "Answer": "a donor" + }, + { + "Category": "PULITZER PRIZE-WINNING DRAMAS", + "Question": "David Mamet won in 1984 for this salesman drama whose title includes 2 4-letter words", + "Answer": "Glengarry Glen Ross" + }, + { + "Category": "SCORING", + "Question": "In this sport you score a point for each 42-pound stone closer to the tee than the opponent's nearest stone", + "Answer": "curling" + }, + { + "Category": "1807", + "Question": "In September he was acquitted of treason against the U.S.", + "Answer": "Aaron Burr" + }, + { + "Category": "FOR THE BIRDS", + "Question": "The genus for this American bird is Turdus; ah, to see the first Turdus of spring", + "Answer": "a robin" + }, + { + "Category": "BACH IN THE SADDLE", + "Question": "Bach often paired a prelude with this form in which a theme is stated, repeated & varied with contrapuntal lines", + "Answer": "a fugue" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "Conversation for 2 people (8)", + "Answer": "a dialogue" + }, + { + "Category": "PULITZER PRIZE-WINNING DRAMAS", + "Question": "In 1928 this playwright had a \"Strange Interlude\"", + "Answer": "O'Neill" + }, + { + "Category": "1807", + "Question": "Later to lead the revolutionary Redshirts, he was born on the Fourth of July", + "Answer": "Garibaldi" + }, + { + "Category": "FOR THE BIRDS", + "Question": "One of the 2 U.S. states with a bird in its official state nickname", + "Answer": "Iowa or Louisiana" + }, + { + "Category": "BACH IN THE SADDLE", + "Question": "Bach was a composer of great reknown in this musical era that takes its name from \"imperfect pearls\"", + "Answer": "Baroque" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "France's patron saint (5)", + "Answer": "Denis" + }, + { + "Category": "PULITZER PRIZE-WINNING DRAMAS", + "Question": "In 1989 her \"Heidi Chronicles\" was the story of the night; sadly she passed away in 2006", + "Answer": "Wasserstein" + }, + { + "Category": "SCORING", + "Question": "Figure skating has scrapped the old system, where this number was perfect, for a new one with triple-digit scores", + "Answer": "6" + }, + { + "Category": "1807", + "Question": "In August, this Robert Fulton-built steamship left NYC for Albany on the Hudson River", + "Answer": "the Clermont" + }, + { + "Category": "FOR THE BIRDS", + "Question": "This long-legged wading bird of the genus Platalea is named for its prominent flatware-like bill", + "Answer": "the spoonbill" + }, + { + "Category": "BACH IN THE SADDLE", + "Question": "A count's insomnia prompted these pieces that were to be played by a 14-year-old harpsichordist", + "Answer": "the Goldberg Variations" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "Fate or kismet (7)", + "Answer": "destiny" + }, + { + "Category": "PULITZER PRIZE-WINNING DRAMAS", + "Question": "In 1938 this playwright's \"Our Town\" had some Pulitzer with the voters", + "Answer": "Wilder" + }, + { + "Category": "1807", + "Question": "In July, Jacobitism ended with the death of Henry Benedict, the last claimant of this royal family to the British throne", + "Answer": "the Stuarts" + }, + { + "Category": "BACH IN THE SADDLE", + "Question": "From the Latin for \"to sing\", only 202 of the 295 of these that Bach wrote in Leipzig survive", + "Answer": "cantatas" + }, + { + "Category": "CROSSWORD CLUES \"D\"", + "Question": "Horn of Africa country (8)", + "Answer": "Djibouti" + }, + { + "Category": "FOREIGN CURRENCY", + "Question": "This currency of Costa Rica gets its name from the first European to see the nation", + "Answer": "the Colon" + }, + { + "Category": "LITERATURE", + "Question": "Walt Whitman's 52-section \"Song Of Myself\" is the longest work in this collection first published in 1855", + "Answer": "\"Leaves of Grass\"" + }, + { + "Category": "\"DO\", \"RE\", \"MI\"", + "Question": "Nancy Davis' married name", + "Answer": "Reagan" + }, + { + "Category": "PLAY REVIVALS", + "Question": "In August 2000 Lea Thompson sallied forth as Sally Bowles in the Broadway revival of this musical", + "Answer": "\"Cabaret\"" + }, + { + "Category": "HERE COMES BAHRAIN AGAIN", + "Question": "In 1991 Bahrain was one of the good guys in this conflict & the U.S. sold it Apache helicopters", + "Answer": "The Gulf War/Operation Desert Storm" + }, + { + "Category": "IT SOUNDS LIKE", + "Question": "Jay Leno's show, it sounds like how you address a letter for Sir Galahad", + "Answer": "Tonight" + }, + { + "Category": "PERCUSSION INSTRUMENTS", + "Question": "Porky popped out of this type of drum at the end of many a Looney Tune", + "Answer": "Bass drum" + }, + { + "Category": "LITERATURE", + "Question": "In this Steinbeck novel, Lennie has nightmarish visions of his dead aunt Clara & of a gigantic rabbit", + "Answer": "\"Of Mice and Men\"" + }, + { + "Category": "\"DO\", \"RE\", \"MI\"", + "Question": "A small filet of prime beef", + "Answer": "Mignon" + }, + { + "Category": "PLAY REVIVALS", + "Question": "In 1992 you could have seen James Gandolfini playing cards with Stanley Kowalski in a revival of this play", + "Answer": "\"A Streetcar Named Desire\"" + }, + { + "Category": "HERE COMES BAHRAIN AGAIN", + "Question": "This country that controlled Bahrain in the 18th century renewed its claim after its 1979 revolution", + "Answer": "Iran" + }, + { + "Category": "IT SOUNDS LIKE", + "Question": "A cylindrical storage container for grain, it sounds like an order to exhale quietly", + "Answer": "Silo" + }, + { + "Category": "PERCUSSION INSTRUMENTS", + "Question": "Type of drum seen here, or a dance done to them", + "Answer": "Conga" + }, + { + "Category": "LITERATURE", + "Question": "In this novel, Javert says, \"There is a brigand, there is a convict called Jean Valjean, and I have got him!\"", + "Answer": "\"Les Miserables\"" + }, + { + "Category": "\"DO\", \"RE\", \"MI\"", + "Question": "It can mean relating to home or a servant who works there", + "Answer": "Domestic" + }, + { + "Category": "PLAY REVIVALS", + "Question": "He starred on Broadway in \"The Crucible\" in 1991, a few years before becoming president (on TV, that is)", + "Answer": "Martin Sheen" + }, + { + "Category": "HERE COMES BAHRAIN AGAIN", + "Question": "The \"humped\" shape of a Bahraini island gives it the name Hawer, meaning \"young\" one of these", + "Answer": "Camel" + }, + { + "Category": "IT SOUNDS LIKE", + "Question": "A pitcher who comes in late in the game, it sounds like a feeling trees have in the spring", + "Answer": "Relief" + }, + { + "Category": "PERCUSSION INSTRUMENTS", + "Question": "On the web you can find A. Claude Ferguson's masterful manual on playing these eating utensils", + "Answer": "Spoons" + }, + { + "Category": "LITERATURE", + "Question": "This James M. Cain novel, which has been filmed \"twice\", was written under the title \"Bar-B-Q\"", + "Answer": "\"The Postman Always Rings Twice\"" + }, + { + "Category": "\"DO\", \"RE\", \"MI\"", + "Question": "This kind of \"name\" is also known as an Internet address", + "Answer": "domain" + }, + { + "Category": "PLAY REVIVALS", + "Question": "George Grizzard was on board as Cap'n Andy when this \"Ol' Man River\" musical rolled into London in 1998", + "Answer": "\"Showboat\"" + }, + { + "Category": "HERE COMES BAHRAIN AGAIN", + "Question": "The Khalifa clan, which has ruled Bahrain for 2 centuries, belongs to this majority branch of Islam", + "Answer": "Sunni" + }, + { + "Category": "IT SOUNDS LIKE", + "Question": "It sounds like the kind of personality most likely to have a heart attack in the capital of Taiwan", + "Answer": "Taipei" + }, + { + "Category": "PERCUSSION INSTRUMENTS", + "Question": "Originally bean-containing dried gourds on handles, they were named by the Tupi of South America", + "Answer": "Maracas" + }, + { + "Category": "LITERATURE", + "Question": "This Muriel Spark novel is set at the Marcia Blaine School For Girls in Edinburgh", + "Answer": "\"The Prime of Miss Jean Brodie\"" + }, + { + "Category": "\"DO\", \"RE\", \"MI\"", + "Question": "Harmful or poisonous fumes caused by decaying organic matter", + "Answer": "Miasma" + }, + { + "Category": "PLAY REVIVALS", + "Question": "Ethan Hawke appeared in a 1992 production of this Chekhov play with another bird in its name", + "Answer": "\"The Seagull\"" + }, + { + "Category": "HERE COMES BAHRAIN AGAIN", + "Question": "A causeway linking Bahrain & Saudi Arabia is named for this man who became Saudi king in 1982", + "Answer": "King Fahd" + }, + { + "Category": "IT SOUNDS LIKE", + "Question": "A runway material, it sounds like what you do before you feather your Apple computer", + "Answer": "Tarmac" + }, + { + "Category": "PERCUSSION INSTRUMENTS", + "Question": "Percussion instrument whose possible changes for a set of five are seen here", + "Answer": "Bells" + }, + { + "Category": "BRITISH NOBILITY", + "Question": "In the 16th C. the Earl of Surrey helped bring this 14-line poetic form to England", + "Answer": "Sonnet" + }, + { + "Category": "WHERE'S THE COLLEGE?", + "Question": "University of Washington", + "Answer": "Seattle" + }, + { + "Category": "QUOTATIONS", + "Question": "With his new $88.5 million contract, this Laker said, \"I'm not really a big spender, I can get a lot of Krispy Kremes\"", + "Answer": "Shaquille O'Neal" + }, + { + "Category": "CARY GRANT FILMS", + "Question": "She done Cary right casting him as her co-star in \"She Done Him Wrong\"", + "Answer": "Mae West" + }, + { + "Category": "WATERFALLS", + "Question": "Wollomombi Falls in northern New South Wales is one of this continent's highest waterfalls", + "Answer": "Australia" + }, + { + "Category": "FILE UNDER \"K\"", + "Question": "Its state flower is the goldenrod", + "Answer": "Kentucky" + }, + { + "Category": "WHERE'S THE COLLEGE?", + "Question": "Kansas State University", + "Answer": "Manhattan" + }, + { + "Category": "QUOTATIONS", + "Question": "Woody Guthrie wrote for this party's paper & joked, \"I've been in the red all my life\"", + "Answer": "Communist party" + }, + { + "Category": "CARY GRANT FILMS", + "Question": "In this 1944 film about a pair of murderous aunts, Cary says, \"Insanity runs in my family. It practically gallops\"", + "Answer": "Arsenic and Old Lace" + }, + { + "Category": "WATERFALLS", + "Question": "This African waterfall is also known as Mosi-Oa-Tunya, or \"Smoke That Thunders\"", + "Answer": "Victoria Falls" + }, + { + "Category": "FILE UNDER \"K\"", + "Question": "The Nancy Drew books are written under this pseudonym", + "Answer": "Carolyn Keene" + }, + { + "Category": "WHERE'S THE COLLEGE?", + "Question": "Johns Hopkins University", + "Answer": "Baltimore" + }, + { + "Category": "QUOTATIONS", + "Question": "In 1783 he wrote, \"There never was a good war or a bad peace\"", + "Answer": "Benjamin Franklin" + }, + { + "Category": "CARY GRANT FILMS", + "Question": "\"High Society\" is a musical version of this Cary Grant-Jimmy Stewart-Katharine Hepburn classic", + "Answer": "The Philadelphia Story" + }, + { + "Category": "WATERFALLS", + "Question": "One of the most spectacular sites in this national park is Bridalveil Fall, which drops a misty curtain of water 620 feet", + "Answer": "Yosemite" + }, + { + "Category": "FILE UNDER \"K\"", + "Question": "His \"Ode To A Nightingale\" says, \"With beaded bubbles winking at the brim, and purple-stained mouth\"", + "Answer": "John Keats" + }, + { + "Category": "BRITISH NOBILITY", + "Question": "As a boy in 1461, the future King Richard III was made Duke of this", + "Answer": "Gloucester" + }, + { + "Category": "WHERE'S THE COLLEGE?", + "Question": "University of South Carolina", + "Answer": "Columbia" + }, + { + "Category": "QUOTATIONS", + "Question": "During the Cuban Missile Crisis, this Sec. of State said, \"We're eyeball to eyeball & I think the other fellow just blinked\"", + "Answer": "Dean Rusk" + }, + { + "Category": "CARY GRANT FILMS", + "Question": "Joan Fontaine thinks that hubby Cary Grant is trying to murder her in this Hitchcock film", + "Answer": "Suspicion" + }, + { + "Category": "WATERFALLS", + "Question": "The height of Shoshone Falls on this river in Idaho exceeds that of Niagara Falls", + "Answer": "Snake River" + }, + { + "Category": "FILE UNDER \"K\"", + "Question": "Former mortuary science student Jonathan Davis plays bagpipes & sings for this \"Freak on a Leash\" group", + "Answer": "Korn" + }, + { + "Category": "BRITISH NOBILITY", + "Question": "In 1702 military hero John Churchill became this \"man\" as the first Duke of it", + "Answer": "Marlborough" + }, + { + "Category": "WHERE'S THE COLLEGE?", + "Question": "University of Miami", + "Answer": "Coral Gables" + }, + { + "Category": "QUOTATIONS", + "Question": "This Nixon aide coined the phrase \"Twist slowly, slowly in the wind\" during a phone call to John Dean", + "Answer": "John Ehrlichman" + }, + { + "Category": "CARY GRANT FILMS", + "Question": "This 1957 Cary Grant-Deborah Kerr weepie was a major plot device in \"Sleepless In Seattle\"", + "Answer": "An Affair To Remember" + }, + { + "Category": "WATERFALLS", + "Question": "This scenic waterfall on the Brazil-Argentina border actually consists of about 275 individual cataracts", + "Answer": "Iguazu Falls" + }, + { + "Category": "FILE UNDER \"K\"", + "Question": "This is white wine & creme de cassis; substitute champagne for white wine & it becomes \"royale\"", + "Answer": "Kir" + }, + { + "Category": "TRANSPORTATION INNOVATIONS", + "Question": "This type of program that began in 1981 was inspired by Green Stamps", + "Answer": "Frequent flyer program" + }, + { + "Category": "ROCK OF STAGES", + "Question": "This stage musical around since 1973 has Brad & Janet but no \"Picture\" in the title", + "Answer": "The Rocky Horror Show" + }, + { + "Category": "WHO DO YOU THINK I AM?!", + "Question": "I died around 965 B.C. & my son Solomon succeeded me as King of Israel", + "Answer": "David" + }, + { + "Category": "THAT'S SOME NERVE", + "Question": "A knock to the ulnar nerve at the bend of the elbow, which we call this, causes that weird tingling sensation", + "Answer": "the funny bone" + }, + { + "Category": "DAN-O-MITE", + "Question": "Daniel & Gabriel were the first 2 names of this thermometer inventor", + "Answer": "Fahrenheit" + }, + { + "Category": "\"SUPER\"", + "Question": "In this 1986 video game, Luigi & his sibling are trying to rescue Princess Toadstool", + "Answer": "Super Mario Brothers" + }, + { + "Category": "THE CONGRESSIONAL BLACK CAUCUS", + "Question": "The CBC's fight against this overseas system of segregation included sponsoring a landmark 1986 act", + "Answer": "apartheid" + }, + { + "Category": "ROCK OF STAGES", + "Question": "Gonna be a big man someday & name this hit U.K. musical based on the music of Queen", + "Answer": "We Will Rock You" + }, + { + "Category": "WHO DO YOU THINK I AM?!", + "Question": "On Feb. 3, 1930 I presided over the founding of the Vietnamese Communist Party", + "Answer": "Ho Chi Minh" + }, + { + "Category": "THAT'S SOME NERVE", + "Question": "The first cranial nerve, it's responsible for the sense of smell", + "Answer": "the olfactory nerve" + }, + { + "Category": "\"SUPER\"", + "Question": "This person is in charge of repairs & maintenance at an apartment building", + "Answer": "superintendent" + }, + { + "Category": "ROCK OF STAGES", + "Question": "Character who sings \"Angry Inch \"", + "Answer": "Hedwig" + }, + { + "Category": "WHO DO YOU THINK I AM?!", + "Question": "Newspapers I own include the Daily Telegraph of Sydney & the Australian", + "Answer": "Rupert Murdoch" + }, + { + "Category": "THAT'S SOME NERVE", + "Question": "This nerve involved in carpal tunnel syndrome shares its name with a math term for the middle number in a sequence", + "Answer": "the median" + }, + { + "Category": "DAN-O-MITE", + "Question": "This 19th c. orator went to Dartmouth & argued Dartmouth College v. Woodward before the Supreme Court", + "Answer": "Webster" + }, + { + "Category": "\"SUPER\"", + "Question": "12-letter word meaning pertaining to the eerie or occult", + "Answer": "supernatural" + }, + { + "Category": "THE CONGRESSIONAL BLACK CAUCUS", + "Question": "The CBC set up a Brain Trust for this kind of \"justice\" to make sure toxic dumps aren't foisted on minority areas", + "Answer": "environmental justice" + }, + { + "Category": "ROCK OF STAGES", + "Question": "\"Smokey Joe's Cafe\" features \"Hound Dog\" & other songs written by Jerry Lieber & him", + "Answer": "Mike Stoller" + }, + { + "Category": "WHO DO YOU THINK I AM?!", + "Question": "Affer Los Alamos, I was the director of Princeton's Institute for Advanced Study from 1947 to 1966", + "Answer": "Oppenheimer" + }, + { + "Category": "THAT'S SOME NERVE", + "Question": "A slipped disc can cause pain along this largest nerve that runs down the leg", + "Answer": "the sciatic nerve" + }, + { + "Category": "DAN-O-MITE", + "Question": "This former defense department employee gave the Pentagon Papers to the New York Times", + "Answer": "Daniel Ellsberg" + }, + { + "Category": "\"SUPER\"", + "Question": "In grammar, it's the highest degree of comparison of adjectives & adverbs", + "Answer": "superlative" + }, + { + "Category": "ROCK OF STAGES", + "Question": "In Tom Stoppard's \"Rock 'n' Roll\", Syd Barrett is a character & the music of this band of his is heard", + "Answer": "Pink Floyd" + }, + { + "Category": "WHO DO YOU THINK I AM?!", + "Question": "I may be a trickster god, but I actually helped Thor get his hammer back after Thrym the frost giant stole it", + "Answer": "Loki" + }, + { + "Category": "THAT'S SOME NERVE", + "Question": "The radial nerve, which travels down the arm, controls movement of this large 3-headed muscle", + "Answer": "the tricep" + }, + { + "Category": "DAN-O-MITE", + "Question": "American architect Daniel Burnham was the Director of Works at the 1893 World's Fair in this city", + "Answer": "Chicago" + }, + { + "Category": "THE NEXT BIBLE BOOK AFTER...", + "Question": "Genesis", + "Answer": "Exodus" + }, + { + "Category": "THE 13th CENTURY", + "Question": "Around 1250 this country's King Alfonso III reclaimed the Algarve from the Moors after 500 years of control", + "Answer": "Portugal" + }, + { + "Category": "LESSER-KNOWN ANCIENT ROMANS?", + "Question": "Embarrassingly but aptly, this baby doctor's name was synonymous with womb", + "Answer": "Uterus" + }, + { + "Category": "TINKER", + "Question": "In November 2008 she opened up Pixie Hollow, located at the edge of Tomorrowland", + "Answer": "Tinkerbell" + }, + { + "Category": "\"EVER\"S", + "Question": "Chris Rock narrated this show, loosely based on his childhood", + "Answer": "Everybody Hates Chris" + }, + { + "Category": "CHANCE", + "Question": "The U.S. golf register says the chances of this have been estimated north of 1 in 20,000", + "Answer": "a hole-in-one" + }, + { + "Category": "THE NEXT BIBLE BOOK AFTER...", + "Question": "Mark", + "Answer": "Luke" + }, + { + "Category": "THE 13th CENTURY", + "Question": "A 1287 storm flooded the land separating the North Sea & the Zuiderzee, turning this village into a major port city", + "Answer": "Amsterdam" + }, + { + "Category": "LESSER-KNOWN ANCIENT ROMANS?", + "Question": "Unconquerable & undefeated, he led Rome to victory in the Rugby World Cup championship", + "Answer": "Invictus" + }, + { + "Category": "TINKER", + "Question": "\"Tinker, Tailor, Soldier, Spy\" is a novel by this Brit", + "Answer": "le Carré" + }, + { + "Category": "\"EVER\"S", + "Question": "This 1965 movie begins with the birth of Jesus", + "Answer": "The Greatest Story Ever Told" + }, + { + "Category": "CHANCE", + "Question": "Theoretically, a U.S. casino's ability to make money on Roulette relies on the presence of these 2 green figures", + "Answer": "0 and 00" + }, + { + "Category": "THE NEXT BIBLE BOOK AFTER...", + "Question": "Numbers", + "Answer": "Deuteronomy" + }, + { + "Category": "THE 13th CENTURY", + "Question": "This Yucatan city whose ruins are a UNESCO world heritage site gave way to Mayapan as a Mayan political center", + "Answer": "Chichen Itza" + }, + { + "Category": "LESSER-KNOWN ANCIENT ROMANS?", + "Question": "A little known trilinguist, this island-dweller was fluent in Greek & Turkish as well as Latin", + "Answer": "Cyprus" + }, + { + "Category": "TINKER", + "Question": "Grant Tinker was known as \"the man who saved\" this TV network", + "Answer": "NBC" + }, + { + "Category": "\"EVER\"S", + "Question": "The answer to this title question of 1962: she cares for her crippled sister Blanche", + "Answer": "Whatever Happened to Baby Jane?" + }, + { + "Category": "THE NEXT BIBLE BOOK AFTER...", + "Question": "Psalms", + "Answer": "Proverbs" + }, + { + "Category": "THE 13th CENTURY", + "Question": "Roger Bacon wrote coded instructions for making the explosive mix of saltpeter, sulfur & charcoal called black this", + "Answer": "powder" + }, + { + "Category": "LESSER-KNOWN ANCIENT ROMANS?", + "Question": "Quiet, efficient & adept at getting around, this Roman Toyota hybrid made for a great spy", + "Answer": "Prius" + }, + { + "Category": "TINKER", + "Question": "2 of the \"Rude Mechanicals\" from this play are Tom Snout the Tinker & Nick Bottom the Weaver", + "Answer": "A Midsummer Night's Dream" + }, + { + "Category": "\"EVER\"S", + "Question": "In a WB TV series, Treat Williams followed his dead wife's wish & took the kids to this Colorado town", + "Answer": "Everwood" + }, + { + "Category": "CHANCE", + "Question": "His 1742 \"A Short Treatise on the Game of Whist\" was a prelude to writings on other games", + "Answer": "Hoyle" + }, + { + "Category": "THE NEXT BIBLE BOOK AFTER...", + "Question": "Joshua", + "Answer": "Judges" + }, + { + "Category": "THE 13th CENTURY", + "Question": "In 1215 a bloody incident on this city's Ponte Vecchio began a civil war between the Guelphs & Ghibellines", + "Answer": "Florence" + }, + { + "Category": "LESSER-KNOWN ANCIENT ROMANS?", + "Question": "This 12-letter guy isn't remembered for much of anything other than getting under people's skin", + "Answer": "Subcutaneous" + }, + { + "Category": "TINKER", + "Question": "Sometimes called \"Irish Cobs\" or \"Gypsy Cobs\", Irish Tinkers are a type of this animal", + "Answer": "horse" + }, + { + "Category": "\"EVER\"S", + "Question": "Eddie Rabbitt sang the title song for this 1978 Clint Eastwood movie about a boxer & his simian sidekick", + "Answer": "Every Which Way but Loose" + }, + { + "Category": "CHANCE", + "Question": "To figure out the chance of a given roll with 2 dice, take the number of ways that total can come up & divide by this", + "Answer": "thirty-six" + }, + { + "Category": "NAME THE POET", + "Question": "\"The spirit who bideth by himself / in the land of mist and snow / he loved the bird that loved the man / who shot him with his bow\"", + "Answer": "Coleridge" + }, + { + "Category": "BIBLICAL FATHERS & SONS", + "Question": "This strongman was killed destroying a Philistine temple & was interred in his father's burying place", + "Answer": "Samson" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Members of the DAR are descended from men & women who participated in this event", + "Answer": "The Revolutionary War" + }, + { + "Category": "WHEAT", + "Question": "Glutamic acid from wheat is used to produce this flavor enhancer", + "Answer": "MSG" + }, + { + "Category": "MOVIE PRODUCERS", + "Question": "The G in MGM, he was excluded from the 1924 deal forming that company", + "Answer": "Samuel Goldwyn" + }, + { + "Category": "FOUNTAINS", + "Question": "There are fountains beyond the outfield at the stadium of this Kansas City baseball team", + "Answer": "Kansas City Royals" + }, + { + "Category": "RHYME TIME", + "Question": "To knock down General George S.", + "Answer": "Flatten Patton" + }, + { + "Category": "BIBLICAL FATHERS & SONS", + "Question": "Zechariah, father of this forerunner of Christ, lost his voice for doubting God's word", + "Answer": "John the Baptist" + }, + { + "Category": "ORGANIZATIONS", + "Question": "This organization abbreviated OA is dedicated to helping those who constantly binge on food", + "Answer": "Overeaters Anonymous" + }, + { + "Category": "WHEAT", + "Question": "South America's main wheat-growing area is the Pampa in this country", + "Answer": "Argentina" + }, + { + "Category": "MOVIE PRODUCERS", + "Question": "Tim Burton, director of the 1989 smash about this comic book hero, also co-produced the 1992 sequel", + "Answer": "Batman" + }, + { + "Category": "FOUNTAINS", + "Question": "Ottorino Respighi wrote a symphonic poem about the \"Fountains Of\" this Italian capital", + "Answer": "Rome" + }, + { + "Category": "RHYME TIME", + "Question": "A really big southpaw", + "Answer": "Hefty lefty" + }, + { + "Category": "BIBLICAL FATHERS & SONS", + "Question": "Abraham was 100 years old & Sarah was 90 when this child was born to them", + "Answer": "Isaac" + }, + { + "Category": "ORGANIZATIONS", + "Question": "Act it out if you wish; it's the organization sung about in the following: [audio clue: \"Young man, there's a place you can go, I say young man, when you're short on your dough...\"]", + "Answer": "Y.M.C.A" + }, + { + "Category": "WHEAT", + "Question": "This embryo of the wheat seed is a rich source of vitamin E", + "Answer": "Germ" + }, + { + "Category": "MOVIE PRODUCERS", + "Question": "Albert R. Broccoli produced 17 James Bond films & this kids' movie also based on an Ian Fleming book", + "Answer": "Chitty Chitty Bang Bang" + }, + { + "Category": "FOUNTAINS", + "Question": "You'll find the Fountain of the Centaurs on the Missouri capital grounds in this city", + "Answer": "Jefferson City" + }, + { + "Category": "RHYME TIME", + "Question": "A humorous Scandinavian dwarf of folklore", + "Answer": "Droll troll" + }, + { + "Category": "BIBLICAL FATHERS & SONS", + "Question": "His son Ham was the father of the Canaanites", + "Answer": "Noah" + }, + { + "Category": "ORGANIZATIONS", + "Question": "You don't have to be a genius to know its name is Latin for \"table\", but you do have to be one to belong", + "Answer": "Mensa" + }, + { + "Category": "WHEAT", + "Question": "Types of wheat are grouped according to these 2 seasons", + "Answer": "Winter & spring" + }, + { + "Category": "MOVIE PRODUCERS", + "Question": "He acted opposite Mary Pickford before starting the Keystone Company to produce comedies", + "Answer": "Mack Sennett" + }, + { + "Category": "FOUNTAINS", + "Question": "Lorado Taft's Fountain of the Great Lakes is now at this city's Art Institute", + "Answer": "Chicago" + }, + { + "Category": "RHYME TIME", + "Question": "A person who teaches you to imitate an owl", + "Answer": "Hooter tutor" + }, + { + "Category": "BIBLICAL FATHERS & SONS", + "Question": "When informed that this king & his son Jonathan had been killed, David said, \"How are the mighty fallen\"", + "Answer": "Saul" + }, + { + "Category": "ORGANIZATIONS", + "Question": "The Max Planck Society is one of this country's chief organizations for scientific research", + "Answer": "Germany" + }, + { + "Category": "WHEAT", + "Question": "Pasta is made from this coarsely-ground grain of durum wheat", + "Answer": "Semolina" + }, + { + "Category": "MOVIE PRODUCERS", + "Question": "Julia Phillips was the first woman producer to win a Best Picture Oscar, for this 1973 con game film", + "Answer": "The Sting" + }, + { + "Category": "FOUNTAINS", + "Question": "Andrea Del Verrocchio sculpted his bronze \"Boy With\" this sea creature for a Medici villa", + "Answer": "Dolphin" + }, + { + "Category": "RHYME TIME", + "Question": "A pumpkin suffering from ennui", + "Answer": "Bored gourd" + }, + { + "Category": "LINGUISTICS", + "Question": "Linguists have debunked the common belief that Eskimos have dozens of words for this substance", + "Answer": "Snow" + }, + { + "Category": "HISTORIC AMERICA", + "Question": "This city's Independence Nat'l Historical Park has been called \"The most historic square mile in America\"", + "Answer": "Philadelphia" + }, + { + "Category": "ANIMALS", + "Question": "This Arctic bear's feet are webbed & have hairy soles", + "Answer": "Polar bear" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "This Alberta capital is called the Gateway to the North", + "Answer": "Edmonton" + }, + { + "Category": "LITERATURE", + "Question": "\"A Tale of Two Cities\" opens as Dr. Alexander Manette is released after 18 years in this prison", + "Answer": "The Bastille" + }, + { + "Category": "10-LETTER WORDS", + "Question": "It's one's partner in crime", + "Answer": "Accomplice" + }, + { + "Category": "LINGUISTICS", + "Question": "These systems of communication that use the hands can be as rich & complex as spoken tongues", + "Answer": "Sign language/signing" + }, + { + "Category": "HISTORIC AMERICA", + "Question": "Pompey's Pillar, a rock formation in Montana, was named by Capt. William Clark for the son of this Indian guide", + "Answer": "Sacajawea" + }, + { + "Category": "ANIMALS", + "Question": "Large feral populations of the \"mute\" species of this long-necked bird inhabit the Mid-Atlantic coast", + "Answer": "Swans" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "A ferry & 2 suspension bridges connect Dartmouth, Nova Scotia with this capital", + "Answer": "Halifax" + }, + { + "Category": "LITERATURE", + "Question": "At one point in this 1862 novel, Jean Valjean owns a factory", + "Answer": "Les Miserables" + }, + { + "Category": "10-LETTER WORDS", + "Question": "It means to set free, as from slavery", + "Answer": "Emancipate" + }, + { + "Category": "LINGUISTICS", + "Question": "Sentence diagrams called these may include lines called branches", + "Answer": "Trees" + }, + { + "Category": "HISTORIC AMERICA", + "Question": "Dating from the early 1700s, the Gonzalez-Alvarez House in this city is the oldest house in Florida", + "Answer": "St. Augustine" + }, + { + "Category": "ANIMALS", + "Question": "The silver dollar fish resembles this feared fish of the Amazon basin but is strictly herbivorous", + "Answer": "Piranha" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "Commercial cod fishing, long a mainstay of this Newfoundland capital, declined to almost nothing by 1990", + "Answer": "St. John's" + }, + { + "Category": "LITERATURE", + "Question": "In \"Through The Looking Glass\", Humpty Dumpty explains to Alice the meaning of this nonsense poem", + "Answer": "Jabberwocky" + }, + { + "Category": "10-LETTER WORDS", + "Question": "Literally meaning \"all powerful\", it's often used to describe God", + "Answer": "Omnipotent" + }, + { + "Category": "LINGUISTICS", + "Question": "Considered part of grammar, it's the study of the interrelation of words in a sentence", + "Answer": "Syntax" + }, + { + "Category": "HISTORIC AMERICA", + "Question": "Carmel Mission in Carmel, Calif. was the headquarters of this Franciscan priest until his death in 1784", + "Answer": "Fr. Junipero Serra" + }, + { + "Category": "ANIMALS", + "Question": "A pocket gopher's pockets are fur-lined & located in these", + "Answer": "Cheeks" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "This Manitoba capital annexed the adjacent community of Saint Boniface in 1972", + "Answer": "Winnipeg" + }, + { + "Category": "LITERATURE", + "Question": "In the final scene of \"Rebecca\", this stately mansion of Maxim De Winter burns", + "Answer": "Manderley" + }, + { + "Category": "10-LETTER WORDS", + "Question": "Lionel Hampton's instrument", + "Answer": "Vibraphone" + }, + { + "Category": "LINGUISTICS", + "Question": "This famed M.I.T. scholar has proposed that humans have the inborn ability to learn language", + "Answer": "Noam Chomsky" + }, + { + "Category": "HISTORIC AMERICA", + "Question": "Sunflower Landing near Clarksdale, Miss. is believed to be where he found the Mississippi River in 1541", + "Answer": "Hernando De Soto" + }, + { + "Category": "ANIMALS", + "Question": "Scientists divide these toothless whales into 3 groups: right whales, gray whales & rorquals", + "Answer": "Baleen whales" + }, + { + "Category": "CANADIAN CAPITALS", + "Question": "This British Columbia capital was the capital of the colony of Vancouver Island 1848-1866", + "Answer": "Victoria" + }, + { + "Category": "LITERATURE", + "Question": "The title of this 1965 Frank Herbert novel refers to the desert planet of Arrakis", + "Answer": "Dune" + }, + { + "Category": "10-LETTER WORDS", + "Question": "From the Latin word for \"tear\", it describes someone mournful, who cries easily", + "Answer": "Lachrymose" + }, + { + "Category": "THE NOBEL PRIZE", + "Question": "The 1996 Chemistry Prize went to the discoverers of a 60-carbon atom molecule called this", + "Answer": "Buckyball" + }, + { + "Category": "MILITARY POWER", + "Question": "Contour flying is when a pilot flies low, following the Earth's contours, to avoid this", + "Answer": "Radar" + }, + { + "Category": "AROUND THE POKER TABLE WITH SLIM", + "Question": "Slim & the others may feed this fund made up of a portion of each pot", + "Answer": "Kitty" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "An exclamation point was warranted for the \"End Of\" This! in 1918", + "Answer": "World War I" + }, + { + "Category": "DREAMY MUSIC", + "Question": "On their 1997 Popmart tour this Irish band covered the Monkees' \"Daydream Believer\"", + "Answer": "U2" + }, + { + "Category": "BUGS", + "Question": "These insects \"chirp\" by rubbing their 2 front wings together", + "Answer": "Crickets" + }, + { + "Category": "FEELING \"ANCY\"", + "Question": "This for life in the U.S. is currently about 76 years", + "Answer": "Life expectancy" + }, + { + "Category": "MILITARY POWER", + "Question": "No armed forces are allowed in this area between North & South Korea", + "Answer": "Demilitarized zone" + }, + { + "Category": "AROUND THE POKER TABLE WITH SLIM", + "Question": "According to Hoyle, before Slim deals, the player to his right has to do this with 5 to 47 cards", + "Answer": "Cut the deck" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "\"Shot Dead By Federal Men In Front Of Movie Theatre\" read his 1934 front-page obituary", + "Answer": "John Dillinger" + }, + { + "Category": "DREAMY MUSIC", + "Question": "He's the singer heard here: \"In dreams, I walk....\"", + "Answer": "Roy Orbison" + }, + { + "Category": "BUGS", + "Question": "This bloodsucking insect, cimex lectularius, is often found in mattresses; don't let 'em bite", + "Answer": "Bedbugs" + }, + { + "Category": "FEELING \"ANCY\"", + "Question": "The three members of our staff, seen here, are all in this condition", + "Answer": "Pregnancy" + }, + { + "Category": "MILITARY POWER", + "Question": "A period of guard duty; in the Navy one may be 4 or 8 hours long", + "Answer": "Watch" + }, + { + "Category": "AROUND THE POKER TABLE WITH SLIM", + "Question": "When Slim gets this hand it reminds him of Bob Saget, Lori Loughlin, & the Olsen Twins", + "Answer": "Full house" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "\"Thousands Trapped In The Subways; Looters And Vandals Hit\" were banners when this hit NYC in July 1977", + "Answer": "Blackout" + }, + { + "Category": "DREAMY MUSIC", + "Question": "It's the Aerosmith tune that encourages you to \"Dream until your dream comes true\"", + "Answer": "Dream On" + }, + { + "Category": "BUGS", + "Question": "This large hairy spider is named for a wolf spider found near the Italian town of Taranto", + "Answer": "Tarantula" + }, + { + "Category": "FEELING \"ANCY\"", + "Question": "Loitering in a town & not having any visible means of support, you may get picked up for it", + "Answer": "Vagrancy" + }, + { + "Category": "MILITARY POWER", + "Question": "It's an order for aircraft to get off the ground ASAP or an egg order to the mess hall cook", + "Answer": "Scramble" + }, + { + "Category": "AROUND THE POKER TABLE WITH SLIM", + "Question": "Slim's numerical term for a bluffer who doesn't have the fifth card to fill out a hand of all the same suit", + "Answer": "Four-flusher" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "Oct. 2, 1962: \"3,000 Troops Put Down....Rioting And Seize 200 As Negro Attends\" this school", + "Answer": "University of Mississippi" + }, + { + "Category": "DREAMY MUSIC", + "Question": "\"The only trouble\" with this Everly Brothers hit is \"Gee whiz, I'm dreaming my life away\"", + "Answer": "All I Have To Do Is Dream" + }, + { + "Category": "BUGS", + "Question": "These small, stinging ants were introduced into the U.S. at Mobile, Alabama", + "Answer": "Fire ants" + }, + { + "Category": "FEELING \"ANCY\"", + "Question": "Derringer or Butler", + "Answer": "Yancy" + }, + { + "Category": "MILITARY POWER", + "Question": "Whether general or ready, they're the troops held close by", + "Answer": "Reserves" + }, + { + "Category": "AROUND THE POKER TABLE WITH SLIM", + "Question": "To do this in stud poker, Slim turns all his cards face down", + "Answer": "Fold" + }, + { + "Category": "NEW YORK TIMES HEADLINES", + "Question": "The Times made its own front page in 1971 when the Supreme Court upheld its publication of these documents", + "Answer": "The Pentagon Papers" + }, + { + "Category": "DREAMY MUSIC", + "Question": "In 1975 this outlaw released \"Dreaming My Dreams\" & his wife Jessi Colter released \"I'm Not Lisa\"", + "Answer": "Waylon Jennings" + }, + { + "Category": "BUGS", + "Question": "Also known as a devil's darning needle, it may have as many as 28,000 lenses in its compound eyes", + "Answer": "Dragonfly" + }, + { + "Category": "FEELING \"ANCY\"", + "Question": "Janet Leigh was sorry she found one of these at the Bates Motel", + "Answer": "Vacancy" + }, + { + "Category": "THE 17TH CENTURY", + "Question": "In 1682 he founded the \"City Of Brotherly Love\"", + "Answer": "William Penn" + }, + { + "Category": "COUNTIES BY STATE", + "Question": "McDuffie, Meriwether, Macon", + "Answer": "Georgia" + }, + { + "Category": "MOVIE CO-STARS", + "Question": "His wife Lauren Bacall was his leading lady in the 1946 film noir \"The Big Sleep\"", + "Answer": "Humphrey Bogart" + }, + { + "Category": "MAY DAYS", + "Question": "Henry VIII imported an executioner from France just to behead this second wife on May 19, 1536", + "Answer": "Anne Boleyn" + }, + { + "Category": "EDNA ST. VINCENT MILLAY SAYS....", + "Question": "Of this deaf composer she wrote, \"Sweet sounds, oh beautiful music, do not cease!\"", + "Answer": "L.V. Beethoven" + }, + { + "Category": "\"EZ\" DOES IT", + "Question": "In the classic sitcom he's the patriarch of \"The Addams Family\"", + "Answer": "Gomez" + }, + { + "Category": "THE 17TH CENTURY", + "Question": "Nearly 13,000 homes & 100 churches were destroyed in this city's Great Fire of 1666", + "Answer": "London" + }, + { + "Category": "COUNTIES BY STATE", + "Question": "McClain, McCurtain, Muskogee", + "Answer": "Oklahoma" + }, + { + "Category": "MOVIE CO-STARS", + "Question": "7 years after \"The Wizard Of Oz\" Ray Bolger co-starred with her again, in \"The Harvey Girls\"", + "Answer": "Judy Garland" + }, + { + "Category": "MAY DAYS", + "Question": "On May 15, 1996 he announced he would soon become \"A private citizen, a Kansan, an American, just a man\"", + "Answer": "Senator Bob Dole" + }, + { + "Category": "EDNA ST. VINCENT MILLAY SAYS....", + "Question": "Later in life she wrote that, like the lonely tree, this season \"sang in me a little while, that in me sings no more\"", + "Answer": "Summer" + }, + { + "Category": "\"EZ\" DOES IT", + "Question": "Port Said is this waterway's northern terminus", + "Answer": "Suez Canal" + }, + { + "Category": "THE 17TH CENTURY", + "Question": "In his 1613 \"Letters On Sunspots\", he openly supported the Copernican theory", + "Answer": "Galileo" + }, + { + "Category": "COUNTIES BY STATE", + "Question": "Baca, Bent, Boulder", + "Answer": "Colorado" + }, + { + "Category": "MOVIE CO-STARS", + "Question": "Meryl Streep & this actress were acclaimed for playing sisters in the 1996 film \"Marvin's Room\"", + "Answer": "Diane Keaton" + }, + { + "Category": "MAY DAYS", + "Question": "Oliver Lewis rode Aristides to victory in the inaugural running of this horse race on May 17, 1875", + "Answer": "Kentucky Derby" + }, + { + "Category": "EDNA ST. VINCENT MILLAY SAYS....", + "Question": "Cynically she wrote that this \"Is not all; it is not meat nor drink nor slumber nor a roof against the rain\"", + "Answer": "Love" + }, + { + "Category": "\"EZ\" DOES IT", + "Question": "One of the large, flat triangular muscles of the shoulder & upper back region", + "Answer": "Trapezius" + }, + { + "Category": "THE 17TH CENTURY", + "Question": "Cheers to this Benedictine monk who pioneered the making of champagne in 1698", + "Answer": "Dom Perignon" + }, + { + "Category": "COUNTIES BY STATE", + "Question": "Whitley, Wayne, Wabash", + "Answer": "Indiana" + }, + { + "Category": "MOVIE CO-STARS", + "Question": "\"Ransom\" reunited her with her \"Lethal Weapon 3\" co-star Mel Gibson", + "Answer": "Rene Russo" + }, + { + "Category": "MAY DAYS", + "Question": "On May 10, 1941 this deputy to Hitler parachuted from a plane over Scotland with a \"peace plan\"", + "Answer": "Rudolf Hess" + }, + { + "Category": "EDNA ST. VINCENT MILLAY SAYS....", + "Question": "Edna wrote that this \"burns at both ends; it will not last the night\"", + "Answer": "My candle" + }, + { + "Category": "\"EZ\" DOES IT", + "Question": "This Frenchman painted the self-portrait seen here:", + "Answer": "Paul Cezanne" + }, + { + "Category": "THE 17TH CENTURY", + "Question": "In 1673 this pair explored the Mississippi River all the way to the mouth of the Arkansas", + "Answer": "Marquette & Joliet" + }, + { + "Category": "COUNTIES BY STATE", + "Question": "Oswego, Onondaga, Oneida", + "Answer": "New York" + }, + { + "Category": "MOVIE CO-STARS", + "Question": "Montgomery Clift & Shelley Winters were nominated for Oscars for this 1951 film; Elizabeth Taylor was not", + "Answer": "A Place in the Sun" + }, + { + "Category": "MAY DAYS", + "Question": "On May 6, 1984 Jose Napoleon Duarte won this country's presidential election with 54% of the vote", + "Answer": "El Salvador" + }, + { + "Category": "EDNA ST. VINCENT MILLAY SAYS....", + "Question": "\"We were very tired, we were very merry -- we had gone back and forth all night in\" this conveyance", + "Answer": "Ferry" + }, + { + "Category": "\"EZ\" DOES IT", + "Question": "Columbus' first landing on the mainland of the Americas was on the coast of what is now this country", + "Answer": "Venezuela" + }, + { + "Category": "AUTHORS", + "Question": "He claimed that as a Pinkerton detective, he had worked the Fatty Arbuckle & Nicky Arnstein cases", + "Answer": "Dashiell Hammett" + }, + { + "Category": "18th CENTURY AMERICA", + "Question": "His wife Abigail wrote to him in a 1776 letter, \"Remember the ladies... all men would be tyrants if they could\"", + "Answer": "John Adams" + }, + { + "Category": "NFL COACHES", + "Question": "In the 1990s Marv Levy led this team to 4 straight Super Bowl appearances", + "Answer": "the Buffalo Bills" + }, + { + "Category": "LEGENDARY LEGENDS", + "Question": "Legend says if you run unto the ghost of the pirate Blackbeard, he may be hard to recognize, as he's missing this", + "Answer": "his head" + }, + { + "Category": "WHAT KIND OF FOWL AM I?", + "Question": "Snow, Mother or Canada", + "Answer": "a goose" + }, + { + "Category": "COLOGNE RANGER", + "Question": "In 1932 one of these speed limit-less German expressways opened between Cologne & Bonn", + "Answer": "an Autobahn" + }, + { + "Category": "TAUNT \"O\"", + "Question": "By its isolated nature, your last original thought might be considered one of these children without parents", + "Answer": "an orphan" + }, + { + "Category": "18th CENTURY AMERICA", + "Question": "In 1792 Robert Thomas founded this almanac that contained useful weather info; the \"Old\" was added later", + "Answer": "The Farmers' Almanac" + }, + { + "Category": "NFL COACHES", + "Question": "In 2004 LSU coach Nick Saban was tapped to be the new head coach for this team", + "Answer": "the Miami Dolphins" + }, + { + "Category": "LEGENDARY LEGENDS", + "Question": "A legendary sailor of the Incas shares his name with this raft on which Thor Heyerdahl sailed the Pacific", + "Answer": "the Kon-Tiki" + }, + { + "Category": "WHAT KIND OF FOWL AM I?", + "Question": "Rock Cornish game hen or Rhode Island Red", + "Answer": "a chicken" + }, + { + "Category": "COLOGNE RANGER", + "Question": "Founded in Cologne, this German airline really took off in 1953", + "Answer": "Lufthansa" + }, + { + "Category": "TAUNT \"O\"", + "Question": "Being around you has completely killed my sense of this, the tendency to expect the best of life", + "Answer": "optimism" + }, + { + "Category": "18th CENTURY AMERICA", + "Question": "In 1796 he said that the U.S. should \"steer clear of permanent alliances\" in foreign policy", + "Answer": "George Washington" + }, + { + "Category": "NFL COACHES", + "Question": "Of current head coaches, this reigning Super Bowl champ has the longest consecutive tenure with 1 team", + "Answer": "Bill Cowher" + }, + { + "Category": "LEGENDARY LEGENDS", + "Question": "A legend about this \"Irish\" group is that they are the descendants of shipwrecked sailors of the Spanish Armada", + "Answer": "the Black Irish" + }, + { + "Category": "WHAT KIND OF FOWL AM I?", + "Question": "Golden or ring-necked", + "Answer": "a pheasant" + }, + { + "Category": "COLOGNE RANGER", + "Question": "Taking nearly 600 years to complete, Cologne Cathedral is the largest in this style in Northern Europe", + "Answer": "Gothic" + }, + { + "Category": "TAUNT \"O\"", + "Question": "At your place of work, it might behoove us to replace you with one of these Pongo pygmaeus apes of Borneo", + "Answer": "an orangutan" + }, + { + "Category": "18th CENTURY AMERICA", + "Question": "On Dec. 26, 1776 Americans killed Col. Johann Rall & captured about 1,000 Hessian troops in this battle", + "Answer": "the Battle of Trenton" + }, + { + "Category": "NFL COACHES", + "Question": "The Raiders rehired this man in 2006, 17 years after making him the first black head coach in the modern NFL", + "Answer": "Art Shell" + }, + { + "Category": "LEGENDARY LEGENDS", + "Question": "Marshall Gold Discovery State Hist. Park is in this county that shares its name with a legendary city of gold", + "Answer": "El Dorado" + }, + { + "Category": "WHAT KIND OF FOWL AM I?", + "Question": "Red-shouldered or red-tailed", + "Answer": "a hawk" + }, + { + "Category": "COLOGNE RANGER", + "Question": "The Zoo Bridge spans this river that runs through Cologne", + "Answer": "the Rhine" + }, + { + "Category": "TAUNT \"O\"", + "Question": "When you try to make a point, you flail around like one of these mollusks with 8 limbs", + "Answer": "an octopus" + }, + { + "Category": "18th CENTURY AMERICA", + "Question": "These 85 essays arguing for adoption of the Constitution appeared between October 27, 1787 & May 28, 1788", + "Answer": "the Federalist Papers" + }, + { + "Category": "LEGENDARY LEGENDS", + "Question": "A modern urban legend says the USS Eldridge disappeared in this city's Navy yard in a 1943 \"Experiment\"", + "Answer": "Philadelphia" + }, + { + "Category": "WHAT KIND OF FOWL AM I?", + "Question": "The blackcock or the ruffed", + "Answer": "a grouse" + }, + { + "Category": "COLOGNE RANGER", + "Question": "Born in Cologne in 1876, he was the first chancellor of West Germany following World War II", + "Answer": "Konrad Adenauer" + }, + { + "Category": "TAUNT \"O\"", + "Question": "After a wrong response, we may need to use one of these cathode-ray \"scopes\" to check for brain activity", + "Answer": "an oscilloscope" + }, + { + "Category": "THE ROMANOV DYNASTY", + "Question": "The Romanov dynasty was named in honor of Roman Yurievich, whose daughter married this \"horrifying\" czar", + "Answer": "Ivan the Terrible" + }, + { + "Category": "TONY WINNERS OF THE '50s", + "Question": "Cyril Ritchard hooked a 1955 Tony for playing Captain Hook in this musical", + "Answer": "Peter Pan" + }, + { + "Category": "LITERARY SISTERS", + "Question": "In this Tennessee Williams play, Tom Wingfield brings a gentleman caller home to meet his crippled sister Laura", + "Answer": "The Glass Menagerie" + }, + { + "Category": "DANCE IN THE DICTIONARY", + "Question": "We've got Bud & Amstel Light in bottles, or Sam Adams \"on\" this syncopated style", + "Answer": "tap" + }, + { + "Category": "THE BODY WOMAN", + "Question": "Women have this piece of thyroid cartilage, too; it's just smaller than a man's & may be under more fat", + "Answer": "an Adam's apple" + }, + { + "Category": "VERBS", + "Question": "4-syllable synonym for \"to count\", from Latin for \"to count\"", + "Answer": "enumerate" + }, + { + "Category": "THE ROMANOV DYNASTY", + "Question": "One bio of this \"Great\" czar says he carried dental instruments around with him because he loved to pull teeth", + "Answer": "Peter the Great" + }, + { + "Category": "TONY WINNERS OF THE '50s", + "Question": "Bloody Mary was the girl the Tonys loved in 1950, when Juanita Hall won for playing her in this musical", + "Answer": "South Pacific" + }, + { + "Category": "LITERARY SISTERS", + "Question": "In \"Gone with the Wind\", Scarlett O'Hara marries Charles Hamilton & Ashley Wilkes marries her, Charles' sister", + "Answer": "Melanie" + }, + { + "Category": "DANCE IN THE DICTIONARY", + "Question": "If you wash your hair in the sink, you might have to deal with this heavy-shoed dance", + "Answer": "clog" + }, + { + "Category": "THE BODY WOMAN", + "Question": "Estrogen & progesterone are hormones produced by these glands", + "Answer": "the ovaries" + }, + { + "Category": "VERBS", + "Question": "This word for a type of running is from a word meaning \"jump\", & it's a talent that long jumpers need to get distance", + "Answer": "sprint" + }, + { + "Category": "THE ROMANOV DYNASTY", + "Question": "At Oranienbaum, this ruler who certainly loved her thrills had a \"sliding hill\", an 18th c. version of a roller coaster", + "Answer": "Catherine the Great" + }, + { + "Category": "TONY WINNERS OF THE '50s", + "Question": "Gertrude Lawrence won in 1952 for playing the title pronoun in this Rodgers & Hammerstein musical", + "Answer": "The King and I" + }, + { + "Category": "LITERARY SISTERS", + "Question": "Meg's the oldest of the sisters in this family; Amy, the youngest", + "Answer": "the Marches" + }, + { + "Category": "DANCE IN THE DICTIONARY", + "Question": "It was established as a cyclic form by Vienna's Josef Lanner; you think you can do this dance in here & order us around?", + "Answer": "waltz" + }, + { + "Category": "THE BODY WOMAN", + "Question": "A fertilized egg travels to this female body part & implants itself there", + "Answer": "the uterus" + }, + { + "Category": "VERBS", + "Question": "You can fluff pillows or do this, also meaning \"chubby\"", + "Answer": "plump" + }, + { + "Category": "THE ROMANOV DYNASTY", + "Question": "All 3 of the Romanov czars named Alexander reigned during this century", + "Answer": "the 19th century" + }, + { + "Category": "TONY WINNERS OF THE '50s", + "Question": "In 1953 Thomas Mitchell won for the musical \"Hazel Flagg\" & this future TV \"Hazel\" won for \"Time of the Cuckoo\"", + "Answer": "Shirley Booth" + }, + { + "Category": "LITERARY SISTERS", + "Question": "While in a cataleptic trance, Roderick's sister Madeline is buried alive in this Poe story", + "Answer": "\"The Fall of the House of Usher\"" + }, + { + "Category": "DANCE IN THE DICTIONARY", + "Question": "This centuries-old English dance \"was up\" for the bank robber when the cops arrived", + "Answer": "jig" + }, + { + "Category": "THE BODY WOMAN", + "Question": "Location of the zygomatic bones; fashion models may have prominent ones", + "Answer": "cheekbones" + }, + { + "Category": "VERBS", + "Question": "Appropriate last name of Captain William of 18th century Virginia, who promoted vigilante justice", + "Answer": "Lynch" + }, + { + "Category": "TONY WINNERS OF THE '50s", + "Question": "This redhead won 4 Tonys in the '50s, for \"Can-Can\", \"Damn Yankees\", \"New Girl in Town\" & \"Redhead\"", + "Answer": "Gwen Verdon" + }, + { + "Category": "LITERARY SISTERS", + "Question": "Holden Caulfield tells this little sister that he wants to be a \"catcher in the rye\" to keep kids from falling", + "Answer": "Phoebe" + }, + { + "Category": "DANCE IN THE DICTIONARY", + "Question": "Our team won 55-0--you could call it this 19th century African-American dance", + "Answer": "a cakewalk" + }, + { + "Category": "THE BODY WOMAN", + "Question": "When a woman's \"water breaks\" in labor, the \"water\" is this fluid", + "Answer": "amniotic fluid" + }, + { + "Category": "VERBS", + "Question": "As a verb, this British nationality means to put an end to something abruptly", + "Answer": "Scotch" + }, + { + "Category": "MOVIE DIRECTORS", + "Question": "He's the only person to direct his daughter & his father in Oscar-winning performances", + "Answer": "John Huston" + }, + { + "Category": "NATIVE AMERICAN PLACE NAMES", + "Question": "Like its lengthy river, this state's name is Algonquian for \"great water\"", + "Answer": "Mississippi" + }, + { + "Category": "THE HUMAN ANIMAL", + "Question": "In the \"Sopranos\" first season finale, Jimmy Altieri gets whacked for being one of these rodents", + "Answer": "a rat" + }, + { + "Category": "TIME'S TOP 10 EVERYTHING OF 2008", + "Question": "No. 7 in \"Food Trends\": Meat from this animal (kid is the tenderest)", + "Answer": "goat" + }, + { + "Category": "SCRAMBLED EGGS", + "Question": "Its eggs weigh around 3 pounds each: RICH SOT", + "Answer": "ostrich" + }, + { + "Category": "TRUTH OR DARE", + "Question": "Dare: Imitate Kikazaru, the monkey who illustrates this phrase that goes with \"see no evil\" & \"speak no evil\"", + "Answer": "\"hear no evil\"" + }, + { + "Category": "NATIVE AMERICAN PLACE NAMES", + "Question": "Laugh all you like but Hiawatha's wife in a poem by Longfellow was named for this Minnesota waterfall", + "Answer": "Minnehaha" + }, + { + "Category": "THE HUMAN ANIMAL", + "Question": "Comanche chief Parra-o-coom was described as \"a great\" this animal \"of a man\"; it's also what his name means", + "Answer": "bear" + }, + { + "Category": "TIME'S TOP 10 EVERYTHING OF 2008", + "Question": "No. 2 in \"Jerry Stiller's Top 10 Words\": This before \"gevalt!\" (Bonus--No. 3 was \"colonoscopy\")", + "Answer": "Oy" + }, + { + "Category": "SCRAMBLED EGGS", + "Question": "Mmm... caviar: SO URGENT", + "Answer": "sturgeon" + }, + { + "Category": "TRUTH OR DARE", + "Question": "Truth: This \"Common Sense\" pamphleteer later turned to inventing, trying to come up with a smokeless candle", + "Answer": "Thomas Paine" + }, + { + "Category": "NATIVE AMERICAN PLACE NAMES", + "Question": "Moving right along--this large Alabama city, as well as a river & bay, was named for an Indian tribe in the region", + "Answer": "Mobile" + }, + { + "Category": "THE HUMAN ANIMAL", + "Question": "Slang for a woman on the prowl for younger men", + "Answer": "a cougar" + }, + { + "Category": "TIME'S TOP 10 EVERYTHING OF 2008", + "Question": "No. 7 in \"Quotes\": This politician, when told that 2/3 of Americans did not support the Iraq War--\"So?\"", + "Answer": "Dick Cheney" + }, + { + "Category": "SCRAMBLED EGGS", + "Question": "A type of this lays the smallest egg for an avian: BRING HIM MUD", + "Answer": "hummingbird" + }, + { + "Category": "TRUTH OR DARE", + "Question": "Dare: Respond with an imitation of this radio therapist whose \"Sexually Speaking\" program began in 1980", + "Answer": "Ruth Westheimer" + }, + { + "Category": "NATIVE AMERICAN PLACE NAMES", + "Question": "Although its name means \"place of sandflies\", we associate this Pennsylvania borough with groundhogs", + "Answer": "Punxsutawney" + }, + { + "Category": "THE HUMAN ANIMAL", + "Question": "On behalf of Western intelligence, Col. Oleg Penkovsky was one of these inside the USSR", + "Answer": "a mole" + }, + { + "Category": "TIME'S TOP 10 EVERYTHING OF 2008", + "Question": "No. 1 in \"Discoveries\": \"Snow on\" this", + "Answer": "Mars" + }, + { + "Category": "SCRAMBLED EGGS", + "Question": "This bird's eggs are so pretty a color is named for them: IN BRO", + "Answer": "robin" + }, + { + "Category": "TRUTH OR DARE", + "Question": "Truth: This fight promoter said \"There was a spontaneous combustion of love\" at the Trump wedding", + "Answer": "Don King" + }, + { + "Category": "NATIVE AMERICAN PLACE NAMES", + "Question": "An RV maker based in Iowa shares its name with this large Wisconsin lake", + "Answer": "Winnebago" + }, + { + "Category": "THE HUMAN ANIMAL", + "Question": "Denis Leary says of firefighters, \"You have to be like\" this sea creature. \"You have to keep moving forward\"", + "Answer": "a shark" + }, + { + "Category": "TIME'S TOP 10 EVERYTHING OF 2008", + "Question": "No. 9 in \"Green Stories\": \"Northeastern utilities bid $38.5 million for the right to emit 12.5 tons of\" this", + "Answer": "carbon dioxide" + }, + { + "Category": "SCRAMBLED EGGS", + "Question": "Reptile born with an \"egg tooth\" so it can escape its shelled jail: TAILOR GAL", + "Answer": "alligator" + }, + { + "Category": "TRUTH OR DARE", + "Question": "Dare: She was born on Aug. 18, 1587, the first English child born in America", + "Answer": "Virginia Dare" + }, + { + "Category": "NIGHT WATCH", + "Question": "July 7, 2009: If you're in Australia, the Americas or sailing the Pacific, look for an eclipse of this", + "Answer": "the Moon" + }, + { + "Category": "CLASSIC MOVIE SPECIAL EFFECTS", + "Question": "1956: The Red Sea is parted", + "Answer": "The Ten Commandments" + }, + { + "Category": "NAME THE PLAY", + "Question": "George: \"It's very simple, Martha, this young man is working on a system whereby chromosomes can be altered\"", + "Answer": "Who's Afraid of Virginia Woolf?" + }, + { + "Category": "HEADLINES", + "Question": "On May 24, 1927 the Las Vegas Review headlined that this man \"Spurns Offers. Back to Air Mail, Says\"", + "Answer": "Lindbergh" + }, + { + "Category": "FROM B TO C", + "Question": "Pertaining to an inflamed swelling of a lymph node, all too common in the 14th century", + "Answer": "bubonic" + }, + { + "Category": "NIGHT WATCH", + "Question": "The schedule is TBD, but if you head way up north in March or Sept., you can probably catch this big light show", + "Answer": "Aurora borealis" + }, + { + "Category": "CLASSIC MOVIE SPECIAL EFFECTS", + "Question": "1968: (Spoiler alert!) Taylor discovers Lady Liberty poking up through the sand", + "Answer": "Planet of the Apes" + }, + { + "Category": "NAME THE PLAY", + "Question": "Algernon: \"You look as if your name was Ernest. You are the most earnest-looking person I ever saw in my life\"", + "Answer": "The Importance of Being Earnest" + }, + { + "Category": "HEADLINES", + "Question": "On May 3, 1973 the Chicago Tribune said this local landmark \"Becomes the Tallest of the Tall\"", + "Answer": "the Sears Tower" + }, + { + "Category": "FROM B TO C", + "Question": "A group of nations acting together, like the old Soviet one", + "Answer": "bloc" + }, + { + "Category": "NIGHT WATCH", + "Question": "January 3, 2010: Look out! The Quadrantids will be coming from Bootes! Oh... relax, it's just a shower of these things", + "Answer": "meteors" + }, + { + "Category": "CLASSIC MOVIE SPECIAL EFFECTS", + "Question": "1998: Bullet trails in the water showcase the horror of the Normandy invasion", + "Answer": "Saving Private Ryan" + }, + { + "Category": "NAME THE PLAY", + "Question": "Nathan: \"There is the highest player of them all... why do you think they call him Sky? That's how high he bets\"", + "Answer": "Guys and Dolls" + }, + { + "Category": "HEADLINES", + "Question": "A Sept. 13, 1901 Buffalo News headline read, he \"Passed Away... from Effects of Cowardly Assassin's Bullet\"", + "Answer": "President McKinley" + }, + { + "Category": "FROM B TO C", + "Question": "Pompous; overblown", + "Answer": "bombastic" + }, + { + "Category": "NIGHT WATCH", + "Question": "If you stay up really, really, late (like till 2061), you'll see this, named for the guy who identified it in 1705", + "Answer": "Halley's Comet" + }, + { + "Category": "CLASSIC MOVIE SPECIAL EFFECTS", + "Question": "1968: Dave enters the airlock without a space helmet", + "Answer": "2001: A Space Odyssey" + }, + { + "Category": "NAME THE PLAY", + "Question": "Orsino: \"O, when mine eyes did see Olivia first, methought she purged the air of pestilence\"", + "Answer": "Twelfth Night" + }, + { + "Category": "HEADLINES", + "Question": "From the July 22, 1925 Knoxville Journal: This man \"Declared Guilty\"; \"Bryan's Testimony Ordered Stricken\"", + "Answer": "Scopes" + }, + { + "Category": "FROM B TO C", + "Question": "1829 novelist of \"Les Chouans\"", + "Answer": "Balzac" + }, + { + "Category": "NIGHT WATCH", + "Question": "June 6, 2012: At sunset, watch this planet make a transit across the sun--only the 8th since the invention of the telescope", + "Answer": "Venus" + }, + { + "Category": "CLASSIC MOVIE SPECIAL EFFECTS", + "Question": "1984: Men ride giant worms & attack the forces of the Emperor", + "Answer": "Dune" + }, + { + "Category": "NAME THE PLAY", + "Question": "Inez: \"I prefer to choose my hell; I prefer to look you in the eyes and fight it out face to face\"", + "Answer": "No Exit" + }, + { + "Category": "HEADLINES", + "Question": "From the Sept. 16, 1961 N.Y. Times: He \"Dies in African Air Crash; Kennedy Going to U.N. in Succession Crisis\"", + "Answer": "Dag Hammarskjold" + }, + { + "Category": "FROM B TO C", + "Question": "Branch of the Indo-European family of languages", + "Answer": "Baltic" + }, + { + "Category": "THE ELEMENTS", + "Question": "Once called radium F, this element was named for the homeland of one of its discoverers", + "Answer": "polonium" + }, + { + "Category": "NONFICTION PULITZER WINNERS", + "Question": "Garry Wills used a lot more than 272 words writing \"Lincoln at\" this place, which won him a 1993 Pulitzer", + "Answer": "Gettysburg" + }, + { + "Category": "THINGS ON NFL HELMETS", + "Question": "A blue star with a white outline", + "Answer": "the Dallas Cowboys" + }, + { + "Category": "EXPIRATION DATES", + "Question": "April 8, 1973: A blue period for the art world with his demise", + "Answer": "Picasso" + }, + { + "Category": "WHAT TO WEAR", + "Question": "Front-closing style of sweater favored by Mr. Rogers", + "Answer": "a cardigan" + }, + { + "Category": "B FOLLOWS A", + "Question": "In a Harry Potter novel, Sirius Black is a convicted murderer who escapes from this island prison in the North Sea", + "Answer": "Azkaban" + }, + { + "Category": "DOWN AT THE OLD FACTORY", + "Question": "Havana's Real Fabrica de Tabacos Partagas has been turning these out since 1845", + "Answer": "cigars" + }, + { + "Category": "NONFICTION PULITZER WINNERS", + "Question": "2007's winner, \"The Looming Tower\" is subtitled this terrorist group \"and the Road to 9/11\"", + "Answer": "al-Qaeda" + }, + { + "Category": "THINGS ON NFL HELMETS", + "Question": "A soldier with a blue 3-cornered hat & red streaks", + "Answer": "the New England Patriots" + }, + { + "Category": "EXPIRATION DATES", + "Question": "May 13, 1884: This inventor did not fear the (mechanical) reaper", + "Answer": "Cyrus McCormick" + }, + { + "Category": "WHAT TO WEAR", + "Question": "Eddie Bauer & The Gap offer the flared-below-the-knee jeans called this \"cut\", from what they fit over", + "Answer": "boot-cut" + }, + { + "Category": "B FOLLOWS A", + "Question": "Meaning loathsome, it precedes snowman or, in a movie title, Dr. Phibes", + "Answer": "abominable" + }, + { + "Category": "DOWN AT THE OLD FACTORY", + "Question": "Charlie Bucket might like to visit this type of factory that opened in 1884 in Voiron, France", + "Answer": "a chocolate factory" + }, + { + "Category": "NONFICTION PULITZER WINNERS", + "Question": "Neil Sheehan's \"A Bright Shining Lie\" centers on John Paul Vann & America's involvement in this event", + "Answer": "the Vietnam War" + }, + { + "Category": "THINGS ON NFL HELMETS", + "Question": "On a tattered red flag, a skull over crossed swords with a football in the middle", + "Answer": "the Tampa Bay Buccaneers" + }, + { + "Category": "EXPIRATION DATES", + "Question": "December 7, 1975: In \"our town\" of Hamden, Conn.", + "Answer": "Thornton Wilder" + }, + { + "Category": "WHAT TO WEAR", + "Question": "Christian Lacroix popularized the pouf type of this", + "Answer": "dress" + }, + { + "Category": "B FOLLOWS A", + "Question": "As a noun, it's a mop used to clean a ship's deck; as a verb, it's what you do with the mop", + "Answer": "swab" + }, + { + "Category": "DOWN AT THE OLD FACTORY", + "Question": "In 2004 \"Mustang Sally\" played on the P.A. as an 86-year-old factory of this company ended production", + "Answer": "Ford" + }, + { + "Category": "NONFICTION PULITZER WINNERS", + "Question": "Herbert P. Bix won in 2001 with a book on this emperor \"and the Making of Modern Japan\"", + "Answer": "Hirohito" + }, + { + "Category": "THINGS ON NFL HELMETS", + "Question": "A white arrowhead with a black outline; inside are 2 letters", + "Answer": "the Kansas City Chiefs" + }, + { + "Category": "EXPIRATION DATES", + "Question": "January 14, 1984: After passing through the golden arches", + "Answer": "Ray Kroc" + }, + { + "Category": "WHAT TO WEAR", + "Question": "In 2002 John Gotti was buried in a pinstripe suit of this characteristic closing type", + "Answer": "double-breasted" + }, + { + "Category": "B FOLLOWS A", + "Question": "It's an outline of what material will be covered in a college course", + "Answer": "a syllabus" + }, + { + "Category": "DOWN AT THE OLD FACTORY", + "Question": "The Edgar Thomson Plant in Braddock, Penn. filled its first orders for this industrial material in 1875", + "Answer": "steel" + }, + { + "Category": "NONFICTION PULITZER WINNERS", + "Question": "William Warner's \"Beautiful Swimmers\" is an exploration of the Atlantic blue crab & this bay", + "Answer": "the Chesapeake" + }, + { + "Category": "THINGS ON NFL HELMETS", + "Question": "A fleur-de-lis", + "Answer": "the New Orleans Saints" + }, + { + "Category": "EXPIRATION DATES", + "Question": "October 11, 1963: The end of this chanteuse's \"vie en rose\"", + "Answer": "Édith Piaf" + }, + { + "Category": "B FOLLOWS A", + "Question": "These 1st & 2nd century B.C. Jewish patriots were active in liberating Judea from Syrian rule", + "Answer": "the Maccabees" + }, + { + "Category": "DOWN AT THE OLD FACTORY", + "Question": "Company that ran the Hawk-Eye Works in Rochester, N.Y.", + "Answer": "Kodak" + }, + { + "Category": "NORTH AMERICAN GEOGRAPHY", + "Question": "With a flood control system, the Red River no longer flows into this river, just into the Atchafalaya", + "Answer": "the Mississippi" + }, + { + "Category": "MUSICAL INSTRUMENT MOVIES", + "Question": "Sinatra as a swinger (What a stretch!): \"Come Blow Your _____\"", + "Answer": "Horn" + }, + { + "Category": "AUSTRALIAN WILDLIFE", + "Question": "This carnivorous marsupial serves as the symbol of the Tasmanian Parks & Wildlife Service", + "Answer": "the Tasmanian devil" + }, + { + "Category": "ALWAYS REMEMBER SEPTEMBER", + "Question": "The names of the 3 ships that left the Canary Islands on Sept. 6, 1492, heading west", + "Answer": "the Nina, the Pinta & the Santa Maria" + }, + { + "Category": "AN ABBREVIATED CATEGORY", + "Question": "To a baseball pitcher: ERA", + "Answer": "earned run average" + }, + { + "Category": "DOWN AT THE OLFACTORY", + "Question": "The perfume Quelques Fleurs, whose name means \"some\" these, supposedly has the fragrances of 313 of them", + "Answer": "flowers" + }, + { + "Category": "MUSICAL INSTRUMENT MOVIES", + "Question": "Holly Hunter played it: \"The _____\"", + "Answer": "Piano" + }, + { + "Category": "AUSTRALIAN WILDLIFE", + "Question": "Australia has the only all-black species of this bird, Cygnus atratus", + "Answer": "a swan" + }, + { + "Category": "ALWAYS REMEMBER SEPTEMBER", + "Question": "On Sept. 13, 1953 Marilyn Monroe made her network TV debut on this stingy comedian's program", + "Answer": "Jack Benny" + }, + { + "Category": "AN ABBREVIATED CATEGORY", + "Question": "On party invitations: BYOB", + "Answer": "bring your own booze" + }, + { + "Category": "NORTH AMERICAN GEOGRAPHY", + "Question": "Washington said a great city would stand where the Cuyahoga met Lake Erie; judge for yourself here", + "Answer": "Cleveland" + }, + { + "Category": "MUSICAL INSTRUMENT MOVIES", + "Question": "A baseball drama: \"Bang the _____ Slowly\"", + "Answer": "Drum" + }, + { + "Category": "AUSTRALIAN WILDLIFE", + "Question": "The quokka, a short-tailed species of this kangaroo relative, is found on Rottnest Island & in W. Australia", + "Answer": "a wallaby" + }, + { + "Category": "ALWAYS REMEMBER SEPTEMBER", + "Question": "French troops under Napoleon entered this capital on September 14, 1812 & found it in flames", + "Answer": "Moscow" + }, + { + "Category": "AN ABBREVIATED CATEGORY", + "Question": "In a Webster's Dictionary entry: imper.", + "Answer": "imperative" + }, + { + "Category": "DOWN AT THE OLFACTORY", + "Question": "You quickly get used to the eggy smell at the Colorado resort called \"Hot\" this type of \"Springs\"", + "Answer": "Sulfur" + }, + { + "Category": "MUSICAL INSTRUMENT MOVIES", + "Question": "A Bergman or Branagh operatic opus: \"The Magic _____\"", + "Answer": "Flute" + }, + { + "Category": "AUSTRALIAN WILDLIFE", + "Question": "The shingleback skink, a type of this, has protruding scales that make it look like a pine cone", + "Answer": "a lizard" + }, + { + "Category": "ALWAYS REMEMBER SEPTEMBER", + "Question": "September 2006 brought news of a \"Unity Deal\" between Hamas & this other 5-letter Palestinian group", + "Answer": "Fatah" + }, + { + "Category": "AN ABBREVIATED CATEGORY", + "Question": "A type of camera: TLR", + "Answer": "twin lens reflex" + }, + { + "Category": "DOWN AT THE OLFACTORY", + "Question": "Introduced in 1890, this product for little backsides advertises its \"clean, classic scent\"", + "Answer": "baby powder" + }, + { + "Category": "NORTH AMERICAN GEOGRAPHY", + "Question": "Long before it empties into the Bay of Fundy, the Saint John River divides Maine from this province", + "Answer": "New Brunswick" + }, + { + "Category": "MUSICAL INSTRUMENT MOVIES", + "Question": "A Capote tale set in the South: \"The Grass _____\"", + "Answer": "Harp" + }, + { + "Category": "AUSTRALIAN WILDLIFE", + "Question": "This manatee relative of the order Sirenia can be found in the coastal waters of North Australia", + "Answer": "a dugong" + }, + { + "Category": "ALWAYS REMEMBER SEPTEMBER", + "Question": "Oxford University's fall term is named for this -mas, not Christmas; it's a saint's Sept. 29 feast day", + "Answer": "Michaelmas" + }, + { + "Category": "AN ABBREVIATED CATEGORY", + "Question": "On a ship: PFD", + "Answer": "personal flotation device" + }, + { + "Category": "DOWN AT THE OLFACTORY", + "Question": "The wood of the Eastern red this tree (actually a juniper) has a distinct aroma familiar from closets", + "Answer": "a cedar" + }, + { + "Category": "ROYALTY", + "Question": "Since 1066, the only British monarch to have 3 children ascend to the British throne", + "Answer": "Henry VIII" + }, + { + "Category": "BOB DYLAN CHRONICLES", + "Question": "\"In the jingle jangle morning I'll come followin' you\"", + "Answer": "\"Mr. Tambourine Man\"" + }, + { + "Category": "THE NORTHERNMOST CAPITAL CITY", + "Question": "Rome, Brussels, Lisbon", + "Answer": "Brussels" + }, + { + "Category": "ALSO A GUN MANUFACTURER", + "Question": "One might run in the Preakness", + "Answer": "a colt" + }, + { + "Category": "YOU BEAST!", + "Question": "The distinctive shoebill is also known as the whale-headed one of these baby deliverers", + "Answer": "a stork" + }, + { + "Category": "THE SHORT FORM", + "Question": "A common adverb, it's also the acronym of a 500,000-member feminist group", + "Answer": "NOW" + }, + { + "Category": "HOMELAND SECURITY", + "Question": "In 1971 Congress told this agency to start protecting visiting heads of state", + "Answer": "the Secret Service" + }, + { + "Category": "BOB DYLAN CHRONICLES", + "Question": "\"Come mothers and fathers throughout the land and don't criticize what you can't understand\"", + "Answer": "\"The Times They Are A-Changin'\"" + }, + { + "Category": "THE NORTHERNMOST CAPITAL CITY", + "Question": "Khartoum, Cairo, Kinshasa", + "Answer": "Cairo" + }, + { + "Category": "ALSO A GUN MANUFACTURER", + "Question": "This 19th century American artist & sculptor was known as \"The Rembrandt of the West\"", + "Answer": "Remington" + }, + { + "Category": "YOU BEAST!", + "Question": "The bulls of these African animals can weigh up to 6 tons", + "Answer": "an elephant" + }, + { + "Category": "THE SHORT FORM", + "Question": "If sending a Valentine to your Guamaninan sweetie, you'll need to know that this is Guam's U.S. postal abbreviation", + "Answer": "GU" + }, + { + "Category": "BOB DYLAN CHRONICLES", + "Question": "\"I got a head full of ideas that are drivin' me insane. It's a shame the way she makes me scrub the floor\"", + "Answer": "\"Maggie's Farm\"" + }, + { + "Category": "THE NORTHERNMOST CAPITAL CITY", + "Question": "Manila, Jakarta, Canberra", + "Answer": "Manila" + }, + { + "Category": "ALSO A GUN MANUFACTURER", + "Question": "He's the guitarist who had a Top 40 hit with \"Rock & Roll Hoochie Koo\"", + "Answer": "Rick Derringer" + }, + { + "Category": "YOU BEAST!", + "Question": "A nide is a brood of these birds (perhaps the ring-necked ones)", + "Answer": "pheasants" + }, + { + "Category": "THE SHORT FORM", + "Question": "In May 1970 many of these buildings were torched on campuses, including Kent State's on May 2", + "Answer": "ROTC" + }, + { + "Category": "HOMELAND SECURITY", + "Question": "Before becoming Homeland Security chief, Michael Chertoff's last job in the Bush admin. was in this Cabinet department", + "Answer": "Justice" + }, + { + "Category": "BOB DYLAN CHRONICLES", + "Question": "\"God say, 'You can do what you want Abe, but the next time you see me comin' you better run'\"", + "Answer": "\"Highway 61 Revisited\"" + }, + { + "Category": "THE NORTHERNMOST CAPITAL CITY", + "Question": "Brasilia, Buenos Aires, Bogota, Belmopan", + "Answer": "Belmopan" + }, + { + "Category": "ALSO A GUN MANUFACTURER", + "Question": "Famous for its cathedral, this English city was the capital of the Anglo-Saxon kingdom of Wessex", + "Answer": "Winchester" + }, + { + "Category": "YOU BEAST!", + "Question": "The Chinese zodiac's 12-year cycle begins & ends with these 2 3-letter animals", + "Answer": "rat & pig" + }, + { + "Category": "THE SHORT FORM", + "Question": "This agreement on world tariffs & trade was signed by 23 countries in Geneva in 1947", + "Answer": "GATT" + }, + { + "Category": "BOB DYLAN CHRONICLES", + "Question": "\"May you build a ladder to the stars and climb on every rung\"", + "Answer": "\"Forever Young\"" + }, + { + "Category": "THE NORTHERNMOST CAPITAL CITY", + "Question": "Hanoi, Phnom Penh, Rangoon, Vientiane", + "Answer": "Hanoi" + }, + { + "Category": "ALSO A GUN MANUFACTURER", + "Question": "Fredric March portrayed this poet in \"The Barrets of Wimpole Street\"", + "Answer": "Browning" + }, + { + "Category": "YOU BEAST!", + "Question": "Russian circuses often feature these animals, a national symobol, trained in the art of juggling with their feet!", + "Answer": "bears" + }, + { + "Category": "THE SHORT FORM", + "Question": "This British organization hands out its equivalent to the Oscars", + "Answer": "BAFTA" + }, + { + "Category": "BRUCE ALMIGHTY", + "Question": "This Freehold-born rocker has had many \"Glory Days\"", + "Answer": "Bruce Springsteen" + }, + { + "Category": "ROUGH POLITICS", + "Question": "On Aug. 5, 1994 he was named independent counsel in the Whitewater affair", + "Answer": "Kenneth Starr" + }, + { + "Category": "ROLL OVER, BEETHOVEN", + "Question": "\"By the time\" this work \"is over, fate has been trampled underfoot by triumphant music\"", + "Answer": "the Fifth Symphony" + }, + { + "Category": "MR. TEA", + "Question": "Around 1908 tea merchant Thomas Sullivan hit upon this innovation that avoids the mess of straining leaves", + "Answer": "a teabag" + }, + { + "Category": "I PITY THE \"FOOL\"", + "Question": "2-word term for a pointless task performed for no good reason", + "Answer": "a fool's errand" + }, + { + "Category": "BRUCE ALMIGHTY", + "Question": "His July 20, 1973 death in Hong Kong at age 32 shocked the world", + "Answer": "Bruce Lee" + }, + { + "Category": "ROUGH POLITICS", + "Question": "In March 1974, 7 ex-Nixon officials were arrested for conspiracy, including this former Chief of Staff", + "Answer": "Haldeman" + }, + { + "Category": "ROLL OVER, BEETHOVEN", + "Question": "\"Betrayed in the hope of getting better\", Beethoven was \"forced to face the prospect of a permanent malady\"--this", + "Answer": "deafness" + }, + { + "Category": "MR. TEA", + "Question": "According to one legend, this spiritual leader born in 563 B.C. was the first to discover tea", + "Answer": "Buddha" + }, + { + "Category": "I PITY THE \"FOOL\"", + "Question": "9-letter word for something designed to be impervious to human incompetence", + "Answer": "foolproof" + }, + { + "Category": "BRUCE ALMIGHTY", + "Question": "Dustin Hoffman starred as this controversial entertainer in a 1974 biopic", + "Answer": "Lenny Bruce" + }, + { + "Category": "ROUGH POLITICS", + "Question": "A N.Y. coroner's inquest came to a finding of murder by this man, Vice President of the United States", + "Answer": "Aaron Burr" + }, + { + "Category": "MR. TEA", + "Question": "One of the first U.S. millionaires, this patriarch of the Astor family traded furs for tea from China", + "Answer": "John Jacob" + }, + { + "Category": "I PITY THE \"FOOL\"", + "Question": "This novel begins in Veracruz when a group of travelers embarks on a trip to Europe", + "Answer": "Ship of Fools" + }, + { + "Category": "BRUCE ALMIGHTY", + "Question": "This actor lived up to the title of his TV show in 1987 when he hit the Top 40 chart with \"Respect Yourself\"", + "Answer": "Bruce Willis" + }, + { + "Category": "ROUGH POLITICS", + "Question": "\"If anyone wants to (follow) me, go ahead. They'd be very bored\", this politician said in 1987; they did, & they weren't", + "Answer": "Gary Hart" + }, + { + "Category": "ROLL OVER, BEETHOVEN", + "Question": "Beethoven's Bagatelle in A Minor for Piano was eventually titled \"Fur\" her", + "Answer": "Elise" + }, + { + "Category": "MR. TEA", + "Question": "The last Dutch governor of New Netherland, he introduced tea to America around 1647", + "Answer": "Peter Stuyvesant" + }, + { + "Category": "I PITY THE \"FOOL\"", + "Question": "Found at fool.com, it's the Gardner brothers' online investment guide", + "Answer": "The Motley Fool" + }, + { + "Category": "BRUCE ALMIGHTY", + "Question": "He directed Jessica Tandy's Oscar-winning performance in \"Driving Miss Daisy\"", + "Answer": "Bruce Beresford" + }, + { + "Category": "ROUGH POLITICS", + "Question": "In October 1974 ths Arkansas congressman's career got kicked in the Fanne (Fox)", + "Answer": "Wilbur Mills" + }, + { + "Category": "ROLL OVER, BEETHOVEN", + "Question": "Symphony Beethoven \"composed to celebrate the memory of a great man\"", + "Answer": "Eroica" + }, + { + "Category": "MR. TEA", + "Question": "Dating from 1662, the English use of tea is attributed to Catherine of Braganza, wife of this \"Restored\" king", + "Answer": "Charles II" + }, + { + "Category": "I PITY THE \"FOOL\"", + "Question": "Senior citizens might object to this proverb popularized by John Lyly in the play \"Mother Bombie\"", + "Answer": "There's no fool like an old fool" + }, + { + "Category": "MAJOR LEAGUE BASEBALL", + "Question": "The team names of these 2 expansion clubs start with the same 3 letters; one might catch the other", + "Answer": "the Seattle Mariners & the Florida Marlins" + }, + { + "Category": "EU, THE EUROPEAN UNION", + "Question": "Each year the EU selects capitals of culture; one of the 2010 cities was this Turkish \"meeting place of cultures\"", + "Answer": "Istanbul" + }, + { + "Category": "ACTORS WHO DIRECT", + "Question": "\"Rocky II\", \"III\" & \"IV\"", + "Answer": "Sylvester Stallone" + }, + { + "Category": "DIALING FOR DIALECTS", + "Question": "Sprechen Sie Plattdeutsch? If you do, you speak the Low variety of this language", + "Answer": "German" + }, + { + "Category": "BREAKING NEWS", + "Question": "Before this hotel mogul's elbow broke through it, a Picasso he owned was worth $139 million; after, $85 million", + "Answer": "Steve Wynn" + }, + { + "Category": "ONE BUCK OR LESS", + "Question": "On December 8, 2008 this national newspaper raised its newsstand price by 25 cents to $1", + "Answer": "USA Today" + }, + { + "Category": "ALSO ON YOUR COMPUTER KEYS", + "Question": "Proverbially, it's \"where the heart is\"", + "Answer": "home" + }, + { + "Category": "EU, THE EUROPEAN UNION", + "Question": "The Schengen Agreement removes any controls at these between most EU neighbors", + "Answer": "national borders" + }, + { + "Category": "ACTORS WHO DIRECT", + "Question": "\"Million Dollar Baby\" & \"Unforgiven\"", + "Answer": "Clint Eastwood" + }, + { + "Category": "DIALING FOR DIALECTS", + "Question": "Dialects of this language include Wu, Yue & Hakka", + "Answer": "Chinese" + }, + { + "Category": "BREAKING NEWS", + "Question": "It was 103 degrees in July 2010 & Con Ed's command center in this N.Y. borough showed 12,963 megawatts consumed at 1 time", + "Answer": "Manhattan" + }, + { + "Category": "ONE BUCK OR LESS", + "Question": "The USPS cost for mailing this, a minimum of 3 1/2 x 5 inches, is 28 cents; wish you were here!", + "Answer": "a postcard" + }, + { + "Category": "ALSO ON YOUR COMPUTER KEYS", + "Question": "A loose-fitting dress hanging straight from the shoulders to below the waist", + "Answer": "a shift" + }, + { + "Category": "EU, THE EUROPEAN UNION", + "Question": "A controversial EU subsidy program is called CAP, short for \"common\" this \"policy\"", + "Answer": "agricultural" + }, + { + "Category": "ACTORS WHO DIRECT", + "Question": "\"The Pledge\" & \"Into the Wild\"", + "Answer": "Sean Penn" + }, + { + "Category": "DIALING FOR DIALECTS", + "Question": "Vedic, dating back at least 4,000 years, is the earliest dialect of this classical language of India", + "Answer": "Sanskrit" + }, + { + "Category": "BREAKING NEWS", + "Question": "Senator Obama attended the 2006 groundbreaking for this man's memorial, 1/2 mile from Lincoln's", + "Answer": "Martin Luther King" + }, + { + "Category": "ONE BUCK OR LESS", + "Question": "In 2002 Eminem signed this rapper to a 7-figure deal, obviously worth a lot more than his name implies", + "Answer": "50 Cent" + }, + { + "Category": "ALSO ON YOUR COMPUTER KEYS", + "Question": "Football position that can be split or tight", + "Answer": "End" + }, + { + "Category": "EU, THE EUROPEAN UNION", + "Question": "Elected every 5 years, it has 736 members from 7 parties", + "Answer": "Parliament" + }, + { + "Category": "ACTORS WHO DIRECT", + "Question": "\"The Great Debaters\"", + "Answer": "Denzel Washington" + }, + { + "Category": "DIALING FOR DIALECTS", + "Question": "While Maltese borrows many words from Italian, it developed from a dialect of this Semitic language", + "Answer": "Arabic" + }, + { + "Category": "BREAKING NEWS", + "Question": "Gambler Charles Wells is believed to have inspired the song \"The Man Who\" did this \"At Monte Carlo\"", + "Answer": "\"Broke The Bank\"" + }, + { + "Category": "ONE BUCK OR LESS", + "Question": "99 cents got me a 4-pack of Ytterlig coasters from this Swedish chain", + "Answer": "IKEA" + }, + { + "Category": "ALSO ON YOUR COMPUTER KEYS", + "Question": "It's an abbreviation for Grand Prix auto racing", + "Answer": "F1" + }, + { + "Category": "EU, THE EUROPEAN UNION", + "Question": "As of 2010, Croatia & Macedonia are candidates but this is the only former Yugoslav republic in the EU", + "Answer": "Slovenia" + }, + { + "Category": "ACTORS WHO DIRECT", + "Question": "\"A Bronx Tale\"", + "Answer": "Robert De Niro" + }, + { + "Category": "DIALING FOR DIALECTS", + "Question": "Aeolic, spoken in ancient times, was a dialect of this", + "Answer": "Ancient Greek" + }, + { + "Category": "BREAKING NEWS", + "Question": "Nearly 10 million YouTubers saw Dave Carroll's clip called this \"friendly skies\" airline \"Breaks Guitars\"", + "Answer": "United Airlines" + }, + { + "Category": "ONE BUCK OR LESS", + "Question": "A 15-ounce V05 Moisture Milks conditioner from this manufacturer averages a buck online", + "Answer": "Alberto" + }, + { + "Category": "ALSO ON YOUR COMPUTER KEYS", + "Question": "An additional section placed within the folds of a newspaper", + "Answer": "an insert" + }, + { + "Category": "NONFICTION", + "Question": "In 2010 this former First Lady published the memoir \"Spoken from the Heart\"", + "Answer": "Laura Bush" + }, + { + "Category": "LEGAL \"E\"s", + "Question": "In English law, it's a title above a gentleman & below a knight; in the U.S., it's usually added to the name of an attorney", + "Answer": "esquire" + }, + { + "Category": "WHAT TO WEAR?", + "Question": "This plain-weave, sheer fabric made with tightly twisted yarn is also used to describe a pie or cake", + "Answer": "chiffon" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "Cape Hatteras is known as this cemetery synonym \"of the Atlantic\"", + "Answer": "a graveyard" + }, + { + "Category": "MAGICAL MOUSE-TERY TOUR", + "Question": "Itchy (the mouse) & Scratchy (the cat) starred in \"Skinless in Seattle\" on a show within this Fox show", + "Answer": "The Simpsons" + }, + { + "Category": "FAMILIAR SAYINGS", + "Question": "Familiarity is said to breed this, from the Latin for \"despise\"", + "Answer": "contempt" + }, + { + "Category": "NONFICTION", + "Question": "This book by Michael Lewis subtitled \"Evolution of a Game\" focused on left tackle prodigy Michael Oher", + "Answer": "The Blind Side" + }, + { + "Category": "LEGAL \"E\"s", + "Question": "One definition of this is entering a private place with the intent of listening secretly to private conversations", + "Answer": "eavesdropping" + }, + { + "Category": "WHAT TO WEAR?", + "Question": "A bit longer than a cocktail dress, one hemmed to end at the shins is this beverage \"length\"", + "Answer": "tea" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "Appropriately enough, this New York metropolis is \"Bison City\"", + "Answer": "Buffalo" + }, + { + "Category": "MAGICAL MOUSE-TERY TOUR", + "Question": "In 1939's cartoon \"The Pointer\", this guy got a new, more pear-shaped body & pupils were added to his eyes", + "Answer": "Mickey" + }, + { + "Category": "FAMILIAR SAYINGS", + "Question": "Even a broken one of these on your wall is right twice a day", + "Answer": "clock" + }, + { + "Category": "NONFICTION", + "Question": "The New Yorker's 1959 review of this said in its brevity & clarity it is \"unlike most such manuals, a book as well as a tool\"", + "Answer": "The Elements of Style" + }, + { + "Category": "LEGAL \"E\"s", + "Question": "This person is appointed by a testator to carry out the directions & requests in his will", + "Answer": "executor" + }, + { + "Category": "WHAT TO WEAR?", + "Question": "Also the name of a rope for leading cattle, this women's backless top has a strap that loops around the neck", + "Answer": "halter" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "This town is known as \"Sin City\" & its downtown is \"Glitter Gulch\"", + "Answer": "Las Vegas" + }, + { + "Category": "MAGICAL MOUSE-TERY TOUR", + "Question": "This 1959 Daniel Keyes novella about Charlie Gordon & a smarter-than-average lab mouse won a Hugo award", + "Answer": "Flowers for Algernon" + }, + { + "Category": "FAMILIAR SAYINGS", + "Question": "If you're one of these capable fellows, you're unfortunately \"master of none\"", + "Answer": "a jack of all trades" + }, + { + "Category": "NONFICTION", + "Question": "Dave Eggers not-so-modestly titled his memoir \"A Heartbreaking Work of\" this", + "Answer": "Staggering Genius" + }, + { + "Category": "LEGAL \"E\"s", + "Question": "This 2-word phrase means the power to take private property for public use; it's ok, as long as there is just compensation", + "Answer": "eminent domain" + }, + { + "Category": "WHAT TO WEAR?", + "Question": "If you're wearing Wellingtons at Wimbledon, you're wearing these", + "Answer": "rainboots" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "It's known as both \"The Steel City\" & \"The Iron City\"", + "Answer": "Pittsburgh" + }, + { + "Category": "MAGICAL MOUSE-TERY TOUR", + "Question": "The samplefest \"The Grey Album\" & the band Gnarls Barkley are 2 projects of Brian Burton, aka this", + "Answer": "Danger Mouse" + }, + { + "Category": "FAMILIAR SAYINGS", + "Question": "A camel is a horse designed by this", + "Answer": "a committee" + }, + { + "Category": "NONFICTION", + "Question": "HBO's miniseries \"John Adams\" was based on this author's Pulitzer Prize-winning biography", + "Answer": "David McCullough" + }, + { + "Category": "LEGAL \"E\"s", + "Question": "This clause in a union contract says that wages will rise or fall depending on a standard such as cost of living", + "Answer": "escalator" + }, + { + "Category": "WHAT TO WEAR?", + "Question": "Throw on an outfit from the \"Marc by\" this designer line", + "Answer": "Marc Jacobs" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "\"The Coyote State\" is an unofficial nickname of this 75,885-square-mile state", + "Answer": "South Dakota" + }, + { + "Category": "MAGICAL MOUSE-TERY TOUR", + "Question": "Maurice LaMarche found his inner Orson Welles to voice this rodent whose simple goal was to take over the world", + "Answer": "the Brain" + }, + { + "Category": "FAMILIAR SAYINGS", + "Question": "It's a poor workman who blames these", + "Answer": "tools" + }, + { + "Category": "19th CENTURY NOVELISTS", + "Question": "William Wilkinson's \"An Account of the Principalities of Wallachia and Moldavia\" inspired this author's most famous novel", + "Answer": "Bram Stoker" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "During the Civil War, this river was called the \"Backbone of the Confederacy\"; it was guarded by several forts", + "Answer": "the Mississippi" + }, + { + "Category": "NYC MUSIC HISTORY", + "Question": "The Who performed this work at the Metropolitan Opera House in Lincoln Center in 1970", + "Answer": "Tommy" + }, + { + "Category": "LUNCH COUNTER LINGO", + "Question": "Bow wow & Coney Island both refer to this food", + "Answer": "a hot dog" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "Selling more than 25 million copies, this WWII diary of a young girl is the bestselling diary in history", + "Answer": "The Diary of Anne Frank" + }, + { + "Category": "NATIONAL SPELLING BEE", + "Question": "This small racing sled has the distinction of being the National Spelling Bee's shortest winning word", + "Answer": "L-U-G-E" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "This \"calm\" lake village in New York State is often called \"America's Switzerland\"", + "Answer": "Lake Placid" + }, + { + "Category": "NYC MUSIC HISTORY", + "Question": "Dvorak's \"New World Symphony\" debuted in this venue in 1893: the Beatles played there in 1964", + "Answer": "Carnegie Hall" + }, + { + "Category": "LUNCH COUNTER LINGO", + "Question": "The name of this state is slang for maple syrup", + "Answer": "Vermont" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "Working with more than 4.5 million donors, this American org. is the world's largest blood provider", + "Answer": "the Red Cross" + }, + { + "Category": "NATIONAL SPELLING BEE", + "Question": "Now that you've got the hang of it, 1932's word was this, like the group that sang \"My Sharona\"", + "Answer": "K-N-A-C-K" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "Maryland is \"the Old Line State\"; this is \"the Old Dominion\"", + "Answer": "Virginia" + }, + { + "Category": "LUNCH COUNTER LINGO", + "Question": "This beverage is Adam's ale", + "Answer": "water" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "With 2,685, Bralanda, Sweden was the site of the largest gathering of these holiday personalities", + "Answer": "Santa Claus" + }, + { + "Category": "NATIONAL SPELLING BEE", + "Question": "Put the bite on this word from 1975, any one of the front cutting teeth", + "Answer": "I-N-C-I-S-O-R" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "Rapid City's nickname, \"Gateway City to the Hills\", refers specifically to these hills", + "Answer": "the Black Hills" + }, + { + "Category": "NYC MUSIC HISTORY", + "Question": "She co-wrote \"The Loco-Motion\" in the Brill Building on Broadway", + "Answer": "Carole King" + }, + { + "Category": "LUNCH COUNTER LINGO", + "Question": "A houseboat is this ice cream & fruit dessert", + "Answer": "a banana split" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "With an average of 80.5 years, this Asian country leads the world in life expectancy", + "Answer": "Japan" + }, + { + "Category": "NATIONAL SPELLING BEE", + "Question": "1970's winning word was this French crescent-shaped roll", + "Answer": "C-R-O-I-S-S-A-N-T" + }, + { + "Category": "U.S. GEOGRAPHIC NICKNAMES", + "Question": "The \"Niagara of the South\", this waterfall near Corbin, Kentucky shares its name with a famous \"gap\"", + "Answer": "Cumberland" + }, + { + "Category": "NYC MUSIC HISTORY", + "Question": "This East Village venue was run by Bill Graham for only 3 years, from 1968 to 1971", + "Answer": "the Fillmore East" + }, + { + "Category": "GUINNESS RECORDS", + "Question": "With a 212-foot wingspan, this jet from Boeing is the world's largest passenger aircraft in service", + "Answer": "the 747" + }, + { + "Category": "NATIONAL SPELLING BEE", + "Question": "A suicide pilot during WWII, it was 1993's winning word", + "Answer": "K-A-M-I-K-A-Z-E" + }, + { + "Category": "SHAKESPEARE", + "Question": "Macduff tells us, \"Not in the legions of horrid hell can come a devil more damn'd in evils to top\" this man", + "Answer": "the Macbeth" + }, + { + "Category": "OSCAR-WINNING ROLES", + "Question": "1952: Marshal Will Kane", + "Answer": "Gary Cooper" + }, + { + "Category": "NATIVE AMERICANS", + "Question": "In August 1934 this president was made an honorary member of the Blackfoot tribe & given the name \"Lone Chief\"", + "Answer": "FDR" + }, + { + "Category": "THE OLD COLLEGE TRY", + "Question": "Basketball superstar Magic Johnson played his college ball at this university in East Lansing", + "Answer": "Michigan State" + }, + { + "Category": "PAINTERS", + "Question": "His \"Potato Eaters\" was inspired by the time he spent as a missionary in the coal-mining region of Belgium in his mid-20s", + "Answer": "Van Gogh" + }, + { + "Category": "\"ANT\" INFESTATION", + "Question": "It's the part of the military that traditionally fights on foot", + "Answer": "infantry" + }, + { + "Category": "SHAKESPEARE", + "Question": "Richard III says, \"How sweet a thing it is to wear\" one & Henry IV says, \"Uneasy lies the head that wears\" one", + "Answer": "a crown" + }, + { + "Category": "OSCAR-WINNING ROLES", + "Question": "1951: Boat captain Charlie Allnut", + "Answer": "Bogart" + }, + { + "Category": "NATIVE AMERICANS", + "Question": "He had 2 adopted sons, One Bull & White Bull", + "Answer": "Sitting Bull" + }, + { + "Category": "THE OLD COLLEGE TRY", + "Question": "Once known as the Antelopes & the Bugeaters, this university's sports teams are now known as the Cornhuskers", + "Answer": "the University of Nebraska" + }, + { + "Category": "PAINTERS", + "Question": "Dr. Tulp was so pleased with this artist's painting of his \"Anatomy Lesson\" that it hung in his school of surgery", + "Answer": "Rembrandt" + }, + { + "Category": "\"ANT\" INFESTATION", + "Question": "B or D, as opposed to A or O", + "Answer": "a consonant" + }, + { + "Category": "SHAKESPEARE", + "Question": "Laertes' first line in this play is \"Dread my lord, your leave and favour to return to France\"", + "Answer": "Hamlet" + }, + { + "Category": "OSCAR-WINNING ROLES", + "Question": "1945: Mildred Pierce", + "Answer": "Joan Crawford" + }, + { + "Category": "NATIVE AMERICANS", + "Question": "Major subgroups of this tribe of the American Southwest include Kiowa, Chiricahua & Mescalero", + "Answer": "the Apache" + }, + { + "Category": "THE OLD COLLEGE TRY", + "Question": "Rhode Island's only Ivy League school is this institution", + "Answer": "Brown" + }, + { + "Category": "PAINTERS", + "Question": "She called her New Mexico home, where she spent the last half century of her life, Ghost Ranch", + "Answer": "Georgia O'Keeffe" + }, + { + "Category": "\"ANT\" INFESTATION", + "Question": "Unyielding in your opinion that the singer of \"Goody Two Shoes\" is the greatest singer ever", + "Answer": "adamant" + }, + { + "Category": "SHAKESPEARE", + "Question": "In different plays, it's the name shared by men linked with Helen of Troy & with Juliet", + "Answer": "Paris" + }, + { + "Category": "OSCAR-WINNING ROLES", + "Question": "1933: Henry VIII", + "Answer": "Charles Laughton" + }, + { + "Category": "NATIVE AMERICANS", + "Question": "This Florida tribe lived in dwellings called chickees that had raised floors & open sides allowing the air to circulate", + "Answer": "the Seminoles" + }, + { + "Category": "THE OLD COLLEGE TRY", + "Question": "College Station is the home of this oldest public university in Texas", + "Answer": "Texas A&M" + }, + { + "Category": "PAINTERS", + "Question": "His first major mural was painted at the Univ. of Mexico's Nat'l Preparatory School in the 1920s", + "Answer": "Rivera" + }, + { + "Category": "\"ANT\" INFESTATION", + "Question": "From the Latin for \"delight\", this is someone who takes delight in dabbling in the arts", + "Answer": "dilettante" + }, + { + "Category": "SHAKESPEARE", + "Question": "It's the play in which Thaliard says, \"So, this is Tyre, and this the court\"", + "Answer": "Pericles, Prince of Tyre" + }, + { + "Category": "OSCAR-WINNING ROLES", + "Question": "1942: Kay Miniver", + "Answer": "Greer Garson" + }, + { + "Category": "NATIVE AMERICANS", + "Question": "Gov. Bradford said that this Indian who taught the Pilgrims how to plant corn was an \"instrument sent of God\"", + "Answer": "Squanto" + }, + { + "Category": "THE OLD COLLEGE TRY", + "Question": "New Haven has Albertus Magnus; Grand Rapids, Michigan has a school named for this other 13th c. theologian", + "Answer": "St. Thomas Acquinas" + }, + { + "Category": "PAINTERS", + "Question": "Last name of Flemish brothers Jan & Hubert, who both are credited with painting portions of the \"Ghent Altarpiece\"", + "Answer": "Van Eyck" + }, + { + "Category": "\"ANT\" INFESTATION", + "Question": "The Huguenots received religious freedom from the 1598 edict of this city", + "Answer": "Nantes" + }, + { + "Category": "EXPLORATION", + "Question": "He wrote in his diary, \"The loss of pony transport in March 1911 obliged me to start later than I had intended\"", + "Answer": "Robert Falcon Scott" + }, + { + "Category": "\"TOMORROW\"", + "Question": "Space Mountain & Star Tours are among its attractions", + "Answer": "Tomorrowland" + }, + { + "Category": "SATURDAY MORNING CARTOONS", + "Question": "This title dog's real first name is Scoobert", + "Answer": "Scooby-Doo" + }, + { + "Category": "SATURDAY AFTERNOON AT THE MOVIES", + "Question": "George Lucas is planning a 3-part prequel to this 1977 film", + "Answer": "Star Wars" + }, + { + "Category": "THE SATURDAY EVENING POST", + "Question": "Pre-\"Peanuts\", he sold some of his cartoons to the Saturday Evening Post", + "Answer": "Charles Schulz" + }, + { + "Category": "THE SEVENTH-DAY ADVENTISTS", + "Question": "Members observe Saturday Sabbath because of Genesis 2:3, which says God did this on the seventh day", + "Answer": "He rested" + }, + { + "Category": "\"TOMORROW\"", + "Question": "In 1960 the Shirelles asked this musical question", + "Answer": "Will you still love me tomorrow?" + }, + { + "Category": "SATURDAY MORNING CARTOONS", + "Question": "Mush Mouth & Dumb Donald were some of the Cosby kids on the show whose title featured this one", + "Answer": "Fat Albert" + }, + { + "Category": "SATURDAY AFTERNOON AT THE MOVIES", + "Question": "He played Cameron Poe, an almost-paroled convict thwarting an escape attempt in \"Con Air\"", + "Answer": "Nicolas Cage" + }, + { + "Category": "THE SATURDAY EVENING POST", + "Question": "In the March 17, 1956 issue, Gary Cooper said, \"In Westerns you were permitted to kiss\" this \"but never your girl\"", + "Answer": "your horse" + }, + { + "Category": "THE SEVENTH-DAY ADVENTISTS", + "Question": "Like Jews, many Adventists follow Leviticus 11:7 in abstaining from this meat", + "Answer": "pork" + }, + { + "Category": "\"TOMORROW\"", + "Question": "In the novel \"Gone with the Wind\", it follows \"I'll think of some way to get him back\"", + "Answer": "Tomorrow is another day" + }, + { + "Category": "SATURDAY MORNING CARTOONS", + "Question": "\"The Immature Radioactive Samurai Slugs\" on \"Tiny Toons\" were a parody of this cartoon group", + "Answer": "the Teenage Mutant Ninja Turtles" + }, + { + "Category": "SATURDAY AFTERNOON AT THE MOVIES", + "Question": "In the same film, Mike Myers played Dr. Evil & this international man of mystery, baby", + "Answer": "Austin Powers" + }, + { + "Category": "THE SATURDAY EVENING POST", + "Question": "Born in NYC in 1894, he painted 317 covers for the Post over 47 years", + "Answer": "Norman Rockwell" + }, + { + "Category": "THE SEVENTH-DAY ADVENTISTS", + "Question": "The church funds worldwide good works by this contribution of 10% of members' incomes", + "Answer": "a tithe" + }, + { + "Category": "\"TOMORROW\"", + "Question": "Annie told us you could \"bet your bottom dollar that\" this would happen", + "Answer": "the sun will come out tomorrow" + }, + { + "Category": "SATURDAY MORNING CARTOONS", + "Question": "In 1985 an animated version of this Soleil Moon Frye sitcom character made the scene", + "Answer": "Punky Brewster" + }, + { + "Category": "THE SATURDAY EVENING POST", + "Question": "The Post's history goes back to The Pennsylvania Gazette founded by this man", + "Answer": "Benjamin Franklin" + }, + { + "Category": "SATURDAY NIGHT ON THE TOWN", + "Question": "Beer lovers head for the beer halls of this Bavarian city, the birthplace of Oktoberfest", + "Answer": "Munich" + }, + { + "Category": "\"TOMORROW\"", + "Question": "This advice on procrastination is credited to a 1749 letter written by Lord Chesterfield to his son", + "Answer": "never put off till tomorrow what you can do today" + }, + { + "Category": "SATURDAY MORNING CARTOONS", + "Question": "This ape was the white elephant that pet store owner Mr. Peebles couldn't get rid of", + "Answer": "Magilla Gorilla" + }, + { + "Category": "SATURDAY AFTERNOON AT THE MOVIES", + "Question": "This sailor hero's adventures include \"The Golden Voyage\" & \"The Eye of the Tiger\"", + "Answer": "Sinbad" + }, + { + "Category": "THE SATURDAY EVENING POST", + "Question": "The 6 Earl Derr Biggers novels about this Chinese-American detective were first serialized in the Post", + "Answer": "Charlie Chan" + }, + { + "Category": "SATURDAY NIGHT ON THE TOWN", + "Question": "Guacara Taina in this capital of the Dominican Republic may be the world's only disco-in-a-cave", + "Answer": "Santo Domingo" + }, + { + "Category": "THE SEVENTH-DAY ADVENTISTS", + "Question": "This group named for a king of Israel split from the church in 1934, a \"branch\" of it became notorious in 1993", + "Answer": "the Davidians" + }, + { + "Category": "PHYSICS 101", + "Question": "The area of physics divided into statics & dynamics or the guys replacing your head gasket", + "Answer": "mechanics" + }, + { + "Category": "THE 19th CENTURY", + "Question": "Opened in 1869, part of it follows the route of a canal dug 12 centuries earlier", + "Answer": "the Suez Canal" + }, + { + "Category": "CITY FOLK", + "Question": "Hamburgers", + "Answer": "residents of Hamburg" + }, + { + "Category": "THEY'RE NOT IN KANSAS ANY MORE", + "Question": "This Kansan made her last known take-off from New Guinea; if you find out where she is, let us know", + "Answer": "Amelia Earhart" + }, + { + "Category": "AIN'T THAT \"GRAND\"", + "Question": "This name for a railroad terminal at Park & 42nd is a synonym for frenzied activity", + "Answer": "Grand Central Station" + }, + { + "Category": "PHYSICS 101", + "Question": "Term for one end of a bar magnet, or for one of the discoverers of radium", + "Answer": "a pole" + }, + { + "Category": "THE 19th CENTURY", + "Question": "One of the 3 large empires of 19th century Eastern Europe was this \"Sick Man\"", + "Answer": "the Ottoman Empire" + }, + { + "Category": "CALIFORNIA HERE I COME FILMS", + "Question": "In this 1981 Burt Reynolds film, the first race car to reach California won", + "Answer": "The Cannonball Run" + }, + { + "Category": "CITY FOLK", + "Question": "Palermitans", + "Answer": "Palermo residents" + }, + { + "Category": "AIN'T THAT \"GRAND\"", + "Question": "The Republicans had been around less than 30 years when they were dubbed this", + "Answer": "the Grand Old Party" + }, + { + "Category": "PHYSICS 101", + "Question": "By definition, liquids & gases do this under stress, solids don't", + "Answer": "they flow" + }, + { + "Category": "THE 19th CENTURY", + "Question": "In 1880 this Lincoln county sheriff captured Billy the Kid", + "Answer": "Pat Garrett" + }, + { + "Category": "CITY FOLK", + "Question": "Madrilenos", + "Answer": "residents of Madrid" + }, + { + "Category": "THEY'RE NOT IN KANSAS ANY MORE", + "Question": "He's the most famous man we know from Russell, Kansas", + "Answer": "Bob Dole" + }, + { + "Category": "AIN'T THAT \"GRAND\"", + "Question": "Term for an extended visit to Europe, once an essential part of a British gent's upbringing", + "Answer": "the Grand Tour" + }, + { + "Category": "PHYSICS 101", + "Question": "In the 19th C. Rudolf Clausius coined this word for measuring increasing disorder in a system", + "Answer": "entropy" + }, + { + "Category": "THE 19th CENTURY", + "Question": "On sale May 1, 1840, the first postage stamp with adhesive on the back had this person on the front", + "Answer": "Queen Victoria" + }, + { + "Category": "CALIFORNIA HERE I COME FILMS", + "Question": "In this 1995 film, Whoopi, Mary-Louise & Drew head to San Diego", + "Answer": "Boys on the Side" + }, + { + "Category": "CITY FOLK", + "Question": "Damascenes", + "Answer": "Damascus residents" + }, + { + "Category": "THEY'RE NOT IN KANSAS ANY MORE", + "Question": "This Wild West town might still be wild if native son Dennis Hopper still lived there", + "Answer": "Dodge City" + }, + { + "Category": "AIN'T THAT \"GRAND\"", + "Question": "A 1085-mile waterway in China & a 2.5 mile waterway in Venice are both called this", + "Answer": "the Grand Canal" + }, + { + "Category": "PHYSICS 101", + "Question": "Silicon is a semiconducting material; this is the term for nonconductors like plastics", + "Answer": "an insulator" + }, + { + "Category": "THE 19th CENTURY", + "Question": "1853 purchase that brought the contiguous U.S. about up to its present area", + "Answer": "the Gadsden Purchase" + }, + { + "Category": "CALIFORNIA HERE I COME FILMS", + "Question": "In \"Calendar Girl\" Jason Priestley heads to L.A. to meet this movie star", + "Answer": "Marilyn Monroe" + }, + { + "Category": "CITY FOLK", + "Question": "Varsovians", + "Answer": "residents of Warsaw" + }, + { + "Category": "THEY'RE NOT IN KANSAS ANY MORE", + "Question": "This author of the \"Guys & Dolls\" stories really was from Manhattan--Manhattan, Kansas, that is", + "Answer": "Damon Runyon" + }, + { + "Category": "AIN'T THAT \"GRAND\"", + "Question": "At 15 in 1991, Judit Polgar became the youngest person & one of the few women to attain this rank", + "Answer": "a grandmaster" + }, + { + "Category": "FINANCE HISTORY", + "Question": "In the 19th c., selling stock you didn't yet own, hoping it would fall, was called selling this animal's skin", + "Answer": "a bear" + }, + { + "Category": "PLAYS & PLAYWRIGHTS", + "Question": "As a youth, this \"Iceman Cometh\" dramatist prospected for gold in Honduras", + "Answer": "Eugene O'Neill" + }, + { + "Category": "BRAND NAMES", + "Question": "In 1986 this company introduced its Dockers line of men's casual wear", + "Answer": "Levi's" + }, + { + "Category": "POLITICS & SHOW BIZ", + "Question": "Mary Bono won election to Congress over Ralph Waite, John-Boy's dad on this show", + "Answer": "The Waltons" + }, + { + "Category": "NATIONS OF AFRICA", + "Question": "Add 2 letters to Niger to get the name of this country just south of it", + "Answer": "Nigeria" + }, + { + "Category": "HE WAS IN THAT?", + "Question": "He appeared fleet-ingly in \"Sailor Beware\" with Martin & Lewis before \"East of Eden\" made him a star", + "Answer": "James Dean" + }, + { + "Category": "ANAGRAMMED CABINET DEPARTMENTS", + "Question": "Taste", + "Answer": "State" + }, + { + "Category": "PLAYS & PLAYWRIGHTS", + "Question": "In a Chekhov play, Mme. Ranevsky is the owner of this title area of land", + "Answer": "\"The Cherry Orchard\"" + }, + { + "Category": "BRAND NAMES", + "Question": "It's \"The Quicker Picker Upper\"", + "Answer": "Bounty" + }, + { + "Category": "POLITICS & SHOW BIZ", + "Question": "Film mogul Jack Warner supposedly said, \"No. Jimmy Stewart for president.\" this man \"for best friend\"", + "Answer": "Ronald Reagan" + }, + { + "Category": "NATIONS OF AFRICA", + "Question": "In a song title, this country whose capital is Nairobi might come before \"Feel the Love Tonight\"", + "Answer": "Kenya" + }, + { + "Category": "HE WAS IN THAT?", + "Question": "Before playing Cliff on \"Cheers\", John Ratzenberger appeared as Major Derlin in this second \"Star Wars\" film", + "Answer": "The Empire Strikes Back" + }, + { + "Category": "ANAGRAMMED CABINET DEPARTMENTS", + "Question": "Send fee", + "Answer": "Defense" + }, + { + "Category": "PLAYS & PLAYWRIGHTS", + "Question": "In 1941 her \"Watch on the Rhine\" was named best American play by the New York Drama Critics' Circle", + "Answer": "Lillian Hellman" + }, + { + "Category": "BRAND NAMES", + "Question": "Elsie the Cow's \"husband\", his face is plastered on glue bottles", + "Answer": "Elmer" + }, + { + "Category": "POLITICS & SHOW BIZ", + "Question": "She's played Queen Elizabeth I, but decided to join the House of Commons:", + "Answer": "Glenda Jackson" + }, + { + "Category": "NATIONS OF AFRICA", + "Question": "In a song title, this country whose capital is Accra might come before \"Fly Now\"", + "Answer": "Ghana" + }, + { + "Category": "HE WAS IN THAT?", + "Question": "Kevin Spacey played a sleazy businessman in this Melanie Griffith film about an ambitious secretary", + "Answer": "Working Girl" + }, + { + "Category": "ANAGRAMMED CABINET DEPARTMENTS", + "Question": "Tire iron", + "Answer": "Interior" + }, + { + "Category": "PLAYS & PLAYWRIGHTS", + "Question": "In 1991 Nigel Hawthorne won a Tony for his role as this author in William Nicholson's play \"Shadowlands\"", + "Answer": "C.S. Lewis" + }, + { + "Category": "BRAND NAMES", + "Question": "Its \"Extra Dry\" was the first aerosol antiperspirant in the U.S.", + "Answer": "Arrid" + }, + { + "Category": "POLITICS & SHOW BIZ", + "Question": "Artists like Gladys Knight have recorded the songs of this senior senator from Utah", + "Answer": "Orrin Hatch" + }, + { + "Category": "NATIONS OF AFRICA", + "Question": "(Hi, I'm NBA All-Star Dikembe Mutombo) One of the many languages I speak is this official one of my birthplace, Congo", + "Answer": "French" + }, + { + "Category": "HE WAS IN THAT?", + "Question": "Mr. C on \"Happy Days\", he played the man Natalie Wood's parents want her to marry in \"Love with the Proper Stranger\"", + "Answer": "Tom Bosley" + }, + { + "Category": "ANAGRAMMED CABINET DEPARTMENTS", + "Question": "Idea count", + "Answer": "Education" + }, + { + "Category": "PLAYS & PLAYWRIGHTS", + "Question": "The search for the philosopher's stone is the subject of Ben Jonson's play about this title profession", + "Answer": "\"The Alchemist\"" + }, + { + "Category": "BRAND NAMES", + "Question": "This sleek swimsuit brand got its start in Australia in 1928", + "Answer": "Speedo" + }, + { + "Category": "POLITICS & SHOW BIZ", + "Question": "Actress & Congresswoman Helen Gahagan took this last name when she wed Oscar-winning actor Melvyn", + "Answer": "Douglas" + }, + { + "Category": "NATIONS OF AFRICA", + "Question": "Milton Obote, no bargain either, ran this country before & after Idi Amin", + "Answer": "Uganda" + }, + { + "Category": "HE WAS IN THAT?", + "Question": "Mike Farrell of \"Providence\" can be seen in the hotel in this 1967 Dustin Hoffman classic", + "Answer": "The Graduate" + }, + { + "Category": "ANAGRAMMED CABINET DEPARTMENTS", + "Question": "To trap on trains", + "Answer": "Transportation" + }, + { + "Category": "FLEMISH & DUTCH MASTERS", + "Question": "His \"Anatomy Lesson of Dr. Tulp\" featured the doctor, his colleagues & a cadaver", + "Answer": "Rembrandt" + }, + { + "Category": "MILITARY MATTERS", + "Question": "This nickname of the World War II U.S. Air Force fighter numbered the P-51 comes from the Spanish for \"stray animal\"", + "Answer": "Mustang" + }, + { + "Category": "EVERYTHING'S \"GOLDEN\", BABY", + "Question": "A bright, tasty, yellow variety of apple; it's as yummy as it sounds", + "Answer": "Golden delicious" + }, + { + "Category": "HOME", + "Question": "In new houses, when all your lights go out, you flip the circuit breaker back; in old houses, you change these", + "Answer": "Fuses" + }, + { + "Category": "CHOPIN", + "Question": "Every piece Chopin composed was for or included this instrument", + "Answer": "Piano" + }, + { + "Category": "NETWORK", + "Question": "\"The Puzzle Place\", \"This Old House\", \"Frontline\"", + "Answer": "PBS" + }, + { + "Category": "FLEMISH & DUTCH MASTERS", + "Question": "Artist whose masterpiece is seen here: (\"Night Cafe\")", + "Answer": "Vincent Van Gogh" + }, + { + "Category": "MILITARY MATTERS", + "Question": "One-third of the Americans who made up the Abraham Lincoln Battalion were killed during this country's civil war", + "Answer": "Spain" + }, + { + "Category": "EVERYTHING'S \"GOLDEN\", BABY", + "Question": "It's the popular breed seen here: (dog)", + "Answer": "Golden retriever" + }, + { + "Category": "HOME", + "Question": "On Oct. 19, 1999 this home & life improvement guru made a bundle after her IPO hit Wall Street", + "Answer": "Martha Stewart" + }, + { + "Category": "CHOPIN", + "Question": "After some miserable months in Vienna, Chopin arrived in this city, another musical mecca, in September 1831", + "Answer": "Paris" + }, + { + "Category": "NETWORK", + "Question": "\"Real World\", \"House of Style\", \"FANatic\"", + "Answer": "MTV" + }, + { + "Category": "FLEMISH & DUTCH MASTERS", + "Question": "Because of his style of painting females, this master's name gave us an adjective for plump women", + "Answer": "Peter Paul Rubens" + }, + { + "Category": "MILITARY MATTERS", + "Question": "There are Chinese & Russian versions of this rifle that's also known as Kalashnikov Model 1947", + "Answer": "AK-47" + }, + { + "Category": "EVERYTHING'S \"GOLDEN\", BABY", + "Question": "While Moses was on Mount Sinai, the Israelites worshipped this", + "Answer": "Golden Calf" + }, + { + "Category": "HOME", + "Question": "It's what andirons are built to hold", + "Answer": "Logs/wood in your fireplace" + }, + { + "Category": "CHOPIN", + "Question": "After meeting this author, Chopin wondered, \"Is she really a woman?\"", + "Answer": "George Sand" + }, + { + "Category": "NETWORK", + "Question": "\"7 Days\", \"WWF Smackdown\", \"Moesha\"", + "Answer": "UPN" + }, + { + "Category": "FLEMISH & DUTCH MASTERS", + "Question": "In 1632 this court painter to England's Charles I & Queen Henrietta Maria was knighted", + "Answer": "Anthony van Dyck" + }, + { + "Category": "MILITARY MATTERS", + "Question": "This kind of \"force\" is a temporary grouping of units to carry out a specific mission", + "Answer": "Task force" + }, + { + "Category": "EVERYTHING'S \"GOLDEN\", BABY", + "Question": "This Mongol army overran Eastern Europe in the 13th century", + "Answer": "The Golden Horde" + }, + { + "Category": "HOME", + "Question": "There are 2 types of these safety devices, photoelectric & ionization", + "Answer": "Smoke detectors" + }, + { + "Category": "CHOPIN", + "Question": "Chopin was born in Poland, & his first printed work at age 7 was one of these appropriately named pieces", + "Answer": "Polonaise" + }, + { + "Category": "NETWORK", + "Question": "\"Emergency Vets\", \"Wild Rescues\", \"Breed All About It\"", + "Answer": "Animal Planet" + }, + { + "Category": "FLEMISH & DUTCH MASTERS", + "Question": "This 20th century painter known for his neoplastic style helped establish a magazine called \"De Stijl\"", + "Answer": "Piet Mondrian" + }, + { + "Category": "MILITARY MATTERS", + "Question": "This German \"operation\" to invade the Soviet Union took its name from a crusading Holy Roman Emperor", + "Answer": "Operation Barbarossa" + }, + { + "Category": "EVERYTHING'S \"GOLDEN\", BABY", + "Question": "Lucius Apuleius wrote it", + "Answer": "\"The Golden Ass\"" + }, + { + "Category": "HOME", + "Question": "A heriz is a Persian one", + "Answer": "Carpet" + }, + { + "Category": "CHOPIN", + "Question": "Chopin disliked the insincerity of this Hungarian pianist-composer 1 year his junior", + "Answer": "Franz Liszt" + }, + { + "Category": "NETWORK", + "Question": "\"Pros & Cons\", \"Crime Stories\", \"DC Insider\"", + "Answer": "Court TV" + }, + { + "Category": "THE BOOK TRADE", + "Question": "According to USA Today, they're the 2 nonconsecutive months that see the highest cookbook sales", + "Answer": "May & December" + }, + { + "Category": "THE ANIMALS", + "Question": "Resembling a small lobster, it's Louisiana's state crustacean", + "Answer": "crawfish/crayfish" + }, + { + "Category": "PETER, PAUL & MARY", + "Question": "Before penning \"Beast\" & \"The Deep\", he was a speechwriter for LBJ", + "Answer": "Peter Benchley" + }, + { + "Category": "THE ROLLING STONES", + "Question": "I can't get none, but with this song the Rolling Stones had their first U.S. No. 1 hit", + "Answer": "\"Satisfaction\"" + }, + { + "Category": "EARTH, WIND & FIRE", + "Question": "On the Beaufort scale, winds range from 0 for calm to 12 to 17 for these powerful storms", + "Answer": "hurricanes" + }, + { + "Category": "THE COMMODORES", + "Question": "The first American naval victory in the Revolution came under Commodore Esek Hopkins in these islands off Fla.", + "Answer": "Bahamas" + }, + { + "Category": "THE \"B.G.\"s", + "Question": "A small piano about 5 feet long", + "Answer": "baby grand" + }, + { + "Category": "THE ANIMALS", + "Question": "Thought to resemble lions associated with Buddha, this Chinese dog breed was protected by royal decree", + "Answer": "Pekingese" + }, + { + "Category": "PETER, PAUL & MARY", + "Question": "The author of a \"monstrous\" 1818 classic, she later wrote the autobiographical \"Lodore\" in 1835", + "Answer": "Mary Shelley" + }, + { + "Category": "THE ROLLING STONES", + "Question": "The Stones played a cleaned-up version of \"Let's Spend The Night Together\" on this U.S. TV variety show in 1967", + "Answer": "The Ed Sullivan Show" + }, + { + "Category": "EARTH, WIND & FIRE", + "Question": "In the '90s home fires caused by these nearly doubled, with almost half of them starting in the bedroom", + "Answer": "candles" + }, + { + "Category": "THE COMMODORES", + "Question": "\"The Commodore\" is one of the tales of this C.S. Forester hero", + "Answer": "Horatio Hornblower" + }, + { + "Category": "THE \"B.G.\"s", + "Question": "(Sofia of the Clue Crew standing in front of a chalkboard) It's a visual method for comparing numbers", + "Answer": "bar graph" + }, + { + "Category": "THE ANIMALS", + "Question": "Tuna are members of Scombridae, known commonly as this \"holy\" family of fishes", + "Answer": "mackerels" + }, + { + "Category": "PETER, PAUL & MARY", + "Question": "Bestsellers from this master of horror include \"Koko\" & \"Ghost Story\"", + "Answer": "Peter Straub" + }, + { + "Category": "THE ROLLING STONES", + "Question": "It was the number of the Rolling Stones' 1966 \"Nervous Breakdown\"", + "Answer": "19th" + }, + { + "Category": "EARTH, WIND & FIRE", + "Question": "A devastating forest fire swept through Peshtigo, Wisconsin on the very same day in 1871 as this city's \"Great\" fire", + "Answer": "Chicago" + }, + { + "Category": "THE COMMODORES", + "Question": "Commodore Isaac Hull commanded this ship to victory over Britain's Guerriere in the War of 1812", + "Answer": "U.S.S. Constitution" + }, + { + "Category": "THE \"B.G.\"s", + "Question": "2-word term for large animals hunted for sport", + "Answer": "big game" + }, + { + "Category": "THE ANIMALS", + "Question": "Extinct before the dinosaurs ever walked, trilobites are key signature creatures of this \"old animal\" era", + "Answer": "Paleozoic" + }, + { + "Category": "PETER, PAUL & MARY", + "Question": "This American silversmith & patriot was noted for his courier service", + "Answer": "Paul Revere" + }, + { + "Category": "THE ROLLING STONES", + "Question": "Footage from a deadly 1969 Stones concert at this speedway was released in 1970 as the documentary \"Gimme Shelter\"", + "Answer": "Altamont" + }, + { + "Category": "EARTH, WIND & FIRE", + "Question": "Oh, \"Boy\"! This warming of the Pacific that causes unusual weather patterns occurs about every 2 to 7 years", + "Answer": "El Nino" + }, + { + "Category": "THE COMMODORES", + "Question": "Negotiated by Matthew Perry, 1854's Treaty of Kanagawa opened up this country to commercial trade with the U.S.", + "Answer": "Japan" + }, + { + "Category": "THE \"B.G.\"s", + "Question": "Swingin' virtuoso heard here", + "Answer": "Benny Goodman" + }, + { + "Category": "THE ANIMALS", + "Question": "(Sarah of the Clue Crew at Zoo Atlanta) There are 3 types of gorilla: mountain & the eastern & western type of these lesser-altitude gorillas", + "Answer": "lowland gorillas" + }, + { + "Category": "PETER, PAUL & MARY", + "Question": "His world travels helped him write \"The Great Railway Bazaar\", \"The Mosquito Coast\" & \"Riding the Iron Rooster\"", + "Answer": "Paul Theroux" + }, + { + "Category": "THE ROLLING STONES", + "Question": "The Rolling Stones took their name from a song by this legendary blues musician", + "Answer": "Muddy Waters" + }, + { + "Category": "EARTH, WIND & FIRE", + "Question": "Scientists believe the continents were once part of a single land mass called this, from the Greek for \"all earth\"", + "Answer": "Pangaea" + }, + { + "Category": "THE COMMODORES", + "Question": "He's the naval hero & commodore famous for his declaration \"Our country, right or wrong!\"", + "Answer": "Stephen Decatur" + }, + { + "Category": "THE \"B.G.\"s", + "Question": "A naval force made up of an aircraft carrier & support vessels", + "Answer": "battle group" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "This Mark Twain character's father \"Pap\" briefly held him prisoner in a cabin on the Illinois side of the Mississippi", + "Answer": "Huckleberry Finn" + }, + { + "Category": "EDUCATION JARGON", + "Question": "65 out of 100 students did the same as or worse than you if your grade is in the 65th of these", + "Answer": "percentile" + }, + { + "Category": "STATE GOVERNMENT", + "Question": "Maine's only publicly elected executive officer; if he dies the state senate president succeeds him", + "Answer": "governor" + }, + { + "Category": "HERE'S LUCY", + "Question": "Before playing Xena, she co-hosted the travel show \"Air New Zealand Holiday\"", + "Answer": "Lucy Lawless" + }, + { + "Category": "CAPITAL PUNISHMENT", + "Question": "Site of a 1977 6.5 earthquake: Bucharest", + "Answer": "Romania" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Carolyn Keene's fictional teenage detective who stars in a sitcom set in Cleveland", + "Answer": "Nancy Drew Carey" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "In this Hemingway WWI novel, ambulance driver Frederic Henry falls in love with British nurse Catherine Barkley", + "Answer": "\"A Farewell to Arms\"" + }, + { + "Category": "EDUCATION JARGON", + "Question": "IDEA is the Individuals with these Education Act, formerly the Education For All Handicapped Children Act", + "Answer": "Disabilities" + }, + { + "Category": "STATE GOVERNMENT", + "Question": "In the Mississippi House of Representatives, this official calls members to order & signs acts", + "Answer": "speaker of the house" + }, + { + "Category": "HERE'S LUCY", + "Question": "In 2000 she became the first Asian-American woman to host \"Saturday Night Live\"", + "Answer": "Lucy Liu" + }, + { + "Category": "CAPITAL PUNISHMENT", + "Question": "Co-capitals: La Paz & Sucre", + "Answer": "Bolivia" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Otis Redding's No. 1 hit that's performed by a Scottish band on S-a-t-u-r-d-a-y Night", + "Answer": "Sitting on the Dock of the Bay City Rollers" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "In this Steinbeck novel, a few buddies get drunk & make a shambles of the Western Biological Lab in Monterey", + "Answer": "\"Cannery Row\"" + }, + { + "Category": "EDUCATION JARGON", + "Question": "It's the rhyming term for the technique of teaching with only a blackboard to help you", + "Answer": "chalk talk/chalk and talk" + }, + { + "Category": "STATE GOVERNMENT", + "Question": "In this post, Jim Ryan is Illinois' chief law enforcement & consumer protection official", + "Answer": "attorney general" + }, + { + "Category": "HERE'S LUCY", + "Question": "Lucy Hobbs Taylor must have aced her orals because in 1866 she became the first woman to receive a degree in this", + "Answer": "dentistry" + }, + { + "Category": "CAPITAL PUNISHMENT", + "Question": "In southern Asia: Dhaka", + "Answer": "Bangladesh" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Novel in which Rhett Butler tells Toad, Rat & Mole, \"My dear, I don't give a damn\"", + "Answer": "Gone With the Wind in the Willows" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "It's the nickname of William Lonigan, the 15-year-old hero of a 1930s trilogy written by James T. Farrell", + "Answer": "\"Studs\"" + }, + { + "Category": "EDUCATION JARGON", + "Question": "From the Latin for \"to heal\", it's the type of education that brings deficient students up to standard levels", + "Answer": "remedial" + }, + { + "Category": "STATE GOVERNMENT", + "Question": "The counties of Iowa & Arizona are headed by boards of these", + "Answer": "supervisors" + }, + { + "Category": "HERE'S LUCY", + "Question": "Lucy Simon, the sister of this pop singer, wrote the music for Broadway's \"The Secret Garden\"", + "Answer": "Carly Simon" + }, + { + "Category": "CAPITAL PUNISHMENT", + "Question": "How peachy: Tbilisi", + "Answer": "Georgia" + }, + { + "Category": "BEFORE & AFTER", + "Question": "The Beatles' 1967 album that was a 2001 WWII miniseries on HBO", + "Answer": "Sgt. Pepper's Lonely Hearts Club Band of Brothers" + }, + { + "Category": "AMERICAN LITERATURE", + "Question": "This captain of the Ghost rescues literary critic Humphrey Van Weyden & poet Maude Brewster from a shipwreck", + "Answer": "Wolf Larsen" + }, + { + "Category": "EDUCATION JARGON", + "Question": "These 2 words, denoting socioeconomically challenged, followed \"A Nation\" in a 1983 report's title", + "Answer": "At Risk" + }, + { + "Category": "STATE GOVERNMENT", + "Question": "Many states have these for state lawmakers, but in 1995 the Supreme Court ruled them unconstitutional for Congress", + "Answer": "term limits" + }, + { + "Category": "HERE'S LUCY", + "Question": "She was the first wife of a president to be called first lady on a regular basis", + "Answer": "\"Lemonade Lucy\" Hayes" + }, + { + "Category": "CAPITAL PUNISHMENT", + "Question": "In west Africa: Luanda", + "Answer": "Angola" + }, + { + "Category": "BEFORE & AFTER", + "Question": "Van Gogh's 1889 painting of director George Romero's 1968 zombie film classic", + "Answer": "Starry Night of the Living Dead" + }, + { + "Category": "NOTABLE NAMES", + "Question": "His last direct descendant was a granddaughter, Elizabeth Hall, born to John & Susanna Hall in 1608", + "Answer": "William Shakespeare" + }, + { + "Category": "AUTHORS", + "Question": "While attending Lisbon Falls High School in Maine, this horror author published a newspaper, The Village Vomit", + "Answer": "Stephen King" + }, + { + "Category": "MUSICAL BY CHARACTERS", + "Question": "Fantine & her daughter Cosette", + "Answer": "Les Misérables" + }, + { + "Category": "FASHION FROM HEAD TO TOE", + "Question": "This type of felt hat that Dick Tracy wore is named for a play by Sardou", + "Answer": "a fedora" + }, + { + "Category": "U.N. OBSERVANCES", + "Question": "December 2 is International Day for the Abolition of this, which didn't disappear in 1865", + "Answer": "Slavery" + }, + { + "Category": "THE WESTERN HEMISPHERE", + "Question": "Cape Catoche, the northeastern tip of this large peninsula, lies a little more than 30 miles north of Cancun", + "Answer": "the Yucatan" + }, + { + "Category": "3-LETTER THE BETTER", + "Question": "To point your mauser", + "Answer": "aim" + }, + { + "Category": "AUTHORS", + "Question": "Robert Louis Stevenson suffered from this lung disease for many years, but died of a cerebral hemorrhage in 1894", + "Answer": "tuberculosis" + }, + { + "Category": "MUSICAL BY CHARACTERS", + "Question": "Miguel de Cervantes & Aldonza", + "Answer": "The Man of La Mancha" + }, + { + "Category": "FASHION FROM HEAD TO TOE", + "Question": "1950s fashion favored this canine skirt", + "Answer": "a poodle skirt" + }, + { + "Category": "U.N. OBSERVANCES", + "Question": "March 22 is World this Resource Day; the theme for 1999 was \"Everyone Lives Downstream\"", + "Answer": "Water" + }, + { + "Category": "THE WESTERN HEMISPHERE", + "Question": "This companion island to Trinidad has its own airport, Crown Point International", + "Answer": "Tobago" + }, + { + "Category": "3-LETTER THE BETTER", + "Question": "What a film reel is stored in; hence something finished is \"in\" it", + "Answer": "the can" + }, + { + "Category": "AUTHORS", + "Question": "Already a successful poet, in 1814 he started his career as a novelist with a tale of the Highlands", + "Answer": "Sir Walter Scott" + }, + { + "Category": "MUSICAL BY CHARACTERS", + "Question": "Emile de Becque & Ensign Nellie Forbush", + "Answer": "South Pacific" + }, + { + "Category": "FASHION FROM HEAD TO TOE", + "Question": "This company's canvas All Star basketball shoe goes all the way back to 1917", + "Answer": "Converse" + }, + { + "Category": "U.N. OBSERVANCES", + "Question": "September 16 is International Day for the Preservation of this atmospheric layer", + "Answer": "the Ozone Layer" + }, + { + "Category": "THE WESTERN HEMISPHERE", + "Question": "A monument dedicated to the men who lost their lives on the USS Maine stands in this capital's Parque del Maine", + "Answer": "Havana" + }, + { + "Category": "3-LETTER THE BETTER", + "Question": "Saturated", + "Answer": "wet" + }, + { + "Category": "AUTHORS", + "Question": "About the \"Human Comedy\" series, he said, \"French society was to be the historian, I was only to be its secretary\"", + "Answer": "Honoré de Balzac" + }, + { + "Category": "MUSICAL BY CHARACTERS", + "Question": "Aunt Eller Murphy & Laurey Williams", + "Answer": "Oklahoma!" + }, + { + "Category": "FASHION FROM HEAD TO TOE", + "Question": "This French-named garment looks like a skirt but is actually pants", + "Answer": "culottes" + }, + { + "Category": "U.N. OBSERVANCES", + "Question": "Can't wait for Oct. 20, World Day for this science of collecting & arranging numerical facts & data", + "Answer": "statistics" + }, + { + "Category": "THE WESTERN HEMISPHERE", + "Question": "This Venezuelan waterfall was named for an American bush pilot who discovered it in 1935", + "Answer": "Angel Falls" + }, + { + "Category": "3-LETTER THE BETTER", + "Question": "To impose a levy", + "Answer": "to tax" + }, + { + "Category": "AUTHORS", + "Question": "His \"The Autobiography of Miss Jane Pittman\" spans 100 years from the Civil War to the civil rights movement", + "Answer": "Ernest J. Gaines" + }, + { + "Category": "MUSICAL BY CHARACTERS", + "Question": "Rolf Gruber & Mother Abbess of Nonnberg Abbey", + "Answer": "The Sound of Music" + }, + { + "Category": "FASHION FROM HEAD TO TOE", + "Question": "The French name of these casual summer shoes derives from a tough wiry grass that's used to make rope", + "Answer": "espadrilles" + }, + { + "Category": "U.N. OBSERVANCES", + "Question": "International this Remembrance Day, January 27, commemorates the 1945 date on which Auschwitz was liberated", + "Answer": "Holocaust" + }, + { + "Category": "THE WESTERN HEMISPHERE", + "Question": "This southwestern U.S. desert has a river of the same name, flowing mainly underground to near Soda lake", + "Answer": "Mojave" + }, + { + "Category": "\"G\"ARDEN GLOSSARY", + "Question": "Inserting a section of one plant into another so that they grow as one plant", + "Answer": "to graft" + }, + { + "Category": "TURN OF THE CENTURY MOVIES", + "Question": "In a northern England mining town, a young boy takes up ballet dancing", + "Answer": "Billy Elliot" + }, + { + "Category": "I SERVED IN HIS CABINET", + "Question": "Secretary of Health & Human Services Kathleen Sebelius", + "Answer": "Barack Obama" + }, + { + "Category": "ARE YOU PERHAPS FRENCH?", + "Question": "Philippe of this family is Chief Ocean Correspondent for Animal Planet", + "Answer": "Cousteau" + }, + { + "Category": "BIBLE BOOK BINDINGS", + "Question": "Hey ___ Law", + "Answer": "Jude" + }, + { + "Category": "GREEK LETTERS", + "Question": "Precedes \"-bits\" in the name of a sweet Post cereal", + "Answer": "alpha" + }, + { + "Category": "\"G\"ARDEN GLOSSARY", + "Question": "Rich in nutrients, this bat or bird dropping is good for your garden", + "Answer": "guano" + }, + { + "Category": "TURN OF THE CENTURY MOVIES", + "Question": "Policeman Ichabod Crane is sent to a small town to investigate a series of decapitations", + "Answer": "Sleepy Hollow" + }, + { + "Category": "I SERVED IN HIS CABINET", + "Question": "Secretary of the Interior James G. Watt", + "Answer": "Ronald Reagan" + }, + { + "Category": "ARE YOU PERHAPS FRENCH?", + "Question": "Born in 1911, Louise Bourgeois worked into her 90s on her biomorphic creations in this art form", + "Answer": "sculpture" + }, + { + "Category": "BIBLE BOOK BINDINGS", + "Question": "Maker's ___ Sanchez", + "Answer": "Mark" + }, + { + "Category": "GREEK LETTERS", + "Question": "The ratio of the circumference of a circle to its diameter", + "Answer": "pi" + }, + { + "Category": "\"G\"ARDEN GLOSSARY", + "Question": "Open an account at one of these banks that exist for the conservation of seeds, tissues or reproductive cells", + "Answer": "a gene bank" + }, + { + "Category": "TURN OF THE CENTURY MOVIES", + "Question": "A young cop works with rogue detective Denzel Washington on the narcotics beat in Los Angeles", + "Answer": "Training Day" + }, + { + "Category": "I SERVED IN HIS CABINET", + "Question": "Secretary of State Cyrus Vance", + "Answer": "Jimmy Carter" + }, + { + "Category": "ARE YOU PERHAPS FRENCH?", + "Question": "Michelin 3-star chef Joel Robuchon opened his first U.S. restaurant in this city, not New York", + "Answer": "Las Vegas" + }, + { + "Category": "BIBLE BOOK BINDINGS", + "Question": "Prime ___ Racket", + "Answer": "Numbers" + }, + { + "Category": "GREEK LETTERS", + "Question": "A little bit, a really little bit", + "Answer": "iota" + }, + { + "Category": "\"G\"ARDEN GLOSSARY", + "Question": "This cereal grain embryo is usually separated from the endosperm during milling; health nuts love the \"wheat\" kind", + "Answer": "the germ" + }, + { + "Category": "TURN OF THE CENTURY MOVIES", + "Question": "A research chemist appears on a \"60 Minutes\" expose of the tobacco industry", + "Answer": "The Insider" + }, + { + "Category": "I SERVED IN HIS CABINET", + "Question": "Secretary of Agriculture Earl Butz", + "Answer": "Nixon" + }, + { + "Category": "ARE YOU PERHAPS FRENCH?", + "Question": "He was Jacques Chirac's predecessor as president", + "Answer": "François Mitterand" + }, + { + "Category": "BIBLE BOOK BINDINGS", + "Question": "Losing ___ Washington", + "Answer": "Isiah" + }, + { + "Category": "GREEK LETTERS", + "Question": "A homophone of a verb meaning \"to paddle\"", + "Answer": "rho" + }, + { + "Category": "TURN OF THE CENTURY MOVIES", + "Question": "2 warriors seek the Green Destiny, a stolen ancient sword", + "Answer": "Crouching Tiger, Hidden Dragon" + }, + { + "Category": "I SERVED IN HIS CABINET", + "Question": "Secretary of Defense George C. Marshall", + "Answer": "Harry Truman" + }, + { + "Category": "ARE YOU PERHAPS FRENCH?", + "Question": "Luc Montagnier identified the AIDS virus while working at the institute named for this 19th c. Frenchman", + "Answer": "Pasteur" + }, + { + "Category": "BIBLE BOOK BINDINGS", + "Question": "The Heidi ___ of Riddick", + "Answer": "Chronicles" + }, + { + "Category": "GREEK LETTERS", + "Question": "Ancient Romans would've read this one as 11", + "Answer": "xi" + }, + { + "Category": "19th CENTURY MUSIC", + "Question": "Lyrics to an 1868 tune by this man began, \"Guten Abend, Gut Nacht, Mit Rosen Bedacht\"", + "Answer": "Johannes Brahms" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "On Pentecost the Apostles amazed people when they \"began to speak with other\" these", + "Answer": "tongues" + }, + { + "Category": "NAME THE FILM", + "Question": "1939: \"I've a feeling we're not in Kansas anymore\"", + "Answer": "The Wizard Of Oz" + }, + { + "Category": "SKIRTING THE ISSUE", + "Question": "Originally worn by highlanders in various tartans, these are also worn by women as skirts", + "Answer": "kilts" + }, + { + "Category": "IDEAS FOR TOURISM CAMPAIGNS", + "Question": "We're mostly 4,000 feet above sea level & Idi Amin doesn't run us anymore. Isn't that enough?", + "Answer": "Uganda" + }, + { + "Category": "FOOD & DRINK", + "Question": "They're the 2 things Little Miss Muffet was consuming while sitting on her tuffet", + "Answer": "curds & whey" + }, + { + "Category": "TIME TO \"EAT\"", + "Question": "To practice trickery or fraud in game play", + "Answer": "cheat" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "Always mentioned last in the list of Jesus' 12 Disciples, he was the treasurer of the group", + "Answer": "Judas Iscariot" + }, + { + "Category": "NAME THE FILM", + "Question": "1972: \"I'm gonna make him an offer he can't refuse\"", + "Answer": "The Godfather" + }, + { + "Category": "SKIRTING THE ISSUE", + "Question": "The silhouette of a slightly flared skirt looks like a certain letter, giving it this name", + "Answer": "an A-line" + }, + { + "Category": "IDEAS FOR TOURISM CAMPAIGNS", + "Question": "Keflavik & Grindavik call to you, & we'll throw in a 50/50 shot at seeing Bjork somewhere", + "Answer": "Iceland" + }, + { + "Category": "FOOD & DRINK", + "Question": "When used to describe meat, \"marbling\" means streaks of this", + "Answer": "fat" + }, + { + "Category": "TIME TO \"EAT\"", + "Question": "A spike on the bottom of an athletic shoe", + "Answer": "a cleat" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "This mother of John The Baptist was well into old age when John was born", + "Answer": "Elizabeth" + }, + { + "Category": "NAME THE FILM", + "Question": "1976: \"You talking to me?\"", + "Answer": "Taxi Driver" + }, + { + "Category": "SKIRTING THE ISSUE", + "Question": "This loose-fitting garment often worn as a beach coverup was copied from Indonesian native dress", + "Answer": "a sarong" + }, + { + "Category": "IDEAS FOR TOURISM CAMPAIGNS", + "Question": "Our Andes are dandy! Only Brazil has more people in South America, but they don't have our coffee. Hail...", + "Answer": "Colombia" + }, + { + "Category": "FOOD & DRINK", + "Question": "In 2006 the Chicago City Council banned restaurants in the city from selling this goose liver dish", + "Answer": "foie gras" + }, + { + "Category": "TIME TO \"EAT\"", + "Question": "Bartender's adjective for a cocktail served without water", + "Answer": "neat" + }, + { + "Category": "NAME THE FILM", + "Question": "1995: \"To infinity, and beyond!\"", + "Answer": "Toy Story" + }, + { + "Category": "SKIRTING THE ISSUE", + "Question": "On the original \"90210\":, Donna wore this type of skirt to the prom; she couldn't sit down all night", + "Answer": "a hoop skirt" + }, + { + "Category": "IDEAS FOR TOURISM CAMPAIGNS", + "Question": "From Koluszki to Kolno, & Wozniki to Strzelce, visit us, but just know we've heard all the jokes already", + "Answer": "Poland" + }, + { + "Category": "FOOD & DRINK", + "Question": "Thailand's best-known dish, it's stir-fried noodles, egg, bean sprouts, peanuts & seasonings", + "Answer": "pad thai" + }, + { + "Category": "TIME TO \"EAT\"", + "Question": "Moss type used as fuel", + "Answer": "peat" + }, + { + "Category": "THE NEW TESTAMENT", + "Question": "In Luke he is quoted as saying, \"I, having examined him before you, have found no fault in this man\"", + "Answer": "Pilate" + }, + { + "Category": "NAME THE FILM", + "Question": "2007: \"I... drink... your... milkshake! I drink it up!\"", + "Answer": "There Will Be Blood" + }, + { + "Category": "SKIRTING THE ISSUE", + "Question": "The sunburst-pleated skirt is also called this for the pleats' resemblance to the bellows of a musical instrument", + "Answer": "an accordion skirt" + }, + { + "Category": "IDEAS FOR TOURISM CAMPAIGNS", + "Question": "We're one big island! (& several small ones); Lemur entertain you! (Disclaimer: Lemurs will not, repeat not, speak to you)", + "Answer": "Madagascar" + }, + { + "Category": "FOOD & DRINK", + "Question": "This rum drink hailing from New Orleans' French Quarter has its own glass of the same name", + "Answer": "the Hurricane" + }, + { + "Category": "TIME TO \"EAT\"", + "Question": "The administrative metropolis in a U.S. county", + "Answer": "the seat" + }, + { + "Category": "20th CENTURY ARTISTS", + "Question": "In 1936 he showed up for a Surrealist exhibition dressed in a diving suit", + "Answer": "Dali" + }, + { + "Category": "RED SOX IT TO ME", + "Question": "On April 20, 1912 the first game at this new venue went 11 innings & ended with a Red Sox win", + "Answer": "Fenway Park" + }, + { + "Category": "BEYOND .COM", + "Question": "It indicates a website about employment, not about a founder of Apple", + "Answer": ".jobs" + }, + { + "Category": "PICK A PLANET", + "Question": "Its \"day\" is 24 hours & 39 minutes", + "Answer": "Mars" + }, + { + "Category": "THE ASSASSINATION OF LINCOLN", + "Question": "One of the other 3 people in the presidential box with Lincoln & Booth at the time of the attack", + "Answer": "Mary Todd Lincoln" + }, + { + "Category": "B.C. & AFTER", + "Question": "Son of Philip II of Macedonia who became the world's largest coral system", + "Answer": "Alexander the Great Barrier Reef" + }, + { + "Category": "20th CENTURY ARTISTS", + "Question": "In 2006 \"Roots\", a 1943 painting by her, sold for $5.6 million, then the record for a Latin American work", + "Answer": "Frida Kahlo" + }, + { + "Category": "RED SOX IT TO ME", + "Question": "With 44 homers, 121 RBIs & a .326 average, Carl Yastrzemski is the last baseball player to win this", + "Answer": "the Triple Crown" + }, + { + "Category": "BEYOND .COM", + "Question": "It's the perfect 2 letters for video-heavy sites such as Geekbrief", + "Answer": "TV" + }, + { + "Category": "PICK A PLANET", + "Question": "It's the third largest in our solar system", + "Answer": "Neptune" + }, + { + "Category": "THE ASSASSINATION OF LINCOLN", + "Question": "In the aftermath this owner of the theater/crime scene was thrown in jail as a possible conspirator", + "Answer": "Ford" + }, + { + "Category": "B.C. & AFTER", + "Question": "Period of time named for an alloy of copper & tin & the new water-bearing Zodiacal era", + "Answer": "the Bronze Age of Aquarius" + }, + { + "Category": "20th CENTURY ARTISTS", + "Question": "This Belgian's \"Mysteries Of The Horizon\" shows 3 men in bowler hats; a sliver of moon hangs above each of them", + "Answer": "Magritte" + }, + { + "Category": "RED SOX IT TO ME", + "Question": "Tim Wakefield has more starts than any pitcher in Red Sox history, mostly due to his success with this low-velocity pitch", + "Answer": "the knuckleball" + }, + { + "Category": "BEYOND .COM", + "Question": "If disseminating facts, knowledge, the 411, try this 4-letter domain, used by New York State's MTA", + "Answer": "info" + }, + { + "Category": "PICK A PLANET", + "Question": "It's never observable when the sky is fully dark", + "Answer": "Mercury" + }, + { + "Category": "THE ASSASSINATION OF LINCOLN", + "Question": "Dirty Harry could tell you it's also the caliber of the Derringer used by John Wilkes Booth to shoot Lincoln", + "Answer": "0.44" + }, + { + "Category": "B.C. & AFTER", + "Question": "\"Wonder\"-ful giant statue of Helios that brings financial aid to study at Oxford", + "Answer": "The Colossus of Rhodes Scholarship" + }, + { + "Category": "20th CENTURY ARTISTS", + "Question": "In 1958 he tripled up on his patriotic painting of \"Three Flags\"", + "Answer": "Johns" + }, + { + "Category": "RED SOX IT TO ME", + "Question": "In 1918 he extended his streak of scoreless World Series innings pitched to 29.2 & tied for the most HRs in the league", + "Answer": "Babe Ruth" + }, + { + "Category": "BEYOND .COM", + "Question": "It follows dot in a domain for companies & \"That's show\" in a familiar phrase", + "Answer": ".biz" + }, + { + "Category": "PICK A PLANET", + "Question": "It was the first to be discovered with the aid of the telescope", + "Answer": "Uranus" + }, + { + "Category": "THE ASSASSINATION OF LINCOLN", + "Question": "The 3-word Latin phrase yelled out by John Wilkes Booth while making his escape", + "Answer": "sic semper tyrannis" + }, + { + "Category": "B.C. & AFTER", + "Question": "Sophoclean tragedy about the killing of a father & his friend, the actor who portrayed Henry Higgins on film", + "Answer": "Oedipus Rex Harrison" + }, + { + "Category": "20th CENTURY ARTISTS", + "Question": "\"Sky Blue\", \"Blue Mountain\" & \"The Blue Rider\" are all paintings by this Russian abstract artist", + "Answer": "Kandinsky" + }, + { + "Category": "RED SOX IT TO ME", + "Question": "In 2001 this Osaka-born pitcher tossed Boston's first no-hitter since 1965", + "Answer": "Nomo" + }, + { + "Category": "BEYOND .COM", + "Question": "As of 2010, you can invent your own domain, according to the folks who regulate the Net; they're at www.icann.this", + "Answer": ".org" + }, + { + "Category": "PICK A PLANET", + "Question": "Leda is its 13th moon", + "Answer": "Jupiter" + }, + { + "Category": "THE ASSASSINATION OF LINCOLN", + "Question": "Attempts on the lives of VP Andrew Johnson & this Secretary of State were also part of the plot", + "Answer": "Seward" + }, + { + "Category": "B.C. & AFTER", + "Question": "Homo erectus archaeological find on Jakarta's island by an expatriate U.S. photographer", + "Answer": "Java Man Ray" + }, + { + "Category": "ROSE BOWL HISTORY", + "Question": "The only time the game wasn't held in Calif. was 1942, when it was in N.C., amidst fears of another event like this one", + "Answer": "Pearl Harbor" + }, + { + "Category": "RELIGIOUS RHYME TIME", + "Question": "Pontiff's cleansing agents", + "Answer": "the Pope's soaps" + }, + { + "Category": "PASS THE CHOCOLATE", + "Question": "The leaf design on Godiva's Autant chocolates is a stylized version of a feather on this \"Gone With the Wind\" heroine's hat", + "Answer": "Scarlett O'Hara" + }, + { + "Category": "KIDDY LIT", + "Question": "This dark horse shares stables with Merrylegs & Ginger", + "Answer": "Black Beauty" + }, + { + "Category": "THE CAT", + "Question": "Of all the varieties of cats big & small, the cheetah is the only one that can't fully retract these", + "Answer": "the claws" + }, + { + "Category": "THE CANARY ISLANDS", + "Question": "The Canary Islands' highest point, 12,000-foot Pico de Teide, is the peak of a dormant one of these", + "Answer": "a volcano" + }, + { + "Category": "RELIGIOUS RHYME TIME", + "Question": "A Latter-Day jury spokesperson", + "Answer": "a Mormon foreman" + }, + { + "Category": "PASS THE CHOCOLATE", + "Question": "Candymakers know that the fat obtained from cocoa beans isn't called cocoa margarine but this", + "Answer": "cocoa butter" + }, + { + "Category": "KIDDY LIT", + "Question": "In this poem, the hero is instructed to shun the frumious Bandersnatch", + "Answer": "Jabberwocky" + }, + { + "Category": "THE CAT", + "Question": "It's the full name for the domesticated kitty called a tortie", + "Answer": "a tortoiseshell" + }, + { + "Category": "THE CANARY ISLANDS", + "Question": "On his 3 15th century voyages to the New World, his ships stopped off at the Canary Islands for supplies", + "Answer": "Columbus" + }, + { + "Category": "RELIGIOUS RHYME TIME", + "Question": "Society of Friends' parcels of land", + "Answer": "Quakers' acres" + }, + { + "Category": "PASS THE CHOCOLATE", + "Question": "A 2007 study said that eating a little dark chocolate daily may reduce this, both systolic & diastolic", + "Answer": "blood pressure" + }, + { + "Category": "KIDDY LIT", + "Question": "The wedding meal eaten by this odd Edward Lear pair is \"mince and slices of quince\"", + "Answer": "the owl and the pussycat" + }, + { + "Category": "THE CAT", + "Question": "It's the tailless cat variety from an island south of Scotland", + "Answer": "a manx" + }, + { + "Category": "THE CANARY ISLANDS", + "Question": "In July 2007 one of these instruments with a 34-foot mirror was completed on the Canary Islands", + "Answer": "a telescope" + }, + { + "Category": "RELIGIOUS RHYME TIME", + "Question": "Around the time of a veiled Muslim garment for women", + "Answer": "circa burka" + }, + { + "Category": "PASS THE CHOCOLATE", + "Question": "Fran's Chocolates of Seattle makes delectable caramels topped with the gray sea type of this", + "Answer": "salt" + }, + { + "Category": "KIDDY LIT", + "Question": "This title flute player's \"queer long coat from heel to head Was half of yellow & half of red\"", + "Answer": "the Pied Piper of Hamelin" + }, + { + "Category": "THE CAT", + "Question": "This shorthaired \"brown\" cat is named for its color, which is said to resemble that of a Cuban cigar", + "Answer": "a havana" + }, + { + "Category": "THE CANARY ISLANDS", + "Question": "In 1936 the Spanish government demoted this general to Governor of the Canary Islands", + "Answer": "Franco" + }, + { + "Category": "RELIGIOUS RHYME TIME", + "Question": "A large Asian white winter radish that's a representation of a saint", + "Answer": "a daikon icon" + }, + { + "Category": "PASS THE CHOCOLATE", + "Question": "Good news: Dark chocolate is rich in these antioxidant compounds whose very name sounds \"flavorful\"", + "Answer": "flavonoids" + }, + { + "Category": "KIDDY LIT", + "Question": "These tiny people in a 1952 Mary Norton story live under the floor in a large country house", + "Answer": "the borrowers" + }, + { + "Category": "THE CAT", + "Question": "This breed of domestic feline from Maine is the first truly American show breed", + "Answer": "a Maine coon" + }, + { + "Category": "THE CANARY ISLANDS", + "Question": "The Canary Islands were named for a large number of these the Romans found there, not yellow songbirds", + "Answer": "wild dogs" + }, + { + "Category": "WORLD WAR I", + "Question": "In 1917 Allied troops from this North American country stormed up Vimy Ridge in a legendary charge", + "Answer": "Canada" + }, + { + "Category": "SECRET IDENTITIES", + "Question": "Superman", + "Answer": "Clark Kent" + }, + { + "Category": "WOMEN'S FIRSTS", + "Question": "Let's show her a little R-E-S-P-E-C-T; she's the first woman inducted into the Rock & Roll Hall of Fame", + "Answer": "Aretha Franklin" + }, + { + "Category": "HOW'S THE WEATHER?", + "Question": "Sept. 4, 2007 was the first time that 2 of these, Henriette & Felix, made landfall on the same day", + "Answer": "hurricanes" + }, + { + "Category": "WORD\"Z\"", + "Question": "In football, it's a charge on the QB by linebackers or defensive backs", + "Answer": "a blitz" + }, + { + "Category": "WORLD WAR I", + "Question": "In the 1st raid of its kind in history, the British town of Yarmouth was bombed in 1915 by a German one of these", + "Answer": "a Zeppelin" + }, + { + "Category": "SECRET IDENTITIES", + "Question": "Batman", + "Answer": "Bruce Wayne" + }, + { + "Category": "LET'S PLAY BLACKJACK", + "Question": "In multi-deck blackjack, the cards are usually dealt from one of these--but not the kind you wear", + "Answer": "a shoe" + }, + { + "Category": "WOMEN'S FIRSTS", + "Question": "In 2007 Drew Gilpin Faust became the first female president in this university's 371-year history", + "Answer": "Harvard" + }, + { + "Category": "HOW'S THE WEATHER?", + "Question": "Mountain passes speed up hot, dry air, giving this U.S. state its Santa Ana winds", + "Answer": "California" + }, + { + "Category": "WORD\"Z\"", + "Question": "A granular form of this common mineral is used to make sandpaper", + "Answer": "quartz" + }, + { + "Category": "WORLD WAR I", + "Question": "Enver Pasha, this country's minister of war, commanded the troops defending the Dardanelles", + "Answer": "Turkey" + }, + { + "Category": "SECRET IDENTITIES", + "Question": "The original Robin, the Boy Wonder", + "Answer": "Dick Grayson" + }, + { + "Category": "WOMEN'S FIRSTS", + "Question": "Registering as K. Switzer, in 1967 Kathrine Switzer became the first woman to officially enter & run this race", + "Answer": "the Boston Marathon" + }, + { + "Category": "HOW'S THE WEATHER?", + "Question": "The forecast is cloudy with a 30% chance of these, characterized by the sudden start & stop of light rainfall", + "Answer": "showers" + }, + { + "Category": "WORD\"Z\"", + "Question": "Many French eateries include this word in their names; it means \"at the home of\"", + "Answer": "chez" + }, + { + "Category": "WORLD WAR I", + "Question": "What the Germans called the Siegfried Line, the Allies called this, after a famous German general of the war", + "Answer": "the Hindenburg Line" + }, + { + "Category": "SECRET IDENTITIES", + "Question": "Wonder Woman", + "Answer": "Diana Prince" + }, + { + "Category": "LET'S PLAY BLACKJACK", + "Question": "When a player & dealer tie, it's called this & no money is won or lost", + "Answer": "a push" + }, + { + "Category": "WOMEN'S FIRSTS", + "Question": "Frances Perkins became the first woman cabinet member when FDR put her to work in this post", + "Answer": "Secretary of Labor" + }, + { + "Category": "HOW'S THE WEATHER?", + "Question": "High clouds may bring this type of damaging precipitation, especially to the \"alley\" for it in the Rockies", + "Answer": "hail" + }, + { + "Category": "WORD\"Z\"", + "Question": "It's true! This city, the first colonial post in Mexico, was founded by Hernando Cortes in 1519", + "Answer": "Veracruz" + }, + { + "Category": "WORLD WAR I", + "Question": "At the 1914 Battle of Tannenberg in East Prussia, this country's army was surrounded & largely destroyed", + "Answer": "Russia" + }, + { + "Category": "SECRET IDENTITIES", + "Question": "Zorro", + "Answer": "Don Diego de la Vega" + }, + { + "Category": "WOMEN'S FIRSTS", + "Question": "Wilma Mankiller was the first woman to serve as principal chief of this Southeast Native American tribe", + "Answer": "the Cherokee" + }, + { + "Category": "HOW'S THE WEATHER?", + "Question": "Longer autumn nights let the ground cool, producing condensation & the \"ground\" type of this", + "Answer": "fog" + }, + { + "Category": "WORD\"Z\"", + "Question": "Last name of German engineer Karl, who in 1885 developed a 3-wheeled vehicle called the Motorwagen", + "Answer": "Benz" + }, + { + "Category": "ACTORS", + "Question": "He never won an Oscar, but this 1960s movie star got a patent for a low-slung bucket seat for race cars", + "Answer": "Steve McQueen" + }, + { + "Category": "THE AMERICAN REVOLUTION", + "Question": "Fighting started April 19, 1775 with a battle in Lexington that spread to this nearby town", + "Answer": "Concord" + }, + { + "Category": "IT'S SANDY!", + "Question": "This TV \"Funny Face\" did a 5-minute workout video in 1990 for people without a lot of time to exercise", + "Answer": "Sandy Duncan" + }, + { + "Category": "REAL ESTATE", + "Question": "Real estate owned with no claims on it is said to be \"free and\" this", + "Answer": "Clear" + }, + { + "Category": "LOVE QUOTES", + "Question": "Napoleon said, \"I have never loved anyone for love's sake, except, perhaps,\" her -- \"a little\"", + "Answer": "Josephine" + }, + { + "Category": "MUSICAL THEATER", + "Question": "It's the musical featuring the song heard here: (\"I'm Getting Married in the Morning\")", + "Answer": "\"My Fair Lady\"" + }, + { + "Category": "CROSSWORD CLUES \"H\"", + "Question": "He who does it is lost (9)", + "Answer": "Hesitates" + }, + { + "Category": "THE AMERICAN REVOLUTION", + "Question": "At Bunker Hill, Colonel Prescott is said to have ordered, \"Don't one of you fire until you see\" these", + "Answer": "The whites of their eyes" + }, + { + "Category": "IT'S SANDY!", + "Question": "In the 1960s he set records of 4 career no-hitters & 382 strikeouts in one year", + "Answer": "Sandy Koufax" + }, + { + "Category": "REAL ESTATE", + "Question": "In 1947 the U.S. was given a 99-year one on Philippine military bases -- it was later shortened", + "Answer": "Lease" + }, + { + "Category": "LOVE QUOTES", + "Question": "Samuel Butler rhymed, \"Love is a boy by poets styled; then spare the rod and\" do this", + "Answer": "Spoil the child" + }, + { + "Category": "MUSICAL THEATER", + "Question": "\"Side Show\" is based on the lives of Daisy & Violet Hilton, a famous pair of these extremely close siblings", + "Answer": "Siamese twins" + }, + { + "Category": "CROSSWORD CLUES \"H\"", + "Question": "Sleep like a bear (9)", + "Answer": "Hibernate" + }, + { + "Category": "THE AMERICAN REVOLUTION", + "Question": "During the war this American naval hero & captain of the Ranger raided the coast of England", + "Answer": "John Paul Jones" + }, + { + "Category": "TECHNOLOGY", + "Question": "\"PPI\" stands for this.", + "Answer": "Pixels Per Inch" + }, + { + "Category": "TECHNOLOGY", + "Question": "\"LED\" stands for this.", + "Answer": "Light EmittingDiode" + }, + { + "Category": "TECHNOLOGY", + "Question": "Steve Jobs, Steve Wozniak and this person founded Apple Computer in 1976.", + "Answer": "Ronald Wayne" + }, + { + "Category": "TECHNOLOGY", + "Question": "The iPhone was launches on this date.", + "Answer": "29th June 2007" + }, + { + "Category": "INDIA", + "Question": "Gandhi famously sent a letter stating this many demands to Lord Irwin.", + "Answer": "11" + }, + { + "Category": "TECHNOLOGY", + "Question": "This was the first smartphone in the world.", + "Answer": "IBM Simon" + }, + { + "Category": "TECHNOLOGY", + "Question": "The Raspberry Pi costs this many dollars.", + "Answer": "35" + }, + { + "Category": "TECHNOLOGY", + "Question": "The average keyboard has this many keys.", + "Answer": "104" + }, + { + "Category": "TECHNOLOGY", + "Question": "The Apple LISA failed because of costing this many dollars at launch.", + "Answer": "10000" + }, + { + "Category": "MOVIES", + "Question": "In this movie, Brad Pitt is the narrator's alter ego.", + "Answer": "Fight Club" + }, + { + "Category": "MOVIES", + "Question": "The first rule of Fight Club is_", + "Answer": "You do not talk about Fight Club" + }, + { + "Category": "MOVIES", + "Question": "In this film, the narrator had both, insomnia and an evil alter ego.", + "Answer": "Fight Club" + }, + { + "Category": "MOVIES", + "Question": "This was the nickname of the Irish man \"who knew how to get things\" in The Shawshank Redemption.", + "Answer": "Red" + }, + { + "Category": "MOVIES", + "Question": "In The Pursuit of Happyness, the protagonist sold these for a living.", + "Answer": "Bone Density Scanners" + }, + { + "Category": "TECHNOLOGY", + "Question": "This key on your keyboard is futile.", + "Answer": "Scroll lock" + }, + { + "Category": "TECHNOLOGY", + "Question": "\"GUI\" stands for this.", + "Answer": "Graphical User Interface" + } +] \ No newline at end of file diff --git a/src/EllieBot/data/typing_articles3.json b/src/EllieBot/data/typing_articles3.json new file mode 100644 index 0000000..0fb9004 --- /dev/null +++ b/src/EllieBot/data/typing_articles3.json @@ -0,0 +1,242 @@ +[ + { + "Source": "Heart Of Darkness", + "Text": "The sea-reach of the Thames stretched before us like the beginning of an interminable waterway. In the offing the sea and the sky were welded together without a joint, and in the luminous space the tanned sails of the barges drifting up with the tide seemed to stand still in red clusters of canvas sharply peaked, with gleams of varnished sprits." + }, + { + "Source": "Heart Of Darkness", + "Text": "I flew around like mad to get ready, and before forty-eight hours I was crossing the Channel to show myself to my employers, and sign the contract. In a very few hours I arrived in a city that always makes me think of a whited sepulchre. Prejudice no doubt. I had no difficulty in finding the Company's offices." + }, + { + "Source": "Heart Of Darkness", + "Text": "It arrested me, and he stood by civilly, holding an empty half-pint champagne bottle (medical comforts) with the candle stuck in it. To my question he said Mr. Kurtz had painted this-in this very station more than a year ago-while waiting for means to go to his trading post. 'Tell me, pray,' said I, 'who is this Mr. Kurtz?'" + }, + { + "Source": "Heart Of Darkness", + "Text": "In exterior he resembled a butcher in a poor neighbourhood, and his eyes had a look of sleepy cunning. He carried his fat paunch with ostentation on his short legs, and during the time his gang infested the station spoke to no one but his nephew. You could see these two roaming about all day long with their heads close together in an everlasting confab." + }, + { + "Source": "Heart Of Darkness", + "Text": "The dusk was falling. I had to wait in a lofty drawing-room with three long windows from floor to ceiling that were like three luminous and bedraped columns. The bent gilt legs and backs of the furniture shone in indistinct curves. The tall marble fireplace had a cold and monumental whiteness. A grand piano stood massively in a corner; with dark gleams on the flat surfaces like a sombre and polished sarcophagus. A high door opened-closed. I rose." + }, + { + "Source": "Alice's Adventures in Wonderland", + "Text": "So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her." + }, + { + "Source": "Alice's Adventures in Wonderland", + "Text": "Very soon the Rabbit noticed Alice, as she went hunting about, and called out to her in an angry tone, 'Why, Mary Ann, what are you doing out here? Run home this moment, and fetch me a pair of gloves and a fan! Quick, now!' And Alice was so much frightened that she ran off at once in the direction it pointed to, without trying to explain the mistake it had made." + }, + { + "Source": "Alice's Adventures in Wonderland", + "Text": "It was so long since she had been anything near the right size, that it felt quite strange at first; but she got used to it in a few minutes, and began talking to herself, as usual. ‘Come, there's half my plan done now! How puzzling all these changes are! I'm never sure what I'm going to be, from one minute to another! However, I've got back to my right size: the next thing is, to get into that beautiful garden-how is that to be done, I wonder?'" + }, + { + "Source": "Alice's Adventures in Wonderland", + "Text": "Alice could see, as well as if she were looking over their shoulders, that all the jurors were writing down ‘stupid things!' on their slates, and she could even make out that one of them didn't know how to spell ‘stupid,' and that he had to ask his neighbour to tell him. ‘A nice muddle their slates'll be in before the trial's over!' thought Alice." + }, + { + "Source": "Alice's Adventures in Wonderland", + "Text": "‘Oh, I've had such a curious dream!' said Alice, and she told her sister, as well as she could remember them, all these strange Adventures of hers that you have just been reading about; and when she had finished, her sister kissed her, and said, ‘It was a curious dream, dear, certainly: but now run in to your tea; it's getting late.' So Alice got up and ran off, thinking while she ran, as well she might, what a wonderful dream it had been." + }, + { + "Source": "Pride And Prejudice", + "Text": "In a few days Mr. Bingley returned Mr. Bennet's visit, and sat about ten minutes with him in his library. He had entertained hopes of being admitted to a sight of the young ladies, of whose beauty he had heard much; but he saw only the father. The ladies were somewhat more fortunate, for they had the advantage of ascertaining from an upper window that he wore a blue coat, and rode a black horse." + }, + { + "Source": "Pride And Prejudice", + "Text": "As no objection was made to the young people's engagement with their aunt, and all Mr. Collins's scruples of leaving Mr. and Mrs. Bennet for a single evening during his visit were most steadily resisted, the coach conveyed him and his five cousins at a suitable hour to Meryton; and the girls had the pleasure of hearing, as they entered the drawing-room, that Mr. Wickham had accepted their uncle's invitation, and was then in the house." + }, + { + "Source": "Pride And Prejudice", + "Text": "She had not been many hours at home before she found that the Brighton scheme, of which Lydia had given them a hint at the inn, was under frequent discussion between her parents. Elizabeth saw directly that her father had not the smallest intention of yielding; but his answers were at the same time so vague and equivocal, that her mother, though often disheartened, had never yet despaired of succeeding at last." + }, + { + "Source": "Pride And Prejudice", + "Text": "When he was gone, they were certain at least of receiving constant information of what was going on, and their uncle promised, at parting, to prevail on Mr. Bennet to return to Longbourn, as soon as he could, to the great consolation of his sister, who considered it as the only security for her husband's not being killed in a duel." + }, + { + "Source": "Pride And Prejudice", + "Text": "If he had been wavering before as to what he should do, which had often seemed likely, the advice and entreaty of so near a relation might settle every doubt, and determine him at once to be as happy as dignity unblemished could make him. In that case he would return no more. Lady Catherine might see him in her way through town; and his engagement to Bingley of coming again to Netherfield must give way." + }, + { + "Source": "Frankenstein; Or, The Modern Prometheus", + "Text": "You may conceive my astonishment on hearing such a question addressed to me from a man on the brink of destruction and to whom I should have supposed that my vessel would have been a resource which he would not have exchanged for the most precious wealth the earth can afford. I replied, however, that we were on a voyage of discovery towards the northern pole." + }, + { + "Source": "Frankenstein; Or, The Modern Prometheus", + "Text": "At that instant my father entered. I saw unhappiness deeply impressed on his countenance, but he endeavoured to welcome me cheerfully; and, after we had exchanged our mournful greeting, would have introduced some other topic than that of our disaster, had not Ernest exclaimed, \"Good God, papa! Victor says that he knows who was the murderer of poor William.\"" + }, + { + "Source": "Frankenstein; Or, The Modern Prometheus", + "Text": "The old man, leaning on his son, walked each day at noon, when it did not rain, as I found it was called when the heavens poured forth its waters. This frequently took place, but a high wind quickly dried the earth, and the season became far more pleasant than it had been." + }, + { + "Source": "Frankenstein; Or, The Modern Prometheus", + "Text": "When the news reached Leghorn that Felix was deprived of his wealth and rank, the merchant commanded his daughter to think no more of her lover, but to prepare to return to her native country. The generous nature of Safie was outraged by this command; she attempted to expostulate with her father, but he left her angrily, reiterating his tyrannical mandate." + }, + { + "Source": "Frankenstein; Or, The Modern Prometheus", + "Text": "The wind, which had fallen in the south, now rose with great violence in the west. The moon had reached her summit in the heavens and was beginning to descend; the clouds swept across it swifter than the flight of the vulture and dimmed her rays, while the lake reflected the scene of the busy heavens, rendered still busier by the restless waves that were beginning to rise. Suddenly a heavy storm of rain descended." + }, + { + "Source": "Huckleberry Finn", + "Text": "Now she had got a start, and she went on and told me all about the good place. She said all a body would have to do there was to go around all day long with a harp and sing, forever and ever. So I didn't think much of it. But I never said so. I asked her if she reckoned Tom Sawyer would go there, and she said not by a considerable sight. I was glad about that, because I wanted him and me to be together." + }, + { + "Source": "Huckleberry Finn", + "Text": "Ben Rogers said he couldn't get out much, only Sundays, and so he wanted to begin next Sunday; but all the boys said it would be wicked to do it on Sunday, and that settled the thing. They agreed to get together and fix a day as soon as they could, and then we elected Tom Sawyer first captain and Jo Harper second captain of the Gang, and so started home." + }, + { + "Source": "Huckleberry Finn", + "Text": "Pap he hadn't been seen for more than a year, and that was comfortable for me; I didn't want to see him no more. He used to always whale me when he was sober and could get his hands on me; though I used to take to the woods most of the time when he was around." + }, + { + "Source": "Huckleberry Finn", + "Text": "I went down to the front garden and clumb over the stile where you go through the high board fence. There was an inch of new snow on the ground, and I seen somebody's tracks. They had come up from the quarry and stood around the stile a while, and then went on around the garden fence. It was funny they hadn't come in, after standing around so. I couldn't make it out. It was very curious, somehow." + }, + { + "Source": "Huckleberry Finn", + "Text": "It did seem a powerful long time before Jim's light showed up; and when it did show it looked like it was a thousand mile off. By the time I got there the sky was beginning to get a little gray in the east; so we struck for an island, and hid the raft, and sunk the skiff, and turned in and slept like dead people." + }, + { + "Source": "A Tale Of Two Cities", + "Text": "With those words the passenger opened the coach-door and got in; not at all assisted by his fellow-passengers, who had expeditiously secreted their watches and purses in their boots, and were now making a general pretence of being asleep. With no more definite purpose than to escape the hazard of originating any other kind of action." + }, + { + "Source": "A Tale Of Two Cities", + "Text": "Making his way through the tainted crowd, dispersed up and down this hideous scene of action, with the skill of a man accustomed to make his way quietly, the messenger found out the door he sought, and handed in his letter through a trap in it. For, people then paid to see the play at the Old Bailey, just as they paid to see the play in Bedlam-only the former entertainment was much the dearer." + }, + { + "Source": "A Tale Of Two Cities", + "Text": "Defarge refreshed himself with a draught of wine-but, he took less than was given to the stranger, as being himself a man to whom it was no rarity-and stood waiting until the countryman had made his breakfast. He looked at no one present, and no one now looked at him; not even Madame Defarge, who had taken up her knitting, and was at work." + }, + { + "Source": "A Tale Of Two Cities", + "Text": "The President required the name of that citizen. The accused explained that the citizen was his first witness. He also referred with confidence to the citizen's letter, which had been taken from him at the Barrier, but which he did not doubt would be found among the papers then before the President." + }, + { + "Source": "A Tale Of Two Cities", + "Text": "But, all this was at first. Before long, the consideration that there was no disgrace in the fate he must meet, and that numbers went the same road wrongfully, and trod it firmly every day, sprang up to stimulate him. Next followed the thought that much of the future peace of mind enjoyable by the dear ones, depended on his quiet fortitude. So, by degrees he calmed into the better state, when he could raise his thoughts much higher, and draw comfort down." + }, + { + "Source": "Metamorphosis", + "Text": "The three gentlemen stepped out of their room and looked round in amazement for their breakfasts; they had been forgotten about. \"Where is our breakfast?\", the middle gentleman asked the cleaner irritably. She just put her finger on her lips and made a quick and silent sign to the men that they might like to come into Gregor's room. They did so, and stood around Gregor's corpse with their hands in the pockets of their well-worn coats. It was now quite light in the room." + }, + { + "Source": "Metamorphosis", + "Text": "The first thing he wanted to do was get the lower part of his body out of the bed, but he had never seen this lower part, and could not imagine what it looked like; it turned out to be too hard to move; it went so slowly; and finally, almost in a frenzy, when he carelessly shoved himself forwards with all the force he could gather, he chose the wrong direction, hit hard against the lower bedpost, and learned from the burning pain he felt that the lower part of his body might well, at present, be the most sensitive." + }, + { + "Source": "Metamorphosis", + "Text": "But the chief clerk had turned away as soon as Gregor had started to speak, and, with protruding lips, only stared back at him over his trembling shoulders as he left. He did not keep still for a moment while Gregor was speaking, but moved steadily towards the door without taking his eyes off him. He moved very gradually, as if there had been some secret prohibition on leaving the room." + }, + { + "Source": "Metamorphosis", + "Text": "He spent the whole night there. Some of the time he passed in a light sleep, although he frequently woke from it in alarm because of his hunger, and some of the time was spent in worries and vague hopes which, however, always led to the same conclusion: for the time being he must remain calm, he must show patience and the greatest consideration so that his family could bear the unpleasantness that he, in his present condition, was forced to impose on them." + }, + { + "Source": "Metamorphosis", + "Text": "He was hardly inside his room before the door was hurriedly shut, bolted and locked. The sudden noise behind Gregor so startled him that his little legs collapsed under him. It was his sister who had been in so much of a rush. She had been standing there waiting and sprung forward lightly, Gregor had not heard her coming at all, and as she turned the key in the lock she said loudly to her parents \"At last!\"." + }, + { + "Source": "Dracula", + "Text": "Just as I had come to this conclusion I heard a heavy step approaching behind the great door, and saw through the chinks the gleam of a coming light. Then there was the sound of rattling chains and the clanking of massive bolts drawn back. A key was turned with the loud grating noise of long disuse, and the great door swung back." + }, + { + "Source": "Dracula", + "Text": "She threw herself on her knees, and raising up her hands, cried the same words in tones which wrung my heart. Then she tore her hair and beat her breast, and abandoned herself to all the violences of extravagant emotion. Finally, she threw herself forward, and, though I could not see her, I could hear the beating of her naked hands against the door." + }, + { + "Source": "Dracula", + "Text": "I feel so happy to-night. I have been so miserably weak, that to be able to think and move about is like feeling sunshine after a long spell of east wind out of a steel sky. Somehow Arthur feels very, very close to me. I seem to feel his presence warm about me. I suppose it is that sickness and weakness are selfish things and turn our inner eyes and sympathy on ourselves, whilst health and strength give Love rein, and in thought and feeling he can wander where he wills." + }, + { + "Source": "Dracula", + "Text": "It was a lonely vigil. Just after I had taken my place I heard a distant clock strike twelve, and in time came one and two. I was chilled and unnerved, and angry with the Professor for taking me on such an errand and with myself for coming. I was too cold and too sleepy to be keenly observant, and not sleepy enough to betray my trust so altogether I had a dreary, miserable time." + }, + { + "Source": "Dracula", + "Text": "Another surprise. Mina woke me early, about the same time as yesterday, and asked me to bring Dr. Van Helsing. I thought that it was another occasion for hypnotism, and without question went for the Professor. He had evidently expected some such call, for I found him dressed in his room. His door was ajar, so that he could hear the opening of the door of our room. He came at once; as he passed into the room, he asked Mina if the others might come, too." + }, + { + "Source": "The Golden Bird", + "Text": "Time passed on; and as the eldest son did not come back, and no tidings were heard of him, the second son set out, and the same thing happened to him. He met the fox, who gave him the good advice: but when he came to the two inns, his eldest brother was standing at the window where the merrymaking was, and called to him to come in; and he could not withstand the temptation, but went in, and forgot the golden bird and his country in the same manner." + }, + { + "Source": "The Goose-Girl", + "Text": "When the time came for them to set out, the fairy went into her bed-chamber, and took a little knife, and cut off a lock of her hair, and gave it to the princess, and said, ‘Take care of it, dear child; for it is a charm that may be of use to you on the road.' Then they all took a sorrowful leave of the princess; and she put the lock of hair into her bosom, got upon her horse, and set off on her journey to her bridegroom's kingdom." + }, + { + "Source": "Hansel And Gretel", + "Text": "They walked the whole night long, and by break of day came once more to their father's house. They knocked at the door, and when the woman opened it and saw that it was Hansel and Gretel, she said: ‘You naughty children, why have you slept so long in the forest?-we thought you were never coming back at all!' The father, however, rejoiced, for it had cut him to the heart to leave them behind alone." + }, + { + "Source": "Frederick And Catherine", + "Text": "Away ran Catherine, and away ran the dog across the field: but he ran faster than she, and stuck close to the steak. ‘It's all gone, and “what can't be cured must be endured”,' said Catherine. So she turned round; and as she had run a good way and was tired, she walked home leisurely to cool herself." + }, + { + "Source": "Snowdrop", + "Text": "Then he told her all that had happened, and said, ‘I love you far better than all the world; so come with me to my father's palace, and you shall be my wife.' And Snowdrop consented, and went home with the prince; and everything was got ready with great pomp and splendour for their wedding." + }, + { + "Source": "War And Peace", + "Text": "One of the next arrivals was a stout, heavily built young man with close-cropped hair, spectacles, the light-colored breeches fashionable at that time, a very high ruffle, and a brown dress coat. This stout young man was an illegitimate son of Count Bezúkhov, a well-known grandee of Catherine's time who now lay dying in Moscow." + }, + { + "Source": "War And Peace", + "Text": "Though he was certainly rather bigger than the other men in the room, her anxiety could only have reference to the clever though shy, but observant and natural, expression which distinguished him from everyone else in that drawing room. " + }, + { + "Source": "War And Peace", + "Text": "The whole day had been hot. Somewhere a storm was gathering, but only a small cloud had scattered some raindrops lightly, sprinkling the road and the sappy leaves. The left side of the forest was dark in the shade, the right side glittered in the sunlight, wet and shiny and scarcely swayed by the breeze. Everything was in blossom, the nightingales trilled, and their voices reverberated now near, now far away." + }, + { + "Source": "War And Peace", + "Text": "All the best and happiest moments of his life-especially his earliest childhood, when he used to be undressed and put to bed, and when leaning over him his nurse sang him to sleep and he, burying his head in the pillow, felt happy in the mere consciousness of life-returned to his memory, not merely as something past but as something present." + }, + { + "Source": "War And Peace", + "Text": "The rain had stopped, and only the mist was falling and drops from the trees. Denísov, the esaul, and Pétya rode silently, following the peasant in the knitted cap who, stepping lightly with outturned toes and moving noiselessly in his bast shoes over the roots and wet leaves, silently led them to the edge of the forest." + }, + { + "Source": "Gulliver's Travels into Several Remote Nations of the World", + "Text": "Ingratitude is among them a capital crime, as we read it to have been in some other countries: for they reason thus; that whoever makes ill returns to his benefactor, must needs be a common enemy to the rest of mankind, from whom he has received no obligation, and therefore such a man is not fit to live." + }, + { + "Source": "Gulliver's Travels into Several Remote Nations of the World", + "Text": "The next day I sailed to another island, and thence to a third and fourth, sometimes using my sail, and sometimes my paddles. But, not to trouble the reader with a particular account of my distresses, let it suffice, that on the fifth day I arrived at the last island in my sight, which lay south-south-east to the former." + }, + { + "Source": "Gulliver's Travels into Several Remote Nations of the World", + "Text": "On the 16th of April we put in at the Downs. I landed next morning, and saw once more my native country, after an absence of five years and six months complete. I went straight to Redriff, where I arrived the same day at two in the afternoon, and found my wife and family in good health." + }, + { + "Source": "Gulliver's Travels into Several Remote Nations of the World", + "Text": "I durst make no return to this malicious insinuation, which debased human understanding below the sagacity of a common hound, who has judgment enough to distinguish and follow the cry of the ablest dog in the pack, without being ever mistaken." + }, + { + "Source": "Gulliver's Travels into Several Remote Nations of the World", + "Text": "It is easy for us who travel into remote countries, which are seldom visited by Englishmen or other Europeans, to form descriptions of wonderful animals both at sea and land. Whereas a traveller's chief aim should be to make men wiser and better, and to improve their minds by the bad, as well as good, example of what they deliver concerning foreign places." + }, + { + "Source": "The Republic", + "Text": "Now, I said, you are on more substantial and almost unanswerable ground; for if the injustice which you were maintaining to be profitable had been admitted by you as by others to be vice and deformity, an answer might have been given to you on received principles; but now I perceive that you will call injustice honourable and strong, and to the unjust you will attribute all the qualities which were attributed by us before to the just, seeing that you do not hesitate to rank injustice with wisdom and virtue." + }, + { + "Source": "The Republic", + "Text": "And is he likely to be brave who has no spirit, whether horse or dog or any other animal? Have you never observed how invincible and unconquerable is spirit and how the presence of it makes the soul of any creature to be absolutely fearless and indomitable?" + }, + { + "Source": "The Republic", + "Text": "Well, I replied, I suppose that I must retrace my steps and say what I perhaps ought to have said before in the proper place. The part of the men has been played out, and now properly enough comes the turn of the women. Of them I will proceed to speak, and the more readily since I am invited by you." + }, + { + "Source": "The Republic", + "Text": "You are aware, I replied, that quick intelligence, memory, sagacity, cleverness, and similar qualities, do not often grow together, and that persons who possess them and are at the same time high-spirited and magnanimous are not so constituted by nature as to live orderly and in a peaceful and settled manner; they are driven any way by their impulses, and all solid principle goes out of them." + }, + { + "Source": "The Republic", + "Text": "And the end is that when they see the people, not of their own accord, but through ignorance, and because they are deceived by informers, seeking to do them wrong, then at last they are forced to become oligarchs in reality; they do not wish to be, but the sting of the drones torments them and breeds revolution in them." + } +] \ No newline at end of file diff --git a/src/EllieBot/data/units.json b/src/EllieBot/data/units.json new file mode 100644 index 0000000..9de5921 --- /dev/null +++ b/src/EllieBot/data/units.json @@ -0,0 +1,757 @@ +[ + { + "Triggers": [ + "millimeter", + "millimeters", + "millimeter", + "mm" + ], + "UnitType": "length", + "Modifier": 0.001 + }, + { + "Triggers": [ + "centimeter", + "centimeters", + "centimeter", + "cm" + ], + "UnitType": "length", + "Modifier": 0.01 + }, + { + "Triggers": [ + "decimeter", + "decimeters", + "decimeter", + "dm" + ], + "UnitType": "length", + "Modifier": 0.1 + }, + { + "Triggers": [ + "meter", + "meters", + "meter", + "m" + ], + "UnitType": "length", + "Modifier": 1.0 + }, + { + "Triggers": [ + "kilometer", + "kilometers", + "kilometer", + "km" + ], + "UnitType": "length", + "Modifier": 1000.0 + }, + { + "Triggers": [ + "foot", + "feet", + "foot", + "ft" + ], + "UnitType": "length", + "Modifier": 0.3048 + }, + { + "Triggers": [ + "inch", + "inches", + "inch", + "in" + ], + "UnitType": "length", + "Modifier": 0.0254 + }, + { + "Triggers": [ + "mile", + "miles", + "mile", + "mi" + ], + "UnitType": "length", + "Modifier": 1609.344 + }, + { + "Triggers": [ + "yard", + "yards", + "yard", + "yd" + ], + "UnitType": "length", + "Modifier": 0.9144 + }, + { + "Triggers": [ + "cubic foot", + "cubic feet", + "cubic foot", + "ft3" + ], + "UnitType": "volume", + "Modifier": 0.02831685 + }, + { + "Triggers": [ + "cubic inch", + "cubic inches", + "cubic inch", + "in3" + ], + "UnitType": "volume", + "Modifier": 0.00001638706 + }, + { + "Triggers": [ + "cubic mile", + "cubic miles", + "cubic mile", + "mi3" + ], + "UnitType": "volume", + "Modifier": 4168182000.0 + }, + { + "Triggers": [ + "cubic yard", + "cubic yards", + "cubic yard", + "yd3" + ], + "UnitType": "volume", + "Modifier": 0.7645549 + }, + { + "Triggers": [ + "cup", + "cups", + "cup", + "cup" + ], + "UnitType": "volume", + "Modifier": 0.0002365882 + }, + { + "Triggers": [ + "imperial gallon", + "Imperial gallons", + "Imperial gallon", + "gal" + ], + "UnitType": "volume", + "Modifier": 0.00454609 + }, + { + "Triggers": [ + "us gallon", + "US gallons", + "US gallon", + "gal" + ], + "UnitType": "volume", + "Modifier": 0.003785412 + }, + { + "Triggers": [ + "milliliter", + "milliliters", + "milliliter", + "mL" + ], + "UnitType": "volume", + "Modifier": 0.000001 + }, + { + "Triggers": [ + "liter", + "liters", + "liter", + "L" + ], + "UnitType": "volume", + "Modifier": 0.001 + }, + { + "Triggers": [ + "imperial fluid ounce", + "Imperial fluid ounces", + "Imperial fluid ounce", + "fl oz" + ], + "UnitType": "volume", + "Modifier": 0.00002841306 + }, + { + "Triggers": [ + "us fluid ounce", + "US fluid ounces", + "US fluid ounce", + "fl oz" + ], + "UnitType": "volume", + "Modifier": 0.00002957353 + }, + { + "Triggers": [ + "imperial pint", + "Imperial pints", + "Imperial pint", + "pt" + ], + "UnitType": "volume", + "Modifier": 0.00056826125 + }, + { + "Triggers": [ + "us liquid pint", + "US pints (liquid)", + "US pint (liquid)", + "pt" + ], + "UnitType": "volume", + "Modifier": 0.0004731765 + }, + { + "Triggers": [ + "us dry pint", + "US pints (dry)", + "US pint (dry)", + "pt" + ], + "UnitType": "volume", + "Modifier": 0.0005506105 + }, + { + "Triggers": [ + "imperial quart", + "Imperial quarts", + "Imperial quart", + "qt" + ], + "UnitType": "volume", + "Modifier": 0.00113652297 + }, + { + "Triggers": [ + "us liquid quart", + "US quarts (liquid)", + "US quart (liquid)", + "qt" + ], + "UnitType": "volume", + "Modifier": 0.0009463529 + }, + { + "Triggers": [ + "us dry quart", + "US quarts (dry)", + "US quart (dry)", + "qt" + ], + "UnitType": "volume", + "Modifier": 0.001101221 + }, + { + "Triggers": [ + "tablespoon", + "tablespoons", + "tablespoon", + "tbsp" + ], + "UnitType": "volume", + "Modifier": 0.00001478676 + }, + { + "Triggers": [ + "teaspoon", + "teaspoons", + "teaspoon", + "tspn" + ], + "UnitType": "volume", + "Modifier": 0.000004928922 + }, + { + "Triggers": [ + "milligram", + "milligrams", + "milligram", + "mg" + ], + "UnitType": "weight", + "Modifier": 0.000001 + }, + { + "Triggers": [ + "gram", + "grams", + "gram", + "g" + ], + "UnitType": "weight", + "Modifier": 0.001 + }, + { + "Triggers": [ + "kilogram", + "kilograms", + "kilogram", + "kg" + ], + "UnitType": "weight", + "Modifier": 1.0 + }, + { + "Triggers": [ + "carat", + "carats", + "carat", + "CD" + ], + "UnitType": "weight", + "Modifier": 0.00020 + }, + { + "Triggers": [ + "grain", + "grains", + "grain", + "gr" + ], + "UnitType": "weight", + "Modifier": 0.00006479891 + }, + { + "Triggers": [ + "ounce", + "ounces", + "ounce", + "oz" + ], + "UnitType": "weight", + "Modifier": 0.02834952 + }, + { + "Triggers": [ + "pennyweight", + "pennyweights", + "pennyweight", + "dwt" + ], + "UnitType": "weight", + "Modifier": 0.001555174 + }, + { + "Triggers": [ + "pound", + "pounds", + "pound", + "lb" + ], + "UnitType": "weight", + "Modifier": 0.4535924 + }, + { + "Triggers": [ + "stone", + "stones", + "stone", + "st" + ], + "UnitType": "weight", + "Modifier": 6.35029318 + }, + { + "Triggers": [ + "slug", + "slugs", + "slug", + "slug" + ], + "UnitType": "weight", + "Modifier": 14.59390 + }, + { + "Triggers": [ + "metric ton", + "metric tons", + "metric ton", + "t" + ], + "UnitType": "weight", + "Modifier": 1000.0 + }, + { + "Triggers": [ + "long ton", + "long tons", + "long ton", + "t" + ], + "UnitType": "weight", + "Modifier": 1016.047 + }, + { + "Triggers": [ + "short ton", + "short tons", + "short ton", + "t" + ], + "UnitType": "weight", + "Modifier": 907.1847 + }, + { + "Triggers": [ + "acre", + "acres", + "acre", + "acre" + ], + "UnitType": "area", + "Modifier": 4046.873 + }, + { + "Triggers": [ + "are", + "ares", + "are", + "a" + ], + "UnitType": "area", + "Modifier": 100.0 + }, + { + "Triggers": [ + "hectare", + "hectares", + "hectare", + "ha" + ], + "UnitType": "area", + "Modifier": 10000.0 + }, + { + "Triggers": [ + "square foot", + "square feet", + "square foot", + "ft2" + ], + "UnitType": "area", + "Modifier": 0.09290304 + }, + { + "Triggers": [ + "square meter", + "square meters", + "square meter", + "m2" + ], + "UnitType": "area", + "Modifier": 1.0 + }, + { + "Triggers": [ + "square kilometer", + "square kilometers", + "square kilometer", + "km2" + ], + "UnitType": "area", + "Modifier": 1000000.0 + }, + { + "Triggers": [ + "square inch", + "square inches", + "square inch", + "in2" + ], + "UnitType": "area", + "Modifier": 0.00064516 + }, + { + "Triggers": [ + "square yard", + "square yards", + "square yard", + "yd2" + ], + "UnitType": "area", + "Modifier": 0.8361274 + }, + { + "Triggers": [ + "square mile", + "square miles", + "square mile", + "mi2" + ], + "UnitType": "area", + "Modifier": 2589988.0 + }, + { + "Triggers": [ + "aankadam", + "aankadam", + "aankadam", + "aankadam" + ], + "UnitType": "area", + "Modifier": 6.69 + }, + { + "Triggers": [ + "perch", + "perches", + "perch", + "perch" + ], + "UnitType": "area", + "Modifier": 25.29 + }, + { + "Triggers": [ + "cent", + "cents", + "cent", + "cent" + ], + "UnitType": "area", + "Modifier": 40.47 + }, + { + "Triggers": [ + "chatak", + "chataks", + "chatak", + "chatak" + ], + "UnitType": "area", + "Modifier": 41.81 + }, + { + "Triggers": [ + "kottah", + "kottah (B)", + "kottah (B)", + "kottah (B)" + ], + "UnitType": "area", + "Modifier": 66.89 + }, + { + "Triggers": [ + "guntha", + "guntha", + "guntha", + "guntha" + ], + "UnitType": "area", + "Modifier": 101.17 + }, + { + "Triggers": [ + "ground", + "grounds", + "ground", + "ground" + ], + "UnitType": "area", + "Modifier": 222.97 + }, + { + "Triggers": [ + "marla", + "marla", + "marla", + "marla" + ], + "UnitType": "area", + "Modifier": 501.68 + }, + { + "Triggers": [ + "rood", + "roods", + "rood", + "rood" + ], + "UnitType": "area", + "Modifier": 1011.71 + }, + { + "Triggers": [ + "bigha I", + "bigha I", + "bigha I", + "bigha I" + ], + "UnitType": "area", + "Modifier": 1618.74 + }, + { + "Triggers": [ + "bigha II", + "bigha II", + "bigha II", + "bigha II" + ], + "UnitType": "area", + "Modifier": 2529.29 + }, + { + "Triggers": [ + "kanal", + "kanal", + "kanal", + "kanal" + ], + "UnitType": "area", + "Modifier": 10033.53 + }, + { + "Triggers": [ + "biswa I", + "biswa I", + "biswa I", + "biswa I" + ], + "UnitType": "area", + "Modifier": 32374.85 + }, + { + "Triggers": [ + "biswa II", + "biswa II", + "biswa II", + "biswa II" + ], + "UnitType": "area", + "Modifier": 50585.71 + }, + { + "Triggers": [ + "pascal", + "pascal", + "pascal", + "Pa" + ], + "UnitType": "pressure", + "Modifier": 1.0 + }, + { + "Triggers": [ + "torr", + "torr", + "torr", + "Torr" + ], + "UnitType": "pressure", + "Modifier": 133.3224 + }, + { + "Triggers": [ + "bar", + "bars", + "bar", + "bar" + ], + "UnitType": "pressure", + "Modifier": 100000.0 + }, + { + "Triggers": [ + "millibar", + "millibars", + "millibar", + "mb" + ], + "UnitType": "pressure", + "Modifier": 100.0 + }, + { + "Triggers": [ + "psi", + "psi", + "psi", + "lbf/in2" + ], + "UnitType": "pressure", + "Modifier": 6894.757 + }, + { + "Triggers": [ + "day", + "days", + "day", + "d" + ], + "UnitType": "time", + "Modifier": 86400.0 + }, + { + "Triggers": [ + "hour", + "hours", + "hour", + "h" + ], + "UnitType": "time", + "Modifier": 3600.0 + }, + { + "Triggers": [ + "minute", + "minutes", + "minute", + "min" + ], + "UnitType": "time", + "Modifier": 60.0 + }, + { + "Triggers": [ + "year", + "years", + "year", + "yr" + ], + "UnitType": "time", + "Modifier": 31536000.0 + }, + { + "Triggers": [ + "K", + "kelvin" + ], + "UnitType": "temperature", + "Modifier": 0.00 + }, + { + "Triggers": [ + "F", + "fahrenheit" + ], + "UnitType": "temperature", + "Modifier": 0.00 + }, + { + "Triggers": [ + "C", + "Celcius", + "Centigrade" + ], + "UnitType": "temperature", + "Modifier": 0.00 + } +] \ No newline at end of file diff --git a/src/EllieBot/data/urero.json b/src/EllieBot/data/urero.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/src/EllieBot/data/urero.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/EllieBot/data/wowjokes.json b/src/EllieBot/data/wowjokes.json new file mode 100644 index 0000000..464b56d --- /dev/null +++ b/src/EllieBot/data/wowjokes.json @@ -0,0 +1,302 @@ +[ + { + "Question": "What do you call a gnome priest", + "Answer": "A compact disc" + }, + { + "Question": "Why does the best raiding guild smell so bad?", + "Answer": "because they never wipe" + }, + { + "Question": "Why are boomkins neither overpowered or underpowered?", + "Answer": "Because they're Balanced" + }, + { + "Question": "Who is George of the Jungle's other brother?", + "Answer": "Mark of the Wild." + }, + { + "Question": "What do you call a masturbating Tauren?", + "Answer": "Beef Stroganoff." + }, + { + "Question": "What's a rogue's favourite drink?", + "Answer": "Subtle Tea" + }, + { + "Question": "Classic: What to noobs and Rogues have in common?", + "Answer": "They both pick locks!" + }, + { + "Question": "What did Gul'dan do when he tripped?", + "Answer": "He fel" + }, + { + "Question": "Why didn't the warrior cross the road?", + "Answer": "No Path Available." + }, + { + "Question": "What are the chances we have gotten the last content patch before a new expansion?", + "Answer": "Slim Tanaan" + }, + { + "Question": "A trolls greeting is usually \"Eyy mon\" but what is a goblins?", + "Answer": "\"\"Mon-eyy\"\n\n^^^^^I'm ^^^^^so ^^^^^sorry..." + }, + { + "Question": "What musician is from ICC?", + "Answer": "What musician is from ICC?\n\nAn Arthas formally known as Prince." + }, + { + "Question": "How do you know if someone's been playing since Vanilla?", + "Answer": "Don't worry, they'll tell you" + }, + { + "Question": "What happens when a demon forgets his sunscreen?", + "Answer": "He ends up with a Burning Region" + }, + { + "Question": "Why are raid guilds recruiting rogues for the illidan fight?", + "Answer": "Because they are the only ones that have the required [preparation](http://www.wowhead.com/spell=14185/preparation) " + }, + { + "Question": "How does Naxxramas fly?", + "Answer": "with it's four wings" + }, + { + "Question": "Why is the Cenarion Circle neutral?", + "Answer": "Circles have no sides." + }, + { + "Question": "Why are rogues the best bar tenders?", + "Answer": "Because they always have cheap shots " + }, + { + "Question": "What does Gul'dan like on his hotdogs?", + "Answer": "EVERYTHIIING" + }, + { + "Question": "Why did a Felhunter win the spelling competition?", + "Answer": "Nobody else could Spell Lock." + }, + { + "Question": "What do you call it when Illidan teaches demon hunters in Legion?", + "Answer": "a 'demon-stration\"" + }, + { + "Question": "Why can't Paladins work out at Planet Fitness?", + "Answer": "Because it's a Judgement-free zone. " + }, + { + "Question": "Why didn't the rogue like his dagger upgrade?", + "Answer": "He wasn't a fan of knives." + }, + { + "Question": "What do you call a Gilnean church?", + "Answer": "Worgenized religion" + }, + { + "Question": "Why were night elves chosen to be Azeroth's first astronauts?", + "Answer": "Because they know the moon well." + }, + { + "Question": "Why are gnomes unable to be paladins?", + "Answer": "Because they cannot reach the Light." + }, + { + "Question": "Did you hear about the resto druid who never plays guardian?", + "Answer": "You could say he's all bark, no bite." + }, + { + "Question": "What's a dwarf rogue's favorite car?", + "Answer": "Dodge Ram" + }, + { + "Question": "Why can you only wear 1 shoe in the Emerald nightmare?", + "Answer": "Because they'll steal Ursoc." + }, + { + "Question": "Why is it impossible for a paladin and a rogue to make a baby?", + "Answer": "Because paladins use protection and rogues do it from behind.\n\n\nTaken from Sodapoppin's stream on December 1st. " + }, + { + "Question": "Do you know how Illidan hurt his knee?", + "Answer": "(this one came through in a GM ticket response today)\n\nDo you know how Illidan hurt his knee?\nIt's simple really...\nHe fel." + }, + { + "Question": "Icecrown Citadel was a pretty cool raid.", + "Answer": "Even thinking about it gives me the chills." + }, + { + "Question": "Why do Blood Elves tan so quickly?", + "Answer": "They use the Sun Well." + }, + { + "Question": "What is Bolvar doing lately?", + "Answer": "Just chillin." + }, + { + "Question": "What do you call 4 Mogu rolling down a hill?", + "Answer": "The Rolling Stones." + }, + { + "Question": "What is Taran Zhu's favorite cooking utensil?", + "Answer": "The Shado-Pan" + }, + { + "Question": "What do you call a vapid celebrity female night elf?", + "Answer": "Kim Darnassian" + }, + { + "Question": "Warlords of Draenor was an emotional expansion.", + "Answer": "Even the raids were in tiers." + }, + { + "Question": "Why do hunters never get married?", + "Answer": "Because they're always dis-engaging." + }, + { + "Question": "What do you call a kind warlock", + "Answer": "Affection lock" + }, + { + "Question": "Which dragon has the dream job?", + "Answer": "Ysera" + }, + { + "Question": "Healers are like artists", + "Answer": "No one appreciates them until they are dead" + }, + { + "Question": "What did Illidan say when one of his group mates' gear was broken?", + "Answer": "\"YOU ARE NOT REPAIRED!\"" + }, + { + "Question": "Why do bars hate rogues?", + "Answer": "Because they only want cheap shots." + }, + { + "Question": "What did the game tell the hunter when he dinged 40?", + "Answer": "You've got mail." + }, + { + "Question": "What do you call a Blood Elf who eats his vegetables?", + "Answer": "Kale'Thas" + }, + { + "Question": "Where do murlocs store their gold and treasure?", + "Answer": "At the River Bank!" + }, + { + "Question": "Why did the undead smell bad?", + "Answer": "He had no nose." + }, + { + "Question": "How did the Rogue one-shot Illidan?", + "Answer": "By using Preparation." + }, + { + "Question": "What's the first thing Illidan sees when he wakes up?", + "Answer": "NOTHING" + }, + { + "Question": "Why are all paladins so clean?", + "Answer": "...Because they are always taking Bubble baths!" + }, + { + "Question": "did you hear about the monk serial killer", + "Answer": "the murders were pre-meditated" + }, + { + "Question": "How much does a serving of Pandaren Cuisine weigh?", + "Answer": "About wonton." + }, + { + "Question": "What injury did Gul'Dan get from playing Tennis.", + "Answer": "Twisted Nethers." + }, + { + "Question": "A patch day joke...", + "Answer": "" + }, + { + "Question": "Yo mamma so fat....", + "Answer": "I tried to shadowstep her and I got a loading screen!" + }, + { + "Question": "What do you call it when the Argent Tournament catches on fire?", + "Answer": "Burning Crusade." + }, + { + "Question": "Why can you never take a good photo of a hunter?", + "Answer": "They are always out of focus" + }, + { + "Question": "How do impoverished Warriors get their weapons?", + "Answer": "They Rend-to-own." + }, + { + "Question": "What is Arthas' favorite camping snack?", + "Answer": "Frostsmores" + }, + { + "Question": "Why are warlocks faster after drinking vodka?", + "Answer": "Because it gives them a Burning Rush!" + }, + { + "Question": "How did the druid catch a fish?", + "Answer": "With his bear hands" + }, + { + "Question": "I really want the new Grove Warden moose mount...", + "Answer": "...you could say, I consider it a moost-have." + }, + { + "Question": "Heard about the time Millhouse Manastorm went to Blackrock Foundry to visit Oregorger?", + "Answer": "Me neither, but I've been assured there will be gnome ore puns." + }, + { + "Question": "So my new maid is a rogue...", + "Answer": "... And she keeps on using [Vanish](http://www.brockaghltd.com/wp/wp-content/uploads/2014/11/31900_4.1405683094.jpg) even when I told her I prefer [Resolve](http://ecx.images-amazon.com/images/I/81a1jTSQzbL._SY355_.jpg). I'm so fed up with her!" + }, + { + "Question": "What do fire elementals eat for breakfast?", + "Answer": "Ragnar-Os" + }, + { + "Question": "Why do mages share cane's?", + "Answer": "Because it's not his cane, it's R Cane!" + }, + { + "Question": "Why do sneaky rogues prefer leather armor?", + "Answer": "because it's made of hide" + }, + { + "Question": "What's it called when an animal spirit crashes your UI?", + "Answer": "A LOA error." + }, + { + "Question": "Man the 90s take so long", + "Answer": "" + }, + { + "Question": "What is Shadow-Lord Iskar's problem?", + "Answer": "Every time we get to him in Hellfire Citadel, he always seems to be in a Fowl mood." + }, + { + "Question": "Why are hunters bad at photography?", + "Answer": "They have no focus." + }, + { + "Question": "Why are paladins good at photography?", + "Answer": "They use the Light" + }, + { + "Question": "How did the paladins get clean?", + "Answer": "They had a bubble bath!" + }, + { + "Question": "You need to be careful of the trees in this game.", + "Answer": "Some of them are shady." + } +] \ No newline at end of file diff --git a/src/EllieBot/data/xp.yml b/src/EllieBot/data/xp.yml new file mode 100644 index 0000000..c680e0b --- /dev/null +++ b/src/EllieBot/data/xp.yml @@ -0,0 +1,58 @@ +# DO NOT CHANGE +version: 6 +# How much XP will the users receive per message +xpPerMessage: 3 +# How often can the users receive XP in minutes +messageXpCooldown: 5 +# Amount of xp users gain from posting an image +xpFromImage: 0 +# Average amount of xp earned per minute in VC +voiceXpPerMinute: 0 +# The maximum amount of minutes the bot will keep track of a user in a voice channel +voiceMaxMinutes: 720 +# The amount of currency users will receive for each point of global xp that they earn +currencyPerXp: 0 +# Xp Shop config +shop: + # Whether the xp shop is enabled + # True -> Users can access the xp shop using .xpshop command + # False -> Users can't access the xp shop + isEnabled: false + # Which patron tier do users need in order to use the .xpshop bgs command + # Leave at 'None' if patron system is disabled or you don't want any restrictions + bgsTierRequirement: None + # Which patron tier do users need in order to use the .xpshop frames command + # Leave at 'None' if patron system is disabled or you don't want any restrictions + framesTierRequirement: None + # Frames available for sale. Keys are unique IDs. + # Do not change keys as they are not publicly visible. Only change properties (name, price, id) + # Removing a key which previously existed means that all previous purchases will also be unusable. + # To remove an item from the shop, but keep previous purchases, set the price to -1 + frames: + default: + # Visible name of the item + name: No frame + # Price of the item. Set to -1 if you no longer want to sell the item but want the users to be able to keep their old purchase + price: 0 + # Direct url to the .png image which will be applied to the user's XP card + url: "" + # Optional preview url which will show instead of the real URL in the shop + preview: + # Optional description of the item + desc: + # Backgrounds available for sale. Keys are unique IDs. + # Do not change keys as they are not publicly visible. Only change properties (name, price, id) + # Removing a key which previously existed means that all previous purchases will also be unusable. + # To remove an item from the shop, but keep previous purchases, set the price to -1 + bgs: + default: + # Visible name of the item + name: Default Background + # Price of the item. Set to -1 if you no longer want to sell the item but want the users to be able to keep their old purchase + price: 0 + # Direct url to the .png image which will be applied to the user's XP card + url: "" + # Optional preview url which will show instead of the real URL in the shop + preview: + # Optional description of the item + desc: diff --git a/src/EllieBot/data/xp_template.json b/src/EllieBot/data/xp_template.json new file mode 100644 index 0000000..df7f289 --- /dev/null +++ b/src/EllieBot/data/xp_template.json @@ -0,0 +1,145 @@ +{ + "Version": 1, + "output_size": { + "X": 800, + "Y": 392 + }, + "User": { + "Name": { + "Color": "ffffffff", + "Show": true, + "FontSize": 50, + "Pos": { + "X": 105, + "Y": 25 + } + }, + "Icon": { + "Show": true, + "Pos": { + "X": 14, + "Y": 14 + }, + "Size": { + "X": 72, + "Y": 71 + } + }, + "GlobalLevel": { + "Color": "ffffffff", + "Show": true, + "FontSize": 45, + "Pos": { + "X": 47, + "Y": 160 + } + }, + "GuildLevel": { + "Color": "ffffffff", + "Show": true, + "FontSize": 45, + "Pos": { + "X": 47, + "Y": 308 + } + }, + "GlobalRank": { + "Color": "ffffffff", + "Show": true, + "FontSize": 30, + "Pos": { + "X": 148, + "Y": 179 + } + }, + "GuildRank": { + "Color": "ffffffff", + "Show": true, + "FontSize": 30, + "Pos": { + "X": 148, + "Y": 326 + } + }, + "Xp": { + "Bar": { + "Show": true, + "Global": { + "Color": "00000095", + "PointA": { + "X": 321, + "Y": 104 + }, + "PointB": { + "X": 286, + "Y": 235 + }, + "Length": 450, + "Direction": 3 + }, + "Guild": { + "Color": "00000095", + "PointA": { + "X": 282, + "Y": 248 + }, + "PointB": { + "X": 247, + "Y": 379 + }, + "Length": 450, + "Direction": 3 + } + }, + "Global": { + "Color": "ffffffff", + "Show": true, + "FontSize": 50, + "Pos": { + "X": 528, + "Y": 170 + } + }, + "Guild": { + "Color": "ffffffff", + "Show": true, + "FontSize": 50, + "Pos": { + "X": 490, + "Y": 313 + } + }, + "Awarded": { + "Color": "ffffffff", + "Show": true, + "FontSize": 25, + "Pos": { + "X": 450, + "Y": 345 + } + } + } + }, + "Club": { + "Icon": { + "Show": true, + "Pos": { + "X": 722, + "Y": 25 + }, + "Size": { + "X": 45, + "Y": 45 + } + }, + "Name": { + "Color": "ffffffff", + "Show": true, + "FontSize": 35, + "Pos": { + "X": 650, + "Y": 55 + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/data/yomama.txt b/src/EllieBot/data/yomama.txt new file mode 100644 index 0000000..6071aca --- /dev/null +++ b/src/EllieBot/data/yomama.txt @@ -0,0 +1,170 @@ +Yo mama is so fat that her bellybutton gets home 15 minutes before she does. +Yo mama is so fat that when she was diagnosed with a flesh-eating disease, the doctor gave her ten years to live. +Yo mama is so fat that the National Weather Service names each one of her farts. +Yo mama is so fat that when she wears a yellow raincoat, people yell "taxi!" +Yo mama is so fat and dumb that the only reason she opened her email was because she heard it contained spam. +Yo mama is so fat she threw on a sheet for Halloween and went as Antarctica. +Yo mama is so fat that she looked up cheat codes for Wii Fit +Yo mama is so fat that the only exercise she gets is when she chases the ice cream truck. +Yo mama is so fat that she sat on a dollar and squeezed a booger out George Washington's nose. +Yo mama is so fat that when she gets in an elevator, it has to go down. +Yo mama is so fat that when her beeper goes off, people think she's backing up. +Yo mama is so fat that she has to iron her pants on the driveway. +Yo mama is so fat that she left the house in high heels and came back wearing flip flops. +Yo mama is so fat that people jog around her for exercise. +Yo mama is so fat that she was floating in the ocean and Spain claimed her for the New World. +Yo mama is so fat that when she walked in front of the TV, I missed 3 seasons of Breaking Bad. +Yo mama is so fat that you have to grease the door frame and hold a twinkie on the other side just to get her through! +Yo mama is so fat that that when she sits on the beach, Greenpeace shows up and tries to tow her back into the ocean... +Yo mama is so fat that when she bungee jumps, she brings down the bridge too. +Yo mama is so fat that when she talks to herself, it's a long distance call. +Yo mama is so fat that the last time she saw 90210, it was on a scale. +Yo mama is so fat that light bends around her. +Yo mama is so fat that I took a picture of her last Christmas and it's still printing! +Yo mama is so fat that when she sat on Wal-Mart, she lowered the prices. +Yo mama is so fat that when she sat on an iphone, it turned into an ipad. +Yo mama is so fat that even god can't lift her spirit. +Yo mama is so fat that she gets group insurance. +Yo mama is so fat that she was zoned for commercial development. +Yo mama is so fat that she walked into the Gap and filled it. +Yo mama is so fat that she comes at you from all directions. +Yo mama is so fat that when she climbed onto a diving board at the beach, the lifeguard told your dad "sorry, you can't park here". +Yo mama is so fat that her cereal bowl came with a lifeguard. +Yo mama is so fat that she looks like shegs smuggling a Volkswagen. +Yo mama is so fat that when she got her shoes shined, she had to take the guygs word for it. +Yo mama is so fat that when she sings, itgs over for everybody. +Yo mama is so fat that when she ran away, they had to use all four sides of the milk carton to display her picture. +Yo mama is so fat that when she was growing up she didngt play with dolls, she played with midgets. +Yo mama is so fat that she uses two buses for roller-blades. +Yo mama's so fat she blew up the Deathstar. +Yo mama is so fat that when she goes to a buffet, she gets the group rate. +Yo mama is so fat that she has to put her belt on with a boomerang. +Yo mama is so fat that she broke the Stairway to Heaven. +Yo mama is so fat that she doesngt eat with a fork, she eats with a forklift. +Yo mama is so fat that the last time the landlord saw her, he doubled the rent. +Yo mama is so fat that Weight Watchers wongt look at her. +Yo mama is so fat that the highway patrol made her wear a sign saying "Caution! Wide Turn". +Yo mama is so fat that when she sits around the house, she SITS AROUND THE HOUSE! +Yo mama is so fat that when she steps on a scale, it reads "one at a time, please". +Yo mama is so fat that she fell in love and broke it. +Yo mama is so fat that when she gets on the scale it says "We don't do livestock". +Yo mama is so fat that when she tripped on 4th Ave, she landed on 12th. +Yo mama is so fat that God couldn't light the Earth until she moved! +Yo mama is so fat that even Bill Gates couldn't pay for her liposuction! +Yo mama is so fat that she has to pull down her pants to get into her pockets. +Yo mama is so fat that she was born on the fourth, fifth, and sixth of June. +Yo mama is so fat that she could fall down and wouldngt even know it. +Yo mama is so fat that the sign inside one restaurant says, “Maximum occupancy: 300, or Yo momma.” +Yo mama is so fat that she puts mayonnaise on aspirin. +Yo mama is so fat that she was born with a silver shovel in her mouth. +Yo mama is so fat that when she hauls ass, she has to make two trips. +Yo mama is so fat that she had to go to Sea World to get baptized. +Yo mama is so fat that her bellybuttons got an echo. +Yo mama is so fat that when she turns around people throw her a welcome back party. +Yo mama is so fat that her belly button doesngt have lint, it has sweaters. +Yo mama is so fat that a picture of her would fall off the wall. +Yo mama is so fat that when she takes a shower, her feet dongt get wet. +Yo mama is so fat that she puts on her lipstick with a paint-roller! +Yo mama is so fat that she could sell shade. +Yo mama is so fat that I ran around her twice and got lost. +Yo mama is so fat that the shadow of her butt weighs 100 pounds. +Yo mama is so fat that when shegs standing on the corner police drive by and yell, “Hey, break it up.” +Yo mama is so fat that her blood type is Ragu. +Yo mama is so fat that when she runs the fifty-yard dash she needs an overnight bag. +Yo mama is so fat that she cangt even fit into an AOL chat room. +Yo mama is so fat when she goes skydiving she doesn't use a parachute to land, she uses a twin-engine plane! +Yo mama is so fat MTX audio's subwoofers couldn't rattle her bones! +Yo mama is so fat her headphones are a pair of PA speakers connected to a car amplifier. +Yo mama is so fat that she doesngt have a tailor, she has a contractor. +Yo mama is so fat that eating contests have banned her because she is unfair competition. +Yo mama is so fat that she measures 36-24-36, and the other arm is just as big. +Yo mama is so fat that she gets her toenails painted at Luckygs Auto Body. +Yo mama is so fat that when she goes to an amusement park, people try to ride HER! +Yo mama is so fat that when she jumps up in the air she gets stuck! +Yo mama is so fat that she has more Chins than a Chinese phone book! +Yo mama is so fat that she influences the tides. +Yo mama is so fat that when she plays hopscotch, she goes "New York, L.A., Chicago..." +Yo mama is so fat that NASA has to orbit a satellite around her! +Yo mama is so fat that when she sits on my face I can't hear the stereo. +Yo mama is so fat that they have to grease the bath tub to get her out! +Yo mama is so fat that she's on both sides of the family! +Yo mama is so fat that at the zoo, the elephants throw HER peanuts. +Yo mama is so fat you have to roll over twice to get off her. +Yo mama is so fat that she sets off car alarms when she runs. +Yo mama is so fat that she cant reach into her back pocket. +Yo mama is so fat that she has her own gravity field. +Yo mama is so fat that she stepped on a rainbow and made Skittles. +Yo mama is so fat that the only pictures you have of her were taken by satellite cameras. +Yo mama is so fat that when she wears a "Malcolm X" T-shirt, helicopters try to land on her back! +Yo mama is so fat that it took Usain Bolt 3 years to run around her. +Yo mama so fat that she sweats more than a dog in a chinese restaurant. +Yo mama so fat, that went she stepped in the water, Thailand had to declare another tsunami warning. +Yo mama is so fat that that she cant tie her own shoes. +Yo mama is so fat that when she lays on the beach, people run around yelling Free Willy. +Yo mama is so fat that she uses redwoods to pick her teeth +Yo mama is so fat that she cut her leg and gravy poured out +Yo mama is so fat that she was in the Macygs Thanksgiving Day Parade... wearing ropes. +Yo mama is so fat that she went on a light diet. As soon as itgs light she starts eating. +Yo mama is so fat that shegs half Italian, half Irish, and half American. +Yo mama is so fat that her waist size is the Equator. +Yo mama is so fat that she cangt even jump to a conclusion. +Yo mama is so fat that she uses a mattress for a tampon. +Yo mama is so fat that when she got hit by a bus, she said, "Who threw that rock at me?" +Yo mama is so fat that we went to the drive-in and didn't have to pay for her because we dressed her up as a Toyota. +Yo mama is so fat that when she was born, she gave the hospital stretch marks. +Yo mama is so fat that she was cut from the cast of E.T., because she caused an eclipse when she rode the bike across the moon. +Yo mama is so fat that when you get on top of her your ears pop. +Yo mama is so fat that she got hit by a car and had to go to the hospital to have it removed. +Yo mama is so fat that she eats "Wheat Thicks". +Yo mama is so fat that we're in her right now! +Yo mama is so fat that she went to the movie theatre and sat next to everyone. +Yo mama is so fat that she has been declared a natural habitat for condors. +Yo mama is so fat that when she wants to shake someones hand, she has to give directions! +Yo mama is so fat that even Dora can't explore her! +Yo mama is so fat that when she gets on the scale it says "to be continued". +Yo mama is so fat that when she goes to a resturant, she looks at the menu and says "okay!" +Yo mama is so fat that even Chuck Norris couldn't run around her. +Yo mama is so fat that her neck looks like a dozen hot dogs! +Yo mama is so fat that when she bungee jumps she goes straight to hell! +Yo mama is so fat that she's got her own area code! +Yo mama is so fat that she looks like she's smuggling a Volkswagon! +Yo mama is so fat that she has to buy three airline tickets. +Yo mama is so fat that whenever she goes to the beach the tide comes in! +Yo mama is so fat that she's got Amtrak written on her leg. +Yo mama is so fat that her legs are like spoiled milk - white & chunky! +Yo mama is so fat that I had to take a train and two buses just to get on the her good side! +Yo mama is so fat that she wakes up in sections! +Yo mama so fat, all she wants for Christmas is to see her feet. +Yo mama is so fat that when she lies on the beach no one else gets any sun! +Yo mama is so fat that that her senior pictures had to be taken from a helicopter! +Yo mama is so fat that everytime she walks in high heels, she strikes oil! +Yo mama is so fat that she fell and created the Grand Canyon! +Yo mama is so fat that her butt drags on the ground and kids yell - "there goes santa claus with his bag of toys!" +Yo mama is so fat that even her clothes have stretch marks! +Yo mama is so fat that she has to use a VCR as a beeper! +Yo mama is so fat that when she asked for a waterbed, they put a blanket over the ocean! +Yo mama is so fat that she got hit by a parked car! +Yo mama is so fat that they use the elastic in her underwear for bungee jumping. +Yo mama is so fat that when we were playing Call of Duty, I got a 20 kill streak for killing her. +Yo mama is so fat that Dracula got Type 2 Diabetes after biting her neck. +Yo mama is so fat that when she visited Toronto's City Hall, she was arrested for attempting to smuggle 500 lbs of crack into Mayor Rob Ford's office. +Yo mama is so fat that when she fell over she rocked herself asleep trying to get up again. +Yo mama is so fat that that when I tried to drive around her I ran out of gas. +Yo mama is so fat that when she went to church and sat on a bible, Jesus came out and said "LET MY PEOPLE GO!" +Yo mama is so fat that when she dances at a concert the whole band skips. +Yo mama is so fat that she stands in two time zones. +Yo mama is so fat that she went to the fair and the kids thought she was a bouncy castle. +Yo mama is so fat that when she goes to an all you can eat buffet, they have to install speed bumps. +Yo mama is so fat that the camera TAKES AWAY 10 lbs from her appearance. +Yo mama is so fat that her sedan can fit 5 people... or just yo mama with the front seats removed. +Yo mama is so fat that when she went to seaworld the whales started singing "We Are Family". +Yo mama is so fat that she fell out of both sides of her bed. +Yo mama is so fat that the stripes on her pajamas never end. +Yo mama is so fat, Al Gore accuses her of global warning everytime she farts! +Yo mama is so fat that she's got every caterer in the city on speed dial! +Yo mama's so fat that when she goes on a scale, it shows her own phone number. +Yo mama's so fat that she doesn't need the internet - she's worldwide. +Yo mama's so fat that when she goes on a scale, it reads "lose some weight". +Yo mama's so fat that she doesn't get dreams, she gets movies! +Yo mama's so fat that when she walks, she changes the earth's rotation! +Yo mama is so fat that she uses the entire country of Mexico as her tanning bed. \ No newline at end of file From 8157d92fdfd21abdf17399840281aa3b6f9dcee4 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 27 Mar 2024 01:32:17 +1300 Subject: [PATCH 12/62] Added some common files --- src/EllieBot/Common/Attributes/Aliases.cs | 12 ++ .../Attributes/CommandNameLoadHelper.cs | 31 +++ .../DontAddToIocContainerAttribute.cs | 11 ++ .../Common/Attributes/EllieCommand.cs | 18 ++ .../Common/Attributes/EllieOptions.cs | 10 + .../Attributes/NoPublicBotPrecondition.cs | 38 ++++ .../Common/Attributes/OwnerOnlyAttribute.cs | 19 ++ src/EllieBot/Common/Attributes/Ratelimit.cs | 38 ++++ src/EllieBot/Common/Attributes/UserPerm.cs | 30 +++ .../Common/Cache/BotCacheExtensions.cs | 46 +++++ src/EllieBot/Common/Cache/IBotCache.cs | 47 +++++ src/EllieBot/Common/Cache/MemoryBotCache.cs | 71 +++++++ src/EllieBot/Common/Cache/RedisBotCache.cs | 119 +++++++++++ src/EllieBot/Common/Configs/BotConfig.cs | 185 ++++++++++++++++++ src/EllieBot/Common/Configs/IConfigSeria.cs | 18 ++ .../Common/ModuleBehaviors/IExecNoCommand.cs | 19 ++ .../Common/ModuleBehaviors/IExecOnMessage.cs | 21 ++ .../ModuleBehaviors/IExecPostCommand.cs | 22 +++ .../Common/ModuleBehaviors/IExecPreCommand.cs | 25 +++ .../ModuleBehaviors/IInputTransformer.cs | 25 +++ .../Common/ModuleBehaviors/IReadyExecutor.cs | 13 ++ src/EllieBot/Common/Yml/CommentAttribute.cs | 11 ++ .../Yml/CommentGatheringTypeInspector.cs | 65 ++++++ .../Common/Yml/CommentsObjectDescriptor.cs | 30 +++ .../Common/Yml/CommentsObjectGraphVisitor.cs | 29 +++ .../Yml/MultilineScalarFlowStyleEmitter.cs | 35 ++++ src/EllieBot/Common/Yml/Rgba32Converter.cs | 47 +++++ src/EllieBot/Common/Yml/UriConverter.cs | 25 +++ src/EllieBot/Common/Yml/Yaml.cs | 28 +++ src/EllieBot/Common/Yml/YamlHelper.cs | 48 +++++ 30 files changed, 1136 insertions(+) create mode 100644 src/EllieBot/Common/Attributes/Aliases.cs create mode 100644 src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs create mode 100644 src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs create mode 100644 src/EllieBot/Common/Attributes/EllieCommand.cs create mode 100644 src/EllieBot/Common/Attributes/EllieOptions.cs create mode 100644 src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs create mode 100644 src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs create mode 100644 src/EllieBot/Common/Attributes/Ratelimit.cs create mode 100644 src/EllieBot/Common/Attributes/UserPerm.cs create mode 100644 src/EllieBot/Common/Cache/BotCacheExtensions.cs create mode 100644 src/EllieBot/Common/Cache/IBotCache.cs create mode 100644 src/EllieBot/Common/Cache/MemoryBotCache.cs create mode 100644 src/EllieBot/Common/Cache/RedisBotCache.cs create mode 100644 src/EllieBot/Common/Configs/BotConfig.cs create mode 100644 src/EllieBot/Common/Configs/IConfigSeria.cs create mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs create mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs create mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs create mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs create mode 100644 src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs create mode 100644 src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs create mode 100644 src/EllieBot/Common/Yml/CommentAttribute.cs create mode 100644 src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs create mode 100644 src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs create mode 100644 src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs create mode 100644 src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs create mode 100644 src/EllieBot/Common/Yml/Rgba32Converter.cs create mode 100644 src/EllieBot/Common/Yml/UriConverter.cs create mode 100644 src/EllieBot/Common/Yml/Yaml.cs create mode 100644 src/EllieBot/Common/Yml/YamlHelper.cs diff --git a/src/EllieBot/Common/Attributes/Aliases.cs b/src/EllieBot/Common/Attributes/Aliases.cs new file mode 100644 index 0000000..14df34a --- /dev/null +++ b/src/EllieBot/Common/Attributes/Aliases.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class AliasesAttribute : AliasAttribute +{ + public AliasesAttribute([CallerMemberName] string memberName = "") + : base(CommandNameLoadHelper.GetAliasesFor(memberName)) + { + } +} diff --git a/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs b/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs new file mode 100644 index 0000000..e77533d --- /dev/null +++ b/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs @@ -0,0 +1,31 @@ +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Attributes; + +public static class CommandNameLoadHelper +{ + private static readonly IDeserializer _deserializer = new Deserializer(); + + private static readonly Lazy> _lazyCommandAliases + = new(() => LoadAliases()); + + public static Dictionary LoadAliases(string aliasesFilePath = "data/aliases.yml") + { + var text = File.ReadAllText(aliasesFilePath); + return _deserializer.Deserialize>(text); + } + + public static string[] GetAliasesFor(string methodName) + => _lazyCommandAliases.Value.TryGetValue(methodName.ToLowerInvariant(), out var aliases) && aliases.Length > 1 + ? aliases.Skip(1).ToArray() + : Array.Empty(); + + public static string GetCommandNameFor(string methodName) + { + methodName = methodName.ToLowerInvariant(); + var toReturn = _lazyCommandAliases.Value.TryGetValue(methodName, out var aliases) && aliases.Length > 0 + ? aliases[0] + : methodName; + return toReturn; + } +} diff --git a/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs b/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs new file mode 100644 index 0000000..666ebbe --- /dev/null +++ b/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Common; + +///

+/// Classed marked with this attribute will not be added to the service provider +/// +[AttributeUsage(AttributeTargets.Class)] +public class DontAddToIocContainerAttribute : Attribute +{ + +} diff --git a/src/EllieBot/Common/Attributes/EllieCommand.cs b/src/EllieBot/Common/Attributes/EllieCommand.cs new file mode 100644 index 0000000..109c1c5 --- /dev/null +++ b/src/EllieBot/Common/Attributes/EllieCommand.cs @@ -0,0 +1,18 @@ +using System.Runtime.CompilerServices; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class CmdAttribute : CommandAttribute +{ + public string MethodName { get; } + + public CmdAttribute([CallerMemberName] string memberName = "") + : base(CommandNameLoadHelper.GetCommandNameFor(memberName)) + { + MethodName = memberName.ToLowerInvariant(); + Aliases = CommandNameLoadHelper.GetAliasesFor(memberName); + Remarks = memberName.ToLowerInvariant(); + Summary = memberName.ToLowerInvariant(); + } +} diff --git a/src/EllieBot/Common/Attributes/EllieOptions.cs b/src/EllieBot/Common/Attributes/EllieOptions.cs new file mode 100644 index 0000000..32f91df --- /dev/null +++ b/src/EllieBot/Common/Attributes/EllieOptions.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class EllieOptionsAttribute : Attribute +{ + public Type OptionType { get; set; } + + public EllieOptionsAttribute(Type t) + => OptionType = t; +} \ No newline at end of file diff --git a/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs b/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs new file mode 100644 index 0000000..d380a92 --- /dev/null +++ b/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs @@ -0,0 +1,38 @@ +#nullable disable +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Common; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +[SuppressMessage("Style", "IDE0022:Use expression body for methods")] +public sealed class NoPublicBotAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { +#if GLOBAL_ELLIE + return Task.FromResult(PreconditionResult.FromError("Not available on the public bot. To learn how to selfhost a private bot, click [here](https://docs.elliebot.net/v4/).")); +#else + return Task.FromResult(PreconditionResult.FromSuccess()); +#endif + } +} + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +[SuppressMessage("Style", "IDE0022:Use expression body for methods")] +public sealed class OnlyPublicBotAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { +#if GLOBAL_ELLIE || DEBUG + return Task.FromResult(PreconditionResult.FromSuccess()); +#else + return Task.FromResult(PreconditionResult.FromError("Only available on the public bot.")); +#endif + } +} diff --git a/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs b/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs new file mode 100644 index 0000000..7aa9317 --- /dev/null +++ b/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public sealed class OwnerOnlyAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + var creds = services.GetRequiredService().GetCreds(); + + return Task.FromResult(creds.IsOwner(context.User) || context.Client.CurrentUser.Id == context.User.Id + ? PreconditionResult.FromSuccess() + : PreconditionResult.FromError("Not owner")); + } +} diff --git a/src/EllieBot/Common/Attributes/Ratelimit.cs b/src/EllieBot/Common/Attributes/Ratelimit.cs new file mode 100644 index 0000000..9a8c887 --- /dev/null +++ b/src/EllieBot/Common/Attributes/Ratelimit.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class RatelimitAttribute : PreconditionAttribute +{ + public int Seconds { get; } + + public RatelimitAttribute(int seconds) + { + if (seconds <= 0) + throw new ArgumentOutOfRangeException(nameof(seconds)); + + Seconds = seconds; + } + + public override async Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + if (Seconds == 0) + return PreconditionResult.FromSuccess(); + + var cache = services.GetRequiredService(); + var rem = await cache.GetRatelimitAsync( + new($"precondition:{context.User.Id}:{command.Name}"), + Seconds.Seconds()); + + if (rem is null) + return PreconditionResult.FromSuccess(); + + var msgContent = $"You can use this command again in {rem.Value.TotalSeconds:F1}s."; + + return PreconditionResult.FromError(msgContent); + } +} diff --git a/src/EllieBot/Common/Attributes/UserPerm.cs b/src/EllieBot/Common/Attributes/UserPerm.cs new file mode 100644 index 0000000..dd2e7b5 --- /dev/null +++ b/src/EllieBot/Common/Attributes/UserPerm.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Modules.Administration.Services; + +namespace Discord; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public class UserPermAttribute : RequireUserPermissionAttribute +{ + public UserPermAttribute(GuildPerm permission) + : base(permission) + { + } + + public UserPermAttribute(ChannelPerm permission) + : base(permission) + { + } + + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + var permService = services.GetRequiredService(); + if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out _)) + return Task.FromResult(PreconditionResult.FromSuccess()); + + return base.CheckPermissionsAsync(context, command, services); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Cache/BotCacheExtensions.cs b/src/EllieBot/Common/Cache/BotCacheExtensions.cs new file mode 100644 index 0000000..41c6066 --- /dev/null +++ b/src/EllieBot/Common/Cache/BotCacheExtensions.cs @@ -0,0 +1,46 @@ +using OneOf; +using OneOf.Types; + +namespace EllieBot.Common; + +public static class BotCacheExtensions +{ + public static async ValueTask GetOrDefaultAsync(this IBotCache cache, TypedKey key) + { + var result = await cache.GetAsync(key); + if (result.TryGetValue(out var val)) + return val; + + return default; + } + + private static TypedKey GetImgKey(Uri uri) + => new($"image:{uri}"); + + public static ValueTask SetImageDataAsync(this IBotCache c, string key, byte[] data) + => c.SetImageDataAsync(new Uri(key), data); + public static async ValueTask SetImageDataAsync(this IBotCache c, Uri key, byte[] data) + => await c.AddAsync(GetImgKey(key), data, expiry: TimeSpan.FromHours(48)); + + public static async ValueTask> GetImageDataAsync(this IBotCache c, Uri key) + => await c.GetAsync(GetImgKey(key)); + + public static async Task GetRatelimitAsync( + this IBotCache c, + TypedKey key, + TimeSpan length) + { + var now = DateTime.UtcNow; + var nowB = now.ToBinary(); + + var cachedValue = await c.GetOrAddAsync(key, + () => Task.FromResult(now.ToBinary()), + expiry: length); + + if (cachedValue == nowB) + return null; + + var diff = now - DateTime.FromBinary(cachedValue); + return length - diff; + } +} diff --git a/src/EllieBot/Common/Cache/IBotCache.cs b/src/EllieBot/Common/Cache/IBotCache.cs new file mode 100644 index 0000000..e1ea2c9 --- /dev/null +++ b/src/EllieBot/Common/Cache/IBotCache.cs @@ -0,0 +1,47 @@ +using OneOf; +using OneOf.Types; + +namespace EllieBot.Common; + +public interface IBotCache +{ + /// + /// Adds an item to the cache + /// + /// Key to add + /// Value to add to the cache + /// Optional expiry + /// Whether old value should be overwritten + /// Type of the value + /// Returns whether add was sucessful. Always true unless ovewrite = false + ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true); + + /// + /// Get an element from the cache + /// + /// Key + /// Type of the value + /// Either a value or + ValueTask> GetAsync(TypedKey key); + + /// + /// Remove a key from the cache + /// + /// Key to remove + /// Type of the value + /// Whether there was item + ValueTask RemoveAsync(TypedKey key); + + /// + /// Get the key if it exists or add a new one + /// + /// Key to get and potentially add + /// Value creation factory + /// Optional expiry + /// Type of the value + /// The retrieved or newly added value + ValueTask GetOrAddAsync( + TypedKey key, + Func> createFactory, + TimeSpan? expiry = null); +} diff --git a/src/EllieBot/Common/Cache/MemoryBotCache.cs b/src/EllieBot/Common/Cache/MemoryBotCache.cs new file mode 100644 index 0000000..d0b7e68 --- /dev/null +++ b/src/EllieBot/Common/Cache/MemoryBotCache.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.Caching.Memory; +using OneOf; +using OneOf.Types; + +// ReSharper disable InconsistentlySynchronizedField + +namespace EllieBot.Common; + +public sealed class MemoryBotCache : IBotCache +{ + // needed for overwrites and Delete return value + private readonly object _cacheLock = new object(); + private readonly MemoryCache _cache; + + public MemoryBotCache() + { + _cache = new MemoryCache(new MemoryCacheOptions()); + } + + public ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) + { + if (overwrite) + { + using var item = _cache.CreateEntry(key.Key); + item.Value = value; + item.AbsoluteExpirationRelativeToNow = expiry; + return new(true); + } + + lock (_cacheLock) + { + if (_cache.TryGetValue(key.Key, out var old) && old is not null) + return new(false); + + using var item = _cache.CreateEntry(key.Key); + item.Value = value; + item.AbsoluteExpirationRelativeToNow = expiry; + return new(true); + } + } + + public async ValueTask GetOrAddAsync( + TypedKey key, + Func> createFactory, + TimeSpan? expiry = null) + => await _cache.GetOrCreateAsync(key.Key, + async ce => + { + ce.AbsoluteExpirationRelativeToNow = expiry; + var val = await createFactory(); + return val; + }); + + public ValueTask> GetAsync(TypedKey key) + { + if (!_cache.TryGetValue(key.Key, out var val) || val is null) + return new(new None()); + + return new((T)val); + } + + public ValueTask RemoveAsync(TypedKey key) + { + lock (_cacheLock) + { + var toReturn = _cache.TryGetValue(key.Key, out var old) && old is not null; + _cache.Remove(key.Key); + return new(toReturn); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Cache/RedisBotCache.cs b/src/EllieBot/Common/Cache/RedisBotCache.cs new file mode 100644 index 0000000..8de00fe --- /dev/null +++ b/src/EllieBot/Common/Cache/RedisBotCache.cs @@ -0,0 +1,119 @@ +using OneOf; +using OneOf.Types; +using StackExchange.Redis; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Common; + +public sealed class RedisBotCache : IBotCache +{ + private static readonly Type[] _supportedTypes = new[] + { + typeof(bool), typeof(int), typeof(uint), typeof(long), + typeof(ulong), typeof(float), typeof(double), + typeof(string), typeof(byte[]), typeof(ReadOnlyMemory), typeof(Memory), + typeof(RedisValue), + }; + + private static readonly JsonSerializerOptions _opts = new() + { + PropertyNameCaseInsensitive = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + AllowTrailingCommas = true, + IgnoreReadOnlyProperties = false, + }; + private readonly ConnectionMultiplexer _conn; + + public RedisBotCache(ConnectionMultiplexer conn) + { + _conn = conn; + } + + public async ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) + { + // if a null value is passed, remove the key + if (value is null) + { + await RemoveAsync(key); + return false; + } + + var db = _conn.GetDatabase(); + RedisValue val = IsSupportedType(typeof(T)) + ? RedisValue.Unbox(value) + : JsonSerializer.Serialize(value, _opts); + + var success = await db.StringSetAsync(key.Key, + val, + expiry: expiry, + when: overwrite ? When.Always : When.NotExists); + + return success; + } + + public bool IsSupportedType(Type type) + { + if (type.IsGenericType) + { + var typeDef = type.GetGenericTypeDefinition(); + if (typeDef == typeof(Nullable<>)) + return IsSupportedType(type.GenericTypeArguments[0]); + } + + foreach (var t in _supportedTypes) + { + if (type == t) + return true; + } + + return false; + } + + public async ValueTask> GetAsync(TypedKey key) + { + var db = _conn.GetDatabase(); + var val = await db.StringGetAsync(key.Key); + if (val == default) + return new None(); + + if (IsSupportedType(typeof(T))) + return (T)((IConvertible)val).ToType(typeof(T), null); + + return JsonSerializer.Deserialize(val.ToString(), _opts)!; + } + + public async ValueTask RemoveAsync(TypedKey key) + { + var db = _conn.GetDatabase(); + + return await db.KeyDeleteAsync(key.Key); + } + + public async ValueTask GetOrAddAsync(TypedKey key, Func> createFactory, TimeSpan? expiry = null) + { + var result = await GetAsync(key); + + return await result.Match>( + v => Task.FromResult(v), + async _ => + { + var factoryValue = await createFactory(); + + if (factoryValue is null) + return default; + + await AddAsync(key, factoryValue, expiry); + + // get again to make sure it's the cached value + // and not the late factory value, in case there's a race condition + + var newResult = await GetAsync(key); + + // it's fine to do this, it should blow up if something went wrong. + return newResult.Match( + v => v, + _ => default); + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Configs/BotConfig.cs b/src/EllieBot/Common/Configs/BotConfig.cs new file mode 100644 index 0000000..80186a9 --- /dev/null +++ b/src/EllieBot/Common/Configs/BotConfig.cs @@ -0,0 +1,185 @@ +#nullable disable +using Cloneable; +using EllieBot.Common.Yml; +using SixLabors.ImageSharp.PixelFormats; +using System.Globalization; +using YamlDotNet.Core; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Configs; + +[Cloneable] +public sealed partial class BotConfig : ICloneable +{ + [Comment(@"DO NOT CHANGE")] + public int Version { get; set; } = 5; + + [Comment(@"Most commands, when executed, have a small colored line +next to the response. The color depends whether the command +is completed, errored or in progress (pending) +Color settings below are for the color of those lines. +To get color's hex, you can go here https://htmlcolorcodes.com/ +and copy the hex code fo your selected color (marked as #)")] + public ColorConfig Color { get; set; } + + [Comment("Default bot language. It has to be in the list of supported languages (.langli)")] + public CultureInfo DefaultLocale { get; set; } + + [Comment(@"Style in which executed commands will show up in the console. +Allowed values: Simple, Normal, None")] + public ConsoleOutputType ConsoleOutputType { get; set; } + + [Comment(@"Whether the bot will check for new releases every hour")] + public bool CheckForUpdates { get; set; } = true; + + [Comment(@"Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?")] + public bool ForwardMessages { get; set; } + + [Comment( + @"Do you want the message to be forwarded only to the first owner specified in the list of owners (in creds.yml), +or all owners? (this might cause the bot to lag if there's a lot of owners specified)")] + public bool ForwardToAllOwners { get; set; } + + [Comment(@"Any messages sent by users in Bot's DM to be forwarded to the specified channel. +This option will only work when ForwardToAllOwners is set to false")] + public ulong? ForwardToChannel { get; set; } + + [Comment(@"When a user DMs the bot with a message which is not a command +they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. +Supports embeds. How it looks: https://puu.sh/B0BLV.png")] + [YamlMember(ScalarStyle = ScalarStyle.Literal)] + public string DmHelpText { get; set; } + + [Comment(@"Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response. +Case insensitive. +Leave empty to reply with DmHelpText to every DM.")] + public List DmHelpTextKeywords { get; set; } + + [Comment(@"This is the response for the .h command")] + [YamlMember(ScalarStyle = ScalarStyle.Literal)] + public string HelpText { get; set; } + + [Comment(@"List of modules and commands completely blocked on the bot")] + public BlockedConfig Blocked { get; set; } + + [Comment(@"Which string will be used to recognize the commands")] + public string Prefix { get; set; } + + [Comment(@"Toggles whether your bot will group greet/bye messages into a single message every 5 seconds. +1st user who joins will get greeted immediately +If more users join within the next 5 seconds, they will be greeted in groups of 5. +This will cause %user.mention% and other placeholders to be replaced with multiple users. +Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail, +it will become invalid, as it will resolve to a list of avatars of grouped users. +note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some + servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited, + and (slightly) reduce the greet spam in those servers.")] + public bool GroupGreets { get; set; } + + [Comment(@"Whether the bot will rotate through all specified statuses. +This setting can be changed via .ropl command. +See RotatingStatuses submodule in Administration.")] + public bool RotateStatuses { get; set; } + + public BotConfig() + { + var color = new ColorConfig(); + Color = color; + DefaultLocale = new("en-US"); + ConsoleOutputType = ConsoleOutputType.Normal; + ForwardMessages = false; + ForwardToAllOwners = false; + DmHelpText = @"{""description"": ""Type `%prefix%h` for help.""}"; + HelpText = @"{ + ""title"": ""To invite me to your server, use this link"", + ""description"": ""https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303"", + ""color"": 53380, + ""thumbnail"": ""https://cdn.elliebot.net/Ellie.png"", + ""fields"": [ + { + ""name"": ""Useful help commands"", + ""value"": ""`%bot.prefix%modules` Lists all bot modules. +`%prefix%h CommandName` Shows some help about a specific command. +`%prefix%commands ModuleName` Lists all commands in a module."", + ""inline"": false + }, + { + ""name"": ""List of all Commands"", + ""value"": ""https://commands.elliebot.net"", + ""inline"": false + }, + { + ""name"": ""Ellie Support Server"", + ""value"": ""https://discord.gg/etQdZxSyEH"", + ""inline"": true + } + ] +}"; + var blocked = new BlockedConfig(); + Blocked = blocked; + Prefix = "."; + RotateStatuses = false; + GroupGreets = false; + DmHelpTextKeywords = new() + { + "help", + "commands", + "cmds", + "module", + "can you do" + }; + } + + // [Comment(@"Whether the prefix will be a suffix, or prefix. + // For example, if your prefix is ! you will run a command called 'cash' by typing either + // '!cash @Someone' if your prefixIsSuffix: false or + // 'cash @Someone!' if your prefixIsSuffix: true")] + // public bool PrefixIsSuffix { get; set; } + + // public string Prefixed(string text) => PrefixIsSuffix + // ? text + Prefix + // : Prefix + text; + + public string Prefixed(string text) + => Prefix + text; +} + +[Cloneable] +public sealed partial class BlockedConfig +{ + public HashSet Commands { get; set; } + public HashSet Modules { get; set; } + + public BlockedConfig() + { + Modules = new(); + Commands = new(); + } +} + +[Cloneable] +public partial class ColorConfig +{ + [Comment(@"Color used for embed responses when command successfully executes")] + public Rgba32 Ok { get; set; } + + [Comment(@"Color used for embed responses when command has an error")] + public Rgba32 Error { get; set; } + + [Comment(@"Color used for embed responses while command is doing work or is in progress")] + public Rgba32 Pending { get; set; } + + public ColorConfig() + { + Ok = Rgba32.ParseHex("00e584"); + Error = Rgba32.ParseHex("ee281f"); + Pending = Rgba32.ParseHex("faa61a"); + } +} + +public enum ConsoleOutputType +{ + Normal = 0, + Simple = 1, + None = 2 +} \ No newline at end of file diff --git a/src/EllieBot/Common/Configs/IConfigSeria.cs b/src/EllieBot/Common/Configs/IConfigSeria.cs new file mode 100644 index 0000000..cced324 --- /dev/null +++ b/src/EllieBot/Common/Configs/IConfigSeria.cs @@ -0,0 +1,18 @@ +namespace EllieBot.Common.Configs; + +/// +/// Base interface for available config serializers +/// +public interface IConfigSeria +{ + /// + /// Serialize the object to string + /// + public string Serialize(T obj) + where T : notnull; + + /// + /// Deserialize string data into an object of the specified type + /// + public T Deserialize(string data); +} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs new file mode 100644 index 0000000..a73a7a7 --- /dev/null +++ b/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs @@ -0,0 +1,19 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// Executed if no command was found for this message +/// +public interface IExecNoCommand +{ + /// + /// Executed at the end of the lifecycle if no command was found + /// → + /// → + /// → + /// [ | **] + /// + /// + /// + /// A task representing completion + Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg); +} \ No newline at end of file diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs b/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs new file mode 100644 index 0000000..eade8d5 --- /dev/null +++ b/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs @@ -0,0 +1,21 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// Implemented by modules to handle non-bot messages received +/// +public interface IExecOnMessage +{ + int Priority { get; } + + /// + /// Ran after a non-bot message was received + /// ** → + /// → + /// → + /// [ | ] + /// + /// Guild where the message was sent + /// The message that was received + /// Whether further processing of this message should be blocked + Task ExecOnMessageAsync(IGuild guild, IUserMessage msg); +} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs new file mode 100644 index 0000000..4f79c31 --- /dev/null +++ b/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs @@ -0,0 +1,22 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// This interface's method is executed after the command successfully finished execution. +/// ***There is no support for this method in EllieBot services.*** +/// It is only meant to be used in marmalade system +/// +public interface IExecPostCommand +{ + /// + /// Executed after a command was successfully executed + /// → + /// → + /// → + /// [** | ] + /// + /// Command context + /// Module name + /// Command name + /// A task representing completion + ValueTask ExecPostCommandAsync(ICommandContext ctx, string moduleName, string commandName); +} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs new file mode 100644 index 0000000..dc14cdd --- /dev/null +++ b/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs @@ -0,0 +1,25 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// This interface's method is executed after a command was found but before it was executed. +/// Able to block further processing of a command +/// +public interface IExecPreCommand +{ + public int Priority { get; } + + /// + /// + /// Ran after a command was found but before execution. + /// + /// → + /// → + /// ** → + /// [ | ] + /// + /// Command context + /// Name of the module + /// Command info + /// Whether further processing of the command is blocked + Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command); +} diff --git a/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs b/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs new file mode 100644 index 0000000..90ae000 --- /dev/null +++ b/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs @@ -0,0 +1,25 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// Implemented by services which may transform input before a command is searched for +/// +public interface IInputTransformer +{ + /// + /// Ran after a non-bot message was received + /// -> + /// ** -> + /// -> + /// [ OR ] + /// + /// Guild + /// Channel in which the message was sent + /// User who sent the message + /// Content of the message + /// New input, if any, otherwise null + Task TransformInput( + IGuild guild, + IMessageChannel channel, + IUser user, + string input); +} diff --git a/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs b/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs new file mode 100644 index 0000000..9ae8211 --- /dev/null +++ b/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs @@ -0,0 +1,13 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// All services which need to execute something after +/// the bot is ready should implement this interface +/// +public interface IReadyExecutor +{ + /// + /// Executed when bot is ready + /// + public Task OnReadyAsync(); +} diff --git a/src/EllieBot/Common/Yml/CommentAttribute.cs b/src/EllieBot/Common/Yml/CommentAttribute.cs new file mode 100644 index 0000000..9d3d7ec --- /dev/null +++ b/src/EllieBot/Common/Yml/CommentAttribute.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Common.Yml; + +[AttributeUsage(AttributeTargets.Property)] +public class CommentAttribute : Attribute +{ + public string Comment { get; } + + public CommentAttribute(string comment) + => Comment = comment; +} diff --git a/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs b/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs new file mode 100644 index 0000000..1a81978 --- /dev/null +++ b/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs @@ -0,0 +1,65 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.TypeInspectors; + +namespace EllieBot.Common.Yml; + +public class CommentGatheringTypeInspector : TypeInspectorSkeleton +{ + private readonly ITypeInspector _innerTypeDescriptor; + + public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor) + => _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor)); + + public override IEnumerable GetProperties(Type type, object container) + => _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d)); + + private sealed class CommentsPropertyDescriptor : IPropertyDescriptor + { + public string Name { get; } + + public Type Type + => _baseDescriptor.Type; + + public Type TypeOverride + { + get => _baseDescriptor.TypeOverride; + set => _baseDescriptor.TypeOverride = value; + } + + public int Order { get; set; } + + public ScalarStyle ScalarStyle + { + get => _baseDescriptor.ScalarStyle; + set => _baseDescriptor.ScalarStyle = value; + } + + public bool CanWrite + => _baseDescriptor.CanWrite; + + private readonly IPropertyDescriptor _baseDescriptor; + + public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor) + { + _baseDescriptor = baseDescriptor; + Name = baseDescriptor.Name; + } + + public void Write(object target, object value) + => _baseDescriptor.Write(target, value); + + public T GetCustomAttribute() + where T : Attribute + => _baseDescriptor.GetCustomAttribute(); + + public IObjectDescriptor Read(object target) + { + var comment = _baseDescriptor.GetCustomAttribute(); + return comment is not null + ? new CommentsObjectDescriptor(_baseDescriptor.Read(target), comment.Comment) + : _baseDescriptor.Read(target); + } + } +} diff --git a/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs b/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs new file mode 100644 index 0000000..9dc61f9 --- /dev/null +++ b/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs @@ -0,0 +1,30 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Yml; + +public sealed class CommentsObjectDescriptor : IObjectDescriptor +{ + public string Comment { get; } + + public object Value + => _innerDescriptor.Value; + + public Type Type + => _innerDescriptor.Type; + + public Type StaticType + => _innerDescriptor.StaticType; + + public ScalarStyle ScalarStyle + => _innerDescriptor.ScalarStyle; + + private readonly IObjectDescriptor _innerDescriptor; + + public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment) + { + _innerDescriptor = innerDescriptor; + Comment = comment; + } +} diff --git a/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs b/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs new file mode 100644 index 0000000..1c89a95 --- /dev/null +++ b/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs @@ -0,0 +1,29 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.ObjectGraphVisitors; + +namespace EllieBot.Common.Yml; + +public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor +{ + public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) + : base(nextVisitor) + { + } + + public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) + { + if (value is CommentsObjectDescriptor commentsDescriptor + && !string.IsNullOrWhiteSpace(commentsDescriptor.Comment)) + { + var parts = commentsDescriptor.Comment.Split('\n'); + + foreach (var part in parts) + context.Emit(new Comment(part.Trim(), false)); + } + + return base.EnterMapping(key, value, context); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs b/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs new file mode 100644 index 0000000..cf9e15f --- /dev/null +++ b/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs @@ -0,0 +1,35 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.EventEmitters; + +namespace EllieBot.Common.Yml; + +public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter +{ + public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter) + : base(nextEmitter) + { + } + + public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) + { + if (typeof(string).IsAssignableFrom(eventInfo.Source.Type)) + { + var value = eventInfo.Source.Value as string; + if (!string.IsNullOrEmpty(value)) + { + var isMultiLine = value.IndexOfAny(new[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0; + if (isMultiLine) + { + eventInfo = new(eventInfo.Source) + { + Style = ScalarStyle.Literal + }; + } + } + } + + nextEmitter.Emit(eventInfo, emitter); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/Rgba32Converter.cs b/src/EllieBot/Common/Yml/Rgba32Converter.cs new file mode 100644 index 0000000..12f6cf9 --- /dev/null +++ b/src/EllieBot/Common/Yml/Rgba32Converter.cs @@ -0,0 +1,47 @@ +#nullable disable +using SixLabors.ImageSharp.PixelFormats; +using System.Globalization; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Yml; + +public class Rgba32Converter : IYamlTypeConverter +{ + public bool Accepts(Type type) + => type == typeof(Rgba32); + + public object ReadYaml(IParser parser, Type type) + { + var scalar = parser.Consume(); + var result = Rgba32.ParseHex(scalar.Value); + return result; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var color = (Rgba32)value; + var val = (uint)((color.B << 0) | (color.G << 8) | (color.R << 16)); + emitter.Emit(new Scalar(val.ToString("X6").ToLower())); + } +} + +public class CultureInfoConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) + => type == typeof(CultureInfo); + + public object ReadYaml(IParser parser, Type type) + { + var scalar = parser.Consume(); + var result = new CultureInfo(scalar.Value); + return result; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var ci = (CultureInfo)value; + emitter.Emit(new Scalar(ci.Name)); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/UriConverter.cs b/src/EllieBot/Common/Yml/UriConverter.cs new file mode 100644 index 0000000..66e2ca0 --- /dev/null +++ b/src/EllieBot/Common/Yml/UriConverter.cs @@ -0,0 +1,25 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Yml; + +public class UriConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) + => type == typeof(Uri); + + public object ReadYaml(IParser parser, Type type) + { + var scalar = parser.Consume(); + var result = new Uri(scalar.Value); + return result; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var uri = (Uri)value; + emitter.Emit(new Scalar(uri.ToString())); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/Yaml.cs b/src/EllieBot/Common/Yml/Yaml.cs new file mode 100644 index 0000000..2c65698 --- /dev/null +++ b/src/EllieBot/Common/Yml/Yaml.cs @@ -0,0 +1,28 @@ +#nullable disable +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace EllieBot.Common.Yml; + +public class Yaml +{ + public static ISerializer Serializer + => new SerializerBuilder().WithTypeInspector(inner => new CommentGatheringTypeInspector(inner)) + .WithEmissionPhaseObjectGraphVisitor(args + => new CommentsObjectGraphVisitor(args.InnerVisitor)) + .WithEventEmitter(args => new MultilineScalarFlowStyleEmitter(args)) + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .WithIndentedSequences() + .WithTypeConverter(new Rgba32Converter()) + .WithTypeConverter(new CultureInfoConverter()) + .WithTypeConverter(new UriConverter()) + .Build(); + + public static IDeserializer Deserializer + => new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance) + .WithTypeConverter(new Rgba32Converter()) + .WithTypeConverter(new CultureInfoConverter()) + .WithTypeConverter(new UriConverter()) + .IgnoreUnmatchedProperties() + .Build(); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/YamlHelper.cs b/src/EllieBot/Common/Yml/YamlHelper.cs new file mode 100644 index 0000000..25dbfd6 --- /dev/null +++ b/src/EllieBot/Common/Yml/YamlHelper.cs @@ -0,0 +1,48 @@ +#nullable disable +namespace EllieBot.Common.Yml; + +public class YamlHelper +{ + // https://github.com/aaubry/YamlDotNet/blob/0f4cc205e8b2dd8ef6589d96de32bf608a687c6f/YamlDotNet/Core/Scanner.cs#L1687 + /// + /// This is modified code from yamldotnet's repo which handles parsing unicode code points + /// it is needed as yamldotnet doesn't support unescaped unicode characters + /// + /// Unicode code point + /// Actual character + public static string UnescapeUnicodeCodePoint(string point) + { + var character = 0; + + // Scan the character value. + + foreach (var c in point) + { + if (!IsHex(c)) + return point; + + character = (character << 4) + AsHex(c); + } + + // Check the value and write the character. + + if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF) + return point; + + return char.ConvertFromUtf32(character); + } + + public static bool IsHex(char c) + => c is (>= '0' and <= '9') or (>= 'A' and <= 'F') or (>= 'a' and <= 'f'); + + public static int AsHex(char c) + { + if (c <= '9') + return c - '0'; + + if (c <= 'F') + return c - 'A' + 10; + + return c - 'a' + 10; + } +} \ No newline at end of file From 64363d2e8bcf0cceaeda2bf1efadd6cd4e1851ac Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 27 Mar 2024 18:37:24 +1300 Subject: [PATCH 13/62] Fixed an issue in Canary.cs --- src/Ellie.Marmalade/Canary.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Ellie.Marmalade/Canary.cs b/src/Ellie.Marmalade/Canary.cs index 19f1d47..64a9c4c 100644 --- a/src/Ellie.Marmalade/Canary.cs +++ b/src/Ellie.Marmalade/Canary.cs @@ -4,14 +4,14 @@ namespace Ellie.Canary; /// /// The base class which will be loaded as a module into EllieBot -/// Any user-defined snek has to inherit from this class. -/// Sneks get instantiated ONLY ONCE during the loading, -/// and any snek commands will be executed on the same instance. +/// Any user-defined canary has to inherit from this class. +/// Canaries get instantiated ONLY ONCE during the loading, +/// and any canary commands will be executed on the same instance. /// -public abstract class Snek : IAsyncDisposable +public abstract class Canary : IAsyncDisposable { /// - /// Name of the snek. Defaults to the lowercase class name + /// Name of the canary. Defaults to the lowercase class name /// public virtual string Name => GetType().Name.ToLowerInvariant(); @@ -25,14 +25,14 @@ public abstract class Snek : IAsyncDisposable => string.Empty; /// - /// Executed once this snek has been instantiated and before any command is executed. + /// Executed once this canary has been instantiated and before any command is executed. /// /// A representing completion public virtual ValueTask InitializeAsync() => default; /// - /// Override to cleanup any resources or references which might hold this snek in memory + /// Override to cleanup any resources or references which might hold this canary in memory /// /// public virtual ValueTask DisposeAsync() @@ -83,8 +83,8 @@ public abstract class Snek : IAsyncDisposable /// /// This method is called after the command was found but not executed, /// and can be used to prevent the command's execution. - /// The command information doesn't have to be from this snek as this method - /// will be called when *any* command from any module or snek was found. + /// The command information doesn't have to be from this canary as this method + /// will be called when *any* command from any module or canary was found. /// You can choose to prevent the execution of the command by returning "true" value. /// Execution order: /// @@ -95,7 +95,7 @@ public abstract class Snek : IAsyncDisposable /// /// /// Command context - /// Name of the snek or module from which the command originates + /// Name of the canary or module from which the command originates /// Name of the command which is about to be executed /// A representing whether the execution should be blocked public virtual ValueTask ExecPreCommandAsync( From daa71f812e99f3237063933d5fff7412bf82fe01 Mon Sep 17 00:00:00 2001 From: Toastie Date: Fri, 29 Mar 2024 01:01:35 +1300 Subject: [PATCH 14/62] Updated a few things in the Marmalade system --- src/Ellie.Marmalade/Attributes/FilterAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/bot_permAttribute.cs | 4 ++-- src/Ellie.Marmalade/Attributes/cmdAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/injectAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/leftoverAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/prioAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/svcAttribute.cs | 2 +- src/Ellie.Marmalade/Attributes/user_permAttribute.cs | 2 +- src/Ellie.Marmalade/Canary.cs | 2 +- src/Ellie.Marmalade/Context/AnyContext.cs | 4 ++-- src/Ellie.Marmalade/Context/DmContext.cs | 2 +- src/Ellie.Marmalade/Context/GuildContext.cs | 2 +- src/Ellie.Marmalade/Ellie.Marmalade.csproj | 2 +- src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs | 2 +- src/Ellie.Marmalade/ParamParser/ParamParser.cs | 2 +- src/Ellie.Marmalade/ParamParser/ParseResult.cs | 2 +- src/Ellie.Marmalade/Strings/CommandStrings.cs | 2 +- src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs | 2 +- src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs | 2 +- src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs | 2 +- src/Ellie.Marmalade/Strings/MarmaladeStrings.cs | 2 +- src/Ellie.Marmalade/Strings/StringsLoader.cs | 2 +- 24 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Ellie.Marmalade/Attributes/FilterAttribute.cs b/src/Ellie.Marmalade/Attributes/FilterAttribute.cs index 1f2858e..de6ae24 100644 --- a/src/Ellie.Marmalade/Attributes/FilterAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/FilterAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Overridden to implement custom checks which commands have to pass in order to be executed. diff --git a/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs b/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs index 0e7003c..0001d76 100644 --- a/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Used as a marker class for bot_perm and user_perm Attributes diff --git a/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs b/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs index cbffa6c..8186614 100644 --- a/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; [AttributeUsage(AttributeTargets.Method)] public sealed class bot_owner_onlyAttribute : MarmaladePermAttribute diff --git a/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs b/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs index faaede2..30fa320 100644 --- a/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Canary; +namespace Ellie.Marmalade; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class bot_permAttribute : MarmaladePermAttribute @@ -13,7 +13,7 @@ public sealed class bot_permAttribute : MarmaladePermAttribute GuildPerm = perm; ChannelPerm = null; } - + public bot_permAttribute(ChannelPermission perm) { ChannelPerm = perm; diff --git a/src/Ellie.Marmalade/Attributes/cmdAttribute.cs b/src/Ellie.Marmalade/Attributes/cmdAttribute.cs index f40ca2e..56ce03b 100644 --- a/src/Ellie.Marmalade/Attributes/cmdAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/cmdAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Marks a method as a snek command diff --git a/src/Ellie.Marmalade/Attributes/injectAttribute.cs b/src/Ellie.Marmalade/Attributes/injectAttribute.cs index 3380b9d..4865cff 100644 --- a/src/Ellie.Marmalade/Attributes/injectAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/injectAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Marks services in command arguments for injection. diff --git a/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs b/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs index d632715..b16c225 100644 --- a/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Marks the parameter to take diff --git a/src/Ellie.Marmalade/Attributes/prioAttribute.cs b/src/Ellie.Marmalade/Attributes/prioAttribute.cs index cf6d0d4..9b1cc81 100644 --- a/src/Ellie.Marmalade/Attributes/prioAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/prioAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Sets the priority of a command in case there are multiple commands with the same name but different parameters. diff --git a/src/Ellie.Marmalade/Attributes/svcAttribute.cs b/src/Ellie.Marmalade/Attributes/svcAttribute.cs index eb225b0..dab065f 100644 --- a/src/Ellie.Marmalade/Attributes/svcAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/svcAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Marks the class as a service which can be used within the same Medusa diff --git a/src/Ellie.Marmalade/Attributes/user_permAttribute.cs b/src/Ellie.Marmalade/Attributes/user_permAttribute.cs index a4826db..7d195eb 100644 --- a/src/Ellie.Marmalade/Attributes/user_permAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/user_permAttribute.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Canary; +namespace Ellie.Marmalade; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class user_permAttribute : MarmaladePermAttribute diff --git a/src/Ellie.Marmalade/Canary.cs b/src/Ellie.Marmalade/Canary.cs index 64a9c4c..6fef82c 100644 --- a/src/Ellie.Marmalade/Canary.cs +++ b/src/Ellie.Marmalade/Canary.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// The base class which will be loaded as a module into EllieBot diff --git a/src/Ellie.Marmalade/Context/AnyContext.cs b/src/Ellie.Marmalade/Context/AnyContext.cs index f333f1e..816a95d 100644 --- a/src/Ellie.Marmalade/Context/AnyContext.cs +++ b/src/Ellie.Marmalade/Context/AnyContext.cs @@ -1,7 +1,7 @@ using Discord; using EllieBot; -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Commands which take this class as a first parameter can be executed in both DMs and Servers @@ -29,7 +29,7 @@ public abstract class AnyContext public abstract ISelfUser Bot { get; } /// - /// Provides access to strings used by this medusa + /// Provides access to strings used by this marmalade /// public abstract IMarmaladeStrings Strings { get; } diff --git a/src/Ellie.Marmalade/Context/DmContext.cs b/src/Ellie.Marmalade/Context/DmContext.cs index 3810984..a703fa4 100644 --- a/src/Ellie.Marmalade/Context/DmContext.cs +++ b/src/Ellie.Marmalade/Context/DmContext.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Commands which take this type as the first parameter can only be executed in DMs diff --git a/src/Ellie.Marmalade/Context/GuildContext.cs b/src/Ellie.Marmalade/Context/GuildContext.cs index 916f945..33cca4f 100644 --- a/src/Ellie.Marmalade/Context/GuildContext.cs +++ b/src/Ellie.Marmalade/Context/GuildContext.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Commands which take this type as a first parameter can only be executed in a server diff --git a/src/Ellie.Marmalade/Ellie.Marmalade.csproj b/src/Ellie.Marmalade/Ellie.Marmalade.csproj index d296490..aa15438 100644 --- a/src/Ellie.Marmalade/Ellie.Marmalade.csproj +++ b/src/Ellie.Marmalade/Ellie.Marmalade.csproj @@ -6,7 +6,7 @@ enable preview true - Ellie.Canary + Ellie.Marmalade The EllieBot Devs diff --git a/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs b/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs index c72859f..c02f973 100644 --- a/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs +++ b/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs @@ -1,5 +1,5 @@ using Discord; -using Ellie.Canary; +using Ellie.Marmalade; namespace EllieBot; diff --git a/src/Ellie.Marmalade/ParamParser/ParamParser.cs b/src/Ellie.Marmalade/ParamParser/ParamParser.cs index feec7d1..a174a78 100644 --- a/src/Ellie.Marmalade/ParamParser/ParamParser.cs +++ b/src/Ellie.Marmalade/ParamParser/ParamParser.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Overridden to implement parsers for custom types diff --git a/src/Ellie.Marmalade/ParamParser/ParseResult.cs b/src/Ellie.Marmalade/ParamParser/ParseResult.cs index 81a8607..e12b77e 100644 --- a/src/Ellie.Marmalade/ParamParser/ParseResult.cs +++ b/src/Ellie.Marmalade/ParamParser/ParseResult.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; public readonly struct ParseResult { diff --git a/src/Ellie.Marmalade/Strings/CommandStrings.cs b/src/Ellie.Marmalade/Strings/CommandStrings.cs index 8328fae..5d06f3c 100644 --- a/src/Ellie.Marmalade/Strings/CommandStrings.cs +++ b/src/Ellie.Marmalade/Strings/CommandStrings.cs @@ -1,6 +1,6 @@ using YamlDotNet.Serialization; -namespace Ellie.Canary; +namespace Ellie.Marmalade; public readonly struct CommandStrings { diff --git a/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs b/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs index 1527bfe..37c4299 100644 --- a/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs +++ b/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs @@ -1,6 +1,6 @@ using System.Globalization; -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Defines methods to retrieve and reload marmalade strings diff --git a/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs b/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs index d2fb1a7..6df86b0 100644 --- a/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs +++ b/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Implemented by classes which provide localized strings in their own ways diff --git a/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs b/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs index 2bb6ca6..0ea98d5 100644 --- a/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs +++ b/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs @@ -1,4 +1,4 @@ -namespace Ellie.Canary; +namespace Ellie.Marmalade; public class LocalMarmaladeStringsProvider : IMarmaladeStringsProvider { diff --git a/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs b/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs index 2880764..286e9a1 100644 --- a/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs +++ b/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs @@ -1,7 +1,7 @@ using System.Globalization; using Serilog; -namespace Ellie.Canary; +namespace Ellie.Marmalade; public class MarmaladeStrings : IMarmaladeStrings { diff --git a/src/Ellie.Marmalade/Strings/StringsLoader.cs b/src/Ellie.Marmalade/Strings/StringsLoader.cs index bec5c17..986fcad 100644 --- a/src/Ellie.Marmalade/Strings/StringsLoader.cs +++ b/src/Ellie.Marmalade/Strings/StringsLoader.cs @@ -2,7 +2,7 @@ using Serilog; using YamlDotNet.Serialization; -namespace Ellie.Canary; +namespace Ellie.Marmalade; /// /// Loads strings from the shortcut or localizable path From 2f3e28390308f0812ede5279cfc6c99cd7e33341 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 31 Mar 2024 23:44:37 +1300 Subject: [PATCH 15/62] Added interactions to Ellie --- .../Common/Interaction/EllieInteraction.cs | 82 +++++++++++++++++++ .../Interaction/EllieInteractionData.cs | 8 ++ .../Interaction/EllieInteractionService.cs | 20 +++++ .../Interaction/IEllieInteractionService.cs | 8 ++ .../Common/Interaction/SimpleInteraction.cs | 20 +++++ 5 files changed, 138 insertions(+) create mode 100644 src/EllieBot/Common/Interaction/EllieInteraction.cs create mode 100644 src/EllieBot/Common/Interaction/EllieInteractionData.cs create mode 100644 src/EllieBot/Common/Interaction/EllieInteractionService.cs create mode 100644 src/EllieBot/Common/Interaction/IEllieInteractionService.cs create mode 100644 src/EllieBot/Common/Interaction/SimpleInteraction.cs diff --git a/src/EllieBot/Common/Interaction/EllieInteraction.cs b/src/EllieBot/Common/Interaction/EllieInteraction.cs new file mode 100644 index 0000000..e77fede --- /dev/null +++ b/src/EllieBot/Common/Interaction/EllieInteraction.cs @@ -0,0 +1,82 @@ +namespace EllieBot; + +public sealed class EllieInteraction +{ + private readonly ulong _authorId; + private readonly ButtonBuilder _button; + private readonly Func _onClick; + private readonly bool _onlyAuthor; + public DiscordSocketClient Client { get; } + + private readonly TaskCompletionSource _interactionCompletedSource; + + private IUserMessage message = null!; + + public EllieInteraction(DiscordSocketClient client, + ulong authorId, + ButtonBuilder button, + Func onClick, + bool onlyAuthor) + { + _authorId = authorId; + _button = button; + _onClick = onClick; + _onlyAuthor = onlyAuthor; + _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + + Client = client; + } + + public async Task RunAsync(IUserMessage msg) + { + message = msg; + + Client.InteractionCreated += OnInteraction; + await Task.WhenAny(Task.Delay(15_000), _interactionCompletedSource.Task); + Client.InteractionCreated -= OnInteraction; + + await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); + } + + private Task OnInteraction(SocketInteraction arg) + { + if (arg is not SocketMessageComponent smc) + return Task.CompletedTask; + + if (smc.Message.Id != message.Id) + return Task.CompletedTask; + + if (_onlyAuthor && smc.User.Id != _authorId) + return Task.CompletedTask; + + if (smc.Data.CustomId != _button.CustomId) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + await ExecuteOnActionAsync(smc); + + // this should only be a thing on single-response buttons + _interactionCompletedSource.TrySetResult(true); + + if (!smc.HasResponded) + { + await smc.DeferAsync(); + } + }); + + return Task.CompletedTask; + } + + + public MessageComponent CreateComponent() + { + var comp = new ComponentBuilder() + .WithButton(_button); + + return comp.Build(); + } + + public Task ExecuteOnActionAsync(SocketMessageComponent smc) + => _onClick(smc); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionData.cs b/src/EllieBot/Common/Interaction/EllieInteractionData.cs new file mode 100644 index 0000000..3e25606 --- /dev/null +++ b/src/EllieBot/Common/Interaction/EllieInteractionData.cs @@ -0,0 +1,8 @@ +namespace EllieBot; + +/// +/// Represents essential interacation data +/// +/// Emote which will show on a button +/// Custom interaction id +public record EllieInteractionData(IEmote Emote, string CustomId, string? Text = null); \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionService.cs b/src/EllieBot/Common/Interaction/EllieInteractionService.cs new file mode 100644 index 0000000..3e97ec1 --- /dev/null +++ b/src/EllieBot/Common/Interaction/EllieInteractionService.cs @@ -0,0 +1,20 @@ +namespace EllieBot; + +public class EllieInteractionService : IEllieInteractionService, IEService +{ + private readonly DiscordSocketClient _client; + + public EllieInteractionService(DiscordSocketClient client) + { + _client = client; + } + + public EllieInteraction Create( + ulong userId, + SimpleInteraction inter) + => new EllieInteraction(_client, + userId, + inter.Button, + inter.TriggerAsync, + onlyAuthor: true); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/IEllieInteractionService.cs b/src/EllieBot/Common/Interaction/IEllieInteractionService.cs new file mode 100644 index 0000000..03a3ba1 --- /dev/null +++ b/src/EllieBot/Common/Interaction/IEllieInteractionService.cs @@ -0,0 +1,8 @@ +namespace EllieBot; + +public interface IEllieInteractionService +{ + public EllieInteraction Create( + ulong userId, + SimpleInteraction inter); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/SimpleInteraction.cs b/src/EllieBot/Common/Interaction/SimpleInteraction.cs new file mode 100644 index 0000000..045d4fc --- /dev/null +++ b/src/EllieBot/Common/Interaction/SimpleInteraction.cs @@ -0,0 +1,20 @@ +namespace EllieBot; + +public class SimpleInteraction +{ + public ButtonBuilder Button { get; } + private readonly Func _onClick; + private readonly T? _state; + + public SimpleInteraction(ButtonBuilder button, Func onClick, T? state = default) + { + Button = button; + _onClick = onClick; + _state = state; + } + + public async Task TriggerAsync(SocketMessageComponent smc) + { + await _onClick(smc, _state!); + } +} \ No newline at end of file From fbfc01c7f3c1a0a684c7990f561484facc7d07e1 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 31 Mar 2024 23:45:30 +1300 Subject: [PATCH 16/62] Added jsonconverters to Ellie --- .../Common/JsonConverters/CultureInfoConverter.cs | 14 ++++++++++++++ .../Common/JsonConverters/Rgba32Converter.cs | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs create mode 100644 src/EllieBot/Common/JsonConverters/Rgba32Converter.cs diff --git a/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs b/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs new file mode 100644 index 0000000..0c26f15 --- /dev/null +++ b/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs @@ -0,0 +1,14 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Common.JsonConverters; + +public class CultureInfoConverter : JsonConverter +{ + public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => new(reader.GetString() ?? "en-US"); + + public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) + => writer.WriteStringValue(value.Name); +} \ No newline at end of file diff --git a/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs b/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs new file mode 100644 index 0000000..ef619a6 --- /dev/null +++ b/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs @@ -0,0 +1,14 @@ +using SixLabors.ImageSharp.PixelFormats; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Common.JsonConverters; + +public class Rgba32Converter : JsonConverter +{ + public override Rgba32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => Rgba32.ParseHex(reader.GetString()); + + public override void Write(Utf8JsonWriter writer, Rgba32 value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToHex()); +} \ No newline at end of file From 08756eeb5c9d3ef3cf065099b2a577c994fec91a Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 31 Mar 2024 23:51:18 +1300 Subject: [PATCH 17/62] Added marmalade subsystem to Ellie --- .../Marmalade/Adapters/BehaviorAdapter.cs | 76 ++ .../Adapters/ContextAdapterFactory.cs | 7 + .../Marmalade/Adapters/DmContextAdapter.cs | 49 + .../Marmalade/Adapters/FilterAdapter.cs | 31 + .../Marmalade/Adapters/GuildContextAdapter.cs | 53 + .../Marmalade/Adapters/ParamParserAdapter.cs | 32 + .../Common/Marmalade/CommandContextType.cs | 27 + .../Config/IMarmaladeConfigService.cs | 8 + .../Marmalade/Config/MarmaladeConfig.cs | 20 + .../Config/MarmaladeConfigService.cs | 45 + .../Marmalade/IMarmaladeLoaderService.cs | 23 + .../Marmalade/MarmaladeAssemblyLoadContext.cs | 36 + .../Marmalade/MarmaladeLoaderService.cs | 917 ++++++++++++++++++ .../Marmalade/MarmaladeServiceProvider.cs | 24 + .../Marmalade/Models/CanaryCommandData.cs | 46 + .../Common/Marmalade/Models/CanaryData.cs | 11 + .../Common/Marmalade/Models/ParamData.cs | 10 + .../Marmalade/Models/ResolvedMarmalade.cs | 14 + 18 files changed, 1429 insertions(+) create mode 100644 src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs create mode 100644 src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs create mode 100644 src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs create mode 100644 src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs create mode 100644 src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs create mode 100644 src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs create mode 100644 src/EllieBot/Common/Marmalade/CommandContextType.cs create mode 100644 src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs create mode 100644 src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs create mode 100644 src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs create mode 100644 src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs create mode 100644 src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs create mode 100644 src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs create mode 100644 src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs create mode 100644 src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs create mode 100644 src/EllieBot/Common/Marmalade/Models/CanaryData.cs create mode 100644 src/EllieBot/Common/Marmalade/Models/ParamData.cs create mode 100644 src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs diff --git a/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs new file mode 100644 index 0000000..935d27a --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs @@ -0,0 +1,76 @@ +#nullable disable + +[DontAddToIocContainer] +public sealed class BehaviorAdapter : ICustomBehavior +{ + private readonly WeakReference _canaryWr; + private readonly IMarmaladeStrings _strings; + private readonly IServiceProvider _services; + private readonly string _name; + + // unused + public int Priority + => 0; + + public BehaviorAdapter(WeakReference canaryWr, IMarmaladeStrings strings, IServiceProvider services) + { + _canaryWr = canaryWr; + _strings = strings; + _services = services; + + _name = canaryWr.TryGetTarget(out var canary) + ? $"canary/{canary.GetType().Name}" + : "unknown"; + } + + public async Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return false; + + return await canary.ExecPreCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), + moduleName, + command.Name); + } + + public async Task ExecOnMessageAsync(IGuild? guild, IUserMessage msg) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return false; + + return await canary.ExecOnMessageAsync(guild, msg); + } + + public async Task TransformInput( + IGuild guild, + IMessageChannel channel, + IUser user, + string input) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return null; + + return await canary.ExecInputTransformAsync(guild, channel, user, input); + } + + public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return; + + await canary.ExecOnNoCommandAsync(guild, msg); + } + + public async ValueTask ExecPostCommandAsync(ICommandContext context, string moduleName, string commandName) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return; + + await canary.ExecPostCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), + moduleName, + commandName); + } + + public override string ToString() + => _name; +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs b/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs new file mode 100644 index 0000000..212e8ee --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs @@ -0,0 +1,7 @@ +internal class ContextFactory +{ + public static AnyContext CreateNew(ICommandContext context, IMarmaladeStrings strings, IServiceProvider services) + => context.Guild is null + ? new DmContextAdapter(context, strings, services) + : new GuildContextAdapter(context, strings, services); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs new file mode 100644 index 0000000..d0aaabc --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.DependencyInjection; + +public sealed class DmContextAdapter : DmContext +{ + public override IMarmaladeStrings Strings { get; } + public override IDMChannel Channel { get; } + public override IUserMessage Message { get; } + public override ISelfUser Bot { get; } + public override IUser User + => Message.Author; + + private readonly IServiceProvider _services; + private readonly Lazy _ebs; + private readonly Lazy _botStrings; + private readonly Lazy _localization; + + public DmContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) + { + if (ctx is not { Channel: IDMChannel ch}) + { + throw new ArgumentException("Can't use non-dm context to create DmContextAdapter", nameof(ctx)); + } + + Strings = strings; + + _services = services; + + Channel = ch; + Message = ctx.Message; + Bot = ctx.Client.CurrentUser; + + _ebs = new(_services.GetRequiredService()); + _botStrings = new(_services.GetRequiredService); + _localization = new(_services.GetRequiredService()); + } + + public override IEmbedBuilder Embed() + => _ebs.Value.Create(); + + public override string GetText(string key, object[]? args = null) + { + var cultureInfo = _localization.Value.GetCultureInfo(default(ulong?)); + var output = Strings.GetText(key, cultureInfo, args ?? Array.Empty()); + if (!string.IsNullOrEmpty(output)) + return output; + + return _botStrings.Value.GetText(key, cultureInfo, args); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs new file mode 100644 index 0000000..1934e38 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs @@ -0,0 +1,31 @@ +namespace Ellie.Marmalade.Adapters; + +public class FilterAdapter : PreconditionAttribute +{ + private readonly FilterAttribute _filterAttribute; + private readonly IMarmaladeStrings _strings; + + public FilterAdapter(FilterAttribute filterAttribute, + IMarmaladeStrings strings) + { + _filterAttribute = filterAttribute; + _strings = strings; + } + + public override async Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + var marmaladeContext = ContextAdapterFactory.CreateNew(context, + _strings, + services); + + var result = await _filterAttribute.CheckAsync(marmaladeContext); + + if (!result) + return PreconditionResult.FromError($"Precondition '{_filterAttribute.GetType().Name}' failed."); + + return PreconditionResult.FromSuccess(); + } +} diff --git a/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs new file mode 100644 index 0000000..f5f0a2b --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.DependencyInjection; + +public sealed class GuildContextAdapter : GuildContext +{ + private readonly IServiceProvider _services; + private readonly ICommandContext _ctx; + private readonly Lazy _ebs; + private readonly Lazy _botStrings; + private readonly Lazy _localization; + + public override IMarmaladeStrings Strings { get; } + public override IGuild Guild { get; } + public override ITextChannel Channel { get; } + public override ISelfUser Bot { get; } + public override IUserMessage Message + => _ctx.Message; + + public override IGuildUser User { get; } + + public override IEmbedBuilder Embed() + => _ebs.Value.Create(); + + public GuildContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) + { + if (ctx.Guild is not IGuild guild || ctx.Channel is not ITextChannel channel) + { + throw new ArgumentException("Can't use non-guild context to create GuildContextAdapter", nameof(ctx)); + } + + Strings = strings; + User = (IGuildUser)ctx.User; + Bot = ctx.Client.CurrentUser; + + _services = services; + _ebs = new(_services.GetRequiredService()); + _botStrings = new(_services.GetRequiredService); + _localization = new(_services.GetRequiredService()); + + (_ctx, Guild, Channel) = (ctx, guild, channel); + } + + public override string GetText(string key, object[]? args = null) + { + args ??= Array.Empty(); + + var cultureInfo = _localization.Value.GetCultureInfo(_ctx.Guild.Id); + var output = Strings.GetText(key, cultureInfo, args); + if (!string.IsNullOrWhiteSpace(output)) + return output; + + return _botStrings.Value.GetText(key, cultureInfo, args); + } +} diff --git a/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs new file mode 100644 index 0000000..1d3b948 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs @@ -0,0 +1,32 @@ +public sealed class ParamParserAdapter : TypeReader +{ + private readonly ParamParser _parser; + private readonly IMarmaladeStrings _strings; + private readonly IServiceProvider _services; + + public ParamParserAdapter(ParamParser parser, + IMarmaladeStrings strings, + IServiceProvider services) + { + _parser = parser; + _strings = strings; + _services = services; + } + + public override async Task ReadAsync( + ICommandContext context, + string input, + IServiceProvider services) + { + var marmaladeContext = ContextAdapterFactory.CreateNew(context, + _strings, + _services); + + var result = await _parser.TryParseAsync(marmaladeContext, input); + + if (result.IsSuccess) + return Discord.Commands.TypeReaderResult.FromSuccess(result.Data); + + return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, "Invalid input"); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/CommandContextType.cs b/src/EllieBot/Common/Marmalade/CommandContextType.cs new file mode 100644 index 0000000..9f9459c --- /dev/null +++ b/src/EllieBot/Common/Marmalade/CommandContextType.cs @@ -0,0 +1,27 @@ +namespace Ellie.Marmalade; + +/// +/// Enum specifying in which context the command can be executed +/// +public enum CommandContextType +{ + /// + /// Command can only be executed in a guild + /// + Guild, + + /// + /// Command can only be executed in DMs + /// + Dm, + + /// + /// Command can be executed anywhere + /// + Any, + + /// + /// Command can be executed anywhere, and it doesn't require context to be passed to it + /// + Unspecified +} diff --git a/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs b/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs new file mode 100644 index 0000000..f3e6f6a --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs @@ -0,0 +1,8 @@ +namespace Ellie.Marmalade; + +public interface IMarmaladeConfigService +{ + IReadOnlyCollection GetLoadedMarmalades(); + void AddLoadedMarmalade(string name); + void RemoveLoadedMarmalade(string name); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs new file mode 100644 index 0000000..82ec302 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs @@ -0,0 +1,20 @@ +#nullable disable +using Cloneable; +using EllieBot.Common.Yml; + +namespace Ellie.Marmalade; + +[Cloneable] +public sealed partial class MarmaladeConfig : ICloneable +{ + [Comment(@"DO NOT CHANGE")] + public int Version { get; set; } = 1; + + [Comment("List of marmalades automatically loaded at startup")] + public List? Loaded { get; set; } + + public MarmaladeConfig() + { + Loaded = new(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs new file mode 100644 index 0000000..fe475e8 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs @@ -0,0 +1,45 @@ +using EllieBot.Common.Configs; + +namespace Ellie.Marmalade; + +public sealed class MarmaladeConfigService : ConfigServiceBase, IMarmaladeConfigService +{ + private const string FILE_PATH = "data/marmalades/marmalade.yml"; + private static readonly TypedKey _changeKey = new("config.marmalade.updated"); + + public override string Name + => "marmalade"; + + public MarmaladeConfigService( + IConfigSeria serializer, + IPubSub pubSub) + : base(FILE_PATH, serializer, pubSub, _changeKey) + { + } + + public IReadOnlyCollection GetLoadedMarmalades() + => Data.Loaded?.ToList() ?? new List(); + + public void AddLoadedMarmalade(string name) + { + ModifyConfig(conf => + { + if (conf.Loaded is null) + conf.Loaded = new(); + + if (!conf.Loaded.Contains(name)) + conf.Loaded.Add(name); + }); + } + + public void RemoveLoadedMarmalade(string name) + { + ModifyConfig(conf => + { + if (conf.Loaded is null) + conf.Loaded = new(); + + conf.Loaded.Remove(name); + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs b/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs new file mode 100644 index 0000000..7064f5c --- /dev/null +++ b/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs @@ -0,0 +1,23 @@ +using System.Globalization; + +namespace Ellie.Marmalade; + +public interface IMarmaladeLoaderService +{ + Task LoadMarmaladeAsync(string marmaladeName); + Task UnloadMarmaladeAsync(string marmaladeName); + string GetCommandDescription(string marmamaleName, string commandName, CultureInfo culture); + string[] GetCommandExampleArgs(string marmamaleName, string commandName, CultureInfo culture); + Task ReloadStrings(); + IReadOnlyCollection GetAllMarmalades(); + IReadOnlyCollection GetLoadedMarmalades(CultureInfo? cultureInfo = null); +} + +public sealed record MarmaladeStats(string Name, + string? Description, + IReadOnlyCollection Canaries); + +public sealed record CanaryStats(string Name, + IReadOnlyCollection Commands); + +public sealed record CanaryCommandStats(string Name); \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs b/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs new file mode 100644 index 0000000..2e30d81 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.Loader; + +namespace Ellie.Marmalade; + +public sealed class MarmaladeAssemblyLoadContext : AssemblyLoadContext +{ + private readonly AssemblyDependencyResolver _depResolver; + + public MarmaladeAssemblyLoadContext(string pluginPath) : base(isCollectible: true) + { + _depResolver = new(pluginPath); + } + + protected override Assembly? Load(AssemblyName assemblyName) + { + var assemblyPath = _depResolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + { + return LoadFromAssemblyPath(assemblyPath); + } + + return null; + } + + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + var libraryPath = _depResolver.ResolveUnmanagedDllToPath(unmanagedDllName); + if (libraryPath != null) + { + return LoadUnmanagedDllFromPath(libraryPath); + } + + return IntPtr.Zero; + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs b/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs new file mode 100644 index 0000000..d31fc51 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs @@ -0,0 +1,917 @@ +using Discord.Commands.Builders; +using Microsoft.Extensions.DependencyInjection; +using Ellie.Marmalade.Adapters; +using EllieBot.Common.ModuleBehaviors; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Ellie.Marmalade; + +// ReSharper disable RedundantAssignment +public sealed class MarmaladeLoaderService : IMarmaladeLoaderService, IReadyExecutor, IEService +{ + private readonly CommandService _cmdService; + private readonly IServiceProvider _botServices; + private readonly IBehaviorHandler _behHandler; + private readonly IPubSub _pubSub; + private readonly IMarmaladeConfigService _marmaladeConfig; + + private readonly ConcurrentDictionary _resolved = new(); +#pragma warning disable IDE0090 // Use 'new(...)' + private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); +#pragma warning restore IDE0090 // Use 'new(...)' + + private readonly TypedKey _loadKey = new("marmalade:load"); + private readonly TypedKey _unloadKey = new("marmalade:unload"); + + private readonly TypedKey _stringsReload = new("marmalade:reload_strings"); + + private const string BASE_DIR = "data/marmalades"; + + public MarmaladeLoaderService(CommandService cmdService, + IServiceProvider botServices, + IBehaviorHandler behHandler, + IPubSub pubSub, + IMarmaladeConfigService marmaladeConfig) + { + _cmdService = cmdService; + _botServices = botServices; + _behHandler = behHandler; + _pubSub = pubSub; + _marmaladeConfig = marmaladeConfig; + + // has to be done this way to support this feature on sharded bots + _pubSub.Sub(_loadKey, async name => await InternalLoadAsync(name)); + _pubSub.Sub(_unloadKey, async name => await InternalUnloadAsync(name)); + + _pubSub.Sub(_stringsReload, async _ => await ReloadStringsInternal()); + } + + public IReadOnlyCollection GetAllMarmalades() + { + if (!Directory.Exists(BASE_DIR)) + return Array.Empty(); + + return Directory.GetDirectories(BASE_DIR) + .Select(x => Path.GetRelativePath(BASE_DIR, x)) + .ToArray(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public IReadOnlyCollection GetLoadedMarmalades(CultureInfo? culture) + { + var toReturn = new List(_resolved.Count); + foreach (var (name, resolvedData) in _resolved) + { + var canaries = new List(resolvedData.CanaryInfos.Count); + + foreach (var canaryInfos in resolvedData.CanaryInfos.Concat(resolvedData.CanaryInfos.SelectMany(x => x.Subcanaries))) + { + var commands = new List(); + + foreach (var command in canaryInfos.Commands) + { + commands.Add(new CanaryCommandStats(command.Aliases.First())); + } + + canaries.Add(new CanaryStats(canaryInfos.Name, commands)); + } + + toReturn.Add(new MarmaladeStats(name, resolvedData.Strings.GetDescription(culture), canaries)); + } + return toReturn; + } + + public async Task OnReadyAsync() + { + foreach (var name in _marmaladeConfig.GetLoadedMarmalades()) + { + var result = await InternalLoadAsync(name); + if (result != MarmaladeLoadResult.Success) + Log.Warning("Unable to load '{MarmaladeName}' marmalade", name); + else + Log.Warning("Loaded marmalade '{MarmaladeName}'", name); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public async Task LoadMarmaladeAsync(string marmaladeName) + { + // try loading on this shard first to see if it works + var res = await InternalLoadAsync(marmaladeName); + if (res == MarmaladeLoadResult.Success) + { + // if it does publish it so that other shards can load the medusa too + // this method will be ran twice on this shard but it doesn't matter as + // the second attempt will be ignored + await _pubSub.Pub(_loadKey, marmaladeName); + } + + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public async Task UnloadMarmaladeAsync(string marmaladeName) + { + var res = await InternalUnloadAsync(marmaladeName); + if (res == MarmaladeUnloadResult.Success) + { + await _pubSub.Pub(_unloadKey, marmaladeName); + } + + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string[] GetCommandExampleArgs(string marmaladeName, string commandName, CultureInfo culture) + { + if (!_resolved.TryGetValue(marmaladeName, out var data)) + return Array.Empty(); + + return data.Strings.GetCommandStrings(commandName, culture).Args + ?? data.CanaryInfos + .SelectMany(x => x.Commands) + .FirstOrDefault(x => x.Aliases.Any(alias + => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) + ?.OptionalStrings + .Args + ?? new[] { string.Empty }; + } + + public Task ReloadStrings() + => _pubSub.Pub(_stringsReload, true); + + [MethodImpl(MethodImplOptions.NoInlining)] + private void ReloadStringsSync() + { + foreach (var resolved in _resolved.Values) + { + resolved.Strings.Reload(); + } + } + + private async Task ReloadStringsInternal() + { + await _lock.WaitAsync(); + try + { + ReloadStringsSync(); + } + finally + { + _lock.Release(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetCommandDescription(string marmaladeName, string commandName, CultureInfo culture) + { + if (!_resolved.TryGetValue(marmaladeName, out var data)) + return string.Empty; + + return data.Strings.GetCommandStrings(commandName, culture).Desc + ?? data.CanaryInfos + .SelectMany(x => x.Commands) + .FirstOrDefault(x => x.Aliases.Any(alias + => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) + ?.OptionalStrings + .Desc + ?? string.Empty; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async ValueTask InternalLoadAsync(string name) + { + if (_resolved.ContainsKey(name)) + return MarmaladeLoadResult.AlreadyLoaded; + + var safeName = Uri.EscapeDataString(name); + + await _lock.WaitAsync(); + try + { + if (LoadAssemblyInternal(safeName, + out var ctx, + out var canaryData, + out var services, + out var strings, + out var typeReaders)) + { + var moduleInfos = new List(); + + LoadTypeReadersInternal(typeReaders); + + foreach (var point in canaryData) + { + try + { + // initialize canary and subcanaries + await point.Instance.InitializeAsync(); + foreach (var sub in point.Subcanaries) + { + await sub.Instance.InitializeAsync(); + } + + var module = await LoadModuleInternalAsync(name, point, strings, services); + moduleInfos.Add(module); + } + catch (Exception ex) + { + Log.Warning(ex, + "Error loading canary {CanaryName}", + point.Name); + } + } + + var execs = GetExecsInternal(canaryData, strings, services); + await _behHandler.AddRangeAsync(execs); + + _resolved[name] = new(LoadContext: ctx, + ModuleInfos: moduleInfos.ToImmutableArray(), + CanaryInfos: canaryData.ToImmutableArray(), + strings, + typeReaders, + execs) + { + Services = services + }; + + + services = null; + _marmaladeConfig.AddLoadedMarmalade(safeName); + return MarmaladeLoadResult.Success; + } + + return MarmaladeLoadResult.Empty; + } + catch (Exception ex) when (ex is FileNotFoundException or BadImageFormatException) + { + return MarmaladeLoadResult.NotFound; + } + catch (Exception ex) + { + Log.Error(ex, "An error occurred loading a marmalade"); + return MarmaladeLoadResult.UnknownError; + } + finally + { + _lock.Release(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private IReadOnlyCollection GetExecsInternal(IReadOnlyCollection canaryData, IMarmaladeStrings strings, IServiceProvider services) + { + var behs = new List(); + foreach (var canary in canaryData) + { + behs.Add(new BehaviorAdapter(new(canary.Instance), strings, services)); + + foreach (var sub in canary.Subcanaries) + { + behs.Add(new BehaviorAdapter(new(sub.Instance), strings, services)); + } + } + + return behs; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void LoadTypeReadersInternal(Dictionary typeReaders) + { + var notAddedTypeReaders = new List(); + foreach (var (type, typeReader) in typeReaders) + { + // if type reader for this type already exists, it will not be replaced + if (_cmdService.TypeReaders.Contains(type)) + { + notAddedTypeReaders.Add(type); + continue; + } + + _cmdService.AddTypeReader(type, typeReader); + } + + // remove the ones that were not added + // to prevent them from being unloaded later + // as they didn't come from this marmalade + foreach (var toRemove in notAddedTypeReaders) + { + typeReaders.Remove(toRemove); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool LoadAssemblyInternal( + string safeName, + [NotNullWhen(true)] out WeakReference? ctxWr, + [NotNullWhen(true)] out IReadOnlyCollection? canaryData, + out IServiceProvider services, + out IMarmaladeStrings strings, + out Dictionary typeReaders) + { + ctxWr = null; + canaryData = null; + + var path = $"{BASE_DIR}/{safeName}/{safeName}.dll"; + strings = MarmaladeStrings.CreateDefault($"{BASE_DIR}/{safeName}"); + var ctx = new MarmaladeAssemblyLoadContext(Path.GetDirectoryName(path)); + var a = ctx.LoadFromAssemblyPath(Path.GetFullPath(path)); + var sis = LoadCanariesFromAssembly(a, out services); + typeReaders = LoadTypeReadersFromAssembly(a, strings, services); + + if (sis.Count == 0) + { + return false; + } + + ctxWr = new(ctx); + canaryData = sis; + + return true; + } + + + private static readonly Type _paramParserType = typeof(ParamParser<>); + + [MethodImpl(MethodImplOptions.NoInlining)] + private Dictionary LoadTypeReadersFromAssembly( + Assembly assembly, + IMarmaladeStrings strings, + IServiceProvider services) + { + var paramParsers = assembly.GetExportedTypes() + .Where(x => x.IsClass + && !x.IsAbstract + && x.BaseType is not null + && x.BaseType.IsGenericType + && x.BaseType.GetGenericTypeDefinition() == _paramParserType); + + var typeReaders = new Dictionary(); + foreach (var parserType in paramParsers) + { + var parserObj = ActivatorUtilities.CreateInstance(services, parserType); + + var targetType = parserType.BaseType!.GetGenericArguments()[0]; + var typeReaderInstance = (TypeReader)Activator.CreateInstance( + typeof(ParamParserAdapter<>).MakeGenericType(targetType), + args: new[] { parserObj, strings, services })!; + + typeReaders.Add(targetType, typeReaderInstance); + } + + return typeReaders; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task LoadModuleInternalAsync(string marmaladeName, CanaryInfo canaryInfo, IMarmaladeStrings strings, IServiceProvider services) + { + var module = await _cmdService.CreateModuleAsync(canaryInfo.Instance.Prefix, + CreateModuleFactory(marmaladeName, canaryInfo, strings, services)); + + return module; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private Action CreateModuleFactory( + string marmaladeName, + CanaryInfo canaryInfo, + IMarmaladeStrings strings, + IServiceProvider marmaladeServices) + => mb => + { + var m = mb.WithName(canaryInfo.Name); + + foreach (var f in canaryInfo.Filters) + { + m.AddPrecondition(new FilterAdapter(f, strings)); + } + + foreach (var cmd in canaryInfo.Commands) + { + m.AddCommand(cmd.Aliases.First(), + CreateCallback(cmd.ContextType, + new(canaryInfo), + new(cmd), + new(marmaladeServices), + strings), + CreateCommandFactory(marmaladeName, cmd, strings)); + } + + foreach (var subInfo in canaryInfo.Subcanaries) + m.AddModule(subInfo.Instance.Prefix, CreateModuleFactory(marmaladeName, subInfo, strings, marmaladeServices)); + }; + +#pragma warning disable IDE0090 // Use 'new(...)' + private static readonly RequireContextAttribute _reqGuild = new RequireContextAttribute(ContextType.Guild); + private static readonly RequireContextAttribute _reqDm = new RequireContextAttribute(ContextType.DM); +#pragma warning restore IDE0090 // Use 'new(...)' + private Action CreateCommandFactory(string marmaladeName, CanaryCommandData cmd, IMarmaladeStrings strings) + => (cb) => + { + cb.AddAliases(cmd.Aliases.Skip(1).ToArray()); + + if (cmd.ContextType == CommandContextType.Guild) + cb.AddPrecondition(_reqGuild); + else if (cmd.ContextType == CommandContextType.Dm) + cb.AddPrecondition(_reqDm); + + foreach (var f in cmd.Filters) + cb.AddPrecondition(new FilterAdapter(f, strings)); + + foreach (var ubp in cmd.UserAndBotPerms) + { + if (ubp is user_permAttribute up) + { + if (up.GuildPerm is { } gp) + cb.AddPrecondition(new UserPermAttribute(gp)); + else if (up.ChannelPerm is { } cp) + cb.AddPrecondition(new UserPermAttribute(cp)); + } + else if (ubp is bot_permAttribute bp) + { + if (bp.GuildPerm is { } gp) + cb.AddPrecondition(new BotPermAttribute(gp)); + else if (bp.ChannelPerm is { } cp) + cb.AddPrecondition(new BotPermAttribute(cp)); + } + else if (ubp is bot_owner_onlyAttribute) + { + cb.AddPrecondition(new OwnerOnlyAttribute()); + } + } + + cb.WithPriority(cmd.Priority); + + // using summary to save method name + // method name is used to retrieve desc/usages + cb.WithRemarks($"marmalade///{marmaladeName}"); + cb.WithSummary(cmd.MethodInfo.Name.ToLowerInvariant()); + + foreach (var param in cmd.Parameters) + { + cb.AddParameter(param.Name, param.Type, CreateParamFactory(param)); + } + }; + + private Action CreateParamFactory(ParamData paramData) + => (pb) => + { + pb.WithIsMultiple(paramData.IsParams) + .WithIsOptional(paramData.IsOptional) + .WithIsRemainder(paramData.IsLeftover); + + if (paramData.IsOptional) + pb.WithDefault(paramData.DefaultValue); + }; + + [MethodImpl(MethodImplOptions.NoInlining)] + private Func CreateCallback( + CommandContextType contextType, + WeakReference canaryDataWr, + WeakReference canaryCommandDataWr, + WeakReference marmaladeServicesWr, + IMarmaladeStrings strings) + => async (context, parameters, svcs, _) => + { + if (!canaryCommandDataWr.TryGetTarget(out var cmdData) + || !canaryDataWr.TryGetTarget(out var canaryData) + || !marmaladeServicesWr.TryGetTarget(out var marmaladeServices)) + { + Log.Warning("Attempted to run an unloaded canary's command"); + return; + } + + var paramObjs = ParamObjs(contextType, cmdData, parameters, context, svcs, marmaladeServices, strings); + + try + { + var methodInfo = cmdData.MethodInfo; + if (methodInfo.ReturnType == typeof(Task) + || (methodInfo.ReturnType.IsGenericType + && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))) + { + await (Task)methodInfo.Invoke(canaryData.Instance, paramObjs)!; + } + else if (methodInfo.ReturnType == typeof(ValueTask)) + { + await ((ValueTask)methodInfo.Invoke(canaryData.Instance, paramObjs)!).AsTask(); + } + else // if (methodInfo.ReturnType == typeof(void)) + { + methodInfo.Invoke(canaryData.Instance, paramObjs); + } + } + finally + { + paramObjs = null; + cmdData = null; + + canaryData = null; + marmaladeServices = null; + } + }; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static object[] ParamObjs( + CommandContextType contextType, + CanaryCommandData cmdData, + object[] parameters, + ICommandContext context, + IServiceProvider svcs, + IServiceProvider svcProvider, + IMarmaladeStrings strings) + { + var extraParams = contextType == CommandContextType.Unspecified ? 0 : 1; + extraParams += cmdData.InjectedParams.Count; + + var paramObjs = new object[parameters.Length + extraParams]; + + var startAt = 0; + if (contextType != CommandContextType.Unspecified) + { + paramObjs[0] = ContextAdapterFactory.CreateNew(context, strings, svcs); + + startAt = 1; + } + + for (var i = 0; i < cmdData.InjectedParams.Count; i++) + { + var svc = svcProvider.GetService(cmdData.InjectedParams[i]); + if (svc is null) + { + throw new ArgumentException($"Cannot inject a service of type {cmdData.InjectedParams[i]}"); + } + + paramObjs[i + startAt] = svc; + + svc = null; + } + + startAt += cmdData.InjectedParams.Count; + + for (var i = 0; i < parameters.Length; i++) + paramObjs[startAt + i] = parameters[i]; + + return paramObjs; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task InternalUnloadAsync(string name) + { + if (!_resolved.Remove(name, out var lsi)) + return MarmaladeUnloadResult.NotLoaded; + + await _lock.WaitAsync(); + try + { + UnloadTypeReaders(lsi.TypeReaders); + + foreach (var mi in lsi.ModuleInfos) + { + await _cmdService.RemoveModuleAsync(mi); + } + + await _behHandler.RemoveRangeAsync(lsi.Execs); + + await DisposeCanaryInstances(lsi); + + var lc = lsi.LoadContext; + + // removing this line will prevent assembly from being unloaded quickly + // as this local variable will be held for a long time potentially + // due to how async works + lsi.Services = null!; + lsi = null; + + _marmaladeConfig.RemoveLoadedMarmalade(name); + return UnloadInternal(lc) + ? MarmaladeUnloadResult.Success + : MarmaladeUnloadResult.PossiblyUnable; + } + finally + { + _lock.Release(); + } + } + + private void UnloadTypeReaders(Dictionary valueTypeReaders) + { + foreach (var tr in valueTypeReaders) + { + _cmdService.TryRemoveTypeReader(tr.Key, false, out _); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task DisposeCanaryInstances(ResolvedMarmalade marmalade) + { + foreach (var si in marmalade.CanaryInfos) + { + try + { + await si.Instance.DisposeAsync(); + foreach (var sub in si.Subcanaries) + { + await sub.Instance.DisposeAsync(); + } + } + catch (Exception ex) + { + Log.Warning(ex, + "Failed cleanup of Canary {CanaryName}. This marmalade might not unload correctly", + si.Instance.Name); + } + } + + // marmalades = null; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool UnloadInternal(WeakReference lsi) + { + UnloadContext(lsi); + GcCleanup(); + + return !lsi.TryGetTarget(out _); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void UnloadContext(WeakReference lsiLoadContext) + { + if (lsiLoadContext.TryGetTarget(out var ctx)) + ctx.Unload(); + } + + private void GcCleanup() + { + // cleanup + for (var i = 0; i < 10; i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.WaitForFullGCComplete(); + GC.Collect(); + } + } + + private static readonly Type _canaryType = typeof(Canary); + + [MethodImpl(MethodImplOptions.NoInlining)] + private IServiceProvider LoadMarmaladeServicesInternal(Assembly a) + => new ServiceCollection() + .Scan(x => x.FromAssemblies(a) + .AddClasses(static x => x.WithAttribute(x => x.Lifetime == Lifetime.Transient)) + .AsSelfWithInterfaces() + .WithTransientLifetime() + .AddClasses(static x => x.WithAttribute(x => x.Lifetime == Lifetime.Singleton)) + .AsSelfWithInterfaces() + .WithSingletonLifetime()) + .BuildServiceProvider(); + + + [MethodImpl(MethodImplOptions.NoInlining)] + public IReadOnlyCollection LoadCanariesFromAssembly(Assembly a, out IServiceProvider services) + { + var marmaladeServices = LoadMarmaladeServicesInternal(a); + services = new MarmaladeServiceProvider(_botServices, marmaladeServices); + + // find all types in teh assembly + var types = a.GetExportedTypes(); + // snek is always a public non abstract class + var classes = types.Where(static x => x.IsClass + && (x.IsNestedPublic || x.IsPublic) + && !x.IsAbstract + && x.BaseType == _canaryType + && (x.DeclaringType is null || x.DeclaringType.IsAssignableTo(_canaryType))) + .ToList(); + + var topModules = new Dictionary(); + + foreach (var cl in classes) + { + if (cl.DeclaringType is not null) + continue; + + // get module data, and add it to the topModules dictionary + var module = GetModuleData(cl, services); + topModules.Add(cl, module); + } + + foreach (var c in classes) + { + if (c.DeclaringType is not Type dt) + continue; + + // if there is no top level module which this module is a child of + // just print a warning and skip it + if (!topModules.TryGetValue(dt, out var parentData)) + { + Log.Warning("Can't load submodule {SubName} because parent module {Name} does not exist", + c.Name, + dt.Name); + continue; + } + + GetModuleData(c, services, parentData); + } + + return topModules.Values.ToArray(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private CanaryInfo GetModuleData(Type type, IServiceProvider services, CanaryInfo? parentData = null) + { + var filters = type.GetCustomAttributes(true) + .ToArray(); + + var instance = (Canary)ActivatorUtilities.CreateInstance(services, type); + + var module = new CanaryInfo(instance.Name, + parentData, + instance, + GetCommands(instance, type), + filters); + + if (parentData is not null) + parentData.Subcanaries.Add(module); + + return module; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private IReadOnlyCollection GetCommands(Canary instance, Type type) + { + var methodInfos = type + .GetMethods(BindingFlags.Instance + | BindingFlags.DeclaredOnly + | BindingFlags.Public) + .Where(static x => + { + if (x.GetCustomAttribute(true) is null) + return false; + + if (x.ReturnType.IsGenericType) + { + var genericType = x.ReturnType.GetGenericTypeDefinition(); + if (genericType == typeof(Task<>)) + return true; + + // if (genericType == typeof(ValueTask<>)) + // return true; + + Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", + x.Name, + x.ReturnType); + + return false; + } + + var succ = x.ReturnType == typeof(Task) + || x.ReturnType == typeof(ValueTask) + || x.ReturnType == typeof(void); + + if (!succ) + { + Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", + x.Name, + x.ReturnType); + } + + return succ; + }); + + + var cmds = new List(); + foreach (var method in methodInfos) + { + var filters = method.GetCustomAttributes(true).ToArray(); + var userAndBotPerms = method.GetCustomAttributes(true) + .ToArray(); + var prio = method.GetCustomAttribute(true)?.Priority ?? 0; + + var paramInfos = method.GetParameters(); + var cmdParams = new List(); + var diParams = new List(); + var cmdContext = CommandContextType.Unspecified; + var canInject = false; + for (var paramCounter = 0; paramCounter < paramInfos.Length; paramCounter++) + { + var pi = paramInfos[paramCounter]; + + var paramName = pi.Name ?? "unnamed"; + var isContext = paramCounter == 0 && pi.ParameterType.IsAssignableTo(typeof(AnyContext)); + + var leftoverAttribute = pi.GetCustomAttribute(true); + var hasDefaultValue = pi.HasDefaultValue; + var defaultValue = pi.DefaultValue; + var isLeftover = leftoverAttribute != null; + var isParams = pi.GetCustomAttribute() is not null; + var paramType = pi.ParameterType; + var isInjected = pi.GetCustomAttribute(true) is not null; + + if (isContext) + { + if (hasDefaultValue || leftoverAttribute != null || isParams) + throw new ArgumentException("IContext parameter cannot be optional, leftover, constant or params. " + GetErrorPath(method, pi)); + + if (paramCounter != 0) + throw new ArgumentException($"IContext parameter has to be first. {GetErrorPath(method, pi)}"); + + canInject = true; + + if (paramType.IsAssignableTo(typeof(GuildContext))) + cmdContext = CommandContextType.Guild; + else if (paramType.IsAssignableTo(typeof(DmContext))) + cmdContext = CommandContextType.Dm; + else + cmdContext = CommandContextType.Any; + + continue; + } + + if (isInjected) + { + if (!canInject && paramCounter != 0) + throw new ArgumentException($"Parameters marked as [Injected] have to come after IContext"); + + canInject = true; + + diParams.Add(paramType); + continue; + } + + canInject = false; + + if (isParams) + { + if (hasDefaultValue) + throw new NotSupportedException("Params can't have const values at the moment. " + + GetErrorPath(method, pi)); + // if it's params, it means it's an array, and i only need a parser for the actual type, + // as the parser will run on each array element, it can't be null + paramType = paramType.GetElementType()!; + } + + // leftover can only be the last parameter. + if (isLeftover && paramCounter != paramInfos.Length - 1) + { + var path = GetErrorPath(method, pi); + Log.Error("Only one parameter can be marked [Leftover] and it has to be the last one. {Path} ", + path); + throw new ArgumentException("Leftover attribute error."); + } + + cmdParams.Add(new ParamData(paramType, paramName, hasDefaultValue, defaultValue, isLeftover, isParams)); + } + + + var cmdAttribute = method.GetCustomAttribute(true)!; + var aliases = cmdAttribute.Aliases; + if (aliases.Length == 0) + aliases = new[] { method.Name.ToLowerInvariant() }; + + cmds.Add(new( + aliases, + method, + instance, + filters, + userAndBotPerms, + cmdContext, + diParams, + cmdParams, + new(cmdAttribute.desc, cmdAttribute.args), + prio + )); + } + + return cmds; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private string GetErrorPath(MethodInfo m, System.Reflection.ParameterInfo pi) + => $@"Module: {m.DeclaringType?.Name} +Command: {m.Name} +ParamName: {pi.Name} +ParamType: {pi.ParameterType.Name}"; +} + +public enum MarmaladeLoadResult +{ + Success, + NotFound, + AlreadyLoaded, + Empty, + UnknownError, +} + +public enum MarmaladeUnloadResult +{ + Success, + NotLoaded, + PossiblyUnable, + NotFound, +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs b/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs new file mode 100644 index 0000000..c2f3c76 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs @@ -0,0 +1,24 @@ +using System.Runtime.CompilerServices; + +namespace Ellie.Marmalade; + +public class MarmaladeServiceProvider : IServiceProvider +{ + private readonly IServiceProvider _ellieServices; + private readonly IServiceProvider _marmaladeServices; + + public MarmaladeServiceProvider(IServiceProvider ellieServices, IServiceProvider marmaladeServices) + { + _ellieServices = ellieServices; + _marmaladeServices = marmaladeServices; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public object? GetService(Type serviceType) + { + if (!serviceType.Assembly.IsCollectible) + return _ellieServices.GetService(serviceType); + + return _marmaladeServices.GetService(serviceType); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs b/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs new file mode 100644 index 0000000..412243d --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs @@ -0,0 +1,46 @@ +using Microsoft.VisualBasic; +using System.Reflection; +using CommandStrings = Ellie.Marmalade.CommandStrings; + +namespace Ellie.Marmalade; + +public sealed class CanaryCommandData +{ + public CanaryCommandData( + IReadOnlyCollection aliases, + MethodInfo methodInfo, + Canary module, + FilterAttribute[] filters, + MarmaladePermAttribute[] userAndBotPerms, + CommandContextType contextType, + IReadOnlyList injectedParams, + IReadOnlyList parameters, + CommandStrings strings, + int priority) + { + Aliases = aliases; + MethodInfo = methodInfo; + Module = module; + Filters = filters; + UserAndBotPerms = userAndBotPerms; + ContextType = contextType; + InjectedParams = injectedParams; + Parameters = parameters; + Priority = priority; + OptionalStrings = strings; + } + + public MarmaladePermAttribute[] UserAndBotPerms { get; set; } + + public CommandStrings OptionalStrings { get; set; } + + public IReadOnlyCollection Aliases { get; } + public MethodInfo MethodInfo { get; set; } + public Canary Module { get; set; } + public FilterAttribute[] Filters { get; set; } + public CommandContextType ContextType { get; } + public IReadOnlyList InjectedParams { get; } + public IReadOnlyList Parameters { get; } + public int Priority { get; } + +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/CanaryData.cs b/src/EllieBot/Common/Marmalade/Models/CanaryData.cs new file mode 100644 index 0000000..b3938e7 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Models/CanaryData.cs @@ -0,0 +1,11 @@ +namespace Ellie.Marmalade; + +public sealed record CanaryInfo( + string Name, + CanaryInfo? Parent, + Canary Instance, + IReadOnlyCollection Commands, + IReadOnlyCollection Filters) +{ + public List Subcanaries { get; set; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/ParamData.cs b/src/EllieBot/Common/Marmalade/Models/ParamData.cs new file mode 100644 index 0000000..e329958 --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Models/ParamData.cs @@ -0,0 +1,10 @@ +namespace Ellie.Marmalade; + +public sealed record ParamData( + Type Type, + string Name, + bool IsOptional, + object? DefaultValue, + bool IsLeftover, + bool IsParams +); \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs b/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs new file mode 100644 index 0000000..bf40d7a --- /dev/null +++ b/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs @@ -0,0 +1,14 @@ +using System.Collections.Immutable; + +namespace Ellie.Marmalade; + +public sealed record ResolvedMarmalade( + WeakReference LoadContext, + IImmutableList ModuleInfos, + IImmutableList CanaryInfos, + IMarmaladeStrings Strings, + Dictionary TypeReaders, + IReadOnlyCollection Execs) +{ + public IServiceProvider Services { get; set; } = null!; +} \ No newline at end of file From 20627b1a61cba842aa48126b972d0b6a33f05a8a Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 31 Mar 2024 23:52:43 +1300 Subject: [PATCH 18/62] Added pubsub to Ellie --- src/EllieBot/Common/PubSub/EventPubSub.cs | 80 +++++++++++++++++++++++ src/EllieBot/Common/PubSub/IPubSub.cs | 10 +++ src/EllieBot/Common/PubSub/ISeria.cs | 7 ++ src/EllieBot/Common/PubSub/JsonSeria.cs | 27 ++++++++ src/EllieBot/Common/PubSub/RedisPubSub.cs | 52 +++++++++++++++ src/EllieBot/Common/PubSub/TypedKey.cs | 30 +++++++++ src/EllieBot/Common/PubSub/YamlSeria.cs | 39 +++++++++++ 7 files changed, 245 insertions(+) create mode 100644 src/EllieBot/Common/PubSub/EventPubSub.cs create mode 100644 src/EllieBot/Common/PubSub/IPubSub.cs create mode 100644 src/EllieBot/Common/PubSub/ISeria.cs create mode 100644 src/EllieBot/Common/PubSub/JsonSeria.cs create mode 100644 src/EllieBot/Common/PubSub/RedisPubSub.cs create mode 100644 src/EllieBot/Common/PubSub/TypedKey.cs create mode 100644 src/EllieBot/Common/PubSub/YamlSeria.cs diff --git a/src/EllieBot/Common/PubSub/EventPubSub.cs b/src/EllieBot/Common/PubSub/EventPubSub.cs new file mode 100644 index 0000000..0e45ed8 --- /dev/null +++ b/src/EllieBot/Common/PubSub/EventPubSub.cs @@ -0,0 +1,80 @@ +namespace EllieBot.Common; + +public class EventPubSub : IPubSub +{ + private readonly Dictionary>>> _actions = new(); + private readonly object _locker = new(); + + public Task Sub(in TypedKey key, Func action) + where TData : notnull + { + Func localAction = obj => action((TData)obj); + lock (_locker) + { + if (!_actions.TryGetValue(key.Key, out var keyActions)) + { + keyActions = new(); + _actions[key.Key] = keyActions; + } + + if (!keyActions.TryGetValue(action, out var sameActions)) + { + sameActions = new(); + keyActions[action] = sameActions; + } + + sameActions.Add(localAction); + + return Task.CompletedTask; + } + } + + public Task Pub(in TypedKey key, TData data) + where TData : notnull + { + lock (_locker) + { + if (_actions.TryGetValue(key.Key, out var actions)) + // if this class ever gets used, this needs to be properly implemented + // 1. ignore all valuetasks which are completed + // 2. run all other tasks in parallel + return actions.SelectMany(kvp => kvp.Value).Select(action => action(data).AsTask()).WhenAll(); + + return Task.CompletedTask; + } + } + + public Task Unsub(in TypedKey key, Func action) + { + lock (_locker) + { + // get subscriptions for this action + if (_actions.TryGetValue(key.Key, out var actions)) + // get subscriptions which have the same action hash code + // note: having this as a list allows for multiple subscriptions of + // the same insance's/static method + { + if (actions.TryGetValue(action, out var sameActions)) + { + // remove last subscription + sameActions.RemoveAt(sameActions.Count - 1); + + // if the last subscription was the only subscription + // we can safely remove this action's dictionary entry + if (sameActions.Count == 0) + { + actions.Remove(action); + + // if our dictionary has no more elements after + // removing the entry + // it's safe to remove it from the key's subscriptions + if (actions.Count == 0) + _actions.Remove(key.Key); + } + } + } + + return Task.CompletedTask; + } + } +} diff --git a/src/EllieBot/Common/PubSub/IPubSub.cs b/src/EllieBot/Common/PubSub/IPubSub.cs new file mode 100644 index 0000000..0d52156 --- /dev/null +++ b/src/EllieBot/Common/PubSub/IPubSub.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Common; + +public interface IPubSub +{ + public Task Pub(in TypedKey key, TData data) + where TData : notnull; + + public Task Sub(in TypedKey key, Func action) + where TData : notnull; +} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/ISeria.cs b/src/EllieBot/Common/PubSub/ISeria.cs new file mode 100644 index 0000000..0eb9706 --- /dev/null +++ b/src/EllieBot/Common/PubSub/ISeria.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Common; + +public interface ISeria +{ + byte[] Serialize(T data); + T? Deserialize(byte[]? data); +} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/JsonSeria.cs b/src/EllieBot/Common/PubSub/JsonSeria.cs new file mode 100644 index 0000000..b8f8033 --- /dev/null +++ b/src/EllieBot/Common/PubSub/JsonSeria.cs @@ -0,0 +1,27 @@ +using EllieBot.Common.JsonConverters; +using System.Text.Json; + +namespace EllieBot.Common; + +public class JsonSeria : ISeria +{ + private readonly JsonSerializerOptions _serializerOptions = new() + { + Converters = + { + new Rgba32Converter(), + new CultureInfoConverter() + } + }; + + public byte[] Serialize(T data) + => JsonSerializer.SerializeToUtf8Bytes(data, _serializerOptions); + + public T? Deserialize(byte[]? data) + { + if (data is null) + return default; + + return JsonSerializer.Deserialize(data, _serializerOptions); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/RedisPubSub.cs b/src/EllieBot/Common/PubSub/RedisPubSub.cs new file mode 100644 index 0000000..82d8a99 --- /dev/null +++ b/src/EllieBot/Common/PubSub/RedisPubSub.cs @@ -0,0 +1,52 @@ +using StackExchange.Redis; + +namespace EllieBot.Common; + +public sealed class RedisPubSub : IPubSub +{ + private readonly IBotCredentials _creds; + private readonly ConnectionMultiplexer _multi; + private readonly ISeria _serializer; + + public RedisPubSub(ConnectionMultiplexer multi, ISeria serializer, IBotCredentials creds) + { + _multi = multi; + _serializer = serializer; + _creds = creds; + } + + public Task Pub(in TypedKey key, TData data) + where TData : notnull + { + var serialized = _serializer.Serialize(data); + return _multi.GetSubscriber() + .PublishAsync($"{_creds.RedisKey()}:{key.Key}", serialized, CommandFlags.FireAndForget); + } + + public Task Sub(in TypedKey key, Func action) + where TData : notnull + { + var eventName = key.Key; + + async void OnSubscribeHandler(RedisChannel _, RedisValue data) + { + try + { + var dataObj = _serializer.Deserialize(data); + if (dataObj is not null) + await action(dataObj); + else + { + Log.Warning("Publishing event {EventName} with a null value. This is not allowed", + eventName); + } + } + catch (Exception ex) + { + Log.Error("Error handling the event {EventName}: {ErrorMessage}", eventName, ex.Message); + } + } + + return _multi.GetSubscriber().SubscribeAsync($"{_creds.RedisKey()}:{eventName}", OnSubscribeHandler); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/TypedKey.cs b/src/EllieBot/Common/PubSub/TypedKey.cs new file mode 100644 index 0000000..e637707 --- /dev/null +++ b/src/EllieBot/Common/PubSub/TypedKey.cs @@ -0,0 +1,30 @@ +namespace EllieBot.Common; + +public readonly struct TypedKey +{ + public string Key { get; } + + public TypedKey(in string key) + => Key = key; + + public static implicit operator TypedKey(in string input) + => new(input); + + public static implicit operator string(in TypedKey input) + => input.Key; + + public static bool operator ==(in TypedKey left, in TypedKey right) + => left.Key == right.Key; + + public static bool operator !=(in TypedKey left, in TypedKey right) + => !(left == right); + + public override bool Equals(object? obj) + => obj is TypedKey o && o == this; + + public override int GetHashCode() + => Key?.GetHashCode() ?? 0; + + public override string ToString() + => Key; +} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/YamlSeria.cs b/src/EllieBot/Common/PubSub/YamlSeria.cs new file mode 100644 index 0000000..2feb5c8 --- /dev/null +++ b/src/EllieBot/Common/PubSub/YamlSeria.cs @@ -0,0 +1,39 @@ +using EllieBot.Common.Configs; +using EllieBot.Common.Yml; +using System.Text.RegularExpressions; +using YamlDotNet.Serialization; + +namespace EllieBot.Common; + +public class YamlSeria : IConfigSeria +{ + private static readonly Regex _codePointRegex = + new(@"(\\U(?[a-zA-Z0-9]{8})|\\u(?[a-zA-Z0-9]{4})|\\x(?[a-zA-Z0-9]{2}))", + RegexOptions.Compiled); + + private readonly IDeserializer _deserializer; + private readonly ISerializer _serializer; + + public YamlSeria() + { + _serializer = Yaml.Serializer; + _deserializer = Yaml.Deserializer; + } + + public string Serialize(T obj) + where T : notnull + { + var escapedOutput = _serializer.Serialize(obj); + var output = _codePointRegex.Replace(escapedOutput, + me => + { + var str = me.Groups["code"].Value; + var newString = YamlHelper.UnescapeUnicodeCodePoint(str); + return newString; + }); + return output; + } + + public T Deserialize(string data) + => _deserializer.Deserialize(data); +} \ No newline at end of file From 1934b2d3c5a54583d67f286a18a53153f3b9021b Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 3 Apr 2024 23:02:45 +1300 Subject: [PATCH 19/62] Fixed some issues with naming schemes --- TODO.md | 3 +- src/EllieBot/creds_example.yml | 24 +++++++------- src/EllieBot/data/aliases.yml | 2 +- src/EllieBot/data/gambling.yml | 2 +- src/EllieBot/data/searches.yml | 4 +-- .../data/strings/commands/commands.en-US.yml | 32 +++++++++---------- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/TODO.md b/TODO.md index 476e447..25bd69c 100644 --- a/TODO.md +++ b/TODO.md @@ -2,4 +2,5 @@ - Finish the full system rewrite - Finish the EllieBot.Tests project - - Finish the EllieBot project \ No newline at end of file + - Finish the EllieBot project + - Fix the issues MarmaladeLoaderService.cs \ No newline at end of file diff --git a/src/EllieBot/creds_example.yml b/src/EllieBot/creds_example.yml index 8146199..e13379b 100644 --- a/src/EllieBot/creds_example.yml +++ b/src/EllieBot/creds_example.yml @@ -11,7 +11,7 @@ usePrivilegedIntents: true # Leave at 1 if you don't know what you're doing. # # note: If you are planning to have more than one shard, then you must change botCache to 'redis'. -# Also, in that case you should be using NadekoBot.Coordinator to start the bot, and it will correctly override this value. +# Also, in that case you should be using EllieBot.Coordinator to start the bot, and it will correctly override this value. totalShards: 1 # Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it. # Then, go to APIs and Services -> Credentials and click Create credentials -> API key. @@ -27,21 +27,21 @@ googleApiKey: "" google: searchId: imageSearchId: -# Settings for voting system for discordbots. Meant for use on global Nadeko. +# Settings for voting system for discordbots. Meant for use on global Ellie. votes: # top.gg votes service url - # This is the url of your instance of the NadekoBot.Votes api + # This is the url of your instance of the EllieBot.Votes api # Example: https://votes.my.cool.bot.com topggServiceUrl: "" # Authorization header value sent to the TopGG service url with each request - # This should be equivalent to the TopggKey in your NadekoBot.Votes api appsettings.json file + # This should be equivalent to the TopggKey in your EllieBot.Votes api appsettings.json file topggKey: "" # discords.com votes service url - # This is the url of your instance of the NadekoBot.Votes api + # This is the url of your instance of the EllieBot.Votes api # Example: https://votes.my.cool.bot.com discordsServiceUrl: "" # Authorization header value sent to the Discords service url with each request - # This should be equivalent to the DiscordsKey in your NadekoBot.Votes api appsettings.json file + # This should be equivalent to the DiscordsKey in your EllieBot.Votes api appsettings.json file discordsKey: "" # Patreon auto reward system settings. # go to https://www.patreon.com/portal -> my clients -> create client @@ -72,10 +72,10 @@ db: type: sqlite # Database connection string. # You MUST change this if you're not using "sqlite" type. - # Default is "Data Source=data/NadekoBot.db" - # Example for mysql: "Server=localhost;Port=3306;Uid=root;Pwd=my_super_secret_mysql_password;Database=nadeko" - # Example for postgresql: "Server=localhost;Port=5432;User Id=postgres;Password=my_super_secret_postgres_password;Database=nadeko;" - connectionString: Data Source=data/NadekoBot.db + # Default is "Data Source=data/EllieBot.db" + # Example for mysql: "Server=localhost;Port=3306;Uid=root;Pwd=my_super_secret_mysql_password;Database=ellie" + # Example for postgresql: "Server=localhost;Port=5432;User Id=postgres;Password=my_super_secret_postgres_password;Database=ellie;" + connectionString: Data Source=data/EllieBot.db # Address and port of the coordinator endpoint. Leave empty for default. # Change only if you've changed the coordinator address or port. coordinatorUrl: http://localhost:3442 @@ -106,9 +106,9 @@ twitchClientSecret: # {1} -> total shards # Linux default # cmd: dotnet -# args: "NadekoBot.dll -- {0}" +# args: "EllieBot.dll -- {0}" # Windows default -# cmd: NadekoBot.exe +# cmd: EllieBot.exe # args: "{0}" restartCommand: cmd: diff --git a/src/EllieBot/data/aliases.yml b/src/EllieBot/data/aliases.yml index 6bf6b78..9348169 100644 --- a/src/EllieBot/data/aliases.yml +++ b/src/EllieBot/data/aliases.yml @@ -1273,7 +1273,7 @@ quotesimport: - qimport showembed: - showembed -# NadekoExpressions +# EllieExpressions exprtoggleglobal: - exprtoggleglobal - extg diff --git a/src/EllieBot/data/gambling.yml b/src/EllieBot/data/gambling.yml index d381cd3..4064cfe 100644 --- a/src/EllieBot/data/gambling.yml +++ b/src/EllieBot/data/gambling.yml @@ -250,7 +250,7 @@ waifu: name: ToiletPaper negative: true # Amount of currency selfhosters will get PER pledged dollar CENT. -# 1 = 100 currency per $. Used almost exclusively on public nadeko. +# 1 = 100 currency per $. Used almost exclusively on public ellie. patreonCurrencyPerCent: 1 # Currency reward per vote. # This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting diff --git a/src/EllieBot/data/searches.yml b/src/EllieBot/data/searches.yml index a4a2309..9b7ab5c 100644 --- a/src/EllieBot/data/searches.yml +++ b/src/EllieBot/data/searches.yml @@ -20,7 +20,7 @@ imgSearchEngine: Google # - `invidious` - recommended advanced, uses invidious api. Requires at least one invidious instance specified in the `invidiousInstances` property ytProvider: Ytdlp # Set the searx instance urls in case you want to use 'searx' for either img or web search. -# Nadeko will use a random one for each request. +# Ellie will use a random one for each request. # Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com` # Instances specified must support 'format=json' query parameter. # - In case you're running your own searx instance, set @@ -34,7 +34,7 @@ ytProvider: Ytdlp # - If you're using a public instance, make sure that the instance you're using supports it (they usually don't) searxInstances: [] # Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search -# Nadeko will use a random one for each request. +# Ellie will use a random one for each request. # These instances may be used for music queue functionality in the future. # Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com # diff --git a/src/EllieBot/data/strings/commands/commands.en-US.yml b/src/EllieBot/data/strings/commands/commands.en-US.yml index 4b1996d..a916919 100644 --- a/src/EllieBot/data/strings/commands/commands.en-US.yml +++ b/src/EllieBot/data/strings/commands/commands.en-US.yml @@ -254,7 +254,7 @@ autoassignrole: - "" - "RoleName" leave: - desc: "Makes Nadeko leave the server. Either server name or server ID is required." + desc: "Makes Ellie leave the server. Either server name or server ID is required." args: - "123123123331" slowmode: @@ -375,7 +375,7 @@ setchanlname: args: - "NewName" prune: - desc: "`{0}prune` removes all Nadeko's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel." + desc: "`{0}prune` removes all Ellie's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel." args: - "" - "-s" @@ -399,7 +399,7 @@ setnick: - "BotNickname" - "@SomeUser New Nickname" setavatar: - desc: "Sets a new avatar image for the NadekoBot. Parameter is a direct link to an image." + desc: "Sets a new avatar image for the EllieBot. Parameter is a direct link to an image." args: - "https://i.imgur.com/xTG3a1I.jpg" setgame: @@ -464,7 +464,7 @@ checkperms: - "me" - "bot" stats: - desc: "Shows some basic stats for Nadeko." + desc: "Shows some basic stats for Ellie." args: - "" userid: @@ -793,7 +793,7 @@ choose: args: - "Get up;Sleep;Sleep more" rps: - desc: "Play a game of Rocket-Paperclip-Scissors with Nadeko. You can bet on it. Multiplier is the same as on betflip." + desc: "Play a game of Rocket-Paperclip-Scissors with Ellie. You can bet on it. Multiplier is the same as on betflip." args: - "r 100" - "scissors" @@ -1311,7 +1311,7 @@ muterole: - "" - "Silenced" adsarm: - desc: "Toggles the automatic deletion of the user's message and Nadeko's confirmations for `{0}iam` and `{0}iamn` commands." + desc: "Toggles the automatic deletion of the user's message and Ellie's confirmations for `{0}iam` and `{0}iamn` commands." args: - "" setstream: @@ -1476,7 +1476,7 @@ slottest: args: - "1000" slot: - desc: "Play Nadeko slots. 1 second cooldown per user." + desc: "Play Ellie slots. 1 second cooldown per user." args: - "5" affinity: @@ -1634,7 +1634,7 @@ aliaslist: - "" - "3" alias: - desc: "Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one." + desc: "Create a custom alias for a certain Ellie command. Provide no alias to remove the existing one." args: - "allin {0}bf all h" - '"linux thingy" >loonix Spyware Windows' @@ -2257,31 +2257,31 @@ deleteemptyservers: desc: "Deletes all servers in which the bot is the only member." args: - "" -medusaload: +marmaladeload: desc: |- Loads a marmalade with the specified name from the data/marmalades/ folder. Provide no name to see the list of loadable marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) args: - - "mycoolmedusa" + - "mycoolmarmalade" - "" -medusaunload: +marmaladeunload: desc: |- Unloads the previously loaded marmalade. Provide no name to see the list of unloadable marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) args: - - "mycoolmedusa" + - "mycoolmarmalade" - "" -medusainfo: +marmaladeinfo: desc: |- Shows information about the specified marmalade such as the author, name, description, list of sneks, number of commands etc. Provide no name to see the basic information about all loaded marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) args: - - "mycoolmedusa" + - "mycoolmarmalade" - "" -medusalist: +marmaladelist: desc: |- Lists all loaded and unloaded marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) @@ -2324,7 +2324,7 @@ eval: `channel` - Channel in which the command is executed `user` - User executing the command `ctx` - Discord.Net command context - `services` - Nadeko's IServiceProvider + `services` - Ellie's IServiceProvider args: - "123 / 4.5f" - "await ctx.OkAsync();" From b8df0d8b063edf8b8a43d2d26a6d095eef1a226d Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 6 Apr 2024 23:24:57 +1300 Subject: [PATCH 20/62] Finally finished the Db potion of the EllieBot code --- src/EllieBot/Db/EllieContext.cs | 491 ++++++++++++++++++ src/EllieBot/Db/Extensions/ClubExtensions.cs | 34 ++ .../CurrencyTransactionExtensions.cs | 20 + src/EllieBot/Db/Extensions/DbExtensions.cs | 12 + .../Db/Extensions/DiscordUserExtensions.cs | 179 +++++++ .../Extensions/EllieExpressionExtensions.cs | 15 + .../Db/Extensions/GuildConfigExtensions.cs | 227 ++++++++ .../MusicPlayerSettingsExtensions.cs | 27 + .../Db/Extensions/MusicPlaylistExtensions.cs | 19 + src/EllieBot/Db/Extensions/PollExtensions.cs | 28 + src/EllieBot/Db/Extensions/QuoteExtensions.cs | 57 ++ .../Db/Extensions/ReminderExtensions.cs | 23 + .../SelfAssignableRolesExtensions.cs | 22 + .../Db/Extensions/UserXpExtensions.cs | 63 +++ src/EllieBot/Db/Extensions/WaifuExtensions.cs | 145 ++++++ .../Db/Extensions/WarningExtensions.cs | 60 +++ src/EllieBot/Db/Models/AntiProtection.cs | 65 +++ src/EllieBot/Db/Models/AutoCommand.cs | 14 + src/EllieBot/Db/Models/AutoPublishChannel.cs | 9 + .../Db/Models/AutoTranslateChannel.cs | 10 + src/EllieBot/Db/Models/AutoTranslateUser.cs | 11 + src/EllieBot/Db/Models/BanTemplate.cs | 9 + src/EllieBot/Db/Models/BankUser.cs | 9 + src/EllieBot/Db/Models/BlacklistEntry.cs | 14 + src/EllieBot/Db/Models/ClubInfo.cs | 42 ++ src/EllieBot/Db/Models/CommandAlias.cs | 8 + src/EllieBot/Db/Models/CommandCooldown.cs | 8 + src/EllieBot/Db/Models/CurrencyTransaction.cs | 12 + src/EllieBot/Db/Models/DbEntity.cs | 12 + src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs | 14 + src/EllieBot/Db/Models/DiscordPermOverride.cs | 10 + src/EllieBot/Db/Models/DiscordUser.cs | 31 ++ src/EllieBot/Db/Models/EllieExpression.cs | 26 + src/EllieBot/Db/Models/FeedSub.cs | 19 + src/EllieBot/Db/Models/FilterChannelId.cs | 30 ++ .../Db/Models/FilterLinksChannelId.cs | 13 + src/EllieBot/Db/Models/FilteredWord.cs | 7 + src/EllieBot/Db/Models/FollowedStream.cs | 37 ++ src/EllieBot/Db/Models/GCChannelId.cs | 14 + src/EllieBot/Db/Models/GamblingStats.cs | 9 + src/EllieBot/Db/Models/GroupName.cs | 11 + src/EllieBot/Db/Models/GuildConfig.cs | 108 ++++ src/EllieBot/Db/Models/IgnoredLogItem.cs | 16 + .../Db/Models/IgnoredVoicePresenceChannel.cs | 8 + src/EllieBot/Db/Models/ImageOnlyChannel.cs | 15 + src/EllieBot/Db/Models/LogSetting.cs | 37 ++ src/EllieBot/Db/Models/MusicPlaylist.cs | 10 + src/EllieBot/Db/Models/MusicSettings.cs | 61 +++ src/EllieBot/Db/Models/MutedUserId.cs | 13 + src/EllieBot/Db/Models/NsfwBlacklistedTag.cs | 14 + src/EllieBot/Db/Models/PatronQuota.cs | 48 ++ src/EllieBot/Db/Models/Permission.cs | 56 ++ src/EllieBot/Db/Models/PlantedCurrency.cs | 12 + src/EllieBot/Db/Models/PlaylistSong.cs | 19 + src/EllieBot/Db/Models/Poll.cs | 17 + src/EllieBot/Db/Models/PollVote.cs | 14 + src/EllieBot/Db/Models/Quote.cs | 26 + src/EllieBot/Db/Models/ReactionRole.cs | 18 + src/EllieBot/Db/Models/Reminder.cs | 12 + src/EllieBot/Db/Models/Repeater.cs | 15 + src/EllieBot/Db/Models/RewardedUser.cs | 10 + .../Db/Models/RotatingPlayingStatus.cs | 8 + src/EllieBot/Db/Models/SelfAssignableRole.cs | 11 + src/EllieBot/Db/Models/ShopEntry.cs | 43 ++ src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs | 20 + src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs | 20 + src/EllieBot/Db/Models/StreamOnlineMessage.cs | 13 + src/EllieBot/Db/Models/StreamRoleSettings.cs | 68 +++ src/EllieBot/Db/Models/UnbanTimer.cs | 14 + src/EllieBot/Db/Models/UnmuteTimer.cs | 14 + src/EllieBot/Db/Models/UnroleTimer.cs | 15 + src/EllieBot/Db/Models/UserXpStats.cs | 13 + src/EllieBot/Db/Models/VcRoleInfo.cs | 8 + src/EllieBot/Db/Models/Waifu.cs | 75 +++ src/EllieBot/Db/Models/WaifuItem.cs | 10 + src/EllieBot/Db/Models/WaifuUpdate.cs | 23 + src/EllieBot/Db/Models/WarnExpireAction.cs | 8 + src/EllieBot/Db/Models/Warning.cs | 13 + src/EllieBot/Db/Models/WarningPunishment.cs | 10 + src/EllieBot/Db/Models/XpSettings.cs | 62 +++ src/EllieBot/Db/Models/XpShotOwnedItem.cs | 18 + src/EllieBot/Db/MysqlContext.cs | 38 ++ src/EllieBot/Db/PostgreSqlContext.cs | 26 + src/EllieBot/Db/SqliteContext.cs | 26 + 84 files changed, 2951 insertions(+) create mode 100644 src/EllieBot/Db/EllieContext.cs create mode 100644 src/EllieBot/Db/Extensions/ClubExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/DbExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/DiscordUserExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/GuildConfigExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/PollExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/QuoteExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/ReminderExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/UserXpExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/WaifuExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/WarningExtensions.cs create mode 100644 src/EllieBot/Db/Models/AntiProtection.cs create mode 100644 src/EllieBot/Db/Models/AutoCommand.cs create mode 100644 src/EllieBot/Db/Models/AutoPublishChannel.cs create mode 100644 src/EllieBot/Db/Models/AutoTranslateChannel.cs create mode 100644 src/EllieBot/Db/Models/AutoTranslateUser.cs create mode 100644 src/EllieBot/Db/Models/BanTemplate.cs create mode 100644 src/EllieBot/Db/Models/BankUser.cs create mode 100644 src/EllieBot/Db/Models/BlacklistEntry.cs create mode 100644 src/EllieBot/Db/Models/ClubInfo.cs create mode 100644 src/EllieBot/Db/Models/CommandAlias.cs create mode 100644 src/EllieBot/Db/Models/CommandCooldown.cs create mode 100644 src/EllieBot/Db/Models/CurrencyTransaction.cs create mode 100644 src/EllieBot/Db/Models/DbEntity.cs create mode 100644 src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs create mode 100644 src/EllieBot/Db/Models/DiscordPermOverride.cs create mode 100644 src/EllieBot/Db/Models/DiscordUser.cs create mode 100644 src/EllieBot/Db/Models/EllieExpression.cs create mode 100644 src/EllieBot/Db/Models/FeedSub.cs create mode 100644 src/EllieBot/Db/Models/FilterChannelId.cs create mode 100644 src/EllieBot/Db/Models/FilterLinksChannelId.cs create mode 100644 src/EllieBot/Db/Models/FilteredWord.cs create mode 100644 src/EllieBot/Db/Models/FollowedStream.cs create mode 100644 src/EllieBot/Db/Models/GCChannelId.cs create mode 100644 src/EllieBot/Db/Models/GamblingStats.cs create mode 100644 src/EllieBot/Db/Models/GroupName.cs create mode 100644 src/EllieBot/Db/Models/GuildConfig.cs create mode 100644 src/EllieBot/Db/Models/IgnoredLogItem.cs create mode 100644 src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs create mode 100644 src/EllieBot/Db/Models/ImageOnlyChannel.cs create mode 100644 src/EllieBot/Db/Models/LogSetting.cs create mode 100644 src/EllieBot/Db/Models/MusicPlaylist.cs create mode 100644 src/EllieBot/Db/Models/MusicSettings.cs create mode 100644 src/EllieBot/Db/Models/MutedUserId.cs create mode 100644 src/EllieBot/Db/Models/NsfwBlacklistedTag.cs create mode 100644 src/EllieBot/Db/Models/PatronQuota.cs create mode 100644 src/EllieBot/Db/Models/Permission.cs create mode 100644 src/EllieBot/Db/Models/PlantedCurrency.cs create mode 100644 src/EllieBot/Db/Models/PlaylistSong.cs create mode 100644 src/EllieBot/Db/Models/Poll.cs create mode 100644 src/EllieBot/Db/Models/PollVote.cs create mode 100644 src/EllieBot/Db/Models/Quote.cs create mode 100644 src/EllieBot/Db/Models/ReactionRole.cs create mode 100644 src/EllieBot/Db/Models/Reminder.cs create mode 100644 src/EllieBot/Db/Models/Repeater.cs create mode 100644 src/EllieBot/Db/Models/RewardedUser.cs create mode 100644 src/EllieBot/Db/Models/RotatingPlayingStatus.cs create mode 100644 src/EllieBot/Db/Models/SelfAssignableRole.cs create mode 100644 src/EllieBot/Db/Models/ShopEntry.cs create mode 100644 src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs create mode 100644 src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs create mode 100644 src/EllieBot/Db/Models/StreamOnlineMessage.cs create mode 100644 src/EllieBot/Db/Models/StreamRoleSettings.cs create mode 100644 src/EllieBot/Db/Models/UnbanTimer.cs create mode 100644 src/EllieBot/Db/Models/UnmuteTimer.cs create mode 100644 src/EllieBot/Db/Models/UnroleTimer.cs create mode 100644 src/EllieBot/Db/Models/UserXpStats.cs create mode 100644 src/EllieBot/Db/Models/VcRoleInfo.cs create mode 100644 src/EllieBot/Db/Models/Waifu.cs create mode 100644 src/EllieBot/Db/Models/WaifuItem.cs create mode 100644 src/EllieBot/Db/Models/WaifuUpdate.cs create mode 100644 src/EllieBot/Db/Models/WarnExpireAction.cs create mode 100644 src/EllieBot/Db/Models/Warning.cs create mode 100644 src/EllieBot/Db/Models/WarningPunishment.cs create mode 100644 src/EllieBot/Db/Models/XpSettings.cs create mode 100644 src/EllieBot/Db/Models/XpShotOwnedItem.cs create mode 100644 src/EllieBot/Db/MysqlContext.cs create mode 100644 src/EllieBot/Db/PostgreSqlContext.cs create mode 100644 src/EllieBot/Db/SqliteContext.cs diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs new file mode 100644 index 0000000..f995daa --- /dev/null +++ b/src/EllieBot/Db/EllieContext.cs @@ -0,0 +1,491 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using EllieBot.Db.Models; +using EllieBot.Services.Database.Models; + +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace EllieBot.Services.Database; + +public abstract class EllieContext : DbContext +{ + public DbSet GuildConfigs { get; set; } + + public DbSet Quotes { get; set; } + public DbSet Reminders { get; set; } + public DbSet SelfAssignableRoles { get; set; } + public DbSet MusicPlaylists { get; set; } + public DbSet Expressions { get; set; } + public DbSet CurrencyTransactions { get; set; } + public DbSet WaifuUpdates { get; set; } + public DbSet WaifuItem { get; set; } + public DbSet Warnings { get; set; } + public DbSet UserXpStats { get; set; } + public DbSet Clubs { get; set; } + public DbSet ClubBans { get; set; } + public DbSet ClubApplicants { get; set; } + + + //logging + public DbSet LogSettings { get; set; } + public DbSet IgnoredVoicePresenceCHannels { get; set; } + public DbSet IgnoredLogChannels { get; set; } + + public DbSet RotatingStatus { get; set; } + public DbSet Blacklist { get; set; } + public DbSet AutoCommands { get; set; } + public DbSet RewardedUsers { get; set; } + public DbSet PlantedCurrency { get; set; } + public DbSet BanTemplates { get; set; } + public DbSet DiscordPermOverrides { get; set; } + public DbSet DiscordUser { get; set; } + public DbSet MusicPlayerSettings { get; set; } + public DbSet Repeaters { get; set; } + public DbSet Poll { get; set; } + public DbSet WaifuInfo { get; set; } + public DbSet ImageOnlyChannels { get; set; } + public DbSet NsfwBlacklistedTags { get; set; } + public DbSet AutoTranslateChannels { get; set; } + public DbSet AutoTranslateUsers { get; set; } + + public DbSet Permissions { get; set; } + + public DbSet BankUsers { get; set; } + + public DbSet ReactionRoles { get; set; } + + public DbSet Patrons { get; set; } + + public DbSet PatronQuotas { get; set; } + + public DbSet StreamOnlineMessages { get; set; } + + + #region Mandatory Provider-Specific Values + + protected abstract string CurrencyTransactionOtherIdDefaultValue { get; } + + #endregion + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + #region QUOTES + + var quoteEntity = modelBuilder.Entity(); + quoteEntity.HasIndex(x => x.GuildId); + quoteEntity.HasIndex(x => x.Keyword); + + #endregion + + #region GuildConfig + + var configEntity = modelBuilder.Entity(); + configEntity.HasIndex(c => c.GuildId) + .IsUnique(); + + configEntity.Property(x => x.VerboseErrors) + .HasDefaultValue(true); + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting); + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting); + + modelBuilder.Entity() + .HasOne(x => x.AntiAltSetting) + .WithOne() + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasAlternateKey(x => new + { + x.GuildConfigId, + x.Url + }); + + modelBuilder.Entity().HasIndex(x => x.MessageId).IsUnique(); + + modelBuilder.Entity().HasIndex(x => x.ChannelId); + + configEntity.HasIndex(x => x.WarnExpireHours).IsUnique(false); + + #endregion + + #region streamrole + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole); + + #endregion + + #region Self Assignable Roles + + var selfassignableRolesEntity = modelBuilder.Entity(); + + selfassignableRolesEntity.HasIndex(s => new + { + s.GuildId, + s.RoleId + }) + .IsUnique(); + + selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0); + + #endregion + + #region MusicPlaylists + + var musicPlaylistEntity = modelBuilder.Entity(); + + musicPlaylistEntity.HasMany(p => p.Songs).WithOne().OnDelete(DeleteBehavior.Cascade); + + #endregion + + #region Waifus + + var wi = modelBuilder.Entity(); + wi.HasOne(x => x.Waifu).WithOne(); + + wi.HasIndex(x => x.Price); + wi.HasIndex(x => x.ClaimerId); + // wi.HasMany(x => x.Items) + // .WithOne() + // .OnDelete(DeleteBehavior.Cascade); + + #endregion + + #region DiscordUser + + modelBuilder.Entity(du => + { + du.Property(x => x.IsClubAdmin) + .HasDefaultValue(false); + + du.Property(x => x.NotifyOnLevelUp) + .HasDefaultValue(XpNotificationLocation.None); + + du.Property(x => x.TotalXp) + .HasDefaultValue(0); + + du.Property(x => x.CurrencyAmount) + .HasDefaultValue(0); + + du.HasAlternateKey(w => w.UserId); + du.HasOne(x => x.Club) + .WithMany(x => x.Members) + .IsRequired(false) + .OnDelete(DeleteBehavior.NoAction); + + du.HasIndex(x => x.TotalXp); + du.HasIndex(x => x.CurrencyAmount); + du.HasIndex(x => x.UserId); + }); + + #endregion + + #region Warnings + + modelBuilder.Entity(warn => + { + warn.HasIndex(x => x.GuildId); + warn.HasIndex(x => x.UserId); + warn.HasIndex(x => x.DateAdded); + warn.Property(x => x.Weight).HasDefaultValue(1); + }); + + #endregion + + #region XpStats + + var xps = modelBuilder.Entity(); + xps.HasIndex(x => new + { + x.UserId, + x.GuildId + }) + .IsUnique(); + + xps.HasIndex(x => x.UserId); + xps.HasIndex(x => x.GuildId); + xps.HasIndex(x => x.Xp); + xps.HasIndex(x => x.AwardedXp); + + #endregion + + #region XpSettings + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings); + + #endregion + + #region XpRoleReward + + modelBuilder.Entity() + .HasIndex(x => new + { + x.XpSettingsId, + x.Level + }) + .IsUnique(); + + #endregion + + #region Club + + var ci = modelBuilder.Entity(); + ci.HasOne(x => x.Owner) + .WithOne() + .HasForeignKey(x => x.OwnerId) + .OnDelete(DeleteBehavior.SetNull); + + ci.HasAlternateKey(x => new + { + x.Name + }); + + #endregion + + #region ClubManytoMany + + modelBuilder.Entity() + .HasKey(t => new + { + t.ClubId, + t.UserId + }); + + modelBuilder.Entity() + .HasOne(pt => pt.User) + .WithMany(); + + modelBuilder.Entity() + .HasOne(pt => pt.Club) + .WithMany(x => x.Applicants); + + modelBuilder.Entity() + .HasKey(t => new + { + t.ClubId, + t.UserId + }); + + modelBuilder.Entity() + .HasOne(pt => pt.User) + .WithMany(); + + modelBuilder.Entity() + .HasOne(pt => pt.Club) + .WithMany(x => x.Bans); + + #endregion + + #region Polls + + modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); + + #endregion + + #region CurrencyTransactions + + modelBuilder.Entity(e => + { + e.HasIndex(x => x.UserId) + .IsUnique(false); + + e.Property(x => x.OtherId) + .HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue); + + e.Property(x => x.Type) + .IsRequired(); + + e.Property(x => x.Extra) + .IsRequired(); + }); + + #endregion + + #region Reminders + + modelBuilder.Entity().HasIndex(x => x.When); + + #endregion + + #region GroupName + + modelBuilder.Entity() + .HasIndex(x => new + { + x.GuildConfigId, + x.Number + }) + .IsUnique(); + + modelBuilder.Entity() + .HasOne(x => x.GuildConfig) + .WithMany(x => x.SelfAssignableRoleGroupNames) + .IsRequired(); + + #endregion + + #region BanTemplate + + modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); + modelBuilder.Entity() + .Property(x => x.PruneDays) + .HasDefaultValue(null) + .IsRequired(false); + + #endregion + + #region Perm Override + + modelBuilder.Entity() + .HasIndex(x => new + { + x.GuildId, + x.Command + }) + .IsUnique(); + + #endregion + + #region Music + + modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); + + modelBuilder.Entity().Property(x => x.Volume).HasDefaultValue(100); + + #endregion + + #region Reaction roles + + modelBuilder.Entity(rr2 => + { + rr2.HasIndex(x => x.GuildId) + .IsUnique(false); + + rr2.HasIndex(x => new + { + x.MessageId, + x.Emote + }) + .IsUnique(); + }); + + #endregion + + #region LogSettings + + modelBuilder.Entity(ls => ls.HasIndex(x => x.GuildId).IsUnique()); + + modelBuilder.Entity(ls => ls + .HasMany(x => x.LogIgnores) + .WithOne(x => x.LogSetting) + .OnDelete(DeleteBehavior.Cascade)); + + modelBuilder.Entity(ili => ili + .HasIndex(x => new + { + x.LogSettingId, + x.LogItemId, + x.ItemType + }) + .IsUnique()); + + #endregion + + modelBuilder.Entity(ioc => ioc.HasIndex(x => x.ChannelId).IsUnique()); + + modelBuilder.Entity(nbt => nbt.HasIndex(x => x.GuildId).IsUnique(false)); + + var atch = modelBuilder.Entity(); + atch.HasIndex(x => x.GuildId).IsUnique(false); + + atch.HasIndex(x => x.ChannelId).IsUnique(); + + atch.HasMany(x => x.Users).WithOne(x => x.Channel).OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity(atu => atu.HasAlternateKey(x => new + { + x.ChannelId, + x.UserId + })); + + #region BANK + + modelBuilder.Entity(bu => bu.HasIndex(x => x.UserId).IsUnique()); + + #endregion + + + #region Patron + + // currency rewards + var pr = modelBuilder.Entity(); + pr.HasIndex(x => x.PlatformUserId).IsUnique(); + + // patrons + // patrons are not identified by their user id, but by their platform user id + // as multiple accounts (even maybe on different platforms) could have + // the same account connected to them + modelBuilder.Entity(pu => + { + pu.HasIndex(x => x.UniquePlatformUserId).IsUnique(); + pu.HasKey(x => x.UserId); + }); + + // quotes are per user id + modelBuilder.Entity(pq => + { + pq.HasIndex(x => x.UserId).IsUnique(false); + pq.HasKey(x => new + { + x.UserId, + x.FeatureType, + x.Feature + }); + }); + + #endregion + + #region Xp Item Shop + + modelBuilder.Entity( + x => + { + // user can own only one of each item + x.HasIndex(model => new + { + model.UserId, + model.ItemType, + model.ItemKey + }) + .IsUnique(); + }); + + #endregion + + #region AutoPublish + + modelBuilder.Entity(apc => apc + .HasIndex(x => x.GuildId) + .IsUnique()); + + #endregion + + #region GamblingStats + + modelBuilder.Entity(gs => gs + .HasIndex(x => x.Feature) + .IsUnique()); + + #endregion + } + +#if DEBUG + private static readonly ILoggerFactory _debugLoggerFactory = LoggerFactory.Create(x => x.AddConsole()); + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseLoggerFactory(_debugLoggerFactory); +#endif +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ClubExtensions.cs b/src/EllieBot/Db/Extensions/ClubExtensions.cs new file mode 100644 index 0000000..d8183fc --- /dev/null +++ b/src/EllieBot/Db/Extensions/ClubExtensions.cs @@ -0,0 +1,34 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class ClubExtensions +{ + private static IQueryable Include(this DbSet clubs) + => clubs.Include(x => x.Owner) + .Include(x => x.Applicants) + .ThenInclude(x => x.User) + .Include(x => x.Bans) + .ThenInclude(x => x.User) + .Include(x => x.Members) + .AsQueryable(); + + public static ClubInfo GetByOwner(this DbSet clubs, ulong userId) + => Include(clubs).FirstOrDefault(c => c.Owner.UserId == userId); + + public static ClubInfo GetByOwnerOrAdmin(this DbSet clubs, ulong userId) + => Include(clubs) + .FirstOrDefault(c => c.Owner.UserId == userId || c.Members.Any(u => u.UserId == userId && u.IsClubAdmin)); + + public static ClubInfo GetByMember(this DbSet clubs, ulong userId) + => Include(clubs).FirstOrDefault(c => c.Members.Any(u => u.UserId == userId)); + + public static ClubInfo GetByName(this DbSet clubs, string name) + => Include(clubs) + .FirstOrDefault(c => c.Name == name); + + public static List GetClubLeaderboardPage(this DbSet clubs, int page) + => clubs.AsNoTracking().OrderByDescending(x => x.Xp).Skip(page * 9).Take(9).ToList(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs new file mode 100644 index 0000000..c6659ca --- /dev/null +++ b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs @@ -0,0 +1,20 @@ +#nullable disable +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class CurrencyTransactionExtensions +{ + public static Task> GetPageFor( + this DbSet set, + ulong userId, + int page) + => set.ToLinqToDBTable() + .Where(x => x.UserId == userId) + .OrderByDescending(x => x.DateAdded) + .Skip(15 * page) + .Take(15) + .ToListAsyncLinqToDB(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DbExtensions.cs b/src/EllieBot/Db/Extensions/DbExtensions.cs new file mode 100644 index 0000000..6878b31 --- /dev/null +++ b/src/EllieBot/Db/Extensions/DbExtensions.cs @@ -0,0 +1,12 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class DbExtensions +{ + public static T GetById(this DbSet set, int id) + where T : DbEntity + => set.FirstOrDefault(x => x.Id == id); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs new file mode 100644 index 0000000..fc165c5 --- /dev/null +++ b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs @@ -0,0 +1,179 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; +using EllieBot.Services.Database; +using System.Collections.Immutable; + +namespace EllieBot.Db; + +public static class DiscordUserExtensions +{ + /// + /// Adds the specified to the database. If a database user with placeholder name + /// and discriminator is present in , their name and discriminator get updated accordingly. + /// + /// This database context. + /// The users to add or update in the database. + /// A tuple with the amount of new users added and old users updated. + public static async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(this EllieContext ctx, List users) + { + var presentDbUsers = await ctx.DiscordUser + .Select(x => new { x.UserId, x.Username, x.Discriminator }) + .Where(x => users.Select(y => y.Id).Contains(x.UserId)) + .ToArrayAsyncEF(); + + var usersToAdd = users + .Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id)) + .Select(x => new DiscordUser() + { + UserId = x.Id, + AvatarId = x.AvatarId, + Username = x.Username, + Discriminator = x.Discriminator + }); + + var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied; + var toUpdateUserIds = presentDbUsers + .Where(x => x.Username == "Unknown" && x.Discriminator == "????") + .Select(x => x.UserId) + .ToArray(); + + foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id))) + { + await ctx.DiscordUser + .Where(x => x.UserId == user.Id) + .UpdateAsync(x => new DiscordUser() + { + Username = user.Username, + Discriminator = user.Discriminator, + + // .award tends to set AvatarId and DateAdded to NULL, so account for that. + AvatarId = user.AvatarId, + DateAdded = x.DateAdded ?? DateTime.UtcNow + }); + } + + return (added, toUpdateUserIds.Length); + } + + public static Task GetByUserIdAsync( + this IQueryable set, + ulong userId) + => set.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId); + + public static void EnsureUserCreated( + this EllieContext ctx, + ulong userId, + string username, + string discrim, + string avatarId) + => ctx.DiscordUser.ToLinqToDBTable() + .InsertOrUpdate( + () => new() + { + UserId = userId, + Username = username, + Discriminator = discrim, + AvatarId = avatarId, + TotalXp = 0, + CurrencyAmount = 0 + }, + old => new() + { + Username = username, + Discriminator = discrim, + AvatarId = avatarId + }, + () => new() + { + UserId = userId + }); + + public static Task EnsureUserCreatedAsync( + this EllieContext ctx, + ulong userId) + => ctx.DiscordUser + .ToLinqToDBTable() + .InsertOrUpdateAsync( + () => new() + { + UserId = userId, + Username = "Unknown", + Discriminator = "????", + AvatarId = string.Empty, + TotalXp = 0, + CurrencyAmount = 0 + }, + old => new() + { + + }, + () => new() + { + UserId = userId + }); + + //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown + public static DiscordUser GetOrCreateUser( + this EllieContext ctx, + ulong userId, + string username, + string discrim, + string avatarId, + Func, IQueryable> includes = null) + { + ctx.EnsureUserCreated(userId, username, discrim, avatarId); + + IQueryable queryable = ctx.DiscordUser; + if (includes is not null) + queryable = includes(queryable); + return queryable.First(u => u.UserId == userId); + } + + public static DiscordUser GetOrCreateUser(this EllieContext ctx, IUser original, Func, IQueryable> includes = null) + => ctx.GetOrCreateUser(original.Id, original.Username, original.Discriminator, original.AvatarId, includes); + + public static int GetUserGlobalRank(this DbSet users, ulong id) + => users.AsQueryable() + .Where(x => x.TotalXp + > users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault()) + .Count() + + 1; + + public static DiscordUser[] GetUsersXpLeaderboardFor(this DbSet users, int page) + => users.AsQueryable().OrderByDescending(x => x.TotalXp).Skip(page * 9).Take(9).AsEnumerable().ToArray(); + + public static List GetTopRichest( + this DbSet users, + ulong botId, + int count, + int page = 0) + => users.AsQueryable() + .Where(c => c.CurrencyAmount > 0 && botId != c.UserId) + .OrderByDescending(c => c.CurrencyAmount) + .Skip(page * 9) + .Take(count) + .ToList(); + + public static async Task GetUserCurrencyAsync(this DbSet users, ulong userId) + => (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0; + + public static void RemoveFromMany(this DbSet users, IEnumerable ids) + { + var items = users.AsQueryable().Where(x => ids.Contains(x.UserId)); + foreach (var item in items) + item.CurrencyAmount = 0; + } + + public static decimal GetTotalCurrency(this DbSet users) + => users.Sum((Func)(x => x.CurrencyAmount)); + + public static decimal GetTopOnePercentCurrency(this DbSet users, ulong botId) + => users.AsQueryable() + .Where(x => x.UserId != botId) + .OrderByDescending(x => x.CurrencyAmount) + .Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100) + .Sum(x => x.CurrencyAmount); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs new file mode 100644 index 0000000..7eaf707 --- /dev/null +++ b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs @@ -0,0 +1,15 @@ +#nullable disable +using LinqToDB; +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class EllieExpressionExtensions +{ + public static int ClearFromGuild(this DbSet exprs, ulong guildId) + => exprs.Delete(x => x.GuildId == guildId); + + public static IEnumerable ForId(this DbSet exprs, ulong id) + => exprs.AsNoTracking().AsQueryable().Where(x => x.GuildId == id).ToList(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs new file mode 100644 index 0000000..2b6272a --- /dev/null +++ b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs @@ -0,0 +1,227 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; +using EllieBot.Services.Database; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class GuildConfigExtensions +{ + private static List DefaultWarnPunishments + => new() + { + new() + { + Count = 3, + Punishment = PunishmentAction.Kick + }, + new() + { + Count = 5, + Punishment = PunishmentAction.Ban + } + }; + + /// + /// Gets full stream role settings for the guild with the specified id. + /// + /// Db Context + /// Id of the guild to get stream role settings for. + /// Guild'p stream role settings + public static StreamRoleSettings GetStreamRoleSettings(this EllieContext ctx, ulong guildId) + { + var conf = ctx.GuildConfigsForId(guildId, + set => set.Include(y => y.StreamRole) + .Include(y => y.StreamRole.Whitelist) + .Include(y => y.StreamRole.Blacklist)); + + if (conf.StreamRole is null) + conf.StreamRole = new(); + + return conf.StreamRole; + } + + private static IQueryable IncludeEverything(this DbSet configs) + => configs.AsQueryable() + .AsSplitQuery() + .Include(gc => gc.CommandCooldowns) + .Include(gc => gc.FollowedStreams) + .Include(gc => gc.StreamRole) + .Include(gc => gc.XpSettings) + .ThenInclude(x => x.ExclusionList) + .Include(gc => gc.DelMsgOnCmdChannels); + + public static IEnumerable GetAllGuildConfigs( + this DbSet configs, + List availableGuilds) + => configs.IncludeEverything().AsNoTracking().Where(x => availableGuilds.Contains(x.GuildId)).ToList(); + + /// + /// Gets and creates if it doesn't exist a config for a guild. + /// + /// Context + /// Id of the guide + /// Use to manipulate the set however you want. Pass null to include everything + /// Config for the guild + public static GuildConfig GuildConfigsForId( + this EllieContext ctx, + ulong guildId, + Func, IQueryable> includes) + { + GuildConfig config; + + if (includes is null) + config = ctx.GuildConfigs.IncludeEverything().FirstOrDefault(c => c.GuildId == guildId); + else + { + var set = includes(ctx.GuildConfigs); + config = set.FirstOrDefault(c => c.GuildId == guildId); + } + + if (config is null) + { + ctx.GuildConfigs.Add(config = new() + { + GuildId = guildId, + Permissions = Permissionv2.GetDefaultPermlist, + WarningsInitialized = true, + WarnPunishments = DefaultWarnPunishments + }); + ctx.SaveChanges(); + } + + if (!config.WarningsInitialized) + { + config.WarningsInitialized = true; + config.WarnPunishments = DefaultWarnPunishments; + } + + return config; + + // ctx.GuildConfigs + // .ToLinqToDBTable() + // .InsertOrUpdate(() => new() + // { + // GuildId = guildId, + // Permissions = Permissionv2.GetDefaultPermlist, + // WarningsInitialized = true, + // WarnPunishments = DefaultWarnPunishments + // }, + // _ => new(), + // () => new() + // { + // GuildId = guildId + // }); + // + // if(includes is null) + // return ctx.GuildConfigs + // .ToLinqToDBTable() + // .First(x => x.GuildId == guildId); + } + + public static LogSetting LogSettingsFor(this EllieContext ctx, ulong guildId) + { + var logSetting = ctx.LogSettings.AsQueryable() + .Include(x => x.LogIgnores) + .Where(x => x.GuildId == guildId) + .FirstOrDefault(); + + if (logSetting is null) + { + ctx.LogSettings.Add(logSetting = new() + { + GuildId = guildId + }); + ctx.SaveChanges(); + } + + return logSetting; + } + + public static IEnumerable PermissionsForAll(this DbSet configs, List include) + { + var query = configs.AsQueryable().Where(x => include.Contains(x.GuildId)).Include(gc => gc.Permissions); + + return query.ToList(); + } + + public static GuildConfig GcWithPermissionsFor(this EllieContext ctx, ulong guildId) + { + var config = ctx.GuildConfigs.AsQueryable() + .Where(gc => gc.GuildId == guildId) + .Include(gc => gc.Permissions) + .FirstOrDefault(); + + if (config is null) // if there is no guildconfig, create new one + { + ctx.GuildConfigs.Add(config = new() + { + GuildId = guildId, + Permissions = Permissionv2.GetDefaultPermlist + }); + ctx.SaveChanges(); + } + else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones + { + config.Permissions = Permissionv2.GetDefaultPermlist; + ctx.SaveChanges(); + } + + return config; + } + + public static IEnumerable GetFollowedStreams(this DbSet configs) + => configs.AsQueryable().Include(x => x.FollowedStreams).SelectMany(gc => gc.FollowedStreams).ToArray(); + + public static IEnumerable GetFollowedStreams(this DbSet configs, List included) + => configs.AsQueryable() + .Where(gc => included.Contains(gc.GuildId)) + .Include(gc => gc.FollowedStreams) + .SelectMany(gc => gc.FollowedStreams) + .ToList(); + + public static void SetCleverbotEnabled(this DbSet configs, ulong id, bool cleverbotEnabled) + { + var conf = configs.FirstOrDefault(gc => gc.GuildId == id); + + if (conf is null) + return; + + conf.CleverbotEnabled = cleverbotEnabled; + } + + public static XpSettings XpSettingsFor(this EllieContext ctx, ulong guildId) + { + var gc = ctx.GuildConfigsForId(guildId, + set => set.Include(x => x.XpSettings) + .ThenInclude(x => x.RoleRewards) + .Include(x => x.XpSettings) + .ThenInclude(x => x.CurrencyRewards) + .Include(x => x.XpSettings) + .ThenInclude(x => x.ExclusionList)); + + if (gc.XpSettings is null) + gc.XpSettings = new(); + + return gc.XpSettings; + } + + public static IEnumerable GetGeneratingChannels(this DbSet configs) + => configs.AsQueryable() + .Include(x => x.GenerateCurrencyChannelIds) + .Where(x => x.GenerateCurrencyChannelIds.Any()) + .SelectMany(x => x.GenerateCurrencyChannelIds) + .Select(x => new GeneratingChannel + { + ChannelId = x.ChannelId, + GuildId = x.GuildConfig.GuildId + }) + .ToArray(); + + public class GeneratingChannel + { + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs new file mode 100644 index 0000000..bbefa11 --- /dev/null +++ b/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs @@ -0,0 +1,27 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class MusicPlayerSettingsExtensions +{ + public static async Task ForGuildAsync(this DbSet settings, ulong guildId) + { + var toReturn = await settings.AsQueryable().FirstOrDefaultAsync(x => x.GuildId == guildId); + + if (toReturn is null) + { + var newSettings = new MusicPlayerSettings + { + GuildId = guildId, + PlayerRepeat = PlayerRepeatType.Queue + }; + + await settings.AddAsync(newSettings); + return newSettings; + } + + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs new file mode 100644 index 0000000..747d218 --- /dev/null +++ b/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs @@ -0,0 +1,19 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class MusicPlaylistExtensions +{ + public static List GetPlaylistsOnPage(this DbSet playlists, int num) + { + if (num < 0) + throw new ArgumentOutOfRangeException(nameof(num)); + + return playlists.AsQueryable().Skip((num - 1) * 20).Take(20).Include(pl => pl.Songs).ToList(); + } + + public static MusicPlaylist GetWithSongs(this DbSet playlists, int id) + => playlists.Include(mpl => mpl.Songs).FirstOrDefault(mpl => mpl.Id == id); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/PollExtensions.cs b/src/EllieBot/Db/Extensions/PollExtensions.cs new file mode 100644 index 0000000..abbf992 --- /dev/null +++ b/src/EllieBot/Db/Extensions/PollExtensions.cs @@ -0,0 +1,28 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class PollExtensions +{ + public static IEnumerable GetAllPolls(this DbSet polls) + => polls.Include(x => x.Answers).Include(x => x.Votes).ToArray(); + + public static void RemovePoll(this EllieContext ctx, int id) + { + var p = ctx.Poll.Include(x => x.Answers).Include(x => x.Votes).FirstOrDefault(x => x.Id == id); + + if (p is null) + return; + + if (p.Votes is not null) + { + ctx.RemoveRange(p.Votes); + p.Answers.Clear(); + } + + ctx.Poll.Remove(p); + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/QuoteExtensions.cs b/src/EllieBot/Db/Extensions/QuoteExtensions.cs new file mode 100644 index 0000000..59cae90 --- /dev/null +++ b/src/EllieBot/Db/Extensions/QuoteExtensions.cs @@ -0,0 +1,57 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class QuoteExtensions +{ + public static IEnumerable GetForGuild(this DbSet quotes, ulong guildId) + => quotes.AsQueryable().Where(x => x.GuildId == guildId); + + public static IReadOnlyCollection GetGroup( + this DbSet quotes, + ulong guildId, + int page, + OrderType order) + { + var q = quotes.AsQueryable().Where(x => x.GuildId == guildId); + if (order == OrderType.Keyword) + q = q.OrderBy(x => x.Keyword); + else + q = q.OrderBy(x => x.Id); + + return q.Skip(15 * page).Take(15).ToArray(); + } + + public static async Task GetRandomQuoteByKeywordAsync( + this DbSet quotes, + ulong guildId, + string keyword) + { + var rng = new EllieRandom(); + return (await quotes.AsQueryable().Where(q => q.GuildId == guildId && q.Keyword == keyword).ToListAsync()) + .OrderBy(_ => rng.Next()) + .FirstOrDefault(); + } + + public static async Task SearchQuoteKeywordTextAsync( + this DbSet quotes, + ulong guildId, + string keyword, + string text) + { + var rngk = new EllieRandom(); + return (await quotes.AsQueryable() + .Where(q => q.GuildId == guildId + && (keyword == null || q.Keyword == keyword) + && (EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%") + || EF.Functions.Like(q.AuthorName, text))) + .ToListAsync()) + .OrderBy(_ => rngk.Next()) + .FirstOrDefault(); + } + + public static void RemoveAllByKeyword(this DbSet quotes, ulong guildId, string keyword) + => quotes.RemoveRange(quotes.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword)); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ReminderExtensions.cs b/src/EllieBot/Db/Extensions/ReminderExtensions.cs new file mode 100644 index 0000000..33a79ca --- /dev/null +++ b/src/EllieBot/Db/Extensions/ReminderExtensions.cs @@ -0,0 +1,23 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class ReminderExtensions +{ + public static IEnumerable GetIncludedReminders( + this DbSet reminders, + IEnumerable guildIds) + => reminders.AsQueryable().Where(x => guildIds.Contains(x.ServerId) || x.ServerId == 0).ToList(); + + public static IEnumerable RemindersFor(this DbSet reminders, ulong userId, int page) + => reminders.AsQueryable().Where(x => x.UserId == userId).OrderBy(x => x.DateAdded).Skip(page * 10).Take(10); + + public static IEnumerable RemindersForServer(this DbSet reminders, ulong serverId, int page) + => reminders.AsQueryable() + .Where(x => x.ServerId == serverId) + .OrderBy(x => x.DateAdded) + .Skip(page * 10) + .Take(10); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs new file mode 100644 index 0000000..ee6ef7b --- /dev/null +++ b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs @@ -0,0 +1,22 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class SelfAssignableRolesExtensions +{ + public static bool DeleteByGuildAndRoleId(this DbSet roles, ulong guildId, ulong roleId) + { + var role = roles.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId); + + if (role is null) + return false; + + roles.Remove(role); + return true; + } + + public static IReadOnlyCollection GetFromGuild(this DbSet roles, ulong guildId) + => roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/UserXpExtensions.cs b/src/EllieBot/Db/Extensions/UserXpExtensions.cs new file mode 100644 index 0000000..be1d97f --- /dev/null +++ b/src/EllieBot/Db/Extensions/UserXpExtensions.cs @@ -0,0 +1,63 @@ +#nullable disable +using LinqToDB; +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class UserXpExtensions +{ + public static UserXpStats GetOrCreateUserXpStats(this EllieContext ctx, ulong guildId, ulong userId) + { + var usr = ctx.UserXpStats.FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId); + + if (usr is null) + { + ctx.Add(usr = new() + { + Xp = 0, + UserId = userId, + NotifyOnLevelUp = XpNotificationLocation.None, + GuildId = guildId + }); + } + + return usr; + } + + public static List GetUsersFor(this DbSet xps, ulong guildId, int page) + => xps.AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .OrderByDescending(x => x.Xp + x.AwardedXp) + .Skip(page * 9) + .Take(9) + .ToList(); + + public static List GetTopUserXps(this DbSet xps, ulong guildId, int count) + => xps.AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .OrderByDescending(x => x.Xp + x.AwardedXp) + .Take(count) + .ToList(); + + public static int GetUserGuildRanking(this DbSet xps, ulong userId, ulong guildId) + => xps.AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId + && x.Xp + x.AwardedXp + > xps.AsQueryable() + .Where(y => y.UserId == userId && y.GuildId == guildId) + .Select(y => y.Xp + y.AwardedXp) + .FirstOrDefault()) + .Count() + + 1; + + public static void ResetGuildUserXp(this DbSet xps, ulong userId, ulong guildId) + => xps.Delete(x => x.UserId == userId && x.GuildId == guildId); + + public static void ResetGuildXp(this DbSet xps, ulong guildId) + => xps.Delete(x => x.GuildId == guildId); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WaifuExtensions.cs b/src/EllieBot/Db/Extensions/WaifuExtensions.cs new file mode 100644 index 0000000..ee1fddf --- /dev/null +++ b/src/EllieBot/Db/Extensions/WaifuExtensions.cs @@ -0,0 +1,145 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; +using EllieBot.Services.Database; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public class WaifuInfoStats +{ + public int WaifuId { get; init; } + public string FullName { get; init; } + public long Price { get; init; } + public string ClaimerName { get; init; } + public string AffinityName { get; init; } + public int AffinityCount { get; init; } + public int DivorceCount { get; init; } + public int ClaimCount { get; init; } +} + +public static class WaifuExtensions +{ + public static WaifuInfo ByWaifuUserId( + this DbSet waifus, + ulong userId, + Func, IQueryable> includes = null) + { + if (includes is null) + { + return waifus.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .Include(wi => wi.Items) + .FirstOrDefault(wi => wi.Waifu.UserId == userId); + } + + return includes(waifus).AsQueryable().FirstOrDefault(wi => wi.Waifu.UserId == userId); + } + + public static IEnumerable GetTop(this DbSet waifus, int count, int skip = 0) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + if (count == 0) + return new List(); + + return waifus.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .OrderByDescending(wi => wi.Price) + .Skip(skip) + .Take(count) + .Select(x => new WaifuLbResult + { + Affinity = x.Affinity == null ? null : x.Affinity.Username, + AffinityDiscrim = x.Affinity == null ? null : x.Affinity.Discriminator, + Claimer = x.Claimer == null ? null : x.Claimer.Username, + ClaimerDiscrim = x.Claimer == null ? null : x.Claimer.Discriminator, + Username = x.Waifu.Username, + Discrim = x.Waifu.Discriminator, + Price = x.Price + }) + .ToList(); + } + + public static decimal GetTotalValue(this DbSet waifus) + => waifus.AsQueryable().Where(x => x.ClaimerId != null).Sum(x => x.Price); + + public static ulong GetWaifuUserId(this DbSet waifus, ulong ownerId, string name) + => waifus.AsQueryable() + .AsNoTracking() + .Where(x => x.Claimer.UserId == ownerId && x.Waifu.Username + "#" + x.Waifu.Discriminator == name) + .Select(x => x.Waifu.UserId) + .FirstOrDefault(); + + public static async Task GetWaifuInfoAsync(this EllieContext ctx, ulong userId) + { + await ctx.WaifuInfo + .ToLinqToDBTable() + .InsertOrUpdateAsync(() => new() + { + AffinityId = null, + ClaimerId = null, + Price = 1, + WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First() + }, + _ => new(), + () => new() + { + WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First() + }); + + var toReturn = ctx.WaifuInfo.AsQueryable() + .Where(w => w.WaifuId + == ctx.Set() + .AsQueryable() + .Where(u => u.UserId == userId) + .Select(u => u.Id) + .FirstOrDefault()) + .Select(w => new WaifuInfoStats + { + WaifuId = w.WaifuId, + FullName = + ctx.Set() + .AsQueryable() + .Where(u => u.UserId == userId) + .Select(u => u.Username + "#" + u.Discriminator) + .FirstOrDefault(), + AffinityCount = + ctx.Set() + .AsQueryable() + .Count(x => x.UserId == w.WaifuId + && x.UpdateType == WaifuUpdateType.AffinityChanged + && x.NewId != null), + AffinityName = + ctx.Set() + .AsQueryable() + .Where(u => u.Id == w.AffinityId) + .Select(u => u.Username + "#" + u.Discriminator) + .FirstOrDefault(), + ClaimCount = ctx.WaifuInfo.AsQueryable().Count(x => x.ClaimerId == w.WaifuId), + ClaimerName = + ctx.Set() + .AsQueryable() + .Where(u => u.Id == w.ClaimerId) + .Select(u => u.Username + "#" + u.Discriminator) + .FirstOrDefault(), + DivorceCount = + ctx.Set() + .AsQueryable() + .Count(x => x.OldId == w.WaifuId + && x.NewId == null + && x.UpdateType == WaifuUpdateType.Claimed), + Price = w.Price, + }) + .FirstOrDefault(); + + if (toReturn is null) + return null; + + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WarningExtensions.cs b/src/EllieBot/Db/Extensions/WarningExtensions.cs new file mode 100644 index 0000000..59474d2 --- /dev/null +++ b/src/EllieBot/Db/Extensions/WarningExtensions.cs @@ -0,0 +1,60 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db; + +public static class WarningExtensions +{ + public static Warning[] ForId(this DbSet warnings, ulong guildId, ulong userId) + { + var query = warnings.AsQueryable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .OrderByDescending(x => x.DateAdded); + + return query.ToArray(); + } + + public static bool Forgive( + this DbSet warnings, + ulong guildId, + ulong userId, + string mod, + int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + + var warn = warnings.AsQueryable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .OrderByDescending(x => x.DateAdded) + .Skip(index) + .FirstOrDefault(); + + if (warn is null || warn.Forgiven) + return false; + + warn.Forgiven = true; + warn.ForgivenBy = mod; + return true; + } + + public static async Task ForgiveAll( + this DbSet warnings, + ulong guildId, + ulong userId, + string mod) + => await warnings.AsQueryable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .ForEachAsync(x => + { + if (x.Forgiven != true) + { + x.Forgiven = true; + x.ForgivenBy = mod; + } + }); + + public static Warning[] GetForGuild(this DbSet warnings, ulong id) + => warnings.AsQueryable().Where(x => x.GuildId == id).ToArray(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AntiProtection.cs b/src/EllieBot/Db/Models/AntiProtection.cs new file mode 100644 index 0000000..2301b42 --- /dev/null +++ b/src/EllieBot/Db/Models/AntiProtection.cs @@ -0,0 +1,65 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class AntiRaidSetting : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public int UserThreshold { get; set; } + public int Seconds { get; set; } + public PunishmentAction Action { get; set; } + + /// + /// Duration of the punishment, in minutes. This works only in supported Actions, like: + /// Mute, ChatMute, VoiceMute, etc... + /// + public int PunishmentDuration { get; set; } +} + +public class AntiSpamSetting : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public PunishmentAction Action { get; set; } + public int MessageThreshold { get; set; } = 3; + public int MuteTime { get; set; } + public ulong? RoleId { get; set; } + public HashSet IgnoredChannels { get; set; } = new(); +} + +public class AntiAltSetting +{ + public int Id { get; set; } + public int GuildConfigId { get; set; } + public TimeSpan MinAge { get; set; } + public PunishmentAction Action { get; set; } + public int ActionDurationMinutes { get; set; } + public ulong? RoleId { get; set; } +} + +public enum PunishmentAction +{ + Mute, + Kick, + Ban, + Softban, + RemoveRoles, + ChatMute, + VoiceMute, + AddRole, + Warn, + TimeOut +} + +public class AntiSpamIgnore : DbEntity +{ + public ulong ChannelId { get; set; } + + public override int GetHashCode() + => ChannelId.GetHashCode(); + + public override bool Equals(object obj) + => obj is AntiSpamIgnore inst ? inst.ChannelId == ChannelId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoCommand.cs b/src/EllieBot/Db/Models/AutoCommand.cs new file mode 100644 index 0000000..3738c37 --- /dev/null +++ b/src/EllieBot/Db/Models/AutoCommand.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class AutoCommand : DbEntity +{ + public string CommandText { get; set; } + public ulong ChannelId { get; set; } + public string ChannelName { get; set; } + public ulong? GuildId { get; set; } + public string GuildName { get; set; } + public ulong? VoiceChannelId { get; set; } + public string VoiceChannelName { get; set; } + public int Interval { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoPublishChannel.cs b/src/EllieBot/Db/Models/AutoPublishChannel.cs new file mode 100644 index 0000000..fa81769 --- /dev/null +++ b/src/EllieBot/Db/Models/AutoPublishChannel.cs @@ -0,0 +1,9 @@ +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db.Models; + +public class AutoPublishChannel : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateChannel.cs b/src/EllieBot/Db/Models/AutoTranslateChannel.cs new file mode 100644 index 0000000..a90df1e --- /dev/null +++ b/src/EllieBot/Db/Models/AutoTranslateChannel.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class AutoTranslateChannel : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public bool AutoDelete { get; set; } + public IList Users { get; set; } = new List(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateUser.cs b/src/EllieBot/Db/Models/AutoTranslateUser.cs new file mode 100644 index 0000000..ebe6754 --- /dev/null +++ b/src/EllieBot/Db/Models/AutoTranslateUser.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class AutoTranslateUser : DbEntity +{ + public int ChannelId { get; set; } + public AutoTranslateChannel Channel { get; set; } + public ulong UserId { get; set; } + public string Source { get; set; } + public string Target { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BanTemplate.cs b/src/EllieBot/Db/Models/BanTemplate.cs new file mode 100644 index 0000000..cc72275 --- /dev/null +++ b/src/EllieBot/Db/Models/BanTemplate.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class BanTemplate : DbEntity +{ + public ulong GuildId { get; set; } + public string Text { get; set; } + public int? PruneDays { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BankUser.cs b/src/EllieBot/Db/Models/BankUser.cs new file mode 100644 index 0000000..7fa6418 --- /dev/null +++ b/src/EllieBot/Db/Models/BankUser.cs @@ -0,0 +1,9 @@ +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db.Models; + +public class BankUser : DbEntity +{ + public ulong UserId { get; set; } + public long Balance { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BlacklistEntry.cs b/src/EllieBot/Db/Models/BlacklistEntry.cs new file mode 100644 index 0000000..849c3f7 --- /dev/null +++ b/src/EllieBot/Db/Models/BlacklistEntry.cs @@ -0,0 +1,14 @@ +namespace EllieBot.Services.Database.Models; + +public class BlacklistEntry : DbEntity +{ + public ulong ItemId { get; set; } + public BlacklistType Type { get; set; } +} + +public enum BlacklistType +{ + Server, + Channel, + User +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ClubInfo.cs b/src/EllieBot/Db/Models/ClubInfo.cs new file mode 100644 index 0000000..75d2d1b --- /dev/null +++ b/src/EllieBot/Db/Models/ClubInfo.cs @@ -0,0 +1,42 @@ +#nullable disable +using EllieBot.Services.Database.Models; +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Db.Models; + +public class ClubInfo : DbEntity +{ + [MaxLength(20)] + public string Name { get; set; } + public string Description { get; set; } + public string ImageUrl { get; set; } + + public int Xp { get; set; } = 0; + public int? OwnerId { get; set; } + public DiscordUser Owner { get; set; } + + public List Members { get; set; } = new(); + public List Applicants { get; set; } = new(); + public List Bans { get; set; } = new(); + + public override string ToString() + => Name; +} + +public class ClubApplicants +{ + public int ClubId { get; set; } + public ClubInfo Club { get; set; } + + public int UserId { get; set; } + public DiscordUser User { get; set; } +} + +public class ClubBans +{ + public int ClubId { get; set; } + public ClubInfo Club { get; set; } + + public int UserId { get; set; } + public DiscordUser User { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandAlias.cs b/src/EllieBot/Db/Models/CommandAlias.cs new file mode 100644 index 0000000..be2a6f1 --- /dev/null +++ b/src/EllieBot/Db/Models/CommandAlias.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class CommandAlias : DbEntity +{ + public string Trigger { get; set; } + public string Mapping { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandCooldown.cs b/src/EllieBot/Db/Models/CommandCooldown.cs new file mode 100644 index 0000000..2b824ef --- /dev/null +++ b/src/EllieBot/Db/Models/CommandCooldown.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class CommandCooldown : DbEntity +{ + public int Seconds { get; set; } + public string CommandName { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CurrencyTransaction.cs b/src/EllieBot/Db/Models/CurrencyTransaction.cs new file mode 100644 index 0000000..9153520 --- /dev/null +++ b/src/EllieBot/Db/Models/CurrencyTransaction.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class CurrencyTransaction : DbEntity +{ + public long Amount { get; set; } + public string Note { get; set; } + public ulong UserId { get; set; } + public string Type { get; set; } + public string Extra { get; set; } + public ulong? OtherId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DbEntity.cs b/src/EllieBot/Db/Models/DbEntity.cs new file mode 100644 index 0000000..035ff76 --- /dev/null +++ b/src/EllieBot/Db/Models/DbEntity.cs @@ -0,0 +1,12 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Services.Database.Models; + +public class DbEntity +{ + [Key] + public int Id { get; set; } + + public DateTime? DateAdded { get; set; } = DateTime.UtcNow; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs new file mode 100644 index 0000000..59ac41d --- /dev/null +++ b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class DelMsgOnCmdChannel : DbEntity +{ + public ulong ChannelId { get; set; } + public bool State { get; set; } + + public override int GetHashCode() + => ChannelId.GetHashCode(); + + public override bool Equals(object obj) + => obj is DelMsgOnCmdChannel x && x.ChannelId == ChannelId; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordPermOverride.cs b/src/EllieBot/Db/Models/DiscordPermOverride.cs new file mode 100644 index 0000000..461dcc4 --- /dev/null +++ b/src/EllieBot/Db/Models/DiscordPermOverride.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class DiscordPermOverride : DbEntity +{ + public GuildPerm Perm { get; set; } + + public ulong? GuildId { get; set; } + public string Command { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordUser.cs b/src/EllieBot/Db/Models/DiscordUser.cs new file mode 100644 index 0000000..aa52e19 --- /dev/null +++ b/src/EllieBot/Db/Models/DiscordUser.cs @@ -0,0 +1,31 @@ +#nullable disable +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db.Models; + +// FUTURE remove LastLevelUp from here and UserXpStats +public class DiscordUser : DbEntity +{ + public ulong UserId { get; set; } + public string Username { get; set; } + public string Discriminator { get; set; } + public string AvatarId { get; set; } + + public int? ClubId { get; set; } + public ClubInfo Club { get; set; } + public bool IsClubAdmin { get; set; } + + public long TotalXp { get; set; } + public XpNotificationLocation NotifyOnLevelUp { get; set; } + + public long CurrencyAmount { get; set; } + + public override bool Equals(object obj) + => obj is DiscordUser du ? du.UserId == UserId : false; + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override string ToString() + => Username + "#" + Discriminator; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/EllieExpression.cs b/src/EllieBot/Db/Models/EllieExpression.cs new file mode 100644 index 0000000..9218e0c --- /dev/null +++ b/src/EllieBot/Db/Models/EllieExpression.cs @@ -0,0 +1,26 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class EllieExpression : DbEntity +{ + public ulong? GuildId { get; set; } + public string Response { get; set; } + public string Trigger { get; set; } + + public bool AutoDeleteTrigger { get; set; } + public bool DmResponse { get; set; } + public bool ContainsAnywhere { get; set; } + public bool AllowTarget { get; set; } + + public string[] GetReactions() + => string.IsNullOrWhiteSpace(Reaactions) ? Array.Empty() : Reaactions.Split("@@@"); + + public bool IsGlobal() + => GuildId is null or 0; +} + +public class ReactionResponse : DbEntity +{ + public bool OwnerOnly { get; set; } + public string Text { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FeedSub.cs b/src/EllieBot/Db/Models/FeedSub.cs new file mode 100644 index 0000000..f15aa81 --- /dev/null +++ b/src/EllieBot/Db/Models/FeedSub.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class FeedSub : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public ulong ChannelId { get; set; } + public string Url { get; set; } + + public string Message { get; set; } + + public override int GetHashCode() + => Url.GetHashCode(StringComparison.InvariantCulture) ^ GuildConfigId.GetHashCode(); + + public override bool Equals(object obj) + => obj is FeedSub s && s.Url.ToLower() == Url.ToLower() && s.GuildConfigId == GuildConfigId; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilterChannelId.cs b/src/EllieBot/Db/Models/FilterChannelId.cs new file mode 100644 index 0000000..e674ec2 --- /dev/null +++ b/src/EllieBot/Db/Models/FilterChannelId.cs @@ -0,0 +1,30 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class FilterChannelId : DbEntity +{ + public ulong ChannelId { get; set; } + + public bool Equals(FilterChannelId other) + => ChannelId == other.ChannelId; + + public override bool Equals(object obj) + => obj is FilterChannelId fci && Equals(fci); + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} + +public class FilterWordsChannelId : DbEntity +{ + public ulong ChannelId { get; set; } + + public bool Equals(FilterWordsChannelId other) + => ChannelId == other.ChannelId; + + public override bool Equals(object obj) + => obj is FilterWordsChannelId fci && Equals(fci); + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilterLinksChannelId.cs b/src/EllieBot/Db/Models/FilterLinksChannelId.cs new file mode 100644 index 0000000..440085e --- /dev/null +++ b/src/EllieBot/Db/Models/FilterLinksChannelId.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class FilterLinksChannelId : DbEntity +{ + public ulong ChannelId { get; set; } + + public override bool Equals(object obj) + => obj is FilterLinksChannelId f && f.ChannelId == ChannelId; + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilteredWord.cs b/src/EllieBot/Db/Models/FilteredWord.cs new file mode 100644 index 0000000..5a5ee93 --- /dev/null +++ b/src/EllieBot/Db/Models/FilteredWord.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class FilteredWord : DbEntity +{ + public string Word { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FollowedStream.cs b/src/EllieBot/Db/Models/FollowedStream.cs new file mode 100644 index 0000000..3a96846 --- /dev/null +++ b/src/EllieBot/Db/Models/FollowedStream.cs @@ -0,0 +1,37 @@ +#nullable disable +using EllieBot.Modules.Searches.Common; +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db.Models; + +public class FollowedStream : DbEntity +{ + public enum FType + { + Twitch = 0, + Picarto = 3, + Youtube = 4, + Facebook = 5, + Trovo = 6 + } + + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public string Username { get; set; } + public FType Type { get; set; } + public string Message { get; set; } + + protected bool Equals(FollowedStream other) + => ChannelId == other.ChannelId + && Username.Trim().ToUpperInvariant() == other.Username.Trim().ToUpperInvariant() + && Type == other.Type; + + public override int GetHashCode() + => HashCode.Combine(ChannelId, Username, (int)Type); + + public override bool Equals(object obj) + => obj is FollowedStream fs && Equals(fs); + + public StreamDataKey CreateKey() + => new(Type, Username.ToLower()); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GCChannelId.cs b/src/EllieBot/Db/Models/GCChannelId.cs new file mode 100644 index 0000000..387605c --- /dev/null +++ b/src/EllieBot/Db/Models/GCChannelId.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class GCChannelId : DbEntity +{ + public GuildConfig GuildConfig { get; set; } + public ulong ChannelId { get; set; } + + public override bool Equals(object obj) + => obj is GCChannelId gc && gc.ChannelId == ChannelId; + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GamblingStats.cs b/src/EllieBot/Db/Models/GamblingStats.cs new file mode 100644 index 0000000..8a4654e --- /dev/null +++ b/src/EllieBot/Db/Models/GamblingStats.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class GamblingStats : DbEntity +{ + public string Feature { get; set; } + public decimal Bet { get; set; } + public decimal PaidOut { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GroupName.cs b/src/EllieBot/Db/Models/GroupName.cs new file mode 100644 index 0000000..52ef07b --- /dev/null +++ b/src/EllieBot/Db/Models/GroupName.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class GroupName : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public int Number { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GuildConfig.cs b/src/EllieBot/Db/Models/GuildConfig.cs new file mode 100644 index 0000000..5346489 --- /dev/null +++ b/src/EllieBot/Db/Models/GuildConfig.cs @@ -0,0 +1,108 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Services.Database.Models; + +public class GuildConfig : DbEntity +{ + public ulong GuildId { get; set; } + + public string Prefix { get; set; } + + public bool DeleteMessageOnCommand { get; set; } + public HashSet DelMsgOnCmdChannels { get; set; } = new(); + + public string AutoAssignRoleIds { get; set; } + + //greet stuff + public int AutoDeleteGreetMessagesTimer { get; set; } = 30; + public int AutoDeleteByeMessagesTimer { get; set; } = 30; + + public ulong GreetMessageChannelId { get; set; } + public ulong ByeMessageChannelId { get; set; } + + public bool SendDmGreetMessage { get; set; } + public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; + + public bool SendChannelGreetMessage { get; set; } + public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; + + public bool SendChannelByeMessage { get; set; } + public string ChannelByeMessageText { get; set; } = "%user% has left!"; + + //self assignable roles + public bool ExclusiveSelfAssignedRoles { get; set; } + public bool AutoDeleteSelfAssignedRoleMessages { get; set; } + + //stream notifications + public HashSet FollowedStreams { get; set; } = new(); + + //currencyGeneration + public HashSet GenerateCurrencyChannelIds { get; set; } = new(); + + public List Permissions { get; set; } + public bool VerbosePermissions { get; set; } = true; + public string PermissionRole { get; set; } + + public HashSet CommandCooldowns { get; set; } = new(); + + //filtering + public bool FilterInvites { get; set; } + public bool FilterLinks { get; set; } + public HashSet FilterInvitesChannelIds { get; set; } = new(); + public HashSet FilterLinksChannelIds { get; set; } = new(); + + //public bool FilterLinks { get; set; } + //public HashSet FilterLinksChannels { get; set; } = new HashSet(); + + public bool FilterWords { get; set; } + public HashSet FilteredWords { get; set; } = new(); + public HashSet FilterWordsChannelIds { get; set; } = new(); + + public HashSet MutedUsers { get; set; } = new(); + + public string MuteRoleName { get; set; } + public bool CleverbotEnabled { get; set; } + + public AntiRaidSetting AntiRaidSetting { get; set; } + public AntiSpamSetting AntiSpamSetting { get; set; } + public AntiAltSetting AntiAltSetting { get; set; } + + public string Locale { get; set; } + public string TimeZoneId { get; set; } + + public HashSet UnmuteTimers { get; set; } = new(); + public HashSet UnbanTimer { get; set; } = new(); + public HashSet UnroleTimer { get; set; } = new(); + public HashSet VcRoleInfos { get; set; } + public HashSet CommandAliases { get; set; } = new(); + public List WarnPunishments { get; set; } = new(); + public bool WarningsInitialized { get; set; } + public HashSet SlowmodeIgnoredUsers { get; set; } + public HashSet SlowmodeIgnoredRoles { get; set; } + + public List ShopEntries { get; set; } + public ulong? GameVoiceChannel { get; set; } + public bool VerboseErrors { get; set; } = true; + + public StreamRoleSettings StreamRole { get; set; } + + public XpSettings XpSettings { get; set; } + public List FeedSubs { get; set; } = new(); + public bool NotifyStreamOffline { get; set; } + public bool DeleteStreamOnlineMessage { get; set; } + public List SelfAssignableRoleGroupNames { get; set; } + public int WarnExpireHours { get; set; } + public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear; + + public bool DisableGlobalExpressions { get; set; } = false; + + #region Boost Message + + public bool SendBoostMessage { get; set; } + public string BoostMessage { get; set; } = "%user% just boosted this server!"; + public ulong BoostMessageChannelId { get; set; } + public int BoostMessageDeleteAfter { get; set; } + + #endregion +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredLogItem.cs b/src/EllieBot/Db/Models/IgnoredLogItem.cs new file mode 100644 index 0000000..060ef32 --- /dev/null +++ b/src/EllieBot/Db/Models/IgnoredLogItem.cs @@ -0,0 +1,16 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class IgnoredLogItem : DbEntity +{ + public int LogSettingId { get; set; } + public LogSetting LogSetting { get; set; } + public ulong LogItemId { get; set; } + public IgnoredItemType ItemType { get; set; } +} + +public enum IgnoredItemType +{ + Channel, + User +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs new file mode 100644 index 0000000..e25c38a --- /dev/null +++ b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class IgnoredVoicePresenceChannel : DbEntity +{ + public LogSetting LogSetting { get; set; } + public ulong ChannelId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ImageOnlyChannel.cs b/src/EllieBot/Db/Models/ImageOnlyChannel.cs new file mode 100644 index 0000000..2fce8d1 --- /dev/null +++ b/src/EllieBot/Db/Models/ImageOnlyChannel.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class ImageOnlyChannel : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public OnlyChannelType Type { get; set; } +} + +public enum OnlyChannelType +{ + Image, + Link +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/LogSetting.cs b/src/EllieBot/Db/Models/LogSetting.cs new file mode 100644 index 0000000..b09371a --- /dev/null +++ b/src/EllieBot/Db/Models/LogSetting.cs @@ -0,0 +1,37 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class LogSetting : DbEntity +{ + public List LogIgnores { get; set; } = new(); + + public ulong GuildId { get; set; } + public ulong? LogOtherId { get; set; } + public ulong? MessageUpdatedId { get; set; } + public ulong? MessageDeletedId { get; set; } + + public ulong? UserJoinedId { get; set; } + public ulong? UserLeftId { get; set; } + public ulong? UserBannedId { get; set; } + public ulong? UserUnbannedId { get; set; } + public ulong? UserUpdatedId { get; set; } + + public ulong? ChannelCreatedId { get; set; } + public ulong? ChannelDestroyedId { get; set; } + public ulong? ChannelUpdatedId { get; set; } + + + public ulong? ThreadDeletedId { get; set; } + public ulong? ThreadCreatedId { get; set; } + + public ulong? UserMutedId { get; set; } + + // userpresence + public ulong? LogUserPresenceId { get; set; } + + // voicepresence + + public ulong? LogVoicePresenceId { get; set; } + public ulong? LogVoicePresenceTTSId { get; set; } + public ulong? LogWarnsId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MusicPlaylist.cs b/src/EllieBot/Db/Models/MusicPlaylist.cs new file mode 100644 index 0000000..3f96d05 --- /dev/null +++ b/src/EllieBot/Db/Models/MusicPlaylist.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class MusicPlaylist : DbEntity +{ + public string Name { get; set; } + public string Author { get; set; } + public ulong AuthorId { get; set; } + public List Songs { get; set; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MusicSettings.cs b/src/EllieBot/Db/Models/MusicSettings.cs new file mode 100644 index 0000000..b81d433 --- /dev/null +++ b/src/EllieBot/Db/Models/MusicSettings.cs @@ -0,0 +1,61 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class MusicPlayerSettings +{ + /// + /// Auto generated Id + /// + public int Id { get; set; } + + /// + /// Id of the guild + /// + public ulong GuildId { get; set; } + + /// + /// Queue repeat type + /// + public PlayerRepeatType PlayerRepeat { get; set; } = PlayerRepeatType.Queue; + + /// + /// Channel id the bot will always try to send track related messages to + /// + public ulong? MusicChannelId { get; set; } + + /// + /// Default volume player will be created with + /// + public int Volume { get; set; } = 100; + + /// + /// Whether the bot should auto disconnect from the voice channel once the queue is done + /// This only has effect if + /// + public bool AutoDisconnect { get; set; } + + /// + /// Selected quality preset for the music player + /// + public QualityPreset QualityPreset { get; set; } + + /// + /// Whether the bot will automatically queue related songs + /// + public bool AutoPlay { get; set; } +} + +public enum QualityPreset +{ + Highest, + High, + Medium, + Low +} + +public enum PlayerRepeatType +{ + None, + Track, + Queue +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MutedUserId.cs b/src/EllieBot/Db/Models/MutedUserId.cs new file mode 100644 index 0000000..2d752f6 --- /dev/null +++ b/src/EllieBot/Db/Models/MutedUserId.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class MutedUserId : DbEntity +{ + public ulong UserId { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is MutedUserId mui ? mui.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs b/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs new file mode 100644 index 0000000..3617132 --- /dev/null +++ b/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class NsfwBlacklistedTag : DbEntity +{ + public ulong GuildId { get; set; } + public string Tag { get; set; } + + public override int GetHashCode() + => Tag.GetHashCode(StringComparison.InvariantCulture); + + public override bool Equals(object obj) + => obj is NsfwBlacklistedTag x && x.Tag == Tag; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PatronQuota.cs b/src/EllieBot/Db/Models/PatronQuota.cs new file mode 100644 index 0000000..ba5129d --- /dev/null +++ b/src/EllieBot/Db/Models/PatronQuota.cs @@ -0,0 +1,48 @@ +#nullable disable +namespace EllieBot.Db.Models; + +/// +/// Contains data about usage of Patron-Only commands per user +/// in order to provide support for quota limitations +/// (allow user x who is pledging amount y to use the specified command only +/// x amount of times in the specified time period) +/// +public class PatronQuota +{ + public ulong UserId { get; set; } + public FeatureType FeatureType { get; set; } + public string Feature { get; set; } + public uint HourlyCount { get; set; } + public uint DailyCount { get; set; } + public uint MonthlyCount { get; set; } +} + +public enum FeatureType +{ + Command, + Group, + Module, + Limit +} + +public class PatronUser +{ + public string UniquePlatformUserId { get; set; } + public ulong UserId { get; set; } + public int AmountCents { get; set; } + + public DateTime LastCharge { get; set; } + + // Date Only component + public DateTime ValidThru { get; set; } + + public PatronUser Clone() + => new PatronUser() + { + UniquePlatformUserId = this.UniquePlatformUserId, + UserId = this.UserId, + AmountCents = this.AmountCents, + LastCharge = this.LastCharge, + ValidThru = this.ValidThru + }; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Permission.cs b/src/EllieBot/Db/Models/Permission.cs new file mode 100644 index 0000000..61089f6 --- /dev/null +++ b/src/EllieBot/Db/Models/Permission.cs @@ -0,0 +1,56 @@ +#nullable disable +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; + +namespace EllieBot.Services.Database.Models; + + +[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")] +public class Permissionv2 : DbEntity, IIndexed +{ + public int? GuildConfigId { get; set; } + public int Index { get; set; } + + public PrimaryPermissionType PrimaryTarget { get; set; } + public ulong PrimaryTargetId { get; set; } + + public SecondaryPermissionType SecondaryTarget { get; set; } + public string SecondaryTargetName { get; set; } + + public bool IsCustomCommand { get; set; } + + public bool State { get; set; } + + [NotMapped] + public static Permissionv2 AllowAllPerm + => new() + { + PrimaryTarget = PrimaryPermissionType.Server, + PrimaryTargetId = 0, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = true, + Index = 0 + }; + + public static List GetDefaultPermlist + => new() + { + AllowAllPerm + }; +} + +public enum PrimaryPermissionType +{ + User, + Channel, + Role, + Server +} + +public enum SecondaryPermissionType +{ + Module, + Command, + AllModules +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlantedCurrency.cs b/src/EllieBot/Db/Models/PlantedCurrency.cs new file mode 100644 index 0000000..3741530 --- /dev/null +++ b/src/EllieBot/Db/Models/PlantedCurrency.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class PlantedCurrency : DbEntity +{ + public long Amount { get; set; } + public string Password { get; set; } + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public ulong UserId { get; set; } + public ulong MessageId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlaylistSong.cs b/src/EllieBot/Db/Models/PlaylistSong.cs new file mode 100644 index 0000000..7a2078d --- /dev/null +++ b/src/EllieBot/Db/Models/PlaylistSong.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class PlaylistSong : DbEntity +{ + public string Provider { get; set; } + public MusicType ProviderType { get; set; } + public string Title { get; set; } + public string Uri { get; set; } + public string Query { get; set; } +} + +public enum MusicType +{ + Radio, + YouTube, + Local, + Soundcloud +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Poll.cs b/src/EllieBot/Db/Models/Poll.cs new file mode 100644 index 0000000..10e988c --- /dev/null +++ b/src/EllieBot/Db/Models/Poll.cs @@ -0,0 +1,17 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class Poll : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public string Question { get; set; } + public IndexedCollection Answers { get; set; } + public HashSet Votes { get; set; } = new(); +} + +public class PollAnswer : DbEntity, IIndexed +{ + public int Index { get; set; } + public string Text { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PollVote.cs b/src/EllieBot/Db/Models/PollVote.cs new file mode 100644 index 0000000..e78dadf --- /dev/null +++ b/src/EllieBot/Db/Models/PollVote.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class PollVote : DbEntity +{ + public ulong UserId { get; set; } + public int VoteIndex { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is PollVote p ? p.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Quote.cs b/src/EllieBot/Db/Models/Quote.cs new file mode 100644 index 0000000..529dc46 --- /dev/null +++ b/src/EllieBot/Db/Models/Quote.cs @@ -0,0 +1,26 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Services.Database.Models; + +public class Quote : DbEntity +{ + public ulong GuildId { get; set; } + + [Required] + public string Keyword { get; set; } + + [Required] + public string AuthorName { get; set; } + + public ulong AuthorId { get; set; } + + [Required] + public string Text { get; set; } +} + +public enum OrderType +{ + Id = -1, + Keyword = -2 +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ReactionRole.cs b/src/EllieBot/Db/Models/ReactionRole.cs new file mode 100644 index 0000000..4e1e4f6 --- /dev/null +++ b/src/EllieBot/Db/Models/ReactionRole.cs @@ -0,0 +1,18 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Services.Database.Models; + +public class ReactionRoleV2 : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + + public ulong MessageId { get; set; } + + [MaxLength(100)] + public string Emote { get; set; } + public ulong RoleId { get; set; } + public int Group { get; set; } + public int LevelReq { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Reminder.cs b/src/EllieBot/Db/Models/Reminder.cs new file mode 100644 index 0000000..df51f6d --- /dev/null +++ b/src/EllieBot/Db/Models/Reminder.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class Reminder : DbEntity +{ + public DateTime When { get; set; } + public ulong ChannelId { get; set; } + public ulong ServerId { get; set; } + public ulong UserId { get; set; } + public string Message { get; set; } + public bool IsPrivate { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Repeater.cs b/src/EllieBot/Db/Models/Repeater.cs new file mode 100644 index 0000000..7ac971e --- /dev/null +++ b/src/EllieBot/Db/Models/Repeater.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class Repeater +{ + public int Id { get; set; } + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public ulong? LastMessageId { get; set; } + public string Message { get; set; } + public TimeSpan Interval { get; set; } + public TimeSpan? StartTimeOfDay { get; set; } + public bool NoRedundant { get; set; } + public DateTime DateAdded { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RewardedUser.cs b/src/EllieBot/Db/Models/RewardedUser.cs new file mode 100644 index 0000000..9ac6e78 --- /dev/null +++ b/src/EllieBot/Db/Models/RewardedUser.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class RewardedUser : DbEntity +{ + public ulong UserId { get; set; } + public string PlatformUserId { get; set; } + public long AmountRewardedThisMonth { get; set; } + public DateTime LastReward { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RotatingPlayingStatus.cs b/src/EllieBot/Db/Models/RotatingPlayingStatus.cs new file mode 100644 index 0000000..a76c38f --- /dev/null +++ b/src/EllieBot/Db/Models/RotatingPlayingStatus.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class RotatingPlayingStatus : DbEntity +{ + public string Status { get; set; } + public ActivityType Type { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SelfAssignableRole.cs b/src/EllieBot/Db/Models/SelfAssignableRole.cs new file mode 100644 index 0000000..df6cd48 --- /dev/null +++ b/src/EllieBot/Db/Models/SelfAssignableRole.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class SelfAssignedRole : DbEntity +{ + public ulong GuildId { get; set; } + public ulong RoleId { get; set; } + + public int Group { get; set; } + public int LevelRequirement { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ShopEntry.cs b/src/EllieBot/Db/Models/ShopEntry.cs new file mode 100644 index 0000000..ed83cb1 --- /dev/null +++ b/src/EllieBot/Db/Models/ShopEntry.cs @@ -0,0 +1,43 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public enum ShopEntryType +{ + Role, + + List + //Infinite_List, +} + +public class ShopEntry : DbEntity, IIndexed +{ + public int Index { get; set; } + public int Price { get; set; } + public string Name { get; set; } + public ulong AuthorId { get; set; } + + public ShopEntryType Type { get; set; } + + //role + public string RoleName { get; set; } + public ulong RoleId { get; set; } + + //list + public HashSet Items { get; set; } = new(); + public ulong? RoleRequirement { get; set; } +} + +public class ShopEntryItem : DbEntity +{ + public string Text { get; set; } + + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + return ((ShopEntryItem)obj).Text == Text; + } + + public override int GetHashCode() + => Text.GetHashCode(StringComparison.InvariantCulture); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs new file mode 100644 index 0000000..a2d6bdd --- /dev/null +++ b/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs @@ -0,0 +1,20 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class SlowmodeIgnoredRole : DbEntity +{ + public ulong RoleId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + + return ((SlowmodeIgnoredRole)obj).RoleId == RoleId; + } + + // override object.GetHashCode + public override int GetHashCode() + => RoleId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs new file mode 100644 index 0000000..92597c3 --- /dev/null +++ b/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs @@ -0,0 +1,20 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class SlowmodeIgnoredUser : DbEntity +{ + public ulong UserId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + + return ((SlowmodeIgnoredUser)obj).UserId == UserId; + } + + // override object.GetHashCode + public override int GetHashCode() + => UserId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamOnlineMessage.cs b/src/EllieBot/Db/Models/StreamOnlineMessage.cs new file mode 100644 index 0000000..e9b1e24 --- /dev/null +++ b/src/EllieBot/Db/Models/StreamOnlineMessage.cs @@ -0,0 +1,13 @@ +#nullable disable +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db.Models; + +public class StreamOnlineMessage : DbEntity +{ + public ulong ChannelId { get; set; } + public ulong MessageId { get; set; } + + public FollowedStream.FType Type { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamRoleSettings.cs b/src/EllieBot/Db/Models/StreamRoleSettings.cs new file mode 100644 index 0000000..dbab2d0 --- /dev/null +++ b/src/EllieBot/Db/Models/StreamRoleSettings.cs @@ -0,0 +1,68 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class StreamRoleSettings : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + /// + /// Whether the feature is enabled in the guild. + /// + public bool Enabled { get; set; } + + /// + /// Id of the role to give to the users in the role 'FromRole' when they start streaming + /// + public ulong AddRoleId { get; set; } + + /// + /// Id of the role whose users are eligible to get the 'AddRole' + /// + public ulong FromRoleId { get; set; } + + /// + /// If set, feature will only apply to users who have this keyword in their streaming status. + /// + public string Keyword { get; set; } + + /// + /// A collection of whitelisted users' IDs. Whitelisted users don't require 'keyword' in + /// order to get the stream role. + /// + public HashSet Whitelist { get; set; } = new(); + + /// + /// A collection of blacklisted users' IDs. Blacklisted useres will never get the stream role. + /// + public HashSet Blacklist { get; set; } = new(); +} + +public class StreamRoleBlacklistedUser : DbEntity +{ + public ulong UserId { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + { + if (obj is not StreamRoleBlacklistedUser x) + return false; + + return x.UserId == UserId; + } + + public override int GetHashCode() + => UserId.GetHashCode(); +} + +public class StreamRoleWhitelistedUser : DbEntity +{ + public ulong UserId { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + => obj is StreamRoleWhitelistedUser x ? x.UserId == UserId : false; + + public override int GetHashCode() + => UserId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnbanTimer.cs b/src/EllieBot/Db/Models/UnbanTimer.cs new file mode 100644 index 0000000..b017624 --- /dev/null +++ b/src/EllieBot/Db/Models/UnbanTimer.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class UnbanTimer : DbEntity +{ + public ulong UserId { get; set; } + public DateTime UnbanAt { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is UnbanTimer ut ? ut.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnmuteTimer.cs b/src/EllieBot/Db/Models/UnmuteTimer.cs new file mode 100644 index 0000000..4619b68 --- /dev/null +++ b/src/EllieBot/Db/Models/UnmuteTimer.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class UnmuteTimer : DbEntity +{ + public ulong UserId { get; set; } + public DateTime UnmuteAt { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is UnmuteTimer ut ? ut.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnroleTimer.cs b/src/EllieBot/Db/Models/UnroleTimer.cs new file mode 100644 index 0000000..f7c7f8d --- /dev/null +++ b/src/EllieBot/Db/Models/UnroleTimer.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class UnroleTimer : DbEntity +{ + public ulong UserId { get; set; } + public ulong RoleId { get; set; } + public DateTime UnbanAt { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode() ^ RoleId.GetHashCode(); + + public override bool Equals(object obj) + => obj is UnroleTimer ut ? ut.UserId == UserId && ut.RoleId == RoleId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UserXpStats.cs b/src/EllieBot/Db/Models/UserXpStats.cs new file mode 100644 index 0000000..e79f735 --- /dev/null +++ b/src/EllieBot/Db/Models/UserXpStats.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class UserXpStats : DbEntity +{ + public ulong UserId { get; set; } + public ulong GuildId { get; set; } + public long Xp { get; set; } + public long AwardedXp { get; set; } + public XpNotificationLocation NotifyOnLevelUp { get; set; } +} + +public enum XpNotificationLocation { None, Dm, Channel } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/VcRoleInfo.cs b/src/EllieBot/Db/Models/VcRoleInfo.cs new file mode 100644 index 0000000..b80fc17 --- /dev/null +++ b/src/EllieBot/Db/Models/VcRoleInfo.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class VcRoleInfo : DbEntity +{ + public ulong VoiceChannelId { get; set; } + public ulong RoleId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Waifu.cs b/src/EllieBot/Db/Models/Waifu.cs new file mode 100644 index 0000000..a140be5 --- /dev/null +++ b/src/EllieBot/Db/Models/Waifu.cs @@ -0,0 +1,75 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Services.Database.Models; + +public class WaifuInfo : DbEntity +{ + public int WaifuId { get; set; } + public DiscordUser Waifu { get; set; } + + public int? ClaimerId { get; set; } + public DiscordUser Claimer { get; set; } + + public int? AffinityId { get; set; } + public DiscordUser Affinity { get; set; } + + public long Price { get; set; } + public List Items { get; set; } = new(); + + public override string ToString() + { + var claimer = "no one"; + var status = string.Empty; + + var waifuUsername = Waifu.Username.TrimTo(20); + var claimerUsername = Claimer?.Username.TrimTo(20); + + if (ClaimerId is not null) + claimer = $"{claimerUsername}#{Claimer.Discriminator}"; + if (AffinityId is null) + status = $"... but {waifuUsername}'s heart is empty"; + else if (AffinityId == ClaimerId) + status = $"... and {waifuUsername} likes {claimerUsername} too <3"; + else + { + status = + $"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}"; + } + + return $"**{waifuUsername}#{Waifu.Discriminator}** - claimed by **{claimer}**\n\t{status}"; + } +} + +public class WaifuLbResult +{ + public string Username { get; set; } + public string Discrim { get; set; } + + public string Claimer { get; set; } + public string ClaimerDiscrim { get; set; } + + public string Affinity { get; set; } + public string AffinityDiscrim { get; set; } + + public long Price { get; set; } + + public override string ToString() + { + var claimer = "no one"; + var status = string.Empty; + + var waifuUsername = Username.TrimTo(20); + var claimerUsername = Claimer?.TrimTo(20); + + if (Claimer is not null) + claimer = $"{claimerUsername}#{ClaimerDiscrim}"; + if (Affinity is null) + status = $"... but {waifuUsername}'s heart is empty"; + else if (Affinity + AffinityDiscrim == Claimer + ClaimerDiscrim) + status = $"... and {waifuUsername} likes {claimerUsername} too <3"; + else + status = $"... but {waifuUsername}'s heart belongs to {Affinity.TrimTo(20)}#{AffinityDiscrim}"; + return $"**{waifuUsername}#{Discrim}** - claimed by **{claimer}**\n\t{status}"; + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WaifuItem.cs b/src/EllieBot/Db/Models/WaifuItem.cs new file mode 100644 index 0000000..32df5ba --- /dev/null +++ b/src/EllieBot/Db/Models/WaifuItem.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class WaifuItem +{ + public WaifuInfo WaifuInfo { get; set; } + public int? WaifuInfoId { get; set; } + public string ItemEmoji { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WaifuUpdate.cs b/src/EllieBot/Db/Models/WaifuUpdate.cs new file mode 100644 index 0000000..70e8960 --- /dev/null +++ b/src/EllieBot/Db/Models/WaifuUpdate.cs @@ -0,0 +1,23 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Services.Database.Models; + +public class WaifuUpdate : DbEntity +{ + public int UserId { get; set; } + public DiscordUser User { get; set; } + public WaifuUpdateType UpdateType { get; set; } + + public int? OldId { get; set; } + public DiscordUser Old { get; set; } + + public int? NewId { get; set; } + public DiscordUser New { get; set; } +} + +public enum WaifuUpdateType +{ + AffinityChanged, + Claimed +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WarnExpireAction.cs b/src/EllieBot/Db/Models/WarnExpireAction.cs new file mode 100644 index 0000000..caa595f --- /dev/null +++ b/src/EllieBot/Db/Models/WarnExpireAction.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public enum WarnExpireAction +{ + Clear, + Delete +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Warning.cs b/src/EllieBot/Db/Models/Warning.cs new file mode 100644 index 0000000..9bd9b41 --- /dev/null +++ b/src/EllieBot/Db/Models/Warning.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class Warning : DbEntity +{ + public ulong GuildId { get; set; } + public ulong UserId { get; set; } + public string Reason { get; set; } + public bool Forgiven { get; set; } + public string ForgivenBy { get; set; } + public string Moderator { get; set; } + public long Weight { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WarningPunishment.cs b/src/EllieBot/Db/Models/WarningPunishment.cs new file mode 100644 index 0000000..02590cd --- /dev/null +++ b/src/EllieBot/Db/Models/WarningPunishment.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class WarningPunishment : DbEntity +{ + public int Count { get; set; } + public PunishmentAction Punishment { get; set; } + public int Time { get; set; } + public ulong? RoleId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/XpSettings.cs b/src/EllieBot/Db/Models/XpSettings.cs new file mode 100644 index 0000000..066cd07 --- /dev/null +++ b/src/EllieBot/Db/Models/XpSettings.cs @@ -0,0 +1,62 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class XpSettings : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public HashSet RoleRewards { get; set; } = new(); + public HashSet CurrencyRewards { get; set; } = new(); + public HashSet ExclusionList { get; set; } = new(); + public bool ServerExcluded { get; set; } +} + +public enum ExcludedItemType { Channel, Role } + +public class XpRoleReward : DbEntity +{ + public int XpSettingsId { get; set; } + public XpSettings XpSettings { get; set; } + + public int Level { get; set; } + public ulong RoleId { get; set; } + + /// + /// Whether the role should be removed (true) or added (false) + /// + public bool Remove { get; set; } + + public override int GetHashCode() + => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); + + public override bool Equals(object obj) + => obj is XpRoleReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; +} + +public class XpCurrencyReward : DbEntity +{ + public int XpSettingsId { get; set; } + public XpSettings XpSettings { get; set; } + + public int Level { get; set; } + public int Amount { get; set; } + + public override int GetHashCode() + => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); + + public override bool Equals(object obj) + => obj is XpCurrencyReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; +} + +public class ExcludedItem : DbEntity +{ + public ulong ItemId { get; set; } + public ExcludedItemType ItemType { get; set; } + + public override int GetHashCode() + => ItemId.GetHashCode() ^ ItemType.GetHashCode(); + + public override bool Equals(object obj) + => obj is ExcludedItem ei && ei.ItemId == ItemId && ei.ItemType == ItemType; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/XpShotOwnedItem.cs b/src/EllieBot/Db/Models/XpShotOwnedItem.cs new file mode 100644 index 0000000..aaba2f6 --- /dev/null +++ b/src/EllieBot/Db/Models/XpShotOwnedItem.cs @@ -0,0 +1,18 @@ +#nullable disable +using EllieBot.Services.Database.Models; + +namespace EllieBot.Db.Models; + +public class XpShopOwnedItem : DbEntity +{ + public ulong UserId { get; set; } + public XpShopItemType ItemType { get; set; } + public bool IsUsing { get; set; } + public string ItemKey { get; set; } +} + +public enum XpShopItemType +{ + Background = 0, + Frame = 1, +} \ No newline at end of file diff --git a/src/EllieBot/Db/MysqlContext.cs b/src/EllieBot/Db/MysqlContext.cs new file mode 100644 index 0000000..5406c1d --- /dev/null +++ b/src/EllieBot/Db/MysqlContext.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Services.Database; + +public sealed class MysqlContext : EllieContext +{ + private readonly string _connStr; + private readonly string _version; + + protected override string CurrencyTransactionOtherIdDefaultValue + => "NULL"; + + public MysqlContext(string connStr = "Server=localhost", string version = "8.0") + { + _connStr = connStr; + _version = version; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + optionsBuilder + .UseLowerCaseNamingConvention() + .UseMySql(_connStr, ServerVersion.Parse(_version)); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // mysql is case insensitive by default + // we can set binary collation to change that + modelBuilder.Entity() + .Property(x => x.Name) + .UseCollation("utf8mb4_bin"); + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/PostgreSqlContext.cs b/src/EllieBot/Db/PostgreSqlContext.cs new file mode 100644 index 0000000..f254aaf --- /dev/null +++ b/src/EllieBot/Db/PostgreSqlContext.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Services.Database; + +public class PostgreSqlContext : EllieContext +{ + private readonly string _connStr; + + protected override string CurrencyTransactionOtherIdDefaultValue + => "NULL"; + + public PostgreSqlContext(string connStr = "Host=localhost") + { + _connStr = connStr; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); + + base.OnConfiguring(optionsBuilder); + optionsBuilder + .UseLowerCaseNamingConvention() + .UseNpgsql(_connStr); + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/SqliteContext.cs b/src/EllieBot/Db/SqliteContext.cs new file mode 100644 index 0000000..6744423 --- /dev/null +++ b/src/EllieBot/Db/SqliteContext.cs @@ -0,0 +1,26 @@ +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Services.Database; + +public sealed class SqliteContext : EllieContext +{ + private readonly string _connectionString; + + protected override string CurrencyTransactionOtherIdDefaultValue + => "NULL"; + + public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60) + { + _connectionString = connectionString; + Database.SetCommandTimeout(commandTimeout); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + var builder = new SqliteConnectionStringBuilder(_connectionString); + builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource); + optionsBuilder.UseSqlite(builder.ToString()); + } +} \ No newline at end of file From 1ee97675b097a3d70c11a2586ea2b22929e62f15 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 14 Apr 2024 23:36:32 +1200 Subject: [PATCH 21/62] I broke the Db I guess? --- src/EllieBot/Db/EllieContext.cs | 6 +-- src/EllieBot/Db/Extensions/ClubExtensions.cs | 2 +- .../CurrencyTransactionExtensions.cs | 12 ++--- src/EllieBot/Db/Extensions/DbExtensions.cs | 2 +- .../Db/Extensions/DiscordUserExtensions.cs | 2 +- .../Extensions/EllieExpressionExtensions.cs | 2 +- .../MusicPlayerSettingsExtensions.cs | 2 +- .../Db/Extensions/MusicPlaylistExtensions.cs | 4 +- src/EllieBot/Db/Extensions/PollExtensions.cs | 10 +++- .../Db/Extensions/ReminderExtensions.cs | 2 +- .../SelfAssignableRolesExtensions.cs | 2 +- .../Db/Extensions/UserXpExtensions.cs | 2 +- src/EllieBot/Db/Extensions/WaifuExtensions.cs | 2 +- .../Db/Extensions/WarningExtensions.cs | 2 +- src/EllieBot/Db/Models/AntiProtection.cs | 12 ++--- src/EllieBot/Db/Models/AutoCommand.cs | 2 +- src/EllieBot/Db/Models/AutoPublishChannel.cs | 2 +- .../Db/Models/AutoTranslateChannel.cs | 2 +- src/EllieBot/Db/Models/AutoTranslateUser.cs | 2 +- src/EllieBot/Db/Models/BanTemplate.cs | 2 +- src/EllieBot/Db/Models/BlacklistEntry.cs | 1 + src/EllieBot/Db/Models/ClubInfo.cs | 8 +-- src/EllieBot/Db/Models/CommandAlias.cs | 2 +- src/EllieBot/Db/Models/CommandCooldown.cs | 2 +- src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs | 4 +- ...dPermOverride.cs => DiscordPemOverride.cs} | 0 src/EllieBot/Db/Models/DiscordUser.cs | 8 +-- src/EllieBot/Db/Models/EllieExpression.cs | 5 +- src/EllieBot/Db/Models/Event.cs | 49 +++++++++++++++++++ src/EllieBot/Db/Models/FeedSub.cs | 4 +- src/EllieBot/Db/Models/FilterChannelId.cs | 6 +-- .../Db/Models/FilterLinksChannelId.cs | 6 +-- src/EllieBot/Db/Models/FilteredWord.cs | 2 +- src/EllieBot/Db/Models/FollowedStream.cs | 2 +- src/EllieBot/Db/Models/GCChannelId.cs | 6 +-- src/EllieBot/Db/Models/GroupName.cs | 2 +- src/EllieBot/Db/Models/GuildConfig.cs | 2 +- src/EllieBot/Db/Models/LogSetting.cs | 4 +- src/EllieBot/Db/Models/MutedUserId.cs | 2 +- src/EllieBot/Db/Models/PatronQuota.cs | 2 +- src/EllieBot/Db/Models/Permission.cs | 3 +- src/EllieBot/Db/Models/SelfAssignableRole.cs | 2 +- src/EllieBot/Db/Models/ShopEntry.cs | 2 +- src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs | 2 +- src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs | 2 +- src/EllieBot/Db/Models/StreamOnlineMessage.cs | 2 +- src/EllieBot/Db/Models/StreamRoleSettings.cs | 2 +- src/EllieBot/Db/Models/UnbanTimer.cs | 2 +- src/EllieBot/Db/Models/UnmuteTimer.cs | 4 +- src/EllieBot/Db/Models/UnroleTimer.cs | 2 +- src/EllieBot/Db/Models/VcRoleInfo.cs | 2 +- src/EllieBot/Db/Models/WaifuItem.cs | 4 +- src/EllieBot/Db/Models/WarnExpireAction.cs | 2 +- src/EllieBot/Db/Models/WarningPunishment.cs | 2 +- src/EllieBot/Db/Models/XpSettings.cs | 2 +- ...{XpShotOwnedItem.cs => XpShopOwnedItem.cs} | 2 +- src/EllieBot/Db/MysqlContext.cs | 4 +- src/EllieBot/Db/PostgreSqlContext.cs | 6 +-- src/EllieBot/Db/SqliteContext.cs | 4 +- 59 files changed, 149 insertions(+), 93 deletions(-) rename src/EllieBot/Db/Models/{DiscordPermOverride.cs => DiscordPemOverride.cs} (100%) create mode 100644 src/EllieBot/Db/Models/Event.cs rename src/EllieBot/Db/Models/{XpShotOwnedItem.cs => XpShopOwnedItem.cs} (91%) diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs index f995daa..b5fffda 100644 --- a/src/EllieBot/Db/EllieContext.cs +++ b/src/EllieBot/Db/EllieContext.cs @@ -11,7 +11,7 @@ namespace EllieBot.Services.Database; public abstract class EllieContext : DbContext { public DbSet GuildConfigs { get; set; } - + public DbSet Quotes { get; set; } public DbSet Reminders { get; set; } public DbSet SelfAssignableRoles { get; set; } @@ -60,8 +60,8 @@ public abstract class EllieContext : DbContext public DbSet PatronQuotas { get; set; } public DbSet StreamOnlineMessages { get; set; } - - + + #region Mandatory Provider-Specific Values protected abstract string CurrencyTransactionOtherIdDefaultValue { get; } diff --git a/src/EllieBot/Db/Extensions/ClubExtensions.cs b/src/EllieBot/Db/Extensions/ClubExtensions.cs index d8183fc..88a851b 100644 --- a/src/EllieBot/Db/Extensions/ClubExtensions.cs +++ b/src/EllieBot/Db/Extensions/ClubExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Db.Models; diff --git a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs index c6659ca..4bd2439 100644 --- a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs +++ b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using LinqToDB.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; @@ -12,9 +12,9 @@ public static class CurrencyTransactionExtensions ulong userId, int page) => set.ToLinqToDBTable() - .Where(x => x.UserId == userId) - .OrderByDescending(x => x.DateAdded) - .Skip(15 * page) - .Take(15) - .ToListAsyncLinqToDB(); + .Where(x => x.UserId == userId) + .OrderByDescending(x => x.DateAdded) + .Skip(15 * page) + .Take(15) + .ToListAsyncLinqToDB(); } \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DbExtensions.cs b/src/EllieBot/Db/Extensions/DbExtensions.cs index 6878b31..568643b 100644 --- a/src/EllieBot/Db/Extensions/DbExtensions.cs +++ b/src/EllieBot/Db/Extensions/DbExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs index fc165c5..8d94814 100644 --- a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs +++ b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using LinqToDB; using LinqToDB.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; diff --git a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs index 7eaf707..658a631 100644 --- a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs +++ b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using LinqToDB; using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs index bbefa11..d8a3d12 100644 --- a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs +++ b/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs index 747d218..e7ac6aa 100644 --- a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs +++ b/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; @@ -8,7 +8,7 @@ public static class MusicPlaylistExtensions { public static List GetPlaylistsOnPage(this DbSet playlists, int num) { - if (num < 0) + if (num < 1) throw new ArgumentOutOfRangeException(nameof(num)); return playlists.AsQueryable().Skip((num - 1) * 20).Take(20).Include(pl => pl.Songs).ToList(); diff --git a/src/EllieBot/Db/Extensions/PollExtensions.cs b/src/EllieBot/Db/Extensions/PollExtensions.cs index abbf992..8491d65 100644 --- a/src/EllieBot/Db/Extensions/PollExtensions.cs +++ b/src/EllieBot/Db/Extensions/PollExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database; using EllieBot.Services.Database.Models; @@ -20,9 +20,15 @@ public static class PollExtensions if (p.Votes is not null) { ctx.RemoveRange(p.Votes); + p.Votes.Clear(); + } + + if (p.Answers is not null) + { + ctx.RemoveRange(p.Answers); p.Answers.Clear(); } - + ctx.Poll.Remove(p); } } \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ReminderExtensions.cs b/src/EllieBot/Db/Extensions/ReminderExtensions.cs index 33a79ca..1fd519f 100644 --- a/src/EllieBot/Db/Extensions/ReminderExtensions.cs +++ b/src/EllieBot/Db/Extensions/ReminderExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs index ee6ef7b..b2e3e39 100644 --- a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs +++ b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Extensions/UserXpExtensions.cs b/src/EllieBot/Db/Extensions/UserXpExtensions.cs index be1d97f..a20071b 100644 --- a/src/EllieBot/Db/Extensions/UserXpExtensions.cs +++ b/src/EllieBot/Db/Extensions/UserXpExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using LinqToDB; using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database; diff --git a/src/EllieBot/Db/Extensions/WaifuExtensions.cs b/src/EllieBot/Db/Extensions/WaifuExtensions.cs index ee1fddf..97d9cf4 100644 --- a/src/EllieBot/Db/Extensions/WaifuExtensions.cs +++ b/src/EllieBot/Db/Extensions/WaifuExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using LinqToDB; using LinqToDB.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; diff --git a/src/EllieBot/Db/Extensions/WarningExtensions.cs b/src/EllieBot/Db/Extensions/WarningExtensions.cs index 59474d2..76d0815 100644 --- a/src/EllieBot/Db/Extensions/WarningExtensions.cs +++ b/src/EllieBot/Db/Extensions/WarningExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Models/AntiProtection.cs b/src/EllieBot/Db/Models/AntiProtection.cs index 2301b42..8539496 100644 --- a/src/EllieBot/Db/Models/AntiProtection.cs +++ b/src/EllieBot/Db/Models/AntiProtection.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class AntiRaidSetting : DbEntity @@ -11,10 +11,10 @@ public class AntiRaidSetting : DbEntity public PunishmentAction Action { get; set; } /// - /// Duration of the punishment, in minutes. This works only in supported Actions, like: - /// Mute, ChatMute, VoiceMute, etc... + /// Duration of the punishment, in minutes. This works only for supported Actions, like: + /// Mute, Chatmute, Voicemute, etc... /// - public int PunishmentDuration { get; set; } + public int PunishDuration { get; set; } } public class AntiSpamSetting : DbEntity @@ -57,9 +57,9 @@ public class AntiSpamIgnore : DbEntity { public ulong ChannelId { get; set; } - public override int GetHashCode() + public override int GetHashCode() => ChannelId.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object obj) => obj is AntiSpamIgnore inst ? inst.ChannelId == ChannelId : false; } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoCommand.cs b/src/EllieBot/Db/Models/AutoCommand.cs index 3738c37..8bcae05 100644 --- a/src/EllieBot/Db/Models/AutoCommand.cs +++ b/src/EllieBot/Db/Models/AutoCommand.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class AutoCommand : DbEntity diff --git a/src/EllieBot/Db/Models/AutoPublishChannel.cs b/src/EllieBot/Db/Models/AutoPublishChannel.cs index fa81769..a19fd28 100644 --- a/src/EllieBot/Db/Models/AutoPublishChannel.cs +++ b/src/EllieBot/Db/Models/AutoPublishChannel.cs @@ -1,4 +1,4 @@ -using EllieBot.Services.Database.Models; +using EllieBot.Services.Database.Models; namespace EllieBot.Db.Models; diff --git a/src/EllieBot/Db/Models/AutoTranslateChannel.cs b/src/EllieBot/Db/Models/AutoTranslateChannel.cs index a90df1e..6f6ef58 100644 --- a/src/EllieBot/Db/Models/AutoTranslateChannel.cs +++ b/src/EllieBot/Db/Models/AutoTranslateChannel.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class AutoTranslateChannel : DbEntity diff --git a/src/EllieBot/Db/Models/AutoTranslateUser.cs b/src/EllieBot/Db/Models/AutoTranslateUser.cs index ebe6754..6e36404 100644 --- a/src/EllieBot/Db/Models/AutoTranslateUser.cs +++ b/src/EllieBot/Db/Models/AutoTranslateUser.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class AutoTranslateUser : DbEntity diff --git a/src/EllieBot/Db/Models/BanTemplate.cs b/src/EllieBot/Db/Models/BanTemplate.cs index cc72275..d32f4c7 100644 --- a/src/EllieBot/Db/Models/BanTemplate.cs +++ b/src/EllieBot/Db/Models/BanTemplate.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class BanTemplate : DbEntity diff --git a/src/EllieBot/Db/Models/BlacklistEntry.cs b/src/EllieBot/Db/Models/BlacklistEntry.cs index 849c3f7..3ecf999 100644 --- a/src/EllieBot/Db/Models/BlacklistEntry.cs +++ b/src/EllieBot/Db/Models/BlacklistEntry.cs @@ -1,3 +1,4 @@ +#nullable disable namespace EllieBot.Services.Database.Models; public class BlacklistEntry : DbEntity diff --git a/src/EllieBot/Db/Models/ClubInfo.cs b/src/EllieBot/Db/Models/ClubInfo.cs index 75d2d1b..8c8f85c 100644 --- a/src/EllieBot/Db/Models/ClubInfo.cs +++ b/src/EllieBot/Db/Models/ClubInfo.cs @@ -9,8 +9,8 @@ public class ClubInfo : DbEntity [MaxLength(20)] public string Name { get; set; } public string Description { get; set; } - public string ImageUrl { get; set; } - + public string ImageUrl { get; set; } = string.Empty; + public int Xp { get; set; } = 0; public int? OwnerId { get; set; } public DiscordUser Owner { get; set; } @@ -27,7 +27,7 @@ public class ClubApplicants { public int ClubId { get; set; } public ClubInfo Club { get; set; } - + public int UserId { get; set; } public DiscordUser User { get; set; } } @@ -36,7 +36,7 @@ public class ClubBans { public int ClubId { get; set; } public ClubInfo Club { get; set; } - + public int UserId { get; set; } public DiscordUser User { get; set; } } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandAlias.cs b/src/EllieBot/Db/Models/CommandAlias.cs index be2a6f1..b3d6fc4 100644 --- a/src/EllieBot/Db/Models/CommandAlias.cs +++ b/src/EllieBot/Db/Models/CommandAlias.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class CommandAlias : DbEntity diff --git a/src/EllieBot/Db/Models/CommandCooldown.cs b/src/EllieBot/Db/Models/CommandCooldown.cs index 2b824ef..f25cd08 100644 --- a/src/EllieBot/Db/Models/CommandCooldown.cs +++ b/src/EllieBot/Db/Models/CommandCooldown.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class CommandCooldown : DbEntity diff --git a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs index 59ac41d..6a24297 100644 --- a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs +++ b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class DelMsgOnCmdChannel : DbEntity @@ -9,6 +9,6 @@ public class DelMsgOnCmdChannel : DbEntity public override int GetHashCode() => ChannelId.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object obj) => obj is DelMsgOnCmdChannel x && x.ChannelId == ChannelId; } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordPermOverride.cs b/src/EllieBot/Db/Models/DiscordPemOverride.cs similarity index 100% rename from src/EllieBot/Db/Models/DiscordPermOverride.cs rename to src/EllieBot/Db/Models/DiscordPemOverride.cs diff --git a/src/EllieBot/Db/Models/DiscordUser.cs b/src/EllieBot/Db/Models/DiscordUser.cs index aa52e19..5f8cc7b 100644 --- a/src/EllieBot/Db/Models/DiscordUser.cs +++ b/src/EllieBot/Db/Models/DiscordUser.cs @@ -10,20 +10,20 @@ public class DiscordUser : DbEntity public string Username { get; set; } public string Discriminator { get; set; } public string AvatarId { get; set; } - + public int? ClubId { get; set; } public ClubInfo Club { get; set; } public bool IsClubAdmin { get; set; } - + public long TotalXp { get; set; } public XpNotificationLocation NotifyOnLevelUp { get; set; } - + public long CurrencyAmount { get; set; } public override bool Equals(object obj) => obj is DiscordUser du ? du.UserId == UserId : false; - public override int GetHashCode() + public override int GetHashCode() => UserId.GetHashCode(); public override string ToString() diff --git a/src/EllieBot/Db/Models/EllieExpression.cs b/src/EllieBot/Db/Models/EllieExpression.cs index 9218e0c..28c75f1 100644 --- a/src/EllieBot/Db/Models/EllieExpression.cs +++ b/src/EllieBot/Db/Models/EllieExpression.cs @@ -6,14 +6,15 @@ public class EllieExpression : DbEntity public ulong? GuildId { get; set; } public string Response { get; set; } public string Trigger { get; set; } - + public bool AutoDeleteTrigger { get; set; } public bool DmResponse { get; set; } public bool ContainsAnywhere { get; set; } public bool AllowTarget { get; set; } + public string Reactions { get; set; } public string[] GetReactions() - => string.IsNullOrWhiteSpace(Reaactions) ? Array.Empty() : Reaactions.Split("@@@"); + => string.IsNullOrWhiteSpace(Reactions) ? Array.Empty() : Reactions.Split("@@@"); public bool IsGlobal() => GuildId is null or 0; diff --git a/src/EllieBot/Db/Models/Event.cs b/src/EllieBot/Db/Models/Event.cs new file mode 100644 index 0000000..bface52 --- /dev/null +++ b/src/EllieBot/Db/Models/Event.cs @@ -0,0 +1,49 @@ +#nullable disable +namespace EllieBot.Services.Database.Models; + +public class CurrencyEvent +{ + public enum Type + { + Reaction, + + GameStatus + //NotRaid, + } + + public ulong ServerId { get; set; } + public ulong ChannelId { get; set; } + public ulong MessageId { get; set; } + public Type EventType { get; set; } + + /// + /// Amount of currency that the user will be rewarded. + /// + public long Amount { get; set; } + + /// + /// Maximum amount of currency that can be handed out. + /// + public long PotSize { get; set; } + + public List AwardedUsers { get; set; } + + /// + /// Used as extra data storage for events which need it. + /// + public ulong ExtraId { get; set; } + + /// + /// May be used for some future event. + /// + public ulong ExtraId2 { get; set; } + + /// + /// May be used for some future event. + /// + public string ExtraString { get; set; } +} + +public class AwardedUser +{ +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FeedSub.cs b/src/EllieBot/Db/Models/FeedSub.cs index f15aa81..f5fccc6 100644 --- a/src/EllieBot/Db/Models/FeedSub.cs +++ b/src/EllieBot/Db/Models/FeedSub.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class FeedSub : DbEntity @@ -8,7 +8,7 @@ public class FeedSub : DbEntity public ulong ChannelId { get; set; } public string Url { get; set; } - + public string Message { get; set; } public override int GetHashCode() diff --git a/src/EllieBot/Db/Models/FilterChannelId.cs b/src/EllieBot/Db/Models/FilterChannelId.cs index e674ec2..9eaf8fa 100644 --- a/src/EllieBot/Db/Models/FilterChannelId.cs +++ b/src/EllieBot/Db/Models/FilterChannelId.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class FilterChannelId : DbEntity @@ -11,7 +11,7 @@ public class FilterChannelId : DbEntity public override bool Equals(object obj) => obj is FilterChannelId fci && Equals(fci); - public override int GetHashCode() + public override int GetHashCode() => ChannelId.GetHashCode(); } @@ -22,7 +22,7 @@ public class FilterWordsChannelId : DbEntity public bool Equals(FilterWordsChannelId other) => ChannelId == other.ChannelId; - public override bool Equals(object obj) + public override bool Equals(object obj) => obj is FilterWordsChannelId fci && Equals(fci); public override int GetHashCode() diff --git a/src/EllieBot/Db/Models/FilterLinksChannelId.cs b/src/EllieBot/Db/Models/FilterLinksChannelId.cs index 440085e..f48d9b4 100644 --- a/src/EllieBot/Db/Models/FilterLinksChannelId.cs +++ b/src/EllieBot/Db/Models/FilterLinksChannelId.cs @@ -1,13 +1,13 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class FilterLinksChannelId : DbEntity { public ulong ChannelId { get; set; } - public override bool Equals(object obj) + public override bool Equals(object obj) => obj is FilterLinksChannelId f && f.ChannelId == ChannelId; - public override int GetHashCode() + public override int GetHashCode() => ChannelId.GetHashCode(); } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilteredWord.cs b/src/EllieBot/Db/Models/FilteredWord.cs index 5a5ee93..4ff32f7 100644 --- a/src/EllieBot/Db/Models/FilteredWord.cs +++ b/src/EllieBot/Db/Models/FilteredWord.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class FilteredWord : DbEntity diff --git a/src/EllieBot/Db/Models/FollowedStream.cs b/src/EllieBot/Db/Models/FollowedStream.cs index 3a96846..ca119b4 100644 --- a/src/EllieBot/Db/Models/FollowedStream.cs +++ b/src/EllieBot/Db/Models/FollowedStream.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Modules.Searches.Common; using EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Models/GCChannelId.cs b/src/EllieBot/Db/Models/GCChannelId.cs index 387605c..1f265d7 100644 --- a/src/EllieBot/Db/Models/GCChannelId.cs +++ b/src/EllieBot/Db/Models/GCChannelId.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class GCChannelId : DbEntity @@ -6,9 +6,9 @@ public class GCChannelId : DbEntity public GuildConfig GuildConfig { get; set; } public ulong ChannelId { get; set; } - public override bool Equals(object obj) + public override bool Equals(object obj) => obj is GCChannelId gc && gc.ChannelId == ChannelId; - public override int GetHashCode() + public override int GetHashCode() => ChannelId.GetHashCode(); } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GroupName.cs b/src/EllieBot/Db/Models/GroupName.cs index 52ef07b..de88717 100644 --- a/src/EllieBot/Db/Models/GroupName.cs +++ b/src/EllieBot/Db/Models/GroupName.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class GroupName : DbEntity diff --git a/src/EllieBot/Db/Models/GuildConfig.cs b/src/EllieBot/Db/Models/GuildConfig.cs index 5346489..b05df52 100644 --- a/src/EllieBot/Db/Models/GuildConfig.cs +++ b/src/EllieBot/Db/Models/GuildConfig.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Db.Models; namespace EllieBot.Services.Database.Models; diff --git a/src/EllieBot/Db/Models/LogSetting.cs b/src/EllieBot/Db/Models/LogSetting.cs index b09371a..93228ca 100644 --- a/src/EllieBot/Db/Models/LogSetting.cs +++ b/src/EllieBot/Db/Models/LogSetting.cs @@ -26,10 +26,10 @@ public class LogSetting : DbEntity public ulong? UserMutedId { get; set; } - // userpresence + //userpresence public ulong? LogUserPresenceId { get; set; } - // voicepresence + //voicepresence public ulong? LogVoicePresenceId { get; set; } public ulong? LogVoicePresenceTTSId { get; set; } diff --git a/src/EllieBot/Db/Models/MutedUserId.cs b/src/EllieBot/Db/Models/MutedUserId.cs index 2d752f6..78fc9f3 100644 --- a/src/EllieBot/Db/Models/MutedUserId.cs +++ b/src/EllieBot/Db/Models/MutedUserId.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class MutedUserId : DbEntity diff --git a/src/EllieBot/Db/Models/PatronQuota.cs b/src/EllieBot/Db/Models/PatronQuota.cs index ba5129d..1ebd2fd 100644 --- a/src/EllieBot/Db/Models/PatronQuota.cs +++ b/src/EllieBot/Db/Models/PatronQuota.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Db.Models; /// diff --git a/src/EllieBot/Db/Models/Permission.cs b/src/EllieBot/Db/Models/Permission.cs index 61089f6..24a8186 100644 --- a/src/EllieBot/Db/Models/Permission.cs +++ b/src/EllieBot/Db/Models/Permission.cs @@ -1,10 +1,9 @@ -#nullable disable +#nullable disable using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics; namespace EllieBot.Services.Database.Models; - [DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")] public class Permissionv2 : DbEntity, IIndexed { diff --git a/src/EllieBot/Db/Models/SelfAssignableRole.cs b/src/EllieBot/Db/Models/SelfAssignableRole.cs index df6cd48..c68fd32 100644 --- a/src/EllieBot/Db/Models/SelfAssignableRole.cs +++ b/src/EllieBot/Db/Models/SelfAssignableRole.cs @@ -5,7 +5,7 @@ public class SelfAssignedRole : DbEntity { public ulong GuildId { get; set; } public ulong RoleId { get; set; } - + public int Group { get; set; } public int LevelRequirement { get; set; } } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ShopEntry.cs b/src/EllieBot/Db/Models/ShopEntry.cs index ed83cb1..6d08ab3 100644 --- a/src/EllieBot/Db/Models/ShopEntry.cs +++ b/src/EllieBot/Db/Models/ShopEntry.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public enum ShopEntryType diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs index a2d6bdd..4e55546 100644 --- a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs +++ b/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class SlowmodeIgnoredRole : DbEntity diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs index 92597c3..c6a62f2 100644 --- a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs +++ b/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class SlowmodeIgnoredUser : DbEntity diff --git a/src/EllieBot/Db/Models/StreamOnlineMessage.cs b/src/EllieBot/Db/Models/StreamOnlineMessage.cs index e9b1e24..2f8c821 100644 --- a/src/EllieBot/Db/Models/StreamOnlineMessage.cs +++ b/src/EllieBot/Db/Models/StreamOnlineMessage.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Services.Database.Models; namespace EllieBot.Db.Models; diff --git a/src/EllieBot/Db/Models/StreamRoleSettings.cs b/src/EllieBot/Db/Models/StreamRoleSettings.cs index dbab2d0..8b9b379 100644 --- a/src/EllieBot/Db/Models/StreamRoleSettings.cs +++ b/src/EllieBot/Db/Models/StreamRoleSettings.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class StreamRoleSettings : DbEntity diff --git a/src/EllieBot/Db/Models/UnbanTimer.cs b/src/EllieBot/Db/Models/UnbanTimer.cs index b017624..6878b00 100644 --- a/src/EllieBot/Db/Models/UnbanTimer.cs +++ b/src/EllieBot/Db/Models/UnbanTimer.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class UnbanTimer : DbEntity diff --git a/src/EllieBot/Db/Models/UnmuteTimer.cs b/src/EllieBot/Db/Models/UnmuteTimer.cs index 4619b68..54638ad 100644 --- a/src/EllieBot/Db/Models/UnmuteTimer.cs +++ b/src/EllieBot/Db/Models/UnmuteTimer.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class UnmuteTimer : DbEntity @@ -9,6 +9,6 @@ public class UnmuteTimer : DbEntity public override int GetHashCode() => UserId.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object obj) => obj is UnmuteTimer ut ? ut.UserId == UserId : false; } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnroleTimer.cs b/src/EllieBot/Db/Models/UnroleTimer.cs index f7c7f8d..ceb0d4c 100644 --- a/src/EllieBot/Db/Models/UnroleTimer.cs +++ b/src/EllieBot/Db/Models/UnroleTimer.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class UnroleTimer : DbEntity diff --git a/src/EllieBot/Db/Models/VcRoleInfo.cs b/src/EllieBot/Db/Models/VcRoleInfo.cs index b80fc17..3f6155e 100644 --- a/src/EllieBot/Db/Models/VcRoleInfo.cs +++ b/src/EllieBot/Db/Models/VcRoleInfo.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class VcRoleInfo : DbEntity diff --git a/src/EllieBot/Db/Models/WaifuItem.cs b/src/EllieBot/Db/Models/WaifuItem.cs index 32df5ba..53b8f8e 100644 --- a/src/EllieBot/Db/Models/WaifuItem.cs +++ b/src/EllieBot/Db/Models/WaifuItem.cs @@ -1,10 +1,10 @@ #nullable disable namespace EllieBot.Services.Database.Models; -public class WaifuItem +public class WaifuItem : DbEntity { public WaifuInfo WaifuInfo { get; set; } public int? WaifuInfoId { get; set; } public string ItemEmoji { get; set; } public string Name { get; set; } -} \ No newline at end of file +} diff --git a/src/EllieBot/Db/Models/WarnExpireAction.cs b/src/EllieBot/Db/Models/WarnExpireAction.cs index caa595f..69d90b8 100644 --- a/src/EllieBot/Db/Models/WarnExpireAction.cs +++ b/src/EllieBot/Db/Models/WarnExpireAction.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public enum WarnExpireAction diff --git a/src/EllieBot/Db/Models/WarningPunishment.cs b/src/EllieBot/Db/Models/WarningPunishment.cs index 02590cd..a0aa731 100644 --- a/src/EllieBot/Db/Models/WarningPunishment.cs +++ b/src/EllieBot/Db/Models/WarningPunishment.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class WarningPunishment : DbEntity diff --git a/src/EllieBot/Db/Models/XpSettings.cs b/src/EllieBot/Db/Models/XpSettings.cs index 066cd07..a0cae1e 100644 --- a/src/EllieBot/Db/Models/XpSettings.cs +++ b/src/EllieBot/Db/Models/XpSettings.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services.Database.Models; public class XpSettings : DbEntity diff --git a/src/EllieBot/Db/Models/XpShotOwnedItem.cs b/src/EllieBot/Db/Models/XpShopOwnedItem.cs similarity index 91% rename from src/EllieBot/Db/Models/XpShotOwnedItem.cs rename to src/EllieBot/Db/Models/XpShopOwnedItem.cs index aaba2f6..dc0f641 100644 --- a/src/EllieBot/Db/Models/XpShotOwnedItem.cs +++ b/src/EllieBot/Db/Models/XpShopOwnedItem.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable warnings using EllieBot.Services.Database.Models; namespace EllieBot.Db.Models; diff --git a/src/EllieBot/Db/MysqlContext.cs b/src/EllieBot/Db/MysqlContext.cs index 5406c1d..1474b30 100644 --- a/src/EllieBot/Db/MysqlContext.cs +++ b/src/EllieBot/Db/MysqlContext.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using EllieBot.Db.Models; namespace EllieBot.Services.Database; @@ -8,7 +8,7 @@ public sealed class MysqlContext : EllieContext private readonly string _connStr; private readonly string _version; - protected override string CurrencyTransactionOtherIdDefaultValue + protected override string CurrencyTransactionOtherIdDefaultValue => "NULL"; public MysqlContext(string connStr = "Server=localhost", string version = "8.0") diff --git a/src/EllieBot/Db/PostgreSqlContext.cs b/src/EllieBot/Db/PostgreSqlContext.cs index f254aaf..dba46f6 100644 --- a/src/EllieBot/Db/PostgreSqlContext.cs +++ b/src/EllieBot/Db/PostgreSqlContext.cs @@ -1,12 +1,12 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; namespace EllieBot.Services.Database; -public class PostgreSqlContext : EllieContext +public sealed class PostgreSqlContext : EllieContext { private readonly string _connStr; - protected override string CurrencyTransactionOtherIdDefaultValue + protected override string CurrencyTransactionOtherIdDefaultValue => "NULL"; public PostgreSqlContext(string connStr = "Host=localhost") diff --git a/src/EllieBot/Db/SqliteContext.cs b/src/EllieBot/Db/SqliteContext.cs index 6744423..530bfb4 100644 --- a/src/EllieBot/Db/SqliteContext.cs +++ b/src/EllieBot/Db/SqliteContext.cs @@ -1,4 +1,4 @@ -using Microsoft.Data.Sqlite; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace EllieBot.Services.Database; @@ -7,7 +7,7 @@ public sealed class SqliteContext : EllieContext { private readonly string _connectionString; - protected override string CurrencyTransactionOtherIdDefaultValue + protected override string CurrencyTransactionOtherIdDefaultValue => "NULL"; public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60) From 3ef832114f73648fa27adc7b6fa5a180cd54b033 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 19:28:35 +1200 Subject: [PATCH 22/62] Removed Ayu.Discord.Voice --- .../Ayu.Discord.Voice.csproj | 17 - src/ayu/Ayu.Discord.Voice/CloseCodes.cs | 35 -- src/ayu/Ayu.Discord.Voice/LibOpus.cs | 125 ------ src/ayu/Ayu.Discord.Voice/LibSodium.cs | 32 -- .../Models/SelectProtocol.cs | 23 -- .../Ayu.Discord.Voice/Models/VoiceHello.cs | 10 - .../Ayu.Discord.Voice/Models/VoiceIdentify.cs | 20 - .../Ayu.Discord.Voice/Models/VoicePayload.cs | 29 -- .../Ayu.Discord.Voice/Models/VoiceReady.cs | 22 - .../Ayu.Discord.Voice/Models/VoiceResume.cs | 16 - .../Models/VoiceSessionDescription.cs | 13 - .../Ayu.Discord.Voice/Models/VoiceSpeaking.cs | 26 -- .../PoopyBufferImmortalized.cs | 136 ------- src/ayu/Ayu.Discord.Voice/SocketClient.cs | 154 ------- src/ayu/Ayu.Discord.Voice/SongBuffer.cs | 95 ----- src/ayu/Ayu.Discord.Voice/VoiceClient.cs | 207 ---------- src/ayu/Ayu.Discord.Voice/VoiceGateway.cs | 375 ------------------ 17 files changed, 1335 deletions(-) delete mode 100644 src/ayu/Ayu.Discord.Voice/Ayu.Discord.Voice.csproj delete mode 100644 src/ayu/Ayu.Discord.Voice/CloseCodes.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/LibOpus.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/LibSodium.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/SelectProtocol.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoiceHello.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoiceIdentify.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoicePayload.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoiceReady.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoiceResume.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoiceSessionDescription.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/Models/VoiceSpeaking.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/PoopyBufferImmortalized.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/SocketClient.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/SongBuffer.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/VoiceClient.cs delete mode 100644 src/ayu/Ayu.Discord.Voice/VoiceGateway.cs diff --git a/src/ayu/Ayu.Discord.Voice/Ayu.Discord.Voice.csproj b/src/ayu/Ayu.Discord.Voice/Ayu.Discord.Voice.csproj deleted file mode 100644 index 4b51f13..0000000 --- a/src/ayu/Ayu.Discord.Voice/Ayu.Discord.Voice.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - netstandard2.1 - 9.0 - true - CS8632 - 1.0.2 - - - - - - - - - diff --git a/src/ayu/Ayu.Discord.Voice/CloseCodes.cs b/src/ayu/Ayu.Discord.Voice/CloseCodes.cs deleted file mode 100644 index e35d27e..0000000 --- a/src/ayu/Ayu.Discord.Voice/CloseCodes.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace Ayu.Discord.Gateway -{ - public static class CloseCodes - { - private static IReadOnlyDictionary _closeCodes = new ReadOnlyDictionary( - new Dictionary() - { - { 4000, ("Unknown error", "We're not sure what went wrong. Try reconnecting?")}, - { 4001, ("Unknown opcode", "You sent an invalid Gateway opcode or an invalid payload for an opcode. Don't do that!")}, - { 4002, ("Decode error", "You sent an invalid payload to us. Don't do that!")}, - { 4003, ("Not authenticated", "You sent us a payload prior to identifying.")}, - { 4004, ("Authentication failed", "The account token sent with your identify payload is incorrect.")}, - { 4005, ("Already authenticated", "You sent more than one identify payload. Don't do that!")}, - { 4007, ("Invalid seq", "The sequence sent when resuming the session was invalid. Reconnect and start a new session.")}, - { 4008, ("Rate limited", "Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this.")}, - { 4009, ("Session timed out", "Your session timed out. Reconnect and start a new one.")}, - { 4010, ("Invalid shard", "You sent us an invalid shard when identifying.")}, - { 4011, ("Sharding required", "The session would have handled too many guilds - you are required to shard your connection in order to connect.")}, - { 4012, ("Invalid API version", "You sent an invalid version for the gateway.")}, - { 4013, ("Invalid intent(s)", "You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value.")}, - { 4014, ("Disallowed intent(s)", "You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not whitelisted for.")} - }); - - public static (string Error, string Message) GetErrorCodeMessage(int closeCode) - { - if (_closeCodes.TryGetValue(closeCode, out var data)) - return data; - -return ("Unknown error", closeCode.ToString()); - } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/LibOpus.cs b/src/ayu/Ayu.Discord.Voice/LibOpus.cs deleted file mode 100644 index 66d5d04..0000000 --- a/src/ayu/Ayu.Discord.Voice/LibOpus.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Ayu.Discord.Voice -{ - internal static unsafe class LibOpus - { - public const string OPUS = "opus"; - - [DllImport(OPUS, EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr CreateEncoder(int Fs, int channels, int application, out OpusError error); - - [DllImport(OPUS, EntryPoint = "opus_encoder_destroy", CallingConvention = CallingConvention.Cdecl)] - internal static extern void DestroyEncoder(IntPtr encoder); - - [DllImport(OPUS, EntryPoint = "opus_encode", CallingConvention = CallingConvention.Cdecl)] - internal static extern int Encode(IntPtr st, byte* pcm, int frame_size, byte* data, int max_data_bytes); - - [DllImport(OPUS, EntryPoint = "opus_encode_float", CallingConvention = CallingConvention.Cdecl)] - internal static extern int EncodeFloat(IntPtr st, byte* pcm, int frame_size, byte* data, int max_data_bytes); - - [DllImport(OPUS, EntryPoint = "opus_encoder_ctl", CallingConvention = CallingConvention.Cdecl)] - internal static extern int EncoderCtl(IntPtr st, OpusCtl request, int value); - } - - public enum OpusApplication - { - VOIP = 2048, - Audio = 2049, - RestrictedLowdelay = 2051 - } - - public unsafe class LibOpusEncoder : IDisposable - { - private readonly IntPtr _encoderPtr; - - private readonly int _sampleRate; - - // private readonly int _channels; - // private readonly int _bitRate; - private readonly int _frameDelay; - - private readonly int _frameSizePerChannel; - public int FrameSizePerChannel => _frameSizePerChannel; - - public const int MaxData = 1276; - - public LibOpusEncoder(int sampleRate, int channels, int bitRate, int frameDelay) - { - _sampleRate = sampleRate; - // _channels = channels; - // _bitRate = bitRate; - _frameDelay = frameDelay; - _frameSizePerChannel = _sampleRate * _frameDelay / 1000; - - _encoderPtr = LibOpus.CreateEncoder(sampleRate, channels, (int) OpusApplication.Audio, out var error); - if (error != OpusError.OK) - throw new ExternalException(error.ToString()); - - LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetSignal, (int) OpusSignal.Music); - LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetInbandFEC, 1); - LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetBitrate, bitRate); - LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetPacketLossPerc, 2); - } - - public int SetControl(OpusCtl ctl, int value) - => LibOpus.EncoderCtl(_encoderPtr, ctl, value); - - public int Encode(Span input, byte[] output) - { - fixed (byte* inPtr = input) - fixed (byte* outPtr = output) - return LibOpus.Encode(_encoderPtr, inPtr, FrameSizePerChannel, outPtr, output.Length); - } - - public int EncodeFloat(Span input, byte[] output) - { - fixed (byte* inPtr = input) - fixed (byte* outPtr = output) - return LibOpus.EncodeFloat(_encoderPtr, inPtr, FrameSizePerChannel, outPtr, output.Length); - } - - - public void Dispose() - => LibOpus.DestroyEncoder(_encoderPtr); - } - - public enum OpusCtl - { - SetBitrate = 4002, - GetBitrate = 4003, - SetBandwidth = 4008, - GetBandwidth = 4009, - SetComplexity = 4010, - GetComplexity = 4011, - SetInbandFEC = 4012, - GetInbandFEC = 4013, - SetPacketLossPerc = 4014, - GetPacketLossPerc = 4015, - SetLsbDepth = 4036, - GetLsbDepth = 4037, - SetDtx = 4016, - GetDtx = 4017, - SetSignal = 4024 - } - - public enum OpusError - { - OK = 0, - BadArg = -1, - BufferToSmall = -2, - InternalError = -3, - InvalidPacket = -4, - Unimplemented = -5, - InvalidState = -6, - AllocFail = -7 - } - - public enum OpusSignal - { - Auto = -1000, - Voice = 3001, - Music = 3002, - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/LibSodium.cs b/src/ayu/Ayu.Discord.Voice/LibSodium.cs deleted file mode 100644 index baa081e..0000000 --- a/src/ayu/Ayu.Discord.Voice/LibSodium.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Ayu.Discord.Voice -{ - internal static unsafe class Sodium - { - private const string SODIUM = "libsodium"; - - [DllImport(SODIUM, EntryPoint = "crypto_secretbox_easy", CallingConvention = CallingConvention.Cdecl)] - private static extern int SecretBoxEasy(byte* output, byte* input, long inputLength, byte* nonce, byte* secret); - [DllImport(SODIUM, EntryPoint = "crypto_secretbox_open_easy", CallingConvention = CallingConvention.Cdecl)] - private static extern int SecretBoxOpenEasy(byte* output, byte* input, ulong inputLength, byte* nonce, byte* secret); - - public static int Encrypt(byte[] input, int inputOffset, long inputLength, byte[] output, int outputOffset, in ReadOnlySpan nonce, byte[] secret) - { - fixed (byte* inPtr = input) - fixed (byte* outPtr = output) - fixed (byte* noncePtr = nonce) - fixed (byte* secretPtr = secret) - return SecretBoxEasy(outPtr + outputOffset, inPtr + inputOffset, inputLength - inputOffset, noncePtr, secretPtr); - } - public static int Decrypt(byte[] input, ulong inputLength, byte[] output, in ReadOnlySpan nonce, byte[] secret) - { - fixed (byte* outPtr = output) - fixed (byte* inPtr = input) - fixed (byte* noncePtr = nonce) - fixed (byte* secretPtr = secret) - return SecretBoxOpenEasy(outPtr, inPtr, inputLength, noncePtr, secretPtr); - } - } -} diff --git a/src/ayu/Ayu.Discord.Voice/Models/SelectProtocol.cs b/src/ayu/Ayu.Discord.Voice/Models/SelectProtocol.cs deleted file mode 100644 index d3ffd25..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/SelectProtocol.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class SelectProtocol - { - [JsonProperty("protocol")] - public string Protocol { get; set; } - - [JsonProperty("data")] - public ProtocolData Data { get; set; } - - public sealed class ProtocolData - { - [JsonProperty("address")] - public string Address { get; set; } - [JsonProperty("port")] - public int Port { get; set; } - [JsonProperty("mode")] - public string Mode { get; set; } - } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoiceHello.cs b/src/ayu/Ayu.Discord.Voice/Models/VoiceHello.cs deleted file mode 100644 index 64e8154..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoiceHello.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class VoiceHello - { - [JsonProperty("heartbeat_interval")] - public int HeartbeatInterval { get; set; } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoiceIdentify.cs b/src/ayu/Ayu.Discord.Voice/Models/VoiceIdentify.cs deleted file mode 100644 index be72f48..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoiceIdentify.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class VoiceIdentify - { - [JsonProperty("server_id")] - public string ServerId { get; set; } - - [JsonProperty("user_id")] - public string UserId { get; set; } - - [JsonProperty("session_id")] - public string SessionId { get; set; } - - [JsonProperty("token")] - public string Token { get; set; } - - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoicePayload.cs b/src/ayu/Ayu.Discord.Voice/Models/VoicePayload.cs deleted file mode 100644 index 5ac642e..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoicePayload.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Discord.Models.Gateway -{ - public sealed class VoicePayload - { - [JsonProperty("op")] - public VoiceOpCode OpCode { get; set; } - - [JsonProperty("d")] - public JToken Data { get; set; } - } - - public enum VoiceOpCode - { - Identify = 0, - SelectProtocol = 1, - Ready = 2, - Heartbeat = 3, - SessionDescription = 4, - Speaking = 5, - HeartbeatAck = 6, - Resume = 7, - Hello = 8, - Resumed = 9, - ClientDisconnect = 13, - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoiceReady.cs b/src/ayu/Ayu.Discord.Voice/Models/VoiceReady.cs deleted file mode 100644 index 8cae4bb..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoiceReady.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class VoiceReady - { - [JsonProperty("ssrc")] - public uint Ssrc { get; set; } - - [JsonProperty("ip")] - public string Ip { get; set; } - - [JsonProperty("port")] - public int Port { get; set; } - - [JsonProperty("modes")] - public string[] Modes { get; set; } - - [JsonProperty("heartbeat_interval")] - public string HeartbeatInterval { get; set; } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoiceResume.cs b/src/ayu/Ayu.Discord.Voice/Models/VoiceResume.cs deleted file mode 100644 index b5875b8..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoiceResume.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class VoiceResume - { - [JsonProperty("server_id")] - public string ServerId { get; set; } - - [JsonProperty("session_id")] - public string SessionId { get; set; } - - [JsonProperty("token")] - public string Token { get; set; } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoiceSessionDescription.cs b/src/ayu/Ayu.Discord.Voice/Models/VoiceSessionDescription.cs deleted file mode 100644 index ca02029..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoiceSessionDescription.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class VoiceSessionDescription - { - [JsonProperty("mode")] - public string Mode { get; set; } - - [JsonProperty("secret_key")] - public byte[] SecretKey { get; set; } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/Models/VoiceSpeaking.cs b/src/ayu/Ayu.Discord.Voice/Models/VoiceSpeaking.cs deleted file mode 100644 index 909c10d..0000000 --- a/src/ayu/Ayu.Discord.Voice/Models/VoiceSpeaking.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace Ayu.Discord.Voice.Models -{ - public sealed class VoiceSpeaking - { - [JsonProperty("speaking")] - public int Speaking { get; set; } - - [JsonProperty("delay")] - public int Delay { get; set; } - - [JsonProperty("ssrc")] - public uint Ssrc { get; set; } - - [Flags] - public enum State - { - None = 0, - Microphone = 1 << 0, - Soundshare = 1 << 1, - Priority = 1 << 2 - } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/PoopyBufferImmortalized.cs b/src/ayu/Ayu.Discord.Voice/PoopyBufferImmortalized.cs deleted file mode 100644 index 581d5fa..0000000 --- a/src/ayu/Ayu.Discord.Voice/PoopyBufferImmortalized.cs +++ /dev/null @@ -1,136 +0,0 @@ -#nullable enable -using System; -using System.Buffers; -using System.Threading; -using System.Threading.Tasks; - -namespace Ayu.Discord.Voice -{ - public sealed class PoopyBufferImmortalized : ISongBuffer - { - private readonly byte[] _buffer; - private readonly byte[] _outputArray; - private CancellationToken _cancellationToken; - private bool _isStopped; - - public int ReadPosition { get; private set; } - public int WritePosition { get; private set; } - - public int ContentLength => WritePosition >= ReadPosition - ? WritePosition - ReadPosition - : (_buffer.Length - ReadPosition) + WritePosition; - - public int FreeSpace => _buffer.Length - ContentLength; - - public bool Stopped => _cancellationToken.IsCancellationRequested || _isStopped; - - public PoopyBufferImmortalized(int frameSize) - { - _buffer = ArrayPool.Shared.Rent(1_000_000); - _outputArray = new byte[frameSize]; - - ReadPosition = 0; - WritePosition = 0; - } - - public void Stop() - => _isStopped = true; - - // this method needs a rewrite - public Task BufferAsync(ITrackDataSource source, CancellationToken cancellationToken) - { - _cancellationToken = cancellationToken; - var bufferingCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - Task.Run(async () => - { - var output = ArrayPool.Shared.Rent(38400); - try - { - int read; - while (!Stopped && (read = source.Read(output)) > 0) - { - while (!Stopped && FreeSpace <= read) - { - bufferingCompleted.TrySetResult(true); - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } - - if (Stopped) - break; - - Write(output, read); - } - } - finally - { - ArrayPool.Shared.Return(output); - bufferingCompleted.TrySetResult(true); - } - }, cancellationToken); - - return bufferingCompleted.Task; - } - - private void Write(byte[] input, int writeCount) - { - if (WritePosition + writeCount < _buffer.Length) - { - Buffer.BlockCopy(input, 0, _buffer, WritePosition, writeCount); - WritePosition += writeCount; - return; - } - - var wroteNormally = _buffer.Length - WritePosition; - Buffer.BlockCopy(input, 0, _buffer, WritePosition, wroteNormally); - var wroteFromStart = writeCount - wroteNormally; - Buffer.BlockCopy(input, wroteNormally, _buffer, 0, wroteFromStart); - WritePosition = wroteFromStart; - } - - public Span Read(int count, out int length) - { - var toRead = Math.Min(ContentLength, count); - var wp = WritePosition; - - if (ContentLength == 0) - { - length = 0; - return Span.Empty; - } - - if (wp > ReadPosition || ReadPosition + toRead <= _buffer.Length) - { - // thsi can be achieved without copying if - // writer never writes until the end, - // but leaves a single chunk free - Span toReturn = _outputArray; - ((Span) _buffer).Slice(ReadPosition, toRead).CopyTo(toReturn); - ReadPosition += toRead; - length = toRead; - return toReturn; - } - else - { - Span toReturn = _outputArray; - var toEnd = _buffer.Length - ReadPosition; - var bufferSpan = (Span) _buffer; - - bufferSpan.Slice(ReadPosition, toEnd).CopyTo(toReturn); - var fromStart = toRead - toEnd; - bufferSpan.Slice(0, fromStart).CopyTo(toReturn.Slice(toEnd)); - ReadPosition = fromStart; - length = toEnd + fromStart; - return toReturn; - } - } - - public void Dispose() - => ArrayPool.Shared.Return(_buffer); - - public void Reset() - { - ReadPosition = 0; - WritePosition = 0; - } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/SocketClient.cs b/src/ayu/Ayu.Discord.Voice/SocketClient.cs deleted file mode 100644 index a7d4620..0000000 --- a/src/ayu/Ayu.Discord.Voice/SocketClient.cs +++ /dev/null @@ -1,154 +0,0 @@ -using Serilog; -using System; -using System.Buffers; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; - -namespace Ayu.Discord.Gateway -{ - public class SocketClient : IDisposable - { - private ClientWebSocket? _ws; - - public event Func? PayloadReceived = delegate { return Task.CompletedTask; }; - public event Func? WebsocketClosed = delegate { return Task.CompletedTask; }; - - const int CHUNK_SIZE = 1024 * 16; - - public async Task RunAndBlockAsync(Uri url, CancellationToken cancel) - { - var error = "Error."; - var bufferWriter = new ArrayBufferWriter(CHUNK_SIZE); - try - { - using (_ws = new()) - { - await _ws.ConnectAsync(url, cancel).ConfigureAwait(false); - // WebsocketConnected!.Invoke(this); - - while (true) - { - var result = await _ws.ReceiveAsync(bufferWriter.GetMemory(CHUNK_SIZE), cancel); - bufferWriter.Advance(result.Count); - if (result.MessageType == WebSocketMessageType.Close) - { - var closeMessage = CloseCodes.GetErrorCodeMessage((int?) _ws.CloseStatus ?? 0).Message; - error = $"Websocket closed ({_ws.CloseStatus}): {_ws.CloseStatusDescription} {closeMessage}"; - break; - } - - if (result.EndOfMessage) - { - var pr = PayloadReceived; - var data = bufferWriter.WrittenMemory.ToArray(); - bufferWriter.Clear(); - - if (pr is not null) - { - await pr.Invoke(data); - } - } - } - } - } - catch (WebSocketException ex) - { - Log.Warning("Disconnected, check your internet connection..."); - Log.Debug(ex, "Websocket Exception in websocket client"); - } - catch (OperationCanceledException) - { - // ignored - } - catch (Exception ex) - { - Log.Error(ex, "Error in websocket client. {Message}", ex.Message); - } - finally - { - bufferWriter.Clear(); - _ws = null; - await ClosedAsync(error).ConfigureAwait(false); - } - } - - private async Task ClosedAsync(string msg = "Error") - { - try - { - await WebsocketClosed!.Invoke(msg).ConfigureAwait(false); - } - catch - { - } - } - - private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1); - - public async Task SendAsync(byte[] data) - { - await _sendLock.WaitAsync().ConfigureAwait(false); - try - { - var ws = _ws; - if (ws is null) - throw new WebSocketException("Websocket is disconnected."); - for (var i = 0; i < data.Length; i += 4096) - { - var count = i + 4096 > data.Length ? data.Length - i : 4096; - await ws.SendAsync(new(data, i, count), - WebSocketMessageType.Text, - i + count >= data.Length, - CancellationToken.None).ConfigureAwait(false); - } - } - finally - { - _sendLock.Release(); - } - } - - public async Task SendBulkAsync(byte[] data) - { - var ws = _ws; - if (ws is null) - throw new WebSocketException("Websocket is disconnected."); - - await ws.SendAsync(new(data, 0, data.Length), - WebSocketMessageType.Binary, - true, - CancellationToken.None).ConfigureAwait(false); - } - - public async Task CloseAsync(string msg = "Stop") - { - if (_ws is not null && _ws.State != WebSocketState.Closed) - { - try - { - await _ws.CloseAsync(WebSocketCloseStatus.InternalServerError, msg, CancellationToken.None) - .ConfigureAwait(false); - -return true; - } - catch - { - } - } - - return false; - } - - public void Dispose() - { - PayloadReceived = null; - WebsocketClosed = null; - var ws = _ws; - if (ws is null) - return; - - ws.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/SongBuffer.cs b/src/ayu/Ayu.Discord.Voice/SongBuffer.cs deleted file mode 100644 index b5f09ef..0000000 --- a/src/ayu/Ayu.Discord.Voice/SongBuffer.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Serilog; -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Ayu.Discord.Voice -{ - public interface ISongBuffer : IDisposable - { - Span Read(int toRead, out int read); - Task BufferAsync(ITrackDataSource source, CancellationToken cancellationToken); - void Reset(); - void Stop(); - } - - public interface ITrackDataSource - { - public int Read(byte[] output); - } - - public sealed class FfmpegTrackDataSource : ITrackDataSource, IDisposable - { - private Process _p; - - private readonly string _streamUrl; - private readonly bool _isLocal; - private readonly string _pcmType; - - private FfmpegTrackDataSource(int bitDepth, string streamUrl, bool isLocal) - { - this._pcmType = bitDepth == 16 ? "s16le" : "f32le"; - this._streamUrl = streamUrl; - this._isLocal = isLocal; - } - - public static FfmpegTrackDataSource CreateAsync(int bitDepth, string streamUrl, bool isLocal) - { - try - { - var source = new FfmpegTrackDataSource(bitDepth, streamUrl, isLocal); - source.StartFFmpegProcess(); - return source; - } - catch (System.ComponentModel.Win32Exception) - { - Log.Error(@"You have not properly installed or configured FFMPEG. -Please install and configure FFMPEG to play music. -Check the guides for your platform on how to setup ffmpeg correctly: - Windows Guide: https://goo.gl/OjKk8F - Linux Guide: https://goo.gl/ShjCUo"); - throw; - } - catch (OperationCanceledException) - { - } - catch (InvalidOperationException) - { - } - catch (Exception ex) - { - Log.Information(ex, "Error starting ffmpeg: {ErrorMessage}", ex.Message); - } - - return null; - } - - private Process StartFFmpegProcess() - { - var args = $"-err_detect ignore_err -i {_streamUrl} -f {_pcmType} -ar 48000 -vn -ac 2 pipe:1 -loglevel error"; - if (!_isLocal) - args = $"-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 {args}"; - - return _p = Process.Start(new ProcessStartInfo - { - FileName = "ffmpeg", - Arguments = args, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = false, - CreateNoWindow = true, - }); - } - - public int Read(byte[] output) - => _p.StandardOutput.BaseStream.Read(output); - - public void Dispose() - { - try { _p?.Kill(); } catch { } - - try { _p?.Dispose(); } catch { } - } - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/VoiceClient.cs b/src/ayu/Ayu.Discord.Voice/VoiceClient.cs deleted file mode 100644 index 31cfd5f..0000000 --- a/src/ayu/Ayu.Discord.Voice/VoiceClient.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using System.Buffers; - -namespace Ayu.Discord.Voice -{ - public sealed class VoiceClient : IDisposable - { - delegate int EncodeDelegate(Span input, byte[] output); - - private readonly int sampleRate; - private readonly int bitRate; - private readonly int channels; - private readonly int frameDelay; - private readonly int bitDepth; - - public LibOpusEncoder Encoder { get; } - private readonly ArrayPool _arrayPool; - - public int BitDepth => bitDepth * 8; - public int Delay => frameDelay; - - private int FrameSizePerChannel => Encoder.FrameSizePerChannel; - public int InputLength => FrameSizePerChannel * channels * bitDepth; - - EncodeDelegate Encode; - - // https://github.com/xiph/opus/issues/42 w - public VoiceClient(SampleRate sampleRate = SampleRate._48k, - Bitrate bitRate = Bitrate._192k, - Channels channels = Channels.Two, - FrameDelay frameDelay = FrameDelay.Delay20, - BitDepthEnum bitDepthEnum = BitDepthEnum.Float32) - { - this.frameDelay = (int) frameDelay; - this.sampleRate = (int) sampleRate; - this.bitRate = (int) bitRate; - this.channels = (int) channels; - this.bitDepth = (int) bitDepthEnum; - - this.Encoder = new(this.sampleRate, this.channels, this.bitRate, this.frameDelay); - - Encode = bitDepthEnum switch - { - BitDepthEnum.Float32 => Encoder.EncodeFloat, - BitDepthEnum.UInt16 => Encoder.Encode, - _ => throw new NotSupportedException(nameof(BitDepth)) - }; - - if (bitDepthEnum == BitDepthEnum.Float32) - { - Encode = Encoder.EncodeFloat; - } - else - { - Encode = Encoder.Encode; - } - - _arrayPool = ArrayPool.Shared; - } - - public int SendPcmFrame(VoiceGateway gw, Span data, int offset, int count) - { - var secretKey = gw.SecretKey; - if (secretKey.Length == 0) - { - return (int) SendPcmError.SecretKeyUnavailable; - } - - // encode using opus - var encodeOutput = _arrayPool.Rent(LibOpusEncoder.MaxData); - try - { - var encodeOutputLength = Encode(data, encodeOutput); - return SendOpusFrame(gw, encodeOutput, 0, encodeOutputLength); - } - finally - { - _arrayPool.Return(encodeOutput); - } - } - - public int SendOpusFrame(VoiceGateway gw, byte[] data, int offset, int count) - { - var secretKey = gw.SecretKey; - if (secretKey is null) - { - return (int) SendPcmError.SecretKeyUnavailable; - } - - // form RTP header - var headerLength = 1 // version + flags - + 1 // payload type - + 2 // sequence - + 4 // timestamp - + 4; // ssrc - - var header = new byte[headerLength]; - - header[0] = 0x80; // version + flags - header[1] = 0x78; // payload type - - // get byte values for header data - var seqBytes = BitConverter.GetBytes(gw.Sequence); // 2 - var nonceBytes = BitConverter.GetBytes(gw.NonceSequence); // 2 - var timestampBytes = BitConverter.GetBytes(gw.Timestamp); // 4 - var ssrcBytes = BitConverter.GetBytes(gw.Ssrc); // 4 - - gw.Timestamp += (uint) FrameSizePerChannel; - gw.Sequence++; - gw.NonceSequence++; - - if (BitConverter.IsLittleEndian) - { - Array.Reverse(seqBytes); - Array.Reverse(nonceBytes); - Array.Reverse(timestampBytes); - Array.Reverse(ssrcBytes); - } - - // copy headers - Buffer.BlockCopy(seqBytes, 0, header, 2, 2); - Buffer.BlockCopy(timestampBytes, 0, header, 4, 4); - Buffer.BlockCopy(ssrcBytes, 0, header, 8, 4); - - //// encryption part - //// create a byte array where to store the encrypted data - //// it has to be inputLength + crypto_secretbox_MACBYTES (constant with value 16) - var encryptedBytes = new byte[count + 16]; - - //// form nonce with header + 12 empty bytes - //var nonce = new byte[24]; - //Buffer.BlockCopy(rtpHeader, 0, nonce, 0, rtpHeader.Length); - - var nonce = new byte[4]; - Buffer.BlockCopy(seqBytes, 0, nonce, 2, 2); - - Sodium.Encrypt(data, 0, count, encryptedBytes, 0, nonce, secretKey); - - var rtpDataLength = headerLength + encryptedBytes.Length + nonce.Length; - var rtpData = _arrayPool.Rent(rtpDataLength); - try - { - //copy headers - Buffer.BlockCopy(header, 0, rtpData, 0, header.Length); - //copy audio data - Buffer.BlockCopy(encryptedBytes, 0, rtpData, header.Length, encryptedBytes.Length); - Buffer.BlockCopy(nonce, 0, rtpData, rtpDataLength - 4, 4); - - gw.SendRtpData(rtpData, rtpDataLength); - // FUTURE When there's a break in the sent data, - // the packet transmission shouldn't simply stop. - // Instead, send five frames of silence (0xF8, 0xFF, 0xFE) - // before stopping to avoid unintended Opus interpolation - // with subsequent transmissions. - - return rtpDataLength; - } - finally - { - _arrayPool.Return(rtpData); - } - } - - public void Dispose() - => Encoder.Dispose(); - } - - public enum SendPcmError - { - SecretKeyUnavailable = -1, - } - - - public enum FrameDelay - { - Delay5 = 5, - Delay10 = 10, - Delay20 = 20, - Delay40 = 40, - Delay60 = 60, - } - - public enum BitDepthEnum - { - UInt16 = sizeof(UInt16), - Float32 = sizeof(float), - } - - public enum SampleRate - { - _48k = 48_000, - } - - public enum Bitrate - { - _64k = 64 * 1024, - _96k = 96 * 1024, - _128k = 128 * 1024, - _192k = 192 * 1024, - } - - public enum Channels - { - One = 1, - Two = 2, - } -} \ No newline at end of file diff --git a/src/ayu/Ayu.Discord.Voice/VoiceGateway.cs b/src/ayu/Ayu.Discord.Voice/VoiceGateway.cs deleted file mode 100644 index 6080572..0000000 --- a/src/ayu/Ayu.Discord.Voice/VoiceGateway.cs +++ /dev/null @@ -1,375 +0,0 @@ -using Ayu.Discord.Voice.Models; -using Discord.Models.Gateway; -using Newtonsoft.Json.Linq; -using Serilog; -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Ayu.Discord.Gateway; -using Newtonsoft.Json; - -namespace Ayu.Discord.Voice -{ - public class VoiceGateway - { - private class QueueItem - { - public VoicePayload Payload { get; } - public TaskCompletionSource Result { get; } - - public QueueItem(VoicePayload payload, TaskCompletionSource result) - { - Payload = payload; - Result = result; - } - } - - private readonly ulong _guildId; - private readonly ulong _userId; - private readonly string _sessionId; - private readonly string _token; - private readonly string _endpoint; - private readonly Uri _websocketUrl; - private readonly Channel _channel; - - public TaskCompletionSource ConnectingFinished { get; } - - private readonly Random _rng; - private readonly SocketClient _ws; - private readonly UdpClient _udpClient; - private Timer? _heartbeatTimer; - private bool _receivedAck; - private IPEndPoint? _udpEp; - - public uint Ssrc { get; private set; } - public string Ip { get; private set; } = string.Empty; - public int Port { get; private set; } = 0; - public byte[] SecretKey { get; private set; } = Array.Empty(); - public string Mode { get; private set; } = string.Empty; - public ushort Sequence { get; set; } - public uint NonceSequence { get; set; } - public uint Timestamp { get; set; } - public string MyIp { get; private set; } = string.Empty; - public ushort MyPort { get; private set; } - private bool _shouldResume; - -private readonly CancellationTokenSource _stopCancellationSource; -private readonly CancellationToken _stopCancellationToken; -public bool Stopped => _stopCancellationToken.IsCancellationRequested; - -public event Func OnClosed = delegate { return Task.CompletedTask; }; - -public VoiceGateway(ulong guildId, ulong userId, string session, string token, string endpoint) -{ - this._guildId = guildId; - this._userId = userId; - this._sessionId = session; - this._token = token; - this._endpoint = endpoint; - - //Log.Information("g: {GuildId} u: {UserId} sess: {Session} tok: {Token} ep: {Endpoint}", - // guildId, userId, session, token, endpoint); - - this._websocketUrl = new($"wss://{_endpoint.Replace(":80", "")}?v=4"); - this._channel = Channel.CreateUnbounded(new() - { - SingleReader = true, - SingleWriter = false, - AllowSynchronousContinuations = false, - }); - - ConnectingFinished = new(); - - _rng = new(); - - _ws = new(); - _udpClient = new(); - _stopCancellationSource = new(); - _stopCancellationToken = _stopCancellationSource.Token; - - _ws.PayloadReceived += _ws_PayloadReceived; - _ws.WebsocketClosed += _ws_WebsocketClosed; -} - -public Task WaitForReadyAsync() - => ConnectingFinished.Task; - -private async Task SendLoop() -{ - while (!_stopCancellationToken.IsCancellationRequested) - { - try - { - var qi = await _channel.Reader.ReadAsync(_stopCancellationToken); - //Log.Information("Sending payload with opcode {OpCode}", qi.Payload.OpCode); - - var json = JsonConvert.SerializeObject(qi.Payload); - - if (!_stopCancellationToken.IsCancellationRequested) - await _ws.SendAsync(Encoding.UTF8.GetBytes(json)); - _ = Task.Run(() => qi.Result.TrySetResult(true)); - } - catch (ChannelClosedException) - { - Log.Warning("Voice gateway send channel is closed"); - } - } -} - -private async Task _ws_PayloadReceived(byte[] arg) -{ - var payload = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(arg)); - if (payload is null) - return; - try - { - //Log.Information("Received payload with opcode {OpCode}", payload.OpCode); - - switch (payload.OpCode) - { - case VoiceOpCode.Identify: - // sent, not received. - break; - case VoiceOpCode.SelectProtocol: - // sent, not received - break; - case VoiceOpCode.Ready: - var ready = payload.Data.ToObject(); - await HandleReadyAsync(ready!); - _shouldResume = true; - break; - case VoiceOpCode.Heartbeat: - // sent, not received - break; - case VoiceOpCode.SessionDescription: - var sd = payload.Data.ToObject(); - await HandleSessionDescription(sd!); - break; - case VoiceOpCode.Speaking: - // ignore for now - break; - case VoiceOpCode.HeartbeatAck: - _receivedAck = true; - break; - case VoiceOpCode.Resume: - // sent, not received - break; - case VoiceOpCode.Hello: - var hello = payload.Data.ToObject(); - await HandleHelloAsync(hello!); - break; - case VoiceOpCode.Resumed: - _shouldResume = true; - break; - case VoiceOpCode.ClientDisconnect: - break; - } - } - catch (Exception ex) - { - Log.Error(ex, "Error handling payload with opcode {OpCode}: {Message}", payload.OpCode, ex.Message); - } -} -private Task _ws_WebsocketClosed(string arg) -{ - if (!string.IsNullOrWhiteSpace(arg)) - { - Log.Warning("Voice Websocket closed: {Arg}", arg); - } - - var hbt = _heartbeatTimer; - hbt?.Change(Timeout.Infinite, Timeout.Infinite); - _heartbeatTimer = null; - - if (!_stopCancellationToken.IsCancellationRequested && _shouldResume) - { - _ = _ws.RunAndBlockAsync(_websocketUrl, _stopCancellationToken); - return Task.CompletedTask; - } - -_ws.WebsocketClosed -= _ws_WebsocketClosed; -_ws.PayloadReceived -= _ws_PayloadReceived; - -if(!_stopCancellationToken.IsCancellationRequested) - _stopCancellationSource.Cancel(); - -return this.OnClosed(this); -} - -public void SendRtpData(byte[] rtpData, int length) - => _udpClient.Send(rtpData, length, _udpEp); - -private Task HandleSessionDescription(VoiceSessionDescription sd) -{ - SecretKey = sd.SecretKey; - Mode = sd.Mode; - - _ = Task.Run(() => ConnectingFinished.TrySetResult(true)); - - return Task.CompletedTask; -} - -private Task ResumeAsync() -{ - _shouldResume = false; - return SendCommandPayloadAsync(new() - { - OpCode = VoiceOpCode.Resume, - Data = JToken.FromObject(new VoiceResume - { - ServerId = this._guildId.ToString(), - SessionId = this._sessionId, - Token = this._token, - }) - }); -} - -private async Task HandleReadyAsync(VoiceReady ready) -{ - Ssrc = ready.Ssrc; - - //Log.Information("Received ready {GuildId}, {Session}, {Token}", guildId, session, token); - - _udpEp = new(IPAddress.Parse(ready.Ip), ready.Port); - - var ssrcBytes = BitConverter.GetBytes(Ssrc); - Array.Reverse(ssrcBytes); - var ipDiscoveryData = new byte[74]; - Buffer.BlockCopy(ssrcBytes, 0, ipDiscoveryData, 4, ssrcBytes.Length); - ipDiscoveryData[0] = 0x00; - ipDiscoveryData[1] = 0x01; - ipDiscoveryData[2] = 0x00; - ipDiscoveryData[3] = 0x46; - await _udpClient.SendAsync(ipDiscoveryData, ipDiscoveryData.Length, _udpEp); - while (true) - { - var buffer = _udpClient.Receive(ref _udpEp); - - if (buffer.Length == 74) - { - //Log.Information("Received IP discovery data."); - - var myIp = Encoding.UTF8.GetString(buffer, 8, buffer.Length - 10); - MyIp = myIp.TrimEnd('\0'); - MyPort = (ushort)((buffer[^2] << 8) | buffer[^1]); - - //Log.Information("{MyIp}:{MyPort}", MyIp, MyPort); - - await SelectProtocol(); - return; - } - - //Log.Information("Received voice data"); - } -} - -private Task HandleHelloAsync(VoiceHello data) -{ - _receivedAck = true; - _heartbeatTimer = new(async _ => - { - await SendHeartbeatAsync(); - }, default, data.HeartbeatInterval, data.HeartbeatInterval); - - if (_shouldResume) - { - return ResumeAsync(); - } - - return IdentifyAsync(); -} - -private Task IdentifyAsync() - => SendCommandPayloadAsync(new() - { - OpCode = VoiceOpCode.Identify, - Data = JToken.FromObject(new VoiceIdentify - { - ServerId = _guildId.ToString(), - SessionId = _sessionId, - Token = _token, - UserId = _userId.ToString(), - }) - }); - -private Task SelectProtocol() - => SendCommandPayloadAsync(new() - { - OpCode = VoiceOpCode.SelectProtocol, - Data = JToken.FromObject(new SelectProtocol - { - Protocol = "udp", - Data = new() - { - Address = MyIp, - Port = MyPort, - Mode = "xsalsa20_poly1305_lite", - } - }) - }); - -private async Task SendHeartbeatAsync() -{ - if (!_receivedAck) - { - Log.Warning("Voice gateway didn't receive HearbeatAck - closing"); - var success = await _ws.CloseAsync(); - if (!success) - await _ws_WebsocketClosed(null); - return; - } - -_receivedAck = false; -await SendCommandPayloadAsync(new() -{ - OpCode = VoiceOpCode.Heartbeat, - Data = JToken.FromObject(_rng.Next()) -}); -} - -public Task SendSpeakingAsync(VoiceSpeaking.State speaking) - => SendCommandPayloadAsync(new() - { - OpCode = VoiceOpCode.Speaking, - Data = JToken.FromObject(new VoiceSpeaking - { - Delay = 0, - Ssrc = Ssrc, - Speaking = (int)speaking - }) - }); - -public Task StopAsync() -{ - Started = false; - _shouldResume = false; - if(!_stopCancellationSource.IsCancellationRequested) - try { _stopCancellationSource.Cancel(); } catch { } - return _ws.CloseAsync("Stopped by the user."); -} - -public Task Start() -{ - Started = true; - _ = SendLoop(); - return _ws.RunAndBlockAsync(_websocketUrl, _stopCancellationToken); -} - -public bool Started { get; set; } - -public async Task SendCommandPayloadAsync(VoicePayload payload) -{ - var complete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - var queueItem = new QueueItem(payload, complete); - - if (!_channel.Writer.TryWrite(queueItem)) - await _channel.Writer.WriteAsync(queueItem); - - await complete.Task; -} - } -} \ No newline at end of file From 32637d42650f2dc933a9ff5e3e20b8787163ed95 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 19:29:05 +1200 Subject: [PATCH 23/62] Removed Ellie.Common --- src/Ellie.Common/AsyncLazy.cs | 19 --- .../Collections/ConcurrentHashSet.cs | 88 ----------- .../Collections/IndexedCollection.cs | 148 ------------------ src/Ellie.Common/Ellie.Common.csproj | 15 -- src/Ellie.Common/EllieRandom.cs | 69 -------- .../Extensions/ArrayExtensions.cs | 51 ------ .../Extensions/EnumerableExtensions.cs | 107 ------------- .../Extensions/HttpClientExtensions.cs | 35 ----- src/Ellie.Common/Extensions/PipExtensions.cs | 22 --- src/Ellie.Common/GlobalUsings.cs | 1 - src/Ellie.Common/Helpers/LogSetup.cs | 36 ----- .../Helpers/StandardConversions.cs | 7 - src/Ellie.Common/Kwum.cs | 100 ------------ src/Ellie.Common/QueueRunner.cs | 63 -------- src/Ellie.Common/ShmartBankAmount.cs | 19 --- src/Ellie.Common/ShmartNumber.cs | 38 ----- 16 files changed, 818 deletions(-) delete mode 100644 src/Ellie.Common/AsyncLazy.cs delete mode 100644 src/Ellie.Common/Collections/ConcurrentHashSet.cs delete mode 100644 src/Ellie.Common/Collections/IndexedCollection.cs delete mode 100644 src/Ellie.Common/Ellie.Common.csproj delete mode 100644 src/Ellie.Common/EllieRandom.cs delete mode 100644 src/Ellie.Common/Extensions/ArrayExtensions.cs delete mode 100644 src/Ellie.Common/Extensions/EnumerableExtensions.cs delete mode 100644 src/Ellie.Common/Extensions/HttpClientExtensions.cs delete mode 100644 src/Ellie.Common/Extensions/PipExtensions.cs delete mode 100644 src/Ellie.Common/GlobalUsings.cs delete mode 100644 src/Ellie.Common/Helpers/LogSetup.cs delete mode 100644 src/Ellie.Common/Helpers/StandardConversions.cs delete mode 100644 src/Ellie.Common/Kwum.cs delete mode 100644 src/Ellie.Common/QueueRunner.cs delete mode 100644 src/Ellie.Common/ShmartBankAmount.cs delete mode 100644 src/Ellie.Common/ShmartNumber.cs diff --git a/src/Ellie.Common/AsyncLazy.cs b/src/Ellie.Common/AsyncLazy.cs deleted file mode 100644 index 5c69a0d..0000000 --- a/src/Ellie.Common/AsyncLazy.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Ellie.Common; - -public class AsyncLazy : Lazy> -{ - public AsyncLazy(Func valueFactory) - : base(() => Task.Run(valueFactory)) - { - } - - public AsyncLazy(Func> taskFactory) - : base(() => Task.Run(taskFactory)) - { - } - - public TaskAwaiter GetAwaiter() - => Value.GetAwaiter(); -} diff --git a/src/Ellie.Common/Collections/ConcurrentHashSet.cs b/src/Ellie.Common/Collections/ConcurrentHashSet.cs deleted file mode 100644 index 19986be..0000000 --- a/src/Ellie.Common/Collections/ConcurrentHashSet.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Diagnostics; - -namespace System.Collections.Generic; - -[DebuggerDisplay("{_backingStore.Count}")] -public sealed class ConcurrentHashSet : IReadOnlyCollection, ICollection where T : notnull -{ - private readonly ConcurrentDictionary _backingStore; - - public ConcurrentHashSet() - => _backingStore = new(); - - public ConcurrentHashSet(IEnumerable values, IEqualityComparer? comparer = null) - => _backingStore = new(values.Select(x => new KeyValuePair(x, true)), comparer); - - public IEnumerator GetEnumerator() - => _backingStore.Keys.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); - - /// - /// Adds the specified item to the . - /// - /// The item to add. - /// - /// true if the items was added to the - /// successfully; false if it already exists. - /// - /// - /// The - /// contains too many items. - /// - public bool Add(T item) - => _backingStore.TryAdd(item, true); - - void ICollection.Add(T item) - => Add(item); - - public void Clear() - => _backingStore.Clear(); - - public bool Contains(T item) - => _backingStore.ContainsKey(item); - - public void CopyTo(T[] array, int arrayIndex) - { - ArgumentNullException.ThrowIfNull(array); - - if (arrayIndex < 0) - throw new ArgumentOutOfRangeException(nameof(arrayIndex)); - - if (arrayIndex >= array.Length) - throw new ArgumentOutOfRangeException(nameof(arrayIndex)); - - CopyToInternal(array, arrayIndex); - } - - private void CopyToInternal(T[] array, int arrayIndex) - { - var len = array.Length; - foreach (var (k, _) in _backingStore) - { - if (arrayIndex >= len) - throw new IndexOutOfRangeException(nameof(arrayIndex)); - - array[arrayIndex++] = k; - } - } - - bool ICollection.Remove(T item) - => TryRemove(item); - - public bool TryRemove(T item) - => _backingStore.TryRemove(item, out _); - - public void RemoveWhere(Func predicate) - { - foreach (var elem in this.Where(predicate)) - TryRemove(elem); - } - - public int Count - => _backingStore.Count; - - public bool IsReadOnly - => false; -} \ No newline at end of file diff --git a/src/Ellie.Common/Collections/IndexedCollection.cs b/src/Ellie.Common/Collections/IndexedCollection.cs deleted file mode 100644 index 15fdc7f..0000000 --- a/src/Ellie.Common/Collections/IndexedCollection.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System.Collections; - -namespace Ellie.Common; - -public interface IIndexed -{ - int Index { get; set; } -} - -public class IndexedCollection : IList - where T : class, IIndexed -{ - public List Source { get; } - - public int Count - => Source.Count; - - public bool IsReadOnly - => false; - - public virtual T this[int index] - { - get => Source[index]; - set - { - lock (_locker) - { - value.Index = index; - Source[index] = value; - } - } - } - - private readonly object _locker = new(); - - public IndexedCollection() - => Source = new(); - - public IndexedCollection(IEnumerable source) - { - lock (_locker) - { - Source = source.OrderBy(x => x.Index).ToList(); - UpdateIndexes(); - } - } - - public int IndexOf(T item) - => item?.Index ?? -1; - - public IEnumerator GetEnumerator() - => Source.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() - => Source.GetEnumerator(); - - public void Add(T item) - { - ArgumentNullException.ThrowIfNull(item); - - lock (_locker) - { - item.Index = Source.Count; - Source.Add(item); - } - } - - public virtual void Clear() - { - lock (_locker) - { - Source.Clear(); - } - } - - public bool Contains(T item) - { - lock (_locker) - { - return Source.Contains(item); - } - } - - public void CopyTo(T[] array, int arrayIndex) - { - lock (_locker) - { - Source.CopyTo(array, arrayIndex); - } - } - - public virtual bool Remove(T item) - { - lock (_locker) - { - if (Source.Remove(item)) - { - for (var i = 0; i < Source.Count; i++) - { - if (Source[i].Index != i) - Source[i].Index = i; - } - - return true; - } - } - - return false; - } - - public virtual void Insert(int index, T item) - { - lock (_locker) - { - Source.Insert(index, item); - for (var i = index; i < Source.Count; i++) - Source[i].Index = i; - } - } - - public virtual void RemoveAt(int index) - { - lock (_locker) - { - Source.RemoveAt(index); - for (var i = index; i < Source.Count; i++) - Source[i].Index = i; - } - } - - public void UpdateIndexes() - { - lock (_locker) - { - for (var i = 0; i < Source.Count; i++) - { - if (Source[i].Index != i) - Source[i].Index = i; - } - } - } - - public static implicit operator List(IndexedCollection x) - => x.Source; - - public List ToList() - => Source.ToList(); -} diff --git a/src/Ellie.Common/Ellie.Common.csproj b/src/Ellie.Common/Ellie.Common.csproj deleted file mode 100644 index 754532f..0000000 --- a/src/Ellie.Common/Ellie.Common.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - net6.0 - enable - enable - - - - - - - - - diff --git a/src/Ellie.Common/EllieRandom.cs b/src/Ellie.Common/EllieRandom.cs deleted file mode 100644 index efb4b8f..0000000 --- a/src/Ellie.Common/EllieRandom.cs +++ /dev/null @@ -1,69 +0,0 @@ -#nullable disable -using System.Security.Cryptography; - -namespace Ellie.Common; - -public class EllieRandom : Random -{ - private readonly RandomNumberGenerator _rng; - - public EllieRandom() - => _rng = RandomNumberGenerator.Create(); - - public override int Next() - { - var bytes = new byte[sizeof(int)]; - _rng.GetBytes(bytes); - return Math.Abs(BitConverter.ToInt32(bytes, 0)); - } - - public override int Next(int maxValue) - { - if (maxValue <= 0) - throw new ArgumentOutOfRangeException(nameof(maxValue)); - var bytes = new byte[sizeof(int)]; - _rng.GetBytes(bytes); - return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue; - } - - public override int Next(int minValue, int maxValue) - { - if (minValue > maxValue) - throw new ArgumentOutOfRangeException(nameof(maxValue)); - if (minValue == maxValue) - return minValue; - var bytes = new byte[sizeof(int)]; - _rng.GetBytes(bytes); - var sign = Math.Sign(BitConverter.ToInt32(bytes, 0)); - return (sign * BitConverter.ToInt32(bytes, 0) % (maxValue - minValue)) + minValue; - } - - public long NextLong(long minValue, long maxValue) - { - if (minValue > maxValue) - throw new ArgumentOutOfRangeException(nameof(maxValue)); - if (minValue == maxValue) - return minValue; - var bytes = new byte[sizeof(long)]; - _rng.GetBytes(bytes); - var sign = Math.Sign(BitConverter.ToInt64(bytes, 0)); - return (sign * BitConverter.ToInt64(bytes, 0) % (maxValue - minValue)) + minValue; - } - - public override void NextBytes(byte[] buffer) - => _rng.GetBytes(buffer); - - protected override double Sample() - { - var bytes = new byte[sizeof(double)]; - _rng.GetBytes(bytes); - return Math.Abs((BitConverter.ToDouble(bytes, 0) / double.MaxValue) + 1); - } - - public override double NextDouble() - { - var bytes = new byte[sizeof(double)]; - _rng.GetBytes(bytes); - return BitConverter.ToDouble(bytes, 0); - } -} diff --git a/src/Ellie.Common/Extensions/ArrayExtensions.cs b/src/Ellie.Common/Extensions/ArrayExtensions.cs deleted file mode 100644 index a861220..0000000 --- a/src/Ellie.Common/Extensions/ArrayExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace Ellie.Common; - -// made for expressions because they almost never get added -// and they get looped through constantly -public static class ArrayExtensions -{ - /// - /// Create a new array from the old array + new element at the end - /// - /// Input array - /// Item to add to the end of the output array - /// Type of the array - /// A new array with the new element at the end - public static T[] With(this T[] input, T added) - { - var newExprs = new T[input.Length + 1]; - Array.Copy(input, 0, newExprs, 0, input.Length); - newExprs[input.Length] = added; - return newExprs; - } - - /// - /// Creates a new array by applying the specified function to every element in the input array - /// - /// Array to modify - /// Function to apply - /// Orignal type of the elements in the array - /// Output type of the elements of the array - /// New array with updated elements - public static TOut[] Map(this TIn[] arr, Func f) - => Array.ConvertAll(arr, x => f(x)); - - /// - /// Creates a new array by applying the specified function to every element in the input array - /// - /// Array to modify - /// Function to apply - /// Orignal type of the elements in the array - /// Output type of the elements of the array - /// New array with updated elements - public static TOut[] Map(this IReadOnlyCollection col, Func f) - { - var toReturn = new TOut[col.Count]; - - var i = 0; - foreach (var item in col) - toReturn[i++] = f(item); - - return toReturn; - } -} diff --git a/src/Ellie.Common/Extensions/EnumerableExtensions.cs b/src/Ellie.Common/Extensions/EnumerableExtensions.cs deleted file mode 100644 index 1583b9f..0000000 --- a/src/Ellie.Common/Extensions/EnumerableExtensions.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System.Security.Cryptography; - -namespace Ellie.Common; - -public static class EnumerableExtensions -{ - /// - /// Concatenates the members of a collection, using the specified separator between each member. - /// - /// Collection to join - /// - /// The character to use as a separator. separator is included in the returned string only if - /// values has more than one element. - /// - /// Optional transformation to apply to each element before concatenation. - /// The type of the members of values. - /// - /// A string that consists of the members of values delimited by the separator character. -or- Empty if values has - /// no elements. - /// - public static string Join(this IEnumerable data, char separator, Func? func = null) - => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); - - /// - /// Concatenates the members of a collection, using the specified separator between each member. - /// - /// Collection to join - /// - /// The string to use as a separator.separator is included in the returned string only if values - /// has more than one element. - /// - /// Optional transformation to apply to each element before concatenation. - /// The type of the members of values. - /// - /// A string that consists of the members of values delimited by the separator character. -or- Empty if values has - /// no elements. - /// - public static string Join(this IEnumerable data, string separator, Func? func = null) - => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); - - /// - /// Randomize element order by performing the Fisher-Yates shuffle - /// - /// Item type - /// Items to shuffle - public static IReadOnlyList Shuffle(this IEnumerable items) - { - using var provider = RandomNumberGenerator.Create(); - var list = items.ToList(); - var n = list.Count; - while (n > 1) - { - var box = new byte[(n / byte.MaxValue) + 1]; - int boxSum; - do - { - provider.GetBytes(box); - boxSum = box.Sum(b => b); - } while (!(boxSum < n * (byte.MaxValue * box.Length / n))); - - var k = boxSum % n; - n--; - (list[k], list[n]) = (list[n], list[k]); - } - - return list; - } - - /// - /// Initializes a new instance of the class - /// that contains elements copied from the specified - /// has the default concurrency level, has the default initial capacity, - /// and uses the default comparer for the key type. - /// - /// - /// The whose elements are copied to the new - /// . - /// - /// A new instance of the class - public static ConcurrentDictionary ToConcurrent( - this IEnumerable> dict) - where TKey : notnull - => new(dict); - - public static IndexedCollection ToIndexed(this IEnumerable enumerable) - where T : class, IIndexed - => new(enumerable); - - /// - /// Creates a task that will complete when all of the objects in an enumerable - /// collection have completed - /// - /// The tasks to wait on for completion. - /// The type of the completed task. - /// A task that represents the completion of all of the supplied tasks. - public static Task WhenAll(this IEnumerable> tasks) - => Task.WhenAll(tasks); - - /// - /// Creates a task that will complete when all of the objects in an enumerable - /// collection have completed - /// - /// The tasks to wait on for completion. - /// A task that represents the completion of all of the supplied tasks. - public static Task WhenAll(this IEnumerable tasks) - => Task.WhenAll(tasks); -} diff --git a/src/Ellie.Common/Extensions/HttpClientExtensions.cs b/src/Ellie.Common/Extensions/HttpClientExtensions.cs deleted file mode 100644 index 1b4b492..0000000 --- a/src/Ellie.Common/Extensions/HttpClientExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Net.Http.Headers; - -namespace Ellie.Common; - -public static class HttpClientExtensions -{ - public static HttpClient AddFakeHeaders(this HttpClient http) - { - AddFakeHeaders(http.DefaultRequestHeaders); - return http; - } - - public static void AddFakeHeaders(this HttpHeaders dict) - { - dict.Clear(); - dict.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); - dict.Add("User-Agent", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"); - } - - public static bool IsImage(this HttpResponseMessage msg) - => IsImage(msg, out _); - - public static bool IsImage(this HttpResponseMessage msg, out string? mimeType) - { - mimeType = msg.Content.Headers.ContentType?.MediaType; - if (mimeType is "image/png" or "image/jpeg" or "image/gif") - return true; - - return false; - } - - public static long GetContentLength(this HttpResponseMessage msg) - => msg.Content.Headers.ContentLength ?? long.MaxValue; -} diff --git a/src/Ellie.Common/Extensions/PipExtensions.cs b/src/Ellie.Common/Extensions/PipExtensions.cs deleted file mode 100644 index eb2b5a2..0000000 --- a/src/Ellie.Common/Extensions/PipExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ellie.Common; - -public delegate TOut PipeFunc(in TIn a); -public delegate TOut PipeFunc(in TIn1 a, in TIn2 b); - -public static class PipeExtensions -{ - public static TOut Pipe(this TIn a, Func fn) - => fn(a); - - public static TOut Pipe(this TIn a, PipeFunc fn) - => fn(a); - - public static TOut Pipe(this (TIn1, TIn2) a, PipeFunc fn) - => fn(a.Item1, a.Item2); - - public static (TIn, TExtra) With(this TIn a, TExtra b) - => (a, b); - - public static async Task Pipe(this Task a, Func fn) - => fn(await a); -} diff --git a/src/Ellie.Common/GlobalUsings.cs b/src/Ellie.Common/GlobalUsings.cs deleted file mode 100644 index 55fdcac..0000000 --- a/src/Ellie.Common/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using NonBlocking; \ No newline at end of file diff --git a/src/Ellie.Common/Helpers/LogSetup.cs b/src/Ellie.Common/Helpers/LogSetup.cs deleted file mode 100644 index 16e1f05..0000000 --- a/src/Ellie.Common/Helpers/LogSetup.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Serilog.Events; -using Serilog.Sinks.SystemConsole.Themes; -using System.Text; -using Serilog; - -namespace Ellie.Common; - -public static class LogSetup -{ - public static void SetupLogger(object source) - { - Log.Logger = new LoggerConfiguration().MinimumLevel.Override("Microsoft", LogEventLevel.Information) - .MinimumLevel.Override("System", LogEventLevel.Information) - .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) - .Enrich.FromLogContext() - .WriteTo.Console(LogEventLevel.Information, - theme: GetTheme(), - outputTemplate: - "[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}") - .Enrich.WithProperty("LogSource", source) - .CreateLogger(); - - Console.OutputEncoding = Encoding.UTF8; - } - - private static ConsoleTheme GetTheme() - { - if (Environment.OSVersion.Platform == PlatformID.Unix) - return AnsiConsoleTheme.Code; -#if DEBUG - return AnsiConsoleTheme.Code; -#else - return ConsoleTheme.None; -#endif - } -} diff --git a/src/Ellie.Common/Helpers/StandardConversions.cs b/src/Ellie.Common/Helpers/StandardConversions.cs deleted file mode 100644 index 6b68353..0000000 --- a/src/Ellie.Common/Helpers/StandardConversions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ellie.Common; - -public static class StandardConversions -{ - public static double CelsiusToFahrenheit(double cel) - => (cel * 1.8f) + 32; -} diff --git a/src/Ellie.Common/Kwum.cs b/src/Ellie.Common/Kwum.cs deleted file mode 100644 index 87e081d..0000000 --- a/src/Ellie.Common/Kwum.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Ellie.Common; - -// needs proper invalid input check (character array input out of range) -// needs negative number support -// ReSharper disable once InconsistentNaming -#pragma warning disable IDE1006 -public readonly struct kwum : IEquatable -#pragma warning restore IDE1006 -{ - private const string VALID_CHARACTERS = "23456789abcdefghijkmnpqrstuvwxyz"; - private readonly int _value; - - public kwum(int num) - => _value = num; - - public kwum(in char c) - { - if (!IsValidChar(c)) - throw new ArgumentException("Character needs to be a valid kwum character.", nameof(c)); - - _value = InternalCharToValue(c); - } - - public kwum(in ReadOnlySpan input) - { - _value = 0; - for (var index = 0; index < input.Length; index++) - { - var c = input[index]; - if (!IsValidChar(c)) - throw new ArgumentException("All characters need to be a valid kwum characters.", nameof(input)); - - _value += VALID_CHARACTERS.IndexOf(c) * (int)Math.Pow(VALID_CHARACTERS.Length, input.Length - index - 1); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int InternalCharToValue(in char c) - => VALID_CHARACTERS.IndexOf(c); - - public static bool TryParse(in ReadOnlySpan input, out kwum value) - { - value = default; - foreach (var c in input) - { - if (!IsValidChar(c)) - return false; - } - - value = new(input); - return true; - } - - public static kwum operator +(kwum left, kwum right) - => new(left._value + right._value); - - public static bool operator ==(kwum left, kwum right) - => left._value == right._value; - - public static bool operator !=(kwum left, kwum right) - => !(left == right); - - public static implicit operator long(kwum kwum) - => kwum._value; - - public static implicit operator int(kwum kwum) - => kwum._value; - - public static implicit operator kwum(int num) - => new(num); - - public static bool IsValidChar(char c) - => VALID_CHARACTERS.Contains(c); - - public override string ToString() - { - var count = VALID_CHARACTERS.Length; - var localValue = _value; - var arrSize = (int)Math.Log(localValue, count) + 1; - Span chars = new char[arrSize]; - while (localValue > 0) - { - localValue = Math.DivRem(localValue, count, out var rem); - chars[--arrSize] = VALID_CHARACTERS[rem]; - } - - return new(chars); - } - - public override bool Equals(object? obj) - => obj is kwum kw && kw == this; - - public bool Equals(kwum other) - => other == this; - - public override int GetHashCode() - => _value.GetHashCode(); -} diff --git a/src/Ellie.Common/QueueRunner.cs b/src/Ellie.Common/QueueRunner.cs deleted file mode 100644 index 80fc691..0000000 --- a/src/Ellie.Common/QueueRunner.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Threading.Channels; -using Serilog; - -namespace Ellie.Common; - -public sealed class QueueRunner -{ - private readonly Channel> _channel; - private readonly int _delayMs; - - public QueueRunner(int delayMs = 0, int maxCapacity = -1) - { - if (delayMs < 0) - throw new ArgumentOutOfRangeException(nameof(delayMs)); - - _delayMs = delayMs; - _channel = maxCapacity switch - { - 0 or < -1 => throw new ArgumentOutOfRangeException(nameof(maxCapacity)), - -1 => Channel.CreateUnbounded>(new UnboundedChannelOptions() - { - SingleReader = true, - SingleWriter = false, - AllowSynchronousContinuations = true, - }), - _ => Channel.CreateBounded>(new BoundedChannelOptions(maxCapacity) - { - Capacity = maxCapacity, - FullMode = BoundedChannelFullMode.DropOldest, - SingleReader = true, - SingleWriter = false, - AllowSynchronousContinuations = true - }) - }; - } - - public async Task RunAsync(CancellationToken cancel = default) - { - while (true) - { - var func = await _channel.Reader.ReadAsync(cancel); - - try - { - await func(); - } - catch (Exception ex) - { - Log.Warning(ex, "Exception executing a staggered func: {ErrorMessage}", ex.Message); - } - finally - { - if (_delayMs != 0) - { - await Task.Delay(_delayMs, cancel); - } - } - } - } - - public ValueTask EnqueueAsync(Func action) - => _channel.Writer.WriteAsync(action); -} diff --git a/src/Ellie.Common/ShmartBankAmount.cs b/src/Ellie.Common/ShmartBankAmount.cs deleted file mode 100644 index 0a6a7d9..0000000 --- a/src/Ellie.Common/ShmartBankAmount.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ellie.Common; - -public readonly struct ShmartBankAmount -{ - public long Amount { get; } - public ShmartBankAmount(long amount) - { - Amount = amount; - } - - public static implicit operator ShmartBankAmount(long num) - => new(num); - - public static implicit operator long(ShmartBankAmount num) - => num.Amount; - - public static implicit operator ShmartBankAmount(int num) - => new(num); -} diff --git a/src/Ellie.Common/ShmartNumber.cs b/src/Ellie.Common/ShmartNumber.cs deleted file mode 100644 index be722a0..0000000 --- a/src/Ellie.Common/ShmartNumber.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Ellie.Common; - -public readonly struct ShmartNumber : IEquatable -{ - public long Value { get; } - - public ShmartNumber(long val) - { - Value = val; - } - - public static implicit operator ShmartNumber(long num) - => new(num); - - public static implicit operator long(ShmartNumber num) - => num.Value; - - public static implicit operator ShmartNumber(int num) - => new(num); - - public override string ToString() - => Value.ToString(); - - public override bool Equals(object? obj) - => obj is ShmartNumber sn && Equals(sn); - - public bool Equals(ShmartNumber other) - => other.Value == Value; - - public override int GetHashCode() - => Value.GetHashCode(); - - public static bool operator ==(ShmartNumber left, ShmartNumber right) - => left.Equals(right); - - public static bool operator !=(ShmartNumber left, ShmartNumber right) - => !(left == right); -} From 9adb5a99063c0229d6ba5554cae42d635b66b94e Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 19:29:23 +1200 Subject: [PATCH 24/62] Removed Ellie.Econ --- src/Ellie.Econ/Deck/Deck.cs | 309 ------------------ src/Ellie.Econ/Deck/NewCard.cs | 5 - src/Ellie.Econ/Deck/NewDeck.cs | 54 --- .../MultipleRegularDeck.cs | 28 -- src/Ellie.Econ/Deck/Regular/RegularCard.cs | 4 - src/Ellie.Econ/Deck/Regular/RegularDeck.cs | 15 - .../Deck/Regular/RegularDeckExtensions.cs | 56 ---- src/Ellie.Econ/Deck/Regular/RegularSuit.cs | 9 - src/Ellie.Econ/Deck/Regular/RegularValue.cs | 18 - src/Ellie.Econ/Ellie.Econ.csproj | 13 - .../Gambling/Betdraw/BetdrawColorGuess.cs | 7 - .../Gambling/Betdraw/BetdrawGame.cs | 86 ----- .../Gambling/Betdraw/BetdrawResult.cs | 9 - .../Gambling/Betdraw/BetdrawResultType.cs | 7 - .../Gambling/Betdraw/BetdrawValueGuess.cs | 7 - .../Gambling/Betflip/BetflipGame.cs | 33 -- .../Gambling/Betflip/BetflipResult.cs | 8 - .../Gambling/Betroll/BetrollGame.cs | 42 --- .../Gambling/Betroll/BetrollResult.cs | 9 - src/Ellie.Econ/Gambling/Rps/RpsGame.cs | 75 ----- src/Ellie.Econ/Gambling/Slot/SlotGame.cs | 116 ------- src/Ellie.Econ/Gambling/Slot/SlotResult.cs | 9 - src/Ellie.Econ/Gambling/Wof/LuLaResult.cs | 9 - src/Ellie.Econ/Gambling/Wof/WofGame.cs | 34 -- src/Ellie.Econ/GlobalUsings.cs | 1 - 25 files changed, 963 deletions(-) delete mode 100644 src/Ellie.Econ/Deck/Deck.cs delete mode 100644 src/Ellie.Econ/Deck/NewCard.cs delete mode 100644 src/Ellie.Econ/Deck/NewDeck.cs delete mode 100644 src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs delete mode 100644 src/Ellie.Econ/Deck/Regular/RegularCard.cs delete mode 100644 src/Ellie.Econ/Deck/Regular/RegularDeck.cs delete mode 100644 src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs delete mode 100644 src/Ellie.Econ/Deck/Regular/RegularSuit.cs delete mode 100644 src/Ellie.Econ/Deck/Regular/RegularValue.cs delete mode 100644 src/Ellie.Econ/Ellie.Econ.csproj delete mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs delete mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs delete mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs delete mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs delete mode 100644 src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs delete mode 100644 src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs delete mode 100644 src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs delete mode 100644 src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs delete mode 100644 src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs delete mode 100644 src/Ellie.Econ/Gambling/Rps/RpsGame.cs delete mode 100644 src/Ellie.Econ/Gambling/Slot/SlotGame.cs delete mode 100644 src/Ellie.Econ/Gambling/Slot/SlotResult.cs delete mode 100644 src/Ellie.Econ/Gambling/Wof/LuLaResult.cs delete mode 100644 src/Ellie.Econ/Gambling/Wof/WofGame.cs delete mode 100644 src/Ellie.Econ/GlobalUsings.cs diff --git a/src/Ellie.Econ/Deck/Deck.cs b/src/Ellie.Econ/Deck/Deck.cs deleted file mode 100644 index 78f5dd0..0000000 --- a/src/Ellie.Econ/Deck/Deck.cs +++ /dev/null @@ -1,309 +0,0 @@ -#nullable disable -namespace Ellie.Econ; - -public class Deck -{ - public enum CardSuit - { - Spades = 1, - Hearts = 2, - Diamonds = 3, - Clubs = 4 - } - - private static readonly Dictionary _cardNames = new() - { - { 1, "Ace" }, - { 2, "Two" }, - { 3, "Three" }, - { 4, "Four" }, - { 5, "Five" }, - { 6, "Six" }, - { 7, "Seven" }, - { 8, "Eight" }, - { 9, "Nine" }, - { 10, "Ten" }, - { 11, "Jack" }, - { 12, "Queen" }, - { 13, "King" } - }; - - private static Dictionary, bool>> handValues; - - public List CardPool { get; set; } - private readonly Random _r = new EllieRandom(); - - static Deck() - => InitHandValues(); - - /// - /// Creates a new instance of the BlackJackGame, this allows you to create multiple games running at one time. - /// - public Deck() - => RefillPool(); - - /// - /// Restart the game of blackjack. It will only refill the pool for now. Probably wont be used, unless you want to have - /// only 1 bjg running at one time, - /// then you will restart the same game every time. - /// - public void Restart() - => RefillPool(); - - /// - /// Removes all cards from the pool and refills the pool with all of the possible cards. NOTE: I think this is too - /// expensive. - /// We should probably make it so it copies another premade list with all the cards, or something. - /// - protected virtual void RefillPool() - { - CardPool = new(52); - //foreach suit - for (var j = 1; j < 14; j++) - // and number - for (var i = 1; i < 5; i++) - //generate a card of that suit and number and add it to the pool - - // the pool will go from ace of spades,hears,diamonds,clubs all the way to the king of spades. hearts, ... - CardPool.Add(new((CardSuit)i, j)); - } - - /// - /// Take a card from the pool, you either take it from the top if the deck is shuffled, or from a random place if the - /// deck is in the default order. - /// - /// A card from the pool - public Card Draw() - { - if (CardPool.Count == 0) - Restart(); - //you can either do this if your deck is not shuffled - - var num = _r.Next(0, CardPool.Count); - var c = CardPool[num]; - CardPool.RemoveAt(num); - return c; - - // if you want to shuffle when you fill, then take the first one - /* - Card c = cardPool[0]; - cardPool.RemoveAt(0); - return c; - */ - } - - /// - /// Shuffles the deck. Use this if you want to take cards from the top of the deck, instead of randomly. See DrawACard - /// method. - /// - private void Shuffle() - { - if (CardPool.Count <= 1) - return; - var orderedPool = CardPool.Shuffle(); - CardPool ??= orderedPool.ToList(); - } - - public override string ToString() - => string.Concat(CardPool.Select(c => c.ToString())) + Environment.NewLine; - - private static void InitHandValues() - { - bool HasPair(List cards) - { - return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 1; - } - - bool IsPair(List cards) - { - return cards.GroupBy(card => card.Number).Count(group => group.Count() == 3) == 0 && HasPair(cards); - } - - bool IsTwoPair(List cards) - { - return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 2; - } - - bool IsStraight(List cards) - { - if (cards.GroupBy(card => card.Number).Count() != cards.Count()) - return false; - var toReturn = cards.Max(card => card.Number) - cards.Min(card => card.Number) == 4; - if (toReturn || cards.All(c => c.Number != 1)) - return toReturn; - - var newCards = cards.Select(c => c.Number == 1 ? new(c.Suit, 14) : c).ToArray(); - return newCards.Max(card => card.Number) - newCards.Min(card => card.Number) == 4; - } - - bool HasThreeOfKind(List cards) - { - return cards.GroupBy(card => card.Number).Any(group => group.Count() == 3); - } - - bool IsThreeOfKind(List cards) - { - return HasThreeOfKind(cards) && !HasPair(cards); - } - - bool IsFlush(List cards) - { - return cards.GroupBy(card => card.Suit).Count() == 1; - } - - bool IsFourOfKind(List cards) - { - return cards.GroupBy(card => card.Number).Any(group => group.Count() == 4); - } - - bool IsFullHouse(List cards) - { - return HasPair(cards) && HasThreeOfKind(cards); - } - - bool HasStraightFlush(List cards) - { - return IsFlush(cards) && IsStraight(cards); - } - - bool IsRoyalFlush(List cards) - { - return cards.Min(card => card.Number) == 1 - && cards.Max(card => card.Number) == 13 - && HasStraightFlush(cards); - } - - bool IsStraightFlush(List cards) - { - return HasStraightFlush(cards) && !IsRoyalFlush(cards); - } - - handValues = new() - { - { "Royal Flush", IsRoyalFlush }, - { "Straight Flush", IsStraightFlush }, - { "Four Of A Kind", IsFourOfKind }, - { "Full House", IsFullHouse }, - { "Flush", IsFlush }, - { "Straight", IsStraight }, - { "Three Of A Kind", IsThreeOfKind }, - { "Two Pairs", IsTwoPair }, - { "A Pair", IsPair } - }; - } - - public static string GetHandValue(List cards) - { - if (handValues is null) - InitHandValues(); - - foreach (var kvp in handValues.Where(x => x.Value(cards))) - return kvp.Key; - return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetValueText() ?? cards.Max().GetValueText()); - } - - public class Card : IComparable - { - private static readonly IReadOnlyDictionary _suitToSuitChar = new Dictionary - { - { CardSuit.Diamonds, "♦" }, - { CardSuit.Clubs, "♣" }, - { CardSuit.Spades, "♠" }, - { CardSuit.Hearts, "♥" } - }; - - private static readonly IReadOnlyDictionary _suitCharToSuit = new Dictionary - { - { "♦", CardSuit.Diamonds }, - { "d", CardSuit.Diamonds }, - { "♣", CardSuit.Clubs }, - { "c", CardSuit.Clubs }, - { "♠", CardSuit.Spades }, - { "s", CardSuit.Spades }, - { "♥", CardSuit.Hearts }, - { "h", CardSuit.Hearts } - }; - - private static readonly IReadOnlyDictionary _numberCharToNumber = new Dictionary - { - { 'a', 1 }, - { '2', 2 }, - { '3', 3 }, - { '4', 4 }, - { '5', 5 }, - { '6', 6 }, - { '7', 7 }, - { '8', 8 }, - { '9', 9 }, - { 't', 10 }, - { 'j', 11 }, - { 'q', 12 }, - { 'k', 13 } - }; - - public CardSuit Suit { get; } - public int Number { get; } - - public string FullName - { - get - { - var str = string.Empty; - - if (Number is <= 10 and > 1) - str += "_" + Number; - else - str += GetValueText().ToLowerInvariant(); - return str + "_of_" + Suit.ToString().ToLowerInvariant(); - } - } - - private readonly string[] _regIndicators = - { - "🇦", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":keycap_ten:", - "🇯", "🇶", "🇰" - }; - - public Card(CardSuit s, int cardNum) - { - Suit = s; - Number = cardNum; - } - - public string GetValueText() - => _cardNames[Number]; - - public override string ToString() - => _cardNames[Number] + " Of " + Suit; - - public int CompareTo(object obj) - { - if (obj is not Card card) - return 0; - return Number - card.Number; - } - - public static Card Parse(string input) - { - if (string.IsNullOrWhiteSpace(input)) - throw new ArgumentNullException(nameof(input)); - - if (input.Length != 2 - || !_numberCharToNumber.TryGetValue(input[0], out var n) - || !_suitCharToSuit.TryGetValue(input[1].ToString(), out var s)) - throw new ArgumentException("Invalid input", nameof(input)); - - return new(s, n); - } - - public string GetEmojiString() - { - var str = string.Empty; - - str += _regIndicators[Number - 1]; - str += _suitToSuitChar[Suit]; - - return str; - } - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/NewCard.cs b/src/Ellie.Econ/Deck/NewCard.cs deleted file mode 100644 index 4a091a4..0000000 --- a/src/Ellie.Econ/Deck/NewCard.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Ellie.Econ; - -public abstract record class NewCard(TSuit Suit, TValue Value) - where TSuit : struct, Enum - where TValue : struct, Enum; \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/NewDeck.cs b/src/Ellie.Econ/Deck/NewDeck.cs deleted file mode 100644 index a71406c..0000000 --- a/src/Ellie.Econ/Deck/NewDeck.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace Ellie.Econ; - -public abstract class NewDeck - where TCard: NewCard - where TSuit : struct, Enum - where TValue : struct, Enum -{ - protected static readonly TSuit[] _suits = Enum.GetValues(); - protected static readonly TValue[] _values = Enum.GetValues(); - - public virtual int CurrentCount - => _cards.Count; - - public virtual int TotalCount { get; } - - protected readonly LinkedList _cards = new(); - public NewDeck() - { - TotalCount = _suits.Length * _values.Length; - } - - public virtual TCard? Draw() - { - var first = _cards.First; - if (first is not null) - { - _cards.RemoveFirst(); - return first.Value; - } - - return null; - } - - public virtual TCard? Peek(int x = 0) - { - var card = _cards.First; - for (var i = 0; i < x; i++) - { - card = card?.Next; - } - - return card?.Value; - } - - public virtual void Shuffle() - { - var cards = _cards.ToList(); - var newCards = cards.Shuffle(); - - _cards.Clear(); - foreach (var card in newCards) - _cards.AddFirst(card); - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs b/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs deleted file mode 100644 index 2a7e7df..0000000 --- a/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Ellie.Econ; - -public class MultipleRegularDeck : NewDeck -{ - private int Decks { get; } - - public override int TotalCount { get; } - - public MultipleRegularDeck(int decks = 1) - { - if (decks < 1) - throw new ArgumentOutOfRangeException(nameof(decks), "Has to be more than 0"); - - Decks = decks; - TotalCount = base.TotalCount * decks; - - for (var i = 0; i < Decks; i++) - { - foreach (var suit in _suits) - { - foreach (var val in _values) - { - _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); - } - } - } - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularCard.cs b/src/Ellie.Econ/Deck/Regular/RegularCard.cs deleted file mode 100644 index 337a1ff..0000000 --- a/src/Ellie.Econ/Deck/Regular/RegularCard.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ellie.Econ; - -public sealed record class RegularCard(RegularSuit Suit, RegularValue Value) - : NewCard(Suit, Value); \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularDeck.cs b/src/Ellie.Econ/Deck/Regular/RegularDeck.cs deleted file mode 100644 index 6997623..0000000 --- a/src/Ellie.Econ/Deck/Regular/RegularDeck.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Ellie.Econ; - -public sealed class RegularDeck : NewDeck -{ - public RegularDeck() - { - foreach (var suit in _suits) - { - foreach (var val in _values) - { - _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); - } - } - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs b/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs deleted file mode 100644 index 98c880c..0000000 --- a/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace Ellie.Econ; - -public static class RegularDeckExtensions -{ - public static string GetEmoji(this RegularSuit suit) - => suit switch - { - RegularSuit.Hearts => "♥️", - RegularSuit.Spades => "♠️", - RegularSuit.Diamonds => "♦️", - _ => "♣️", - }; - - public static string GetEmoji(this RegularValue value) - => value switch - { - RegularValue.Ace => "🇦", - RegularValue.Two => "2️⃣", - RegularValue.Three => "3️⃣", - RegularValue.Four => "4️⃣", - RegularValue.Five => "5️⃣", - RegularValue.Six => "6️⃣", - RegularValue.Seven => "7️⃣", - RegularValue.Eight => "8️⃣", - RegularValue.Nine => "9️⃣", - RegularValue.Ten => "🔟", - RegularValue.Jack => "🇯", - RegularValue.Queen => "🇶", - _ => "🇰", - }; - - public static string GetEmoji(this RegularCard card) - => $"{card.Value.GetEmoji()} {card.Suit.GetEmoji()}"; - - public static string GetName(this RegularValue value) - => value.ToString(); - - public static string GetName(this RegularSuit suit) - => suit.ToString(); - - public static string GetName(this RegularCard card) - => $"{card.Value.ToString()} of {card.Suit.GetName()}"; -} - - - - - - - - - - - - - diff --git a/src/Ellie.Econ/Deck/Regular/RegularSuit.cs b/src/Ellie.Econ/Deck/Regular/RegularSuit.cs deleted file mode 100644 index dc4167b..0000000 --- a/src/Ellie.Econ/Deck/Regular/RegularSuit.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ellie.Econ; - -public enum RegularSuit -{ - Hearts, - Diamonds, - Clubs, - Spades -} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularValue.cs b/src/Ellie.Econ/Deck/Regular/RegularValue.cs deleted file mode 100644 index 8aa9171..0000000 --- a/src/Ellie.Econ/Deck/Regular/RegularValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ellie.Econ; - -public enum RegularValue -{ - Ace = 1, - Two = 2, - Three = 3, - Four = 4, - Five = 5, - Six = 6, - Seven = 7, - Eight = 8, - Nine = 9, - Ten = 10, - Jack = 12, - Queen = 13, - King = 14, -} \ No newline at end of file diff --git a/src/Ellie.Econ/Ellie.Econ.csproj b/src/Ellie.Econ/Ellie.Econ.csproj deleted file mode 100644 index 038763e..0000000 --- a/src/Ellie.Econ/Ellie.Econ.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net6.0 - enable - enable - - - - - - - diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs deleted file mode 100644 index 7ecd3bd..0000000 --- a/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ellie.Econ.Gambling.Betdraw; - -public enum BetdrawColorGuess -{ - Red, - Black -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs deleted file mode 100644 index d52ae43..0000000 --- a/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Serilog; - -namespace Ellie.Econ.Gambling.Betdraw; - -public sealed class BetdrawGame -{ - private static readonly EllieRandom _rng = new(); - private readonly RegularDeck _deck; - - private const decimal SINGLE_GUESS_MULTI = 2.075M; - private const decimal DOUBLE_GUESS_MULTI = 4.15M; - - public BetdrawGame() - { - _deck = new RegularDeck(); - } - - public BetdrawResult Draw(BetdrawValueGuess? val, BetdrawColorGuess? col, decimal amount) - { - if (val is null && col is null) - throw new ArgumentNullException(nameof(val)); - - var card = _deck.Peek(_rng.Next(0, 52))!; - - var realVal = (int)card.Value < 7 - ? BetdrawValueGuess.Low - : BetdrawValueGuess.High; - - var realCol = card.Suit is RegularSuit.Diamonds or RegularSuit.Hearts - ? BetdrawColorGuess.Red - : BetdrawColorGuess.Black; - - // if card is 7, autoloss - if (card.Value == RegularValue.Seven) - { - return new() - { - Won = 0M, - Multiplier = 0M, - ResultType = BetdrawResultType.Lose, - Card = card, - }; - } - - byte win = 0; - if (val is BetdrawValueGuess valGuess) - { - if (realVal != valGuess) - return new() - { - Won = 0M, - Multiplier = 0M, - ResultType = BetdrawResultType.Lose, - Card = card - }; - - ++win; - } - - if (col is BetdrawColorGuess colGuess) - { - if (realCol != colGuess) - return new() - { - Won = 0M, - Multiplier = 0M, - ResultType = BetdrawResultType.Lose, - Card = card - }; - - ++win; - } - - var multi = win == 1 - ? SINGLE_GUESS_MULTI - : DOUBLE_GUESS_MULTI; - - return new() - { - Won = amount * multi, - Multiplier = multi, - ResultType = BetdrawResultType.Win, - Card = card - }; - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs deleted file mode 100644 index 82661ac..0000000 --- a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ellie.Econ.Gambling.Betdraw; - -public readonly struct BetdrawResult -{ - public decimal Won { get; init; } - public decimal Multiplier { get; init; } - public BetdrawResultType ResultType { get; init; } - public RegularCard Card { get; init; } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs deleted file mode 100644 index 371b8fa..0000000 --- a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ellie.Econ.Gambling.Betdraw; - -public enum BetdrawResultType -{ - Win, - Lose -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs deleted file mode 100644 index caf2a14..0000000 --- a/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ellie.Econ.Gambling.Betdraw; - -public enum BetdrawValueGuess -{ - High, - Low, -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs b/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs deleted file mode 100644 index d6d26aa..0000000 --- a/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public sealed class BetflipGame -{ - private readonly decimal _winMulti; - private static readonly EllieRandom _rng = new EllieRandom(); - - public BetflipGame(decimal winMulti) - { - _winMulti = winMulti; - } - - public BetflipResult Flip(byte guess, decimal amount) - { - var side = (byte)_rng.Next(0, 2); - if (side == guess) - { - return new BetflipResult() - { - Side = side, - Won = amount * _winMulti, - Multiplier = _winMulti - }; - } - - return new BetflipResult() - { - Side = side, - Won = 0, - Multiplier = 0, - }; - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs b/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs deleted file mode 100644 index 8763f50..0000000 --- a/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public readonly struct BetflipResult -{ - public decimal Won { get; init; } - public byte Side { get; init; } - public decimal Multiplier { get; init; } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs b/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs deleted file mode 100644 index 5938957..0000000 --- a/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public sealed class BetrollGame -{ - private readonly (int WhenAbove, decimal MultiplyBy)[] _thresholdPairs; - private readonly EllieRandom _rng; - - public BetrollGame(IReadOnlyList<(int WhenAbove, decimal MultiplyBy)> pairs) - { - _thresholdPairs = pairs.OrderByDescending(x => x.WhenAbove).ToArray(); - _rng = new(); - } - - public BetrollResult Roll(decimal amount = 0) - { - var roll = _rng.Next(1, 101); - - for (var i = 0; i < _thresholdPairs.Length; i++) - { - ref var pair = ref _thresholdPairs[i]; - - if (pair.WhenAbove < roll) - { - return new() - { - Multiplier = pair.MultiplyBy, - Roll = roll, - Threshold = pair.WhenAbove, - Won = amount * pair.MultiplyBy - }; - } - } - - return new() - { - Multiplier = 0, - Roll = roll, - Threshold = -1, - Won = 0, - }; - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs b/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs deleted file mode 100644 index ddafa5c..0000000 --- a/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public readonly struct BetrollResult -{ - public int Roll { get; init; } - public decimal Multiplier { get; init; } - public decimal Threshold { get; init; } - public decimal Won { get; init; } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Rps/RpsGame.cs b/src/Ellie.Econ/Gambling/Rps/RpsGame.cs deleted file mode 100644 index 8d3c623..0000000 --- a/src/Ellie.Econ/Gambling/Rps/RpsGame.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace Ellie.Econ.Gambling.Rps; - -public sealed class RpsGame -{ - private static readonly EllieRandom _rng = new EllieRandom(); - - const decimal WIN_MULTI = 1.95m; - const decimal DRAW_MULTI = 1m; - const decimal LOSE_MULTI = 0m; - - public RpsGame() - { - - } - - public RpsResult Play(RpsPick pick, decimal amount) - { - var compPick = (RpsPick)_rng.Next(0, 3); - if (compPick == pick) - { - return new() - { - Won = amount * DRAW_MULTI, - Multiplier = DRAW_MULTI, - ComputerPick = compPick, - Result = RpsResultType.Draw, - }; - } - - if ((compPick == RpsPick.Paper && pick == RpsPick.Rock) - || (compPick == RpsPick.Rock && pick == RpsPick.Scissors) - || (compPick == RpsPick.Scissors && pick == RpsPick.Paper)) - { - return new() - { - Won = amount * LOSE_MULTI, - Multiplier = LOSE_MULTI, - Result = RpsResultType.Lose, - ComputerPick = compPick, - }; - } - - return new() - { - Won = amount * WIN_MULTI, - Multiplier = WIN_MULTI, - Result = RpsResultType.Win, - ComputerPick = compPick, - }; - } -} - -public enum RpsPick : byte -{ - Rock = 0, - Paper = 1, - Scissors = 2, -} - -public enum RpsResultType : byte -{ - Win, - Draw, - Lose -} - - - -public readonly struct RpsResult -{ - public decimal Won { get; init; } - public decimal Multiplier { get; init; } - public RpsResultType Result { get; init; } - public RpsPick ComputerPick { get; init; } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Slot/SlotGame.cs b/src/Ellie.Econ/Gambling/Slot/SlotGame.cs deleted file mode 100644 index f6cddb9..0000000 --- a/src/Ellie.Econ/Gambling/Slot/SlotGame.cs +++ /dev/null @@ -1,116 +0,0 @@ -namespace Ellie.Econ.Gambling; - -//here is a payout chart -//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg -//thanks to judge for helping me with this -public class SlotGame -{ - private static readonly EllieRandom _rng = new EllieRandom(); - - public SlotResult Spin(decimal bet) - { - var rolls = new[] - { - (byte)_rng.Next(0, 6), - (byte)_rng.Next(0, 6), - (byte)_rng.Next(0, 6) - }; - - ref var a = ref rolls[0]; - ref var b = ref rolls[1]; - ref var c = ref rolls[2]; - - var multi = 0; - var winType = SlotWinType.None; - if (a == b && b == c) - { - if (a == 5) - { - winType = SlotWinType.TrippleJoker; - multi = 30; - } - else - { - winType = SlotWinType.TrippleNormal; - multi = 10; - } - } - else if (a == 5 && (b == 5 || c == 5) - || (b == 5 && c == 5)) - { - winType = SlotWinType.DoubleJoker; - multi = 4; - } - else if (a == 5 || b == 5 || c == 5) - { - winType = SlotWinType.SingleJoker; - multi = 1; - } - - return new() - { - Won = bet * multi, - WinType = winType, - Multiplier = multi, - Rolls = rolls, - }; - } -} - -public enum SlotWinType : byte -{ - None, - SingleJoker, - DoubleJoker, - TrippleNormal, - TrippleJoker, -} - -/* -var rolls = new[] - { - _rng.Next(default(byte), 6), - _rng.Next(default(byte), 6), - _rng.Next(default(byte), 6) - }; - - var multi = 0; - var winType = SlotWinType.None; - - ref var a = ref rolls[0]; - ref var b = ref rolls[1]; - ref var c = ref rolls[2]; - if (a == b && b == c) - { - if (a == 5) - { - winType = SlotWinType.TrippleJoker; - multi = 30; - } - else - { - winType = SlotWinType.TrippleNormal; - multi = 10; - } - } - else if (a == 5 && (b == 5 || c == 5) - || (b == 5 && c == 5)) - { - winType = SlotWinType.DoubleJoker; - multi = 4; - } - else if (rolls.Any(x => x == 5)) - { - winType = SlotWinType.SingleJoker; - multi = 1; - } - - return new() - { - Won = bet * multi, - WinType = winType, - Multiplier = multi, - Rolls = rolls, - }; - } -*/ \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Slot/SlotResult.cs b/src/Ellie.Econ/Gambling/Slot/SlotResult.cs deleted file mode 100644 index 42d3630..0000000 --- a/src/Ellie.Econ/Gambling/Slot/SlotResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public readonly struct SlotResult -{ - public decimal Multiplier { get; init; } - public byte[] Rolls { get; init; } - public decimal Won { get; init; } - public SlotWinType WinType { get; init; } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs b/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs deleted file mode 100644 index 0f98e1a..0000000 --- a/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public readonly struct LuLaResult -{ - public int Index { get; init; } - public decimal Multiplier { get; init; } - public decimal Won { get; init; } - public IReadOnlyList Multipliers { get; init; } -} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Wof/WofGame.cs b/src/Ellie.Econ/Gambling/Wof/WofGame.cs deleted file mode 100644 index d76a215..0000000 --- a/src/Ellie.Econ/Gambling/Wof/WofGame.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Ellie.Econ.Gambling; - -public sealed class LulaGame -{ - private static readonly IReadOnlyList DEFAULT_MULTIPLIERS = new[] { 1.7M, 1.5M, 0.2M, 0.1M, 0.3M, 0.5M, 1.2M, 2.4M }; - - private readonly IReadOnlyList _multipliers; - private static readonly EllieRandom _rng = new(); - - public LulaGame(IReadOnlyList multipliers) - { - _multipliers = multipliers; - } - - public LulaGame() : this(DEFAULT_MULTIPLIERS) - { - } - - public LuLaResult Spin(long bet) - { - var result = _rng.Next(0, _multipliers.Count); - - var multi = _multipliers[result]; - var amount = bet * multi; - - return new() - { - Index = result, - Multiplier = multi, - Won = amount, - Multipliers = _multipliers.ToArray(), - }; - } -} \ No newline at end of file diff --git a/src/Ellie.Econ/GlobalUsings.cs b/src/Ellie.Econ/GlobalUsings.cs deleted file mode 100644 index a197f0b..0000000 --- a/src/Ellie.Econ/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Ellie.Common; \ No newline at end of file From 957790a85b7d031186f2494776aef5f65b3e5068 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 19:30:05 +1200 Subject: [PATCH 25/62] Removed a bunch of things out of EllieBot --- src/EllieBot/Bot.cs | 404 ++++++++ src/EllieBot/Common/Attributes/Aliases.cs | 12 - .../Attributes/CommandNameLoadHelper.cs | 31 - .../DontAddToIocContainerAttribute.cs | 11 - .../Common/Attributes/EllieCommand.cs | 18 - .../Common/Attributes/EllieOptions.cs | 10 - .../Attributes/NoPublicBotPrecondition.cs | 38 - .../Common/Attributes/OwnerOnlyAttribute.cs | 19 - src/EllieBot/Common/Attributes/Ratelimit.cs | 38 - src/EllieBot/Common/Attributes/UserPerm.cs | 30 - .../Common/Cache/BotCacheExtensions.cs | 46 - src/EllieBot/Common/Cache/IBotCache.cs | 47 - src/EllieBot/Common/Cache/MemoryBotCache.cs | 71 -- src/EllieBot/Common/Cache/RedisBotCache.cs | 119 --- src/EllieBot/Common/Configs/BotConfig.cs | 185 ---- src/EllieBot/Common/Configs/IConfigSeria.cs | 18 - .../Common/Interaction/EllieInteraction.cs | 82 -- .../Interaction/EllieInteractionData.cs | 8 - .../Interaction/EllieInteractionService.cs | 20 - .../Interaction/IEllieInteractionService.cs | 8 - .../Common/Interaction/SimpleInteraction.cs | 20 - .../JsonConverters/CultureInfoConverter.cs | 14 - .../Common/JsonConverters/Rgba32Converter.cs | 14 - .../Marmalade/Adapters/BehaviorAdapter.cs | 76 -- .../Adapters/ContextAdapterFactory.cs | 7 - .../Marmalade/Adapters/DmContextAdapter.cs | 49 - .../Marmalade/Adapters/FilterAdapter.cs | 31 - .../Marmalade/Adapters/GuildContextAdapter.cs | 53 - .../Marmalade/Adapters/ParamParserAdapter.cs | 32 - .../Common/Marmalade/CommandContextType.cs | 27 - .../Config/IMarmaladeConfigService.cs | 8 - .../Marmalade/Config/MarmaladeConfig.cs | 20 - .../Config/MarmaladeConfigService.cs | 45 - .../Marmalade/IMarmaladeLoaderService.cs | 23 - .../Marmalade/MarmaladeAssemblyLoadContext.cs | 36 - .../Marmalade/MarmaladeLoaderService.cs | 917 ------------------ .../Marmalade/MarmaladeServiceProvider.cs | 24 - .../Marmalade/Models/CanaryCommandData.cs | 46 - .../Common/Marmalade/Models/CanaryData.cs | 11 - .../Common/Marmalade/Models/ParamData.cs | 10 - .../Marmalade/Models/ResolvedMarmalade.cs | 14 - .../Common/ModuleBehaviors/IExecNoCommand.cs | 19 - .../Common/ModuleBehaviors/IExecOnMessage.cs | 21 - .../ModuleBehaviors/IExecPostCommand.cs | 22 - .../Common/ModuleBehaviors/IExecPreCommand.cs | 25 - .../ModuleBehaviors/IInputTransformer.cs | 25 - .../Common/ModuleBehaviors/IReadyExecutor.cs | 13 - src/EllieBot/Common/PubSub/EventPubSub.cs | 80 -- src/EllieBot/Common/PubSub/IPubSub.cs | 10 - src/EllieBot/Common/PubSub/ISeria.cs | 7 - src/EllieBot/Common/PubSub/JsonSeria.cs | 27 - src/EllieBot/Common/PubSub/RedisPubSub.cs | 52 - src/EllieBot/Common/PubSub/TypedKey.cs | 30 - src/EllieBot/Common/PubSub/YamlSeria.cs | 39 - src/EllieBot/Common/Yml/CommentAttribute.cs | 11 - .../Yml/CommentGatheringTypeInspector.cs | 65 -- .../Common/Yml/CommentsObjectDescriptor.cs | 30 - .../Common/Yml/CommentsObjectGraphVisitor.cs | 29 - .../Yml/MultilineScalarFlowStyleEmitter.cs | 35 - src/EllieBot/Common/Yml/Rgba32Converter.cs | 47 - src/EllieBot/Common/Yml/UriConverter.cs | 25 - src/EllieBot/Common/Yml/Yaml.cs | 28 - src/EllieBot/Common/Yml/YamlHelper.cs | 48 - src/EllieBot/Db/EllieContext.cs | 491 ---------- src/EllieBot/Db/Extensions/ClubExtensions.cs | 34 - .../CurrencyTransactionExtensions.cs | 20 - src/EllieBot/Db/Extensions/DbExtensions.cs | 12 - .../Db/Extensions/DiscordUserExtensions.cs | 179 ---- .../Extensions/EllieExpressionExtensions.cs | 15 - .../Db/Extensions/GuildConfigExtensions.cs | 227 ----- .../MusicPlayerSettingsExtensions.cs | 27 - .../Db/Extensions/MusicPlaylistExtensions.cs | 19 - src/EllieBot/Db/Extensions/PollExtensions.cs | 34 - src/EllieBot/Db/Extensions/QuoteExtensions.cs | 57 -- .../Db/Extensions/ReminderExtensions.cs | 23 - .../SelfAssignableRolesExtensions.cs | 22 - .../Db/Extensions/UserXpExtensions.cs | 63 -- src/EllieBot/Db/Extensions/WaifuExtensions.cs | 145 --- .../Db/Extensions/WarningExtensions.cs | 60 -- src/EllieBot/Db/Models/AntiProtection.cs | 65 -- src/EllieBot/Db/Models/AutoCommand.cs | 14 - src/EllieBot/Db/Models/AutoPublishChannel.cs | 9 - .../Db/Models/AutoTranslateChannel.cs | 10 - src/EllieBot/Db/Models/AutoTranslateUser.cs | 11 - src/EllieBot/Db/Models/BanTemplate.cs | 9 - src/EllieBot/Db/Models/BankUser.cs | 9 - src/EllieBot/Db/Models/BlacklistEntry.cs | 15 - src/EllieBot/Db/Models/ClubInfo.cs | 42 - src/EllieBot/Db/Models/CommandAlias.cs | 8 - src/EllieBot/Db/Models/CommandCooldown.cs | 8 - src/EllieBot/Db/Models/CurrencyTransaction.cs | 12 - src/EllieBot/Db/Models/DbEntity.cs | 12 - src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs | 14 - src/EllieBot/Db/Models/DiscordPemOverride.cs | 10 - src/EllieBot/Db/Models/DiscordUser.cs | 31 - src/EllieBot/Db/Models/EllieExpression.cs | 27 - src/EllieBot/Db/Models/Event.cs | 49 - src/EllieBot/Db/Models/FeedSub.cs | 19 - src/EllieBot/Db/Models/FilterChannelId.cs | 30 - .../Db/Models/FilterLinksChannelId.cs | 13 - src/EllieBot/Db/Models/FilteredWord.cs | 7 - src/EllieBot/Db/Models/FollowedStream.cs | 37 - src/EllieBot/Db/Models/GCChannelId.cs | 14 - src/EllieBot/Db/Models/GamblingStats.cs | 9 - src/EllieBot/Db/Models/GroupName.cs | 11 - src/EllieBot/Db/Models/GuildConfig.cs | 108 --- src/EllieBot/Db/Models/IgnoredLogItem.cs | 16 - .../Db/Models/IgnoredVoicePresenceChannel.cs | 8 - src/EllieBot/Db/Models/ImageOnlyChannel.cs | 15 - src/EllieBot/Db/Models/LogSetting.cs | 37 - src/EllieBot/Db/Models/MusicPlaylist.cs | 10 - src/EllieBot/Db/Models/MusicSettings.cs | 61 -- src/EllieBot/Db/Models/MutedUserId.cs | 13 - src/EllieBot/Db/Models/NsfwBlacklistedTag.cs | 14 - src/EllieBot/Db/Models/PatronQuota.cs | 48 - src/EllieBot/Db/Models/Permission.cs | 55 -- src/EllieBot/Db/Models/PlantedCurrency.cs | 12 - src/EllieBot/Db/Models/PlaylistSong.cs | 19 - src/EllieBot/Db/Models/Poll.cs | 17 - src/EllieBot/Db/Models/PollVote.cs | 14 - src/EllieBot/Db/Models/Quote.cs | 26 - src/EllieBot/Db/Models/ReactionRole.cs | 18 - src/EllieBot/Db/Models/Reminder.cs | 12 - src/EllieBot/Db/Models/Repeater.cs | 15 - src/EllieBot/Db/Models/RewardedUser.cs | 10 - .../Db/Models/RotatingPlayingStatus.cs | 8 - src/EllieBot/Db/Models/SelfAssignableRole.cs | 11 - src/EllieBot/Db/Models/ShopEntry.cs | 43 - src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs | 20 - src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs | 20 - src/EllieBot/Db/Models/StreamOnlineMessage.cs | 13 - src/EllieBot/Db/Models/StreamRoleSettings.cs | 68 -- src/EllieBot/Db/Models/UnbanTimer.cs | 14 - src/EllieBot/Db/Models/UnmuteTimer.cs | 14 - src/EllieBot/Db/Models/UnroleTimer.cs | 15 - src/EllieBot/Db/Models/UserXpStats.cs | 13 - src/EllieBot/Db/Models/VcRoleInfo.cs | 8 - src/EllieBot/Db/Models/Waifu.cs | 75 -- src/EllieBot/Db/Models/WaifuItem.cs | 10 - src/EllieBot/Db/Models/WaifuUpdate.cs | 23 - src/EllieBot/Db/Models/WarnExpireAction.cs | 8 - src/EllieBot/Db/Models/Warning.cs | 13 - src/EllieBot/Db/Models/WarningPunishment.cs | 10 - src/EllieBot/Db/Models/XpSettings.cs | 62 -- src/EllieBot/Db/Models/XpShopOwnedItem.cs | 18 - src/EllieBot/Db/MysqlContext.cs | 38 - src/EllieBot/Db/PostgreSqlContext.cs | 26 - src/EllieBot/Db/SqliteContext.cs | 26 - src/EllieBot/EllieBot.csproj | 1 - src/EllieBot/GlobalUsings.cs | 31 + 150 files changed, 435 insertions(+), 5984 deletions(-) create mode 100644 src/EllieBot/Bot.cs delete mode 100644 src/EllieBot/Common/Attributes/Aliases.cs delete mode 100644 src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs delete mode 100644 src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs delete mode 100644 src/EllieBot/Common/Attributes/EllieCommand.cs delete mode 100644 src/EllieBot/Common/Attributes/EllieOptions.cs delete mode 100644 src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs delete mode 100644 src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs delete mode 100644 src/EllieBot/Common/Attributes/Ratelimit.cs delete mode 100644 src/EllieBot/Common/Attributes/UserPerm.cs delete mode 100644 src/EllieBot/Common/Cache/BotCacheExtensions.cs delete mode 100644 src/EllieBot/Common/Cache/IBotCache.cs delete mode 100644 src/EllieBot/Common/Cache/MemoryBotCache.cs delete mode 100644 src/EllieBot/Common/Cache/RedisBotCache.cs delete mode 100644 src/EllieBot/Common/Configs/BotConfig.cs delete mode 100644 src/EllieBot/Common/Configs/IConfigSeria.cs delete mode 100644 src/EllieBot/Common/Interaction/EllieInteraction.cs delete mode 100644 src/EllieBot/Common/Interaction/EllieInteractionData.cs delete mode 100644 src/EllieBot/Common/Interaction/EllieInteractionService.cs delete mode 100644 src/EllieBot/Common/Interaction/IEllieInteractionService.cs delete mode 100644 src/EllieBot/Common/Interaction/SimpleInteraction.cs delete mode 100644 src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs delete mode 100644 src/EllieBot/Common/JsonConverters/Rgba32Converter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/CommandContextType.cs delete mode 100644 src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs delete mode 100644 src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs delete mode 100644 src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs delete mode 100644 src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs delete mode 100644 src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs delete mode 100644 src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs delete mode 100644 src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/CanaryData.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/ParamData.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs delete mode 100644 src/EllieBot/Common/PubSub/EventPubSub.cs delete mode 100644 src/EllieBot/Common/PubSub/IPubSub.cs delete mode 100644 src/EllieBot/Common/PubSub/ISeria.cs delete mode 100644 src/EllieBot/Common/PubSub/JsonSeria.cs delete mode 100644 src/EllieBot/Common/PubSub/RedisPubSub.cs delete mode 100644 src/EllieBot/Common/PubSub/TypedKey.cs delete mode 100644 src/EllieBot/Common/PubSub/YamlSeria.cs delete mode 100644 src/EllieBot/Common/Yml/CommentAttribute.cs delete mode 100644 src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs delete mode 100644 src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs delete mode 100644 src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs delete mode 100644 src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs delete mode 100644 src/EllieBot/Common/Yml/Rgba32Converter.cs delete mode 100644 src/EllieBot/Common/Yml/UriConverter.cs delete mode 100644 src/EllieBot/Common/Yml/Yaml.cs delete mode 100644 src/EllieBot/Common/Yml/YamlHelper.cs delete mode 100644 src/EllieBot/Db/EllieContext.cs delete mode 100644 src/EllieBot/Db/Extensions/ClubExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/DbExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/DiscordUserExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/GuildConfigExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/PollExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/QuoteExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/ReminderExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/UserXpExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/WaifuExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/WarningExtensions.cs delete mode 100644 src/EllieBot/Db/Models/AntiProtection.cs delete mode 100644 src/EllieBot/Db/Models/AutoCommand.cs delete mode 100644 src/EllieBot/Db/Models/AutoPublishChannel.cs delete mode 100644 src/EllieBot/Db/Models/AutoTranslateChannel.cs delete mode 100644 src/EllieBot/Db/Models/AutoTranslateUser.cs delete mode 100644 src/EllieBot/Db/Models/BanTemplate.cs delete mode 100644 src/EllieBot/Db/Models/BankUser.cs delete mode 100644 src/EllieBot/Db/Models/BlacklistEntry.cs delete mode 100644 src/EllieBot/Db/Models/ClubInfo.cs delete mode 100644 src/EllieBot/Db/Models/CommandAlias.cs delete mode 100644 src/EllieBot/Db/Models/CommandCooldown.cs delete mode 100644 src/EllieBot/Db/Models/CurrencyTransaction.cs delete mode 100644 src/EllieBot/Db/Models/DbEntity.cs delete mode 100644 src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs delete mode 100644 src/EllieBot/Db/Models/DiscordPemOverride.cs delete mode 100644 src/EllieBot/Db/Models/DiscordUser.cs delete mode 100644 src/EllieBot/Db/Models/EllieExpression.cs delete mode 100644 src/EllieBot/Db/Models/Event.cs delete mode 100644 src/EllieBot/Db/Models/FeedSub.cs delete mode 100644 src/EllieBot/Db/Models/FilterChannelId.cs delete mode 100644 src/EllieBot/Db/Models/FilterLinksChannelId.cs delete mode 100644 src/EllieBot/Db/Models/FilteredWord.cs delete mode 100644 src/EllieBot/Db/Models/FollowedStream.cs delete mode 100644 src/EllieBot/Db/Models/GCChannelId.cs delete mode 100644 src/EllieBot/Db/Models/GamblingStats.cs delete mode 100644 src/EllieBot/Db/Models/GroupName.cs delete mode 100644 src/EllieBot/Db/Models/GuildConfig.cs delete mode 100644 src/EllieBot/Db/Models/IgnoredLogItem.cs delete mode 100644 src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs delete mode 100644 src/EllieBot/Db/Models/ImageOnlyChannel.cs delete mode 100644 src/EllieBot/Db/Models/LogSetting.cs delete mode 100644 src/EllieBot/Db/Models/MusicPlaylist.cs delete mode 100644 src/EllieBot/Db/Models/MusicSettings.cs delete mode 100644 src/EllieBot/Db/Models/MutedUserId.cs delete mode 100644 src/EllieBot/Db/Models/NsfwBlacklistedTag.cs delete mode 100644 src/EllieBot/Db/Models/PatronQuota.cs delete mode 100644 src/EllieBot/Db/Models/Permission.cs delete mode 100644 src/EllieBot/Db/Models/PlantedCurrency.cs delete mode 100644 src/EllieBot/Db/Models/PlaylistSong.cs delete mode 100644 src/EllieBot/Db/Models/Poll.cs delete mode 100644 src/EllieBot/Db/Models/PollVote.cs delete mode 100644 src/EllieBot/Db/Models/Quote.cs delete mode 100644 src/EllieBot/Db/Models/ReactionRole.cs delete mode 100644 src/EllieBot/Db/Models/Reminder.cs delete mode 100644 src/EllieBot/Db/Models/Repeater.cs delete mode 100644 src/EllieBot/Db/Models/RewardedUser.cs delete mode 100644 src/EllieBot/Db/Models/RotatingPlayingStatus.cs delete mode 100644 src/EllieBot/Db/Models/SelfAssignableRole.cs delete mode 100644 src/EllieBot/Db/Models/ShopEntry.cs delete mode 100644 src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs delete mode 100644 src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs delete mode 100644 src/EllieBot/Db/Models/StreamOnlineMessage.cs delete mode 100644 src/EllieBot/Db/Models/StreamRoleSettings.cs delete mode 100644 src/EllieBot/Db/Models/UnbanTimer.cs delete mode 100644 src/EllieBot/Db/Models/UnmuteTimer.cs delete mode 100644 src/EllieBot/Db/Models/UnroleTimer.cs delete mode 100644 src/EllieBot/Db/Models/UserXpStats.cs delete mode 100644 src/EllieBot/Db/Models/VcRoleInfo.cs delete mode 100644 src/EllieBot/Db/Models/Waifu.cs delete mode 100644 src/EllieBot/Db/Models/WaifuItem.cs delete mode 100644 src/EllieBot/Db/Models/WaifuUpdate.cs delete mode 100644 src/EllieBot/Db/Models/WarnExpireAction.cs delete mode 100644 src/EllieBot/Db/Models/Warning.cs delete mode 100644 src/EllieBot/Db/Models/WarningPunishment.cs delete mode 100644 src/EllieBot/Db/Models/XpSettings.cs delete mode 100644 src/EllieBot/Db/Models/XpShopOwnedItem.cs delete mode 100644 src/EllieBot/Db/MysqlContext.cs delete mode 100644 src/EllieBot/Db/PostgreSqlContext.cs delete mode 100644 src/EllieBot/Db/SqliteContext.cs create mode 100644 src/EllieBot/GlobalUsings.cs diff --git a/src/EllieBot/Bot.cs b/src/EllieBot/Bot.cs new file mode 100644 index 0000000..d6ab91a --- /dev/null +++ b/src/EllieBot/Bot.cs @@ -0,0 +1,404 @@ +#nullable disable +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Common.Configs; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Modules.Utility; +using EllieBot.Services.Database.Models; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Net; +using System.Reflection; +using RunMode = Discord.Commands.RunMode; + +namespace EllieBot; + +public sealed class Bot +{ + public event Func JoinedGuild = delegate { return Task.CompletedTask; }; + + public DiscordSocketClient Client { get; } + public ImmutableArray AllGuildConfigs { get; private set; } + + private IServiceProvider Services { get; set; } + + public string Mention { get; private set; } + public bool IsReady { get; private set; } + public int ShardId { get; set; } + + private readonly IBotCredentials _creds; + private readonly CommandService _commandService; + private readonly DbService _db; + + private readonly IBotCredsProvider _credsProvider; + // private readonly InteractionService _interactionService; + + public Bot(int shardId, int? totalShards, string credPath = null) + { + if (shardId < 0) + throw new ArgumentOutOfRangeException(nameof(shardId)); + + ShardId = shardId; + _credsProvider = new BotCredsProvider(totalShards, credPath); + _creds = _credsProvider.GetCreds(); + + _db = new(_credsProvider); + + var messageCacheSize = +#if GLOBAL_ELLIE + 0; +#else + 50; +#endif + + if(!_creds.UsePrivilegedIntents) + Log.Warning("You are not using privileged intents. Some features will not work properly"); + + Client = new(new() + { + MessageCacheSize = messageCacheSize, + LogLevel = LogSeverity.Warning, + ConnectionTimeout = int.MaxValue, + TotalShards = _creds.TotalShards, + ShardId = shardId, + AlwaysDownloadUsers = false, + AlwaysResolveStickers = false, + AlwaysDownloadDefaultStickers = false, + GatewayIntents = _creds.UsePrivilegedIntents + ? GatewayIntents.All + : GatewayIntents.AllUnprivileged, + LogGatewayIntentWarnings = false, + FormatUsersInBidirectionalUnicode = false, + DefaultRetryMode = RetryMode.Retry502 + }); + + _commandService = new(new() + { + CaseSensitiveCommands = false, + DefaultRunMode = RunMode.Sync, + }); + + // _interactionService = new(Client.Rest); + + Client.Log += Client_Log; + } + + + public List GetCurrentGuildIds() + => Client.Guilds.Select(x => x.Id).ToList(); + + private void AddServices() + { + var startingGuildIdList = GetCurrentGuildIds(); + var sw = Stopwatch.StartNew(); + var bot = Client.CurrentUser; + + using (var uow = _db.GetDbContext()) + { + uow.EnsureUserCreated(bot.Id, bot.Username, bot.Discriminator, bot.AvatarId); + AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); + } + + var svcs = new ServiceCollection().AddTransient(_ => _credsProvider.GetCreds()) // bot creds + .AddSingleton(_credsProvider) + .AddSingleton(_db) // database + .AddSingleton(Client) // discord socket client + .AddSingleton(_commandService) + // .AddSingleton(_interactionService) + .AddSingleton(this) + .AddSingleton() + .AddSingleton() + .AddConfigServices() + .AddConfigMigrators() + .AddMemoryCache() + // music + .AddMusic() + // cache + .AddCache(_creds); + + + svcs.AddHttpClient(); + svcs.AddHttpClient("memelist") + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler + { + AllowAutoRedirect = false + }); + + svcs.AddHttpClient("google:search") + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() + { + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }); + + if (Environment.GetEnvironmentVariable("ELLIE_IS_COORDINATED") != "1") + svcs.AddSingleton(); + else + { + svcs.AddSingleton() + .AddSingleton(x => x.GetRequiredService()) + .AddSingleton(x => x.GetRequiredService()); + } + + svcs.Scan(scan => scan.FromAssemblyOf() + .AddClasses(classes => classes.AssignableToAny( + // services + typeof(IEService), + + // behaviours + typeof(IExecOnMessage), + typeof(IInputTransformer), + typeof(IExecPreCommand), + typeof(IExecPostCommand), + typeof(IExecNoCommand)) + .WithoutAttribute() +#if GLOBAL_ELLIE + .WithoutAttribute() +#endif + ) + .AsSelfWithInterfaces() + .WithSingletonLifetime()); + + //initialize Services + Services = svcs.BuildServiceProvider(); + Services.GetRequiredService().Initialize(); + Services.GetRequiredService(); + + if (Client.ShardId == 0) + ApplyConfigMigrations(); + + _ = LoadTypeReaders(typeof(Bot).Assembly); + + sw.Stop(); + Log.Information( "All services loaded in {ServiceLoadTime:F2}s", sw.Elapsed.TotalSeconds); + } + + private void ApplyConfigMigrations() + { + // execute all migrators + var migrators = Services.GetServices(); + foreach (var migrator in migrators) + migrator.EnsureMigrated(); + } + + private IEnumerable LoadTypeReaders(Assembly assembly) + { + Type[] allTypes; + try + { + allTypes = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + Log.Warning(ex.LoaderExceptions[0], "Error getting types"); + return Enumerable.Empty(); + } + + var filteredTypes = allTypes.Where(x => x.IsSubclassOf(typeof(TypeReader)) + && x.BaseType?.GetGenericArguments().Length > 0 + && !x.IsAbstract); + + var toReturn = new List(); + foreach (var ft in filteredTypes) + { + var x = (TypeReader)ActivatorUtilities.CreateInstance(Services, ft); + var baseType = ft.BaseType; + if (baseType is null) + continue; + var typeArgs = baseType.GetGenericArguments(); + _commandService.AddTypeReader(typeArgs[0], x); + toReturn.Add(x); + } + + return toReturn; + } + + private async Task LoginAsync(string token) + { + var clientReady = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + async Task SetClientReady() + { + clientReady.TrySetResult(true); + try + { + foreach (var chan in await Client.GetDMChannelsAsync()) + await chan.CloseAsync(); + } + catch + { + // ignored + } + } + + //connect + Log.Information("Shard {ShardId} logging in ...", Client.ShardId); + try + { + Client.Ready += SetClientReady; + + await Client.LoginAsync(TokenType.Bot, token); + await Client.StartAsync(); + } + catch (HttpException ex) + { + LoginErrorHandler.Handle(ex); + Helpers.ReadErrorAndExit(3); + } + catch (Exception ex) + { + LoginErrorHandler.Handle(ex); + Helpers.ReadErrorAndExit(4); + } + + await clientReady.Task.ConfigureAwait(false); + Client.Ready -= SetClientReady; + + Client.JoinedGuild += Client_JoinedGuild; + Client.LeftGuild += Client_LeftGuild; + + // _ = Client.SetStatusAsync(UserStatus.Online); + Log.Information("Shard {ShardId} logged in", Client.ShardId); + } + + private Task Client_LeftGuild(SocketGuild arg) + { + Log.Information("Left server: {GuildName} [{GuildId}]", arg?.Name, arg?.Id); + return Task.CompletedTask; + } + + private Task Client_JoinedGuild(SocketGuild arg) + { + Log.Information("Joined server: {GuildName} [{GuildId}]", arg.Name, arg.Id); + _ = Task.Run(async () => + { + GuildConfig gc; + await using (var uow = _db.GetDbContext()) + { + gc = uow.GuildConfigsForId(arg.Id, null); + } + + await JoinedGuild.Invoke(gc); + }); + return Task.CompletedTask; + } + + public async Task RunAsync() + { + if (ShardId == 0) + await _db.SetupAsync(); + + var sw = Stopwatch.StartNew(); + + await LoginAsync(_creds.Token); + + Mention = Client.CurrentUser.Mention; + Log.Information("Shard {ShardId} loading services...", Client.ShardId); + try + { + AddServices(); + } + catch (Exception ex) + { + Log.Error(ex, "Error adding services"); + Helpers.ReadErrorAndExit(9); + } + + sw.Stop(); + Log.Information("Shard {ShardId} connected in {Elapsed:F2}s", Client.ShardId, sw.Elapsed.TotalSeconds); + var commandHandler = Services.GetRequiredService(); + + // start handling messages received in commandhandler + await commandHandler.StartHandling(); + + await _commandService.AddModulesAsync(typeof(Bot).Assembly, Services); + // await _interactionService.AddModulesAsync(typeof(Bot).Assembly, Services); + IsReady = true; + + await EnsureBotOwnershipAsync(); + _ = Task.Run(ExecuteReadySubscriptions); + Log.Information("Shard {ShardId} ready", Client.ShardId); + } + + private async ValueTask EnsureBotOwnershipAsync() + { + try + { + if (_creds.OwnerIds.Count != 0) + return; + + Log.Information("Initializing Owner Id..."); + var info = await Client.GetApplicationInfoAsync(); + _credsProvider.ModifyCredsFile(x => x.OwnerIds = new[] { info.Owner.Id }); + } + catch (Exception ex) + { + Log.Warning("Getting application info failed: {ErrorMessage}", ex.Message); + } + } + + private Task ExecuteReadySubscriptions() + { + var readyExecutors = Services.GetServices(); + var tasks = readyExecutors.Select(async toExec => + { + try + { + await toExec.OnReadyAsync(); + } + catch (Exception ex) + { + Log.Error(ex, + "Failed running OnReadyAsync method on {Type} type: {Message}", + toExec.GetType().Name, + ex.Message); + } + }); + + return tasks.WhenAll(); + } + + private Task Client_Log(LogMessage arg) + { + if (arg.Message?.Contains("unknown dispatch", StringComparison.InvariantCultureIgnoreCase) ?? false) + return Task.CompletedTask; + + if (arg.Exception is { InnerException: WebSocketClosedException { CloseCode: 4014 } }) + { + Log.Error(@" +Login failed. + +*** Please enable privileged intents *** + +Certain Ellie features require Discord's privileged gateway intents. +These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding. + +How to enable privileged intents: +1. Head over to the Discord Developer Portal https://discord.com/developers/applications/ +2. Select your Application. +3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section. +4. Enable all intents. +5. Restart your bot. + +Read this only if your bot is in 100 or more servers: + +You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal. +Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before. +While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the ellie's features"); + return Task.CompletedTask; + } + +#if GLOBAL_ELLIE || DEBUG + if (arg.Exception is not null) + Log.Warning(arg.Exception, "{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message); + else + Log.Warning("{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message); +#endif + return Task.CompletedTask; + } + + public async Task RunAndBlockAsync() + { + await RunAsync(); + await Task.Delay(-1); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Attributes/Aliases.cs b/src/EllieBot/Common/Attributes/Aliases.cs deleted file mode 100644 index 14df34a..0000000 --- a/src/EllieBot/Common/Attributes/Aliases.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class AliasesAttribute : AliasAttribute -{ - public AliasesAttribute([CallerMemberName] string memberName = "") - : base(CommandNameLoadHelper.GetAliasesFor(memberName)) - { - } -} diff --git a/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs b/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs deleted file mode 100644 index e77533d..0000000 --- a/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs +++ /dev/null @@ -1,31 +0,0 @@ -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Attributes; - -public static class CommandNameLoadHelper -{ - private static readonly IDeserializer _deserializer = new Deserializer(); - - private static readonly Lazy> _lazyCommandAliases - = new(() => LoadAliases()); - - public static Dictionary LoadAliases(string aliasesFilePath = "data/aliases.yml") - { - var text = File.ReadAllText(aliasesFilePath); - return _deserializer.Deserialize>(text); - } - - public static string[] GetAliasesFor(string methodName) - => _lazyCommandAliases.Value.TryGetValue(methodName.ToLowerInvariant(), out var aliases) && aliases.Length > 1 - ? aliases.Skip(1).ToArray() - : Array.Empty(); - - public static string GetCommandNameFor(string methodName) - { - methodName = methodName.ToLowerInvariant(); - var toReturn = _lazyCommandAliases.Value.TryGetValue(methodName, out var aliases) && aliases.Length > 0 - ? aliases[0] - : methodName; - return toReturn; - } -} diff --git a/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs b/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs deleted file mode 100644 index 666ebbe..0000000 --- a/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Common; - -/// -/// Classed marked with this attribute will not be added to the service provider -/// -[AttributeUsage(AttributeTargets.Class)] -public class DontAddToIocContainerAttribute : Attribute -{ - -} diff --git a/src/EllieBot/Common/Attributes/EllieCommand.cs b/src/EllieBot/Common/Attributes/EllieCommand.cs deleted file mode 100644 index 109c1c5..0000000 --- a/src/EllieBot/Common/Attributes/EllieCommand.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class CmdAttribute : CommandAttribute -{ - public string MethodName { get; } - - public CmdAttribute([CallerMemberName] string memberName = "") - : base(CommandNameLoadHelper.GetCommandNameFor(memberName)) - { - MethodName = memberName.ToLowerInvariant(); - Aliases = CommandNameLoadHelper.GetAliasesFor(memberName); - Remarks = memberName.ToLowerInvariant(); - Summary = memberName.ToLowerInvariant(); - } -} diff --git a/src/EllieBot/Common/Attributes/EllieOptions.cs b/src/EllieBot/Common/Attributes/EllieOptions.cs deleted file mode 100644 index 32f91df..0000000 --- a/src/EllieBot/Common/Attributes/EllieOptions.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class EllieOptionsAttribute : Attribute -{ - public Type OptionType { get; set; } - - public EllieOptionsAttribute(Type t) - => OptionType = t; -} \ No newline at end of file diff --git a/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs b/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs deleted file mode 100644 index d380a92..0000000 --- a/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs +++ /dev/null @@ -1,38 +0,0 @@ -#nullable disable -using System.Diagnostics.CodeAnalysis; - -namespace EllieBot.Common; - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -[SuppressMessage("Style", "IDE0022:Use expression body for methods")] -public sealed class NoPublicBotAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { -#if GLOBAL_ELLIE - return Task.FromResult(PreconditionResult.FromError("Not available on the public bot. To learn how to selfhost a private bot, click [here](https://docs.elliebot.net/v4/).")); -#else - return Task.FromResult(PreconditionResult.FromSuccess()); -#endif - } -} - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -[SuppressMessage("Style", "IDE0022:Use expression body for methods")] -public sealed class OnlyPublicBotAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { -#if GLOBAL_ELLIE || DEBUG - return Task.FromResult(PreconditionResult.FromSuccess()); -#else - return Task.FromResult(PreconditionResult.FromError("Only available on the public bot.")); -#endif - } -} diff --git a/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs b/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs deleted file mode 100644 index 7aa9317..0000000 --- a/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -public sealed class OwnerOnlyAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - var creds = services.GetRequiredService().GetCreds(); - - return Task.FromResult(creds.IsOwner(context.User) || context.Client.CurrentUser.Id == context.User.Id - ? PreconditionResult.FromSuccess() - : PreconditionResult.FromError("Not owner")); - } -} diff --git a/src/EllieBot/Common/Attributes/Ratelimit.cs b/src/EllieBot/Common/Attributes/Ratelimit.cs deleted file mode 100644 index 9a8c887..0000000 --- a/src/EllieBot/Common/Attributes/Ratelimit.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class RatelimitAttribute : PreconditionAttribute -{ - public int Seconds { get; } - - public RatelimitAttribute(int seconds) - { - if (seconds <= 0) - throw new ArgumentOutOfRangeException(nameof(seconds)); - - Seconds = seconds; - } - - public override async Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - if (Seconds == 0) - return PreconditionResult.FromSuccess(); - - var cache = services.GetRequiredService(); - var rem = await cache.GetRatelimitAsync( - new($"precondition:{context.User.Id}:{command.Name}"), - Seconds.Seconds()); - - if (rem is null) - return PreconditionResult.FromSuccess(); - - var msgContent = $"You can use this command again in {rem.Value.TotalSeconds:F1}s."; - - return PreconditionResult.FromError(msgContent); - } -} diff --git a/src/EllieBot/Common/Attributes/UserPerm.cs b/src/EllieBot/Common/Attributes/UserPerm.cs deleted file mode 100644 index dd2e7b5..0000000 --- a/src/EllieBot/Common/Attributes/UserPerm.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using EllieBot.Modules.Administration.Services; - -namespace Discord; - -[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] -public class UserPermAttribute : RequireUserPermissionAttribute -{ - public UserPermAttribute(GuildPerm permission) - : base(permission) - { - } - - public UserPermAttribute(ChannelPerm permission) - : base(permission) - { - } - - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - var permService = services.GetRequiredService(); - if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out _)) - return Task.FromResult(PreconditionResult.FromSuccess()); - - return base.CheckPermissionsAsync(context, command, services); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Cache/BotCacheExtensions.cs b/src/EllieBot/Common/Cache/BotCacheExtensions.cs deleted file mode 100644 index 41c6066..0000000 --- a/src/EllieBot/Common/Cache/BotCacheExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using OneOf; -using OneOf.Types; - -namespace EllieBot.Common; - -public static class BotCacheExtensions -{ - public static async ValueTask GetOrDefaultAsync(this IBotCache cache, TypedKey key) - { - var result = await cache.GetAsync(key); - if (result.TryGetValue(out var val)) - return val; - - return default; - } - - private static TypedKey GetImgKey(Uri uri) - => new($"image:{uri}"); - - public static ValueTask SetImageDataAsync(this IBotCache c, string key, byte[] data) - => c.SetImageDataAsync(new Uri(key), data); - public static async ValueTask SetImageDataAsync(this IBotCache c, Uri key, byte[] data) - => await c.AddAsync(GetImgKey(key), data, expiry: TimeSpan.FromHours(48)); - - public static async ValueTask> GetImageDataAsync(this IBotCache c, Uri key) - => await c.GetAsync(GetImgKey(key)); - - public static async Task GetRatelimitAsync( - this IBotCache c, - TypedKey key, - TimeSpan length) - { - var now = DateTime.UtcNow; - var nowB = now.ToBinary(); - - var cachedValue = await c.GetOrAddAsync(key, - () => Task.FromResult(now.ToBinary()), - expiry: length); - - if (cachedValue == nowB) - return null; - - var diff = now - DateTime.FromBinary(cachedValue); - return length - diff; - } -} diff --git a/src/EllieBot/Common/Cache/IBotCache.cs b/src/EllieBot/Common/Cache/IBotCache.cs deleted file mode 100644 index e1ea2c9..0000000 --- a/src/EllieBot/Common/Cache/IBotCache.cs +++ /dev/null @@ -1,47 +0,0 @@ -using OneOf; -using OneOf.Types; - -namespace EllieBot.Common; - -public interface IBotCache -{ - /// - /// Adds an item to the cache - /// - /// Key to add - /// Value to add to the cache - /// Optional expiry - /// Whether old value should be overwritten - /// Type of the value - /// Returns whether add was sucessful. Always true unless ovewrite = false - ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true); - - /// - /// Get an element from the cache - /// - /// Key - /// Type of the value - /// Either a value or - ValueTask> GetAsync(TypedKey key); - - /// - /// Remove a key from the cache - /// - /// Key to remove - /// Type of the value - /// Whether there was item - ValueTask RemoveAsync(TypedKey key); - - /// - /// Get the key if it exists or add a new one - /// - /// Key to get and potentially add - /// Value creation factory - /// Optional expiry - /// Type of the value - /// The retrieved or newly added value - ValueTask GetOrAddAsync( - TypedKey key, - Func> createFactory, - TimeSpan? expiry = null); -} diff --git a/src/EllieBot/Common/Cache/MemoryBotCache.cs b/src/EllieBot/Common/Cache/MemoryBotCache.cs deleted file mode 100644 index d0b7e68..0000000 --- a/src/EllieBot/Common/Cache/MemoryBotCache.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.Extensions.Caching.Memory; -using OneOf; -using OneOf.Types; - -// ReSharper disable InconsistentlySynchronizedField - -namespace EllieBot.Common; - -public sealed class MemoryBotCache : IBotCache -{ - // needed for overwrites and Delete return value - private readonly object _cacheLock = new object(); - private readonly MemoryCache _cache; - - public MemoryBotCache() - { - _cache = new MemoryCache(new MemoryCacheOptions()); - } - - public ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) - { - if (overwrite) - { - using var item = _cache.CreateEntry(key.Key); - item.Value = value; - item.AbsoluteExpirationRelativeToNow = expiry; - return new(true); - } - - lock (_cacheLock) - { - if (_cache.TryGetValue(key.Key, out var old) && old is not null) - return new(false); - - using var item = _cache.CreateEntry(key.Key); - item.Value = value; - item.AbsoluteExpirationRelativeToNow = expiry; - return new(true); - } - } - - public async ValueTask GetOrAddAsync( - TypedKey key, - Func> createFactory, - TimeSpan? expiry = null) - => await _cache.GetOrCreateAsync(key.Key, - async ce => - { - ce.AbsoluteExpirationRelativeToNow = expiry; - var val = await createFactory(); - return val; - }); - - public ValueTask> GetAsync(TypedKey key) - { - if (!_cache.TryGetValue(key.Key, out var val) || val is null) - return new(new None()); - - return new((T)val); - } - - public ValueTask RemoveAsync(TypedKey key) - { - lock (_cacheLock) - { - var toReturn = _cache.TryGetValue(key.Key, out var old) && old is not null; - _cache.Remove(key.Key); - return new(toReturn); - } - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Cache/RedisBotCache.cs b/src/EllieBot/Common/Cache/RedisBotCache.cs deleted file mode 100644 index 8de00fe..0000000 --- a/src/EllieBot/Common/Cache/RedisBotCache.cs +++ /dev/null @@ -1,119 +0,0 @@ -using OneOf; -using OneOf.Types; -using StackExchange.Redis; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EllieBot.Common; - -public sealed class RedisBotCache : IBotCache -{ - private static readonly Type[] _supportedTypes = new[] - { - typeof(bool), typeof(int), typeof(uint), typeof(long), - typeof(ulong), typeof(float), typeof(double), - typeof(string), typeof(byte[]), typeof(ReadOnlyMemory), typeof(Memory), - typeof(RedisValue), - }; - - private static readonly JsonSerializerOptions _opts = new() - { - PropertyNameCaseInsensitive = true, - NumberHandling = JsonNumberHandling.AllowReadingFromString, - AllowTrailingCommas = true, - IgnoreReadOnlyProperties = false, - }; - private readonly ConnectionMultiplexer _conn; - - public RedisBotCache(ConnectionMultiplexer conn) - { - _conn = conn; - } - - public async ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) - { - // if a null value is passed, remove the key - if (value is null) - { - await RemoveAsync(key); - return false; - } - - var db = _conn.GetDatabase(); - RedisValue val = IsSupportedType(typeof(T)) - ? RedisValue.Unbox(value) - : JsonSerializer.Serialize(value, _opts); - - var success = await db.StringSetAsync(key.Key, - val, - expiry: expiry, - when: overwrite ? When.Always : When.NotExists); - - return success; - } - - public bool IsSupportedType(Type type) - { - if (type.IsGenericType) - { - var typeDef = type.GetGenericTypeDefinition(); - if (typeDef == typeof(Nullable<>)) - return IsSupportedType(type.GenericTypeArguments[0]); - } - - foreach (var t in _supportedTypes) - { - if (type == t) - return true; - } - - return false; - } - - public async ValueTask> GetAsync(TypedKey key) - { - var db = _conn.GetDatabase(); - var val = await db.StringGetAsync(key.Key); - if (val == default) - return new None(); - - if (IsSupportedType(typeof(T))) - return (T)((IConvertible)val).ToType(typeof(T), null); - - return JsonSerializer.Deserialize(val.ToString(), _opts)!; - } - - public async ValueTask RemoveAsync(TypedKey key) - { - var db = _conn.GetDatabase(); - - return await db.KeyDeleteAsync(key.Key); - } - - public async ValueTask GetOrAddAsync(TypedKey key, Func> createFactory, TimeSpan? expiry = null) - { - var result = await GetAsync(key); - - return await result.Match>( - v => Task.FromResult(v), - async _ => - { - var factoryValue = await createFactory(); - - if (factoryValue is null) - return default; - - await AddAsync(key, factoryValue, expiry); - - // get again to make sure it's the cached value - // and not the late factory value, in case there's a race condition - - var newResult = await GetAsync(key); - - // it's fine to do this, it should blow up if something went wrong. - return newResult.Match( - v => v, - _ => default); - }); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Configs/BotConfig.cs b/src/EllieBot/Common/Configs/BotConfig.cs deleted file mode 100644 index 80186a9..0000000 --- a/src/EllieBot/Common/Configs/BotConfig.cs +++ /dev/null @@ -1,185 +0,0 @@ -#nullable disable -using Cloneable; -using EllieBot.Common.Yml; -using SixLabors.ImageSharp.PixelFormats; -using System.Globalization; -using YamlDotNet.Core; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Configs; - -[Cloneable] -public sealed partial class BotConfig : ICloneable -{ - [Comment(@"DO NOT CHANGE")] - public int Version { get; set; } = 5; - - [Comment(@"Most commands, when executed, have a small colored line -next to the response. The color depends whether the command -is completed, errored or in progress (pending) -Color settings below are for the color of those lines. -To get color's hex, you can go here https://htmlcolorcodes.com/ -and copy the hex code fo your selected color (marked as #)")] - public ColorConfig Color { get; set; } - - [Comment("Default bot language. It has to be in the list of supported languages (.langli)")] - public CultureInfo DefaultLocale { get; set; } - - [Comment(@"Style in which executed commands will show up in the console. -Allowed values: Simple, Normal, None")] - public ConsoleOutputType ConsoleOutputType { get; set; } - - [Comment(@"Whether the bot will check for new releases every hour")] - public bool CheckForUpdates { get; set; } = true; - - [Comment(@"Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?")] - public bool ForwardMessages { get; set; } - - [Comment( - @"Do you want the message to be forwarded only to the first owner specified in the list of owners (in creds.yml), -or all owners? (this might cause the bot to lag if there's a lot of owners specified)")] - public bool ForwardToAllOwners { get; set; } - - [Comment(@"Any messages sent by users in Bot's DM to be forwarded to the specified channel. -This option will only work when ForwardToAllOwners is set to false")] - public ulong? ForwardToChannel { get; set; } - - [Comment(@"When a user DMs the bot with a message which is not a command -they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. -Supports embeds. How it looks: https://puu.sh/B0BLV.png")] - [YamlMember(ScalarStyle = ScalarStyle.Literal)] - public string DmHelpText { get; set; } - - [Comment(@"Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response. -Case insensitive. -Leave empty to reply with DmHelpText to every DM.")] - public List DmHelpTextKeywords { get; set; } - - [Comment(@"This is the response for the .h command")] - [YamlMember(ScalarStyle = ScalarStyle.Literal)] - public string HelpText { get; set; } - - [Comment(@"List of modules and commands completely blocked on the bot")] - public BlockedConfig Blocked { get; set; } - - [Comment(@"Which string will be used to recognize the commands")] - public string Prefix { get; set; } - - [Comment(@"Toggles whether your bot will group greet/bye messages into a single message every 5 seconds. -1st user who joins will get greeted immediately -If more users join within the next 5 seconds, they will be greeted in groups of 5. -This will cause %user.mention% and other placeholders to be replaced with multiple users. -Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail, -it will become invalid, as it will resolve to a list of avatars of grouped users. -note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some - servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited, - and (slightly) reduce the greet spam in those servers.")] - public bool GroupGreets { get; set; } - - [Comment(@"Whether the bot will rotate through all specified statuses. -This setting can be changed via .ropl command. -See RotatingStatuses submodule in Administration.")] - public bool RotateStatuses { get; set; } - - public BotConfig() - { - var color = new ColorConfig(); - Color = color; - DefaultLocale = new("en-US"); - ConsoleOutputType = ConsoleOutputType.Normal; - ForwardMessages = false; - ForwardToAllOwners = false; - DmHelpText = @"{""description"": ""Type `%prefix%h` for help.""}"; - HelpText = @"{ - ""title"": ""To invite me to your server, use this link"", - ""description"": ""https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303"", - ""color"": 53380, - ""thumbnail"": ""https://cdn.elliebot.net/Ellie.png"", - ""fields"": [ - { - ""name"": ""Useful help commands"", - ""value"": ""`%bot.prefix%modules` Lists all bot modules. -`%prefix%h CommandName` Shows some help about a specific command. -`%prefix%commands ModuleName` Lists all commands in a module."", - ""inline"": false - }, - { - ""name"": ""List of all Commands"", - ""value"": ""https://commands.elliebot.net"", - ""inline"": false - }, - { - ""name"": ""Ellie Support Server"", - ""value"": ""https://discord.gg/etQdZxSyEH"", - ""inline"": true - } - ] -}"; - var blocked = new BlockedConfig(); - Blocked = blocked; - Prefix = "."; - RotateStatuses = false; - GroupGreets = false; - DmHelpTextKeywords = new() - { - "help", - "commands", - "cmds", - "module", - "can you do" - }; - } - - // [Comment(@"Whether the prefix will be a suffix, or prefix. - // For example, if your prefix is ! you will run a command called 'cash' by typing either - // '!cash @Someone' if your prefixIsSuffix: false or - // 'cash @Someone!' if your prefixIsSuffix: true")] - // public bool PrefixIsSuffix { get; set; } - - // public string Prefixed(string text) => PrefixIsSuffix - // ? text + Prefix - // : Prefix + text; - - public string Prefixed(string text) - => Prefix + text; -} - -[Cloneable] -public sealed partial class BlockedConfig -{ - public HashSet Commands { get; set; } - public HashSet Modules { get; set; } - - public BlockedConfig() - { - Modules = new(); - Commands = new(); - } -} - -[Cloneable] -public partial class ColorConfig -{ - [Comment(@"Color used for embed responses when command successfully executes")] - public Rgba32 Ok { get; set; } - - [Comment(@"Color used for embed responses when command has an error")] - public Rgba32 Error { get; set; } - - [Comment(@"Color used for embed responses while command is doing work or is in progress")] - public Rgba32 Pending { get; set; } - - public ColorConfig() - { - Ok = Rgba32.ParseHex("00e584"); - Error = Rgba32.ParseHex("ee281f"); - Pending = Rgba32.ParseHex("faa61a"); - } -} - -public enum ConsoleOutputType -{ - Normal = 0, - Simple = 1, - None = 2 -} \ No newline at end of file diff --git a/src/EllieBot/Common/Configs/IConfigSeria.cs b/src/EllieBot/Common/Configs/IConfigSeria.cs deleted file mode 100644 index cced324..0000000 --- a/src/EllieBot/Common/Configs/IConfigSeria.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace EllieBot.Common.Configs; - -/// -/// Base interface for available config serializers -/// -public interface IConfigSeria -{ - /// - /// Serialize the object to string - /// - public string Serialize(T obj) - where T : notnull; - - /// - /// Deserialize string data into an object of the specified type - /// - public T Deserialize(string data); -} diff --git a/src/EllieBot/Common/Interaction/EllieInteraction.cs b/src/EllieBot/Common/Interaction/EllieInteraction.cs deleted file mode 100644 index e77fede..0000000 --- a/src/EllieBot/Common/Interaction/EllieInteraction.cs +++ /dev/null @@ -1,82 +0,0 @@ -namespace EllieBot; - -public sealed class EllieInteraction -{ - private readonly ulong _authorId; - private readonly ButtonBuilder _button; - private readonly Func _onClick; - private readonly bool _onlyAuthor; - public DiscordSocketClient Client { get; } - - private readonly TaskCompletionSource _interactionCompletedSource; - - private IUserMessage message = null!; - - public EllieInteraction(DiscordSocketClient client, - ulong authorId, - ButtonBuilder button, - Func onClick, - bool onlyAuthor) - { - _authorId = authorId; - _button = button; - _onClick = onClick; - _onlyAuthor = onlyAuthor; - _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); - - Client = client; - } - - public async Task RunAsync(IUserMessage msg) - { - message = msg; - - Client.InteractionCreated += OnInteraction; - await Task.WhenAny(Task.Delay(15_000), _interactionCompletedSource.Task); - Client.InteractionCreated -= OnInteraction; - - await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); - } - - private Task OnInteraction(SocketInteraction arg) - { - if (arg is not SocketMessageComponent smc) - return Task.CompletedTask; - - if (smc.Message.Id != message.Id) - return Task.CompletedTask; - - if (_onlyAuthor && smc.User.Id != _authorId) - return Task.CompletedTask; - - if (smc.Data.CustomId != _button.CustomId) - return Task.CompletedTask; - - _ = Task.Run(async () => - { - await ExecuteOnActionAsync(smc); - - // this should only be a thing on single-response buttons - _interactionCompletedSource.TrySetResult(true); - - if (!smc.HasResponded) - { - await smc.DeferAsync(); - } - }); - - return Task.CompletedTask; - } - - - public MessageComponent CreateComponent() - { - var comp = new ComponentBuilder() - .WithButton(_button); - - return comp.Build(); - } - - public Task ExecuteOnActionAsync(SocketMessageComponent smc) - => _onClick(smc); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionData.cs b/src/EllieBot/Common/Interaction/EllieInteractionData.cs deleted file mode 100644 index 3e25606..0000000 --- a/src/EllieBot/Common/Interaction/EllieInteractionData.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EllieBot; - -/// -/// Represents essential interacation data -/// -/// Emote which will show on a button -/// Custom interaction id -public record EllieInteractionData(IEmote Emote, string CustomId, string? Text = null); \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionService.cs b/src/EllieBot/Common/Interaction/EllieInteractionService.cs deleted file mode 100644 index 3e97ec1..0000000 --- a/src/EllieBot/Common/Interaction/EllieInteractionService.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace EllieBot; - -public class EllieInteractionService : IEllieInteractionService, IEService -{ - private readonly DiscordSocketClient _client; - - public EllieInteractionService(DiscordSocketClient client) - { - _client = client; - } - - public EllieInteraction Create( - ulong userId, - SimpleInteraction inter) - => new EllieInteraction(_client, - userId, - inter.Button, - inter.TriggerAsync, - onlyAuthor: true); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/IEllieInteractionService.cs b/src/EllieBot/Common/Interaction/IEllieInteractionService.cs deleted file mode 100644 index 03a3ba1..0000000 --- a/src/EllieBot/Common/Interaction/IEllieInteractionService.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EllieBot; - -public interface IEllieInteractionService -{ - public EllieInteraction Create( - ulong userId, - SimpleInteraction inter); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/SimpleInteraction.cs b/src/EllieBot/Common/Interaction/SimpleInteraction.cs deleted file mode 100644 index 045d4fc..0000000 --- a/src/EllieBot/Common/Interaction/SimpleInteraction.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace EllieBot; - -public class SimpleInteraction -{ - public ButtonBuilder Button { get; } - private readonly Func _onClick; - private readonly T? _state; - - public SimpleInteraction(ButtonBuilder button, Func onClick, T? state = default) - { - Button = button; - _onClick = onClick; - _state = state; - } - - public async Task TriggerAsync(SocketMessageComponent smc) - { - await _onClick(smc, _state!); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs b/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs deleted file mode 100644 index 0c26f15..0000000 --- a/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EllieBot.Common.JsonConverters; - -public class CultureInfoConverter : JsonConverter -{ - public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => new(reader.GetString() ?? "en-US"); - - public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) - => writer.WriteStringValue(value.Name); -} \ No newline at end of file diff --git a/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs b/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs deleted file mode 100644 index ef619a6..0000000 --- a/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using SixLabors.ImageSharp.PixelFormats; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EllieBot.Common.JsonConverters; - -public class Rgba32Converter : JsonConverter -{ - public override Rgba32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => Rgba32.ParseHex(reader.GetString()); - - public override void Write(Utf8JsonWriter writer, Rgba32 value, JsonSerializerOptions options) - => writer.WriteStringValue(value.ToHex()); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs deleted file mode 100644 index 935d27a..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs +++ /dev/null @@ -1,76 +0,0 @@ -#nullable disable - -[DontAddToIocContainer] -public sealed class BehaviorAdapter : ICustomBehavior -{ - private readonly WeakReference _canaryWr; - private readonly IMarmaladeStrings _strings; - private readonly IServiceProvider _services; - private readonly string _name; - - // unused - public int Priority - => 0; - - public BehaviorAdapter(WeakReference canaryWr, IMarmaladeStrings strings, IServiceProvider services) - { - _canaryWr = canaryWr; - _strings = strings; - _services = services; - - _name = canaryWr.TryGetTarget(out var canary) - ? $"canary/{canary.GetType().Name}" - : "unknown"; - } - - public async Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return false; - - return await canary.ExecPreCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), - moduleName, - command.Name); - } - - public async Task ExecOnMessageAsync(IGuild? guild, IUserMessage msg) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return false; - - return await canary.ExecOnMessageAsync(guild, msg); - } - - public async Task TransformInput( - IGuild guild, - IMessageChannel channel, - IUser user, - string input) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return null; - - return await canary.ExecInputTransformAsync(guild, channel, user, input); - } - - public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return; - - await canary.ExecOnNoCommandAsync(guild, msg); - } - - public async ValueTask ExecPostCommandAsync(ICommandContext context, string moduleName, string commandName) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return; - - await canary.ExecPostCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), - moduleName, - commandName); - } - - public override string ToString() - => _name; -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs b/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs deleted file mode 100644 index 212e8ee..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -internal class ContextFactory -{ - public static AnyContext CreateNew(ICommandContext context, IMarmaladeStrings strings, IServiceProvider services) - => context.Guild is null - ? new DmContextAdapter(context, strings, services) - : new GuildContextAdapter(context, strings, services); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs deleted file mode 100644 index d0aaabc..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -public sealed class DmContextAdapter : DmContext -{ - public override IMarmaladeStrings Strings { get; } - public override IDMChannel Channel { get; } - public override IUserMessage Message { get; } - public override ISelfUser Bot { get; } - public override IUser User - => Message.Author; - - private readonly IServiceProvider _services; - private readonly Lazy _ebs; - private readonly Lazy _botStrings; - private readonly Lazy _localization; - - public DmContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) - { - if (ctx is not { Channel: IDMChannel ch}) - { - throw new ArgumentException("Can't use non-dm context to create DmContextAdapter", nameof(ctx)); - } - - Strings = strings; - - _services = services; - - Channel = ch; - Message = ctx.Message; - Bot = ctx.Client.CurrentUser; - - _ebs = new(_services.GetRequiredService()); - _botStrings = new(_services.GetRequiredService); - _localization = new(_services.GetRequiredService()); - } - - public override IEmbedBuilder Embed() - => _ebs.Value.Create(); - - public override string GetText(string key, object[]? args = null) - { - var cultureInfo = _localization.Value.GetCultureInfo(default(ulong?)); - var output = Strings.GetText(key, cultureInfo, args ?? Array.Empty()); - if (!string.IsNullOrEmpty(output)) - return output; - - return _botStrings.Value.GetText(key, cultureInfo, args); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs deleted file mode 100644 index 1934e38..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Ellie.Marmalade.Adapters; - -public class FilterAdapter : PreconditionAttribute -{ - private readonly FilterAttribute _filterAttribute; - private readonly IMarmaladeStrings _strings; - - public FilterAdapter(FilterAttribute filterAttribute, - IMarmaladeStrings strings) - { - _filterAttribute = filterAttribute; - _strings = strings; - } - - public override async Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - var marmaladeContext = ContextAdapterFactory.CreateNew(context, - _strings, - services); - - var result = await _filterAttribute.CheckAsync(marmaladeContext); - - if (!result) - return PreconditionResult.FromError($"Precondition '{_filterAttribute.GetType().Name}' failed."); - - return PreconditionResult.FromSuccess(); - } -} diff --git a/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs deleted file mode 100644 index f5f0a2b..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -public sealed class GuildContextAdapter : GuildContext -{ - private readonly IServiceProvider _services; - private readonly ICommandContext _ctx; - private readonly Lazy _ebs; - private readonly Lazy _botStrings; - private readonly Lazy _localization; - - public override IMarmaladeStrings Strings { get; } - public override IGuild Guild { get; } - public override ITextChannel Channel { get; } - public override ISelfUser Bot { get; } - public override IUserMessage Message - => _ctx.Message; - - public override IGuildUser User { get; } - - public override IEmbedBuilder Embed() - => _ebs.Value.Create(); - - public GuildContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) - { - if (ctx.Guild is not IGuild guild || ctx.Channel is not ITextChannel channel) - { - throw new ArgumentException("Can't use non-guild context to create GuildContextAdapter", nameof(ctx)); - } - - Strings = strings; - User = (IGuildUser)ctx.User; - Bot = ctx.Client.CurrentUser; - - _services = services; - _ebs = new(_services.GetRequiredService()); - _botStrings = new(_services.GetRequiredService); - _localization = new(_services.GetRequiredService()); - - (_ctx, Guild, Channel) = (ctx, guild, channel); - } - - public override string GetText(string key, object[]? args = null) - { - args ??= Array.Empty(); - - var cultureInfo = _localization.Value.GetCultureInfo(_ctx.Guild.Id); - var output = Strings.GetText(key, cultureInfo, args); - if (!string.IsNullOrWhiteSpace(output)) - return output; - - return _botStrings.Value.GetText(key, cultureInfo, args); - } -} diff --git a/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs deleted file mode 100644 index 1d3b948..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs +++ /dev/null @@ -1,32 +0,0 @@ -public sealed class ParamParserAdapter : TypeReader -{ - private readonly ParamParser _parser; - private readonly IMarmaladeStrings _strings; - private readonly IServiceProvider _services; - - public ParamParserAdapter(ParamParser parser, - IMarmaladeStrings strings, - IServiceProvider services) - { - _parser = parser; - _strings = strings; - _services = services; - } - - public override async Task ReadAsync( - ICommandContext context, - string input, - IServiceProvider services) - { - var marmaladeContext = ContextAdapterFactory.CreateNew(context, - _strings, - _services); - - var result = await _parser.TryParseAsync(marmaladeContext, input); - - if (result.IsSuccess) - return Discord.Commands.TypeReaderResult.FromSuccess(result.Data); - - return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, "Invalid input"); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/CommandContextType.cs b/src/EllieBot/Common/Marmalade/CommandContextType.cs deleted file mode 100644 index 9f9459c..0000000 --- a/src/EllieBot/Common/Marmalade/CommandContextType.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Ellie.Marmalade; - -/// -/// Enum specifying in which context the command can be executed -/// -public enum CommandContextType -{ - /// - /// Command can only be executed in a guild - /// - Guild, - - /// - /// Command can only be executed in DMs - /// - Dm, - - /// - /// Command can be executed anywhere - /// - Any, - - /// - /// Command can be executed anywhere, and it doesn't require context to be passed to it - /// - Unspecified -} diff --git a/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs b/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs deleted file mode 100644 index f3e6f6a..0000000 --- a/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ellie.Marmalade; - -public interface IMarmaladeConfigService -{ - IReadOnlyCollection GetLoadedMarmalades(); - void AddLoadedMarmalade(string name); - void RemoveLoadedMarmalade(string name); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs deleted file mode 100644 index 82ec302..0000000 --- a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -using Cloneable; -using EllieBot.Common.Yml; - -namespace Ellie.Marmalade; - -[Cloneable] -public sealed partial class MarmaladeConfig : ICloneable -{ - [Comment(@"DO NOT CHANGE")] - public int Version { get; set; } = 1; - - [Comment("List of marmalades automatically loaded at startup")] - public List? Loaded { get; set; } - - public MarmaladeConfig() - { - Loaded = new(); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs deleted file mode 100644 index fe475e8..0000000 --- a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs +++ /dev/null @@ -1,45 +0,0 @@ -using EllieBot.Common.Configs; - -namespace Ellie.Marmalade; - -public sealed class MarmaladeConfigService : ConfigServiceBase, IMarmaladeConfigService -{ - private const string FILE_PATH = "data/marmalades/marmalade.yml"; - private static readonly TypedKey _changeKey = new("config.marmalade.updated"); - - public override string Name - => "marmalade"; - - public MarmaladeConfigService( - IConfigSeria serializer, - IPubSub pubSub) - : base(FILE_PATH, serializer, pubSub, _changeKey) - { - } - - public IReadOnlyCollection GetLoadedMarmalades() - => Data.Loaded?.ToList() ?? new List(); - - public void AddLoadedMarmalade(string name) - { - ModifyConfig(conf => - { - if (conf.Loaded is null) - conf.Loaded = new(); - - if (!conf.Loaded.Contains(name)) - conf.Loaded.Add(name); - }); - } - - public void RemoveLoadedMarmalade(string name) - { - ModifyConfig(conf => - { - if (conf.Loaded is null) - conf.Loaded = new(); - - conf.Loaded.Remove(name); - }); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs b/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs deleted file mode 100644 index 7064f5c..0000000 --- a/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Globalization; - -namespace Ellie.Marmalade; - -public interface IMarmaladeLoaderService -{ - Task LoadMarmaladeAsync(string marmaladeName); - Task UnloadMarmaladeAsync(string marmaladeName); - string GetCommandDescription(string marmamaleName, string commandName, CultureInfo culture); - string[] GetCommandExampleArgs(string marmamaleName, string commandName, CultureInfo culture); - Task ReloadStrings(); - IReadOnlyCollection GetAllMarmalades(); - IReadOnlyCollection GetLoadedMarmalades(CultureInfo? cultureInfo = null); -} - -public sealed record MarmaladeStats(string Name, - string? Description, - IReadOnlyCollection Canaries); - -public sealed record CanaryStats(string Name, - IReadOnlyCollection Commands); - -public sealed record CanaryCommandStats(string Name); \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs b/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs deleted file mode 100644 index 2e30d81..0000000 --- a/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.Loader; - -namespace Ellie.Marmalade; - -public sealed class MarmaladeAssemblyLoadContext : AssemblyLoadContext -{ - private readonly AssemblyDependencyResolver _depResolver; - - public MarmaladeAssemblyLoadContext(string pluginPath) : base(isCollectible: true) - { - _depResolver = new(pluginPath); - } - - protected override Assembly? Load(AssemblyName assemblyName) - { - var assemblyPath = _depResolver.ResolveAssemblyToPath(assemblyName); - if (assemblyPath != null) - { - return LoadFromAssemblyPath(assemblyPath); - } - - return null; - } - - protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) - { - var libraryPath = _depResolver.ResolveUnmanagedDllToPath(unmanagedDllName); - if (libraryPath != null) - { - return LoadUnmanagedDllFromPath(libraryPath); - } - - return IntPtr.Zero; - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs b/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs deleted file mode 100644 index d31fc51..0000000 --- a/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs +++ /dev/null @@ -1,917 +0,0 @@ -using Discord.Commands.Builders; -using Microsoft.Extensions.DependencyInjection; -using Ellie.Marmalade.Adapters; -using EllieBot.Common.ModuleBehaviors; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Ellie.Marmalade; - -// ReSharper disable RedundantAssignment -public sealed class MarmaladeLoaderService : IMarmaladeLoaderService, IReadyExecutor, IEService -{ - private readonly CommandService _cmdService; - private readonly IServiceProvider _botServices; - private readonly IBehaviorHandler _behHandler; - private readonly IPubSub _pubSub; - private readonly IMarmaladeConfigService _marmaladeConfig; - - private readonly ConcurrentDictionary _resolved = new(); -#pragma warning disable IDE0090 // Use 'new(...)' - private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); -#pragma warning restore IDE0090 // Use 'new(...)' - - private readonly TypedKey _loadKey = new("marmalade:load"); - private readonly TypedKey _unloadKey = new("marmalade:unload"); - - private readonly TypedKey _stringsReload = new("marmalade:reload_strings"); - - private const string BASE_DIR = "data/marmalades"; - - public MarmaladeLoaderService(CommandService cmdService, - IServiceProvider botServices, - IBehaviorHandler behHandler, - IPubSub pubSub, - IMarmaladeConfigService marmaladeConfig) - { - _cmdService = cmdService; - _botServices = botServices; - _behHandler = behHandler; - _pubSub = pubSub; - _marmaladeConfig = marmaladeConfig; - - // has to be done this way to support this feature on sharded bots - _pubSub.Sub(_loadKey, async name => await InternalLoadAsync(name)); - _pubSub.Sub(_unloadKey, async name => await InternalUnloadAsync(name)); - - _pubSub.Sub(_stringsReload, async _ => await ReloadStringsInternal()); - } - - public IReadOnlyCollection GetAllMarmalades() - { - if (!Directory.Exists(BASE_DIR)) - return Array.Empty(); - - return Directory.GetDirectories(BASE_DIR) - .Select(x => Path.GetRelativePath(BASE_DIR, x)) - .ToArray(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public IReadOnlyCollection GetLoadedMarmalades(CultureInfo? culture) - { - var toReturn = new List(_resolved.Count); - foreach (var (name, resolvedData) in _resolved) - { - var canaries = new List(resolvedData.CanaryInfos.Count); - - foreach (var canaryInfos in resolvedData.CanaryInfos.Concat(resolvedData.CanaryInfos.SelectMany(x => x.Subcanaries))) - { - var commands = new List(); - - foreach (var command in canaryInfos.Commands) - { - commands.Add(new CanaryCommandStats(command.Aliases.First())); - } - - canaries.Add(new CanaryStats(canaryInfos.Name, commands)); - } - - toReturn.Add(new MarmaladeStats(name, resolvedData.Strings.GetDescription(culture), canaries)); - } - return toReturn; - } - - public async Task OnReadyAsync() - { - foreach (var name in _marmaladeConfig.GetLoadedMarmalades()) - { - var result = await InternalLoadAsync(name); - if (result != MarmaladeLoadResult.Success) - Log.Warning("Unable to load '{MarmaladeName}' marmalade", name); - else - Log.Warning("Loaded marmalade '{MarmaladeName}'", name); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public async Task LoadMarmaladeAsync(string marmaladeName) - { - // try loading on this shard first to see if it works - var res = await InternalLoadAsync(marmaladeName); - if (res == MarmaladeLoadResult.Success) - { - // if it does publish it so that other shards can load the medusa too - // this method will be ran twice on this shard but it doesn't matter as - // the second attempt will be ignored - await _pubSub.Pub(_loadKey, marmaladeName); - } - - return res; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public async Task UnloadMarmaladeAsync(string marmaladeName) - { - var res = await InternalUnloadAsync(marmaladeName); - if (res == MarmaladeUnloadResult.Success) - { - await _pubSub.Pub(_unloadKey, marmaladeName); - } - - return res; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public string[] GetCommandExampleArgs(string marmaladeName, string commandName, CultureInfo culture) - { - if (!_resolved.TryGetValue(marmaladeName, out var data)) - return Array.Empty(); - - return data.Strings.GetCommandStrings(commandName, culture).Args - ?? data.CanaryInfos - .SelectMany(x => x.Commands) - .FirstOrDefault(x => x.Aliases.Any(alias - => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) - ?.OptionalStrings - .Args - ?? new[] { string.Empty }; - } - - public Task ReloadStrings() - => _pubSub.Pub(_stringsReload, true); - - [MethodImpl(MethodImplOptions.NoInlining)] - private void ReloadStringsSync() - { - foreach (var resolved in _resolved.Values) - { - resolved.Strings.Reload(); - } - } - - private async Task ReloadStringsInternal() - { - await _lock.WaitAsync(); - try - { - ReloadStringsSync(); - } - finally - { - _lock.Release(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public string GetCommandDescription(string marmaladeName, string commandName, CultureInfo culture) - { - if (!_resolved.TryGetValue(marmaladeName, out var data)) - return string.Empty; - - return data.Strings.GetCommandStrings(commandName, culture).Desc - ?? data.CanaryInfos - .SelectMany(x => x.Commands) - .FirstOrDefault(x => x.Aliases.Any(alias - => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) - ?.OptionalStrings - .Desc - ?? string.Empty; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async ValueTask InternalLoadAsync(string name) - { - if (_resolved.ContainsKey(name)) - return MarmaladeLoadResult.AlreadyLoaded; - - var safeName = Uri.EscapeDataString(name); - - await _lock.WaitAsync(); - try - { - if (LoadAssemblyInternal(safeName, - out var ctx, - out var canaryData, - out var services, - out var strings, - out var typeReaders)) - { - var moduleInfos = new List(); - - LoadTypeReadersInternal(typeReaders); - - foreach (var point in canaryData) - { - try - { - // initialize canary and subcanaries - await point.Instance.InitializeAsync(); - foreach (var sub in point.Subcanaries) - { - await sub.Instance.InitializeAsync(); - } - - var module = await LoadModuleInternalAsync(name, point, strings, services); - moduleInfos.Add(module); - } - catch (Exception ex) - { - Log.Warning(ex, - "Error loading canary {CanaryName}", - point.Name); - } - } - - var execs = GetExecsInternal(canaryData, strings, services); - await _behHandler.AddRangeAsync(execs); - - _resolved[name] = new(LoadContext: ctx, - ModuleInfos: moduleInfos.ToImmutableArray(), - CanaryInfos: canaryData.ToImmutableArray(), - strings, - typeReaders, - execs) - { - Services = services - }; - - - services = null; - _marmaladeConfig.AddLoadedMarmalade(safeName); - return MarmaladeLoadResult.Success; - } - - return MarmaladeLoadResult.Empty; - } - catch (Exception ex) when (ex is FileNotFoundException or BadImageFormatException) - { - return MarmaladeLoadResult.NotFound; - } - catch (Exception ex) - { - Log.Error(ex, "An error occurred loading a marmalade"); - return MarmaladeLoadResult.UnknownError; - } - finally - { - _lock.Release(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private IReadOnlyCollection GetExecsInternal(IReadOnlyCollection canaryData, IMarmaladeStrings strings, IServiceProvider services) - { - var behs = new List(); - foreach (var canary in canaryData) - { - behs.Add(new BehaviorAdapter(new(canary.Instance), strings, services)); - - foreach (var sub in canary.Subcanaries) - { - behs.Add(new BehaviorAdapter(new(sub.Instance), strings, services)); - } - } - - return behs; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void LoadTypeReadersInternal(Dictionary typeReaders) - { - var notAddedTypeReaders = new List(); - foreach (var (type, typeReader) in typeReaders) - { - // if type reader for this type already exists, it will not be replaced - if (_cmdService.TypeReaders.Contains(type)) - { - notAddedTypeReaders.Add(type); - continue; - } - - _cmdService.AddTypeReader(type, typeReader); - } - - // remove the ones that were not added - // to prevent them from being unloaded later - // as they didn't come from this marmalade - foreach (var toRemove in notAddedTypeReaders) - { - typeReaders.Remove(toRemove); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private bool LoadAssemblyInternal( - string safeName, - [NotNullWhen(true)] out WeakReference? ctxWr, - [NotNullWhen(true)] out IReadOnlyCollection? canaryData, - out IServiceProvider services, - out IMarmaladeStrings strings, - out Dictionary typeReaders) - { - ctxWr = null; - canaryData = null; - - var path = $"{BASE_DIR}/{safeName}/{safeName}.dll"; - strings = MarmaladeStrings.CreateDefault($"{BASE_DIR}/{safeName}"); - var ctx = new MarmaladeAssemblyLoadContext(Path.GetDirectoryName(path)); - var a = ctx.LoadFromAssemblyPath(Path.GetFullPath(path)); - var sis = LoadCanariesFromAssembly(a, out services); - typeReaders = LoadTypeReadersFromAssembly(a, strings, services); - - if (sis.Count == 0) - { - return false; - } - - ctxWr = new(ctx); - canaryData = sis; - - return true; - } - - - private static readonly Type _paramParserType = typeof(ParamParser<>); - - [MethodImpl(MethodImplOptions.NoInlining)] - private Dictionary LoadTypeReadersFromAssembly( - Assembly assembly, - IMarmaladeStrings strings, - IServiceProvider services) - { - var paramParsers = assembly.GetExportedTypes() - .Where(x => x.IsClass - && !x.IsAbstract - && x.BaseType is not null - && x.BaseType.IsGenericType - && x.BaseType.GetGenericTypeDefinition() == _paramParserType); - - var typeReaders = new Dictionary(); - foreach (var parserType in paramParsers) - { - var parserObj = ActivatorUtilities.CreateInstance(services, parserType); - - var targetType = parserType.BaseType!.GetGenericArguments()[0]; - var typeReaderInstance = (TypeReader)Activator.CreateInstance( - typeof(ParamParserAdapter<>).MakeGenericType(targetType), - args: new[] { parserObj, strings, services })!; - - typeReaders.Add(targetType, typeReaderInstance); - } - - return typeReaders; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task LoadModuleInternalAsync(string marmaladeName, CanaryInfo canaryInfo, IMarmaladeStrings strings, IServiceProvider services) - { - var module = await _cmdService.CreateModuleAsync(canaryInfo.Instance.Prefix, - CreateModuleFactory(marmaladeName, canaryInfo, strings, services)); - - return module; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private Action CreateModuleFactory( - string marmaladeName, - CanaryInfo canaryInfo, - IMarmaladeStrings strings, - IServiceProvider marmaladeServices) - => mb => - { - var m = mb.WithName(canaryInfo.Name); - - foreach (var f in canaryInfo.Filters) - { - m.AddPrecondition(new FilterAdapter(f, strings)); - } - - foreach (var cmd in canaryInfo.Commands) - { - m.AddCommand(cmd.Aliases.First(), - CreateCallback(cmd.ContextType, - new(canaryInfo), - new(cmd), - new(marmaladeServices), - strings), - CreateCommandFactory(marmaladeName, cmd, strings)); - } - - foreach (var subInfo in canaryInfo.Subcanaries) - m.AddModule(subInfo.Instance.Prefix, CreateModuleFactory(marmaladeName, subInfo, strings, marmaladeServices)); - }; - -#pragma warning disable IDE0090 // Use 'new(...)' - private static readonly RequireContextAttribute _reqGuild = new RequireContextAttribute(ContextType.Guild); - private static readonly RequireContextAttribute _reqDm = new RequireContextAttribute(ContextType.DM); -#pragma warning restore IDE0090 // Use 'new(...)' - private Action CreateCommandFactory(string marmaladeName, CanaryCommandData cmd, IMarmaladeStrings strings) - => (cb) => - { - cb.AddAliases(cmd.Aliases.Skip(1).ToArray()); - - if (cmd.ContextType == CommandContextType.Guild) - cb.AddPrecondition(_reqGuild); - else if (cmd.ContextType == CommandContextType.Dm) - cb.AddPrecondition(_reqDm); - - foreach (var f in cmd.Filters) - cb.AddPrecondition(new FilterAdapter(f, strings)); - - foreach (var ubp in cmd.UserAndBotPerms) - { - if (ubp is user_permAttribute up) - { - if (up.GuildPerm is { } gp) - cb.AddPrecondition(new UserPermAttribute(gp)); - else if (up.ChannelPerm is { } cp) - cb.AddPrecondition(new UserPermAttribute(cp)); - } - else if (ubp is bot_permAttribute bp) - { - if (bp.GuildPerm is { } gp) - cb.AddPrecondition(new BotPermAttribute(gp)); - else if (bp.ChannelPerm is { } cp) - cb.AddPrecondition(new BotPermAttribute(cp)); - } - else if (ubp is bot_owner_onlyAttribute) - { - cb.AddPrecondition(new OwnerOnlyAttribute()); - } - } - - cb.WithPriority(cmd.Priority); - - // using summary to save method name - // method name is used to retrieve desc/usages - cb.WithRemarks($"marmalade///{marmaladeName}"); - cb.WithSummary(cmd.MethodInfo.Name.ToLowerInvariant()); - - foreach (var param in cmd.Parameters) - { - cb.AddParameter(param.Name, param.Type, CreateParamFactory(param)); - } - }; - - private Action CreateParamFactory(ParamData paramData) - => (pb) => - { - pb.WithIsMultiple(paramData.IsParams) - .WithIsOptional(paramData.IsOptional) - .WithIsRemainder(paramData.IsLeftover); - - if (paramData.IsOptional) - pb.WithDefault(paramData.DefaultValue); - }; - - [MethodImpl(MethodImplOptions.NoInlining)] - private Func CreateCallback( - CommandContextType contextType, - WeakReference canaryDataWr, - WeakReference canaryCommandDataWr, - WeakReference marmaladeServicesWr, - IMarmaladeStrings strings) - => async (context, parameters, svcs, _) => - { - if (!canaryCommandDataWr.TryGetTarget(out var cmdData) - || !canaryDataWr.TryGetTarget(out var canaryData) - || !marmaladeServicesWr.TryGetTarget(out var marmaladeServices)) - { - Log.Warning("Attempted to run an unloaded canary's command"); - return; - } - - var paramObjs = ParamObjs(contextType, cmdData, parameters, context, svcs, marmaladeServices, strings); - - try - { - var methodInfo = cmdData.MethodInfo; - if (methodInfo.ReturnType == typeof(Task) - || (methodInfo.ReturnType.IsGenericType - && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))) - { - await (Task)methodInfo.Invoke(canaryData.Instance, paramObjs)!; - } - else if (methodInfo.ReturnType == typeof(ValueTask)) - { - await ((ValueTask)methodInfo.Invoke(canaryData.Instance, paramObjs)!).AsTask(); - } - else // if (methodInfo.ReturnType == typeof(void)) - { - methodInfo.Invoke(canaryData.Instance, paramObjs); - } - } - finally - { - paramObjs = null; - cmdData = null; - - canaryData = null; - marmaladeServices = null; - } - }; - - [MethodImpl(MethodImplOptions.NoInlining)] - private static object[] ParamObjs( - CommandContextType contextType, - CanaryCommandData cmdData, - object[] parameters, - ICommandContext context, - IServiceProvider svcs, - IServiceProvider svcProvider, - IMarmaladeStrings strings) - { - var extraParams = contextType == CommandContextType.Unspecified ? 0 : 1; - extraParams += cmdData.InjectedParams.Count; - - var paramObjs = new object[parameters.Length + extraParams]; - - var startAt = 0; - if (contextType != CommandContextType.Unspecified) - { - paramObjs[0] = ContextAdapterFactory.CreateNew(context, strings, svcs); - - startAt = 1; - } - - for (var i = 0; i < cmdData.InjectedParams.Count; i++) - { - var svc = svcProvider.GetService(cmdData.InjectedParams[i]); - if (svc is null) - { - throw new ArgumentException($"Cannot inject a service of type {cmdData.InjectedParams[i]}"); - } - - paramObjs[i + startAt] = svc; - - svc = null; - } - - startAt += cmdData.InjectedParams.Count; - - for (var i = 0; i < parameters.Length; i++) - paramObjs[startAt + i] = parameters[i]; - - return paramObjs; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task InternalUnloadAsync(string name) - { - if (!_resolved.Remove(name, out var lsi)) - return MarmaladeUnloadResult.NotLoaded; - - await _lock.WaitAsync(); - try - { - UnloadTypeReaders(lsi.TypeReaders); - - foreach (var mi in lsi.ModuleInfos) - { - await _cmdService.RemoveModuleAsync(mi); - } - - await _behHandler.RemoveRangeAsync(lsi.Execs); - - await DisposeCanaryInstances(lsi); - - var lc = lsi.LoadContext; - - // removing this line will prevent assembly from being unloaded quickly - // as this local variable will be held for a long time potentially - // due to how async works - lsi.Services = null!; - lsi = null; - - _marmaladeConfig.RemoveLoadedMarmalade(name); - return UnloadInternal(lc) - ? MarmaladeUnloadResult.Success - : MarmaladeUnloadResult.PossiblyUnable; - } - finally - { - _lock.Release(); - } - } - - private void UnloadTypeReaders(Dictionary valueTypeReaders) - { - foreach (var tr in valueTypeReaders) - { - _cmdService.TryRemoveTypeReader(tr.Key, false, out _); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task DisposeCanaryInstances(ResolvedMarmalade marmalade) - { - foreach (var si in marmalade.CanaryInfos) - { - try - { - await si.Instance.DisposeAsync(); - foreach (var sub in si.Subcanaries) - { - await sub.Instance.DisposeAsync(); - } - } - catch (Exception ex) - { - Log.Warning(ex, - "Failed cleanup of Canary {CanaryName}. This marmalade might not unload correctly", - si.Instance.Name); - } - } - - // marmalades = null; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private bool UnloadInternal(WeakReference lsi) - { - UnloadContext(lsi); - GcCleanup(); - - return !lsi.TryGetTarget(out _); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void UnloadContext(WeakReference lsiLoadContext) - { - if (lsiLoadContext.TryGetTarget(out var ctx)) - ctx.Unload(); - } - - private void GcCleanup() - { - // cleanup - for (var i = 0; i < 10; i++) - { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.WaitForFullGCComplete(); - GC.Collect(); - } - } - - private static readonly Type _canaryType = typeof(Canary); - - [MethodImpl(MethodImplOptions.NoInlining)] - private IServiceProvider LoadMarmaladeServicesInternal(Assembly a) - => new ServiceCollection() - .Scan(x => x.FromAssemblies(a) - .AddClasses(static x => x.WithAttribute(x => x.Lifetime == Lifetime.Transient)) - .AsSelfWithInterfaces() - .WithTransientLifetime() - .AddClasses(static x => x.WithAttribute(x => x.Lifetime == Lifetime.Singleton)) - .AsSelfWithInterfaces() - .WithSingletonLifetime()) - .BuildServiceProvider(); - - - [MethodImpl(MethodImplOptions.NoInlining)] - public IReadOnlyCollection LoadCanariesFromAssembly(Assembly a, out IServiceProvider services) - { - var marmaladeServices = LoadMarmaladeServicesInternal(a); - services = new MarmaladeServiceProvider(_botServices, marmaladeServices); - - // find all types in teh assembly - var types = a.GetExportedTypes(); - // snek is always a public non abstract class - var classes = types.Where(static x => x.IsClass - && (x.IsNestedPublic || x.IsPublic) - && !x.IsAbstract - && x.BaseType == _canaryType - && (x.DeclaringType is null || x.DeclaringType.IsAssignableTo(_canaryType))) - .ToList(); - - var topModules = new Dictionary(); - - foreach (var cl in classes) - { - if (cl.DeclaringType is not null) - continue; - - // get module data, and add it to the topModules dictionary - var module = GetModuleData(cl, services); - topModules.Add(cl, module); - } - - foreach (var c in classes) - { - if (c.DeclaringType is not Type dt) - continue; - - // if there is no top level module which this module is a child of - // just print a warning and skip it - if (!topModules.TryGetValue(dt, out var parentData)) - { - Log.Warning("Can't load submodule {SubName} because parent module {Name} does not exist", - c.Name, - dt.Name); - continue; - } - - GetModuleData(c, services, parentData); - } - - return topModules.Values.ToArray(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private CanaryInfo GetModuleData(Type type, IServiceProvider services, CanaryInfo? parentData = null) - { - var filters = type.GetCustomAttributes(true) - .ToArray(); - - var instance = (Canary)ActivatorUtilities.CreateInstance(services, type); - - var module = new CanaryInfo(instance.Name, - parentData, - instance, - GetCommands(instance, type), - filters); - - if (parentData is not null) - parentData.Subcanaries.Add(module); - - return module; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private IReadOnlyCollection GetCommands(Canary instance, Type type) - { - var methodInfos = type - .GetMethods(BindingFlags.Instance - | BindingFlags.DeclaredOnly - | BindingFlags.Public) - .Where(static x => - { - if (x.GetCustomAttribute(true) is null) - return false; - - if (x.ReturnType.IsGenericType) - { - var genericType = x.ReturnType.GetGenericTypeDefinition(); - if (genericType == typeof(Task<>)) - return true; - - // if (genericType == typeof(ValueTask<>)) - // return true; - - Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", - x.Name, - x.ReturnType); - - return false; - } - - var succ = x.ReturnType == typeof(Task) - || x.ReturnType == typeof(ValueTask) - || x.ReturnType == typeof(void); - - if (!succ) - { - Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", - x.Name, - x.ReturnType); - } - - return succ; - }); - - - var cmds = new List(); - foreach (var method in methodInfos) - { - var filters = method.GetCustomAttributes(true).ToArray(); - var userAndBotPerms = method.GetCustomAttributes(true) - .ToArray(); - var prio = method.GetCustomAttribute(true)?.Priority ?? 0; - - var paramInfos = method.GetParameters(); - var cmdParams = new List(); - var diParams = new List(); - var cmdContext = CommandContextType.Unspecified; - var canInject = false; - for (var paramCounter = 0; paramCounter < paramInfos.Length; paramCounter++) - { - var pi = paramInfos[paramCounter]; - - var paramName = pi.Name ?? "unnamed"; - var isContext = paramCounter == 0 && pi.ParameterType.IsAssignableTo(typeof(AnyContext)); - - var leftoverAttribute = pi.GetCustomAttribute(true); - var hasDefaultValue = pi.HasDefaultValue; - var defaultValue = pi.DefaultValue; - var isLeftover = leftoverAttribute != null; - var isParams = pi.GetCustomAttribute() is not null; - var paramType = pi.ParameterType; - var isInjected = pi.GetCustomAttribute(true) is not null; - - if (isContext) - { - if (hasDefaultValue || leftoverAttribute != null || isParams) - throw new ArgumentException("IContext parameter cannot be optional, leftover, constant or params. " + GetErrorPath(method, pi)); - - if (paramCounter != 0) - throw new ArgumentException($"IContext parameter has to be first. {GetErrorPath(method, pi)}"); - - canInject = true; - - if (paramType.IsAssignableTo(typeof(GuildContext))) - cmdContext = CommandContextType.Guild; - else if (paramType.IsAssignableTo(typeof(DmContext))) - cmdContext = CommandContextType.Dm; - else - cmdContext = CommandContextType.Any; - - continue; - } - - if (isInjected) - { - if (!canInject && paramCounter != 0) - throw new ArgumentException($"Parameters marked as [Injected] have to come after IContext"); - - canInject = true; - - diParams.Add(paramType); - continue; - } - - canInject = false; - - if (isParams) - { - if (hasDefaultValue) - throw new NotSupportedException("Params can't have const values at the moment. " - + GetErrorPath(method, pi)); - // if it's params, it means it's an array, and i only need a parser for the actual type, - // as the parser will run on each array element, it can't be null - paramType = paramType.GetElementType()!; - } - - // leftover can only be the last parameter. - if (isLeftover && paramCounter != paramInfos.Length - 1) - { - var path = GetErrorPath(method, pi); - Log.Error("Only one parameter can be marked [Leftover] and it has to be the last one. {Path} ", - path); - throw new ArgumentException("Leftover attribute error."); - } - - cmdParams.Add(new ParamData(paramType, paramName, hasDefaultValue, defaultValue, isLeftover, isParams)); - } - - - var cmdAttribute = method.GetCustomAttribute(true)!; - var aliases = cmdAttribute.Aliases; - if (aliases.Length == 0) - aliases = new[] { method.Name.ToLowerInvariant() }; - - cmds.Add(new( - aliases, - method, - instance, - filters, - userAndBotPerms, - cmdContext, - diParams, - cmdParams, - new(cmdAttribute.desc, cmdAttribute.args), - prio - )); - } - - return cmds; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private string GetErrorPath(MethodInfo m, System.Reflection.ParameterInfo pi) - => $@"Module: {m.DeclaringType?.Name} -Command: {m.Name} -ParamName: {pi.Name} -ParamType: {pi.ParameterType.Name}"; -} - -public enum MarmaladeLoadResult -{ - Success, - NotFound, - AlreadyLoaded, - Empty, - UnknownError, -} - -public enum MarmaladeUnloadResult -{ - Success, - NotLoaded, - PossiblyUnable, - NotFound, -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs b/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs deleted file mode 100644 index c2f3c76..0000000 --- a/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Ellie.Marmalade; - -public class MarmaladeServiceProvider : IServiceProvider -{ - private readonly IServiceProvider _ellieServices; - private readonly IServiceProvider _marmaladeServices; - - public MarmaladeServiceProvider(IServiceProvider ellieServices, IServiceProvider marmaladeServices) - { - _ellieServices = ellieServices; - _marmaladeServices = marmaladeServices; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public object? GetService(Type serviceType) - { - if (!serviceType.Assembly.IsCollectible) - return _ellieServices.GetService(serviceType); - - return _marmaladeServices.GetService(serviceType); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs b/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs deleted file mode 100644 index 412243d..0000000 --- a/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.VisualBasic; -using System.Reflection; -using CommandStrings = Ellie.Marmalade.CommandStrings; - -namespace Ellie.Marmalade; - -public sealed class CanaryCommandData -{ - public CanaryCommandData( - IReadOnlyCollection aliases, - MethodInfo methodInfo, - Canary module, - FilterAttribute[] filters, - MarmaladePermAttribute[] userAndBotPerms, - CommandContextType contextType, - IReadOnlyList injectedParams, - IReadOnlyList parameters, - CommandStrings strings, - int priority) - { - Aliases = aliases; - MethodInfo = methodInfo; - Module = module; - Filters = filters; - UserAndBotPerms = userAndBotPerms; - ContextType = contextType; - InjectedParams = injectedParams; - Parameters = parameters; - Priority = priority; - OptionalStrings = strings; - } - - public MarmaladePermAttribute[] UserAndBotPerms { get; set; } - - public CommandStrings OptionalStrings { get; set; } - - public IReadOnlyCollection Aliases { get; } - public MethodInfo MethodInfo { get; set; } - public Canary Module { get; set; } - public FilterAttribute[] Filters { get; set; } - public CommandContextType ContextType { get; } - public IReadOnlyList InjectedParams { get; } - public IReadOnlyList Parameters { get; } - public int Priority { get; } - -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/CanaryData.cs b/src/EllieBot/Common/Marmalade/Models/CanaryData.cs deleted file mode 100644 index b3938e7..0000000 --- a/src/EllieBot/Common/Marmalade/Models/CanaryData.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ellie.Marmalade; - -public sealed record CanaryInfo( - string Name, - CanaryInfo? Parent, - Canary Instance, - IReadOnlyCollection Commands, - IReadOnlyCollection Filters) -{ - public List Subcanaries { get; set; } = new(); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/ParamData.cs b/src/EllieBot/Common/Marmalade/Models/ParamData.cs deleted file mode 100644 index e329958..0000000 --- a/src/EllieBot/Common/Marmalade/Models/ParamData.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ellie.Marmalade; - -public sealed record ParamData( - Type Type, - string Name, - bool IsOptional, - object? DefaultValue, - bool IsLeftover, - bool IsParams -); \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs b/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs deleted file mode 100644 index bf40d7a..0000000 --- a/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Immutable; - -namespace Ellie.Marmalade; - -public sealed record ResolvedMarmalade( - WeakReference LoadContext, - IImmutableList ModuleInfos, - IImmutableList CanaryInfos, - IMarmaladeStrings Strings, - Dictionary TypeReaders, - IReadOnlyCollection Execs) -{ - public IServiceProvider Services { get; set; } = null!; -} \ No newline at end of file diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs deleted file mode 100644 index a73a7a7..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// Executed if no command was found for this message -/// -public interface IExecNoCommand -{ - /// - /// Executed at the end of the lifecycle if no command was found - /// → - /// → - /// → - /// [ | **] - /// - /// - /// - /// A task representing completion - Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg); -} \ No newline at end of file diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs b/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs deleted file mode 100644 index eade8d5..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// Implemented by modules to handle non-bot messages received -/// -public interface IExecOnMessage -{ - int Priority { get; } - - /// - /// Ran after a non-bot message was received - /// ** → - /// → - /// → - /// [ | ] - /// - /// Guild where the message was sent - /// The message that was received - /// Whether further processing of this message should be blocked - Task ExecOnMessageAsync(IGuild guild, IUserMessage msg); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs deleted file mode 100644 index 4f79c31..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// This interface's method is executed after the command successfully finished execution. -/// ***There is no support for this method in EllieBot services.*** -/// It is only meant to be used in marmalade system -/// -public interface IExecPostCommand -{ - /// - /// Executed after a command was successfully executed - /// → - /// → - /// → - /// [** | ] - /// - /// Command context - /// Module name - /// Command name - /// A task representing completion - ValueTask ExecPostCommandAsync(ICommandContext ctx, string moduleName, string commandName); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs deleted file mode 100644 index dc14cdd..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// This interface's method is executed after a command was found but before it was executed. -/// Able to block further processing of a command -/// -public interface IExecPreCommand -{ - public int Priority { get; } - - /// - /// - /// Ran after a command was found but before execution. - /// - /// → - /// → - /// ** → - /// [ | ] - /// - /// Command context - /// Name of the module - /// Command info - /// Whether further processing of the command is blocked - Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs b/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs deleted file mode 100644 index 90ae000..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// Implemented by services which may transform input before a command is searched for -/// -public interface IInputTransformer -{ - /// - /// Ran after a non-bot message was received - /// -> - /// ** -> - /// -> - /// [ OR ] - /// - /// Guild - /// Channel in which the message was sent - /// User who sent the message - /// Content of the message - /// New input, if any, otherwise null - Task TransformInput( - IGuild guild, - IMessageChannel channel, - IUser user, - string input); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs b/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs deleted file mode 100644 index 9ae8211..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// All services which need to execute something after -/// the bot is ready should implement this interface -/// -public interface IReadyExecutor -{ - /// - /// Executed when bot is ready - /// - public Task OnReadyAsync(); -} diff --git a/src/EllieBot/Common/PubSub/EventPubSub.cs b/src/EllieBot/Common/PubSub/EventPubSub.cs deleted file mode 100644 index 0e45ed8..0000000 --- a/src/EllieBot/Common/PubSub/EventPubSub.cs +++ /dev/null @@ -1,80 +0,0 @@ -namespace EllieBot.Common; - -public class EventPubSub : IPubSub -{ - private readonly Dictionary>>> _actions = new(); - private readonly object _locker = new(); - - public Task Sub(in TypedKey key, Func action) - where TData : notnull - { - Func localAction = obj => action((TData)obj); - lock (_locker) - { - if (!_actions.TryGetValue(key.Key, out var keyActions)) - { - keyActions = new(); - _actions[key.Key] = keyActions; - } - - if (!keyActions.TryGetValue(action, out var sameActions)) - { - sameActions = new(); - keyActions[action] = sameActions; - } - - sameActions.Add(localAction); - - return Task.CompletedTask; - } - } - - public Task Pub(in TypedKey key, TData data) - where TData : notnull - { - lock (_locker) - { - if (_actions.TryGetValue(key.Key, out var actions)) - // if this class ever gets used, this needs to be properly implemented - // 1. ignore all valuetasks which are completed - // 2. run all other tasks in parallel - return actions.SelectMany(kvp => kvp.Value).Select(action => action(data).AsTask()).WhenAll(); - - return Task.CompletedTask; - } - } - - public Task Unsub(in TypedKey key, Func action) - { - lock (_locker) - { - // get subscriptions for this action - if (_actions.TryGetValue(key.Key, out var actions)) - // get subscriptions which have the same action hash code - // note: having this as a list allows for multiple subscriptions of - // the same insance's/static method - { - if (actions.TryGetValue(action, out var sameActions)) - { - // remove last subscription - sameActions.RemoveAt(sameActions.Count - 1); - - // if the last subscription was the only subscription - // we can safely remove this action's dictionary entry - if (sameActions.Count == 0) - { - actions.Remove(action); - - // if our dictionary has no more elements after - // removing the entry - // it's safe to remove it from the key's subscriptions - if (actions.Count == 0) - _actions.Remove(key.Key); - } - } - } - - return Task.CompletedTask; - } - } -} diff --git a/src/EllieBot/Common/PubSub/IPubSub.cs b/src/EllieBot/Common/PubSub/IPubSub.cs deleted file mode 100644 index 0d52156..0000000 --- a/src/EllieBot/Common/PubSub/IPubSub.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EllieBot.Common; - -public interface IPubSub -{ - public Task Pub(in TypedKey key, TData data) - where TData : notnull; - - public Task Sub(in TypedKey key, Func action) - where TData : notnull; -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/ISeria.cs b/src/EllieBot/Common/PubSub/ISeria.cs deleted file mode 100644 index 0eb9706..0000000 --- a/src/EllieBot/Common/PubSub/ISeria.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EllieBot.Common; - -public interface ISeria -{ - byte[] Serialize(T data); - T? Deserialize(byte[]? data); -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/JsonSeria.cs b/src/EllieBot/Common/PubSub/JsonSeria.cs deleted file mode 100644 index b8f8033..0000000 --- a/src/EllieBot/Common/PubSub/JsonSeria.cs +++ /dev/null @@ -1,27 +0,0 @@ -using EllieBot.Common.JsonConverters; -using System.Text.Json; - -namespace EllieBot.Common; - -public class JsonSeria : ISeria -{ - private readonly JsonSerializerOptions _serializerOptions = new() - { - Converters = - { - new Rgba32Converter(), - new CultureInfoConverter() - } - }; - - public byte[] Serialize(T data) - => JsonSerializer.SerializeToUtf8Bytes(data, _serializerOptions); - - public T? Deserialize(byte[]? data) - { - if (data is null) - return default; - - return JsonSerializer.Deserialize(data, _serializerOptions); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/RedisPubSub.cs b/src/EllieBot/Common/PubSub/RedisPubSub.cs deleted file mode 100644 index 82d8a99..0000000 --- a/src/EllieBot/Common/PubSub/RedisPubSub.cs +++ /dev/null @@ -1,52 +0,0 @@ -using StackExchange.Redis; - -namespace EllieBot.Common; - -public sealed class RedisPubSub : IPubSub -{ - private readonly IBotCredentials _creds; - private readonly ConnectionMultiplexer _multi; - private readonly ISeria _serializer; - - public RedisPubSub(ConnectionMultiplexer multi, ISeria serializer, IBotCredentials creds) - { - _multi = multi; - _serializer = serializer; - _creds = creds; - } - - public Task Pub(in TypedKey key, TData data) - where TData : notnull - { - var serialized = _serializer.Serialize(data); - return _multi.GetSubscriber() - .PublishAsync($"{_creds.RedisKey()}:{key.Key}", serialized, CommandFlags.FireAndForget); - } - - public Task Sub(in TypedKey key, Func action) - where TData : notnull - { - var eventName = key.Key; - - async void OnSubscribeHandler(RedisChannel _, RedisValue data) - { - try - { - var dataObj = _serializer.Deserialize(data); - if (dataObj is not null) - await action(dataObj); - else - { - Log.Warning("Publishing event {EventName} with a null value. This is not allowed", - eventName); - } - } - catch (Exception ex) - { - Log.Error("Error handling the event {EventName}: {ErrorMessage}", eventName, ex.Message); - } - } - - return _multi.GetSubscriber().SubscribeAsync($"{_creds.RedisKey()}:{eventName}", OnSubscribeHandler); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/TypedKey.cs b/src/EllieBot/Common/PubSub/TypedKey.cs deleted file mode 100644 index e637707..0000000 --- a/src/EllieBot/Common/PubSub/TypedKey.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace EllieBot.Common; - -public readonly struct TypedKey -{ - public string Key { get; } - - public TypedKey(in string key) - => Key = key; - - public static implicit operator TypedKey(in string input) - => new(input); - - public static implicit operator string(in TypedKey input) - => input.Key; - - public static bool operator ==(in TypedKey left, in TypedKey right) - => left.Key == right.Key; - - public static bool operator !=(in TypedKey left, in TypedKey right) - => !(left == right); - - public override bool Equals(object? obj) - => obj is TypedKey o && o == this; - - public override int GetHashCode() - => Key?.GetHashCode() ?? 0; - - public override string ToString() - => Key; -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/YamlSeria.cs b/src/EllieBot/Common/PubSub/YamlSeria.cs deleted file mode 100644 index 2feb5c8..0000000 --- a/src/EllieBot/Common/PubSub/YamlSeria.cs +++ /dev/null @@ -1,39 +0,0 @@ -using EllieBot.Common.Configs; -using EllieBot.Common.Yml; -using System.Text.RegularExpressions; -using YamlDotNet.Serialization; - -namespace EllieBot.Common; - -public class YamlSeria : IConfigSeria -{ - private static readonly Regex _codePointRegex = - new(@"(\\U(?[a-zA-Z0-9]{8})|\\u(?[a-zA-Z0-9]{4})|\\x(?[a-zA-Z0-9]{2}))", - RegexOptions.Compiled); - - private readonly IDeserializer _deserializer; - private readonly ISerializer _serializer; - - public YamlSeria() - { - _serializer = Yaml.Serializer; - _deserializer = Yaml.Deserializer; - } - - public string Serialize(T obj) - where T : notnull - { - var escapedOutput = _serializer.Serialize(obj); - var output = _codePointRegex.Replace(escapedOutput, - me => - { - var str = me.Groups["code"].Value; - var newString = YamlHelper.UnescapeUnicodeCodePoint(str); - return newString; - }); - return output; - } - - public T Deserialize(string data) - => _deserializer.Deserialize(data); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/CommentAttribute.cs b/src/EllieBot/Common/Yml/CommentAttribute.cs deleted file mode 100644 index 9d3d7ec..0000000 --- a/src/EllieBot/Common/Yml/CommentAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Common.Yml; - -[AttributeUsage(AttributeTargets.Property)] -public class CommentAttribute : Attribute -{ - public string Comment { get; } - - public CommentAttribute(string comment) - => Comment = comment; -} diff --git a/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs b/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs deleted file mode 100644 index 1a81978..0000000 --- a/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs +++ /dev/null @@ -1,65 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.TypeInspectors; - -namespace EllieBot.Common.Yml; - -public class CommentGatheringTypeInspector : TypeInspectorSkeleton -{ - private readonly ITypeInspector _innerTypeDescriptor; - - public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor) - => _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor)); - - public override IEnumerable GetProperties(Type type, object container) - => _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d)); - - private sealed class CommentsPropertyDescriptor : IPropertyDescriptor - { - public string Name { get; } - - public Type Type - => _baseDescriptor.Type; - - public Type TypeOverride - { - get => _baseDescriptor.TypeOverride; - set => _baseDescriptor.TypeOverride = value; - } - - public int Order { get; set; } - - public ScalarStyle ScalarStyle - { - get => _baseDescriptor.ScalarStyle; - set => _baseDescriptor.ScalarStyle = value; - } - - public bool CanWrite - => _baseDescriptor.CanWrite; - - private readonly IPropertyDescriptor _baseDescriptor; - - public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor) - { - _baseDescriptor = baseDescriptor; - Name = baseDescriptor.Name; - } - - public void Write(object target, object value) - => _baseDescriptor.Write(target, value); - - public T GetCustomAttribute() - where T : Attribute - => _baseDescriptor.GetCustomAttribute(); - - public IObjectDescriptor Read(object target) - { - var comment = _baseDescriptor.GetCustomAttribute(); - return comment is not null - ? new CommentsObjectDescriptor(_baseDescriptor.Read(target), comment.Comment) - : _baseDescriptor.Read(target); - } - } -} diff --git a/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs b/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs deleted file mode 100644 index 9dc61f9..0000000 --- a/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Yml; - -public sealed class CommentsObjectDescriptor : IObjectDescriptor -{ - public string Comment { get; } - - public object Value - => _innerDescriptor.Value; - - public Type Type - => _innerDescriptor.Type; - - public Type StaticType - => _innerDescriptor.StaticType; - - public ScalarStyle ScalarStyle - => _innerDescriptor.ScalarStyle; - - private readonly IObjectDescriptor _innerDescriptor; - - public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment) - { - _innerDescriptor = innerDescriptor; - Comment = comment; - } -} diff --git a/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs b/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs deleted file mode 100644 index 1c89a95..0000000 --- a/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs +++ /dev/null @@ -1,29 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.ObjectGraphVisitors; - -namespace EllieBot.Common.Yml; - -public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor -{ - public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) - : base(nextVisitor) - { - } - - public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) - { - if (value is CommentsObjectDescriptor commentsDescriptor - && !string.IsNullOrWhiteSpace(commentsDescriptor.Comment)) - { - var parts = commentsDescriptor.Comment.Split('\n'); - - foreach (var part in parts) - context.Emit(new Comment(part.Trim(), false)); - } - - return base.EnterMapping(key, value, context); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs b/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs deleted file mode 100644 index cf9e15f..0000000 --- a/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.EventEmitters; - -namespace EllieBot.Common.Yml; - -public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter -{ - public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter) - : base(nextEmitter) - { - } - - public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) - { - if (typeof(string).IsAssignableFrom(eventInfo.Source.Type)) - { - var value = eventInfo.Source.Value as string; - if (!string.IsNullOrEmpty(value)) - { - var isMultiLine = value.IndexOfAny(new[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0; - if (isMultiLine) - { - eventInfo = new(eventInfo.Source) - { - Style = ScalarStyle.Literal - }; - } - } - } - - nextEmitter.Emit(eventInfo, emitter); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/Rgba32Converter.cs b/src/EllieBot/Common/Yml/Rgba32Converter.cs deleted file mode 100644 index 12f6cf9..0000000 --- a/src/EllieBot/Common/Yml/Rgba32Converter.cs +++ /dev/null @@ -1,47 +0,0 @@ -#nullable disable -using SixLabors.ImageSharp.PixelFormats; -using System.Globalization; -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Yml; - -public class Rgba32Converter : IYamlTypeConverter -{ - public bool Accepts(Type type) - => type == typeof(Rgba32); - - public object ReadYaml(IParser parser, Type type) - { - var scalar = parser.Consume(); - var result = Rgba32.ParseHex(scalar.Value); - return result; - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var color = (Rgba32)value; - var val = (uint)((color.B << 0) | (color.G << 8) | (color.R << 16)); - emitter.Emit(new Scalar(val.ToString("X6").ToLower())); - } -} - -public class CultureInfoConverter : IYamlTypeConverter -{ - public bool Accepts(Type type) - => type == typeof(CultureInfo); - - public object ReadYaml(IParser parser, Type type) - { - var scalar = parser.Consume(); - var result = new CultureInfo(scalar.Value); - return result; - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var ci = (CultureInfo)value; - emitter.Emit(new Scalar(ci.Name)); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/UriConverter.cs b/src/EllieBot/Common/Yml/UriConverter.cs deleted file mode 100644 index 66e2ca0..0000000 --- a/src/EllieBot/Common/Yml/UriConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Yml; - -public class UriConverter : IYamlTypeConverter -{ - public bool Accepts(Type type) - => type == typeof(Uri); - - public object ReadYaml(IParser parser, Type type) - { - var scalar = parser.Consume(); - var result = new Uri(scalar.Value); - return result; - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var uri = (Uri)value; - emitter.Emit(new Scalar(uri.ToString())); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/Yaml.cs b/src/EllieBot/Common/Yml/Yaml.cs deleted file mode 100644 index 2c65698..0000000 --- a/src/EllieBot/Common/Yml/Yaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -#nullable disable -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.NamingConventions; - -namespace EllieBot.Common.Yml; - -public class Yaml -{ - public static ISerializer Serializer - => new SerializerBuilder().WithTypeInspector(inner => new CommentGatheringTypeInspector(inner)) - .WithEmissionPhaseObjectGraphVisitor(args - => new CommentsObjectGraphVisitor(args.InnerVisitor)) - .WithEventEmitter(args => new MultilineScalarFlowStyleEmitter(args)) - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithIndentedSequences() - .WithTypeConverter(new Rgba32Converter()) - .WithTypeConverter(new CultureInfoConverter()) - .WithTypeConverter(new UriConverter()) - .Build(); - - public static IDeserializer Deserializer - => new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithTypeConverter(new Rgba32Converter()) - .WithTypeConverter(new CultureInfoConverter()) - .WithTypeConverter(new UriConverter()) - .IgnoreUnmatchedProperties() - .Build(); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/YamlHelper.cs b/src/EllieBot/Common/Yml/YamlHelper.cs deleted file mode 100644 index 25dbfd6..0000000 --- a/src/EllieBot/Common/Yml/YamlHelper.cs +++ /dev/null @@ -1,48 +0,0 @@ -#nullable disable -namespace EllieBot.Common.Yml; - -public class YamlHelper -{ - // https://github.com/aaubry/YamlDotNet/blob/0f4cc205e8b2dd8ef6589d96de32bf608a687c6f/YamlDotNet/Core/Scanner.cs#L1687 - /// - /// This is modified code from yamldotnet's repo which handles parsing unicode code points - /// it is needed as yamldotnet doesn't support unescaped unicode characters - /// - /// Unicode code point - /// Actual character - public static string UnescapeUnicodeCodePoint(string point) - { - var character = 0; - - // Scan the character value. - - foreach (var c in point) - { - if (!IsHex(c)) - return point; - - character = (character << 4) + AsHex(c); - } - - // Check the value and write the character. - - if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF) - return point; - - return char.ConvertFromUtf32(character); - } - - public static bool IsHex(char c) - => c is (>= '0' and <= '9') or (>= 'A' and <= 'F') or (>= 'a' and <= 'f'); - - public static int AsHex(char c) - { - if (c <= '9') - return c - '0'; - - if (c <= 'F') - return c - 'A' + 10; - - return c - 'a' + 10; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs deleted file mode 100644 index b5fffda..0000000 --- a/src/EllieBot/Db/EllieContext.cs +++ /dev/null @@ -1,491 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using EllieBot.Db.Models; -using EllieBot.Services.Database.Models; - -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace EllieBot.Services.Database; - -public abstract class EllieContext : DbContext -{ - public DbSet GuildConfigs { get; set; } - - public DbSet Quotes { get; set; } - public DbSet Reminders { get; set; } - public DbSet SelfAssignableRoles { get; set; } - public DbSet MusicPlaylists { get; set; } - public DbSet Expressions { get; set; } - public DbSet CurrencyTransactions { get; set; } - public DbSet WaifuUpdates { get; set; } - public DbSet WaifuItem { get; set; } - public DbSet Warnings { get; set; } - public DbSet UserXpStats { get; set; } - public DbSet Clubs { get; set; } - public DbSet ClubBans { get; set; } - public DbSet ClubApplicants { get; set; } - - - //logging - public DbSet LogSettings { get; set; } - public DbSet IgnoredVoicePresenceCHannels { get; set; } - public DbSet IgnoredLogChannels { get; set; } - - public DbSet RotatingStatus { get; set; } - public DbSet Blacklist { get; set; } - public DbSet AutoCommands { get; set; } - public DbSet RewardedUsers { get; set; } - public DbSet PlantedCurrency { get; set; } - public DbSet BanTemplates { get; set; } - public DbSet DiscordPermOverrides { get; set; } - public DbSet DiscordUser { get; set; } - public DbSet MusicPlayerSettings { get; set; } - public DbSet Repeaters { get; set; } - public DbSet Poll { get; set; } - public DbSet WaifuInfo { get; set; } - public DbSet ImageOnlyChannels { get; set; } - public DbSet NsfwBlacklistedTags { get; set; } - public DbSet AutoTranslateChannels { get; set; } - public DbSet AutoTranslateUsers { get; set; } - - public DbSet Permissions { get; set; } - - public DbSet BankUsers { get; set; } - - public DbSet ReactionRoles { get; set; } - - public DbSet Patrons { get; set; } - - public DbSet PatronQuotas { get; set; } - - public DbSet StreamOnlineMessages { get; set; } - - - #region Mandatory Provider-Specific Values - - protected abstract string CurrencyTransactionOtherIdDefaultValue { get; } - - #endregion - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - #region QUOTES - - var quoteEntity = modelBuilder.Entity(); - quoteEntity.HasIndex(x => x.GuildId); - quoteEntity.HasIndex(x => x.Keyword); - - #endregion - - #region GuildConfig - - var configEntity = modelBuilder.Entity(); - configEntity.HasIndex(c => c.GuildId) - .IsUnique(); - - configEntity.Property(x => x.VerboseErrors) - .HasDefaultValue(true); - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting); - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting); - - modelBuilder.Entity() - .HasOne(x => x.AntiAltSetting) - .WithOne() - .HasForeignKey(x => x.GuildConfigId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasAlternateKey(x => new - { - x.GuildConfigId, - x.Url - }); - - modelBuilder.Entity().HasIndex(x => x.MessageId).IsUnique(); - - modelBuilder.Entity().HasIndex(x => x.ChannelId); - - configEntity.HasIndex(x => x.WarnExpireHours).IsUnique(false); - - #endregion - - #region streamrole - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole); - - #endregion - - #region Self Assignable Roles - - var selfassignableRolesEntity = modelBuilder.Entity(); - - selfassignableRolesEntity.HasIndex(s => new - { - s.GuildId, - s.RoleId - }) - .IsUnique(); - - selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0); - - #endregion - - #region MusicPlaylists - - var musicPlaylistEntity = modelBuilder.Entity(); - - musicPlaylistEntity.HasMany(p => p.Songs).WithOne().OnDelete(DeleteBehavior.Cascade); - - #endregion - - #region Waifus - - var wi = modelBuilder.Entity(); - wi.HasOne(x => x.Waifu).WithOne(); - - wi.HasIndex(x => x.Price); - wi.HasIndex(x => x.ClaimerId); - // wi.HasMany(x => x.Items) - // .WithOne() - // .OnDelete(DeleteBehavior.Cascade); - - #endregion - - #region DiscordUser - - modelBuilder.Entity(du => - { - du.Property(x => x.IsClubAdmin) - .HasDefaultValue(false); - - du.Property(x => x.NotifyOnLevelUp) - .HasDefaultValue(XpNotificationLocation.None); - - du.Property(x => x.TotalXp) - .HasDefaultValue(0); - - du.Property(x => x.CurrencyAmount) - .HasDefaultValue(0); - - du.HasAlternateKey(w => w.UserId); - du.HasOne(x => x.Club) - .WithMany(x => x.Members) - .IsRequired(false) - .OnDelete(DeleteBehavior.NoAction); - - du.HasIndex(x => x.TotalXp); - du.HasIndex(x => x.CurrencyAmount); - du.HasIndex(x => x.UserId); - }); - - #endregion - - #region Warnings - - modelBuilder.Entity(warn => - { - warn.HasIndex(x => x.GuildId); - warn.HasIndex(x => x.UserId); - warn.HasIndex(x => x.DateAdded); - warn.Property(x => x.Weight).HasDefaultValue(1); - }); - - #endregion - - #region XpStats - - var xps = modelBuilder.Entity(); - xps.HasIndex(x => new - { - x.UserId, - x.GuildId - }) - .IsUnique(); - - xps.HasIndex(x => x.UserId); - xps.HasIndex(x => x.GuildId); - xps.HasIndex(x => x.Xp); - xps.HasIndex(x => x.AwardedXp); - - #endregion - - #region XpSettings - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings); - - #endregion - - #region XpRoleReward - - modelBuilder.Entity() - .HasIndex(x => new - { - x.XpSettingsId, - x.Level - }) - .IsUnique(); - - #endregion - - #region Club - - var ci = modelBuilder.Entity(); - ci.HasOne(x => x.Owner) - .WithOne() - .HasForeignKey(x => x.OwnerId) - .OnDelete(DeleteBehavior.SetNull); - - ci.HasAlternateKey(x => new - { - x.Name - }); - - #endregion - - #region ClubManytoMany - - modelBuilder.Entity() - .HasKey(t => new - { - t.ClubId, - t.UserId - }); - - modelBuilder.Entity() - .HasOne(pt => pt.User) - .WithMany(); - - modelBuilder.Entity() - .HasOne(pt => pt.Club) - .WithMany(x => x.Applicants); - - modelBuilder.Entity() - .HasKey(t => new - { - t.ClubId, - t.UserId - }); - - modelBuilder.Entity() - .HasOne(pt => pt.User) - .WithMany(); - - modelBuilder.Entity() - .HasOne(pt => pt.Club) - .WithMany(x => x.Bans); - - #endregion - - #region Polls - - modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); - - #endregion - - #region CurrencyTransactions - - modelBuilder.Entity(e => - { - e.HasIndex(x => x.UserId) - .IsUnique(false); - - e.Property(x => x.OtherId) - .HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue); - - e.Property(x => x.Type) - .IsRequired(); - - e.Property(x => x.Extra) - .IsRequired(); - }); - - #endregion - - #region Reminders - - modelBuilder.Entity().HasIndex(x => x.When); - - #endregion - - #region GroupName - - modelBuilder.Entity() - .HasIndex(x => new - { - x.GuildConfigId, - x.Number - }) - .IsUnique(); - - modelBuilder.Entity() - .HasOne(x => x.GuildConfig) - .WithMany(x => x.SelfAssignableRoleGroupNames) - .IsRequired(); - - #endregion - - #region BanTemplate - - modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); - modelBuilder.Entity() - .Property(x => x.PruneDays) - .HasDefaultValue(null) - .IsRequired(false); - - #endregion - - #region Perm Override - - modelBuilder.Entity() - .HasIndex(x => new - { - x.GuildId, - x.Command - }) - .IsUnique(); - - #endregion - - #region Music - - modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); - - modelBuilder.Entity().Property(x => x.Volume).HasDefaultValue(100); - - #endregion - - #region Reaction roles - - modelBuilder.Entity(rr2 => - { - rr2.HasIndex(x => x.GuildId) - .IsUnique(false); - - rr2.HasIndex(x => new - { - x.MessageId, - x.Emote - }) - .IsUnique(); - }); - - #endregion - - #region LogSettings - - modelBuilder.Entity(ls => ls.HasIndex(x => x.GuildId).IsUnique()); - - modelBuilder.Entity(ls => ls - .HasMany(x => x.LogIgnores) - .WithOne(x => x.LogSetting) - .OnDelete(DeleteBehavior.Cascade)); - - modelBuilder.Entity(ili => ili - .HasIndex(x => new - { - x.LogSettingId, - x.LogItemId, - x.ItemType - }) - .IsUnique()); - - #endregion - - modelBuilder.Entity(ioc => ioc.HasIndex(x => x.ChannelId).IsUnique()); - - modelBuilder.Entity(nbt => nbt.HasIndex(x => x.GuildId).IsUnique(false)); - - var atch = modelBuilder.Entity(); - atch.HasIndex(x => x.GuildId).IsUnique(false); - - atch.HasIndex(x => x.ChannelId).IsUnique(); - - atch.HasMany(x => x.Users).WithOne(x => x.Channel).OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity(atu => atu.HasAlternateKey(x => new - { - x.ChannelId, - x.UserId - })); - - #region BANK - - modelBuilder.Entity(bu => bu.HasIndex(x => x.UserId).IsUnique()); - - #endregion - - - #region Patron - - // currency rewards - var pr = modelBuilder.Entity(); - pr.HasIndex(x => x.PlatformUserId).IsUnique(); - - // patrons - // patrons are not identified by their user id, but by their platform user id - // as multiple accounts (even maybe on different platforms) could have - // the same account connected to them - modelBuilder.Entity(pu => - { - pu.HasIndex(x => x.UniquePlatformUserId).IsUnique(); - pu.HasKey(x => x.UserId); - }); - - // quotes are per user id - modelBuilder.Entity(pq => - { - pq.HasIndex(x => x.UserId).IsUnique(false); - pq.HasKey(x => new - { - x.UserId, - x.FeatureType, - x.Feature - }); - }); - - #endregion - - #region Xp Item Shop - - modelBuilder.Entity( - x => - { - // user can own only one of each item - x.HasIndex(model => new - { - model.UserId, - model.ItemType, - model.ItemKey - }) - .IsUnique(); - }); - - #endregion - - #region AutoPublish - - modelBuilder.Entity(apc => apc - .HasIndex(x => x.GuildId) - .IsUnique()); - - #endregion - - #region GamblingStats - - modelBuilder.Entity(gs => gs - .HasIndex(x => x.Feature) - .IsUnique()); - - #endregion - } - -#if DEBUG - private static readonly ILoggerFactory _debugLoggerFactory = LoggerFactory.Create(x => x.AddConsole()); - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseLoggerFactory(_debugLoggerFactory); -#endif -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ClubExtensions.cs b/src/EllieBot/Db/Extensions/ClubExtensions.cs deleted file mode 100644 index 88a851b..0000000 --- a/src/EllieBot/Db/Extensions/ClubExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; - -namespace EllieBot.Db; - -public static class ClubExtensions -{ - private static IQueryable Include(this DbSet clubs) - => clubs.Include(x => x.Owner) - .Include(x => x.Applicants) - .ThenInclude(x => x.User) - .Include(x => x.Bans) - .ThenInclude(x => x.User) - .Include(x => x.Members) - .AsQueryable(); - - public static ClubInfo GetByOwner(this DbSet clubs, ulong userId) - => Include(clubs).FirstOrDefault(c => c.Owner.UserId == userId); - - public static ClubInfo GetByOwnerOrAdmin(this DbSet clubs, ulong userId) - => Include(clubs) - .FirstOrDefault(c => c.Owner.UserId == userId || c.Members.Any(u => u.UserId == userId && u.IsClubAdmin)); - - public static ClubInfo GetByMember(this DbSet clubs, ulong userId) - => Include(clubs).FirstOrDefault(c => c.Members.Any(u => u.UserId == userId)); - - public static ClubInfo GetByName(this DbSet clubs, string name) - => Include(clubs) - .FirstOrDefault(c => c.Name == name); - - public static List GetClubLeaderboardPage(this DbSet clubs, int page) - => clubs.AsNoTracking().OrderByDescending(x => x.Xp).Skip(page * 9).Take(9).ToList(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs deleted file mode 100644 index 4bd2439..0000000 --- a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -using LinqToDB.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class CurrencyTransactionExtensions -{ - public static Task> GetPageFor( - this DbSet set, - ulong userId, - int page) - => set.ToLinqToDBTable() - .Where(x => x.UserId == userId) - .OrderByDescending(x => x.DateAdded) - .Skip(15 * page) - .Take(15) - .ToListAsyncLinqToDB(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DbExtensions.cs b/src/EllieBot/Db/Extensions/DbExtensions.cs deleted file mode 100644 index 568643b..0000000 --- a/src/EllieBot/Db/Extensions/DbExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class DbExtensions -{ - public static T GetById(this DbSet set, int id) - where T : DbEntity - => set.FirstOrDefault(x => x.Id == id); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs deleted file mode 100644 index 8d94814..0000000 --- a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs +++ /dev/null @@ -1,179 +0,0 @@ -#nullable disable -using LinqToDB; -using LinqToDB.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; -using EllieBot.Services.Database; -using System.Collections.Immutable; - -namespace EllieBot.Db; - -public static class DiscordUserExtensions -{ - /// - /// Adds the specified to the database. If a database user with placeholder name - /// and discriminator is present in , their name and discriminator get updated accordingly. - /// - /// This database context. - /// The users to add or update in the database. - /// A tuple with the amount of new users added and old users updated. - public static async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(this EllieContext ctx, List users) - { - var presentDbUsers = await ctx.DiscordUser - .Select(x => new { x.UserId, x.Username, x.Discriminator }) - .Where(x => users.Select(y => y.Id).Contains(x.UserId)) - .ToArrayAsyncEF(); - - var usersToAdd = users - .Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id)) - .Select(x => new DiscordUser() - { - UserId = x.Id, - AvatarId = x.AvatarId, - Username = x.Username, - Discriminator = x.Discriminator - }); - - var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied; - var toUpdateUserIds = presentDbUsers - .Where(x => x.Username == "Unknown" && x.Discriminator == "????") - .Select(x => x.UserId) - .ToArray(); - - foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id))) - { - await ctx.DiscordUser - .Where(x => x.UserId == user.Id) - .UpdateAsync(x => new DiscordUser() - { - Username = user.Username, - Discriminator = user.Discriminator, - - // .award tends to set AvatarId and DateAdded to NULL, so account for that. - AvatarId = user.AvatarId, - DateAdded = x.DateAdded ?? DateTime.UtcNow - }); - } - - return (added, toUpdateUserIds.Length); - } - - public static Task GetByUserIdAsync( - this IQueryable set, - ulong userId) - => set.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId); - - public static void EnsureUserCreated( - this EllieContext ctx, - ulong userId, - string username, - string discrim, - string avatarId) - => ctx.DiscordUser.ToLinqToDBTable() - .InsertOrUpdate( - () => new() - { - UserId = userId, - Username = username, - Discriminator = discrim, - AvatarId = avatarId, - TotalXp = 0, - CurrencyAmount = 0 - }, - old => new() - { - Username = username, - Discriminator = discrim, - AvatarId = avatarId - }, - () => new() - { - UserId = userId - }); - - public static Task EnsureUserCreatedAsync( - this EllieContext ctx, - ulong userId) - => ctx.DiscordUser - .ToLinqToDBTable() - .InsertOrUpdateAsync( - () => new() - { - UserId = userId, - Username = "Unknown", - Discriminator = "????", - AvatarId = string.Empty, - TotalXp = 0, - CurrencyAmount = 0 - }, - old => new() - { - - }, - () => new() - { - UserId = userId - }); - - //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown - public static DiscordUser GetOrCreateUser( - this EllieContext ctx, - ulong userId, - string username, - string discrim, - string avatarId, - Func, IQueryable> includes = null) - { - ctx.EnsureUserCreated(userId, username, discrim, avatarId); - - IQueryable queryable = ctx.DiscordUser; - if (includes is not null) - queryable = includes(queryable); - return queryable.First(u => u.UserId == userId); - } - - public static DiscordUser GetOrCreateUser(this EllieContext ctx, IUser original, Func, IQueryable> includes = null) - => ctx.GetOrCreateUser(original.Id, original.Username, original.Discriminator, original.AvatarId, includes); - - public static int GetUserGlobalRank(this DbSet users, ulong id) - => users.AsQueryable() - .Where(x => x.TotalXp - > users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault()) - .Count() - + 1; - - public static DiscordUser[] GetUsersXpLeaderboardFor(this DbSet users, int page) - => users.AsQueryable().OrderByDescending(x => x.TotalXp).Skip(page * 9).Take(9).AsEnumerable().ToArray(); - - public static List GetTopRichest( - this DbSet users, - ulong botId, - int count, - int page = 0) - => users.AsQueryable() - .Where(c => c.CurrencyAmount > 0 && botId != c.UserId) - .OrderByDescending(c => c.CurrencyAmount) - .Skip(page * 9) - .Take(count) - .ToList(); - - public static async Task GetUserCurrencyAsync(this DbSet users, ulong userId) - => (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0; - - public static void RemoveFromMany(this DbSet users, IEnumerable ids) - { - var items = users.AsQueryable().Where(x => ids.Contains(x.UserId)); - foreach (var item in items) - item.CurrencyAmount = 0; - } - - public static decimal GetTotalCurrency(this DbSet users) - => users.Sum((Func)(x => x.CurrencyAmount)); - - public static decimal GetTopOnePercentCurrency(this DbSet users, ulong botId) - => users.AsQueryable() - .Where(x => x.UserId != botId) - .OrderByDescending(x => x.CurrencyAmount) - .Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100) - .Sum(x => x.CurrencyAmount); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs deleted file mode 100644 index 658a631..0000000 --- a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -using LinqToDB; -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class EllieExpressionExtensions -{ - public static int ClearFromGuild(this DbSet exprs, ulong guildId) - => exprs.Delete(x => x.GuildId == guildId); - - public static IEnumerable ForId(this DbSet exprs, ulong id) - => exprs.AsNoTracking().AsQueryable().Where(x => x.GuildId == id).ToList(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs deleted file mode 100644 index 2b6272a..0000000 --- a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs +++ /dev/null @@ -1,227 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class GuildConfigExtensions -{ - private static List DefaultWarnPunishments - => new() - { - new() - { - Count = 3, - Punishment = PunishmentAction.Kick - }, - new() - { - Count = 5, - Punishment = PunishmentAction.Ban - } - }; - - /// - /// Gets full stream role settings for the guild with the specified id. - /// - /// Db Context - /// Id of the guild to get stream role settings for. - /// Guild'p stream role settings - public static StreamRoleSettings GetStreamRoleSettings(this EllieContext ctx, ulong guildId) - { - var conf = ctx.GuildConfigsForId(guildId, - set => set.Include(y => y.StreamRole) - .Include(y => y.StreamRole.Whitelist) - .Include(y => y.StreamRole.Blacklist)); - - if (conf.StreamRole is null) - conf.StreamRole = new(); - - return conf.StreamRole; - } - - private static IQueryable IncludeEverything(this DbSet configs) - => configs.AsQueryable() - .AsSplitQuery() - .Include(gc => gc.CommandCooldowns) - .Include(gc => gc.FollowedStreams) - .Include(gc => gc.StreamRole) - .Include(gc => gc.XpSettings) - .ThenInclude(x => x.ExclusionList) - .Include(gc => gc.DelMsgOnCmdChannels); - - public static IEnumerable GetAllGuildConfigs( - this DbSet configs, - List availableGuilds) - => configs.IncludeEverything().AsNoTracking().Where(x => availableGuilds.Contains(x.GuildId)).ToList(); - - /// - /// Gets and creates if it doesn't exist a config for a guild. - /// - /// Context - /// Id of the guide - /// Use to manipulate the set however you want. Pass null to include everything - /// Config for the guild - public static GuildConfig GuildConfigsForId( - this EllieContext ctx, - ulong guildId, - Func, IQueryable> includes) - { - GuildConfig config; - - if (includes is null) - config = ctx.GuildConfigs.IncludeEverything().FirstOrDefault(c => c.GuildId == guildId); - else - { - var set = includes(ctx.GuildConfigs); - config = set.FirstOrDefault(c => c.GuildId == guildId); - } - - if (config is null) - { - ctx.GuildConfigs.Add(config = new() - { - GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist, - WarningsInitialized = true, - WarnPunishments = DefaultWarnPunishments - }); - ctx.SaveChanges(); - } - - if (!config.WarningsInitialized) - { - config.WarningsInitialized = true; - config.WarnPunishments = DefaultWarnPunishments; - } - - return config; - - // ctx.GuildConfigs - // .ToLinqToDBTable() - // .InsertOrUpdate(() => new() - // { - // GuildId = guildId, - // Permissions = Permissionv2.GetDefaultPermlist, - // WarningsInitialized = true, - // WarnPunishments = DefaultWarnPunishments - // }, - // _ => new(), - // () => new() - // { - // GuildId = guildId - // }); - // - // if(includes is null) - // return ctx.GuildConfigs - // .ToLinqToDBTable() - // .First(x => x.GuildId == guildId); - } - - public static LogSetting LogSettingsFor(this EllieContext ctx, ulong guildId) - { - var logSetting = ctx.LogSettings.AsQueryable() - .Include(x => x.LogIgnores) - .Where(x => x.GuildId == guildId) - .FirstOrDefault(); - - if (logSetting is null) - { - ctx.LogSettings.Add(logSetting = new() - { - GuildId = guildId - }); - ctx.SaveChanges(); - } - - return logSetting; - } - - public static IEnumerable PermissionsForAll(this DbSet configs, List include) - { - var query = configs.AsQueryable().Where(x => include.Contains(x.GuildId)).Include(gc => gc.Permissions); - - return query.ToList(); - } - - public static GuildConfig GcWithPermissionsFor(this EllieContext ctx, ulong guildId) - { - var config = ctx.GuildConfigs.AsQueryable() - .Where(gc => gc.GuildId == guildId) - .Include(gc => gc.Permissions) - .FirstOrDefault(); - - if (config is null) // if there is no guildconfig, create new one - { - ctx.GuildConfigs.Add(config = new() - { - GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist - }); - ctx.SaveChanges(); - } - else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones - { - config.Permissions = Permissionv2.GetDefaultPermlist; - ctx.SaveChanges(); - } - - return config; - } - - public static IEnumerable GetFollowedStreams(this DbSet configs) - => configs.AsQueryable().Include(x => x.FollowedStreams).SelectMany(gc => gc.FollowedStreams).ToArray(); - - public static IEnumerable GetFollowedStreams(this DbSet configs, List included) - => configs.AsQueryable() - .Where(gc => included.Contains(gc.GuildId)) - .Include(gc => gc.FollowedStreams) - .SelectMany(gc => gc.FollowedStreams) - .ToList(); - - public static void SetCleverbotEnabled(this DbSet configs, ulong id, bool cleverbotEnabled) - { - var conf = configs.FirstOrDefault(gc => gc.GuildId == id); - - if (conf is null) - return; - - conf.CleverbotEnabled = cleverbotEnabled; - } - - public static XpSettings XpSettingsFor(this EllieContext ctx, ulong guildId) - { - var gc = ctx.GuildConfigsForId(guildId, - set => set.Include(x => x.XpSettings) - .ThenInclude(x => x.RoleRewards) - .Include(x => x.XpSettings) - .ThenInclude(x => x.CurrencyRewards) - .Include(x => x.XpSettings) - .ThenInclude(x => x.ExclusionList)); - - if (gc.XpSettings is null) - gc.XpSettings = new(); - - return gc.XpSettings; - } - - public static IEnumerable GetGeneratingChannels(this DbSet configs) - => configs.AsQueryable() - .Include(x => x.GenerateCurrencyChannelIds) - .Where(x => x.GenerateCurrencyChannelIds.Any()) - .SelectMany(x => x.GenerateCurrencyChannelIds) - .Select(x => new GeneratingChannel - { - ChannelId = x.ChannelId, - GuildId = x.GuildConfig.GuildId - }) - .ToArray(); - - public class GeneratingChannel - { - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs deleted file mode 100644 index d8a3d12..0000000 --- a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class MusicPlayerSettingsExtensions -{ - public static async Task ForGuildAsync(this DbSet settings, ulong guildId) - { - var toReturn = await settings.AsQueryable().FirstOrDefaultAsync(x => x.GuildId == guildId); - - if (toReturn is null) - { - var newSettings = new MusicPlayerSettings - { - GuildId = guildId, - PlayerRepeat = PlayerRepeatType.Queue - }; - - await settings.AddAsync(newSettings); - return newSettings; - } - - return toReturn; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs deleted file mode 100644 index e7ac6aa..0000000 --- a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class MusicPlaylistExtensions -{ - public static List GetPlaylistsOnPage(this DbSet playlists, int num) - { - if (num < 1) - throw new ArgumentOutOfRangeException(nameof(num)); - - return playlists.AsQueryable().Skip((num - 1) * 20).Take(20).Include(pl => pl.Songs).ToList(); - } - - public static MusicPlaylist GetWithSongs(this DbSet playlists, int id) - => playlists.Include(mpl => mpl.Songs).FirstOrDefault(mpl => mpl.Id == id); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/PollExtensions.cs b/src/EllieBot/Db/Extensions/PollExtensions.cs deleted file mode 100644 index 8491d65..0000000 --- a/src/EllieBot/Db/Extensions/PollExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class PollExtensions -{ - public static IEnumerable GetAllPolls(this DbSet polls) - => polls.Include(x => x.Answers).Include(x => x.Votes).ToArray(); - - public static void RemovePoll(this EllieContext ctx, int id) - { - var p = ctx.Poll.Include(x => x.Answers).Include(x => x.Votes).FirstOrDefault(x => x.Id == id); - - if (p is null) - return; - - if (p.Votes is not null) - { - ctx.RemoveRange(p.Votes); - p.Votes.Clear(); - } - - if (p.Answers is not null) - { - ctx.RemoveRange(p.Answers); - p.Answers.Clear(); - } - - ctx.Poll.Remove(p); - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/QuoteExtensions.cs b/src/EllieBot/Db/Extensions/QuoteExtensions.cs deleted file mode 100644 index 59cae90..0000000 --- a/src/EllieBot/Db/Extensions/QuoteExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class QuoteExtensions -{ - public static IEnumerable GetForGuild(this DbSet quotes, ulong guildId) - => quotes.AsQueryable().Where(x => x.GuildId == guildId); - - public static IReadOnlyCollection GetGroup( - this DbSet quotes, - ulong guildId, - int page, - OrderType order) - { - var q = quotes.AsQueryable().Where(x => x.GuildId == guildId); - if (order == OrderType.Keyword) - q = q.OrderBy(x => x.Keyword); - else - q = q.OrderBy(x => x.Id); - - return q.Skip(15 * page).Take(15).ToArray(); - } - - public static async Task GetRandomQuoteByKeywordAsync( - this DbSet quotes, - ulong guildId, - string keyword) - { - var rng = new EllieRandom(); - return (await quotes.AsQueryable().Where(q => q.GuildId == guildId && q.Keyword == keyword).ToListAsync()) - .OrderBy(_ => rng.Next()) - .FirstOrDefault(); - } - - public static async Task SearchQuoteKeywordTextAsync( - this DbSet quotes, - ulong guildId, - string keyword, - string text) - { - var rngk = new EllieRandom(); - return (await quotes.AsQueryable() - .Where(q => q.GuildId == guildId - && (keyword == null || q.Keyword == keyword) - && (EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%") - || EF.Functions.Like(q.AuthorName, text))) - .ToListAsync()) - .OrderBy(_ => rngk.Next()) - .FirstOrDefault(); - } - - public static void RemoveAllByKeyword(this DbSet quotes, ulong guildId, string keyword) - => quotes.RemoveRange(quotes.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword)); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ReminderExtensions.cs b/src/EllieBot/Db/Extensions/ReminderExtensions.cs deleted file mode 100644 index 1fd519f..0000000 --- a/src/EllieBot/Db/Extensions/ReminderExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class ReminderExtensions -{ - public static IEnumerable GetIncludedReminders( - this DbSet reminders, - IEnumerable guildIds) - => reminders.AsQueryable().Where(x => guildIds.Contains(x.ServerId) || x.ServerId == 0).ToList(); - - public static IEnumerable RemindersFor(this DbSet reminders, ulong userId, int page) - => reminders.AsQueryable().Where(x => x.UserId == userId).OrderBy(x => x.DateAdded).Skip(page * 10).Take(10); - - public static IEnumerable RemindersForServer(this DbSet reminders, ulong serverId, int page) - => reminders.AsQueryable() - .Where(x => x.ServerId == serverId) - .OrderBy(x => x.DateAdded) - .Skip(page * 10) - .Take(10); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs deleted file mode 100644 index b2e3e39..0000000 --- a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class SelfAssignableRolesExtensions -{ - public static bool DeleteByGuildAndRoleId(this DbSet roles, ulong guildId, ulong roleId) - { - var role = roles.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId); - - if (role is null) - return false; - - roles.Remove(role); - return true; - } - - public static IReadOnlyCollection GetFromGuild(this DbSet roles, ulong guildId) - => roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/UserXpExtensions.cs b/src/EllieBot/Db/Extensions/UserXpExtensions.cs deleted file mode 100644 index a20071b..0000000 --- a/src/EllieBot/Db/Extensions/UserXpExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -#nullable disable -using LinqToDB; -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class UserXpExtensions -{ - public static UserXpStats GetOrCreateUserXpStats(this EllieContext ctx, ulong guildId, ulong userId) - { - var usr = ctx.UserXpStats.FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId); - - if (usr is null) - { - ctx.Add(usr = new() - { - Xp = 0, - UserId = userId, - NotifyOnLevelUp = XpNotificationLocation.None, - GuildId = guildId - }); - } - - return usr; - } - - public static List GetUsersFor(this DbSet xps, ulong guildId, int page) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId) - .OrderByDescending(x => x.Xp + x.AwardedXp) - .Skip(page * 9) - .Take(9) - .ToList(); - - public static List GetTopUserXps(this DbSet xps, ulong guildId, int count) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId) - .OrderByDescending(x => x.Xp + x.AwardedXp) - .Take(count) - .ToList(); - - public static int GetUserGuildRanking(this DbSet xps, ulong userId, ulong guildId) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId - && x.Xp + x.AwardedXp - > xps.AsQueryable() - .Where(y => y.UserId == userId && y.GuildId == guildId) - .Select(y => y.Xp + y.AwardedXp) - .FirstOrDefault()) - .Count() - + 1; - - public static void ResetGuildUserXp(this DbSet xps, ulong userId, ulong guildId) - => xps.Delete(x => x.UserId == userId && x.GuildId == guildId); - - public static void ResetGuildXp(this DbSet xps, ulong guildId) - => xps.Delete(x => x.GuildId == guildId); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WaifuExtensions.cs b/src/EllieBot/Db/Extensions/WaifuExtensions.cs deleted file mode 100644 index 97d9cf4..0000000 --- a/src/EllieBot/Db/Extensions/WaifuExtensions.cs +++ /dev/null @@ -1,145 +0,0 @@ -#nullable disable -using LinqToDB; -using LinqToDB.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public class WaifuInfoStats -{ - public int WaifuId { get; init; } - public string FullName { get; init; } - public long Price { get; init; } - public string ClaimerName { get; init; } - public string AffinityName { get; init; } - public int AffinityCount { get; init; } - public int DivorceCount { get; init; } - public int ClaimCount { get; init; } -} - -public static class WaifuExtensions -{ - public static WaifuInfo ByWaifuUserId( - this DbSet waifus, - ulong userId, - Func, IQueryable> includes = null) - { - if (includes is null) - { - return waifus.Include(wi => wi.Waifu) - .Include(wi => wi.Affinity) - .Include(wi => wi.Claimer) - .Include(wi => wi.Items) - .FirstOrDefault(wi => wi.Waifu.UserId == userId); - } - - return includes(waifus).AsQueryable().FirstOrDefault(wi => wi.Waifu.UserId == userId); - } - - public static IEnumerable GetTop(this DbSet waifus, int count, int skip = 0) - { - if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count)); - if (count == 0) - return new List(); - - return waifus.Include(wi => wi.Waifu) - .Include(wi => wi.Affinity) - .Include(wi => wi.Claimer) - .OrderByDescending(wi => wi.Price) - .Skip(skip) - .Take(count) - .Select(x => new WaifuLbResult - { - Affinity = x.Affinity == null ? null : x.Affinity.Username, - AffinityDiscrim = x.Affinity == null ? null : x.Affinity.Discriminator, - Claimer = x.Claimer == null ? null : x.Claimer.Username, - ClaimerDiscrim = x.Claimer == null ? null : x.Claimer.Discriminator, - Username = x.Waifu.Username, - Discrim = x.Waifu.Discriminator, - Price = x.Price - }) - .ToList(); - } - - public static decimal GetTotalValue(this DbSet waifus) - => waifus.AsQueryable().Where(x => x.ClaimerId != null).Sum(x => x.Price); - - public static ulong GetWaifuUserId(this DbSet waifus, ulong ownerId, string name) - => waifus.AsQueryable() - .AsNoTracking() - .Where(x => x.Claimer.UserId == ownerId && x.Waifu.Username + "#" + x.Waifu.Discriminator == name) - .Select(x => x.Waifu.UserId) - .FirstOrDefault(); - - public static async Task GetWaifuInfoAsync(this EllieContext ctx, ulong userId) - { - await ctx.WaifuInfo - .ToLinqToDBTable() - .InsertOrUpdateAsync(() => new() - { - AffinityId = null, - ClaimerId = null, - Price = 1, - WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First() - }, - _ => new(), - () => new() - { - WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First() - }); - - var toReturn = ctx.WaifuInfo.AsQueryable() - .Where(w => w.WaifuId - == ctx.Set() - .AsQueryable() - .Where(u => u.UserId == userId) - .Select(u => u.Id) - .FirstOrDefault()) - .Select(w => new WaifuInfoStats - { - WaifuId = w.WaifuId, - FullName = - ctx.Set() - .AsQueryable() - .Where(u => u.UserId == userId) - .Select(u => u.Username + "#" + u.Discriminator) - .FirstOrDefault(), - AffinityCount = - ctx.Set() - .AsQueryable() - .Count(x => x.UserId == w.WaifuId - && x.UpdateType == WaifuUpdateType.AffinityChanged - && x.NewId != null), - AffinityName = - ctx.Set() - .AsQueryable() - .Where(u => u.Id == w.AffinityId) - .Select(u => u.Username + "#" + u.Discriminator) - .FirstOrDefault(), - ClaimCount = ctx.WaifuInfo.AsQueryable().Count(x => x.ClaimerId == w.WaifuId), - ClaimerName = - ctx.Set() - .AsQueryable() - .Where(u => u.Id == w.ClaimerId) - .Select(u => u.Username + "#" + u.Discriminator) - .FirstOrDefault(), - DivorceCount = - ctx.Set() - .AsQueryable() - .Count(x => x.OldId == w.WaifuId - && x.NewId == null - && x.UpdateType == WaifuUpdateType.Claimed), - Price = w.Price, - }) - .FirstOrDefault(); - - if (toReturn is null) - return null; - - return toReturn; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WarningExtensions.cs b/src/EllieBot/Db/Extensions/WarningExtensions.cs deleted file mode 100644 index 76d0815..0000000 --- a/src/EllieBot/Db/Extensions/WarningExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class WarningExtensions -{ - public static Warning[] ForId(this DbSet warnings, ulong guildId, ulong userId) - { - var query = warnings.AsQueryable() - .Where(x => x.GuildId == guildId && x.UserId == userId) - .OrderByDescending(x => x.DateAdded); - - return query.ToArray(); - } - - public static bool Forgive( - this DbSet warnings, - ulong guildId, - ulong userId, - string mod, - int index) - { - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index)); - - var warn = warnings.AsQueryable() - .Where(x => x.GuildId == guildId && x.UserId == userId) - .OrderByDescending(x => x.DateAdded) - .Skip(index) - .FirstOrDefault(); - - if (warn is null || warn.Forgiven) - return false; - - warn.Forgiven = true; - warn.ForgivenBy = mod; - return true; - } - - public static async Task ForgiveAll( - this DbSet warnings, - ulong guildId, - ulong userId, - string mod) - => await warnings.AsQueryable() - .Where(x => x.GuildId == guildId && x.UserId == userId) - .ForEachAsync(x => - { - if (x.Forgiven != true) - { - x.Forgiven = true; - x.ForgivenBy = mod; - } - }); - - public static Warning[] GetForGuild(this DbSet warnings, ulong id) - => warnings.AsQueryable().Where(x => x.GuildId == id).ToArray(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AntiProtection.cs b/src/EllieBot/Db/Models/AntiProtection.cs deleted file mode 100644 index 8539496..0000000 --- a/src/EllieBot/Db/Models/AntiProtection.cs +++ /dev/null @@ -1,65 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AntiRaidSetting : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public int UserThreshold { get; set; } - public int Seconds { get; set; } - public PunishmentAction Action { get; set; } - - /// - /// Duration of the punishment, in minutes. This works only for supported Actions, like: - /// Mute, Chatmute, Voicemute, etc... - /// - public int PunishDuration { get; set; } -} - -public class AntiSpamSetting : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public PunishmentAction Action { get; set; } - public int MessageThreshold { get; set; } = 3; - public int MuteTime { get; set; } - public ulong? RoleId { get; set; } - public HashSet IgnoredChannels { get; set; } = new(); -} - -public class AntiAltSetting -{ - public int Id { get; set; } - public int GuildConfigId { get; set; } - public TimeSpan MinAge { get; set; } - public PunishmentAction Action { get; set; } - public int ActionDurationMinutes { get; set; } - public ulong? RoleId { get; set; } -} - -public enum PunishmentAction -{ - Mute, - Kick, - Ban, - Softban, - RemoveRoles, - ChatMute, - VoiceMute, - AddRole, - Warn, - TimeOut -} - -public class AntiSpamIgnore : DbEntity -{ - public ulong ChannelId { get; set; } - - public override int GetHashCode() - => ChannelId.GetHashCode(); - - public override bool Equals(object obj) - => obj is AntiSpamIgnore inst ? inst.ChannelId == ChannelId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoCommand.cs b/src/EllieBot/Db/Models/AutoCommand.cs deleted file mode 100644 index 8bcae05..0000000 --- a/src/EllieBot/Db/Models/AutoCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AutoCommand : DbEntity -{ - public string CommandText { get; set; } - public ulong ChannelId { get; set; } - public string ChannelName { get; set; } - public ulong? GuildId { get; set; } - public string GuildName { get; set; } - public ulong? VoiceChannelId { get; set; } - public string VoiceChannelName { get; set; } - public int Interval { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoPublishChannel.cs b/src/EllieBot/Db/Models/AutoPublishChannel.cs deleted file mode 100644 index a19fd28..0000000 --- a/src/EllieBot/Db/Models/AutoPublishChannel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class AutoPublishChannel : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateChannel.cs b/src/EllieBot/Db/Models/AutoTranslateChannel.cs deleted file mode 100644 index 6f6ef58..0000000 --- a/src/EllieBot/Db/Models/AutoTranslateChannel.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AutoTranslateChannel : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public bool AutoDelete { get; set; } - public IList Users { get; set; } = new List(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateUser.cs b/src/EllieBot/Db/Models/AutoTranslateUser.cs deleted file mode 100644 index 6e36404..0000000 --- a/src/EllieBot/Db/Models/AutoTranslateUser.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AutoTranslateUser : DbEntity -{ - public int ChannelId { get; set; } - public AutoTranslateChannel Channel { get; set; } - public ulong UserId { get; set; } - public string Source { get; set; } - public string Target { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BanTemplate.cs b/src/EllieBot/Db/Models/BanTemplate.cs deleted file mode 100644 index d32f4c7..0000000 --- a/src/EllieBot/Db/Models/BanTemplate.cs +++ /dev/null @@ -1,9 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class BanTemplate : DbEntity -{ - public ulong GuildId { get; set; } - public string Text { get; set; } - public int? PruneDays { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BankUser.cs b/src/EllieBot/Db/Models/BankUser.cs deleted file mode 100644 index 7fa6418..0000000 --- a/src/EllieBot/Db/Models/BankUser.cs +++ /dev/null @@ -1,9 +0,0 @@ -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class BankUser : DbEntity -{ - public ulong UserId { get; set; } - public long Balance { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BlacklistEntry.cs b/src/EllieBot/Db/Models/BlacklistEntry.cs deleted file mode 100644 index 3ecf999..0000000 --- a/src/EllieBot/Db/Models/BlacklistEntry.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class BlacklistEntry : DbEntity -{ - public ulong ItemId { get; set; } - public BlacklistType Type { get; set; } -} - -public enum BlacklistType -{ - Server, - Channel, - User -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ClubInfo.cs b/src/EllieBot/Db/Models/ClubInfo.cs deleted file mode 100644 index 8c8f85c..0000000 --- a/src/EllieBot/Db/Models/ClubInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -#nullable disable -using EllieBot.Services.Database.Models; -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Db.Models; - -public class ClubInfo : DbEntity -{ - [MaxLength(20)] - public string Name { get; set; } - public string Description { get; set; } - public string ImageUrl { get; set; } = string.Empty; - - public int Xp { get; set; } = 0; - public int? OwnerId { get; set; } - public DiscordUser Owner { get; set; } - - public List Members { get; set; } = new(); - public List Applicants { get; set; } = new(); - public List Bans { get; set; } = new(); - - public override string ToString() - => Name; -} - -public class ClubApplicants -{ - public int ClubId { get; set; } - public ClubInfo Club { get; set; } - - public int UserId { get; set; } - public DiscordUser User { get; set; } -} - -public class ClubBans -{ - public int ClubId { get; set; } - public ClubInfo Club { get; set; } - - public int UserId { get; set; } - public DiscordUser User { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandAlias.cs b/src/EllieBot/Db/Models/CommandAlias.cs deleted file mode 100644 index b3d6fc4..0000000 --- a/src/EllieBot/Db/Models/CommandAlias.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CommandAlias : DbEntity -{ - public string Trigger { get; set; } - public string Mapping { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandCooldown.cs b/src/EllieBot/Db/Models/CommandCooldown.cs deleted file mode 100644 index f25cd08..0000000 --- a/src/EllieBot/Db/Models/CommandCooldown.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CommandCooldown : DbEntity -{ - public int Seconds { get; set; } - public string CommandName { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CurrencyTransaction.cs b/src/EllieBot/Db/Models/CurrencyTransaction.cs deleted file mode 100644 index 9153520..0000000 --- a/src/EllieBot/Db/Models/CurrencyTransaction.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CurrencyTransaction : DbEntity -{ - public long Amount { get; set; } - public string Note { get; set; } - public ulong UserId { get; set; } - public string Type { get; set; } - public string Extra { get; set; } - public ulong? OtherId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DbEntity.cs b/src/EllieBot/Db/Models/DbEntity.cs deleted file mode 100644 index 035ff76..0000000 --- a/src/EllieBot/Db/Models/DbEntity.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Services.Database.Models; - -public class DbEntity -{ - [Key] - public int Id { get; set; } - - public DateTime? DateAdded { get; set; } = DateTime.UtcNow; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs deleted file mode 100644 index 6a24297..0000000 --- a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class DelMsgOnCmdChannel : DbEntity -{ - public ulong ChannelId { get; set; } - public bool State { get; set; } - - public override int GetHashCode() - => ChannelId.GetHashCode(); - - public override bool Equals(object obj) - => obj is DelMsgOnCmdChannel x && x.ChannelId == ChannelId; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordPemOverride.cs b/src/EllieBot/Db/Models/DiscordPemOverride.cs deleted file mode 100644 index 461dcc4..0000000 --- a/src/EllieBot/Db/Models/DiscordPemOverride.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class DiscordPermOverride : DbEntity -{ - public GuildPerm Perm { get; set; } - - public ulong? GuildId { get; set; } - public string Command { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordUser.cs b/src/EllieBot/Db/Models/DiscordUser.cs deleted file mode 100644 index 5f8cc7b..0000000 --- a/src/EllieBot/Db/Models/DiscordUser.cs +++ /dev/null @@ -1,31 +0,0 @@ -#nullable disable -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -// FUTURE remove LastLevelUp from here and UserXpStats -public class DiscordUser : DbEntity -{ - public ulong UserId { get; set; } - public string Username { get; set; } - public string Discriminator { get; set; } - public string AvatarId { get; set; } - - public int? ClubId { get; set; } - public ClubInfo Club { get; set; } - public bool IsClubAdmin { get; set; } - - public long TotalXp { get; set; } - public XpNotificationLocation NotifyOnLevelUp { get; set; } - - public long CurrencyAmount { get; set; } - - public override bool Equals(object obj) - => obj is DiscordUser du ? du.UserId == UserId : false; - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override string ToString() - => Username + "#" + Discriminator; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/EllieExpression.cs b/src/EllieBot/Db/Models/EllieExpression.cs deleted file mode 100644 index 28c75f1..0000000 --- a/src/EllieBot/Db/Models/EllieExpression.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class EllieExpression : DbEntity -{ - public ulong? GuildId { get; set; } - public string Response { get; set; } - public string Trigger { get; set; } - - public bool AutoDeleteTrigger { get; set; } - public bool DmResponse { get; set; } - public bool ContainsAnywhere { get; set; } - public bool AllowTarget { get; set; } - public string Reactions { get; set; } - - public string[] GetReactions() - => string.IsNullOrWhiteSpace(Reactions) ? Array.Empty() : Reactions.Split("@@@"); - - public bool IsGlobal() - => GuildId is null or 0; -} - -public class ReactionResponse : DbEntity -{ - public bool OwnerOnly { get; set; } - public string Text { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Event.cs b/src/EllieBot/Db/Models/Event.cs deleted file mode 100644 index bface52..0000000 --- a/src/EllieBot/Db/Models/Event.cs +++ /dev/null @@ -1,49 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CurrencyEvent -{ - public enum Type - { - Reaction, - - GameStatus - //NotRaid, - } - - public ulong ServerId { get; set; } - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } - public Type EventType { get; set; } - - /// - /// Amount of currency that the user will be rewarded. - /// - public long Amount { get; set; } - - /// - /// Maximum amount of currency that can be handed out. - /// - public long PotSize { get; set; } - - public List AwardedUsers { get; set; } - - /// - /// Used as extra data storage for events which need it. - /// - public ulong ExtraId { get; set; } - - /// - /// May be used for some future event. - /// - public ulong ExtraId2 { get; set; } - - /// - /// May be used for some future event. - /// - public string ExtraString { get; set; } -} - -public class AwardedUser -{ -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FeedSub.cs b/src/EllieBot/Db/Models/FeedSub.cs deleted file mode 100644 index f5fccc6..0000000 --- a/src/EllieBot/Db/Models/FeedSub.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FeedSub : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public ulong ChannelId { get; set; } - public string Url { get; set; } - - public string Message { get; set; } - - public override int GetHashCode() - => Url.GetHashCode(StringComparison.InvariantCulture) ^ GuildConfigId.GetHashCode(); - - public override bool Equals(object obj) - => obj is FeedSub s && s.Url.ToLower() == Url.ToLower() && s.GuildConfigId == GuildConfigId; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilterChannelId.cs b/src/EllieBot/Db/Models/FilterChannelId.cs deleted file mode 100644 index 9eaf8fa..0000000 --- a/src/EllieBot/Db/Models/FilterChannelId.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FilterChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public bool Equals(FilterChannelId other) - => ChannelId == other.ChannelId; - - public override bool Equals(object obj) - => obj is FilterChannelId fci && Equals(fci); - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} - -public class FilterWordsChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public bool Equals(FilterWordsChannelId other) - => ChannelId == other.ChannelId; - - public override bool Equals(object obj) - => obj is FilterWordsChannelId fci && Equals(fci); - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilterLinksChannelId.cs b/src/EllieBot/Db/Models/FilterLinksChannelId.cs deleted file mode 100644 index f48d9b4..0000000 --- a/src/EllieBot/Db/Models/FilterLinksChannelId.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FilterLinksChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public override bool Equals(object obj) - => obj is FilterLinksChannelId f && f.ChannelId == ChannelId; - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilteredWord.cs b/src/EllieBot/Db/Models/FilteredWord.cs deleted file mode 100644 index 4ff32f7..0000000 --- a/src/EllieBot/Db/Models/FilteredWord.cs +++ /dev/null @@ -1,7 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FilteredWord : DbEntity -{ - public string Word { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FollowedStream.cs b/src/EllieBot/Db/Models/FollowedStream.cs deleted file mode 100644 index ca119b4..0000000 --- a/src/EllieBot/Db/Models/FollowedStream.cs +++ /dev/null @@ -1,37 +0,0 @@ -#nullable disable -using EllieBot.Modules.Searches.Common; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class FollowedStream : DbEntity -{ - public enum FType - { - Twitch = 0, - Picarto = 3, - Youtube = 4, - Facebook = 5, - Trovo = 6 - } - - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public string Username { get; set; } - public FType Type { get; set; } - public string Message { get; set; } - - protected bool Equals(FollowedStream other) - => ChannelId == other.ChannelId - && Username.Trim().ToUpperInvariant() == other.Username.Trim().ToUpperInvariant() - && Type == other.Type; - - public override int GetHashCode() - => HashCode.Combine(ChannelId, Username, (int)Type); - - public override bool Equals(object obj) - => obj is FollowedStream fs && Equals(fs); - - public StreamDataKey CreateKey() - => new(Type, Username.ToLower()); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GCChannelId.cs b/src/EllieBot/Db/Models/GCChannelId.cs deleted file mode 100644 index 1f265d7..0000000 --- a/src/EllieBot/Db/Models/GCChannelId.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class GCChannelId : DbEntity -{ - public GuildConfig GuildConfig { get; set; } - public ulong ChannelId { get; set; } - - public override bool Equals(object obj) - => obj is GCChannelId gc && gc.ChannelId == ChannelId; - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GamblingStats.cs b/src/EllieBot/Db/Models/GamblingStats.cs deleted file mode 100644 index 8a4654e..0000000 --- a/src/EllieBot/Db/Models/GamblingStats.cs +++ /dev/null @@ -1,9 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class GamblingStats : DbEntity -{ - public string Feature { get; set; } - public decimal Bet { get; set; } - public decimal PaidOut { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GroupName.cs b/src/EllieBot/Db/Models/GroupName.cs deleted file mode 100644 index de88717..0000000 --- a/src/EllieBot/Db/Models/GroupName.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class GroupName : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public int Number { get; set; } - public string Name { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GuildConfig.cs b/src/EllieBot/Db/Models/GuildConfig.cs deleted file mode 100644 index b05df52..0000000 --- a/src/EllieBot/Db/Models/GuildConfig.cs +++ /dev/null @@ -1,108 +0,0 @@ -#nullable disable -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database.Models; - -public class GuildConfig : DbEntity -{ - public ulong GuildId { get; set; } - - public string Prefix { get; set; } - - public bool DeleteMessageOnCommand { get; set; } - public HashSet DelMsgOnCmdChannels { get; set; } = new(); - - public string AutoAssignRoleIds { get; set; } - - //greet stuff - public int AutoDeleteGreetMessagesTimer { get; set; } = 30; - public int AutoDeleteByeMessagesTimer { get; set; } = 30; - - public ulong GreetMessageChannelId { get; set; } - public ulong ByeMessageChannelId { get; set; } - - public bool SendDmGreetMessage { get; set; } - public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; - - public bool SendChannelGreetMessage { get; set; } - public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; - - public bool SendChannelByeMessage { get; set; } - public string ChannelByeMessageText { get; set; } = "%user% has left!"; - - //self assignable roles - public bool ExclusiveSelfAssignedRoles { get; set; } - public bool AutoDeleteSelfAssignedRoleMessages { get; set; } - - //stream notifications - public HashSet FollowedStreams { get; set; } = new(); - - //currencyGeneration - public HashSet GenerateCurrencyChannelIds { get; set; } = new(); - - public List Permissions { get; set; } - public bool VerbosePermissions { get; set; } = true; - public string PermissionRole { get; set; } - - public HashSet CommandCooldowns { get; set; } = new(); - - //filtering - public bool FilterInvites { get; set; } - public bool FilterLinks { get; set; } - public HashSet FilterInvitesChannelIds { get; set; } = new(); - public HashSet FilterLinksChannelIds { get; set; } = new(); - - //public bool FilterLinks { get; set; } - //public HashSet FilterLinksChannels { get; set; } = new HashSet(); - - public bool FilterWords { get; set; } - public HashSet FilteredWords { get; set; } = new(); - public HashSet FilterWordsChannelIds { get; set; } = new(); - - public HashSet MutedUsers { get; set; } = new(); - - public string MuteRoleName { get; set; } - public bool CleverbotEnabled { get; set; } - - public AntiRaidSetting AntiRaidSetting { get; set; } - public AntiSpamSetting AntiSpamSetting { get; set; } - public AntiAltSetting AntiAltSetting { get; set; } - - public string Locale { get; set; } - public string TimeZoneId { get; set; } - - public HashSet UnmuteTimers { get; set; } = new(); - public HashSet UnbanTimer { get; set; } = new(); - public HashSet UnroleTimer { get; set; } = new(); - public HashSet VcRoleInfos { get; set; } - public HashSet CommandAliases { get; set; } = new(); - public List WarnPunishments { get; set; } = new(); - public bool WarningsInitialized { get; set; } - public HashSet SlowmodeIgnoredUsers { get; set; } - public HashSet SlowmodeIgnoredRoles { get; set; } - - public List ShopEntries { get; set; } - public ulong? GameVoiceChannel { get; set; } - public bool VerboseErrors { get; set; } = true; - - public StreamRoleSettings StreamRole { get; set; } - - public XpSettings XpSettings { get; set; } - public List FeedSubs { get; set; } = new(); - public bool NotifyStreamOffline { get; set; } - public bool DeleteStreamOnlineMessage { get; set; } - public List SelfAssignableRoleGroupNames { get; set; } - public int WarnExpireHours { get; set; } - public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear; - - public bool DisableGlobalExpressions { get; set; } = false; - - #region Boost Message - - public bool SendBoostMessage { get; set; } - public string BoostMessage { get; set; } = "%user% just boosted this server!"; - public ulong BoostMessageChannelId { get; set; } - public int BoostMessageDeleteAfter { get; set; } - - #endregion -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredLogItem.cs b/src/EllieBot/Db/Models/IgnoredLogItem.cs deleted file mode 100644 index 060ef32..0000000 --- a/src/EllieBot/Db/Models/IgnoredLogItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class IgnoredLogItem : DbEntity -{ - public int LogSettingId { get; set; } - public LogSetting LogSetting { get; set; } - public ulong LogItemId { get; set; } - public IgnoredItemType ItemType { get; set; } -} - -public enum IgnoredItemType -{ - Channel, - User -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs deleted file mode 100644 index e25c38a..0000000 --- a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class IgnoredVoicePresenceChannel : DbEntity -{ - public LogSetting LogSetting { get; set; } - public ulong ChannelId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ImageOnlyChannel.cs b/src/EllieBot/Db/Models/ImageOnlyChannel.cs deleted file mode 100644 index 2fce8d1..0000000 --- a/src/EllieBot/Db/Models/ImageOnlyChannel.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class ImageOnlyChannel : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public OnlyChannelType Type { get; set; } -} - -public enum OnlyChannelType -{ - Image, - Link -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/LogSetting.cs b/src/EllieBot/Db/Models/LogSetting.cs deleted file mode 100644 index 93228ca..0000000 --- a/src/EllieBot/Db/Models/LogSetting.cs +++ /dev/null @@ -1,37 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class LogSetting : DbEntity -{ - public List LogIgnores { get; set; } = new(); - - public ulong GuildId { get; set; } - public ulong? LogOtherId { get; set; } - public ulong? MessageUpdatedId { get; set; } - public ulong? MessageDeletedId { get; set; } - - public ulong? UserJoinedId { get; set; } - public ulong? UserLeftId { get; set; } - public ulong? UserBannedId { get; set; } - public ulong? UserUnbannedId { get; set; } - public ulong? UserUpdatedId { get; set; } - - public ulong? ChannelCreatedId { get; set; } - public ulong? ChannelDestroyedId { get; set; } - public ulong? ChannelUpdatedId { get; set; } - - - public ulong? ThreadDeletedId { get; set; } - public ulong? ThreadCreatedId { get; set; } - - public ulong? UserMutedId { get; set; } - - //userpresence - public ulong? LogUserPresenceId { get; set; } - - //voicepresence - - public ulong? LogVoicePresenceId { get; set; } - public ulong? LogVoicePresenceTTSId { get; set; } - public ulong? LogWarnsId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MusicPlaylist.cs b/src/EllieBot/Db/Models/MusicPlaylist.cs deleted file mode 100644 index 3f96d05..0000000 --- a/src/EllieBot/Db/Models/MusicPlaylist.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class MusicPlaylist : DbEntity -{ - public string Name { get; set; } - public string Author { get; set; } - public ulong AuthorId { get; set; } - public List Songs { get; set; } = new(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MusicSettings.cs b/src/EllieBot/Db/Models/MusicSettings.cs deleted file mode 100644 index b81d433..0000000 --- a/src/EllieBot/Db/Models/MusicSettings.cs +++ /dev/null @@ -1,61 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class MusicPlayerSettings -{ - /// - /// Auto generated Id - /// - public int Id { get; set; } - - /// - /// Id of the guild - /// - public ulong GuildId { get; set; } - - /// - /// Queue repeat type - /// - public PlayerRepeatType PlayerRepeat { get; set; } = PlayerRepeatType.Queue; - - /// - /// Channel id the bot will always try to send track related messages to - /// - public ulong? MusicChannelId { get; set; } - - /// - /// Default volume player will be created with - /// - public int Volume { get; set; } = 100; - - /// - /// Whether the bot should auto disconnect from the voice channel once the queue is done - /// This only has effect if - /// - public bool AutoDisconnect { get; set; } - - /// - /// Selected quality preset for the music player - /// - public QualityPreset QualityPreset { get; set; } - - /// - /// Whether the bot will automatically queue related songs - /// - public bool AutoPlay { get; set; } -} - -public enum QualityPreset -{ - Highest, - High, - Medium, - Low -} - -public enum PlayerRepeatType -{ - None, - Track, - Queue -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MutedUserId.cs b/src/EllieBot/Db/Models/MutedUserId.cs deleted file mode 100644 index 78fc9f3..0000000 --- a/src/EllieBot/Db/Models/MutedUserId.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class MutedUserId : DbEntity -{ - public ulong UserId { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is MutedUserId mui ? mui.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs b/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs deleted file mode 100644 index 3617132..0000000 --- a/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class NsfwBlacklistedTag : DbEntity -{ - public ulong GuildId { get; set; } - public string Tag { get; set; } - - public override int GetHashCode() - => Tag.GetHashCode(StringComparison.InvariantCulture); - - public override bool Equals(object obj) - => obj is NsfwBlacklistedTag x && x.Tag == Tag; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PatronQuota.cs b/src/EllieBot/Db/Models/PatronQuota.cs deleted file mode 100644 index 1ebd2fd..0000000 --- a/src/EllieBot/Db/Models/PatronQuota.cs +++ /dev/null @@ -1,48 +0,0 @@ -#nullable disable -namespace EllieBot.Db.Models; - -/// -/// Contains data about usage of Patron-Only commands per user -/// in order to provide support for quota limitations -/// (allow user x who is pledging amount y to use the specified command only -/// x amount of times in the specified time period) -/// -public class PatronQuota -{ - public ulong UserId { get; set; } - public FeatureType FeatureType { get; set; } - public string Feature { get; set; } - public uint HourlyCount { get; set; } - public uint DailyCount { get; set; } - public uint MonthlyCount { get; set; } -} - -public enum FeatureType -{ - Command, - Group, - Module, - Limit -} - -public class PatronUser -{ - public string UniquePlatformUserId { get; set; } - public ulong UserId { get; set; } - public int AmountCents { get; set; } - - public DateTime LastCharge { get; set; } - - // Date Only component - public DateTime ValidThru { get; set; } - - public PatronUser Clone() - => new PatronUser() - { - UniquePlatformUserId = this.UniquePlatformUserId, - UserId = this.UserId, - AmountCents = this.AmountCents, - LastCharge = this.LastCharge, - ValidThru = this.ValidThru - }; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Permission.cs b/src/EllieBot/Db/Models/Permission.cs deleted file mode 100644 index 24a8186..0000000 --- a/src/EllieBot/Db/Models/Permission.cs +++ /dev/null @@ -1,55 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations.Schema; -using System.Diagnostics; - -namespace EllieBot.Services.Database.Models; - -[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")] -public class Permissionv2 : DbEntity, IIndexed -{ - public int? GuildConfigId { get; set; } - public int Index { get; set; } - - public PrimaryPermissionType PrimaryTarget { get; set; } - public ulong PrimaryTargetId { get; set; } - - public SecondaryPermissionType SecondaryTarget { get; set; } - public string SecondaryTargetName { get; set; } - - public bool IsCustomCommand { get; set; } - - public bool State { get; set; } - - [NotMapped] - public static Permissionv2 AllowAllPerm - => new() - { - PrimaryTarget = PrimaryPermissionType.Server, - PrimaryTargetId = 0, - SecondaryTarget = SecondaryPermissionType.AllModules, - SecondaryTargetName = "*", - State = true, - Index = 0 - }; - - public static List GetDefaultPermlist - => new() - { - AllowAllPerm - }; -} - -public enum PrimaryPermissionType -{ - User, - Channel, - Role, - Server -} - -public enum SecondaryPermissionType -{ - Module, - Command, - AllModules -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlantedCurrency.cs b/src/EllieBot/Db/Models/PlantedCurrency.cs deleted file mode 100644 index 3741530..0000000 --- a/src/EllieBot/Db/Models/PlantedCurrency.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class PlantedCurrency : DbEntity -{ - public long Amount { get; set; } - public string Password { get; set; } - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public ulong UserId { get; set; } - public ulong MessageId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlaylistSong.cs b/src/EllieBot/Db/Models/PlaylistSong.cs deleted file mode 100644 index 7a2078d..0000000 --- a/src/EllieBot/Db/Models/PlaylistSong.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class PlaylistSong : DbEntity -{ - public string Provider { get; set; } - public MusicType ProviderType { get; set; } - public string Title { get; set; } - public string Uri { get; set; } - public string Query { get; set; } -} - -public enum MusicType -{ - Radio, - YouTube, - Local, - Soundcloud -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Poll.cs b/src/EllieBot/Db/Models/Poll.cs deleted file mode 100644 index 10e988c..0000000 --- a/src/EllieBot/Db/Models/Poll.cs +++ /dev/null @@ -1,17 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Poll : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public string Question { get; set; } - public IndexedCollection Answers { get; set; } - public HashSet Votes { get; set; } = new(); -} - -public class PollAnswer : DbEntity, IIndexed -{ - public int Index { get; set; } - public string Text { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PollVote.cs b/src/EllieBot/Db/Models/PollVote.cs deleted file mode 100644 index e78dadf..0000000 --- a/src/EllieBot/Db/Models/PollVote.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class PollVote : DbEntity -{ - public ulong UserId { get; set; } - public int VoteIndex { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is PollVote p ? p.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Quote.cs b/src/EllieBot/Db/Models/Quote.cs deleted file mode 100644 index 529dc46..0000000 --- a/src/EllieBot/Db/Models/Quote.cs +++ /dev/null @@ -1,26 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Services.Database.Models; - -public class Quote : DbEntity -{ - public ulong GuildId { get; set; } - - [Required] - public string Keyword { get; set; } - - [Required] - public string AuthorName { get; set; } - - public ulong AuthorId { get; set; } - - [Required] - public string Text { get; set; } -} - -public enum OrderType -{ - Id = -1, - Keyword = -2 -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ReactionRole.cs b/src/EllieBot/Db/Models/ReactionRole.cs deleted file mode 100644 index 4e1e4f6..0000000 --- a/src/EllieBot/Db/Models/ReactionRole.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Services.Database.Models; - -public class ReactionRoleV2 : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - - public ulong MessageId { get; set; } - - [MaxLength(100)] - public string Emote { get; set; } - public ulong RoleId { get; set; } - public int Group { get; set; } - public int LevelReq { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Reminder.cs b/src/EllieBot/Db/Models/Reminder.cs deleted file mode 100644 index df51f6d..0000000 --- a/src/EllieBot/Db/Models/Reminder.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Reminder : DbEntity -{ - public DateTime When { get; set; } - public ulong ChannelId { get; set; } - public ulong ServerId { get; set; } - public ulong UserId { get; set; } - public string Message { get; set; } - public bool IsPrivate { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Repeater.cs b/src/EllieBot/Db/Models/Repeater.cs deleted file mode 100644 index 7ac971e..0000000 --- a/src/EllieBot/Db/Models/Repeater.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Repeater -{ - public int Id { get; set; } - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public ulong? LastMessageId { get; set; } - public string Message { get; set; } - public TimeSpan Interval { get; set; } - public TimeSpan? StartTimeOfDay { get; set; } - public bool NoRedundant { get; set; } - public DateTime DateAdded { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RewardedUser.cs b/src/EllieBot/Db/Models/RewardedUser.cs deleted file mode 100644 index 9ac6e78..0000000 --- a/src/EllieBot/Db/Models/RewardedUser.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class RewardedUser : DbEntity -{ - public ulong UserId { get; set; } - public string PlatformUserId { get; set; } - public long AmountRewardedThisMonth { get; set; } - public DateTime LastReward { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RotatingPlayingStatus.cs b/src/EllieBot/Db/Models/RotatingPlayingStatus.cs deleted file mode 100644 index a76c38f..0000000 --- a/src/EllieBot/Db/Models/RotatingPlayingStatus.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class RotatingPlayingStatus : DbEntity -{ - public string Status { get; set; } - public ActivityType Type { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SelfAssignableRole.cs b/src/EllieBot/Db/Models/SelfAssignableRole.cs deleted file mode 100644 index c68fd32..0000000 --- a/src/EllieBot/Db/Models/SelfAssignableRole.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class SelfAssignedRole : DbEntity -{ - public ulong GuildId { get; set; } - public ulong RoleId { get; set; } - - public int Group { get; set; } - public int LevelRequirement { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ShopEntry.cs b/src/EllieBot/Db/Models/ShopEntry.cs deleted file mode 100644 index 6d08ab3..0000000 --- a/src/EllieBot/Db/Models/ShopEntry.cs +++ /dev/null @@ -1,43 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public enum ShopEntryType -{ - Role, - - List - //Infinite_List, -} - -public class ShopEntry : DbEntity, IIndexed -{ - public int Index { get; set; } - public int Price { get; set; } - public string Name { get; set; } - public ulong AuthorId { get; set; } - - public ShopEntryType Type { get; set; } - - //role - public string RoleName { get; set; } - public ulong RoleId { get; set; } - - //list - public HashSet Items { get; set; } = new(); - public ulong? RoleRequirement { get; set; } -} - -public class ShopEntryItem : DbEntity -{ - public string Text { get; set; } - - public override bool Equals(object obj) - { - if (obj is null || GetType() != obj.GetType()) - return false; - return ((ShopEntryItem)obj).Text == Text; - } - - public override int GetHashCode() - => Text.GetHashCode(StringComparison.InvariantCulture); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs deleted file mode 100644 index 4e55546..0000000 --- a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class SlowmodeIgnoredRole : DbEntity -{ - public ulong RoleId { get; set; } - - // override object.Equals - public override bool Equals(object obj) - { - if (obj is null || GetType() != obj.GetType()) - return false; - - return ((SlowmodeIgnoredRole)obj).RoleId == RoleId; - } - - // override object.GetHashCode - public override int GetHashCode() - => RoleId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs deleted file mode 100644 index c6a62f2..0000000 --- a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class SlowmodeIgnoredUser : DbEntity -{ - public ulong UserId { get; set; } - - // override object.Equals - public override bool Equals(object obj) - { - if (obj is null || GetType() != obj.GetType()) - return false; - - return ((SlowmodeIgnoredUser)obj).UserId == UserId; - } - - // override object.GetHashCode - public override int GetHashCode() - => UserId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamOnlineMessage.cs b/src/EllieBot/Db/Models/StreamOnlineMessage.cs deleted file mode 100644 index 2f8c821..0000000 --- a/src/EllieBot/Db/Models/StreamOnlineMessage.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class StreamOnlineMessage : DbEntity -{ - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } - - public FollowedStream.FType Type { get; set; } - public string Name { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamRoleSettings.cs b/src/EllieBot/Db/Models/StreamRoleSettings.cs deleted file mode 100644 index 8b9b379..0000000 --- a/src/EllieBot/Db/Models/StreamRoleSettings.cs +++ /dev/null @@ -1,68 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class StreamRoleSettings : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - /// - /// Whether the feature is enabled in the guild. - /// - public bool Enabled { get; set; } - - /// - /// Id of the role to give to the users in the role 'FromRole' when they start streaming - /// - public ulong AddRoleId { get; set; } - - /// - /// Id of the role whose users are eligible to get the 'AddRole' - /// - public ulong FromRoleId { get; set; } - - /// - /// If set, feature will only apply to users who have this keyword in their streaming status. - /// - public string Keyword { get; set; } - - /// - /// A collection of whitelisted users' IDs. Whitelisted users don't require 'keyword' in - /// order to get the stream role. - /// - public HashSet Whitelist { get; set; } = new(); - - /// - /// A collection of blacklisted users' IDs. Blacklisted useres will never get the stream role. - /// - public HashSet Blacklist { get; set; } = new(); -} - -public class StreamRoleBlacklistedUser : DbEntity -{ - public ulong UserId { get; set; } - public string Username { get; set; } - - public override bool Equals(object obj) - { - if (obj is not StreamRoleBlacklistedUser x) - return false; - - return x.UserId == UserId; - } - - public override int GetHashCode() - => UserId.GetHashCode(); -} - -public class StreamRoleWhitelistedUser : DbEntity -{ - public ulong UserId { get; set; } - public string Username { get; set; } - - public override bool Equals(object obj) - => obj is StreamRoleWhitelistedUser x ? x.UserId == UserId : false; - - public override int GetHashCode() - => UserId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnbanTimer.cs b/src/EllieBot/Db/Models/UnbanTimer.cs deleted file mode 100644 index 6878b00..0000000 --- a/src/EllieBot/Db/Models/UnbanTimer.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UnbanTimer : DbEntity -{ - public ulong UserId { get; set; } - public DateTime UnbanAt { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is UnbanTimer ut ? ut.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnmuteTimer.cs b/src/EllieBot/Db/Models/UnmuteTimer.cs deleted file mode 100644 index 54638ad..0000000 --- a/src/EllieBot/Db/Models/UnmuteTimer.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UnmuteTimer : DbEntity -{ - public ulong UserId { get; set; } - public DateTime UnmuteAt { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is UnmuteTimer ut ? ut.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnroleTimer.cs b/src/EllieBot/Db/Models/UnroleTimer.cs deleted file mode 100644 index ceb0d4c..0000000 --- a/src/EllieBot/Db/Models/UnroleTimer.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UnroleTimer : DbEntity -{ - public ulong UserId { get; set; } - public ulong RoleId { get; set; } - public DateTime UnbanAt { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode() ^ RoleId.GetHashCode(); - - public override bool Equals(object obj) - => obj is UnroleTimer ut ? ut.UserId == UserId && ut.RoleId == RoleId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UserXpStats.cs b/src/EllieBot/Db/Models/UserXpStats.cs deleted file mode 100644 index e79f735..0000000 --- a/src/EllieBot/Db/Models/UserXpStats.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UserXpStats : DbEntity -{ - public ulong UserId { get; set; } - public ulong GuildId { get; set; } - public long Xp { get; set; } - public long AwardedXp { get; set; } - public XpNotificationLocation NotifyOnLevelUp { get; set; } -} - -public enum XpNotificationLocation { None, Dm, Channel } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/VcRoleInfo.cs b/src/EllieBot/Db/Models/VcRoleInfo.cs deleted file mode 100644 index 3f6155e..0000000 --- a/src/EllieBot/Db/Models/VcRoleInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class VcRoleInfo : DbEntity -{ - public ulong VoiceChannelId { get; set; } - public ulong RoleId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Waifu.cs b/src/EllieBot/Db/Models/Waifu.cs deleted file mode 100644 index a140be5..0000000 --- a/src/EllieBot/Db/Models/Waifu.cs +++ /dev/null @@ -1,75 +0,0 @@ -#nullable disable -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database.Models; - -public class WaifuInfo : DbEntity -{ - public int WaifuId { get; set; } - public DiscordUser Waifu { get; set; } - - public int? ClaimerId { get; set; } - public DiscordUser Claimer { get; set; } - - public int? AffinityId { get; set; } - public DiscordUser Affinity { get; set; } - - public long Price { get; set; } - public List Items { get; set; } = new(); - - public override string ToString() - { - var claimer = "no one"; - var status = string.Empty; - - var waifuUsername = Waifu.Username.TrimTo(20); - var claimerUsername = Claimer?.Username.TrimTo(20); - - if (ClaimerId is not null) - claimer = $"{claimerUsername}#{Claimer.Discriminator}"; - if (AffinityId is null) - status = $"... but {waifuUsername}'s heart is empty"; - else if (AffinityId == ClaimerId) - status = $"... and {waifuUsername} likes {claimerUsername} too <3"; - else - { - status = - $"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}"; - } - - return $"**{waifuUsername}#{Waifu.Discriminator}** - claimed by **{claimer}**\n\t{status}"; - } -} - -public class WaifuLbResult -{ - public string Username { get; set; } - public string Discrim { get; set; } - - public string Claimer { get; set; } - public string ClaimerDiscrim { get; set; } - - public string Affinity { get; set; } - public string AffinityDiscrim { get; set; } - - public long Price { get; set; } - - public override string ToString() - { - var claimer = "no one"; - var status = string.Empty; - - var waifuUsername = Username.TrimTo(20); - var claimerUsername = Claimer?.TrimTo(20); - - if (Claimer is not null) - claimer = $"{claimerUsername}#{ClaimerDiscrim}"; - if (Affinity is null) - status = $"... but {waifuUsername}'s heart is empty"; - else if (Affinity + AffinityDiscrim == Claimer + ClaimerDiscrim) - status = $"... and {waifuUsername} likes {claimerUsername} too <3"; - else - status = $"... but {waifuUsername}'s heart belongs to {Affinity.TrimTo(20)}#{AffinityDiscrim}"; - return $"**{waifuUsername}#{Discrim}** - claimed by **{claimer}**\n\t{status}"; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WaifuItem.cs b/src/EllieBot/Db/Models/WaifuItem.cs deleted file mode 100644 index 53b8f8e..0000000 --- a/src/EllieBot/Db/Models/WaifuItem.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class WaifuItem : DbEntity -{ - public WaifuInfo WaifuInfo { get; set; } - public int? WaifuInfoId { get; set; } - public string ItemEmoji { get; set; } - public string Name { get; set; } -} diff --git a/src/EllieBot/Db/Models/WaifuUpdate.cs b/src/EllieBot/Db/Models/WaifuUpdate.cs deleted file mode 100644 index 70e8960..0000000 --- a/src/EllieBot/Db/Models/WaifuUpdate.cs +++ /dev/null @@ -1,23 +0,0 @@ -#nullable disable -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database.Models; - -public class WaifuUpdate : DbEntity -{ - public int UserId { get; set; } - public DiscordUser User { get; set; } - public WaifuUpdateType UpdateType { get; set; } - - public int? OldId { get; set; } - public DiscordUser Old { get; set; } - - public int? NewId { get; set; } - public DiscordUser New { get; set; } -} - -public enum WaifuUpdateType -{ - AffinityChanged, - Claimed -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WarnExpireAction.cs b/src/EllieBot/Db/Models/WarnExpireAction.cs deleted file mode 100644 index 69d90b8..0000000 --- a/src/EllieBot/Db/Models/WarnExpireAction.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public enum WarnExpireAction -{ - Clear, - Delete -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Warning.cs b/src/EllieBot/Db/Models/Warning.cs deleted file mode 100644 index 9bd9b41..0000000 --- a/src/EllieBot/Db/Models/Warning.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Warning : DbEntity -{ - public ulong GuildId { get; set; } - public ulong UserId { get; set; } - public string Reason { get; set; } - public bool Forgiven { get; set; } - public string ForgivenBy { get; set; } - public string Moderator { get; set; } - public long Weight { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WarningPunishment.cs b/src/EllieBot/Db/Models/WarningPunishment.cs deleted file mode 100644 index a0aa731..0000000 --- a/src/EllieBot/Db/Models/WarningPunishment.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class WarningPunishment : DbEntity -{ - public int Count { get; set; } - public PunishmentAction Punishment { get; set; } - public int Time { get; set; } - public ulong? RoleId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/XpSettings.cs b/src/EllieBot/Db/Models/XpSettings.cs deleted file mode 100644 index a0cae1e..0000000 --- a/src/EllieBot/Db/Models/XpSettings.cs +++ /dev/null @@ -1,62 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class XpSettings : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public HashSet RoleRewards { get; set; } = new(); - public HashSet CurrencyRewards { get; set; } = new(); - public HashSet ExclusionList { get; set; } = new(); - public bool ServerExcluded { get; set; } -} - -public enum ExcludedItemType { Channel, Role } - -public class XpRoleReward : DbEntity -{ - public int XpSettingsId { get; set; } - public XpSettings XpSettings { get; set; } - - public int Level { get; set; } - public ulong RoleId { get; set; } - - /// - /// Whether the role should be removed (true) or added (false) - /// - public bool Remove { get; set; } - - public override int GetHashCode() - => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); - - public override bool Equals(object obj) - => obj is XpRoleReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; -} - -public class XpCurrencyReward : DbEntity -{ - public int XpSettingsId { get; set; } - public XpSettings XpSettings { get; set; } - - public int Level { get; set; } - public int Amount { get; set; } - - public override int GetHashCode() - => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); - - public override bool Equals(object obj) - => obj is XpCurrencyReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; -} - -public class ExcludedItem : DbEntity -{ - public ulong ItemId { get; set; } - public ExcludedItemType ItemType { get; set; } - - public override int GetHashCode() - => ItemId.GetHashCode() ^ ItemType.GetHashCode(); - - public override bool Equals(object obj) - => obj is ExcludedItem ei && ei.ItemId == ItemId && ei.ItemType == ItemType; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/XpShopOwnedItem.cs b/src/EllieBot/Db/Models/XpShopOwnedItem.cs deleted file mode 100644 index dc0f641..0000000 --- a/src/EllieBot/Db/Models/XpShopOwnedItem.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable warnings -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class XpShopOwnedItem : DbEntity -{ - public ulong UserId { get; set; } - public XpShopItemType ItemType { get; set; } - public bool IsUsing { get; set; } - public string ItemKey { get; set; } -} - -public enum XpShopItemType -{ - Background = 0, - Frame = 1, -} \ No newline at end of file diff --git a/src/EllieBot/Db/MysqlContext.cs b/src/EllieBot/Db/MysqlContext.cs deleted file mode 100644 index 1474b30..0000000 --- a/src/EllieBot/Db/MysqlContext.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database; - -public sealed class MysqlContext : EllieContext -{ - private readonly string _connStr; - private readonly string _version; - - protected override string CurrencyTransactionOtherIdDefaultValue - => "NULL"; - - public MysqlContext(string connStr = "Server=localhost", string version = "8.0") - { - _connStr = connStr; - _version = version; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - optionsBuilder - .UseLowerCaseNamingConvention() - .UseMySql(_connStr, ServerVersion.Parse(_version)); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - // mysql is case insensitive by default - // we can set binary collation to change that - modelBuilder.Entity() - .Property(x => x.Name) - .UseCollation("utf8mb4_bin"); - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/PostgreSqlContext.cs b/src/EllieBot/Db/PostgreSqlContext.cs deleted file mode 100644 index dba46f6..0000000 --- a/src/EllieBot/Db/PostgreSqlContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace EllieBot.Services.Database; - -public sealed class PostgreSqlContext : EllieContext -{ - private readonly string _connStr; - - protected override string CurrencyTransactionOtherIdDefaultValue - => "NULL"; - - public PostgreSqlContext(string connStr = "Host=localhost") - { - _connStr = connStr; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); - - base.OnConfiguring(optionsBuilder); - optionsBuilder - .UseLowerCaseNamingConvention() - .UseNpgsql(_connStr); - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/SqliteContext.cs b/src/EllieBot/Db/SqliteContext.cs deleted file mode 100644 index 530bfb4..0000000 --- a/src/EllieBot/Db/SqliteContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; - -namespace EllieBot.Services.Database; - -public sealed class SqliteContext : EllieContext -{ - private readonly string _connectionString; - - protected override string CurrencyTransactionOtherIdDefaultValue - => "NULL"; - - public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60) - { - _connectionString = connectionString; - Database.SetCommandTimeout(commandTimeout); - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - var builder = new SqliteConnectionStringBuilder(_connectionString); - builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource); - optionsBuilder.UseSqlite(builder.ToString()); - } -} \ No newline at end of file diff --git a/src/EllieBot/EllieBot.csproj b/src/EllieBot/EllieBot.csproj index 42d6327..5f4dbb0 100644 --- a/src/EllieBot/EllieBot.csproj +++ b/src/EllieBot/EllieBot.csproj @@ -99,7 +99,6 @@ - diff --git a/src/EllieBot/GlobalUsings.cs b/src/EllieBot/GlobalUsings.cs new file mode 100644 index 0000000..7984372 --- /dev/null +++ b/src/EllieBot/GlobalUsings.cs @@ -0,0 +1,31 @@ +// global using System.Collections.Concurrent +global using NonBlocking; + +// packages +global using Serilog; +global using Humanizer; + +// elliebot +global using EllieBot; +global using EllieBot.Services; +global using Ellie.Common; // new project +global using EllieBot.Common; // old + elliebot specific things +global using EllieBot.Common.Attributes; +global using EllieBot.Extensions; +global using Ellie.Marmalade; + +// discord +global using Discord; +global using Discord.Commands; +global using Discord.Net; +global using Discord.WebSocket; + +// aliases +global using GuildPerm = Discord.GuildPermission; +global using ChannelPerm = Discord.ChannelPermission; +global using BotPermAttribute = Discord.Commands.RequireBotPermissionAttribute; +global using LeftoverAttribute = Discord.Commands.RemainderAttribute; +global using TypeReaderResult = EllieBot.Common.TypeReaders.TypeReaderResult; + +// non-essential +global using JetBrains.Annotations; \ No newline at end of file From f2d5ac147d9154f4adb7abf2a7e3748a2210f387 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 19:30:47 +1200 Subject: [PATCH 26/62] Updated EllieBot.sln and TODO.md --- EllieBot.sln | 17 ++++------------- TODO.md | 7 +++++-- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/EllieBot.sln b/EllieBot.sln index c83e592..ecc63b7 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -11,14 +11,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Dockerfile = Dockerfile LICENSE = LICENSE README.md = README.md + TODO.md = TODO.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot", "src\EllieBot\EllieBot.csproj", "{BCB21472-84D2-4B63-B5DD-31E6A3EC9791}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ayu", "ayu", "{872A4C63-833C-4AE0-91AB-3CE348D3E6F8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ayu.Discord.Voice", "src\ayu\Ayu.Discord.Voice\Ayu.Discord.Voice.csproj", "{5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Tests", "src\EllieBot.Tests\EllieBot.Tests.csproj", "{179DF3B3-AD32-4335-8231-9818338DF3A2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Coordinator", "src\EllieBot.Coordinator\EllieBot.Coordinator.csproj", "{A631DDF0-3AD1-4CB9-8458-314B1320868A}" @@ -27,11 +24,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Generators", "src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.VotesApi", "src\EllieBot.VotesApi\EllieBot.VotesApi.csproj", "{F1A77F56-71B0-430E-AE46-94CDD7D43874}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Marmalade", "src\Ellie.Marmalade\Ellie.Marmalade.csproj", "{76AC715D-12FF-4CBE-9585-A861139A2D0C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Marmalade", "src\Ellie.Marmalade\Ellie.Marmalade.csproj", "{76AC715D-12FF-4CBE-9585-A861139A2D0C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Common", "src\Ellie.Common\Ellie.Common.csproj", "{5C1B88B0-B881-4E20-8382-4DDE275F8642}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Common", "src\Ellie.Common\Ellie.Common.csproj", "{5C1B88B0-B881-4E20-8382-4DDE275F8642}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ellie.Econ", "src\Ellie.Econ\Ellie.Econ.csproj", "{A73A6399-50E1-4362-BE29-86C2C88CF05A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Econ", "src\Ellie.Econ\Ellie.Econ.csproj", "{A73A6399-50E1-4362-BE29-86C2C88CF05A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -43,10 +40,6 @@ Global {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Debug|Any CPU.Build.0 = Debug|Any CPU {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Release|Any CPU.Build.0 = Release|Any CPU - {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067}.Release|Any CPU.Build.0 = Release|Any CPU {179DF3B3-AD32-4335-8231-9818338DF3A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {179DF3B3-AD32-4335-8231-9818338DF3A2}.Debug|Any CPU.Build.0 = Debug|Any CPU {179DF3B3-AD32-4335-8231-9818338DF3A2}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -81,8 +74,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {BCB21472-84D2-4B63-B5DD-31E6A3EC9791} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} - {872A4C63-833C-4AE0-91AB-3CE348D3E6F8} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} - {5AD2EFFB-7774-49B2-A791-3BAC4DAEE067} = {872A4C63-833C-4AE0-91AB-3CE348D3E6F8} {179DF3B3-AD32-4335-8231-9818338DF3A2} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {A631DDF0-3AD1-4CB9-8458-314B1320868A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} diff --git a/TODO.md b/TODO.md index 25bd69c..15c0a05 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,9 @@ # List of things to do - - Finish the full system rewrite + - Finish the Ellie.Marmalade project - Finish the EllieBot.Tests project - Finish the EllieBot project - - Fix the issues MarmaladeLoaderService.cs \ No newline at end of file + - Finish the EllieBot.Coordinator project + - Finish the EllieBot.Generators project + - Finish the EllieBot.Voice project + - Finish the EllieBot.VotesApi project \ No newline at end of file From dac6e283e8a47ba19060b1295dec7b1970c2a2e5 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 21:22:46 +1200 Subject: [PATCH 27/62] Added EllieBot.Voice --- EllieBot.sln | 19 +- src/EllieBot.Voice/CloseCodes.cs | 35 ++ src/EllieBot.Voice/EllieBot.Voice.csproj | 15 + src/EllieBot.Voice/LibOpus.cs | 125 ++++++ src/EllieBot.Voice/LibSodium.cs | 32 ++ src/EllieBot.Voice/Models/SelectProtocol.cs | 23 ++ src/EllieBot.Voice/Models/VoiceHello.cs | 10 + src/EllieBot.Voice/Models/VoiceIdentify.cs | 20 + src/EllieBot.Voice/Models/VoicePayload.cs | 29 ++ src/EllieBot.Voice/Models/VoiceReady.cs | 22 + src/EllieBot.Voice/Models/VoiceResume.cs | 16 + .../Models/VoiceSessionDescription.cs | 13 + src/EllieBot.Voice/Models/VoiceSpeaking.cs | 26 ++ src/EllieBot.Voice/PoopyBufferImmortalized.cs | 136 +++++++ src/EllieBot.Voice/SocketClient.cs | 154 +++++++ src/EllieBot.Voice/SongBuffer.cs | 95 +++++ src/EllieBot.Voice/VoiceClient.cs | 207 ++++++++++ src/EllieBot.Voice/VoiceGateway.cs | 375 ++++++++++++++++++ 18 files changed, 1339 insertions(+), 13 deletions(-) create mode 100644 src/EllieBot.Voice/CloseCodes.cs create mode 100644 src/EllieBot.Voice/EllieBot.Voice.csproj create mode 100644 src/EllieBot.Voice/LibOpus.cs create mode 100644 src/EllieBot.Voice/LibSodium.cs create mode 100644 src/EllieBot.Voice/Models/SelectProtocol.cs create mode 100644 src/EllieBot.Voice/Models/VoiceHello.cs create mode 100644 src/EllieBot.Voice/Models/VoiceIdentify.cs create mode 100644 src/EllieBot.Voice/Models/VoicePayload.cs create mode 100644 src/EllieBot.Voice/Models/VoiceReady.cs create mode 100644 src/EllieBot.Voice/Models/VoiceResume.cs create mode 100644 src/EllieBot.Voice/Models/VoiceSessionDescription.cs create mode 100644 src/EllieBot.Voice/Models/VoiceSpeaking.cs create mode 100644 src/EllieBot.Voice/PoopyBufferImmortalized.cs create mode 100644 src/EllieBot.Voice/SocketClient.cs create mode 100644 src/EllieBot.Voice/SongBuffer.cs create mode 100644 src/EllieBot.Voice/VoiceClient.cs create mode 100644 src/EllieBot.Voice/VoiceGateway.cs diff --git a/EllieBot.sln b/EllieBot.sln index ecc63b7..5a74f26 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -26,9 +26,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.VotesApi", "src\El EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Marmalade", "src\Ellie.Marmalade\Ellie.Marmalade.csproj", "{76AC715D-12FF-4CBE-9585-A861139A2D0C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Common", "src\Ellie.Common\Ellie.Common.csproj", "{5C1B88B0-B881-4E20-8382-4DDE275F8642}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Econ", "src\Ellie.Econ\Ellie.Econ.csproj", "{A73A6399-50E1-4362-BE29-86C2C88CF05A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Voice", "src\EllieBot.Voice\EllieBot.Voice.csproj", "{1D93CE3C-80B4-49C7-A9A2-99988920AAEC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -60,14 +58,10 @@ Global {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU {76AC715D-12FF-4CBE-9585-A861139A2D0C}.Release|Any CPU.Build.0 = Release|Any CPU - {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5C1B88B0-B881-4E20-8382-4DDE275F8642}.Release|Any CPU.Build.0 = Release|Any CPU - {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A73A6399-50E1-4362-BE29-86C2C88CF05A}.Release|Any CPU.Build.0 = Release|Any CPU + {1D93CE3C-80B4-49C7-A9A2-99988920AAEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D93CE3C-80B4-49C7-A9A2-99988920AAEC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D93CE3C-80B4-49C7-A9A2-99988920AAEC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D93CE3C-80B4-49C7-A9A2-99988920AAEC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -79,8 +73,7 @@ Global {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {F1A77F56-71B0-430E-AE46-94CDD7D43874} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {76AC715D-12FF-4CBE-9585-A861139A2D0C} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} - {5C1B88B0-B881-4E20-8382-4DDE275F8642} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} - {A73A6399-50E1-4362-BE29-86C2C88CF05A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {1D93CE3C-80B4-49C7-A9A2-99988920AAEC} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79F61C2C-CDBB-4361-A234-91A0B334CFE4} diff --git a/src/EllieBot.Voice/CloseCodes.cs b/src/EllieBot.Voice/CloseCodes.cs new file mode 100644 index 0000000..6102a19 --- /dev/null +++ b/src/EllieBot.Voice/CloseCodes.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Ayu.Discord.Gateway +{ + public static class CloseCodes + { + private static IReadOnlyDictionary _closeCodes = new ReadOnlyDictionary( + new Dictionary() + { + { 4000, ("Unknown error", "We're not sure what went wrong. Try reconnecting?")}, + { 4001, ("Unknown opcode", "You sent an invalid Gateway opcode or an invalid payload for an opcode. Don't do that!")}, + { 4002, ("Decode error", "You sent an invalid payload to us. Don't do that!")}, + { 4003, ("Not authenticated", "You sent us a payload prior to identifying.")}, + { 4004, ("Authentication failed", "The account token sent with your identify payload is incorrect.")}, + { 4005, ("Already authenticated", "You sent more than one identify payload. Don't do that!")}, + { 4007, ("Invalid seq", "The sequence sent when resuming the session was invalid. Reconnect and start a new session.")}, + { 4008, ("Rate limited", "Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this.")}, + { 4009, ("Session timed out", "Your session timed out. Reconnect and start a new one.")}, + { 4010, ("Invalid shard", "You sent us an invalid shard when identifying.")}, + { 4011, ("Sharding required", "The session would have handled too many guilds - you are required to shard your connection in order to connect.")}, + { 4012, ("Invalid API version", "You sent an invalid version for the gateway.")}, + { 4013, ("Invalid intent(s)", "You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value.")}, + { 4014, ("Disallowed intent(s)", "You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not whitelisted for.")} + }); + + public static (string Error, string Message) GetErrorCodeMessage(int closeCode) + { + if (_closeCodes.TryGetValue(closeCode, out var data)) + return data; + + return ("Unknown error", closeCode.ToString()); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/EllieBot.Voice.csproj b/src/EllieBot.Voice/EllieBot.Voice.csproj new file mode 100644 index 0000000..b8d42d2 --- /dev/null +++ b/src/EllieBot.Voice/EllieBot.Voice.csproj @@ -0,0 +1,15 @@ + + + netstandard2.1 + 9.0 + true + CS8632 + 1.0.2 + EllieBot.Voice + + + + + + + diff --git a/src/EllieBot.Voice/LibOpus.cs b/src/EllieBot.Voice/LibOpus.cs new file mode 100644 index 0000000..a43a9d8 --- /dev/null +++ b/src/EllieBot.Voice/LibOpus.cs @@ -0,0 +1,125 @@ +using System; +using System.Runtime.InteropServices; + +namespace EllieBot.Voice +{ + internal static unsafe class LibOpus + { + public const string OPUS = "data/lib/opus"; + + [DllImport(OPUS, EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr CreateEncoder(int Fs, int channels, int application, out OpusError error); + + [DllImport(OPUS, EntryPoint = "opus_encoder_destroy", CallingConvention = CallingConvention.Cdecl)] + internal static extern void DestroyEncoder(IntPtr encoder); + + [DllImport(OPUS, EntryPoint = "opus_encode", CallingConvention = CallingConvention.Cdecl)] + internal static extern int Encode(IntPtr st, byte* pcm, int frame_size, byte* data, int max_data_bytes); + + [DllImport(OPUS, EntryPoint = "opus_encode_float", CallingConvention = CallingConvention.Cdecl)] + internal static extern int EncodeFloat(IntPtr st, byte* pcm, int frame_size, byte* data, int max_data_bytes); + + [DllImport(OPUS, EntryPoint = "opus_encoder_ctl", CallingConvention = CallingConvention.Cdecl)] + internal static extern int EncoderCtl(IntPtr st, OpusCtl request, int value); + } + + public enum OpusApplication + { + VOIP = 2048, + Audio = 2049, + RestrictedLowdelay = 2051 + } + + public unsafe class LibOpusEncoder : IDisposable + { + private readonly IntPtr _encoderPtr; + + private readonly int _sampleRate; + + // private readonly int _channels; + // private readonly int _bitRate; + private readonly int _frameDelay; + + private readonly int _frameSizePerChannel; + public int FrameSizePerChannel => _frameSizePerChannel; + + public const int MaxData = 1276; + + public LibOpusEncoder(int sampleRate, int channels, int bitRate, int frameDelay) + { + _sampleRate = sampleRate; + // _channels = channels; + // _bitRate = bitRate; + _frameDelay = frameDelay; + _frameSizePerChannel = _sampleRate * _frameDelay / 1000; + + _encoderPtr = LibOpus.CreateEncoder(sampleRate, channels, (int)OpusApplication.Audio, out var error); + if (error != OpusError.OK) + throw new ExternalException(error.ToString()); + + LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetSignal, (int)OpusSignal.Music); + LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetInbandFEC, 1); + LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetBitrate, bitRate); + LibOpus.EncoderCtl(_encoderPtr, OpusCtl.SetPacketLossPerc, 2); + } + + public int SetControl(OpusCtl ctl, int value) + => LibOpus.EncoderCtl(_encoderPtr, ctl, value); + + public int Encode(Span input, byte[] output) + { + fixed (byte* inPtr = input) + fixed (byte* outPtr = output) + return LibOpus.Encode(_encoderPtr, inPtr, FrameSizePerChannel, outPtr, output.Length); + } + + public int EncodeFloat(Span input, byte[] output) + { + fixed (byte* inPtr = input) + fixed (byte* outPtr = output) + return LibOpus.EncodeFloat(_encoderPtr, inPtr, FrameSizePerChannel, outPtr, output.Length); + } + + + public void Dispose() + => LibOpus.DestroyEncoder(_encoderPtr); + } + + public enum OpusCtl + { + SetBitrate = 4002, + GetBitrate = 4003, + SetBandwidth = 4008, + GetBandwidth = 4009, + SetComplexity = 4010, + GetComplexity = 4011, + SetInbandFEC = 4012, + GetInbandFEC = 4013, + SetPacketLossPerc = 4014, + GetPacketLossPerc = 4015, + SetLsbDepth = 4036, + GetLsbDepth = 4037, + SetDtx = 4016, + GetDtx = 4017, + SetSignal = 4024 + } + + public enum OpusError + { + OK = 0, + BadArg = -1, + BufferToSmall = -2, + InternalError = -3, + InvalidPacket = -4, + Unimplemented = -5, + InvalidState = -6, + AllocFail = -7 + } + + public enum OpusSignal + { + Auto = -1000, + Voice = 3001, + Music = 3002, + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/LibSodium.cs b/src/EllieBot.Voice/LibSodium.cs new file mode 100644 index 0000000..bbbc77d --- /dev/null +++ b/src/EllieBot.Voice/LibSodium.cs @@ -0,0 +1,32 @@ +using System; +using System.Runtime.InteropServices; + +namespace EllieBot.Voice +{ + internal static unsafe class Sodium + { + private const string SODIUM = "data/lib/libsodium"; + + [DllImport(SODIUM, EntryPoint = "crypto_secretbox_easy", CallingConvention = CallingConvention.Cdecl)] + private static extern int SecretBoxEasy(byte* output, byte* input, long inputLength, byte* nonce, byte* secret); + [DllImport(SODIUM, EntryPoint = "crypto_secretbox_open_easy", CallingConvention = CallingConvention.Cdecl)] + private static extern int SecretBoxOpenEasy(byte* output, byte* input, ulong inputLength, byte* nonce, byte* secret); + + public static int Encrypt(byte[] input, int inputOffset, long inputLength, byte[] output, int outputOffset, in ReadOnlySpan nonce, byte[] secret) + { + fixed (byte* inPtr = input) + fixed (byte* outPtr = output) + fixed (byte* noncePtr = nonce) + fixed (byte* secretPtr = secret) + return SecretBoxEasy(outPtr + outputOffset, inPtr + inputOffset, inputLength - inputOffset, noncePtr, secretPtr); + } + public static int Decrypt(byte[] input, ulong inputLength, byte[] output, in ReadOnlySpan nonce, byte[] secret) + { + fixed (byte* outPtr = output) + fixed (byte* inPtr = input) + fixed (byte* noncePtr = nonce) + fixed (byte* secretPtr = secret) + return SecretBoxOpenEasy(outPtr, inPtr, inputLength, noncePtr, secretPtr); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/SelectProtocol.cs b/src/EllieBot.Voice/Models/SelectProtocol.cs new file mode 100644 index 0000000..1a9dfa9 --- /dev/null +++ b/src/EllieBot.Voice/Models/SelectProtocol.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; + +namespace EllieBot.Voice.Models +{ + public sealed class SelectProtocol + { + [JsonProperty("protocol")] + public string Protocol { get; set; } + + [JsonProperty("data")] + public ProtocolData Data { get; set; } + + public sealed class ProtocolData + { + [JsonProperty("address")] + public string Address { get; set; } + [JsonProperty("port")] + public int Port { get; set; } + [JsonProperty("mode")] + public string Mode { get; set; } + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoiceHello.cs b/src/EllieBot.Voice/Models/VoiceHello.cs new file mode 100644 index 0000000..8fda1d1 --- /dev/null +++ b/src/EllieBot.Voice/Models/VoiceHello.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace EllieBot.Voice.Models +{ + public sealed class VoiceHello + { + [JsonProperty("heartbeat_interval")] + public int HeartbeatInterval { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoiceIdentify.cs b/src/EllieBot.Voice/Models/VoiceIdentify.cs new file mode 100644 index 0000000..9841869 --- /dev/null +++ b/src/EllieBot.Voice/Models/VoiceIdentify.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; + +namespace EllieBot.Voice.Models +{ + public sealed class VoiceIdentify + { + [JsonProperty("server_id")] + public string ServerId { get; set; } + + [JsonProperty("user_id")] + public string UserId { get; set; } + + [JsonProperty("session_id")] + public string SessionId { get; set; } + + [JsonProperty("token")] + public string Token { get; set; } + + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoicePayload.cs b/src/EllieBot.Voice/Models/VoicePayload.cs new file mode 100644 index 0000000..5ac642e --- /dev/null +++ b/src/EllieBot.Voice/Models/VoicePayload.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Discord.Models.Gateway +{ + public sealed class VoicePayload + { + [JsonProperty("op")] + public VoiceOpCode OpCode { get; set; } + + [JsonProperty("d")] + public JToken Data { get; set; } + } + + public enum VoiceOpCode + { + Identify = 0, + SelectProtocol = 1, + Ready = 2, + Heartbeat = 3, + SessionDescription = 4, + Speaking = 5, + HeartbeatAck = 6, + Resume = 7, + Hello = 8, + Resumed = 9, + ClientDisconnect = 13, + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoiceReady.cs b/src/EllieBot.Voice/Models/VoiceReady.cs new file mode 100644 index 0000000..99cc753 --- /dev/null +++ b/src/EllieBot.Voice/Models/VoiceReady.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace EllieBot.Voice.Models +{ + public sealed class VoiceReady + { + [JsonProperty("ssrc")] + public uint Ssrc { get; set; } + + [JsonProperty("ip")] + public string Ip { get; set; } + + [JsonProperty("port")] + public int Port { get; set; } + + [JsonProperty("modes")] + public string[] Modes { get; set; } + + [JsonProperty("heartbeat_interval")] + public string HeartbeatInterval { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoiceResume.cs b/src/EllieBot.Voice/Models/VoiceResume.cs new file mode 100644 index 0000000..bad82b2 --- /dev/null +++ b/src/EllieBot.Voice/Models/VoiceResume.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace EllieBot.Voice.Models +{ + public sealed class VoiceResume + { + [JsonProperty("server_id")] + public string ServerId { get; set; } + + [JsonProperty("session_id")] + public string SessionId { get; set; } + + [JsonProperty("token")] + public string Token { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoiceSessionDescription.cs b/src/EllieBot.Voice/Models/VoiceSessionDescription.cs new file mode 100644 index 0000000..85bdc5e --- /dev/null +++ b/src/EllieBot.Voice/Models/VoiceSessionDescription.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace EllieBot.Voice.Models +{ + public sealed class VoiceSessionDescription + { + [JsonProperty("mode")] + public string Mode { get; set; } + + [JsonProperty("secret_key")] + public byte[] SecretKey { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/Models/VoiceSpeaking.cs b/src/EllieBot.Voice/Models/VoiceSpeaking.cs new file mode 100644 index 0000000..a9a0610 --- /dev/null +++ b/src/EllieBot.Voice/Models/VoiceSpeaking.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using System; + +namespace EllieBot.Voice.Models +{ + public sealed class VoiceSpeaking + { + [JsonProperty("speaking")] + public int Speaking { get; set; } + + [JsonProperty("delay")] + public int Delay { get; set; } + + [JsonProperty("ssrc")] + public uint Ssrc { get; set; } + + [Flags] + public enum State + { + None = 0, + Microphone = 1 << 0, + Soundshare = 1 << 1, + Priority = 1 << 2 + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/PoopyBufferImmortalized.cs b/src/EllieBot.Voice/PoopyBufferImmortalized.cs new file mode 100644 index 0000000..4a80c86 --- /dev/null +++ b/src/EllieBot.Voice/PoopyBufferImmortalized.cs @@ -0,0 +1,136 @@ +#nullable enable +using System; +using System.Buffers; +using System.Threading; +using System.Threading.Tasks; + +namespace EllieBot.Voice +{ + public sealed class PoopyBufferImmortalized : ISongBuffer + { + private readonly byte[] _buffer; + private readonly byte[] _outputArray; + private CancellationToken _cancellationToken; + private bool _isStopped; + + public int ReadPosition { get; private set; } + public int WritePosition { get; private set; } + + public int ContentLength => WritePosition >= ReadPosition + ? WritePosition - ReadPosition + : (_buffer.Length - ReadPosition) + WritePosition; + + public int FreeSpace => _buffer.Length - ContentLength; + + public bool Stopped => _cancellationToken.IsCancellationRequested || _isStopped; + + public PoopyBufferImmortalized(int frameSize) + { + _buffer = ArrayPool.Shared.Rent(1_000_000); + _outputArray = new byte[frameSize]; + + ReadPosition = 0; + WritePosition = 0; + } + + public void Stop() + => _isStopped = true; + + // this method needs a rewrite + public Task BufferAsync(ITrackDataSource source, CancellationToken cancellationToken) + { + _cancellationToken = cancellationToken; + var bufferingCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + Task.Run(async () => + { + var output = ArrayPool.Shared.Rent(38400); + try + { + int read; + while (!Stopped && (read = source.Read(output)) > 0) + { + while (!Stopped && FreeSpace <= read) + { + bufferingCompleted.TrySetResult(true); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + + if (Stopped) + break; + + Write(output, read); + } + } + finally + { + ArrayPool.Shared.Return(output); + bufferingCompleted.TrySetResult(true); + } + }, cancellationToken); + + return bufferingCompleted.Task; + } + + private void Write(byte[] input, int writeCount) + { + if (WritePosition + writeCount < _buffer.Length) + { + Buffer.BlockCopy(input, 0, _buffer, WritePosition, writeCount); + WritePosition += writeCount; + return; + } + + var wroteNormally = _buffer.Length - WritePosition; + Buffer.BlockCopy(input, 0, _buffer, WritePosition, wroteNormally); + var wroteFromStart = writeCount - wroteNormally; + Buffer.BlockCopy(input, wroteNormally, _buffer, 0, wroteFromStart); + WritePosition = wroteFromStart; + } + + public Span Read(int count, out int length) + { + var toRead = Math.Min(ContentLength, count); + var wp = WritePosition; + + if (ContentLength == 0) + { + length = 0; + return Span.Empty; + } + + if (wp > ReadPosition || ReadPosition + toRead <= _buffer.Length) + { + // thsi can be achieved without copying if + // writer never writes until the end, + // but leaves a single chunk free + Span toReturn = _outputArray; + ((Span)_buffer).Slice(ReadPosition, toRead).CopyTo(toReturn); + ReadPosition += toRead; + length = toRead; + return toReturn; + } + else + { + Span toReturn = _outputArray; + var toEnd = _buffer.Length - ReadPosition; + var bufferSpan = (Span)_buffer; + + bufferSpan.Slice(ReadPosition, toEnd).CopyTo(toReturn); + var fromStart = toRead - toEnd; + bufferSpan.Slice(0, fromStart).CopyTo(toReturn.Slice(toEnd)); + ReadPosition = fromStart; + length = toEnd + fromStart; + return toReturn; + } + } + + public void Dispose() + => ArrayPool.Shared.Return(_buffer); + + public void Reset() + { + ReadPosition = 0; + WritePosition = 0; + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/SocketClient.cs b/src/EllieBot.Voice/SocketClient.cs new file mode 100644 index 0000000..7c32af1 --- /dev/null +++ b/src/EllieBot.Voice/SocketClient.cs @@ -0,0 +1,154 @@ +using Serilog; +using System; +using System.Buffers; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; + +namespace Ayu.Discord.Gateway +{ + public class SocketClient : IDisposable + { + private ClientWebSocket? _ws; + + public event Func? PayloadReceived = delegate { return Task.CompletedTask; }; + public event Func? WebsocketClosed = delegate { return Task.CompletedTask; }; + + const int CHUNK_SIZE = 1024 * 16; + + public async Task RunAndBlockAsync(Uri url, CancellationToken cancel) + { + var error = "Error."; + var bufferWriter = new ArrayBufferWriter(CHUNK_SIZE); + try + { + using (_ws = new()) + { + await _ws.ConnectAsync(url, cancel).ConfigureAwait(false); + // WebsocketConnected!.Invoke(this); + + while (true) + { + var result = await _ws.ReceiveAsync(bufferWriter.GetMemory(CHUNK_SIZE), cancel); + bufferWriter.Advance(result.Count); + if (result.MessageType == WebSocketMessageType.Close) + { + var closeMessage = CloseCodes.GetErrorCodeMessage((int?)_ws.CloseStatus ?? 0).Message; + error = $"Websocket closed ({_ws.CloseStatus}): {_ws.CloseStatusDescription} {closeMessage}"; + break; + } + + if (result.EndOfMessage) + { + var pr = PayloadReceived; + var data = bufferWriter.WrittenMemory.ToArray(); + bufferWriter.Clear(); + + if (pr is not null) + { + await pr.Invoke(data); + } + } + } + } + } + catch (WebSocketException ex) + { + Log.Warning("Disconnected, check your internet connection..."); + Log.Debug(ex, "Websocket Exception in websocket client"); + } + catch (OperationCanceledException) + { + // ignored + } + catch (Exception ex) + { + Log.Error(ex, "Error in websocket client. {Message}", ex.Message); + } + finally + { + bufferWriter.Clear(); + _ws = null; + await ClosedAsync(error).ConfigureAwait(false); + } + } + + private async Task ClosedAsync(string msg = "Error") + { + try + { + await WebsocketClosed!.Invoke(msg).ConfigureAwait(false); + } + catch + { + } + } + + private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1); + + public async Task SendAsync(byte[] data) + { + await _sendLock.WaitAsync().ConfigureAwait(false); + try + { + var ws = _ws; + if (ws is null) + throw new WebSocketException("Websocket is disconnected."); + for (var i = 0; i < data.Length; i += 4096) + { + var count = i + 4096 > data.Length ? data.Length - i : 4096; + await ws.SendAsync(new(data, i, count), + WebSocketMessageType.Text, + i + count >= data.Length, + CancellationToken.None).ConfigureAwait(false); + } + } + finally + { + _sendLock.Release(); + } + } + + public async Task SendBulkAsync(byte[] data) + { + var ws = _ws; + if (ws is null) + throw new WebSocketException("Websocket is disconnected."); + + await ws.SendAsync(new(data, 0, data.Length), + WebSocketMessageType.Binary, + true, + CancellationToken.None).ConfigureAwait(false); + } + + public async Task CloseAsync(string msg = "Stop") + { + if (_ws is not null && _ws.State != WebSocketState.Closed) + { + try + { + await _ws.CloseAsync(WebSocketCloseStatus.InternalServerError, msg, CancellationToken.None) + .ConfigureAwait(false); + + return true; + } + catch + { + } + } + + return false; + } + + public void Dispose() + { + PayloadReceived = null; + WebsocketClosed = null; + var ws = _ws; + if (ws is null) + return; + + ws.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/SongBuffer.cs b/src/EllieBot.Voice/SongBuffer.cs new file mode 100644 index 0000000..73f2bd1 --- /dev/null +++ b/src/EllieBot.Voice/SongBuffer.cs @@ -0,0 +1,95 @@ +using Serilog; +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace EllieBot.Voice +{ + public interface ISongBuffer : IDisposable + { + Span Read(int toRead, out int read); + Task BufferAsync(ITrackDataSource source, CancellationToken cancellationToken); + void Reset(); + void Stop(); + } + + public interface ITrackDataSource + { + public int Read(byte[] output); + } + + public sealed class FfmpegTrackDataSource : ITrackDataSource, IDisposable + { + private Process _p; + + private readonly string _streamUrl; + private readonly bool _isLocal; + private readonly string _pcmType; + + private FfmpegTrackDataSource(int bitDepth, string streamUrl, bool isLocal) + { + this._pcmType = bitDepth == 16 ? "s16le" : "f32le"; + this._streamUrl = streamUrl; + this._isLocal = isLocal; + } + + public static FfmpegTrackDataSource CreateAsync(int bitDepth, string streamUrl, bool isLocal) + { + try + { + var source = new FfmpegTrackDataSource(bitDepth, streamUrl, isLocal); + source.StartFFmpegProcess(); + return source; + } + catch (System.ComponentModel.Win32Exception) + { + Log.Error(@"You have not properly installed or configured FFMPEG. +Please install and configure FFMPEG to play music. +Check the guides for your platform on how to setup ffmpeg correctly: + Windows Guide: https://goo.gl/OjKk8F + Linux Guide: https://goo.gl/ShjCUo"); + throw; + } + catch (OperationCanceledException) + { + } + catch (InvalidOperationException) + { + } + catch (Exception ex) + { + Log.Information(ex, "Error starting ffmpeg: {ErrorMessage}", ex.Message); + } + + return null; + } + + private Process StartFFmpegProcess() + { + var args = $"-err_detect ignore_err -i {_streamUrl} -f {_pcmType} -ar 48000 -vn -ac 2 pipe:1 -loglevel error"; + if (!_isLocal) + args = $"-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 {args}"; + + return _p = Process.Start(new ProcessStartInfo + { + FileName = "ffmpeg", + Arguments = args, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = false, + CreateNoWindow = true, + }); + } + + public int Read(byte[] output) + => _p.StandardOutput.BaseStream.Read(output); + + public void Dispose() + { + try { _p?.Kill(); } catch { } + + try { _p?.Dispose(); } catch { } + } + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/VoiceClient.cs b/src/EllieBot.Voice/VoiceClient.cs new file mode 100644 index 0000000..12d6e20 --- /dev/null +++ b/src/EllieBot.Voice/VoiceClient.cs @@ -0,0 +1,207 @@ +using System; +using System.Buffers; + +namespace EllieBot.Voice +{ + public sealed class VoiceClient : IDisposable + { + delegate int EncodeDelegate(Span input, byte[] output); + + private readonly int sampleRate; + private readonly int bitRate; + private readonly int channels; + private readonly int frameDelay; + private readonly int bitDepth; + + public LibOpusEncoder Encoder { get; } + private readonly ArrayPool _arrayPool; + + public int BitDepth => bitDepth * 8; + public int Delay => frameDelay; + + private int FrameSizePerChannel => Encoder.FrameSizePerChannel; + public int InputLength => FrameSizePerChannel * channels * bitDepth; + + EncodeDelegate Encode; + + // https://github.com/xiph/opus/issues/42 w + public VoiceClient(SampleRate sampleRate = SampleRate._48k, + Bitrate bitRate = Bitrate._192k, + Channels channels = Channels.Two, + FrameDelay frameDelay = FrameDelay.Delay20, + BitDepthEnum bitDepthEnum = BitDepthEnum.Float32) + { + this.frameDelay = (int)frameDelay; + this.sampleRate = (int)sampleRate; + this.bitRate = (int)bitRate; + this.channels = (int)channels; + this.bitDepth = (int)bitDepthEnum; + + this.Encoder = new(this.sampleRate, this.channels, this.bitRate, this.frameDelay); + + Encode = bitDepthEnum switch + { + BitDepthEnum.Float32 => Encoder.EncodeFloat, + BitDepthEnum.UInt16 => Encoder.Encode, + _ => throw new NotSupportedException(nameof(BitDepth)) + }; + + if (bitDepthEnum == BitDepthEnum.Float32) + { + Encode = Encoder.EncodeFloat; + } + else + { + Encode = Encoder.Encode; + } + + _arrayPool = ArrayPool.Shared; + } + + public int SendPcmFrame(VoiceGateway gw, Span data, int offset, int count) + { + var secretKey = gw.SecretKey; + if (secretKey.Length == 0) + { + return (int)SendPcmError.SecretKeyUnavailable; + } + + // encode using opus + var encodeOutput = _arrayPool.Rent(LibOpusEncoder.MaxData); + try + { + var encodeOutputLength = Encode(data, encodeOutput); + return SendOpusFrame(gw, encodeOutput, 0, encodeOutputLength); + } + finally + { + _arrayPool.Return(encodeOutput); + } + } + + public int SendOpusFrame(VoiceGateway gw, byte[] data, int offset, int count) + { + var secretKey = gw.SecretKey; + if (secretKey is null) + { + return (int)SendPcmError.SecretKeyUnavailable; + } + + // form RTP header + var headerLength = 1 // version + flags + + 1 // payload type + + 2 // sequence + + 4 // timestamp + + 4; // ssrc + + var header = new byte[headerLength]; + + header[0] = 0x80; // version + flags + header[1] = 0x78; // payload type + + // get byte values for header data + var seqBytes = BitConverter.GetBytes(gw.Sequence); // 2 + var nonceBytes = BitConverter.GetBytes(gw.NonceSequence); // 2 + var timestampBytes = BitConverter.GetBytes(gw.Timestamp); // 4 + var ssrcBytes = BitConverter.GetBytes(gw.Ssrc); // 4 + + gw.Timestamp += (uint)FrameSizePerChannel; + gw.Sequence++; + gw.NonceSequence++; + + if (BitConverter.IsLittleEndian) + { + Array.Reverse(seqBytes); + Array.Reverse(nonceBytes); + Array.Reverse(timestampBytes); + Array.Reverse(ssrcBytes); + } + + // copy headers + Buffer.BlockCopy(seqBytes, 0, header, 2, 2); + Buffer.BlockCopy(timestampBytes, 0, header, 4, 4); + Buffer.BlockCopy(ssrcBytes, 0, header, 8, 4); + + //// encryption part + //// create a byte array where to store the encrypted data + //// it has to be inputLength + crypto_secretbox_MACBYTES (constant with value 16) + var encryptedBytes = new byte[count + 16]; + + //// form nonce with header + 12 empty bytes + //var nonce = new byte[24]; + //Buffer.BlockCopy(rtpHeader, 0, nonce, 0, rtpHeader.Length); + + var nonce = new byte[4]; + Buffer.BlockCopy(seqBytes, 0, nonce, 2, 2); + + Sodium.Encrypt(data, 0, count, encryptedBytes, 0, nonce, secretKey); + + var rtpDataLength = headerLength + encryptedBytes.Length + nonce.Length; + var rtpData = _arrayPool.Rent(rtpDataLength); + try + { + //copy headers + Buffer.BlockCopy(header, 0, rtpData, 0, header.Length); + //copy audio data + Buffer.BlockCopy(encryptedBytes, 0, rtpData, header.Length, encryptedBytes.Length); + Buffer.BlockCopy(nonce, 0, rtpData, rtpDataLength - 4, 4); + + gw.SendRtpData(rtpData, rtpDataLength); + // FUTURE When there's a break in the sent data, + // the packet transmission shouldn't simply stop. + // Instead, send five frames of silence (0xF8, 0xFF, 0xFE) + // before stopping to avoid unintended Opus interpolation + // with subsequent transmissions. + + return rtpDataLength; + } + finally + { + _arrayPool.Return(rtpData); + } + } + + public void Dispose() + => Encoder.Dispose(); + } + + public enum SendPcmError + { + SecretKeyUnavailable = -1, + } + + + public enum FrameDelay + { + Delay5 = 5, + Delay10 = 10, + Delay20 = 20, + Delay40 = 40, + Delay60 = 60, + } + + public enum BitDepthEnum + { + UInt16 = sizeof(UInt16), + Float32 = sizeof(float), + } + + public enum SampleRate + { + _48k = 48_000, + } + + public enum Bitrate + { + _64k = 64 * 1024, + _96k = 96 * 1024, + _128k = 128 * 1024, + _192k = 192 * 1024, + } + + public enum Channels + { + One = 1, + Two = 2, + } +} \ No newline at end of file diff --git a/src/EllieBot.Voice/VoiceGateway.cs b/src/EllieBot.Voice/VoiceGateway.cs new file mode 100644 index 0000000..af20aa3 --- /dev/null +++ b/src/EllieBot.Voice/VoiceGateway.cs @@ -0,0 +1,375 @@ +using EllieBot.Voice.Models; +using Discord.Models.Gateway; +using Newtonsoft.Json.Linq; +using Serilog; +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Ayu.Discord.Gateway; +using Newtonsoft.Json; + +namespace EllieBot.Voice +{ + public class VoiceGateway + { + private class QueueItem + { + public VoicePayload Payload { get; } + public TaskCompletionSource Result { get; } + + public QueueItem(VoicePayload payload, TaskCompletionSource result) + { + Payload = payload; + Result = result; + } + } + + private readonly ulong _guildId; + private readonly ulong _userId; + private readonly string _sessionId; + private readonly string _token; + private readonly string _endpoint; + private readonly Uri _websocketUrl; + private readonly Channel _channel; + + public TaskCompletionSource ConnectingFinished { get; } + + private readonly Random _rng; + private readonly SocketClient _ws; + private readonly UdpClient _udpClient; + private Timer? _heartbeatTimer; + private bool _receivedAck; + private IPEndPoint? _udpEp; + + public uint Ssrc { get; private set; } + public string Ip { get; private set; } = string.Empty; + public int Port { get; private set; } = 0; + public byte[] SecretKey { get; private set; } = Array.Empty(); + public string Mode { get; private set; } = string.Empty; + public ushort Sequence { get; set; } + public uint NonceSequence { get; set; } + public uint Timestamp { get; set; } + public string MyIp { get; private set; } = string.Empty; + public ushort MyPort { get; private set; } + private bool _shouldResume; + + private readonly CancellationTokenSource _stopCancellationSource; + private readonly CancellationToken _stopCancellationToken; + public bool Stopped => _stopCancellationToken.IsCancellationRequested; + + public event Func OnClosed = delegate { return Task.CompletedTask; }; + + public VoiceGateway(ulong guildId, ulong userId, string session, string token, string endpoint) + { + this._guildId = guildId; + this._userId = userId; + this._sessionId = session; + this._token = token; + this._endpoint = endpoint; + + //Log.Information("g: {GuildId} u: {UserId} sess: {Session} tok: {Token} ep: {Endpoint}", + // guildId, userId, session, token, endpoint); + + this._websocketUrl = new($"wss://{_endpoint.Replace(":80", "")}?v=4"); + this._channel = Channel.CreateUnbounded(new() + { + SingleReader = true, + SingleWriter = false, + AllowSynchronousContinuations = false, + }); + + ConnectingFinished = new(); + + _rng = new(); + + _ws = new(); + _udpClient = new(); + _stopCancellationSource = new(); + _stopCancellationToken = _stopCancellationSource.Token; + + _ws.PayloadReceived += _ws_PayloadReceived; + _ws.WebsocketClosed += _ws_WebsocketClosed; + } + + public Task WaitForReadyAsync() + => ConnectingFinished.Task; + + private async Task SendLoop() + { + while (!_stopCancellationToken.IsCancellationRequested) + { + try + { + var qi = await _channel.Reader.ReadAsync(_stopCancellationToken); + //Log.Information("Sending payload with opcode {OpCode}", qi.Payload.OpCode); + + var json = JsonConvert.SerializeObject(qi.Payload); + + if (!_stopCancellationToken.IsCancellationRequested) + await _ws.SendAsync(Encoding.UTF8.GetBytes(json)); + _ = Task.Run(() => qi.Result.TrySetResult(true)); + } + catch (ChannelClosedException) + { + Log.Warning("Voice gateway send channel is closed"); + } + } + } + + private async Task _ws_PayloadReceived(byte[] arg) + { + var payload = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(arg)); + if (payload is null) + return; + try + { + //Log.Information("Received payload with opcode {OpCode}", payload.OpCode); + + switch (payload.OpCode) + { + case VoiceOpCode.Identify: + // sent, not received. + break; + case VoiceOpCode.SelectProtocol: + // sent, not received + break; + case VoiceOpCode.Ready: + var ready = payload.Data.ToObject(); + await HandleReadyAsync(ready!); + _shouldResume = true; + break; + case VoiceOpCode.Heartbeat: + // sent, not received + break; + case VoiceOpCode.SessionDescription: + var sd = payload.Data.ToObject(); + await HandleSessionDescription(sd!); + break; + case VoiceOpCode.Speaking: + // ignore for now + break; + case VoiceOpCode.HeartbeatAck: + _receivedAck = true; + break; + case VoiceOpCode.Resume: + // sent, not received + break; + case VoiceOpCode.Hello: + var hello = payload.Data.ToObject(); + await HandleHelloAsync(hello!); + break; + case VoiceOpCode.Resumed: + _shouldResume = true; + break; + case VoiceOpCode.ClientDisconnect: + break; + } + } + catch (Exception ex) + { + Log.Error(ex, "Error handling payload with opcode {OpCode}: {Message}", payload.OpCode, ex.Message); + } + } + private Task _ws_WebsocketClosed(string arg) + { + if (!string.IsNullOrWhiteSpace(arg)) + { + Log.Warning("Voice Websocket closed: {Arg}", arg); + } + + var hbt = _heartbeatTimer; + hbt?.Change(Timeout.Infinite, Timeout.Infinite); + _heartbeatTimer = null; + + if (!_stopCancellationToken.IsCancellationRequested && _shouldResume) + { + _ = _ws.RunAndBlockAsync(_websocketUrl, _stopCancellationToken); + return Task.CompletedTask; + } + + _ws.WebsocketClosed -= _ws_WebsocketClosed; + _ws.PayloadReceived -= _ws_PayloadReceived; + + if (!_stopCancellationToken.IsCancellationRequested) + _stopCancellationSource.Cancel(); + + return this.OnClosed(this); + } + + public void SendRtpData(byte[] rtpData, int length) + => _udpClient.Send(rtpData, length, _udpEp); + + private Task HandleSessionDescription(VoiceSessionDescription sd) + { + SecretKey = sd.SecretKey; + Mode = sd.Mode; + + _ = Task.Run(() => ConnectingFinished.TrySetResult(true)); + + return Task.CompletedTask; + } + + private Task ResumeAsync() + { + _shouldResume = false; + return SendCommandPayloadAsync(new() + { + OpCode = VoiceOpCode.Resume, + Data = JToken.FromObject(new VoiceResume + { + ServerId = this._guildId.ToString(), + SessionId = this._sessionId, + Token = this._token, + }) + }); + } + + private async Task HandleReadyAsync(VoiceReady ready) + { + Ssrc = ready.Ssrc; + + //Log.Information("Received ready {GuildId}, {Session}, {Token}", guildId, session, token); + + _udpEp = new(IPAddress.Parse(ready.Ip), ready.Port); + + var ssrcBytes = BitConverter.GetBytes(Ssrc); + Array.Reverse(ssrcBytes); + var ipDiscoveryData = new byte[74]; + Buffer.BlockCopy(ssrcBytes, 0, ipDiscoveryData, 4, ssrcBytes.Length); + ipDiscoveryData[0] = 0x00; + ipDiscoveryData[1] = 0x01; + ipDiscoveryData[2] = 0x00; + ipDiscoveryData[3] = 0x46; + await _udpClient.SendAsync(ipDiscoveryData, ipDiscoveryData.Length, _udpEp); + while (true) + { + var buffer = _udpClient.Receive(ref _udpEp); + + if (buffer.Length == 74) + { + //Log.Information("Received IP discovery data."); + + var myIp = Encoding.UTF8.GetString(buffer, 8, buffer.Length - 10); + MyIp = myIp.TrimEnd('\0'); + MyPort = (ushort)((buffer[^2] << 8) | buffer[^1]); + + //Log.Information("{MyIp}:{MyPort}", MyIp, MyPort); + + await SelectProtocol(); + return; + } + + //Log.Information("Received voice data"); + } + } + + private Task HandleHelloAsync(VoiceHello data) + { + _receivedAck = true; + _heartbeatTimer = new(async _ => + { + await SendHeartbeatAsync(); + }, default, data.HeartbeatInterval, data.HeartbeatInterval); + + if (_shouldResume) + { + return ResumeAsync(); + } + + return IdentifyAsync(); + } + + private Task IdentifyAsync() + => SendCommandPayloadAsync(new() + { + OpCode = VoiceOpCode.Identify, + Data = JToken.FromObject(new VoiceIdentify + { + ServerId = _guildId.ToString(), + SessionId = _sessionId, + Token = _token, + UserId = _userId.ToString(), + }) + }); + + private Task SelectProtocol() + => SendCommandPayloadAsync(new() + { + OpCode = VoiceOpCode.SelectProtocol, + Data = JToken.FromObject(new SelectProtocol + { + Protocol = "udp", + Data = new() + { + Address = MyIp, + Port = MyPort, + Mode = "xsalsa20_poly1305_lite", + } + }) + }); + + private async Task SendHeartbeatAsync() + { + if (!_receivedAck) + { + Log.Warning("Voice gateway didn't receive HearbeatAck - closing"); + var success = await _ws.CloseAsync(); + if (!success) + await _ws_WebsocketClosed(null); + return; + } + + _receivedAck = false; + await SendCommandPayloadAsync(new() + { + OpCode = VoiceOpCode.Heartbeat, + Data = JToken.FromObject(_rng.Next()) + }); + } + + public Task SendSpeakingAsync(VoiceSpeaking.State speaking) + => SendCommandPayloadAsync(new() + { + OpCode = VoiceOpCode.Speaking, + Data = JToken.FromObject(new VoiceSpeaking + { + Delay = 0, + Ssrc = Ssrc, + Speaking = (int)speaking + }) + }); + + public Task StopAsync() + { + Started = false; + _shouldResume = false; + if (!_stopCancellationSource.IsCancellationRequested) + try { _stopCancellationSource.Cancel(); } catch { } + return _ws.CloseAsync("Stopped by the user."); + } + + public Task Start() + { + Started = true; + _ = SendLoop(); + return _ws.RunAndBlockAsync(_websocketUrl, _stopCancellationToken); + } + + public bool Started { get; set; } + + public async Task SendCommandPayloadAsync(VoicePayload payload) + { + var complete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var queueItem = new QueueItem(payload, complete); + + if (!_channel.Writer.TryWrite(queueItem)) + await _channel.Writer.WriteAsync(queueItem); + + await complete.Task; + } + } +} \ No newline at end of file From b1e6e93fe4e0bd09d4319de77dc27a4123593c24 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 23:43:23 +1200 Subject: [PATCH 28/62] Updated Ellie.Marmalade --- .../Attributes/FilterAttribute.cs | 2 +- .../Attributes/MarmaladePermAttribute.cs | 2 +- .../Attributes/bot_owner_onlyAttribute.cs | 2 +- .../Attributes/bot_permAttribute.cs | 2 +- .../Attributes/cmdAttribute.cs | 2 +- .../Attributes/injectAttribute.cs | 2 +- .../Attributes/leftoverAttribute.cs | 2 +- .../Attributes/prioAttribute.cs | 2 +- .../Attributes/svcAttribute.cs | 2 +- .../Attributes/user_permAttribute.cs | 2 +- src/Ellie.Marmalade/Canary.cs | 2 +- src/Ellie.Marmalade/Context/AnyContext.cs | 11 +------ src/Ellie.Marmalade/Context/DmContext.cs | 2 +- src/Ellie.Marmalade/Context/GuildContext.cs | 2 +- src/Ellie.Marmalade/Ellie.Marmalade.csproj | 13 ++++----- .../Extensions/EmbedBuilderExtensions.cs | 14 --------- .../Extensions/MarmaladeExtensions.cs | 29 ++++++++----------- .../ParamParser/ParamParser.cs | 2 +- .../ParamParser/ParseResult.cs | 2 +- src/Ellie.Marmalade/Strings/CommandStrings.cs | 2 +- .../Strings/IMarmaladeStrings.cs | 2 +- .../Strings/IMarmaladeStringsProvider.cs | 2 +- .../Strings/LocalMarmaladeStringsProvider.cs | 2 +- .../Strings/MarmaladeStrings.cs | 2 +- src/Ellie.Marmalade/Strings/StringsLoader.cs | 2 +- 25 files changed, 39 insertions(+), 70 deletions(-) delete mode 100644 src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs diff --git a/src/Ellie.Marmalade/Attributes/FilterAttribute.cs b/src/Ellie.Marmalade/Attributes/FilterAttribute.cs index de6ae24..d5a428b 100644 --- a/src/Ellie.Marmalade/Attributes/FilterAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/FilterAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Overridden to implement custom checks which commands have to pass in order to be executed. diff --git a/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs b/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs index 0001d76..0f04c23 100644 --- a/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/MarmaladePermAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Used as a marker class for bot_perm and user_perm Attributes diff --git a/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs b/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs index 8186614..31c3cfd 100644 --- a/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/bot_owner_onlyAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; [AttributeUsage(AttributeTargets.Method)] public sealed class bot_owner_onlyAttribute : MarmaladePermAttribute diff --git a/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs b/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs index 30fa320..6bd6af1 100644 --- a/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/bot_permAttribute.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class bot_permAttribute : MarmaladePermAttribute diff --git a/src/Ellie.Marmalade/Attributes/cmdAttribute.cs b/src/Ellie.Marmalade/Attributes/cmdAttribute.cs index 56ce03b..0dc068e 100644 --- a/src/Ellie.Marmalade/Attributes/cmdAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/cmdAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Marks a method as a snek command diff --git a/src/Ellie.Marmalade/Attributes/injectAttribute.cs b/src/Ellie.Marmalade/Attributes/injectAttribute.cs index 4865cff..be843ae 100644 --- a/src/Ellie.Marmalade/Attributes/injectAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/injectAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Marks services in command arguments for injection. diff --git a/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs b/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs index b16c225..71543e2 100644 --- a/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/leftoverAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Marks the parameter to take diff --git a/src/Ellie.Marmalade/Attributes/prioAttribute.cs b/src/Ellie.Marmalade/Attributes/prioAttribute.cs index 9b1cc81..2868b23 100644 --- a/src/Ellie.Marmalade/Attributes/prioAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/prioAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Sets the priority of a command in case there are multiple commands with the same name but different parameters. diff --git a/src/Ellie.Marmalade/Attributes/svcAttribute.cs b/src/Ellie.Marmalade/Attributes/svcAttribute.cs index dab065f..a453303 100644 --- a/src/Ellie.Marmalade/Attributes/svcAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/svcAttribute.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Marks the class as a service which can be used within the same Medusa diff --git a/src/Ellie.Marmalade/Attributes/user_permAttribute.cs b/src/Ellie.Marmalade/Attributes/user_permAttribute.cs index 7d195eb..b0a3aa3 100644 --- a/src/Ellie.Marmalade/Attributes/user_permAttribute.cs +++ b/src/Ellie.Marmalade/Attributes/user_permAttribute.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class user_permAttribute : MarmaladePermAttribute diff --git a/src/Ellie.Marmalade/Canary.cs b/src/Ellie.Marmalade/Canary.cs index 6fef82c..4b7bbbb 100644 --- a/src/Ellie.Marmalade/Canary.cs +++ b/src/Ellie.Marmalade/Canary.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// The base class which will be loaded as a module into EllieBot diff --git a/src/Ellie.Marmalade/Context/AnyContext.cs b/src/Ellie.Marmalade/Context/AnyContext.cs index 816a95d..4f7207c 100644 --- a/src/Ellie.Marmalade/Context/AnyContext.cs +++ b/src/Ellie.Marmalade/Context/AnyContext.cs @@ -1,7 +1,7 @@ using Discord; using EllieBot; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Commands which take this class as a first parameter can be executed in both DMs and Servers @@ -40,13 +40,4 @@ public abstract class AnyContext /// Arguments (if any) to format in /// A formatted localized string public abstract string GetText(string key, object[]? args = null); - - /// - /// Creates a context-aware instance - /// (future feature for guild-based embed colors) - /// Any code dealing with embeds should use it for future-proofness - /// instead of manually creating embedbuilder instances - /// - /// A context-aware instance - public abstract IEmbedBuilder Embed(); } \ No newline at end of file diff --git a/src/Ellie.Marmalade/Context/DmContext.cs b/src/Ellie.Marmalade/Context/DmContext.cs index a703fa4..d971ee5 100644 --- a/src/Ellie.Marmalade/Context/DmContext.cs +++ b/src/Ellie.Marmalade/Context/DmContext.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Commands which take this type as the first parameter can only be executed in DMs diff --git a/src/Ellie.Marmalade/Context/GuildContext.cs b/src/Ellie.Marmalade/Context/GuildContext.cs index 33cca4f..63ca873 100644 --- a/src/Ellie.Marmalade/Context/GuildContext.cs +++ b/src/Ellie.Marmalade/Context/GuildContext.cs @@ -1,6 +1,6 @@ using Discord; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Commands which take this type as a first parameter can only be executed in a server diff --git a/src/Ellie.Marmalade/Ellie.Marmalade.csproj b/src/Ellie.Marmalade/Ellie.Marmalade.csproj index aa15438..b01a911 100644 --- a/src/Ellie.Marmalade/Ellie.Marmalade.csproj +++ b/src/Ellie.Marmalade/Ellie.Marmalade.csproj @@ -1,24 +1,21 @@ - net6.0 + net8.0 enable enable - preview - true - Ellie.Marmalade The EllieBot Devs - - - + + + - 5.0.0 + 9.0.0 diff --git a/src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs b/src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs deleted file mode 100644 index 6b6d50d..0000000 --- a/src/Ellie.Marmalade/Extensions/EmbedBuilderExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace EllieBot; - -public static class EmbedBuilderExtensions -{ - public static IEmbedBuilder WithOkColor(this IEmbedBuilder eb) - => eb.WithColor(EmbedColor.Ok); - - public static IEmbedBuilder WithPendingColor(this IEmbedBuilder eb) - => eb.WithColor(EmbedColor.Pending); - - public static IEmbedBuilder WithErrorColor(this IEmbedBuilder eb) - => eb.WithColor(EmbedColor.Error); - -} diff --git a/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs b/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs index c02f973..1047966 100644 --- a/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs +++ b/src/Ellie.Marmalade/Extensions/MarmaladeExtensions.cs @@ -1,11 +1,10 @@ using Discord; -using Ellie.Marmalade; -namespace EllieBot; +namespace EllieBot.Marmalade; public static class MarmaladeExtensions { - public static Task EmbedAsync(this IMessageChannel ch, IEmbedBuilder embed, string msg = "") + public static Task EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "") => ch.SendMessageAsync(msg, embed: embed.Build(), options: new() @@ -13,25 +12,21 @@ public static class MarmaladeExtensions RetryMode = RetryMode.Retry502 }); - // unlocalized - public static Task SendConfirmAsync(this IMessageChannel ch, AnyContext ctx, string msg) - => ch.EmbedAsync(ctx.Embed().WithOkColor().WithDescription(msg)); - - public static Task SendPendingAsync(this IMessageChannel ch, AnyContext ctx, string msg) - => ch.EmbedAsync(ctx.Embed().WithPendingColor().WithDescription(msg)); - - public static Task SendErrorAsync(this IMessageChannel ch, AnyContext ctx, string msg) - => ch.EmbedAsync(ctx.Embed().WithErrorColor().WithDescription(msg)); - // unlocalized public static Task SendConfirmAsync(this AnyContext ctx, string msg) - => ctx.Channel.SendConfirmAsync(ctx, msg); + => ctx.Channel.EmbedAsync(new EmbedBuilder() + .WithColor(0, 200, 0) + .WithDescription(msg)); public static Task SendPendingAsync(this AnyContext ctx, string msg) - => ctx.Channel.SendPendingAsync(ctx, msg); + => ctx.Channel.EmbedAsync(new EmbedBuilder() + .WithColor(200, 200, 0) + .WithDescription(msg)); public static Task SendErrorAsync(this AnyContext ctx, string msg) - => ctx.Channel.SendErrorAsync(ctx, msg); + => ctx.Channel.EmbedAsync(new EmbedBuilder() + .WithColor(200, 0, 0) + .WithDescription(msg)); // localized public static Task ConfirmAsync(this AnyContext ctx) @@ -63,4 +58,4 @@ public static class MarmaladeExtensions public static Task ReplyConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args) => ctx.SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}"); -} +} \ No newline at end of file diff --git a/src/Ellie.Marmalade/ParamParser/ParamParser.cs b/src/Ellie.Marmalade/ParamParser/ParamParser.cs index a174a78..e4758d6 100644 --- a/src/Ellie.Marmalade/ParamParser/ParamParser.cs +++ b/src/Ellie.Marmalade/ParamParser/ParamParser.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Overridden to implement parsers for custom types diff --git a/src/Ellie.Marmalade/ParamParser/ParseResult.cs b/src/Ellie.Marmalade/ParamParser/ParseResult.cs index e12b77e..24c115b 100644 --- a/src/Ellie.Marmalade/ParamParser/ParseResult.cs +++ b/src/Ellie.Marmalade/ParamParser/ParseResult.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; public readonly struct ParseResult { diff --git a/src/Ellie.Marmalade/Strings/CommandStrings.cs b/src/Ellie.Marmalade/Strings/CommandStrings.cs index 5d06f3c..056d028 100644 --- a/src/Ellie.Marmalade/Strings/CommandStrings.cs +++ b/src/Ellie.Marmalade/Strings/CommandStrings.cs @@ -1,6 +1,6 @@ using YamlDotNet.Serialization; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; public readonly struct CommandStrings { diff --git a/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs b/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs index 37c4299..f76cf82 100644 --- a/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs +++ b/src/Ellie.Marmalade/Strings/IMarmaladeStrings.cs @@ -1,6 +1,6 @@ using System.Globalization; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Defines methods to retrieve and reload marmalade strings diff --git a/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs b/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs index 6df86b0..2845f94 100644 --- a/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs +++ b/src/Ellie.Marmalade/Strings/IMarmaladeStringsProvider.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Implemented by classes which provide localized strings in their own ways diff --git a/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs b/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs index 0ea98d5..3b02ca6 100644 --- a/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs +++ b/src/Ellie.Marmalade/Strings/LocalMarmaladeStringsProvider.cs @@ -1,4 +1,4 @@ -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; public class LocalMarmaladeStringsProvider : IMarmaladeStringsProvider { diff --git a/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs b/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs index 286e9a1..c4f9f26 100644 --- a/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs +++ b/src/Ellie.Marmalade/Strings/MarmaladeStrings.cs @@ -1,7 +1,7 @@ using System.Globalization; using Serilog; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; public class MarmaladeStrings : IMarmaladeStrings { diff --git a/src/Ellie.Marmalade/Strings/StringsLoader.cs b/src/Ellie.Marmalade/Strings/StringsLoader.cs index 986fcad..e9b2493 100644 --- a/src/Ellie.Marmalade/Strings/StringsLoader.cs +++ b/src/Ellie.Marmalade/Strings/StringsLoader.cs @@ -2,7 +2,7 @@ using Serilog; using YamlDotNet.Serialization; -namespace Ellie.Marmalade; +namespace EllieBot.Marmalade; /// /// Loads strings from the shortcut or localizable path From 9a92725f41f23eb3b234bb69d73d956fd9aa3f7b Mon Sep 17 00:00:00 2001 From: Toastie Date: Mon, 13 May 2024 00:37:12 +1200 Subject: [PATCH 29/62] Added pack-and-push.ps1 --- src/Ellie.Marmalade/pack-and-push.ps1 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/Ellie.Marmalade/pack-and-push.ps1 diff --git a/src/Ellie.Marmalade/pack-and-push.ps1 b/src/Ellie.Marmalade/pack-and-push.ps1 new file mode 100644 index 0000000..5f5a2eb --- /dev/null +++ b/src/Ellie.Marmalade/pack-and-push.ps1 @@ -0,0 +1,2 @@ +dotnet pack -o bin/Release/packed +dotnet nuget push bin/Release/packed/ --source emotionlab \ No newline at end of file From 83a8a34aeacaf83d108cd114af4dfabceaa0afe4 Mon Sep 17 00:00:00 2001 From: Toastie Date: Mon, 13 May 2024 00:56:07 +1200 Subject: [PATCH 30/62] Updated EllieBot.VotesApi --- src/EllieBot.VotesApi/Common/AuthHandler.cs | 3 +-- src/EllieBot.VotesApi/EllieBot.VotesApi.csproj | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/EllieBot.VotesApi/Common/AuthHandler.cs b/src/EllieBot.VotesApi/Common/AuthHandler.cs index 9294153..fbe7aa8 100644 --- a/src/EllieBot.VotesApi/Common/AuthHandler.cs +++ b/src/EllieBot.VotesApi/Common/AuthHandler.cs @@ -20,9 +20,8 @@ namespace EllieBot.VotesApi public AuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, - ISystemClock clock, IConfiguration conf) - : base(options, logger, encoder, clock) + : base(options, logger, encoder) => _conf = conf; protected override Task HandleAuthenticateAsync() diff --git a/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj b/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj index f42db3d..af0ed1f 100644 --- a/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj +++ b/src/EllieBot.VotesApi/EllieBot.VotesApi.csproj @@ -1,13 +1,13 @@  - net6.0 + net8.0 Linux - + From f3d824c0fd9b77d7ba8cf1f8ab7cb9fe1fad7fbe Mon Sep 17 00:00:00 2001 From: Toastie Date: Mon, 13 May 2024 00:56:41 +1200 Subject: [PATCH 31/62] Updated TODO.md --- TODO.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 15c0a05..dc3a441 100644 --- a/TODO.md +++ b/TODO.md @@ -1,9 +1,9 @@ # List of things to do - - Finish the Ellie.Marmalade project + - ~~Finish the Ellie.Marmalade project~~ Done - Finish the EllieBot.Tests project - Finish the EllieBot project - Finish the EllieBot.Coordinator project - Finish the EllieBot.Generators project - - Finish the EllieBot.Voice project - - Finish the EllieBot.VotesApi project \ No newline at end of file + - ~~Finish the EllieBot.Voice project~~ Done + - ~~Finish the EllieBot.VotesApi project~~ \ No newline at end of file From 453d823e5be3473ca58cb0d24f8f976e0b587eb5 Mon Sep 17 00:00:00 2001 From: Toastie Date: Mon, 13 May 2024 01:00:17 +1200 Subject: [PATCH 32/62] Updated EllieBot.Coordinator --- src/EllieBot.Coordinator/EllieBot.Coordinator.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj b/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj index 91942cc..af90db3 100644 --- a/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj +++ b/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 @@ -9,11 +9,11 @@ - - - + + + - + From 4d7056dc61ba25bc0ce83c28be313ea847d532a7 Mon Sep 17 00:00:00 2001 From: Toastie Date: Mon, 13 May 2024 01:08:29 +1200 Subject: [PATCH 33/62] Updated EllieBot.Generators --- .../Cloneable/CloneableGenerator.cs | 96 ++--- .../Cloneable/SymbolExtensions.cs | 3 +- .../Cloneable/SyntaxReceiver.cs | 2 +- .../Command/CommandAttributesGenerator.cs | 336 ------------------ .../EllieBot.Generators.csproj | 1 + .../LocalizedStringsGenerator.cs | 36 +- 6 files changed, 69 insertions(+), 405 deletions(-) delete mode 100644 src/EllieBot.Generators/Command/CommandAttributesGenerator.cs diff --git a/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs b/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs index 6bd7da4..4b5f8cb 100644 --- a/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs +++ b/src/EllieBot.Generators/Cloneable/CloneableGenerator.cs @@ -6,8 +6,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; -using System.Collections.Generic; -using System.Linq; using System.Text; namespace Cloneable @@ -23,54 +21,60 @@ namespace Cloneable private const string CLONE_ATTRIBUTE_STRING = "CloneAttribute"; private const string IGNORE_CLONE_ATTRIBUTE_STRING = "IgnoreCloneAttribute"; - private const string CLONEABLE_ATTRIBUTE_TEXT = @"// -using System; + private const string CLONEABLE_ATTRIBUTE_TEXT = $$""" + // + using System; + + namespace {{CLONEABLE_NAMESPACE}} + { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)] + internal sealed class {{CLONEABLE_ATTRIBUTE_STRING}} : Attribute + { + public {{CLONEABLE_ATTRIBUTE_STRING}}() + { + } + + public bool {{EXPLICIT_DECLARATION_KEY_STRING}} { get; set; } + } + } -namespace " + CLONEABLE_NAMESPACE + @" -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)] - public sealed class " + CLONEABLE_ATTRIBUTE_STRING + @" : Attribute - { - public " + CLONEABLE_ATTRIBUTE_STRING + @"() - { - } + """; - public bool " + EXPLICIT_DECLARATION_KEY_STRING + @" { get; set; } - } -} -"; + private const string CLONE_PROPERTY_ATTRIBUTE_TEXT = $$""" + // + using System; + + namespace {{CLONEABLE_NAMESPACE}} + { + [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] + internal sealed class {{CLONE_ATTRIBUTE_STRING}} : Attribute + { + public {{CLONE_ATTRIBUTE_STRING}}() + { + } + + public bool {{PREVENT_DEEP_COPY_KEY_STRING}} { get; set; } + } + } - private const string CLONE_PROPERTY_ATTRIBUTE_TEXT = @"// -using System; + """; -namespace " + CLONEABLE_NAMESPACE + @" -{ - [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] - public sealed class " + CLONE_ATTRIBUTE_STRING + @" : Attribute - { - public " + CLONE_ATTRIBUTE_STRING + @"() - { - } + private const string IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT = $$""" + // + using System; + + namespace {{CLONEABLE_NAMESPACE}} + { + [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] + internal sealed class {{IGNORE_CLONE_ATTRIBUTE_STRING}} : Attribute + { + public {{IGNORE_CLONE_ATTRIBUTE_STRING}}() + { + } + } + } - public bool " + PREVENT_DEEP_COPY_KEY_STRING + @" { get; set; } - } -} -"; - - private const string IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT = @"// -using System; - -namespace " + CLONEABLE_NAMESPACE + @" -{ - [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] - public sealed class " + IGNORE_CLONE_ATTRIBUTE_STRING + @" : Attribute - { - public " + IGNORE_CLONE_ATTRIBUTE_STRING + @"() - { - } - } -} -"; + """; private INamedTypeSymbol? _cloneableAttribute; private INamedTypeSymbol? _ignoreCloneAttribute; @@ -180,7 +184,7 @@ namespace {namespaceName} }}"; } - private IEnumerable<(string line, bool isCloneable)> GenerateFieldAssignmentsCode(INamedTypeSymbol classSymbol, bool isExplicit) + private IEnumerable<(string line, bool isCloneable)> GenerateFieldAssignmentsCode(INamedTypeSymbol classSymbol, bool isExplicit ) { var fieldNames = GetCloneableProperties(classSymbol, isExplicit); diff --git a/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs b/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs index 6c0c605..8d6de76 100644 --- a/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs +++ b/src/EllieBot.Generators/Cloneable/SymbolExtensions.cs @@ -1,8 +1,7 @@ // Code temporarily yeeted from // https://github.com/mostmand/Cloneable/blob/master/Cloneable/CloneableGenerator.cs // because of NRT issue -using System.Collections.Generic; -using System.Linq; + using Microsoft.CodeAnalysis; namespace Cloneable diff --git a/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs b/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs index 962c395..ae0d029 100644 --- a/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs +++ b/src/EllieBot.Generators/Cloneable/SyntaxReceiver.cs @@ -1,7 +1,7 @@ // Code temporarily yeeted from // https://github.com/mostmand/Cloneable/blob/master/Cloneable/CloneableGenerator.cs // because of NRT issue -using System.Collections.Generic; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/EllieBot.Generators/Command/CommandAttributesGenerator.cs b/src/EllieBot.Generators/Command/CommandAttributesGenerator.cs deleted file mode 100644 index 81a758c..0000000 --- a/src/EllieBot.Generators/Command/CommandAttributesGenerator.cs +++ /dev/null @@ -1,336 +0,0 @@ -// #nullable enable -// using System; -// using System.CodeDom.Compiler; -// using System.Collections.Generic; -// using System.Collections.Immutable; -// using System.Collections.ObjectModel; -// using System.Diagnostics; -// using System.IO; -// using System.Linq; -// using System.Text; -// using System.Threading; -// using Microsoft.CodeAnalysis; -// using Microsoft.CodeAnalysis.CSharp; -// using Microsoft.CodeAnalysis.CSharp.Syntax; -// using Microsoft.CodeAnalysis.Text; -// -// namespace EllieBot.Generators.Command; -// -// [Generator] -// public class CommandAttributesGenerator : IIncrementalGenerator -// { -// public const string ATTRIBUTE = @"// -// -// namespace EllieBot.Common; -// -// [System.AttributeUsage(System.AttributeTargets.Method)] -// public class CmdAttribute : System.Attribute -// { -// -// }"; -// -// public class MethodModel -// { -// public string? Namespace { get; } -// public IReadOnlyCollection Classes { get; } -// public string ReturnType { get; } -// public string MethodName { get; } -// public IEnumerable Params { get; } -// -// public MethodModel(string? ns, IReadOnlyCollection classes, string returnType, string methodName, IEnumerable @params) -// { -// Namespace = ns; -// Classes = classes; -// ReturnType = returnType; -// MethodName = methodName; -// Params = @params; -// } -// } -// -// public class FileModel -// { -// public string? Namespace { get; } -// public IReadOnlyCollection ClassHierarchy { get; } -// public IReadOnlyCollection Methods { get; } -// -// public FileModel(string? ns, IReadOnlyCollection classHierarchy, IReadOnlyCollection methods) -// { -// Namespace = ns; -// ClassHierarchy = classHierarchy; -// Methods = methods; -// } -// } -// -// public void Initialize(IncrementalGeneratorInitializationContext context) -// { -// // #if DEBUG -// // if (!Debugger.IsAttached) -// // Debugger.Launch(); -// // // SpinWait.SpinUntil(() => Debugger.IsAttached); -// // #endif -// context.RegisterPostInitializationOutput(static ctx => ctx.AddSource( -// "CmdAttribute.g.cs", -// SourceText.From(ATTRIBUTE, Encoding.UTF8))); -// -// var methods = context.SyntaxProvider -// .CreateSyntaxProvider( -// static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 }, -// static (ctx, cancel) => Transform(ctx, cancel)) -// .Where(static m => m is not null) -// .Where(static m => m?.ChildTokens().Any(static x => x.IsKind(SyntaxKind.PublicKeyword)) ?? false); -// -// var compilationMethods = context.CompilationProvider.Combine(methods.Collect()); -// -// context.RegisterSourceOutput(compilationMethods, -// static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right)); -// } -// -// private static void RegisterAction(in SourceProductionContext ctx, -// Compilation comp, -// in ImmutableArray methods) -// { -// if (methods is { IsDefaultOrEmpty: true }) -// return; -// -// var models = GetModels(comp, methods, ctx.CancellationToken); -// -// foreach (var model in models) -// { -// var name = $"{model.Namespace}.{string.Join(".", model.ClassHierarchy)}.g.cs"; -// try -// { -// var source = GetSourceText(model); -// ctx.AddSource(name, SourceText.From(source, Encoding.UTF8)); -// } -// catch (Exception ex) -// { -// Console.WriteLine($"Error writing source file {name}\n" + ex); -// } -// } -// } -// -// private static string GetSourceText(FileModel model) -// { -// using var sw = new StringWriter(); -// using var tw = new IndentedTextWriter(sw); -// -// tw.WriteLine("// "); -// tw.WriteLine("#pragma warning disable CS1066"); -// -// if (model.Namespace is not null) -// { -// tw.WriteLine($"namespace {model.Namespace};"); -// tw.WriteLine(); -// } -// -// foreach (var className in model.ClassHierarchy) -// { -// tw.WriteLine($"public partial class {className}"); -// tw.WriteLine("{"); -// tw.Indent ++; -// } -// -// foreach (var method in model.Methods) -// { -// tw.WriteLine("[EllieCommand]"); -// tw.WriteLine("[EllieDescription]"); -// tw.WriteLine("[Aliases]"); -// tw.WriteLine($"public partial {method.ReturnType} {method.MethodName}({string.Join(", ", method.Params)});"); -// } -// -// foreach (var _ in model.ClassHierarchy) -// { -// tw.Indent --; -// tw.WriteLine("}"); -// } -// -// tw.Flush(); -// return sw.ToString(); -// } -// -// private static IReadOnlyCollection GetModels(Compilation compilation, -// in ImmutableArray inputMethods, -// CancellationToken cancel) -// { -// var models = new List(); -// -// var methods = inputMethods -// .Where(static x => x is not null) -// .Distinct(); -// -// var methodModels = methods -// .Select(x => MethodDeclarationToMethodModel(compilation, x!)) -// .Where(static x => x is not null) -// .Cast(); -// -// var groups = methodModels -// .GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}"); -// -// foreach (var group in groups) -// { -// if (cancel.IsCancellationRequested) -// return new Collection(); -// -// if (group is null) -// continue; -// -// var elems = group.ToList(); -// if (elems.Count is 0) -// continue; -// -// var model = new FileModel( -// methods: elems, -// ns: elems[0].Namespace, -// classHierarchy: elems![0].Classes -// ); -// -// models.Add(model); -// } -// -// -// return models; -// } -// -// private static MethodModel? MethodDeclarationToMethodModel(Compilation comp, MethodDeclarationSyntax decl) -// { -// // SpinWait.SpinUntil(static () => Debugger.IsAttached); -// -// SemanticModel semanticModel; -// try -// { -// semanticModel = comp.GetSemanticModel(decl.SyntaxTree); -// } -// catch -// { -// // for some reason this method can throw "Not part of this compilation" argument exception -// return null; -// } -// -// var methodModel = new MethodModel( -// @params: decl.ParameterList.Parameters -// .Where(p => p.Type is not null) -// .Select(p => -// { -// var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword)) -// ? "params " -// : string.Empty; -// -// var type = semanticModel -// .GetTypeInfo(p.Type!) -// .Type -// ?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); -// -// -// var name = p.Identifier.Text; -// -// var suffix = string.Empty; -// if (p.Default is not null) -// { -// if (p.Default.Value is LiteralExpressionSyntax) -// { -// suffix = " = " + p.Default.Value; -// } -// else if (p.Default.Value is MemberAccessExpressionSyntax maes) -// { -// var maesSemModel = comp.GetSemanticModel(maes.SyntaxTree); -// var sym = maesSemModel.GetSymbolInfo(maes.Name); -// if (sym.Symbol is null) -// { -// suffix = " = " + p.Default.Value; -// } -// else -// { -// suffix = " = " + sym.Symbol.ToDisplayString(); -// } -// } -// } -// -// return $"{prefix}{type} {name}{suffix}"; -// }) -// .ToList(), -// methodName: decl.Identifier.Text, -// returnType: decl.ReturnType.ToString(), -// ns: GetNamespace(decl), -// classes: GetClasses(decl) -// ); -// -// return methodModel; -// } -// -// //https://github.com/andrewlock/NetEscapades.EnumGenerators/blob/main/src/NetEscapades.EnumGenerators/EnumGenerator.cs -// static string? GetNamespace(MethodDeclarationSyntax declarationSyntax) -// { -// // determine the namespace the class is declared in, if any -// string? nameSpace = null; -// var parentOfInterest = declarationSyntax.Parent; -// while (parentOfInterest is not null) -// { -// parentOfInterest = parentOfInterest.Parent; -// -// if (parentOfInterest is BaseNamespaceDeclarationSyntax ns) -// { -// nameSpace = ns.Name.ToString(); -// while (true) -// { -// if (ns.Parent is not NamespaceDeclarationSyntax parent) -// { -// break; -// } -// -// ns = parent; -// nameSpace = $"{ns.Name}.{nameSpace}"; -// } -// -// return nameSpace; -// } -// -// } -// -// return nameSpace; -// } -// -// static IReadOnlyCollection GetClasses(MethodDeclarationSyntax declarationSyntax) -// { -// // determine the namespace the class is declared in, if any -// var classes = new LinkedList(); -// var parentOfInterest = declarationSyntax.Parent; -// while (parentOfInterest is not null) -// { -// if (parentOfInterest is ClassDeclarationSyntax cds) -// { -// classes.AddFirst(cds.Identifier.ToString()); -// } -// -// parentOfInterest = parentOfInterest.Parent; -// } -// -// Debug.WriteLine($"Method {declarationSyntax.Identifier.Text} has {classes.Count} classes"); -// -// return classes; -// } -// -// private static MethodDeclarationSyntax? Transform(GeneratorSyntaxContext ctx, CancellationToken cancel) -// { -// var methodDecl = ctx.Node as MethodDeclarationSyntax; -// if (methodDecl is null) -// return default; -// -// foreach (var attListSyntax in methodDecl.AttributeLists) -// { -// foreach (var attSyntax in attListSyntax.Attributes) -// { -// if (cancel.IsCancellationRequested) -// return default; -// -// var symbol = ctx.SemanticModel.GetSymbolInfo(attSyntax).Symbol; -// if (symbol is not IMethodSymbol attSymbol) -// continue; -// -// if (attSymbol.ContainingType.ToDisplayString() == "EllieBot.Common.CmdAttribute") -// return methodDecl; -// } -// } -// -// return default; -// } -// } \ No newline at end of file diff --git a/src/EllieBot.Generators/EllieBot.Generators.csproj b/src/EllieBot.Generators/EllieBot.Generators.csproj index 742b2ea..1dbbc1d 100644 --- a/src/EllieBot.Generators/EllieBot.Generators.csproj +++ b/src/EllieBot.Generators/EllieBot.Generators.csproj @@ -5,6 +5,7 @@ latest false true + true diff --git a/src/EllieBot.Generators/LocalizedStringsGenerator.cs b/src/EllieBot.Generators/LocalizedStringsGenerator.cs index 95abda9..72d5040 100644 --- a/src/EllieBot.Generators/LocalizedStringsGenerator.cs +++ b/src/EllieBot.Generators/LocalizedStringsGenerator.cs @@ -1,10 +1,6 @@ #nullable enable -using System; using System.CodeDom.Compiler; -using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.Linq; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; using Newtonsoft.Json; @@ -26,24 +22,23 @@ namespace EllieBot.Generators [Generator] public class LocalizedStringsGenerator : ISourceGenerator { - private const string LOC_STR_SOURCE = @"namespace EllieBot -{ - public readonly struct LocStr - { - public readonly string Key; - public readonly object[] Params; - - public LocStr(string key, params object[] data) - { - Key = key; - Params = data; - } - } -}"; + // private const string LOC_STR_SOURCE = @"namespace EllieBot + // { + // public readonly struct LocStr + // { + // public readonly string Key; + // public readonly object[] Params; + // + // public LocStr(string key, params object[] data) + // { + // Key = key; + // Params = data; + // } + // } + // }"; public void Initialize(GeneratorInitializationContext context) { - } public void Execute(GeneratorExecutionContext context) @@ -55,6 +50,7 @@ namespace EllieBot.Generators using (var stringWriter = new StringWriter()) using (var sw = new IndentedTextWriter(stringWriter)) { + sw.WriteLine("#pragma warning disable CS8981"); sw.WriteLine("namespace EllieBot;"); sw.WriteLine(); @@ -106,7 +102,7 @@ namespace EllieBot.Generators context.AddSource("strs.g.cs", stringWriter.ToString()); } - context.AddSource("LocStr.g.cs", LOC_STR_SOURCE); + // context.AddSource("LocStr.g.cs", LOC_STR_SOURCE); } private List GetFields(string? dataText) From 545786e23ef6e97afebe9017a616c0fb3491bc3f Mon Sep 17 00:00:00 2001 From: Toastie Date: Mon, 13 May 2024 01:11:00 +1200 Subject: [PATCH 34/62] Updated TODO.md with finished projects --- TODO.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index dc3a441..d7b33d4 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,7 @@ - ~~Finish the Ellie.Marmalade project~~ Done - Finish the EllieBot.Tests project - Finish the EllieBot project - - Finish the EllieBot.Coordinator project - - Finish the EllieBot.Generators project + - ~~Finish the EllieBot.Coordinator project~~ Done + - ~~Finish the EllieBot.Generators project~~ Done - ~~Finish the EllieBot.Voice project~~ Done - - ~~Finish the EllieBot.VotesApi project~~ \ No newline at end of file + - ~~Finish the EllieBot.VotesApi project~~ Done \ No newline at end of file From 9fff64f9512be7ffae38ecc29c4ab47c8e5db1e5 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 14 May 2024 23:08:36 +1200 Subject: [PATCH 35/62] Added Db stuff --- src/EllieBot/Db/EllieContext.cs | 535 ++++++++++++++++++ src/EllieBot/Db/EllieDbService.cs | 76 +++ src/EllieBot/Db/Extensions/ClubExtensions.cs | 34 ++ .../CurrencyTransactionExtensions.cs | 20 + src/EllieBot/Db/Extensions/DbExtensions.cs | 12 + .../Db/Extensions/DiscordUserExtensions.cs | 125 ++++ .../Extensions/EllieExpressionExtensions.cs | 15 + .../Db/Extensions/GuildConfigExtensions.cs | 227 ++++++++ src/EllieBot/Db/Extensions/QuoteExtensions.cs | 53 ++ .../Db/Extensions/ReminderExtensions.cs | 23 + .../SelfAssignableRolesExtensions.cs | 22 + .../Db/Extensions/UserXpExtensions.cs | 71 +++ .../Db/Extensions/WarningExtensions.cs | 60 ++ src/EllieBot/Db/Helpers/ActivityType.cs | 22 + src/EllieBot/Db/Helpers/GuildPerm.cs | 47 ++ src/EllieBot/Db/LevelStats.cs | 40 ++ src/EllieBot/Db/Models/AutoCommand.cs | 14 + src/EllieBot/Db/Models/AutoPublishChannel.cs | 7 + .../Db/Models/AutoTranslateChannel.cs | 10 + src/EllieBot/Db/Models/AutoTranslateUser.cs | 11 + src/EllieBot/Db/Models/BlacklistEntry.cs | 15 + src/EllieBot/Db/Models/CommandAlias.cs | 8 + src/EllieBot/Db/Models/CommandCooldown.cs | 8 + src/EllieBot/Db/Models/CurrencyTransaction.cs | 12 + src/EllieBot/Db/Models/DbEntity.cs | 12 + src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs | 14 + src/EllieBot/Db/Models/DiscordPemOverride.cs | 10 + src/EllieBot/Db/Models/DiscordUser.cs | 35 ++ src/EllieBot/Db/Models/Event.cs | 49 ++ src/EllieBot/Db/Models/FeedSub.cs | 19 + src/EllieBot/Db/Models/FollowedStream.cs | 33 ++ src/EllieBot/Db/Models/GCChannelId.cs | 14 + src/EllieBot/Db/Models/GamblingStats.cs | 9 + src/EllieBot/Db/Models/GroupName.cs | 11 + src/EllieBot/Db/Models/GuildColors.cs | 18 + src/EllieBot/Db/Models/GuildConfig.cs | 107 ++++ src/EllieBot/Db/Models/IgnoredLogItem.cs | 16 + .../Db/Models/IgnoredVoicePresenceChannel.cs | 8 + src/EllieBot/Db/Models/ImageOnlyChannel.cs | 15 + src/EllieBot/Db/Models/LogSetting.cs | 38 ++ src/EllieBot/Db/Models/Permission.cs | 55 ++ src/EllieBot/Db/Models/PlantedCurrency.cs | 12 + src/EllieBot/Db/Models/PlaylistSong.cs | 18 + src/EllieBot/Db/Models/Reminder.cs | 19 + src/EllieBot/Db/Models/Repeater.cs | 15 + .../Db/Models/RotatingPlayingStatus.cs | 8 + src/EllieBot/Db/Models/ShopEntry.cs | 46 ++ src/EllieBot/Db/Models/StreamOnlineMessage.cs | 11 + src/EllieBot/Db/Models/StreamRoleSettings.cs | 68 +++ src/EllieBot/Db/Models/VcRoleInfo.cs | 8 + src/EllieBot/Db/Models/Waifu.cs | 75 +++ src/EllieBot/Db/Models/anti/AntiAltSetting.cs | 11 + .../Db/Models/anti/AntiRaidSetting.cs | 19 + src/EllieBot/Db/Models/anti/AntiSpamIgnore.cs | 12 + .../Db/Models/anti/AntiSpamSetting.cs | 14 + src/EllieBot/Db/Models/club/ClubInfo.cs | 41 ++ src/EllieBot/Db/Models/currency/BankUser.cs | 7 + .../Db/Models/expr/EllieExpression.cs | 27 + src/EllieBot/Db/Models/expr/Quote.cs | 26 + .../Db/Models/filter/FilterChannelId.cs | 30 + .../Db/Models/filter/FilterLinksChannelId.cs | 13 + src/EllieBot/Db/Models/filter/FilteredWord.cs | 7 + .../Db/Models/giveaway/GiveawayModel.cs | 14 + .../Db/Models/giveaway/GiveawayUser.cs | 10 + src/EllieBot/Db/Models/punish/BanTemplate.cs | 9 + src/EllieBot/Db/Models/punish/MutedUserId.cs | 13 + .../Db/Models/punish/PunishmentAction.cs | 15 + .../Db/Models/punish/WarnExpireAction.cs | 8 + src/EllieBot/Db/Models/punish/Warning.cs | 13 + .../Db/Models/punish/WarningPunishment.cs | 10 + src/EllieBot/Db/Models/roles/ReactionRole.cs | 18 + .../Db/Models/roles/SelfAssignableRole.cs | 11 + src/EllieBot/Db/Models/roles/StickyRoles.cs | 14 + .../Db/Models/slowmode/SlowmodeIgnoredRole.cs | 20 + .../Db/Models/slowmode/SlowmodeIgnoredUser.cs | 20 + src/EllieBot/Db/Models/support/PatronQuota.cs | 48 ++ .../Db/Models/support/RewardedUser.cs | 10 + .../Db/Models/todo/ArchivedTodoListModel.cs | 10 + src/EllieBot/Db/Models/todo/TodoModel.cs | 13 + src/EllieBot/Db/Models/untimer/UnbanTimer.cs | 14 + src/EllieBot/Db/Models/untimer/UnmuteTimer.cs | 14 + src/EllieBot/Db/Models/untimer/UnroleTimer.cs | 15 + src/EllieBot/Db/Models/xp/UserXpStats.cs | 13 + src/EllieBot/Db/Models/xp/XpSettings.cs | 62 ++ src/EllieBot/Db/MysqlContext.cs | 38 ++ src/EllieBot/Db/PostgreSqlContext.cs | 26 + src/EllieBot/Db/SqliteContext.cs | 26 + 87 files changed, 2881 insertions(+) create mode 100644 src/EllieBot/Db/EllieContext.cs create mode 100644 src/EllieBot/Db/EllieDbService.cs create mode 100644 src/EllieBot/Db/Extensions/ClubExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/DbExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/DiscordUserExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/GuildConfigExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/QuoteExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/ReminderExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/UserXpExtensions.cs create mode 100644 src/EllieBot/Db/Extensions/WarningExtensions.cs create mode 100644 src/EllieBot/Db/Helpers/ActivityType.cs create mode 100644 src/EllieBot/Db/Helpers/GuildPerm.cs create mode 100644 src/EllieBot/Db/LevelStats.cs create mode 100644 src/EllieBot/Db/Models/AutoCommand.cs create mode 100644 src/EllieBot/Db/Models/AutoPublishChannel.cs create mode 100644 src/EllieBot/Db/Models/AutoTranslateChannel.cs create mode 100644 src/EllieBot/Db/Models/AutoTranslateUser.cs create mode 100644 src/EllieBot/Db/Models/BlacklistEntry.cs create mode 100644 src/EllieBot/Db/Models/CommandAlias.cs create mode 100644 src/EllieBot/Db/Models/CommandCooldown.cs create mode 100644 src/EllieBot/Db/Models/CurrencyTransaction.cs create mode 100644 src/EllieBot/Db/Models/DbEntity.cs create mode 100644 src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs create mode 100644 src/EllieBot/Db/Models/DiscordPemOverride.cs create mode 100644 src/EllieBot/Db/Models/DiscordUser.cs create mode 100644 src/EllieBot/Db/Models/Event.cs create mode 100644 src/EllieBot/Db/Models/FeedSub.cs create mode 100644 src/EllieBot/Db/Models/FollowedStream.cs create mode 100644 src/EllieBot/Db/Models/GCChannelId.cs create mode 100644 src/EllieBot/Db/Models/GamblingStats.cs create mode 100644 src/EllieBot/Db/Models/GroupName.cs create mode 100644 src/EllieBot/Db/Models/GuildColors.cs create mode 100644 src/EllieBot/Db/Models/GuildConfig.cs create mode 100644 src/EllieBot/Db/Models/IgnoredLogItem.cs create mode 100644 src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs create mode 100644 src/EllieBot/Db/Models/ImageOnlyChannel.cs create mode 100644 src/EllieBot/Db/Models/LogSetting.cs create mode 100644 src/EllieBot/Db/Models/Permission.cs create mode 100644 src/EllieBot/Db/Models/PlantedCurrency.cs create mode 100644 src/EllieBot/Db/Models/PlaylistSong.cs create mode 100644 src/EllieBot/Db/Models/Reminder.cs create mode 100644 src/EllieBot/Db/Models/Repeater.cs create mode 100644 src/EllieBot/Db/Models/RotatingPlayingStatus.cs create mode 100644 src/EllieBot/Db/Models/ShopEntry.cs create mode 100644 src/EllieBot/Db/Models/StreamOnlineMessage.cs create mode 100644 src/EllieBot/Db/Models/StreamRoleSettings.cs create mode 100644 src/EllieBot/Db/Models/VcRoleInfo.cs create mode 100644 src/EllieBot/Db/Models/Waifu.cs create mode 100644 src/EllieBot/Db/Models/anti/AntiAltSetting.cs create mode 100644 src/EllieBot/Db/Models/anti/AntiRaidSetting.cs create mode 100644 src/EllieBot/Db/Models/anti/AntiSpamIgnore.cs create mode 100644 src/EllieBot/Db/Models/anti/AntiSpamSetting.cs create mode 100644 src/EllieBot/Db/Models/club/ClubInfo.cs create mode 100644 src/EllieBot/Db/Models/currency/BankUser.cs create mode 100644 src/EllieBot/Db/Models/expr/EllieExpression.cs create mode 100644 src/EllieBot/Db/Models/expr/Quote.cs create mode 100644 src/EllieBot/Db/Models/filter/FilterChannelId.cs create mode 100644 src/EllieBot/Db/Models/filter/FilterLinksChannelId.cs create mode 100644 src/EllieBot/Db/Models/filter/FilteredWord.cs create mode 100644 src/EllieBot/Db/Models/giveaway/GiveawayModel.cs create mode 100644 src/EllieBot/Db/Models/giveaway/GiveawayUser.cs create mode 100644 src/EllieBot/Db/Models/punish/BanTemplate.cs create mode 100644 src/EllieBot/Db/Models/punish/MutedUserId.cs create mode 100644 src/EllieBot/Db/Models/punish/PunishmentAction.cs create mode 100644 src/EllieBot/Db/Models/punish/WarnExpireAction.cs create mode 100644 src/EllieBot/Db/Models/punish/Warning.cs create mode 100644 src/EllieBot/Db/Models/punish/WarningPunishment.cs create mode 100644 src/EllieBot/Db/Models/roles/ReactionRole.cs create mode 100644 src/EllieBot/Db/Models/roles/SelfAssignableRole.cs create mode 100644 src/EllieBot/Db/Models/roles/StickyRoles.cs create mode 100644 src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredRole.cs create mode 100644 src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredUser.cs create mode 100644 src/EllieBot/Db/Models/support/PatronQuota.cs create mode 100644 src/EllieBot/Db/Models/support/RewardedUser.cs create mode 100644 src/EllieBot/Db/Models/todo/ArchivedTodoListModel.cs create mode 100644 src/EllieBot/Db/Models/todo/TodoModel.cs create mode 100644 src/EllieBot/Db/Models/untimer/UnbanTimer.cs create mode 100644 src/EllieBot/Db/Models/untimer/UnmuteTimer.cs create mode 100644 src/EllieBot/Db/Models/untimer/UnroleTimer.cs create mode 100644 src/EllieBot/Db/Models/xp/UserXpStats.cs create mode 100644 src/EllieBot/Db/Models/xp/XpSettings.cs create mode 100644 src/EllieBot/Db/MysqlContext.cs create mode 100644 src/EllieBot/Db/PostgreSqlContext.cs create mode 100644 src/EllieBot/Db/SqliteContext.cs diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs new file mode 100644 index 0000000..d61d2f7 --- /dev/null +++ b/src/EllieBot/Db/EllieContext.cs @@ -0,0 +1,535 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using EllieBot.Db.Models; + +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace EllieBot.Db; + +public abstract class EllieContext : DbContext +{ + public DbSet GuildConfigs { get; set; } + + public DbSet Quotes { get; set; } + public DbSet Reminders { get; set; } + public DbSet SelfAssignableRoles { get; set; } + public DbSet MusicPlaylists { get; set; } + public DbSet Expressions { get; set; } + public DbSet CurrencyTransactions { get; set; } + public DbSet WaifuUpdates { get; set; } + public DbSet WaifuItem { get; set; } + public DbSet Warnings { get; set; } + public DbSet UserXpStats { get; set; } + public DbSet Clubs { get; set; } + public DbSet ClubBans { get; set; } + public DbSet ClubApplicants { get; set; } + + + //logging + public DbSet LogSettings { get; set; } + public DbSet IgnoredVoicePresenceCHannels { get; set; } + public DbSet IgnoredLogChannels { get; set; } + + public DbSet RotatingStatus { get; set; } + public DbSet Blacklist { get; set; } + public DbSet AutoCommands { get; set; } + public DbSet RewardedUsers { get; set; } + public DbSet PlantedCurrency { get; set; } + public DbSet BanTemplates { get; set; } + public DbSet DiscordPermOverrides { get; set; } + public DbSet DiscordUser { get; set; } + public DbSet MusicPlayerSettings { get; set; } + public DbSet Repeaters { get; set; } + public DbSet WaifuInfo { get; set; } + public DbSet ImageOnlyChannels { get; set; } + public DbSet AutoTranslateChannels { get; set; } + public DbSet AutoTranslateUsers { get; set; } + + public DbSet Permissions { get; set; } + + public DbSet BankUsers { get; set; } + + public DbSet ReactionRoles { get; set; } + + public DbSet Patrons { get; set; } + + public DbSet PatronQuotas { get; set; } + + public DbSet StreamOnlineMessages { get; set; } + + public DbSet StickyRoles { get; set; } + + public DbSet Todos { get; set; } + public DbSet TodosArchive { get; set; } + + // todo add guild colors + // public DbSet GuildColors { get; set; } + + + #region Mandatory Provider-Specific Values + + protected abstract string CurrencyTransactionOtherIdDefaultValue { get; } + + #endregion + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + #region QUOTES + + var quoteEntity = modelBuilder.Entity(); + quoteEntity.HasIndex(x => x.GuildId); + quoteEntity.HasIndex(x => x.Keyword); + + #endregion + + #region GuildConfig + + var configEntity = modelBuilder.Entity(); + configEntity.HasIndex(c => c.GuildId) + .IsUnique(); + + configEntity.Property(x => x.VerboseErrors) + .HasDefaultValue(true); + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting); + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting); + + modelBuilder.Entity() + .HasOne(x => x.AntiAltSetting) + .WithOne() + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasAlternateKey(x => new + { + x.GuildConfigId, + x.Url + }); + + modelBuilder.Entity().HasIndex(x => x.MessageId).IsUnique(); + + modelBuilder.Entity().HasIndex(x => x.ChannelId); + + configEntity.HasIndex(x => x.WarnExpireHours).IsUnique(false); + + #endregion + + #region streamrole + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole); + + #endregion + + #region Self Assignable Roles + + var selfassignableRolesEntity = modelBuilder.Entity(); + + selfassignableRolesEntity.HasIndex(s => new + { + s.GuildId, + s.RoleId + }) + .IsUnique(); + + selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0); + + #endregion + + #region MusicPlaylists + + var musicPlaylistEntity = modelBuilder.Entity(); + + musicPlaylistEntity.HasMany(p => p.Songs).WithOne().OnDelete(DeleteBehavior.Cascade); + + #endregion + + #region Waifus + + var wi = modelBuilder.Entity(); + wi.HasOne(x => x.Waifu).WithOne(); + + wi.HasIndex(x => x.Price); + wi.HasIndex(x => x.ClaimerId); + // wi.HasMany(x => x.Items) + // .WithOne() + // .OnDelete(DeleteBehavior.Cascade); + + #endregion + + #region DiscordUser + + modelBuilder.Entity(du => + { + du.Property(x => x.IsClubAdmin) + .HasDefaultValue(false); + + du.Property(x => x.NotifyOnLevelUp) + .HasDefaultValue(XpNotificationLocation.None); + + du.Property(x => x.TotalXp) + .HasDefaultValue(0); + + du.Property(x => x.CurrencyAmount) + .HasDefaultValue(0); + + du.HasAlternateKey(w => w.UserId); + du.HasOne(x => x.Club) + .WithMany(x => x.Members) + .IsRequired(false) + .OnDelete(DeleteBehavior.NoAction); + + du.HasIndex(x => x.TotalXp); + du.HasIndex(x => x.CurrencyAmount); + du.HasIndex(x => x.UserId); + }); + + #endregion + + #region Warnings + + modelBuilder.Entity(warn => + { + warn.HasIndex(x => x.GuildId); + warn.HasIndex(x => x.UserId); + warn.HasIndex(x => x.DateAdded); + warn.Property(x => x.Weight).HasDefaultValue(1); + }); + + #endregion + + #region XpStats + + var xps = modelBuilder.Entity(); + xps.HasIndex(x => new + { + x.UserId, + x.GuildId + }) + .IsUnique(); + + xps.HasIndex(x => x.UserId); + xps.HasIndex(x => x.GuildId); + xps.HasIndex(x => x.Xp); + xps.HasIndex(x => x.AwardedXp); + + #endregion + + #region XpSettings + + modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings); + + #endregion + + #region XpRoleReward + + modelBuilder.Entity() + .HasIndex(x => new + { + x.XpSettingsId, + x.Level + }) + .IsUnique(); + + #endregion + + #region Club + + var ci = modelBuilder.Entity(); + ci.HasOne(x => x.Owner) + .WithOne() + .HasForeignKey(x => x.OwnerId) + .OnDelete(DeleteBehavior.SetNull); + + ci.HasIndex(x => new + { + x.Name + }) + .IsUnique(); + + #endregion + + #region ClubManytoMany + + modelBuilder.Entity() + .HasKey(t => new + { + t.ClubId, + t.UserId + }); + + modelBuilder.Entity() + .HasOne(pt => pt.User) + .WithMany(); + + modelBuilder.Entity() + .HasOne(pt => pt.Club) + .WithMany(x => x.Applicants); + + modelBuilder.Entity() + .HasKey(t => new + { + t.ClubId, + t.UserId + }); + + modelBuilder.Entity() + .HasOne(pt => pt.User) + .WithMany(); + + modelBuilder.Entity() + .HasOne(pt => pt.Club) + .WithMany(x => x.Bans); + + #endregion + + #region CurrencyTransactions + + modelBuilder.Entity(e => + { + e.HasIndex(x => x.UserId) + .IsUnique(false); + + e.Property(x => x.OtherId) + .HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue); + + e.Property(x => x.Type) + .IsRequired(); + + e.Property(x => x.Extra) + .IsRequired(); + }); + + #endregion + + #region Reminders + + modelBuilder.Entity().HasIndex(x => x.When); + + #endregion + + #region GroupName + + modelBuilder.Entity() + .HasIndex(x => new + { + x.GuildConfigId, + x.Number + }) + .IsUnique(); + + modelBuilder.Entity() + .HasOne(x => x.GuildConfig) + .WithMany(x => x.SelfAssignableRoleGroupNames) + .IsRequired(); + + #endregion + + #region BanTemplate + + modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); + modelBuilder.Entity() + .Property(x => x.PruneDays) + .HasDefaultValue(null) + .IsRequired(false); + + #endregion + + #region Perm Override + + modelBuilder.Entity() + .HasIndex(x => new + { + x.GuildId, + x.Command + }) + .IsUnique(); + + #endregion + + #region Music + + modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); + + modelBuilder.Entity().Property(x => x.Volume).HasDefaultValue(100); + + #endregion + + #region Reaction roles + + modelBuilder.Entity(rr2 => + { + rr2.HasIndex(x => x.GuildId) + .IsUnique(false); + + rr2.HasIndex(x => new + { + x.MessageId, + x.Emote + }) + .IsUnique(); + }); + + #endregion + + #region LogSettings + + modelBuilder.Entity(ls => ls.HasIndex(x => x.GuildId).IsUnique()); + + modelBuilder.Entity(ls => ls + .HasMany(x => x.LogIgnores) + .WithOne(x => x.LogSetting) + .OnDelete(DeleteBehavior.Cascade)); + + modelBuilder.Entity(ili => ili + .HasIndex(x => new + { + x.LogSettingId, + x.LogItemId, + x.ItemType + }) + .IsUnique()); + + #endregion + + modelBuilder.Entity(ioc => ioc.HasIndex(x => x.ChannelId).IsUnique()); + + var atch = modelBuilder.Entity(); + atch.HasIndex(x => x.GuildId).IsUnique(false); + + atch.HasIndex(x => x.ChannelId).IsUnique(); + + atch.HasMany(x => x.Users).WithOne(x => x.Channel).OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity(atu => atu.HasAlternateKey(x => new + { + x.ChannelId, + x.UserId + })); + + #region BANK + + modelBuilder.Entity(bu => bu.HasIndex(x => x.UserId).IsUnique()); + + #endregion + + + #region Patron + + // currency rewards + var pr = modelBuilder.Entity(); + pr.HasIndex(x => x.PlatformUserId).IsUnique(); + + // patrons + // patrons are not identified by their user id, but by their platform user id + // as multiple accounts (even maybe on different platforms) could have + // the same account connected to them + modelBuilder.Entity(pu => + { + pu.HasIndex(x => x.UniquePlatformUserId).IsUnique(); + pu.HasKey(x => x.UserId); + }); + + // quotes are per user id + modelBuilder.Entity(pq => + { + pq.HasIndex(x => x.UserId).IsUnique(false); + pq.HasKey(x => new + { + x.UserId, + x.FeatureType, + x.Feature + }); + }); + + #endregion + + #region Xp Item Shop + + modelBuilder.Entity( + x => + { + // user can own only one of each item + x.HasIndex(model => new + { + model.UserId, + model.ItemType, + model.ItemKey + }) + .IsUnique(); + }); + + #endregion + + #region AutoPublish + + modelBuilder.Entity(apc => apc + .HasIndex(x => x.GuildId) + .IsUnique()); + + #endregion + + #region GamblingStats + + modelBuilder.Entity(gs => gs + .HasIndex(x => x.Feature) + .IsUnique()); + + #endregion + + #region Sticky Roles + + modelBuilder.Entity(sr => sr.HasIndex(x => new + { + x.GuildId, + x.UserId + }).IsUnique()); + + #endregion + + + #region Giveaway + + modelBuilder.Entity() + .HasMany(x => x.Participants) + .WithOne() + .HasForeignKey(x => x.GiveawayId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity(gu => gu + .HasIndex(x => new + { + x.GiveawayId, + x.UserId + }) + .IsUnique()); + + #endregion + + #region Todo + + modelBuilder.Entity() + .HasKey(x => x.Id); + + modelBuilder.Entity() + .HasIndex(x => x.UserId) + .IsUnique(false); + + modelBuilder.Entity() + .HasMany(x => x.Items) + .WithOne() + .HasForeignKey(x => x.ArchiveId) + .OnDelete(DeleteBehavior.Cascade); + + #endregion + } + +#if DEBUG + private static readonly ILoggerFactory _debugLoggerFactory = LoggerFactory.Create(x => x.AddConsole()); + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseLoggerFactory(_debugLoggerFactory); +#endif +} \ No newline at end of file diff --git a/src/EllieBot/Db/EllieDbService.cs b/src/EllieBot/Db/EllieDbService.cs new file mode 100644 index 0000000..2a3382e --- /dev/null +++ b/src/EllieBot/Db/EllieDbService.cs @@ -0,0 +1,76 @@ +using LinqToDB.Common; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Db; + +public sealed class EllieDbService : DbService +{ + private readonly IBotCredsProvider _creds; + + // these are props because creds can change at runtime + private string DbType => _creds.GetCreds().Db.Type.ToLowerInvariant().Trim(); + private string ConnString => _creds.GetCreds().Db.ConnectionString; + + public EllieDbService(IBotCredsProvider creds) + { + LinqToDBForEFTools.Initialize(); + Configuration.Linq.DisableQueryCache = true; + + _creds = creds; + } + + public override async Task SetupAsync() + { + var dbType = DbType; + var connString = ConnString; + + await using var context = CreateRawDbContext(dbType, connString); + + // make sure sqlite db is in wal journal mode + if (context is SqliteContext) + { + await context.Database.ExecuteSqlRawAsync("PRAGMA journal_mode=WAL"); + } + + await context.Database.MigrateAsync(); + } + + public override EllieContext CreateRawDbContext(string dbType, string connString) + { + switch (dbType) + { + case "postgresql": + case "postgres": + case "pgsql": + return new PostgreSqlContext(connString); + case "mysql": + return new MysqlContext(connString); + case "sqlite": + return new SqliteContext(connString); + default: + throw new NotSupportedException($"The database provide type of '{dbType}' is not supported."); + } + } + + private EllieContext GetDbContextInternal() + { + var dbType = DbType; + var connString = ConnString; + + var context = CreateRawDbContext(dbType, connString); + if (context is SqliteContext) + { + var conn = context.Database.GetDbConnection(); + conn.Open(); + using var com = conn.CreateCommand(); + com.CommandText = "PRAGMA synchronous=OFF"; + com.ExecuteNonQuery(); + } + + return context; + } + + public override EllieContext GetDbContext() + => GetDbContextInternal(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ClubExtensions.cs b/src/EllieBot/Db/Extensions/ClubExtensions.cs new file mode 100644 index 0000000..d8183fc --- /dev/null +++ b/src/EllieBot/Db/Extensions/ClubExtensions.cs @@ -0,0 +1,34 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class ClubExtensions +{ + private static IQueryable Include(this DbSet clubs) + => clubs.Include(x => x.Owner) + .Include(x => x.Applicants) + .ThenInclude(x => x.User) + .Include(x => x.Bans) + .ThenInclude(x => x.User) + .Include(x => x.Members) + .AsQueryable(); + + public static ClubInfo GetByOwner(this DbSet clubs, ulong userId) + => Include(clubs).FirstOrDefault(c => c.Owner.UserId == userId); + + public static ClubInfo GetByOwnerOrAdmin(this DbSet clubs, ulong userId) + => Include(clubs) + .FirstOrDefault(c => c.Owner.UserId == userId || c.Members.Any(u => u.UserId == userId && u.IsClubAdmin)); + + public static ClubInfo GetByMember(this DbSet clubs, ulong userId) + => Include(clubs).FirstOrDefault(c => c.Members.Any(u => u.UserId == userId)); + + public static ClubInfo GetByName(this DbSet clubs, string name) + => Include(clubs) + .FirstOrDefault(c => c.Name == name); + + public static List GetClubLeaderboardPage(this DbSet clubs, int page) + => clubs.AsNoTracking().OrderByDescending(x => x.Xp).Skip(page * 9).Take(9).ToList(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs new file mode 100644 index 0000000..69401b0 --- /dev/null +++ b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs @@ -0,0 +1,20 @@ +#nullable disable +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class CurrencyTransactionExtensions +{ + public static Task> GetPageFor( + this DbSet set, + ulong userId, + int page) + => set.ToLinqToDBTable() + .Where(x => x.UserId == userId) + .OrderByDescending(x => x.DateAdded) + .Skip(15 * page) + .Take(15) + .ToListAsyncLinqToDB(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DbExtensions.cs b/src/EllieBot/Db/Extensions/DbExtensions.cs new file mode 100644 index 0000000..fafade9 --- /dev/null +++ b/src/EllieBot/Db/Extensions/DbExtensions.cs @@ -0,0 +1,12 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class DbExtensions +{ + public static T GetById(this DbSet set, int id) + where T : DbEntity + => set.FirstOrDefault(x => x.Id == id); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs new file mode 100644 index 0000000..6d74316 --- /dev/null +++ b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs @@ -0,0 +1,125 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class DiscordUserExtensions +{ + public static Task GetByUserIdAsync( + this IQueryable set, + ulong userId) + => set.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId); + + public static void EnsureUserCreated( + this DbContext ctx, + ulong userId, + string username, + string discrim, + string avatarId) + => ctx.GetTable() + .InsertOrUpdate( + () => new() + { + UserId = userId, + Username = username, + Discriminator = discrim, + AvatarId = avatarId, + TotalXp = 0, + CurrencyAmount = 0 + }, + old => new() + { + Username = username, + Discriminator = discrim, + AvatarId = avatarId + }, + () => new() + { + UserId = userId + }); + + public static Task EnsureUserCreatedAsync( + this DbContext ctx, + ulong userId) + => ctx.GetTable() + .InsertOrUpdateAsync( + () => new() + { + UserId = userId, + Username = "Unknown", + Discriminator = "????", + AvatarId = string.Empty, + TotalXp = 0, + CurrencyAmount = 0 + }, + old => new() + { + }, + () => new() + { + UserId = userId + }); + + //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown + public static DiscordUser GetOrCreateUser( + this DbContext ctx, + ulong userId, + string username, + string discrim, + string avatarId, + Func, IQueryable> includes = null) + { + ctx.EnsureUserCreated(userId, username, discrim, avatarId); + + IQueryable queryable = ctx.Set(); + if (includes is not null) + queryable = includes(queryable); + return queryable.First(u => u.UserId == userId); + } + + + public static int GetUserGlobalRank(this DbSet users, ulong id) + => users.AsQueryable() + .Where(x => x.TotalXp + > users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault()) + .Count() + + 1; + + public static DiscordUser[] GetUsersXpLeaderboardFor(this DbSet users, int page, int perPage) + => users.AsQueryable().OrderByDescending(x => x.TotalXp).Skip(page * perPage).Take(perPage).AsEnumerable() + .ToArray(); + + public static Task> GetTopRichest( + this DbSet users, + ulong botId, + int page = 0, int perPage = 9) + => users.AsQueryable() + .Where(c => c.CurrencyAmount > 0 && botId != c.UserId) + .OrderByDescending(c => c.CurrencyAmount) + .Skip(page * perPage) + .Take(perPage) + .ToListAsyncLinqToDB(); + + public static async Task GetUserCurrencyAsync(this DbSet users, ulong userId) + => (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0; + + public static void RemoveFromMany(this DbSet users, IEnumerable ids) + { + var items = users.AsQueryable().Where(x => ids.Contains(x.UserId)); + foreach (var item in items) + item.CurrencyAmount = 0; + } + + public static decimal GetTotalCurrency(this DbSet users) + => users.Sum((Func)(x => x.CurrencyAmount)); + + public static decimal GetTopOnePercentCurrency(this DbSet users, ulong botId) + => users.AsQueryable() + .Where(x => x.UserId != botId) + .OrderByDescending(x => x.CurrencyAmount) + .Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100) + .Sum(x => x.CurrencyAmount); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs new file mode 100644 index 0000000..02a3453 --- /dev/null +++ b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs @@ -0,0 +1,15 @@ +#nullable disable +using LinqToDB; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class EllieExpressionExtensions +{ + public static int ClearFromGuild(this DbSet exprs, ulong guildId) + => exprs.Delete(x => x.GuildId == guildId); + + public static IEnumerable ForId(this DbSet exprs, ulong id) + => exprs.AsNoTracking().AsQueryable().Where(x => x.GuildId == id).ToList(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs new file mode 100644 index 0000000..bffa943 --- /dev/null +++ b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs @@ -0,0 +1,227 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class GuildConfigExtensions +{ + private static List DefaultWarnPunishments + => new() + { + new() + { + Count = 3, + Punishment = PunishmentAction.Kick + }, + new() + { + Count = 5, + Punishment = PunishmentAction.Ban + } + }; + + /// + /// Gets full stream role settings for the guild with the specified id. + /// + /// Db Context + /// Id of the guild to get stream role settings for. + /// Guild'p stream role settings + public static StreamRoleSettings GetStreamRoleSettings(this DbContext ctx, ulong guildId) + { + var conf = ctx.GuildConfigsForId(guildId, + set => set.Include(y => y.StreamRole) + .Include(y => y.StreamRole.Whitelist) + .Include(y => y.StreamRole.Blacklist)); + + if (conf.StreamRole is null) + conf.StreamRole = new(); + + return conf.StreamRole; + } + + private static IQueryable IncludeEverything(this DbSet configs) + => configs.AsQueryable() + .AsSplitQuery() + .Include(gc => gc.CommandCooldowns) + .Include(gc => gc.FollowedStreams) + .Include(gc => gc.StreamRole) + .Include(gc => gc.XpSettings) + .ThenInclude(x => x.ExclusionList) + .Include(gc => gc.DelMsgOnCmdChannels); + + public static IEnumerable GetAllGuildConfigs( + this DbSet configs, + IReadOnlyList availableGuilds) + => configs.IncludeEverything().AsNoTracking().Where(x => availableGuilds.Contains(x.GuildId)).ToList(); + + /// + /// Gets and creates if it doesn't exist a config for a guild. + /// + /// Context + /// Id of the guide + /// Use to manipulate the set however you want. Pass null to include everything + /// Config for the guild + public static GuildConfig GuildConfigsForId( + this DbContext ctx, + ulong guildId, + Func, IQueryable> includes) + { + GuildConfig config; + + if (includes is null) + config = ctx.Set().IncludeEverything().FirstOrDefault(c => c.GuildId == guildId); + else + { + var set = includes(ctx.Set()); + config = set.FirstOrDefault(c => c.GuildId == guildId); + } + + if (config is null) + { + ctx.Set().Add(config = new() + { + GuildId = guildId, + Permissions = Permissionv2.GetDefaultPermlist, + WarningsInitialized = true, + WarnPunishments = DefaultWarnPunishments + }); + ctx.SaveChanges(); + } + + if (!config.WarningsInitialized) + { + config.WarningsInitialized = true; + config.WarnPunishments = DefaultWarnPunishments; + } + + return config; + + // ctx.GuildConfigs + // .ToLinqToDBTable() + // .InsertOrUpdate(() => new() + // { + // GuildId = guildId, + // Permissions = Permissionv2.GetDefaultPermlist, + // WarningsInitialized = true, + // WarnPunishments = DefaultWarnPunishments + // }, + // _ => new(), + // () => new() + // { + // GuildId = guildId + // }); + // + // if(includes is null) + // return ctx.GuildConfigs + // .ToLinqToDBTable() + // .First(x => x.GuildId == guildId); + } + + public static LogSetting LogSettingsFor(this DbContext ctx, ulong guildId) + { + var logSetting = ctx.Set() + .AsQueryable() + .Include(x => x.LogIgnores) + .Where(x => x.GuildId == guildId) + .FirstOrDefault(); + + if (logSetting is null) + { + ctx.Set() + .Add(logSetting = new() + { + GuildId = guildId + }); + ctx.SaveChanges(); + } + + return logSetting; + } + + public static IEnumerable PermissionsForAll(this DbSet configs, List include) + { + var query = configs.AsQueryable().Where(x => include.Contains(x.GuildId)).Include(gc => gc.Permissions); + + return query.ToList(); + } + + public static GuildConfig GcWithPermissionsFor(this DbContext ctx, ulong guildId) + { + var config = ctx.Set().AsQueryable() + .Where(gc => gc.GuildId == guildId) + .Include(gc => gc.Permissions) + .FirstOrDefault(); + + if (config is null) // if there is no guildconfig, create new one + { + ctx.Set().Add(config = new() + { + GuildId = guildId, + Permissions = Permissionv2.GetDefaultPermlist + }); + ctx.SaveChanges(); + } + else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones + { + config.Permissions = Permissionv2.GetDefaultPermlist; + ctx.SaveChanges(); + } + + return config; + } + + public static IEnumerable GetFollowedStreams(this DbSet configs) + => configs.AsQueryable().Include(x => x.FollowedStreams).SelectMany(gc => gc.FollowedStreams).ToArray(); + + public static IEnumerable GetFollowedStreams(this DbSet configs, List included) + => configs.AsQueryable() + .Where(gc => included.Contains(gc.GuildId)) + .Include(gc => gc.FollowedStreams) + .SelectMany(gc => gc.FollowedStreams) + .ToList(); + + public static void SetCleverbotEnabled(this DbSet configs, ulong id, bool cleverbotEnabled) + { + var conf = configs.FirstOrDefault(gc => gc.GuildId == id); + + if (conf is null) + return; + + conf.CleverbotEnabled = cleverbotEnabled; + } + + public static XpSettings XpSettingsFor(this DbContext ctx, ulong guildId) + { + var gc = ctx.GuildConfigsForId(guildId, + set => set.Include(x => x.XpSettings) + .ThenInclude(x => x.RoleRewards) + .Include(x => x.XpSettings) + .ThenInclude(x => x.CurrencyRewards) + .Include(x => x.XpSettings) + .ThenInclude(x => x.ExclusionList)); + + if (gc.XpSettings is null) + gc.XpSettings = new(); + + return gc.XpSettings; + } + + public static IEnumerable GetGeneratingChannels(this DbSet configs) + => configs.AsQueryable() + .Include(x => x.GenerateCurrencyChannelIds) + .Where(x => x.GenerateCurrencyChannelIds.Any()) + .SelectMany(x => x.GenerateCurrencyChannelIds) + .Select(x => new GeneratingChannel + { + ChannelId = x.ChannelId, + GuildId = x.GuildConfig.GuildId + }) + .ToArray(); + + public class GeneratingChannel + { + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/QuoteExtensions.cs b/src/EllieBot/Db/Extensions/QuoteExtensions.cs new file mode 100644 index 0000000..67698e9 --- /dev/null +++ b/src/EllieBot/Db/Extensions/QuoteExtensions.cs @@ -0,0 +1,53 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class QuoteExtensions +{ + public static IEnumerable GetForGuild(this DbSet quotes, ulong guildId) + => quotes.AsQueryable().Where(x => x.GuildId == guildId); + + public static IReadOnlyCollection GetGroup( + this DbSet quotes, + ulong guildId, + int page, + OrderType order) + { + var q = quotes.AsQueryable().Where(x => x.GuildId == guildId); + if (order == OrderType.Keyword) + q = q.OrderBy(x => x.Keyword); + else + q = q.OrderBy(x => x.Id); + + return q.Skip(15 * page).Take(15).ToArray(); + } + + public static async Task GetRandomQuoteByKeywordAsync( + this DbSet quotes, + ulong guildId, + string keyword) + { + return (await quotes.AsQueryable().Where(q => q.GuildId == guildId && q.Keyword == keyword).ToArrayAsync()) + .RandomOrDefault(); + } + + public static async Task SearchQuoteKeywordTextAsync( + this DbSet quotes, + ulong guildId, + string keyword, + string text) + { + return (await quotes.AsQueryable() + .Where(q => q.GuildId == guildId + && (keyword == null || q.Keyword == keyword) + && (EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%") + || EF.Functions.Like(q.AuthorName, text))) + .ToArrayAsync()) + .RandomOrDefault(); + } + + public static void RemoveAllByKeyword(this DbSet quotes, ulong guildId, string keyword) + => quotes.RemoveRange(quotes.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword)); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ReminderExtensions.cs b/src/EllieBot/Db/Extensions/ReminderExtensions.cs new file mode 100644 index 0000000..8a7d992 --- /dev/null +++ b/src/EllieBot/Db/Extensions/ReminderExtensions.cs @@ -0,0 +1,23 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class ReminderExtensions +{ + public static IEnumerable GetIncludedReminders( + this DbSet reminders, + IEnumerable guildIds) + => reminders.AsQueryable().Where(x => guildIds.Contains(x.ServerId) || x.ServerId == 0).ToList(); + + public static IEnumerable RemindersFor(this DbSet reminders, ulong userId, int page) + => reminders.AsQueryable().Where(x => x.UserId == userId).OrderBy(x => x.DateAdded).Skip(page * 10).Take(10); + + public static IEnumerable RemindersForServer(this DbSet reminders, ulong serverId, int page) + => reminders.AsQueryable() + .Where(x => x.ServerId == serverId) + .OrderBy(x => x.DateAdded) + .Skip(page * 10) + .Take(10); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs new file mode 100644 index 0000000..740a155 --- /dev/null +++ b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs @@ -0,0 +1,22 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class SelfAssignableRolesExtensions +{ + public static bool DeleteByGuildAndRoleId(this DbSet roles, ulong guildId, ulong roleId) + { + var role = roles.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId); + + if (role is null) + return false; + + roles.Remove(role); + return true; + } + + public static IReadOnlyCollection GetFromGuild(this DbSet roles, ulong guildId) + => roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/UserXpExtensions.cs b/src/EllieBot/Db/Extensions/UserXpExtensions.cs new file mode 100644 index 0000000..c7e0f8c --- /dev/null +++ b/src/EllieBot/Db/Extensions/UserXpExtensions.cs @@ -0,0 +1,71 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class UserXpExtensions +{ + public static UserXpStats GetOrCreateUserXpStats(this DbContext ctx, ulong guildId, ulong userId) + { + var usr = ctx.Set().FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId); + + if (usr is null) + { + ctx.Add(usr = new() + { + Xp = 0, + UserId = userId, + NotifyOnLevelUp = XpNotificationLocation.None, + GuildId = guildId + }); + } + + return usr; + } + + public static List GetUsersFor(this DbSet xps, ulong guildId, int page) + => xps.AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .OrderByDescending(x => x.Xp + x.AwardedXp) + .Skip(page * 9) + .Take(9) + .ToList(); + + public static List GetTopUserXps(this DbSet xps, ulong guildId, int count) + => xps.AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .OrderByDescending(x => x.Xp + x.AwardedXp) + .Take(count) + .ToList(); + + public static int GetUserGuildRanking(this DbSet xps, ulong userId, ulong guildId) + => xps.AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId + && x.Xp + x.AwardedXp + > xps.AsQueryable() + .Where(y => y.UserId == userId && y.GuildId == guildId) + .Select(y => y.Xp + y.AwardedXp) + .FirstOrDefault()) + .Count() + + 1; + + public static void ResetGuildUserXp(this DbSet xps, ulong userId, ulong guildId) + => xps.Delete(x => x.UserId == userId && x.GuildId == guildId); + + public static void ResetGuildXp(this DbSet xps, ulong guildId) + => xps.Delete(x => x.GuildId == guildId); + + public static async Task GetLevelDataFor(this ITable userXp, ulong guildId, ulong userId) + => await userXp + .Where(x => x.GuildId == guildId && x.UserId == userId) + .FirstOrDefaultAsyncLinqToDB() is UserXpStats uxs + ? new(uxs.Xp + uxs.AwardedXp) + : new(0); + +} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WarningExtensions.cs b/src/EllieBot/Db/Extensions/WarningExtensions.cs new file mode 100644 index 0000000..c223f7d --- /dev/null +++ b/src/EllieBot/Db/Extensions/WarningExtensions.cs @@ -0,0 +1,60 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class WarningExtensions +{ + public static Warning[] ForId(this DbSet warnings, ulong guildId, ulong userId) + { + var query = warnings.AsQueryable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .OrderByDescending(x => x.DateAdded); + + return query.ToArray(); + } + + public static bool Forgive( + this DbSet warnings, + ulong guildId, + ulong userId, + string mod, + int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + + var warn = warnings.AsQueryable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .OrderByDescending(x => x.DateAdded) + .Skip(index) + .FirstOrDefault(); + + if (warn is null || warn.Forgiven) + return false; + + warn.Forgiven = true; + warn.ForgivenBy = mod; + return true; + } + + public static async Task ForgiveAll( + this DbSet warnings, + ulong guildId, + ulong userId, + string mod) + => await warnings.AsQueryable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .ForEachAsync(x => + { + if (x.Forgiven != true) + { + x.Forgiven = true; + x.ForgivenBy = mod; + } + }); + + public static Warning[] GetForGuild(this DbSet warnings, ulong id) + => warnings.AsQueryable().Where(x => x.GuildId == id).ToArray(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Helpers/ActivityType.cs b/src/EllieBot/Db/Helpers/ActivityType.cs new file mode 100644 index 0000000..64bdd73 --- /dev/null +++ b/src/EllieBot/Db/Helpers/ActivityType.cs @@ -0,0 +1,22 @@ +namespace EllieBot.Db; + +public enum DbActivityType +{ + /// The user is playing a game. + Playing, + + /// The user is streaming online. + Streaming, + + /// The user is listening to a song. + Listening, + + /// The user is watching some form of media. + Watching, + + /// The user has set a custom status. + CustomStatus, + + /// The user is competing in a game. + Competing, +} \ No newline at end of file diff --git a/src/EllieBot/Db/Helpers/GuildPerm.cs b/src/EllieBot/Db/Helpers/GuildPerm.cs new file mode 100644 index 0000000..4713afa --- /dev/null +++ b/src/EllieBot/Db/Helpers/GuildPerm.cs @@ -0,0 +1,47 @@ +namespace EllieBot.Db; + +[Flags] +public enum GuildPerm : ulong +{ + CreateInstantInvite = 1, + KickMembers = 2, + BanMembers = 4, + Administrator = 8, + ManageChannels = 16, // 0x0000000000000010 + ManageGuild = 32, // 0x0000000000000020 + ViewGuildInsights = 524288, // 0x0000000000080000 + AddReactions = 64, // 0x0000000000000040 + ViewAuditLog = 128, // 0x0000000000000080 + ViewChannel = 1024, // 0x0000000000000400 + SendMessages = 2048, // 0x0000000000000800 + SendTTSMessages = 4096, // 0x0000000000001000 + ManageMessages = 8192, // 0x0000000000002000 + EmbedLinks = 16384, // 0x0000000000004000 + AttachFiles = 32768, // 0x0000000000008000 + ReadMessageHistory = 65536, // 0x0000000000010000 + MentionEveryone = 131072, // 0x0000000000020000 + UseExternalEmojis = 262144, // 0x0000000000040000 + Connect = 1048576, // 0x0000000000100000 + Speak = 2097152, // 0x0000000000200000 + MuteMembers = 4194304, // 0x0000000000400000 + DeafenMembers = 8388608, // 0x0000000000800000 + MoveMembers = 16777216, // 0x0000000001000000 + UseVAD = 33554432, // 0x0000000002000000 + PrioritySpeaker = 256, // 0x0000000000000100 + Stream = 512, // 0x0000000000000200 + ChangeNickname = 67108864, // 0x0000000004000000 + ManageNicknames = 134217728, // 0x0000000008000000 + ManageRoles = 268435456, // 0x0000000010000000 + ManageWebhooks = 536870912, // 0x0000000020000000 + ManageEmojisAndStickers = 1073741824, // 0x0000000040000000 + UseApplicationCommands = 2147483648, // 0x0000000080000000 + RequestToSpeak = 4294967296, // 0x0000000100000000 + ManageEvents = 8589934592, // 0x0000000200000000 + ManageThreads = 17179869184, // 0x0000000400000000 + CreatePublicThreads = 34359738368, // 0x0000000800000000 + CreatePrivateThreads = 68719476736, // 0x0000001000000000 + UseExternalStickers = 137438953472, // 0x0000002000000000 + SendMessagesInThreads = 274877906944, // 0x0000004000000000 + StartEmbeddedActivities = 549755813888, // 0x0000008000000000 + ModerateMembers = 1099511627776, // 0x0000010000000000 +} diff --git a/src/EllieBot/Db/LevelStats.cs b/src/EllieBot/Db/LevelStats.cs new file mode 100644 index 0000000..fbb2e47 --- /dev/null +++ b/src/EllieBot/Db/LevelStats.cs @@ -0,0 +1,40 @@ +#nullable disable +namespace EllieBot.Db; + +public readonly struct LevelStats +{ + public const int XP_REQUIRED_LVL_1 = 36; + + public long Level { get; } + public long LevelXp { get; } + public long RequiredXp { get; } + public long TotalXp { get; } + + public LevelStats(long xp) + { + if (xp < 0) + xp = 0; + + TotalXp = xp; + + const int baseXp = XP_REQUIRED_LVL_1; + + var required = baseXp; + var totalXp = 0; + var lvl = 1; + while (true) + { + required = (int)(baseXp + (baseXp / 4.0 * (lvl - 1))); + + if (required + totalXp > xp) + break; + + totalXp += required; + lvl++; + } + + Level = lvl - 1; + LevelXp = xp - totalXp; + RequiredXp = required; + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoCommand.cs b/src/EllieBot/Db/Models/AutoCommand.cs new file mode 100644 index 0000000..f412448 --- /dev/null +++ b/src/EllieBot/Db/Models/AutoCommand.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class AutoCommand : DbEntity +{ + public string CommandText { get; set; } + public ulong ChannelId { get; set; } + public string ChannelName { get; set; } + public ulong? GuildId { get; set; } + public string GuildName { get; set; } + public ulong? VoiceChannelId { get; set; } + public string VoiceChannelName { get; set; } + public int Interval { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoPublishChannel.cs b/src/EllieBot/Db/Models/AutoPublishChannel.cs new file mode 100644 index 0000000..c632776 --- /dev/null +++ b/src/EllieBot/Db/Models/AutoPublishChannel.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Db.Models; + +public class AutoPublishChannel : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateChannel.cs b/src/EllieBot/Db/Models/AutoTranslateChannel.cs new file mode 100644 index 0000000..33423c1 --- /dev/null +++ b/src/EllieBot/Db/Models/AutoTranslateChannel.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class AutoTranslateChannel : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public bool AutoDelete { get; set; } + public IList Users { get; set; } = new List(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateUser.cs b/src/EllieBot/Db/Models/AutoTranslateUser.cs new file mode 100644 index 0000000..459d58b --- /dev/null +++ b/src/EllieBot/Db/Models/AutoTranslateUser.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class AutoTranslateUser : DbEntity +{ + public int ChannelId { get; set; } + public AutoTranslateChannel Channel { get; set; } + public ulong UserId { get; set; } + public string Source { get; set; } + public string Target { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BlacklistEntry.cs b/src/EllieBot/Db/Models/BlacklistEntry.cs new file mode 100644 index 0000000..d457e8a --- /dev/null +++ b/src/EllieBot/Db/Models/BlacklistEntry.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class BlacklistEntry : DbEntity +{ + public ulong ItemId { get; set; } + public BlacklistType Type { get; set; } +} + +public enum BlacklistType +{ + Server, + Channel, + User +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandAlias.cs b/src/EllieBot/Db/Models/CommandAlias.cs new file mode 100644 index 0000000..28f614a --- /dev/null +++ b/src/EllieBot/Db/Models/CommandAlias.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class CommandAlias : DbEntity +{ + public string Trigger { get; set; } + public string Mapping { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandCooldown.cs b/src/EllieBot/Db/Models/CommandCooldown.cs new file mode 100644 index 0000000..e12ef9c --- /dev/null +++ b/src/EllieBot/Db/Models/CommandCooldown.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class CommandCooldown : DbEntity +{ + public int Seconds { get; set; } + public string CommandName { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CurrencyTransaction.cs b/src/EllieBot/Db/Models/CurrencyTransaction.cs new file mode 100644 index 0000000..8b9f6a6 --- /dev/null +++ b/src/EllieBot/Db/Models/CurrencyTransaction.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class CurrencyTransaction : DbEntity +{ + public long Amount { get; set; } + public string Note { get; set; } + public ulong UserId { get; set; } + public string Type { get; set; } + public string Extra { get; set; } + public ulong? OtherId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DbEntity.cs b/src/EllieBot/Db/Models/DbEntity.cs new file mode 100644 index 0000000..0ed8388 --- /dev/null +++ b/src/EllieBot/Db/Models/DbEntity.cs @@ -0,0 +1,12 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Db.Models; + +public class DbEntity +{ + [Key] + public int Id { get; set; } + + public DateTime? DateAdded { get; set; } = DateTime.UtcNow; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs new file mode 100644 index 0000000..6cbe756 --- /dev/null +++ b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class DelMsgOnCmdChannel : DbEntity +{ + public ulong ChannelId { get; set; } + public bool State { get; set; } + + public override int GetHashCode() + => ChannelId.GetHashCode(); + + public override bool Equals(object obj) + => obj is DelMsgOnCmdChannel x && x.ChannelId == ChannelId; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordPemOverride.cs b/src/EllieBot/Db/Models/DiscordPemOverride.cs new file mode 100644 index 0000000..b9ecd24 --- /dev/null +++ b/src/EllieBot/Db/Models/DiscordPemOverride.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class DiscordPermOverride : DbEntity +{ + public GuildPerm Perm { get; set; } + + public ulong? GuildId { get; set; } + public string Command { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordUser.cs b/src/EllieBot/Db/Models/DiscordUser.cs new file mode 100644 index 0000000..83bda60 --- /dev/null +++ b/src/EllieBot/Db/Models/DiscordUser.cs @@ -0,0 +1,35 @@ +#nullable disable +namespace EllieBot.Db.Models; + + +// FUTURE remove LastLevelUp from here and UserXpStats +public class DiscordUser : DbEntity +{ + public ulong UserId { get; set; } + public string Username { get; set; } + public string Discriminator { get; set; } + public string AvatarId { get; set; } + + public int? ClubId { get; set; } + public ClubInfo Club { get; set; } + public bool IsClubAdmin { get; set; } + + public long TotalXp { get; set; } + public XpNotificationLocation NotifyOnLevelUp { get; set; } + + public long CurrencyAmount { get; set; } + + public override bool Equals(object obj) + => obj is DiscordUser du ? du.UserId == UserId : false; + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override string ToString() + { + if (string.IsNullOrWhiteSpace(Discriminator) || Discriminator == "0000") + return Username; + + return Username + "#" + Discriminator; + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Event.cs b/src/EllieBot/Db/Models/Event.cs new file mode 100644 index 0000000..63202f6 --- /dev/null +++ b/src/EllieBot/Db/Models/Event.cs @@ -0,0 +1,49 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class CurrencyEvent +{ + public enum Type + { + Reaction, + + GameStatus + //NotRaid, + } + + public ulong ServerId { get; set; } + public ulong ChannelId { get; set; } + public ulong MessageId { get; set; } + public Type EventType { get; set; } + + /// + /// Amount of currency that the user will be rewarded. + /// + public long Amount { get; set; } + + /// + /// Maximum amount of currency that can be handed out. + /// + public long PotSize { get; set; } + + public List AwardedUsers { get; set; } + + /// + /// Used as extra data storage for events which need it. + /// + public ulong ExtraId { get; set; } + + /// + /// May be used for some future event. + /// + public ulong ExtraId2 { get; set; } + + /// + /// May be used for some future event. + /// + public string ExtraString { get; set; } +} + +public class AwardedUser +{ +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FeedSub.cs b/src/EllieBot/Db/Models/FeedSub.cs new file mode 100644 index 0000000..66fc6f1 --- /dev/null +++ b/src/EllieBot/Db/Models/FeedSub.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class FeedSub : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public ulong ChannelId { get; set; } + public string Url { get; set; } + + public string Message { get; set; } + + public override int GetHashCode() + => Url.GetHashCode(StringComparison.InvariantCulture) ^ GuildConfigId.GetHashCode(); + + public override bool Equals(object obj) + => obj is FeedSub s && s.Url.ToLower() == Url.ToLower() && s.GuildConfigId == GuildConfigId; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FollowedStream.cs b/src/EllieBot/Db/Models/FollowedStream.cs new file mode 100644 index 0000000..c880a8d --- /dev/null +++ b/src/EllieBot/Db/Models/FollowedStream.cs @@ -0,0 +1,33 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class FollowedStream : DbEntity +{ + public enum FType + { + Twitch = 0, + Picarto = 3, + Youtube = 4, + Facebook = 5, + Trovo = 6 + } + + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public string Username { get; set; } + public FType Type { get; set; } + public string Message { get; set; } + + protected bool Equals(FollowedStream other) + => ChannelId == other.ChannelId + && Username.Trim().ToUpperInvariant() == other.Username.Trim().ToUpperInvariant() + && Type == other.Type; + + public override int GetHashCode() + => HashCode.Combine(ChannelId, Username, (int)Type); + + public override bool Equals(object obj) + => obj is FollowedStream fs && Equals(fs); + + +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GCChannelId.cs b/src/EllieBot/Db/Models/GCChannelId.cs new file mode 100644 index 0000000..c6f922b --- /dev/null +++ b/src/EllieBot/Db/Models/GCChannelId.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class GCChannelId : DbEntity +{ + public GuildConfig GuildConfig { get; set; } + public ulong ChannelId { get; set; } + + public override bool Equals(object obj) + => obj is GCChannelId gc && gc.ChannelId == ChannelId; + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GamblingStats.cs b/src/EllieBot/Db/Models/GamblingStats.cs new file mode 100644 index 0000000..3c91a3b --- /dev/null +++ b/src/EllieBot/Db/Models/GamblingStats.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class GamblingStats : DbEntity +{ + public string Feature { get; set; } + public decimal Bet { get; set; } + public decimal PaidOut { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GroupName.cs b/src/EllieBot/Db/Models/GroupName.cs new file mode 100644 index 0000000..3e29b31 --- /dev/null +++ b/src/EllieBot/Db/Models/GroupName.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class GroupName : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public int Number { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GuildColors.cs b/src/EllieBot/Db/Models/GuildColors.cs new file mode 100644 index 0000000..efd5fc1 --- /dev/null +++ b/src/EllieBot/Db/Models/GuildColors.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Db.Models; + +public class GuildColors +{ + [Key] + public ulong GuildId { get; set; } + + [Length(0, 9)] + public string? OkColor { get; set; } + + [Length(0, 9)] + public string? ErrorColor { get; set; } + + [Length(0, 9)] + public string? PendingColor { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GuildConfig.cs b/src/EllieBot/Db/Models/GuildConfig.cs new file mode 100644 index 0000000..a7b5ac5 --- /dev/null +++ b/src/EllieBot/Db/Models/GuildConfig.cs @@ -0,0 +1,107 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class GuildConfig : DbEntity +{ + public ulong GuildId { get; set; } + + public string Prefix { get; set; } + + public bool DeleteMessageOnCommand { get; set; } + public HashSet DelMsgOnCmdChannels { get; set; } = new(); + + public string AutoAssignRoleIds { get; set; } + + //greet stuff + public int AutoDeleteGreetMessagesTimer { get; set; } = 30; + public int AutoDeleteByeMessagesTimer { get; set; } = 30; + + public ulong GreetMessageChannelId { get; set; } + public ulong ByeMessageChannelId { get; set; } + + public bool SendDmGreetMessage { get; set; } + public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; + + public bool SendChannelGreetMessage { get; set; } + public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; + + public bool SendChannelByeMessage { get; set; } + public string ChannelByeMessageText { get; set; } = "%user% has left!"; + + //self assignable roles + public bool ExclusiveSelfAssignedRoles { get; set; } + public bool AutoDeleteSelfAssignedRoleMessages { get; set; } + + //stream notifications + public HashSet FollowedStreams { get; set; } = new(); + + //currencyGeneration + public HashSet GenerateCurrencyChannelIds { get; set; } = new(); + + public List Permissions { get; set; } + public bool VerbosePermissions { get; set; } = true; + public string PermissionRole { get; set; } + + public HashSet CommandCooldowns { get; set; } = new(); + + //filtering + public bool FilterInvites { get; set; } + public bool FilterLinks { get; set; } + public HashSet FilterInvitesChannelIds { get; set; } = new(); + public HashSet FilterLinksChannelIds { get; set; } = new(); + + //public bool FilterLinks { get; set; } + //public HashSet FilterLinksChannels { get; set; } = new HashSet(); + + public bool FilterWords { get; set; } + public HashSet FilteredWords { get; set; } = new(); + public HashSet FilterWordsChannelIds { get; set; } = new(); + + public HashSet MutedUsers { get; set; } = new(); + + public string MuteRoleName { get; set; } + public bool CleverbotEnabled { get; set; } + + public AntiRaidSetting AntiRaidSetting { get; set; } + public AntiSpamSetting AntiSpamSetting { get; set; } + public AntiAltSetting AntiAltSetting { get; set; } + + public string Locale { get; set; } + public string TimeZoneId { get; set; } + + public HashSet UnmuteTimers { get; set; } = new(); + public HashSet UnbanTimer { get; set; } = new(); + public HashSet UnroleTimer { get; set; } = new(); + public HashSet VcRoleInfos { get; set; } + public HashSet CommandAliases { get; set; } = new(); + public List WarnPunishments { get; set; } = new(); + public bool WarningsInitialized { get; set; } + public HashSet SlowmodeIgnoredUsers { get; set; } + public HashSet SlowmodeIgnoredRoles { get; set; } + + public List ShopEntries { get; set; } + public ulong? GameVoiceChannel { get; set; } + public bool VerboseErrors { get; set; } = true; + + public StreamRoleSettings StreamRole { get; set; } + + public XpSettings XpSettings { get; set; } + public List FeedSubs { get; set; } = new(); + public bool NotifyStreamOffline { get; set; } + public bool DeleteStreamOnlineMessage { get; set; } + public List SelfAssignableRoleGroupNames { get; set; } + public int WarnExpireHours { get; set; } + public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear; + + public bool DisableGlobalExpressions { get; set; } = false; + + #region Boost Message + + public bool SendBoostMessage { get; set; } + public string BoostMessage { get; set; } = "%user% just boosted this server!"; + public ulong BoostMessageChannelId { get; set; } + public int BoostMessageDeleteAfter { get; set; } + public bool StickyRoles { get; set; } + + #endregion +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredLogItem.cs b/src/EllieBot/Db/Models/IgnoredLogItem.cs new file mode 100644 index 0000000..7424d84 --- /dev/null +++ b/src/EllieBot/Db/Models/IgnoredLogItem.cs @@ -0,0 +1,16 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class IgnoredLogItem : DbEntity +{ + public int LogSettingId { get; set; } + public LogSetting LogSetting { get; set; } + public ulong LogItemId { get; set; } + public IgnoredItemType ItemType { get; set; } +} + +public enum IgnoredItemType +{ + Channel, + User +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs new file mode 100644 index 0000000..cbbda9e --- /dev/null +++ b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class IgnoredVoicePresenceChannel : DbEntity +{ + public LogSetting LogSetting { get; set; } + public ulong ChannelId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ImageOnlyChannel.cs b/src/EllieBot/Db/Models/ImageOnlyChannel.cs new file mode 100644 index 0000000..01d01fa --- /dev/null +++ b/src/EllieBot/Db/Models/ImageOnlyChannel.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class ImageOnlyChannel : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public OnlyChannelType Type { get; set; } +} + +public enum OnlyChannelType +{ + Image, + Link +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/LogSetting.cs b/src/EllieBot/Db/Models/LogSetting.cs new file mode 100644 index 0000000..677a128 --- /dev/null +++ b/src/EllieBot/Db/Models/LogSetting.cs @@ -0,0 +1,38 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class LogSetting : DbEntity +{ + public List LogIgnores { get; set; } = new(); + + public ulong GuildId { get; set; } + public ulong? LogOtherId { get; set; } + public ulong? MessageUpdatedId { get; set; } + public ulong? MessageDeletedId { get; set; } + + public ulong? UserJoinedId { get; set; } + public ulong? UserLeftId { get; set; } + public ulong? UserBannedId { get; set; } + public ulong? UserUnbannedId { get; set; } + public ulong? UserUpdatedId { get; set; } + + public ulong? ChannelCreatedId { get; set; } + public ulong? ChannelDestroyedId { get; set; } + public ulong? ChannelUpdatedId { get; set; } + + + public ulong? ThreadDeletedId { get; set; } + public ulong? ThreadCreatedId { get; set; } + + public ulong? UserMutedId { get; set; } + + //userpresence + public ulong? LogUserPresenceId { get; set; } + + //voicepresence + + public ulong? LogVoicePresenceId { get; set; } + + public ulong? LogVoicePresenceTTSId { get; set; } + public ulong? LogWarnsId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Permission.cs b/src/EllieBot/Db/Models/Permission.cs new file mode 100644 index 0000000..5670dd8 --- /dev/null +++ b/src/EllieBot/Db/Models/Permission.cs @@ -0,0 +1,55 @@ +#nullable disable +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; + +namespace EllieBot.Db.Models; + +[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")] +public class Permissionv2 : DbEntity, IIndexed +{ + public int? GuildConfigId { get; set; } + public int Index { get; set; } + + public PrimaryPermissionType PrimaryTarget { get; set; } + public ulong PrimaryTargetId { get; set; } + + public SecondaryPermissionType SecondaryTarget { get; set; } + public string SecondaryTargetName { get; set; } + + public bool IsCustomCommand { get; set; } + + public bool State { get; set; } + + [NotMapped] + public static Permissionv2 AllowAllPerm + => new() + { + PrimaryTarget = PrimaryPermissionType.Server, + PrimaryTargetId = 0, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = true, + Index = 0 + }; + + public static List GetDefaultPermlist + => new() + { + AllowAllPerm + }; +} + +public enum PrimaryPermissionType +{ + User, + Channel, + Role, + Server +} + +public enum SecondaryPermissionType +{ + Module, + Command, + AllModules +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlantedCurrency.cs b/src/EllieBot/Db/Models/PlantedCurrency.cs new file mode 100644 index 0000000..7e640a5 --- /dev/null +++ b/src/EllieBot/Db/Models/PlantedCurrency.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class PlantedCurrency : DbEntity +{ + public long Amount { get; set; } + public string Password { get; set; } + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public ulong UserId { get; set; } + public ulong MessageId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlaylistSong.cs b/src/EllieBot/Db/Models/PlaylistSong.cs new file mode 100644 index 0000000..ccd9312 --- /dev/null +++ b/src/EllieBot/Db/Models/PlaylistSong.cs @@ -0,0 +1,18 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class PlaylistSong : DbEntity +{ + public string Provider { get; set; } + public MusicType ProviderType { get; set; } + public string Title { get; set; } + public string Uri { get; set; } + public string Query { get; set; } +} + +public enum MusicType +{ + Radio, + YouTube, + Local, +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Reminder.cs b/src/EllieBot/Db/Models/Reminder.cs new file mode 100644 index 0000000..046615a --- /dev/null +++ b/src/EllieBot/Db/Models/Reminder.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class Reminder : DbEntity +{ + public DateTime When { get; set; } + public ulong ChannelId { get; set; } + public ulong ServerId { get; set; } + public ulong UserId { get; set; } + public string Message { get; set; } + public bool IsPrivate { get; set; } + public ReminderType Type { get; set; } +} + +public enum ReminderType +{ + User, + Timely +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Repeater.cs b/src/EllieBot/Db/Models/Repeater.cs new file mode 100644 index 0000000..d0ef69e --- /dev/null +++ b/src/EllieBot/Db/Models/Repeater.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class Repeater +{ + public int Id { get; set; } + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + public ulong? LastMessageId { get; set; } + public string Message { get; set; } + public TimeSpan Interval { get; set; } + public TimeSpan? StartTimeOfDay { get; set; } + public bool NoRedundant { get; set; } + public DateTime DateAdded { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RotatingPlayingStatus.cs b/src/EllieBot/Db/Models/RotatingPlayingStatus.cs new file mode 100644 index 0000000..6cf5cc4 --- /dev/null +++ b/src/EllieBot/Db/Models/RotatingPlayingStatus.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class RotatingPlayingStatus : DbEntity +{ + public string Status { get; set; } + public DbActivityType Type { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ShopEntry.cs b/src/EllieBot/Db/Models/ShopEntry.cs new file mode 100644 index 0000000..34cc8fe --- /dev/null +++ b/src/EllieBot/Db/Models/ShopEntry.cs @@ -0,0 +1,46 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public enum ShopEntryType +{ + Role, + + List, + Command +} + +public class ShopEntry : DbEntity, IIndexed +{ + public int Index { get; set; } + public int Price { get; set; } + public string Name { get; set; } + public ulong AuthorId { get; set; } + + public ShopEntryType Type { get; set; } + + //role + public string RoleName { get; set; } + public ulong RoleId { get; set; } + + //list + public HashSet Items { get; set; } = new(); + public ulong? RoleRequirement { get; set; } + + // command + public string Command { get; set; } +} + +public class ShopEntryItem : DbEntity +{ + public string Text { get; set; } + + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + return ((ShopEntryItem)obj).Text == Text; + } + + public override int GetHashCode() + => Text.GetHashCode(StringComparison.InvariantCulture); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamOnlineMessage.cs b/src/EllieBot/Db/Models/StreamOnlineMessage.cs new file mode 100644 index 0000000..c6443a6 --- /dev/null +++ b/src/EllieBot/Db/Models/StreamOnlineMessage.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class StreamOnlineMessage : DbEntity +{ + public ulong ChannelId { get; set; } + public ulong MessageId { get; set; } + + public FollowedStream.FType Type { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamRoleSettings.cs b/src/EllieBot/Db/Models/StreamRoleSettings.cs new file mode 100644 index 0000000..02674d5 --- /dev/null +++ b/src/EllieBot/Db/Models/StreamRoleSettings.cs @@ -0,0 +1,68 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class StreamRoleSettings : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + /// + /// Whether the feature is enabled in the guild. + /// + public bool Enabled { get; set; } + + /// + /// Id of the role to give to the users in the role 'FromRole' when they start streaming + /// + public ulong AddRoleId { get; set; } + + /// + /// Id of the role whose users are eligible to get the 'AddRole' + /// + public ulong FromRoleId { get; set; } + + /// + /// If set, feature will only apply to users who have this keyword in their streaming status. + /// + public string Keyword { get; set; } + + /// + /// A collection of whitelisted users' IDs. Whitelisted users don't require 'keyword' in + /// order to get the stream role. + /// + public HashSet Whitelist { get; set; } = new(); + + /// + /// A collection of blacklisted users' IDs. Blacklisted useres will never get the stream role. + /// + public HashSet Blacklist { get; set; } = new(); +} + +public class StreamRoleBlacklistedUser : DbEntity +{ + public ulong UserId { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + { + if (obj is not StreamRoleBlacklistedUser x) + return false; + + return x.UserId == UserId; + } + + public override int GetHashCode() + => UserId.GetHashCode(); +} + +public class StreamRoleWhitelistedUser : DbEntity +{ + public ulong UserId { get; set; } + public string Username { get; set; } + + public override bool Equals(object obj) + => obj is StreamRoleWhitelistedUser x ? x.UserId == UserId : false; + + public override int GetHashCode() + => UserId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/VcRoleInfo.cs b/src/EllieBot/Db/Models/VcRoleInfo.cs new file mode 100644 index 0000000..bb28450 --- /dev/null +++ b/src/EllieBot/Db/Models/VcRoleInfo.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class VcRoleInfo : DbEntity +{ + public ulong VoiceChannelId { get; set; } + public ulong RoleId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Waifu.cs b/src/EllieBot/Db/Models/Waifu.cs new file mode 100644 index 0000000..78ca0b3 --- /dev/null +++ b/src/EllieBot/Db/Models/Waifu.cs @@ -0,0 +1,75 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Services.Database.Models; + +public class WaifuInfo : DbEntity +{ + public int WaifuId { get; set; } + public DiscordUser Waifu { get; set; } + + public int? ClaimerId { get; set; } + public DiscordUser Claimer { get; set; } + + public int? AffinityId { get; set; } + public DiscordUser Affinity { get; set; } + + public long Price { get; set; } + public List Items { get; set; } = new(); + + public override string ToString() + { + var status = string.Empty; + + var waifuUsername = Waifu.ToString().TrimTo(20); + var claimer = Claimer?.ToString().TrimTo(20) + ?? "no one"; + + var affinity = Affinity?.ToString().TrimTo(20); + + if (AffinityId is null) + status = $"... but {waifuUsername}'s heart is empty"; + else if (AffinityId == ClaimerId) + status = $"... and {waifuUsername} likes {claimer} too <3"; + else + { + status = + $"... but {waifuUsername}'s heart belongs to {affinity}"; + } + + return $"**{waifuUsername}** - claimed by **{claimer}**\n\t{status}"; + } +} + +public class WaifuLbResult +{ + public string Username { get; set; } + public string Discrim { get; set; } + + public string Claimer { get; set; } + public string ClaimerDiscrim { get; set; } + + public string Affinity { get; set; } + public string AffinityDiscrim { get; set; } + + public long Price { get; set; } + + public override string ToString() + { + var claimer = "no one"; + var status = string.Empty; + + var waifuUsername = Username.TrimTo(20); + var claimerUsername = Claimer?.TrimTo(20); + + if (Claimer is not null) + claimer = $"{claimerUsername}#{ClaimerDiscrim}"; + if (Affinity is null) + status = $"... but {waifuUsername}'s heart is empty"; + else if (Affinity + AffinityDiscrim == Claimer + ClaimerDiscrim) + status = $"... and {waifuUsername} likes {claimerUsername} too <3"; + else + status = $"... but {waifuUsername}'s heart belongs to {Affinity.TrimTo(20)}#{AffinityDiscrim}"; + return $"**{waifuUsername}#{Discrim}** - claimed by **{claimer}**\n\t{status}"; + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/anti/AntiAltSetting.cs b/src/EllieBot/Db/Models/anti/AntiAltSetting.cs new file mode 100644 index 0000000..b9f9e58 --- /dev/null +++ b/src/EllieBot/Db/Models/anti/AntiAltSetting.cs @@ -0,0 +1,11 @@ +namespace EllieBot.Db.Models; + +public class AntiAltSetting +{ + public int Id { get; set; } + public int GuildConfigId { get; set; } + public TimeSpan MinAge { get; set; } + public PunishmentAction Action { get; set; } + public int ActionDurationMinutes { get; set; } + public ulong? RoleId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs b/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs new file mode 100644 index 0000000..aef2658 --- /dev/null +++ b/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Db.Models; + + +public class AntiRaidSetting : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public int UserThreshold { get; set; } + public int Seconds { get; set; } + public PunishmentAction Action { get; set; } + + /// + /// Duration of the punishment, in minutes. This works only for supported Actions, like: + /// Mute, Chatmute, Voicemute, etc... + /// + public int PunishDuration { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/anti/AntiSpamIgnore.cs b/src/EllieBot/Db/Models/anti/AntiSpamIgnore.cs new file mode 100644 index 0000000..a3cd623 --- /dev/null +++ b/src/EllieBot/Db/Models/anti/AntiSpamIgnore.cs @@ -0,0 +1,12 @@ +namespace EllieBot.Db.Models; + +public class AntiSpamIgnore : DbEntity +{ + public ulong ChannelId { get; set; } + + public override int GetHashCode() + => ChannelId.GetHashCode(); + + public override bool Equals(object? obj) + => obj is AntiSpamIgnore inst && inst.ChannelId == ChannelId; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs b/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs new file mode 100644 index 0000000..42c2183 --- /dev/null +++ b/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs @@ -0,0 +1,14 @@ +namespace EllieBot.Db.Models; + +#nullable disable +public class AntiSpamSetting : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public PunishmentAction Action { get; set; } + public int MessageThreshold { get; set; } = 3; + public int MuteTime { get; set; } + public ulong? RoleId { get; set; } + public HashSet IgnoredChannels { get; set; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/club/ClubInfo.cs b/src/EllieBot/Db/Models/club/ClubInfo.cs new file mode 100644 index 0000000..e5b7407 --- /dev/null +++ b/src/EllieBot/Db/Models/club/ClubInfo.cs @@ -0,0 +1,41 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Db.Models; + +public class ClubInfo : DbEntity +{ + [MaxLength(20)] + public string Name { get; set; } + public string Description { get; set; } + public string ImageUrl { get; set; } = string.Empty; + + public int Xp { get; set; } = 0; + public int? OwnerId { get; set; } + public DiscordUser Owner { get; set; } + + public List Members { get; set; } = new(); + public List Applicants { get; set; } = new(); + public List Bans { get; set; } = new(); + + public override string ToString() + => Name; +} + +public class ClubApplicants +{ + public int ClubId { get; set; } + public ClubInfo Club { get; set; } + + public int UserId { get; set; } + public DiscordUser User { get; set; } +} + +public class ClubBans +{ + public int ClubId { get; set; } + public ClubInfo Club { get; set; } + + public int UserId { get; set; } + public DiscordUser User { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/currency/BankUser.cs b/src/EllieBot/Db/Models/currency/BankUser.cs new file mode 100644 index 0000000..b62b49d --- /dev/null +++ b/src/EllieBot/Db/Models/currency/BankUser.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Db.Models; + +public class BankUser : DbEntity +{ + public ulong UserId { get; set; } + public long Balance { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/expr/EllieExpression.cs b/src/EllieBot/Db/Models/expr/EllieExpression.cs new file mode 100644 index 0000000..53eef8b --- /dev/null +++ b/src/EllieBot/Db/Models/expr/EllieExpression.cs @@ -0,0 +1,27 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class EllieExpression : DbEntity +{ + public ulong? GuildId { get; set; } + public string Response { get; set; } + public string Trigger { get; set; } + + public bool AutoDeleteTrigger { get; set; } + public bool DmResponse { get; set; } + public bool ContainsAnywhere { get; set; } + public bool AllowTarget { get; set; } + public string Reactions { get; set; } + + public string[] GetReactions() + => string.IsNullOrWhiteSpace(Reactions) ? Array.Empty() : Reactions.Split("@@@"); + + public bool IsGlobal() + => GuildId is null or 0; +} + +public class ReactionResponse : DbEntity +{ + public bool OwnerOnly { get; set; } + public string Text { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/expr/Quote.cs b/src/EllieBot/Db/Models/expr/Quote.cs new file mode 100644 index 0000000..62f57d7 --- /dev/null +++ b/src/EllieBot/Db/Models/expr/Quote.cs @@ -0,0 +1,26 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Db.Models; + +public class Quote : DbEntity +{ + public ulong GuildId { get; set; } + + [Required] + public string Keyword { get; set; } + + [Required] + public string AuthorName { get; set; } + + public ulong AuthorId { get; set; } + + [Required] + public string Text { get; set; } +} + +public enum OrderType +{ + Id = -1, + Keyword = -2 +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/filter/FilterChannelId.cs b/src/EllieBot/Db/Models/filter/FilterChannelId.cs new file mode 100644 index 0000000..fe3b97b --- /dev/null +++ b/src/EllieBot/Db/Models/filter/FilterChannelId.cs @@ -0,0 +1,30 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class FilterChannelId : DbEntity +{ + public ulong ChannelId { get; set; } + + public bool Equals(FilterChannelId other) + => ChannelId == other.ChannelId; + + public override bool Equals(object obj) + => obj is FilterChannelId fci && Equals(fci); + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} + +public class FilterWordsChannelId : DbEntity +{ + public ulong ChannelId { get; set; } + + public bool Equals(FilterWordsChannelId other) + => ChannelId == other.ChannelId; + + public override bool Equals(object obj) + => obj is FilterWordsChannelId fci && Equals(fci); + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/filter/FilterLinksChannelId.cs b/src/EllieBot/Db/Models/filter/FilterLinksChannelId.cs new file mode 100644 index 0000000..50aca96 --- /dev/null +++ b/src/EllieBot/Db/Models/filter/FilterLinksChannelId.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class FilterLinksChannelId : DbEntity +{ + public ulong ChannelId { get; set; } + + public override bool Equals(object obj) + => obj is FilterLinksChannelId f && f.ChannelId == ChannelId; + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/filter/FilteredWord.cs b/src/EllieBot/Db/Models/filter/FilteredWord.cs new file mode 100644 index 0000000..de66d7a --- /dev/null +++ b/src/EllieBot/Db/Models/filter/FilteredWord.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class FilteredWord : DbEntity +{ + public string Word { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/giveaway/GiveawayModel.cs b/src/EllieBot/Db/Models/giveaway/GiveawayModel.cs new file mode 100644 index 0000000..ca077b2 --- /dev/null +++ b/src/EllieBot/Db/Models/giveaway/GiveawayModel.cs @@ -0,0 +1,14 @@ +namespace EllieBot.Db.Models; + +#nullable disable +public sealed class GiveawayModel +{ + public int Id { get; set; } + public ulong GuildId { get; set; } + public ulong MessageId { get; set; } + public ulong ChannelId { get; set; } + public string Message { get; set; } + + public IList Participants { get; set; } = new List(); + public DateTime EndsAt { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/giveaway/GiveawayUser.cs b/src/EllieBot/Db/Models/giveaway/GiveawayUser.cs new file mode 100644 index 0000000..a8b964e --- /dev/null +++ b/src/EllieBot/Db/Models/giveaway/GiveawayUser.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Db.Models; + +#nullable disable +public sealed class GiveawayUser +{ + public int Id { get; set; } + public int GiveawayId { get; set; } + public ulong UserId { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/punish/BanTemplate.cs b/src/EllieBot/Db/Models/punish/BanTemplate.cs new file mode 100644 index 0000000..0c8519f --- /dev/null +++ b/src/EllieBot/Db/Models/punish/BanTemplate.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class BanTemplate : DbEntity +{ + public ulong GuildId { get; set; } + public string Text { get; set; } + public int? PruneDays { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/punish/MutedUserId.cs b/src/EllieBot/Db/Models/punish/MutedUserId.cs new file mode 100644 index 0000000..f067e77 --- /dev/null +++ b/src/EllieBot/Db/Models/punish/MutedUserId.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class MutedUserId : DbEntity +{ + public ulong UserId { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is MutedUserId mui ? mui.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/punish/PunishmentAction.cs b/src/EllieBot/Db/Models/punish/PunishmentAction.cs new file mode 100644 index 0000000..5788e65 --- /dev/null +++ b/src/EllieBot/Db/Models/punish/PunishmentAction.cs @@ -0,0 +1,15 @@ +namespace EllieBot.Db.Models; + +public enum PunishmentAction +{ + Mute, + Kick, + Ban, + Softban, + RemoveRoles, + ChatMute, + VoiceMute, + AddRole, + Warn, + TimeOut +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/punish/WarnExpireAction.cs b/src/EllieBot/Db/Models/punish/WarnExpireAction.cs new file mode 100644 index 0000000..0de916e --- /dev/null +++ b/src/EllieBot/Db/Models/punish/WarnExpireAction.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public enum WarnExpireAction +{ + Clear, + Delete +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/punish/Warning.cs b/src/EllieBot/Db/Models/punish/Warning.cs new file mode 100644 index 0000000..454a4cb --- /dev/null +++ b/src/EllieBot/Db/Models/punish/Warning.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class Warning : DbEntity +{ + public ulong GuildId { get; set; } + public ulong UserId { get; set; } + public string Reason { get; set; } + public bool Forgiven { get; set; } + public string ForgivenBy { get; set; } + public string Moderator { get; set; } + public long Weight { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/punish/WarningPunishment.cs b/src/EllieBot/Db/Models/punish/WarningPunishment.cs new file mode 100644 index 0000000..5368938 --- /dev/null +++ b/src/EllieBot/Db/Models/punish/WarningPunishment.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class WarningPunishment : DbEntity +{ + public int Count { get; set; } + public PunishmentAction Punishment { get; set; } + public int Time { get; set; } + public ulong? RoleId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/roles/ReactionRole.cs b/src/EllieBot/Db/Models/roles/ReactionRole.cs new file mode 100644 index 0000000..2dedbfe --- /dev/null +++ b/src/EllieBot/Db/Models/roles/ReactionRole.cs @@ -0,0 +1,18 @@ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Db.Models; + +public class ReactionRoleV2 : DbEntity +{ + public ulong GuildId { get; set; } + public ulong ChannelId { get; set; } + + public ulong MessageId { get; set; } + + [MaxLength(100)] + public string Emote { get; set; } + public ulong RoleId { get; set; } + public int Group { get; set; } + public int LevelReq { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/roles/SelfAssignableRole.cs b/src/EllieBot/Db/Models/roles/SelfAssignableRole.cs new file mode 100644 index 0000000..ac147b6 --- /dev/null +++ b/src/EllieBot/Db/Models/roles/SelfAssignableRole.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class SelfAssignedRole : DbEntity +{ + public ulong GuildId { get; set; } + public ulong RoleId { get; set; } + + public int Group { get; set; } + public int LevelRequirement { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/roles/StickyRoles.cs b/src/EllieBot/Db/Models/roles/StickyRoles.cs new file mode 100644 index 0000000..3e01ae9 --- /dev/null +++ b/src/EllieBot/Db/Models/roles/StickyRoles.cs @@ -0,0 +1,14 @@ +namespace EllieBot.Db.Models; + +#nullable disable +public class StickyRole : DbEntity +{ + public ulong GuildId { get; set; } + public string RoleIds { get; set; } + public ulong UserId { get; set; } + + public ulong[] GetRoleIds() + => string.IsNullOrWhiteSpace(RoleIds) + ? [] + : RoleIds.Split(',').Select(ulong.Parse).ToArray(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredRole.cs b/src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredRole.cs new file mode 100644 index 0000000..e41c2e7 --- /dev/null +++ b/src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredRole.cs @@ -0,0 +1,20 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class SlowmodeIgnoredRole : DbEntity +{ + public ulong RoleId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + + return ((SlowmodeIgnoredRole)obj).RoleId == RoleId; + } + + // override object.GetHashCode + public override int GetHashCode() + => RoleId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredUser.cs b/src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredUser.cs new file mode 100644 index 0000000..7ae0a05 --- /dev/null +++ b/src/EllieBot/Db/Models/slowmode/SlowmodeIgnoredUser.cs @@ -0,0 +1,20 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class SlowmodeIgnoredUser : DbEntity +{ + public ulong UserId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + + return ((SlowmodeIgnoredUser)obj).UserId == UserId; + } + + // override object.GetHashCode + public override int GetHashCode() + => UserId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/support/PatronQuota.cs b/src/EllieBot/Db/Models/support/PatronQuota.cs new file mode 100644 index 0000000..b87dcbc --- /dev/null +++ b/src/EllieBot/Db/Models/support/PatronQuota.cs @@ -0,0 +1,48 @@ +#nullable disable +namespace EllieBot.Db.Models; + +/// +/// Contains data about usage of Patron-Only commands per user +/// in order to provide support for quota limitations +/// (allow user x who is pledging amount y to use the specified command only +/// x amount of times in the specified time period) +/// +public class PatronQuota +{ + public ulong UserId { get; set; } + public FeatureType FeatureType { get; set; } + public string Feature { get; set; } + public uint HourlyCount { get; set; } + public uint DailyCount { get; set; } + public uint MonthlyCount { get; set; } +} + +public enum FeatureType +{ + Command, + Group, + Module, + Limit +} + +public class PatronUser +{ + public string UniquePlatformUserId { get; set; } + public ulong UserId { get; set; } + public int AmountCents { get; set; } + + public DateTime LastCharge { get; set; } + + // Date Only component + public DateTime ValidThru { get; set; } + + public PatronUser Clone() + => new PatronUser() + { + UniquePlatformUserId = this.UniquePlatformUserId, + UserId = this.UserId, + AmountCents = this.AmountCents, + LastCharge = this.LastCharge, + ValidThru = this.ValidThru + }; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/support/RewardedUser.cs b/src/EllieBot/Db/Models/support/RewardedUser.cs new file mode 100644 index 0000000..bc12bdd --- /dev/null +++ b/src/EllieBot/Db/Models/support/RewardedUser.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class RewardedUser : DbEntity +{ + public ulong UserId { get; set; } + public string PlatformUserId { get; set; } + public long AmountRewardedThisMonth { get; set; } + public DateTime LastReward { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/todo/ArchivedTodoListModel.cs b/src/EllieBot/Db/Models/todo/ArchivedTodoListModel.cs new file mode 100644 index 0000000..b213788 --- /dev/null +++ b/src/EllieBot/Db/Models/todo/ArchivedTodoListModel.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Db.Models; + +#nullable disable +public sealed class ArchivedTodoListModel +{ + public int Id { get; set; } + public ulong UserId { get; set; } + public string Name { get; set; } + public List Items { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/todo/TodoModel.cs b/src/EllieBot/Db/Models/todo/TodoModel.cs new file mode 100644 index 0000000..ba3c8c1 --- /dev/null +++ b/src/EllieBot/Db/Models/todo/TodoModel.cs @@ -0,0 +1,13 @@ +namespace EllieBot.Db.Models; + +#nullable disable +public sealed class TodoModel +{ + public int Id { get; set; } + public ulong UserId { get; set; } + public string Todo { get; set; } + + public DateTime DateAdded { get; set; } + public bool IsDone { get; set; } + public int? ArchiveId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/untimer/UnbanTimer.cs b/src/EllieBot/Db/Models/untimer/UnbanTimer.cs new file mode 100644 index 0000000..2f61402 --- /dev/null +++ b/src/EllieBot/Db/Models/untimer/UnbanTimer.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class UnbanTimer : DbEntity +{ + public ulong UserId { get; set; } + public DateTime UnbanAt { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is UnbanTimer ut ? ut.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/untimer/UnmuteTimer.cs b/src/EllieBot/Db/Models/untimer/UnmuteTimer.cs new file mode 100644 index 0000000..18b2903 --- /dev/null +++ b/src/EllieBot/Db/Models/untimer/UnmuteTimer.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class UnmuteTimer : DbEntity +{ + public ulong UserId { get; set; } + public DateTime UnmuteAt { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is UnmuteTimer ut ? ut.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/untimer/UnroleTimer.cs b/src/EllieBot/Db/Models/untimer/UnroleTimer.cs new file mode 100644 index 0000000..27193c2 --- /dev/null +++ b/src/EllieBot/Db/Models/untimer/UnroleTimer.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class UnroleTimer : DbEntity +{ + public ulong UserId { get; set; } + public ulong RoleId { get; set; } + public DateTime UnbanAt { get; set; } + + public override int GetHashCode() + => UserId.GetHashCode() ^ RoleId.GetHashCode(); + + public override bool Equals(object obj) + => obj is UnroleTimer ut ? ut.UserId == UserId && ut.RoleId == RoleId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/xp/UserXpStats.cs b/src/EllieBot/Db/Models/xp/UserXpStats.cs new file mode 100644 index 0000000..d603360 --- /dev/null +++ b/src/EllieBot/Db/Models/xp/UserXpStats.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class UserXpStats : DbEntity +{ + public ulong UserId { get; set; } + public ulong GuildId { get; set; } + public long Xp { get; set; } + public long AwardedXp { get; set; } + public XpNotificationLocation NotifyOnLevelUp { get; set; } +} + +public enum XpNotificationLocation { None, Dm, Channel } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/xp/XpSettings.cs b/src/EllieBot/Db/Models/xp/XpSettings.cs new file mode 100644 index 0000000..694b289 --- /dev/null +++ b/src/EllieBot/Db/Models/xp/XpSettings.cs @@ -0,0 +1,62 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class XpSettings : DbEntity +{ + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public HashSet RoleRewards { get; set; } = new(); + public HashSet CurrencyRewards { get; set; } = new(); + public HashSet ExclusionList { get; set; } = new(); + public bool ServerExcluded { get; set; } +} + +public enum ExcludedItemType { Channel, Role } + +public class XpRoleReward : DbEntity +{ + public int XpSettingsId { get; set; } + public XpSettings XpSettings { get; set; } + + public int Level { get; set; } + public ulong RoleId { get; set; } + + /// + /// Whether the role should be removed (true) or added (false) + /// + public bool Remove { get; set; } + + public override int GetHashCode() + => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); + + public override bool Equals(object obj) + => obj is XpRoleReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; +} + +public class XpCurrencyReward : DbEntity +{ + public int XpSettingsId { get; set; } + public XpSettings XpSettings { get; set; } + + public int Level { get; set; } + public int Amount { get; set; } + + public override int GetHashCode() + => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); + + public override bool Equals(object obj) + => obj is XpCurrencyReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; +} + +public class ExcludedItem : DbEntity +{ + public ulong ItemId { get; set; } + public ExcludedItemType ItemType { get; set; } + + public override int GetHashCode() + => ItemId.GetHashCode() ^ ItemType.GetHashCode(); + + public override bool Equals(object obj) + => obj is ExcludedItem ei && ei.ItemId == ItemId && ei.ItemType == ItemType; +} \ No newline at end of file diff --git a/src/EllieBot/Db/MysqlContext.cs b/src/EllieBot/Db/MysqlContext.cs new file mode 100644 index 0000000..e8f4eba --- /dev/null +++ b/src/EllieBot/Db/MysqlContext.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public sealed class MysqlContext : EllieContext +{ + private readonly string _connStr; + private readonly string _version; + + protected override string CurrencyTransactionOtherIdDefaultValue + => "NULL"; + + public MysqlContext(string connStr = "Server=localhost", string version = "8.0") + { + _connStr = connStr; + _version = version; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + optionsBuilder + .UseLowerCaseNamingConvention() + .UseMySql(_connStr, ServerVersion.Parse(_version)); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // mysql is case insensitive by default + // we can set binary collation to change that + modelBuilder.Entity() + .Property(x => x.Name) + .UseCollation("utf8mb4_bin"); + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/PostgreSqlContext.cs b/src/EllieBot/Db/PostgreSqlContext.cs new file mode 100644 index 0000000..aea3e7c --- /dev/null +++ b/src/EllieBot/Db/PostgreSqlContext.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Db; + +public sealed class PostgreSqlContext : EllieContext +{ + private readonly string _connStr; + + protected override string CurrencyTransactionOtherIdDefaultValue + => "NULL"; + + public PostgreSqlContext(string connStr = "Host=localhost") + { + _connStr = connStr; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); + + base.OnConfiguring(optionsBuilder); + optionsBuilder + .UseLowerCaseNamingConvention() + .UseNpgsql(_connStr); + } +} \ No newline at end of file diff --git a/src/EllieBot/Db/SqliteContext.cs b/src/EllieBot/Db/SqliteContext.cs new file mode 100644 index 0000000..e284968 --- /dev/null +++ b/src/EllieBot/Db/SqliteContext.cs @@ -0,0 +1,26 @@ +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Db; + +public sealed class SqliteContext : EllieContext +{ + private readonly string _connectionString; + + protected override string CurrencyTransactionOtherIdDefaultValue + => "NULL"; + + public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60) + { + _connectionString = connectionString; + Database.SetCommandTimeout(commandTimeout); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + var builder = new SqliteConnectionStringBuilder(_connectionString); + builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource); + optionsBuilder.UseSqlite(builder.ToString()); + } +} \ No newline at end of file From 2e587e83ebd0a4611bfd4a3da3d1ff7c26798c2e Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 14 May 2024 23:59:24 +1200 Subject: [PATCH 36/62] Updated data files and GlobalUsings.cs --- src/EllieBot/GlobalUsings.cs | 3 +- src/EllieBot/data/aliases.yml | 147 +- src/EllieBot/data/bot.yml | 7 +- src/EllieBot/data/gambling.yml | 54 +- src/EllieBot/{ => data/lib}/libsodium.dll | Bin src/EllieBot/{ => data/lib}/libsodium.so | Bin src/EllieBot/{ => data/lib}/opus.dll | Bin src/EllieBot/{libopus.so => data/lib/opus.so} | Bin .../data/strings/commands/commands.en-US.yml | 4998 ++++++++++++----- .../strings/responses/responses.en-US.json | 44 +- src/EllieBot/data/units.json | 11 + 11 files changed, 3689 insertions(+), 1575 deletions(-) rename src/EllieBot/{ => data/lib}/libsodium.dll (100%) rename src/EllieBot/{ => data/lib}/libsodium.so (100%) rename src/EllieBot/{ => data/lib}/opus.dll (100%) rename src/EllieBot/{libopus.so => data/lib/opus.so} (100%) diff --git a/src/EllieBot/GlobalUsings.cs b/src/EllieBot/GlobalUsings.cs index 7984372..dbac5fd 100644 --- a/src/EllieBot/GlobalUsings.cs +++ b/src/EllieBot/GlobalUsings.cs @@ -3,16 +3,15 @@ global using NonBlocking; // packages global using Serilog; -global using Humanizer; // elliebot global using EllieBot; +global using EllieBot.Db; global using EllieBot.Services; global using Ellie.Common; // new project global using EllieBot.Common; // old + elliebot specific things global using EllieBot.Common.Attributes; global using EllieBot.Extensions; -global using Ellie.Marmalade; // discord global using Discord; diff --git a/src/EllieBot/data/aliases.yml b/src/EllieBot/data/aliases.yml index 9348169..4ec12e0 100644 --- a/src/EllieBot/data/aliases.yml +++ b/src/EllieBot/data/aliases.yml @@ -185,6 +185,9 @@ threaddelete: prune: - prune - clear +prunecancel: + - prunecancel + - prunec die: - die setname: @@ -195,6 +198,8 @@ setnick: setavatar: - setavatar - setav +setbanner: + - setbanner setgame: - setgame send: @@ -416,8 +421,6 @@ typestop: - typestop typeadd: - typeadd -pollend: - - pollend pick: - pick plant: @@ -432,8 +435,6 @@ choose: - choose rps: - rps -linux: - - linux next: - next - n @@ -461,9 +462,6 @@ queuesearch: - queuesearch - qs - yqs -soundcloudqueue: - - soundcloudqueue - - sq listqueue: - listqueue - lq @@ -477,9 +475,6 @@ volume: playlist: - playlist - pl -soundcloudpl: - - soundcloudpl - - scpl localplaylist: - localplaylist - lopl @@ -511,6 +506,8 @@ queuerepeat: queueautoplay: - queueautoplay - qap +queuefairplay: + - qfp save: - save streamrole: @@ -647,8 +644,6 @@ chucknorris: magicitem: - magicitem - mi -safebooru: - - safebooru wiki: - wiki - wikipedia @@ -658,25 +653,6 @@ color: avatar: - avatar - av -hentai: - - hentai -danbooru: - - danbooru -derpibooru: - - derpibooru - - derpi -gelbooru: - - gelbooru -rule34: - - rule34 -e621: - - e621 -boobs: - - boobs -butts: - - butts - - ass - - butt translate: - translate - trans @@ -757,10 +733,6 @@ chatmute: - chatmute voicemute: - voicemute -konachan: - - konachan -sankaku: - - sankaku muterole: - muterole - setmuterole @@ -774,13 +746,6 @@ unmute: - unmute xkcd: - xkcd -placelist: - - placelist -place: - - place -poll: - - poll - - ppoll autotranslang: - autotranslang - atl @@ -797,8 +762,6 @@ typelist: - typelist listservers: - listservers -hentaibomb: - - hentaibomb cleverbot: - cleverbot - chatgpt @@ -807,8 +770,6 @@ shorten: wikia: - wikia - fandom -yandere: - - yandere magicthegathering: - magicthegathering - mtg @@ -833,8 +794,6 @@ define: - def activity: - activity -autohentai: - - autohentai setstatus: - setstatus invitecreate: @@ -848,8 +807,6 @@ invitedelete: - invitedelete - invrm - invdel -pollstats: - - pollstats antilist: - antilist - antilst @@ -919,8 +876,6 @@ languageset: languageslist: - languageslist - langli -rategirl: - - rategirl aliaslist: - aliaslist - cmdmaplist @@ -1055,9 +1010,6 @@ configreload: - creload - confreload - crel -nsfwtagblacklist: - - nsfwtagbl - - nsfwtbl experience: - experience - xp @@ -1137,10 +1089,8 @@ clubleaderboard: - clubs clubadmin: - clubadmin -autoboobs: - - autoboobs -autobutts: - - autobutts +clubrename: + - clubrename eightball: - eightball - 8ball @@ -1163,6 +1113,8 @@ sqlexec: - sqlexec sqlselect: - sqlselect +sqlselectcsv: + - sqlselectcsv deletewaifus: - deletewaifus deletewaifu: @@ -1211,19 +1163,19 @@ pathofexilecurrency: - poec rollduel: - rollduel -reactionroleadd: - - reactionroleadd +reroadd: + - reroadd - reroa -reactionroleslist: - - reactionroleslist +rerolist: + - rerolist - reroli -reactionrolesremove: - - reactionrolesremove +reroremove: + - reroremove - rerorm -reactionrolesdeleteall: +rerodeleteall: - rerodeleteall - rerodela -reactionrolestransfer: +rerotransfer: - rerotransfer - rerot blackjack: @@ -1247,10 +1199,9 @@ delete: roleid: - roleid - rid -nsfwtoggle: +agerestricttoggle: - nsfwtoggle - - nsfw - - nsfwtgl + - artoggle economy: - economy purgeuser: @@ -1356,6 +1307,9 @@ marmaladelist: marmaladeinfo: - marmaladeinfo - mainfo +marmaladesearch: + - marmaladesearch + - masearchW # Bank stuff bankdeposit: - deposit @@ -1389,3 +1343,56 @@ doas: - execas cacheusers: - cacheusers +giveawaystart: + - start +giveawayend: + - end +giveawaycancel: + - cancel +giveawayreroll: + - reroll +giveawaylist: + - list +# todos +todoadd: + - add + - a +todolist: + - list + - ls +tododelete: + - delete + - del + - remove + - rm +todoclear: + - clear + - clr + - cls +todocomplete: + - complete + - done + - finish +todoarchiveadd: + - add + - create + - new +todoarchiveshow: + - show +todoarchivelist: + - list + - ls +todoarchivedelete: + - delete + - del + - remove + - rm +todoedit: + - edit + - change +todoshow: + - show + - sh + - see +stickyroles: + - stickyroles diff --git a/src/EllieBot/data/bot.yml b/src/EllieBot/data/bot.yml index 42753e0..81130d1 100644 --- a/src/EllieBot/data/bot.yml +++ b/src/EllieBot/data/bot.yml @@ -1,5 +1,5 @@ # DO NOT CHANGE -version: 5 +version: 7 # Most commands, when executed, have a small colored line # next to the response. The color depends whether the command # is completed, errored or in progress (pending) @@ -28,6 +28,11 @@ forwardToAllOwners: false # Any messages sent by users in Bot's DM to be forwarded to the specified channel. # This option will only work when ForwardToAllOwners is set to false forwardToChannel: +# Should the bot ignore messages from other bots? +# Settings this to false might get your bot banned if it gets into a spam loop with another bot. +# This will only affect command executions, other features will still block bots from access. +# Default true +ignoreOtherBots: true # When a user DMs the bot with a message which is not a command # they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. # Supports embeds. How it looks: https://puu.sh/B0BLV.png diff --git a/src/EllieBot/data/gambling.yml b/src/EllieBot/data/gambling.yml index 4064cfe..fbcbdc4 100644 --- a/src/EllieBot/data/gambling.yml +++ b/src/EllieBot/data/gambling.yml @@ -1,12 +1,12 @@ # DO NOT CHANGE -version: 6 +version: 7 # Currency settings currency: -# What is the emoji/character which represents the currency + # What is the emoji/character which represents the currency sign: "💵" # What is the name of the currency name: Ellie Cash - # For how long will the transactions be kept in the database (curtrs) + # For how long (in days) will the transactions be kept in the database (curtrs) # Set 0 to disable cleanup (keep transactions forever) transactionsLifetime: 0 # Minimum amount users can bet (>=0) @@ -16,13 +16,13 @@ minBet: 0 maxBet: 0 # Settings for betflip command betFlip: -# Bet multiplier if user guesses correctly + # Bet multiplier if user guesses correctly multiplier: 1.95 # Settings for betroll command betRoll: -# When betroll is played, user will roll a number 0-100. -# This setting will describe which multiplier is used for when the roll is higher than the given number. -# Doesn't have to be ordered. + # When betroll is played, user will roll a number 0-100. + # This setting will describe which multiplier is used for when the roll is higher than the given number. + # Doesn't have to be ordered. pairs: - whenAbove: 99 multiplyBy: 10 @@ -32,9 +32,9 @@ betRoll: multiplyBy: 2 # Automatic currency generation settings. generation: -# when currency is generated, should it also have a random password -# associated with it which users have to type after the .pick command -# in order to get it + # when currency is generated, should it also have a random password + # associated with it which users have to type after the .pick command + # in order to get it hasPassword: true # Every message sent has a certain % chance to generate the currency # specify the percentage here (1 being 100%, 0 being 0% - for example @@ -50,16 +50,16 @@ generation: # Settings for timely command # (letting people claim X amount of currency every Y hours) timely: -# How much currency will the users get every time they run .timely command -# setting to 0 or less will disable this feature + # How much currency will the users get every time they run .timely command + # setting to 0 or less will disable this feature amount: 120 # How often (in hours) can users claim currency with .timely command # setting to 0 or less will disable this feature cooldown: 12 # How much will each user's owned currency decay over time. decay: -# Percentage of user's current currency which will be deducted every 24h. -# 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) + # Percentage of user's current currency which will be deducted every 24h. + # 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) percent: 0 # Maximum amount of user's currency that can decay at each interval. 0 for unlimited. maxDecay: 0 @@ -67,9 +67,17 @@ decay: minThreshold: 99 # How often, in hours, does the decay run. Default is 24 hours hourInterval: 24 +# What is the bot's cut on some transactions +botCuts: + # Shop sale cut percentage. + # Whenever a user buys something from the shop, bot will take a cut equal to this percentage. + # The rest goes to the user who posted the item/role/whatever to the shop. + # This is a good way to reduce the amount of currency in circulation therefore keeping the inflation in check. + # Default 0.1 (10%). + shopSaleCut: 0.1 # Settings for LuckyLadder command luckyLadder: -# Self-Explanatory. Has to have 8 values, otherwise the command won't work. + # Self-Explanatory. Has to have 8 values, otherwise the command won't work. multipliers: - 2.4 - 1.7 @@ -81,12 +89,12 @@ luckyLadder: - 0.1 # Settings related to waifus waifu: -# Minimum price a waifu can have + # Minimum price a waifu can have minPrice: 50 multipliers: - # Multiplier for waifureset. Default 150. - # Formula (at the time of writing this): - # price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up + # Multiplier for waifureset. Default 150. + # Formula (at the time of writing this): + # price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up waifuReset: 150 # The minimum amount of currency that you have to pay # in order to buy a waifu who doesn't have a crush on you. @@ -117,9 +125,9 @@ waifu: # Settings for periodic waifu price decay. # Waifu price decays only if the waifu has no claimer. decay: - # Percentage (0 - 100) of the waifu value to reduce. - # Set 0 to disable - # For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$) + # Percentage (0 - 100) of the waifu value to reduce. + # Set 0 to disable + # For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$) percent: 0 # How often to decay waifu values, in hours hourInterval: 24 @@ -257,5 +265,5 @@ patreonCurrencyPerCent: 1 voteReward: 100 # Slot config slots: -# Hex value of the color which the numbers on the slot image will have. + # Hex value of the color which the numbers on the slot image will have. currencyFontColor: ff0000 diff --git a/src/EllieBot/libsodium.dll b/src/EllieBot/data/lib/libsodium.dll similarity index 100% rename from src/EllieBot/libsodium.dll rename to src/EllieBot/data/lib/libsodium.dll diff --git a/src/EllieBot/libsodium.so b/src/EllieBot/data/lib/libsodium.so similarity index 100% rename from src/EllieBot/libsodium.so rename to src/EllieBot/data/lib/libsodium.so diff --git a/src/EllieBot/opus.dll b/src/EllieBot/data/lib/opus.dll similarity index 100% rename from src/EllieBot/opus.dll rename to src/EllieBot/data/lib/opus.dll diff --git a/src/EllieBot/libopus.so b/src/EllieBot/data/lib/opus.so similarity index 100% rename from src/EllieBot/libopus.so rename to src/EllieBot/data/lib/opus.so diff --git a/src/EllieBot/data/strings/commands/commands.en-US.yml b/src/EllieBot/data/strings/commands/commands.en-US.yml index a916919..61d97ee 100644 --- a/src/EllieBot/data/strings/commands/commands.en-US.yml +++ b/src/EllieBot/data/strings/commands/commands.en-US.yml @@ -1,35 +1,57 @@ h: - desc: "Either shows a help for a single command, or DMs you help link if no parameters are specified." - args: + desc: Either shows a help for a single command, or DMs you help link if no parameters are specified. + ex: - "{0}cmds" - "" + params: + - fail: + desc: "Fallback parameter if the command is not found." + - com: + desc: "The command information that the help is being requested for." gencmdlist: - desc: "Generates the command list and sends it to the chat. Optionally also uploads it to DO spaces (not supported)." - args: + desc: Generates the command list and sends it to the chat. Optionally also uploads it to DO spaces (not supported). + ex: - "" + params: + - {} donate: - desc: "Instructions for helping the project financially." - args: + desc: Instructions for helping the project financially. + ex: - "" + params: + - {} modules: - desc: "Lists all bot modules." - args: + desc: Lists all bot modules. + ex: - "" + params: + - page: + desc: "The number of the page to display in the list of bot modules." commands: - desc: "List all of the bot's commands from the specified module. You can either specify the full name or only the first few letters of the module name. Specifying no module will show the list of modules instead." - args: - - "Admin" - - "Admin --view 1" + desc: List all of the bot's commands from the specified module. You can either specify the full name or only the first few letters of the module name. Specifying no module will show the list of modules instead. + ex: + - Admin + - Admin --view 1 - "" + params: + - module: + desc: "The name of a module to retrieve command information for." + params: + desc: "The names of one or more modules to retrieve commands from, allowing for partial matching and optional omission." greetdel: - desc: "Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion." - args: - - "0" - - "30" + desc: Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. + ex: + - 0 + - 30 + params: + - timer: + desc: "The amount of time before greeting messages are automatically deleted from the chat." greet: - desc: "Toggles announcements on the current channel when someone joins the server." - args: + desc: Toggles announcements on the current channel when someone joins the server. + ex: - "" + params: + - {} greetmsg: desc: |- Sets a new join announcement message which will be shown in the server's channel. @@ -37,12 +59,17 @@ greetmsg: Full list of placeholders can be found here Using it with no message will show the current greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. - args: - - "Welcome, %user.mention%." + ex: + - Welcome, %user.mention%. + params: + - text: + desc: "The new announcement message to be displayed when a user joins the server." bye: - desc: "Toggles announcements on the current channel when someone leaves the server." - args: + desc: Toggles announcements on the current channel when someone leaves the server. + ex: - "" + params: + - {} byemsg: desc: |- Sets a new leave announcement message. @@ -50,160 +77,305 @@ byemsg: Full list of placeholders can be found here Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. - args: + ex: - "%user.mention% has left." + params: + - text: + desc: "The user's farewell message to display when they leave the chat." byedel: - desc: "Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion." - args: - - "0" - - "30" + desc: Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. + ex: + - 0 + - 30 + params: + - timer: + desc: "The amount of time before a bye message is automatically deleted." greetdm: - desc: "Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled)." - args: + desc: Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). + ex: - "" + params: + - {} greettest: - desc: "Sends the greet message in the current channel as if you just joined the server. You can optionally specify a different user." - args: + desc: Sends the greet message in the current channel as if you just joined the server. You can optionally specify a different user. + ex: - "" - "@SomeoneElse" + params: + - user: + desc: "The user to impersonate when sending the greeting, or null for the bot's own account." greetdmtest: - desc: "Sends the greet direct message to you as if you just joined the server. You can optionally specify a different user." - args: + desc: Sends the greet direct message to you as if you just joined the server. You can optionally specify a different user. + ex: - "" - "@SomeoneElse" + params: + - user: + desc: "The recipient of the greeting, which defaults to the caller if not specified." byetest: - desc: "Sends the bye message in the current channel as if you just left the server. You can optionally specify a different user." - args: + desc: Sends the bye message in the current channel as if you just left the server. You can optionally specify a different user. + ex: - "" - "@SomeoneElse" + params: + - user: + desc: "The user who is leaving the channel, or whose account is being represented as leaving the channel." boost: - desc: "Toggles announcements on the current channel when someone boosts the server." - args: + desc: Toggles announcements on the current channel when someone boosts the server. + ex: - "" + params: + - {} boostmsg: desc: |- Sets a new boost announcement message. Type `%user.mention%` if you want to show the name the user who left. - Full list of placeholders can be found here + Full list of placeholders can be found here Using this command with no message will show the current boost message. You can use embed json from instead of a regular text, if you want the message to be embedded. - args: + ex: - "%user.mention% has boosted the server!!!" + params: + - text: + desc: "The text to set as the new announcement message." boostdel: - desc: "Sets the time it takes (in seconds) for boost messages to be auto-deleted. Set it to `0` to disable automatic deletion." - args: - - "0" - - "30" + desc: Sets the time it takes (in seconds) for boost messages to be auto-deleted. Set it to `0` to disable automatic deletion. + ex: + - 0 + - 30 + params: + - timer: + desc: "The amount of time before boost messages are automatically deleted." logserver: - desc: "Enables or Disables ALL log events. If enabled, all log events will log to this channel." - args: - - "enable" - - "disable" + desc: Enables or Disables ALL log events. If enabled, all log events will log to this channel. + ex: + - enable + - disable + params: + - action: + desc: "The type of action to take on the log event." logignore: - desc: "Toggles whether the `{0}logserver` command ignores the specified channel or user. Provide no arguments to see the list of currently ignored users and channels" - args: + desc: Toggles whether the `{0}logserver` command ignores the specified channel or user. Provide no arguments to see the list of currently ignored users and channels + ex: - "" - "@SomeUser" - "#some-channel" + params: + - {} + - target: + desc: "The channel to ignore or show the list of ignored channels for." + - target: + desc: "The user or channel being targeted for logging ignore or inclusion." repeatlist: - desc: "Shows currently repeating messages and their indexes." - args: + desc: Shows currently repeating messages and their indexes. + ex: - "" + params: + - {} repeatremove: - desc: "Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes." - args: - - "2" + desc: Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + ex: + - 2 + params: + - index: + desc: "The index at which the repeating message should be removed." repeatinvoke: - desc: "Immediately shows the repeat message on a certain index and restarts its timer." - args: - - "1" + desc: Immediately shows the repeat message on a certain index and restarts its timer. + ex: + - 1 + params: + - index: + desc: "The index at which to display the repeat message." repeat: - desc: "Repeat a message once every specified amount of time in the current channel. You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). If you've specified time of day, you can still override the default daily interval with your own interval. You can have up to 5 repeating messages on the server in total." - args: - - "Hello there" - - "1h5m Hello @erryone" - - "10:00 Daily have a nice day! This will execute once every 24h." - - "21:00 30m Starting at 21 and every 30 minutes after that i will send this message!" + desc: Repeat a message once every specified amount of time in the current channel. You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). If you've specified time of day, you can still override the default daily interval with your own interval. You can have up to 5 repeating messages on the server in total. + ex: + - Hello there + - 1h5m Hello @erryone + - 10:00 Daily have a nice day! This will execute once every 24h. + - 21:00 30m Starting at 21 and every 30 minutes after that i will send this message! + params: + - message: + desc: "The text to be repeated at the specified intervals or times." + - channel: + desc: "The channel where the message will be repeated." + message: + desc: "The text to be repeated at the specified intervals or times." + - interval: + desc: "The amount of time between each repetition." + message: + desc: "The text to be repeated at the specified intervals or times." + - ch: + desc: "The channel where the message will be sent." + interval: + desc: "The amount of time between each repetition." + message: + desc: "The text to be repeated at the specified intervals or times." + - dt: + desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + message: + desc: "The text to be repeated at the specified intervals or times." + - channel: + desc: "The channel where the message will be repeated." + dt: + desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + message: + desc: "The text to be repeated at the specified intervals or times." + - dt: + desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + interval: + desc: "The amount of time between each repetition." + message: + desc: "The text to be repeated at the specified intervals or times." + - channel: + desc: "The channel where the message will be repeated." + dt: + desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + interval: + desc: "The amount of time between each repetition." + message: + desc: "The text to be repeated at the specified intervals or times." repeatredundant: - desc: "Specify repeater's index (use `{0}repli` to find it) to toggle whether that repeater's message should be reposted if the last message in the channel is the same repeater's message. This is useful if you want to remind everyone to be nice in the channel every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone." - args: - - "1" + desc: Specify repeater's index (use `{0}repli` to find it) to toggle whether that repeater's message should be reposted if the last message in the channel is the same repeater's message. This is useful if you want to remind everyone to be nice in the channel every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone. + ex: + - 1 + params: + - index: + desc: "The number of times a message should be repeated before reposting." repeatskip: - desc: "Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. This setting is not stored in the database and will get reset if the bot is restarted." - args: - - "3" + desc: Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. This setting is not stored in the database and will get reset if the bot is restarted. + ex: + - 3 + params: + - index: + desc: "The number of times to skip before triggering again." rotateplaying: - desc: "Toggles rotation of playing status of the dynamic strings you previously specified." - args: + desc: Toggles rotation of playing status of the dynamic strings you previously specified. + ex: - "" + params: + - {} addplaying: - desc: "Adds a specified string to the list of playing strings to rotate. You have to pick either 'Playing', 'Watching' or 'Listening' as the first parameter." - args: - - "Playing with you" - - "Watching you sleep" + desc: Adds a specified string to the list of playing strings to rotate. You have to pick either 'Playing', 'Watching' or 'Listening' as the first parameter. + ex: + - Playing with you + - Watching you sleep + params: + - t: + desc: "The type of status, allowed values are 'Playing', 'Watching', or 'Listening'." + status: + desc: "The status text." listplaying: - desc: "Lists all playing statuses with their corresponding number." - args: + desc: Lists all playing statuses with their corresponding number. + ex: - "" + params: + - {} removeplaying: - desc: "Removes a playing string on a given number." - args: + desc: Removes a playing string on a given number. + ex: - "" + params: + - index: + desc: "The position in the list where the playing string should be removed." vcrolelist: - desc: "Shows a list of currently set voice channel roles." - args: + desc: Shows a list of currently set voice channel roles. + ex: - "" + params: + - {} vcrole: - desc: "Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command." - args: - - "SomeRole" + desc: Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. + ex: + - SomeRole - "" + params: + - role: + desc: "The role that is assigned to new members of the voice channel." vcrolerm: - desc: "Removes vcrole associated with the specified voice channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted." - args: - - "123123123123123" + desc: Removes vcrole associated with the specified voice channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted. + ex: + - 123123123123123 + params: + - vcId: + desc: "The unique identifier of the voice channel to remove the vcrole from." asar: - desc: "Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled, users will be able to pick one role per group." - args: - - "Gamer" - - "1 Alliance" - - "1 Horde" + desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled, users will be able to pick one role per group. + ex: + - Gamer + - 1 Alliance + - 1 Horde + params: + - role: + desc: "The role that can be assigned by the user." + - group: + desc: "The ID of a group that the new role should belong to." + role: + desc: "The role that can be assigned by the user." rsar: - desc: "Removes a specified role from the list of self-assignable roles." - args: - - "Gamer" - - "Alliance" - - "Horde" + desc: Removes a specified role from the list of self-assignable roles. + ex: + - Gamer + - Alliance + - Horde + params: + - role: + desc: "The role being removed from the list of self-assignable roles." lsar: - desc: "Lists self-assignable roles. Shows 20 roles per page." - args: + desc: Lists self-assignable roles. Shows 20 roles per page. + ex: - "" - - "2" + - 2 + params: + - page: + desc: "The current page number for the list of roles." sargn: - desc: "Sets a self assignable role group name. Provide no name to remove." - args: - - "1 Faction" - - "2" + desc: Sets a self assignable role group name. Provide no name to remove. + ex: + - 1 Faction + - 2 + params: + - group: + desc: "The ID of the group to set as self-assignable." + name: + desc: "The name of the new or existing role group to set." togglexclsar: - desc: "Toggles whether the self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group." - args: + desc: Toggles whether the self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group. + ex: - "" + params: + - {} iam: - desc: "Adds a role to you that you choose. Role must be on a list of self-assignable roles." - args: - - "Gamer" + desc: Adds a role to you that you choose. Role must be on a list of self-assignable roles. + ex: + - Gamer + params: + - role: + desc: "The type of access or permission granted to the user." iamnot: - desc: "Removes a specified role from you. Role must be on a list of self-assignable roles." - args: - - "Gamer" + desc: Removes a specified role from you. Role must be on a list of self-assignable roles. + ex: + - Gamer + params: + - role: + desc: "The role being removed from the user's assignment." expradd: desc: "Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide here: " - args: + ex: - '"hello" Hi there %user.mention%' + params: + - key: + desc: "The trigger word that sets off the response when typed by a user." + message: + desc: "The text of the message that triggers the response when typed by a user." expraddserver: desc: "Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. Guide here: " - args: + ex: - '"hello" Hi there %user.mention%' + params: + - key: + desc: "The unique identifier for the expression to be added in this server." + message: + desc: "The text of the message that triggers the bot's response." exprlist: desc: |- Lists global or server expressions (20 commands per page). @@ -213,1019 +385,1803 @@ exprlist: • 🗯️ Triggered if trigger matches any word (`{0}h {0}exca`) • ✉️ Response will be DMed (`{0}h {0}exdm`) • ❌ Trigger will be deleted (`{0}h {0}exad`) - args: - - "1" - - "all" + ex: + - 1 + - all + params: + - page: + desc: "The number of pages to display in the list." exprshow: - desc: "Shows an expression's response on a given ID." - args: - - "1" + desc: Shows an expression's response on a given ID. + ex: + - 1 + params: + - id: + desc: "The identifier for the entity whose response is being displayed." exprdelete: - desc: "Deletes an expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression." - args: - - "5" + desc: Deletes an expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression. + ex: + - 5 + params: + - id: + desc: "The identifier of the expression to be deleted." exprdeleteserver: - desc: "Deletes an expression on a specific index on this server." - args: - - "5c" + desc: Deletes an expression on a specific index on this server. + ex: + - 5c + params: + - id: + desc: "The identifier of the expression to be deleted." exprclear: - desc: "Deletes all expression on this server." - args: + desc: Deletes all expression on this server. + ex: - "" + params: + - {} fwclear: - desc: "Deletes all filtered words on this server." - args: + desc: Deletes all filtered words on this server. + ex: - "" + params: + - {} filterlist: - desc: "Lists invite and link filter channels and status." - args: + desc: Lists invite and link filter channels and status. + ex: - "" + params: + - {} aliasesclear: - desc: "Deletes all aliases on this server." - args: + desc: Deletes all aliases on this server. + ex: - "" + params: + - {} autoassignrole: desc: |- Toggles the role which will be assigned to every user who joins the server. You can run this command multiple times to add multiple roles (up to 3). Specifying the role that is already added will remove that role from the list. Provide no parameters to list current roles. - args: + ex: - "" - - "RoleName" + - RoleName + params: + - role: + desc: "The role assigned to new users, determining their permissions and access rights within the server." + - {} leave: - desc: "Makes Ellie leave the server. Either server name or server ID is required." - args: - - "123123123331" + desc: Makes Ellie leave the server. Either server name or server ID is required. + ex: + - 123123123331 + params: + - guildStr: + desc: "The name of the server where Ellie should leave." slowmode: - desc: "Toggles slowmode on the current channel with the specified amount of time. Provide no parameters to disable." - args: + desc: Toggles slowmode on the current channel with the specified amount of time. Provide no parameters to disable. + ex: - "" - - "27s" - - "3h15m5s" + - 27s + - 3h15m5s + params: + - time: + desc: "The duration for which the slowmode should be enabled." delmsgoncmd: desc: "Toggles the automatic deletion of the user's successful command message to prevent chat flood. You can use it either as a server toggle, channel whitelist, or channel blacklist, as channel option has 3 settings: Enable (always do it on this channel), Disable (never do it on this channel), and Inherit (respect server setting). Use `list` parameter to see the current states." - args: + ex: - "" - - "channel enable" - - "ch inherit" - - "list" + - channel enable + - ch inherit + - list + params: + - _: + desc: "The list of channels or servers where the automatic deletion is enabled, disabled, or inherited." + - _: + desc: "The server where the command is being executed or monitored for chat flood prevention." + - _: + desc: "The channel where the automatic deletion of successful command messages should be toggled." + s: + desc: "The state of whether automatic deletion is enabled or disabled for a specific channel." + ch: + desc: "The channel where the automatic deletion of successful command messages should be toggled for." + - _: + desc: "The channel where the automatic deletion of successful command messages should be toggled." + s: + desc: "The state of whether automatic deletion is enabled or disabled for a specific channel." + chId: + desc: "The ID of a channel where the automatic deletion should be toggled or inherited." restart: - desc: "Restarts the bot. Might not work." - args: + desc: Restarts the bot. Might not work. + ex: - "" + params: + - {} setrole: - desc: "Gives a role to a user. The role you specify has to be lower in the role hierarchy than your highest role." - args: + desc: Gives a role to a user. The role you specify has to be lower in the role hierarchy than your highest role. + ex: - "@User Guest" + params: + - targetUser: + desc: "The user being given the new role, which must have a lower rank than the assistant's highest role." + roleToAdd: + desc: "The role that is being added grants specific permissions and access rights to the user." removerole: - desc: "Removes a role from a user. The role you specify has to be lower in the role hierarchy than your highest role." - args: + desc: Removes a role from a user. The role you specify has to be lower in the role hierarchy than your highest role. + ex: - "@User Admin" + params: + - targetUser: + desc: "The user account being modified or checked for role eligibility." + roleToRemove: + desc: "The role being removed from the user's set of assigned roles." renamerole: - desc: "Renames a role. The role you specify has to be lower in the role hierarchy than your highest role." - args: + desc: Renames a role. The role you specify has to be lower in the role hierarchy than your highest role. + ex: - '"First role" SecondRole' + params: + - roleToEdit: + desc: "The role being edited or updated." + newname: + desc: "The name for the new role." removeallroles: - desc: "Removes all roles which are lower than your highest role in the role hierarchy from the user you specify." - args: + desc: Removes all roles which are lower than your highest role in the role hierarchy from the user you specify. + ex: - "@User" + params: + - user: + desc: "The user whose roles will be updated to reflect the new role hierarchy." rolehoist: - desc: "Toggles whether this role is displayed in the sidebar or not. The role you specify has to be lower in the role hierarchy than your highest role." - args: - - "Guests" - - "Space Wizards" + desc: Toggles whether this role is displayed in the sidebar or not. The role you specify has to be lower in the role hierarchy than your highest role. + ex: + - Guests + - Space Wizards + params: + - role: + desc: "The role that determines the visibility of the sidebar." createrole: - desc: "Creates a role with a given name." - args: - - "Awesome Role" + desc: Creates a role with a given name. + ex: + - Awesome Role + params: + - roleName: + desc: "The name of the new role being created." deleterole: - desc: "Deletes a role with a given name." - args: - - "Awesome Role" + desc: Deletes a role with a given name. + ex: + - Awesome Role + params: + - role: + desc: "The role being deleted, as identified by its unique identifier." rolecolor: - desc: "Set a role's color using its hex value. Provide no color in order to see the hex value of the color of the specified role. The role you specify has to be lower in the role hierarchy than your highest role." - args: - - "Admin" - - "ffba55 Admin" + desc: Set a role's color using its hex value. Provide no color in order to see the hex value of the color of the specified role. The role you specify has to be lower in the role hierarchy than your highest role. + ex: + - Admin + - ffba55 Admin + params: + - role: + desc: "The role that will have its color set or retrieved." + - color: + desc: "The color used for the role's text and background." + role: + desc: "The role that will have its color set or retrieved." ban: - desc: "Bans a user by ID or name with an optional message. You can specify a time string before the user name to ban the user temporarily." - args: + desc: Bans a user by ID or name with an optional message. You can specify a time string before the user name to ban the user temporarily. + ex: - "@Someone Get out!" - '"Some Guy#1234" Your behaviour is toxic.' - - "1d12h @Someone Come back when u chill" + - 1d12h @Someone Come back when u chill + params: + - time: + desc: "The duration of the temporary ban." + user: + desc: "The user being banned, either by ID or name, and potentially temporarily." + msg: + desc: "The reason for the ban is provided in this message." + - time: + desc: "The duration of the temporary ban." + userId: + desc: "The unique identifier of the user being banned." + msg: + desc: "The reason for the ban is provided in this message." + - userId: + desc: "The unique identifier of the user being banned." + msg: + desc: "The reason for the ban is provided in this message." + - user: + desc: "The user being banned, either by ID or name, and potentially temporarily." + msg: + desc: "The reason for the ban is provided in this message." softban: - desc: "Bans and then unbans a user by ID or name with an optional message." - args: + desc: Bans and then unbans a user by ID or name with an optional message. + ex: - "@Someone Get out!" - '"Some Guy#1234" Your behaviour is toxic.' + params: + - user: + desc: "The user being banned and then unbanned." + msg: + desc: "The reason for the ban is described in this string." + - userId: + desc: "The unique identifier for the user being banned and then unbanned." + msg: + desc: "The reason for the ban is described in this string." kick: - desc: "Kicks a mentioned user." - args: + desc: Kicks a mentioned user. + ex: - "@Someone Get out!" - '"Some Guy#1234" Your behaviour is toxic.' + params: + - user: + desc: "The user being kicked from the guild." + msg: + desc: "The message to display when kicking the user." + - userId: + desc: "The ID of the user being kicked from the chat." + msg: + desc: "The message to display when kicking the user." timeout: - desc: "Times the user out for the specified amount of time. You may optionally specify a reason, which will be sent to the user." - args: + desc: Times the user out for the specified amount of time. You may optionally specify a reason, which will be sent to the user. + ex: - "@Someone 3h Shut up!" - "@Someone 1h30m" + params: + - globalUser: + desc: "The user's account or identity that is being timed out." + time: + desc: "The duration of the timeout period." + msg: + desc: "The brief message explaining why the user was timed out." mute: - desc: "Mutes a mentioned user both from speaking and chatting. You can also specify time string for how long the user should be muted. You can optionally specify a reason." - args: + desc: Mutes a mentioned user both from speaking and chatting. You can also specify time string for how long the user should be muted. You can optionally specify a reason. + ex: - "@Someone" - "@Someone too noisy" - - "1h30m @Someone" - - "1h30m @Someone too noisy" + - 1h30m @Someone + - 1h30m @Someone too noisy + params: + - target: + desc: "The user to whom the mute action is being applied." + reason: + desc: "The optional reason provided helps to explain why the user was muted." + - time: + desc: "The duration of the mute period." + user: + desc: "The user to whom the mute action is being applied." + reason: + desc: "The optional reason provided helps to explain why the user was muted." voiceunmute: - desc: "Gives a previously voice-muted user a permission to speak." - args: + desc: Gives a previously voice-muted user a permission to speak. + ex: - "@Someguy" + params: + - user: + desc: "The user who was previously muted is now able to participate in the conversation again." + reason: + desc: "The reason for the user's previous mute." deafen: - desc: "Deafens mentioned user or users." - args: + desc: Deafens mentioned user or users. + ex: - '"@Someguy"' - '"@Someguy" "@Someguy"' + params: + - users: + desc: "The list of users to be affected by the deafening action." undeafen: - desc: "Undeafens mentioned user or users." - args: + desc: Undeafens mentioned user or users. + ex: - '"@Someguy"' - '"@Someguy" "@Someguy"' + params: + - users: + desc: "The list of users to undeafen." delvoichanl: - desc: "Deletes a voice channel with a given name." - args: - - "VoiceChannelName" + desc: Deletes a voice channel with a given name. + ex: + - VoiceChannelName + params: + - voiceChannel: + desc: "The voice channel being deleted." creatvoichanl: - desc: "Creates a new voice channel with a given name." - args: - - "VoiceChannelName" + desc: Creates a new voice channel with a given name. + ex: + - VoiceChannelName + params: + - channelName: + desc: "The name of the new voice channel being created." deltxtchanl: - desc: "Deletes a text channel with a given name." - args: - - "TextChannelName" + desc: Deletes a text channel with a given name. + ex: + - TextChannelName + params: + - toDelete: + desc: "The channel to be deleted, specified by its object reference." creatxtchanl: - desc: "Creates a new text channel with a given name." - args: - - "TextChannelName" + desc: Creates a new text channel with a given name. + ex: + - TextChannelName + params: + - channelName: + desc: "The name of the new channel to be created." settopic: - desc: "Sets a topic on the current channel." - args: - - "My new topic" + desc: Sets a topic on the current channel. + ex: + - My new topic + params: + - topic: + desc: "The new topic for discussion on the channel." setchanlname: - desc: "Changes the name of the current channel." - args: - - "NewName" + desc: Changes the name of the current channel. + ex: + - NewName + params: + - name: + desc: "The new name for the channel." prune: desc: "`{0}prune` removes all Ellie's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel." - args: + ex: - "" - - "-s" - - "5" - - "5 --safe" + - -s + - 5 + - 5 --safe - "@Someone" - "@Someone --safe" - "@Someone X" - "@Someone X -s" -die: - desc: "Shuts the bot down." - args: + params: + - params: + desc: "The list of users, channels or message counts to be removed from the conversation history." + - count: + desc: "The number of messages to remove from the channel or user's messages." + params: + desc: "The list of users, channels or message counts to be removed from the conversation history." + - user: + desc: "The user whose messages are to be removed from the channel." + count: + desc: "The number of messages to remove from the channel or user's messages." + params: + desc: "The list of users, channels or message counts to be removed from the conversation history." + - userId: + desc: "The ID of a user to filter messages by." + count: + desc: "The number of messages to remove from the channel or user's messages." + params: + desc: "The list of users, channels or message counts to be removed from the conversation history." +prunecancel: + desc: Cancels an active prune if there is any. + ex: - "" + params: + - {} +die: + desc: Shuts the bot down. + ex: + - "" + params: + - graceful: + desc: "The option to perform a controlled shutdown, allowing for any necessary cleanup or notifications before termination." setname: - desc: "Gives the bot a new name." - args: - - "BotName" + desc: Gives the bot a new name. + ex: + - BotName + params: + - newName: + desc: "The new name given to the bot." setnick: - desc: "Changes the nickname of the bot on this server. You can also target other users to change their nickname." - args: - - "BotNickname" + desc: Changes the nickname of the bot on this server. You can also target other users to change their nickname. + ex: + - BotNickname - "@SomeUser New Nickname" + params: + - newNick: + desc: "The new nickname to be displayed for the bot or targeted user." + - gu: + desc: "The guild user that is being targeted for a nickname change." + newNick: + desc: "The new nickname to be displayed for the bot or targeted user." setavatar: - desc: "Sets a new avatar image for the EllieBot. Parameter is a direct link to an image." - args: - - "https://i.imgur.com/xTG3a1I.jpg" + desc: Sets a new avatar image for the EllieBot. Parameter is a direct link to an image. + ex: + - https://i.imgur.com/xTG3a1I.jpg + params: + - img: + desc: "The URL of the image file to be displayed as the bot's avatar." +setbanner: + desc: Sets a new banner image for the EllieBot. Parameter is a direct link to an image. Supports gifs. + ex: + - https://i.imgur.com/xTG3a1I.jpg + params: + - img: + desc: "The URL of the image file to be displayed as the bot's banner." setgame: - desc: "Sets the bots game status to either Playing, Listening, or Watching." - args: - - "Playing with snakes." - - "Watching anime." - - "Listening music." + desc: Sets the bots game status to either Playing, Listening, or Watching. + ex: + - Playing with snakes. + - Watching anime. + - Listening music. + params: + - type: + desc: "The activity type determines whether the bot is engaged in a game, listening to audio, or watching a video." + game: + desc: "The current state of the bot's activity in the game." send: - desc: "Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`." - args: - - "serverid|c:channelid message" - - "serverid|u:userid message" + desc: "Sends a message to a channel or user. Channel or user can be " + ex: + - channel 123123123132312 Stop spamming commands plz + - user 1231231232132 I can see in the console what you're doing. + params: + - to: + desc: "The destination where the message will be sent, such as a specific channel or individual user." + id: + desc: "The identifier of the recipient, either a channel or a user." + text: + desc: "The recipient's preferred format for the message, such as plain text or formatted text with images and links." savechat: - desc: "Saves a number of messages to a text file and sends it to you." - args: - - "150" + desc: Saves a number of messages to a text file and sends it to you. + ex: + - 150 + params: + - cnt: + desc: "The number of messages to be saved." remind: desc: "Sends a message to you or a channel after certain amount of time (max 2 months). First parameter is `me`/`here`/'channelname'. Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third parameter is a (multiword) message. Requires ManageMessages server permission if you're targeting a different channel." - args: - - "me 1d5h Do something" + ex: + - me 1d5h Do something - "#general 1m Start now!" + params: + - meorhere: + desc: "The enum value of 'me' if the user wants to be reminded, or 'here' if the user wants to be reminded in the current channel." + remindString: + desc: "The reminder duration and message to be sent. The message must start with a short time string in the form of 5d1h30m for example." + - channel: + desc: "The name of the channel to send the reminder to, or 'here' for the current channel." + remindString: + desc: "The reminder message to be sent." reminddelete: desc: "Deletes a reminder on the specified index. You can specify 'server' option if you're an Administrator, and you want to delete a reminder on this server created by someone else. " - args: - - "3" - - "server 2" + ex: + - 3 + - server 2 + params: + - _: + desc: "The server where the reminder was created or is stored." + index: + desc: "The index of the reminder to be deleted." + - index: + desc: "The index of the reminder to be deleted." remindlist: - desc: "Lists all reminders you created. You can specify 'server' option if you're an Administrator to list all reminders created on this server. Paginated." - args: - - "1" - - "server 2" + desc: Lists all reminders you created. You can specify 'server' option if you're an Administrator to list all reminders created on this server. Paginated. + ex: + - 1 + - server 2 + params: + - _: + desc: "The server where the reminders are stored or being retrieved from." + page: + desc: "The number of the page to display in the result set." + - page: + desc: "The number of the page to display in the result set." serverinfo: - desc: "Shows info about the server the bot is on. If no server is supplied, it defaults to current one." - args: - - "Some Server" + desc: Shows info about the server with the specified ID. The bot has to be on that server. If no server is supplied, it defaults to current one. + ex: + - 123123132233 + params: + - guildId: + desc: "The ID of a server for which to retrieve information." + - {} channelinfo: - desc: "Shows info about the channel. If no channel is supplied, it defaults to current one." - args: + desc: Shows info about the channel. If no channel is supplied, it defaults to current one. + ex: - "#some-channel" + params: + - channel: + desc: "The channel where the information will be retrieved from or displayed in." roleinfo: - desc: "Shows info about the specified role." - args: - - "Gamers" + desc: Shows info about the specified role. + ex: + - Gamers + params: + - role: + desc: "The type of user account associated with the role." userinfo: - desc: "Shows info about the user. If no user is supplied, it defaults a user running the command." - args: + desc: Shows info about the user. If no user is supplied, it defaults a user running the command. + ex: - "@SomeUser" + params: + - usr: + desc: "The guild user that the information is being retrieved for." whosplaying: - desc: "Shows a list of users who are playing the specified game." - args: - - "Overwatch" + desc: Shows a list of users who are playing the specified game. + ex: + - Overwatch + params: + - game: + desc: "The name of the game being played by the users." inrole: - desc: "Lists every person from the specified role on this server. You can specify a page before the role to jump to that page. Provide no role to list users who have no roles" - args: - - "RoleName" - - "5 RoleName" + desc: Lists every person from the specified role on this server. You can specify a page before the role to jump to that page. Provide no role to list users who have no roles + ex: + - RoleName + - 5 RoleName - "" + params: + - page: + desc: "The starting page number for the result set." + role: + desc: "The type of user or group being targeted for listing." + - role: + desc: "The type of user or group being targeted for listing." checkperms: - desc: "Checks yours or bot's user-specific permissions on this channel." - args: - - "me" - - "bot" + desc: Checks yours or bot's user-specific permissions on this channel. + ex: + - me + - bot + params: + - who: + desc: "The identity of the entity whose permissions are being checked." stats: - desc: "Shows some basic stats for Ellie." - args: + desc: Shows some basic stats for Ellie. + ex: - "" + params: + - {} userid: - desc: "Shows user ID." - args: + desc: Shows user ID. + ex: - "" - "@Someone" + params: + - target: + desc: "The guild the user is a member of." channelid: - desc: "Shows current channel ID." - args: + desc: Shows current channel ID. + ex: - "" + params: + - {} serverid: - desc: "Shows current server ID." - args: + desc: Shows current server ID. + ex: - "" + params: + - {} roles: - desc: "List roles on this server or roles of a user if specified. Paginated, 20 roles per page." - args: - - "2" + desc: List roles on this server or roles of a user if specified. Paginated, 20 roles per page. + ex: + - 2 - "@Someone" + params: + - target: + desc: "The guild or user for which to list the roles." + page: + desc: "The page number for the list of roles to be displayed." + - page: + desc: "The page number for the list of roles to be displayed." channeltopic: - desc: "Sends current channel's topic as a message." - args: + desc: Sends current channel's topic as a message. + ex: - "" + params: + - channel: + desc: "The channel where the topic is retrieved from." chnlfilterinv: - desc: "Toggles automatic deletion of invites posted in the channel. Does not negate the `{0}srvrfilterinv` enabled setting. Does not affect users with the Administrator permission." - args: + desc: Toggles automatic deletion of invites posted in the channel. Does not negate the `{0}srvrfilterinv` enabled setting. Does not affect users with the Administrator permission. + ex: - "" + params: + - {} srvrfilterinv: - desc: "Toggles automatic deletion of invites posted in the server. Does not affect users with the Administrator permission." - args: + desc: Toggles automatic deletion of invites posted in the server. Does not affect users with the Administrator permission. + ex: - "" + params: + - {} chnlfilterlin: - desc: "Toggles automatic deletion of links posted in the channel. Does not negate the `{0}srvrfilterlin` enabled setting. Does not affect users with the Administrator permission." - args: + desc: Toggles automatic deletion of links posted in the channel. Does not negate the `{0}srvrfilterlin` enabled setting. Does not affect users with the Administrator permission. + ex: - "" + params: + - {} srvrfilterlin: - desc: "Toggles automatic deletion of links posted in the server. Does not affect users with the Administrator permission." - args: + desc: Toggles automatic deletion of links posted in the server. Does not affect users with the Administrator permission. + ex: - "" + params: + - {} chnlfilterwords: - desc: "Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `{0}srvrfilterwords` enabled setting. Does not affect users with the Administrator permission." - args: + desc: Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `{0}srvrfilterwords` enabled setting. Does not affect users with the Administrator permission. + ex: - "" + params: + - {} filterword: - desc: "Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering." - args: - - "poop" + desc: Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering. + ex: + - poop + params: + - word: + desc: "The word to be added or removed from the list of filtered words." srvrfilterwords: - desc: "Toggles automatic deletion of messages containing filtered words on the server. Does not affect users with the Administrator permission." - args: + desc: Toggles automatic deletion of messages containing filtered words on the server. Does not affect users with the Administrator permission. + ex: - "" + params: + - {} lstfilterwords: - desc: "Shows a list of filtered words." - args: + desc: Shows a list of filtered words. + ex: - "" + params: + - page: + desc: "The current page number in the list of filtered words." permrole: - desc: "Sets a role which can change permissions. Supply no parameters to see the current one. Type 'reset' instead of the role name to reset the currently set permission role. Users with the Administrator server permissions can use permission commands regardless of whether they have the specified role. There is no default permission role." - args: - - "Some Role" - - "reset" + desc: Sets a role which can change permissions. Supply no parameters to see the current one. Type 'reset' instead of the role name to reset the currently set permission role. Users with the Administrator server permissions can use permission commands regardless of whether they have the specified role. There is no default permission role. + ex: + - Some Role + - reset + params: + - role: + desc: "The role that a user must have to change permissions." + - _: + desc: "The role that users must have to execute certain permission commands." verbose: - desc: "Toggles or sets whether to show when a command/module is blocked." - args: + desc: Toggles or sets whether to show when a command/module is blocked. + ex: - "" - - "true" + - true + params: + - action: + desc: "The permission required for the action to proceed." srvrmdl: - desc: "Sets a module's permission at the server level." - args: - - "ModuleName enable" + desc: Sets a module's permission at the server level. + ex: + - ModuleName enable + params: + - module: + desc: "The type of module or content repository information being set for server-level permissions." + action: + desc: "The type of permission action to perform, such as granting or revoking access." srvrcmd: - desc: "Sets a command's permission at the server level." - args: + desc: Sets a command's permission at the server level. + ex: - '"command name" disable' + params: + - command: + desc: "The type of command or expression being set, such as a specific SQL query or system function." + action: + desc: "The type of action to take on the permission, such as granting or revoking access." rolemdl: - desc: "Sets a module's permission at the role level." - args: - - "ModuleName enable MyRole" + desc: Sets a module's permission at the role level. + ex: + - ModuleName enable MyRole + params: + - module: + desc: "The type of content or resource being managed by the module." + action: + desc: "The type of action that can be performed by users with this role." + role: + desc: "The role that determines the permissions for the module." rolecmd: - desc: "Sets a command's permission at the role level." - args: + desc: Sets a command's permission at the role level. + ex: - '"command name" disable MyRole' + params: + - command: + desc: "The command or expression that is being set as a permission for a specific role." + action: + desc: "The type of action to take on the permission, such as granting or denying access." + role: + desc: "The role that determines who can use this command." chnlmdl: - desc: "Sets a module's permission at the channel level." - args: - - "ModuleName enable SomeChannel" + desc: Sets a module's permission at the channel level. + ex: + - ModuleName enable SomeChannel + params: + - module: + desc: "The type of entity being set as a permission for the channel." + action: + desc: "The type of permission action to take on the channel." + chnl: + desc: "The channel where the permission is being set for the module." chnlcmd: - desc: "Sets a command's permission at the channel level." - args: + desc: Sets a command's permission at the channel level. + ex: - '"command name" enable SomeChannel' + params: + - command: + desc: "The type of command or expression being set for the channel's permissions." + action: + desc: "The type of permission action to take on the channel." + chnl: + desc: "The channel where the command's permission is being set." usrmdl: - desc: "Sets a module's permission at the user level." - args: - - "ModuleName enable SomeUsername" + desc: Sets a module's permission at the user level. + ex: + - ModuleName enable SomeUsername + params: + - module: + desc: "The type of module or content reference information being set for the user's permissions." + action: + desc: "The type of permission action to take on the module, such as granting or revoking access." + user: + desc: "The user who owns the guild and is being granted or denied access to the module's features." usrcmd: - desc: "Sets a command's permission at the user level." - args: + desc: Sets a command's permission at the user level. + ex: - '"command name" enable SomeUsername' + params: + - command: + desc: "The type of command or expression being set for the specified user." + action: + desc: "The type of action to take on the permission, such as granting or revoking access." + user: + desc: "The user who owns the guild or has the specified role can execute the command." allsrvrmdls: - desc: "Enable or disable all modules for your server." - args: + desc: Enable or disable all modules for your server. + ex: - "[enable/disable]" + params: + - action: + desc: "The type of action to take on the enabled/disabled modules, such as enable or disable." allchnlmdls: - desc: "Enable or disable all modules in a specified channel." - args: + desc: Enable or disable all modules in a specified channel. + ex: - "enable #SomeChannel" + params: + - action: + desc: "The type of permission action to apply to the module, such as granting or revoking access." + chnl: + desc: "The channel where the operation is being performed on the modules." allrolemdls: - desc: "Enable or disable all modules for a specific role." - args: + desc: Enable or disable all modules for a specific role. + ex: - "[enable/disable] MyRole" + params: + - action: + desc: "The type of permission action to perform, such as granting or revoking access." + role: + desc: "The role that the operation is being performed on." userblacklist: desc: |- Either [add]s or [rem]oves a user or users specified by a Mention or an ID from a blacklist. Specify no argument or a page number to list blacklisted users. - args: - - "add @SomeUser @SomeUser2 @SomeUser3" - - "rem 12312312313" + ex: + - add @SomeUser @SomeUser2 @SomeUser3 + - rem 12312312313 - "" - - "4" + - 4 + params: + - page: + desc: "The page number for pagination of the listed blacklisted users." + - action: + desc: "The type of operation to perform on the user, either adding or removing them from the blacklist." + id: + desc: "The unique identifier of the user to be added, removed, or listed." + - action: + desc: "The type of operation to perform on the user, either adding or removing them from the blacklist." + usr: + desc: "The ID of the user to be added, removed, or listed." channelblacklist: desc: |- Either [add]s or [rem]oves a channel or channels specified an ID from a blacklist. Specify no argument or a page number to list blacklisted channels. - args: - - "add 12312312312 66666666666" - - "rem 12312312312" + ex: + - add 12312312312 66666666666 + - rem 12312312312 - "" - - "3" + - 3 + params: + - page: + desc: "The page number for pagination of the blacklisted channels list." + - action: + desc: "The type of operation to perform on the channel, either adding it to the blacklist or removing it from it." + id: + desc: "The unique identifier of the channel being added, removed, or listed." serverblacklist: desc: |- Either [add]s or [rem]oves a server, or servers specified by an ID from a blacklist. Specify no argument or a page number to list blacklisted servers. - args: - - "add 12312321312" - - "rem 12312321312" + ex: + - add 12312321312 + - rem 12312321312 - "" - - "2" + - 2 + params: + - page: + desc: "The page number for pagination of the blacklist listing." + - action: + desc: "The type of operation to perform on the server(s). It can be either adding or removing them from the blacklist." + id: + desc: "The unique identifier of the server being added, removed, or listed." + - action: + desc: "The type of operation to perform on the server(s). It can be either adding or removing them from the blacklist." + guild: + desc: "The guild for which the server blacklist is being managed." cmdcooldown: - desc: - "Sets a cooldown, in seconds, for a command or an expression which will be applied per user. - Set it to 0 to remove the cooldown. - Supports a special command `cleverbot:response` which can be used limit how often users can talk to cleverbot" - args: - - ".h 5" - - ".pat 30" + desc: Sets a cooldown, in seconds, for a command or an expression which will be applied per user. Set it to 0 to remove the cooldown. Supports a special command `cleverbot:response` which can be used limit how often users can talk to cleverbot + ex: + - .h 5 + - .pat 30 + params: + - command: + desc: "The response string from CleverBot, used to generate a conversation with the user." + secs: + desc: "The time, in seconds, after which the user is allowed to use the command again." + - command: + desc: "The command or expression that is being cooled down, allowing for control over when it can be executed again." + secs: + desc: "The time, in seconds, after which the user is allowed to use the command again." allcmdcooldowns: - desc: "Shows a list of all commands and their respective cooldowns." - args: + desc: Shows a list of all commands and their respective cooldowns. + ex: - "" + params: + - page: + desc: "The number of the page to display in the list of command cooldowns." quoteadd: - desc: "Adds a new quote with the specified name and message." - args: - - "sayhi Hi" + desc: Adds a new quote with the specified name and message. + ex: + - sayhi Hi + params: + - keyword: + desc: "The name of the quote used to retrieve the quote." + text: + desc: "The message of the quote." quoteprint: - desc: "Prints a random quote with a specified name." - args: - - "abc" + desc: Prints a random quote with a specified name. + ex: + - abc + params: + - keyword: + desc: "The author or origin of the quote being printed." quoteshow: - desc: "Shows information about a quote with the specified ID." - args: - - "123" + desc: Shows information about a quote with the specified ID. + ex: + - 123 + params: + - id: + desc: "The unique identifier for the quote being queried." quotesearch: desc: "Shows a random quote given a search query. Partially matches in several ways: 1) Only content of any quote, 2) only by author, 3) keyword and content, 3) or keyword and author" - args: + ex: - '"find this long text"' - - "AuthorName" - - "keyword some text" - - "keyword AuthorName" + - AuthorName + - keyword some text + - keyword AuthorName + params: + - textOrAuthor: + desc: "The search term to find a matching quote." + - keyword: + desc: "The search term to look for in the quote's content." + textOrAuthor: + desc: "The search term to find a matching quote." quoteid: - desc: "Displays the quote with the specified ID number. Quote ID numbers can be found by typing `{0}liqu [num]` where `[num]` is a number of a page which contains 15 quotes." - args: - - "123456" + desc: Displays the quote with the specified ID number. Quote ID numbers can be found by typing `{0}liqu [num]` where `[num]` is a number of a page which contains 15 quotes. + ex: + - 123456 + params: + - id: + desc: "The unique identifier for the quote to be displayed." quotedelete: - desc: "Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it." - args: - - "123456" + desc: Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it. + ex: + - 123456 + params: + - id: + desc: "The unique identifier for the quote being deleted." quotedeleteauthor: - desc: "Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required." - args: + desc: Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required. + ex: - "@QuoteSpammer" + params: + - user: + desc: "The user whose quotes are to be deleted." + - userId: + desc: "The ID of the user whose quotes are to be deleted." draw: - desc: "Draws a card from this server's deck. You can draw up to 10 cards by supplying a number of cards to draw." - args: + desc: Draws a card from this server's deck. You can draw up to 10 cards by supplying a number of cards to draw. + ex: - "" - - "5" + - 5 + params: + - num: + desc: "The number of cards to be drawn from the deck." drawnew: - desc: "Draws a card from the NEW deck of cards. You can draw up to 10 cards by supplying a number of cards to draw." - args: + desc: Draws a card from the NEW deck of cards. You can draw up to 10 cards by supplying a number of cards to draw. + ex: - "" - - "5" + - 5 + params: + - num: + desc: "The number of cards to be drawn from the new deck." playlistshuffle: - desc: "Shuffles the current playlist." - args: + desc: Shuffles the current playlist. + ex: - "" + params: + - {} flip: - desc: "Flips coin(s) - heads or tails, and shows an image." - args: + desc: Flips coin(s) - heads or tails, and shows an image. + ex: - "" - - "3" + - 3 + params: + - count: + desc: "The number of times the coin is flipped." betflip: - desc: "Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner." - args: - - "5 heads" - - "3 t" + desc: Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. + ex: + - 5 heads + - 3 t + params: + - amount: + desc: "The amount of money to be wagered on the bet." + guess: + desc: "The user's prediction about whether the next coin flip will result in heads or tails." roll: - desc: "Rolls 0-100. If you supply a number `X` it rolls up to 30 normal dice. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. `Y` can be a letter 'F' if you want to roll fate dice instead of dnd." - args: + desc: Rolls 0-100. If you supply a number `X` it rolls up to 30 normal dice. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. `Y` can be a letter 'F' if you want to roll fate dice instead of dnd. + ex: - "" - - "7" - - "3d5" - - "5dF" + - 7 + - 3d5 + - 5dF + params: + - {} + - num: + desc: "The number of sides on the dice being rolled." + - arg: + desc: "The input string specifies the type of dice roll or the number of dice to roll, allowing users to customize their random outcome." rolluo: - desc: "Rolls `X` normal dice (up to 30) unordered. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`." - args: + desc: Rolls `X` normal dice (up to 30) unordered. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. + ex: - "" - - "7" - - "3d5" + - 7 + - 3d5 + params: + - num: + desc: "The number of sides on the dice being rolled." + - arg: + desc: "The number of sides on the dice to be rolled." nroll: - desc: "Rolls in a given range. If you specify just one number instead of the range, it will roll from 0 to that number." - args: - - "5" - - "5-15" + desc: Rolls in a given range. If you specify just one number instead of the range, it will roll from 0 to that number. + ex: + - 5 + - 5-15 + params: + - range: + desc: "The minimum and maximum values for the random number generation process." race: - desc: "Starts a new animal race." - args: + desc: Starts a new animal race. + ex: - "" + params: + - params: + desc: "The list of commands or actions for the animals in the race." joinrace: - desc: "Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win." - args: + desc: Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. + ex: - "" - - "5" + - 5 + params: + - amount: + desc: "The amount to be wagered on the race." nunchi: - desc: "Creates or joins an existing nunchi game. Users have to count up by 1 from the starting number shown by the bot. If someone makes a mistake (types an incorrect number, or repeats the same number) they are out of the game and a new round starts without them. Minimum 3 users required." - args: + desc: Creates or joins an existing nunchi game. Users have to count up by 1 from the starting number shown by the bot. If someone makes a mistake (types an incorrect number, or repeats the same number) they are out of the game and a new round starts without them. Minimum 3 users required. + ex: - "" + params: + - {} connect4: - desc: "Creates or joins an existing connect4 game. 2 players are required for the game. Objective of the game is to get 4 of your pieces next to each other in a vertical, horizontal or diagonal line. You can specify a bet when you create a game and only users who bet the same amount will be able to join your game." - args: + desc: Creates or joins an existing connect4 game. 2 players are required for the game. Objective of the game is to get 4 of your pieces next to each other in a vertical, horizontal or diagonal line. You can specify a bet when you create a game and only users who bet the same amount will be able to join your game. + ex: - "" + params: + - params: + desc: "The list of command-line arguments passed by the user to customize the game setup or behavior." raffle: - desc: "Prints a name and ID of a random online user from the server, or from the online user in the specified role." - args: + desc: Prints a name and ID of a random online user from the server, or from the online user in the specified role. + ex: - "" - - "RoleName" + - RoleName + params: + - role: + desc: "The role of the online user to be selected from." raffleany: - desc: "Prints a name and ID of a random user from the server, or from the specified role." - args: + desc: Prints a name and ID of a random user from the server, or from the specified role. + ex: - "" - " RoleName" + params: + - role: + desc: "The role that determines which users are eligible for selection." give: - desc: "Give someone a certain amount of currency. You can specify the reason after the mention." - args: - - "1 @Someone" - - "5 @CootGurl Ur so pwetty" + desc: Give someone a certain amount of currency. You can specify the reason after the mention. + ex: + - 1 @Someone + - 5 @CootGurl Ur so pwetty + params: + - amount: + desc: "The total value of the gift being bestowed." + receiver: + desc: "The user receiving the currency, such as a gift or reward." + msg: + desc: "The message explaining why you're giving them the currency." + - amount: + desc: "The total value of the gift being bestowed." + receiver: + desc: "The user receiving the currency, such as a gift or reward." award: - desc: "Awards someone a certain amount of currency. You can specify the reason after the Username. You can also specify a role name to award currency to all users in a role." - args: - - "100 @person" - - "5 Role Of Gamblers" + desc: Awards someone a certain amount of currency. You can specify the reason after the Username. You can also specify a role name to award currency to all users in a role. + ex: + - 100 @person + - 5 Role Of Gamblers + params: + - amount: + desc: "The amount of currency being awarded." + usr: + desc: "The user or guild member being awarded the currency." + msg: + desc: "The message describing why the user is being awarded the currency." + - amount: + desc: "The amount of currency being awarded." + usr: + desc: "The user or guild member being awarded the currency." + - amount: + desc: "The amount of currency being awarded." + usrId: + desc: "The ID of the user to whom the currency is being awarded." + msg: + desc: "The message describing why the user is being awarded the currency." + - amount: + desc: "The amount of currency being awarded." + role: + desc: "The role for which to award currency to all members." take: - desc: "Takes the specified amount of currency from someone. You can specify a role instead to take the specified amount of currency from all users in the role." - args: - - "1 @Someone" - - "50 SomeRole" + desc: Takes the specified amount of currency from someone. You can specify a role instead to take the specified amount of currency from all users in the role. + ex: + - 1 @Someone + - 50 SomeRole + params: + - amount: + desc: "The total value of the funds being withdrawn." + role: + desc: "The role of the person or group from whom the currency is being taken." + - amount: + desc: "The total value of the funds being withdrawn." + user: + desc: "The user or guild member being affected by the currency removal." + - amount: + desc: "The total value of the funds being withdrawn." + usrId: + desc: "The ID of the user whose funds are being taken." betroll: - desc: "Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10." - args: - - "5" + desc: Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + ex: + - 5 + params: + - amount: + desc: "The amount to be wagered on the roll of the dice." luckyladder: - desc: "Bets a certain amount of currency on the lucky ladder. You can stop on one of many different multipliers. Won amount is rounded down to the nearest whole number." - args: - - "10" + desc: Bets a certain amount of currency on the lucky ladder. You can stop on one of many different multipliers. Won amount is rounded down to the nearest whole number. + ex: + - 10 + params: + - amount: + desc: "The total value of the bet being placed." leaderboard: - desc: "Displays the bot's currency leaderboard." - args: + desc: Displays the bot's currency leaderboard. + ex: - "" + params: + - params: + desc: "The list of player names or IDs to display in the leaderboard." + - page: + desc: "The number of pages to display in the leaderboard." + params: + desc: "The list of player names or IDs to display in the leaderboard." trivia: - desc: "Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question." - args: + desc: Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. + ex: - "" - - "--timeout 5 -p -w 3 -q 10" + - --timeout 5 -p -w 3 -q 10 + params: + - params: + desc: "The list of questions and answers for the trivia game." tl: - desc: "Shows a current trivia leaderboard." - args: + desc: Shows a current trivia leaderboard. + ex: - "" + params: + - {} tq: - desc: "Quits current trivia after current question." - args: + desc: Quits current trivia after current question. + ex: - "" + params: + - {} typestart: - desc: "Starts a typing contest." - args: + desc: Starts a typing contest. + ex: - "" + params: + - params: + desc: "The list of words or phrases for the contestants to type." typestop: - desc: "Stops a typing contest on the current channel." - args: + desc: Stops a typing contest on the current channel. + ex: - "" + params: + - {} typeadd: - desc: "Adds a new article to the typing contest." - args: - - "wordswords" -pollend: - desc: "Stops active poll on this server and prints the results in this channel." - args: - - "" + desc: Adds a new article to the typing contest. + ex: + - wordswords + params: + - text: + desc: "The title or name of the article being added." pick: - desc: "Picks the currency planted in this channel. If the plant has a password, you need to specify it." - args: + desc: Picks the currency planted in this channel. If the plant has a password, you need to specify it. + ex: - "" - - "passwd" + - passwd + params: + - pass: + desc: "The password required for accessing the plant's contents." plant: - desc: "Spend an amount of currency to plant it in this channel. Default is 1. You can specify the password after the amount. Password has to be alphanumeric and it will be trimmed down to 10 characters if it's longer." - args: - - "5" - - "10 meow" + desc: Spend an amount of currency to plant it in this channel. Default is 1. You can specify the password after the amount. Password has to be alphanumeric and it will be trimmed down to 10 characters if it's longer. + ex: + - 5 + - 10 meow + params: + - amount: + desc: "The number of units or quantity of something being planted." + pass: + desc: "The password for secure planting of the item in this channel." gencurrency: - desc: "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%)" - args: + desc: 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%) + ex: - "" + params: + - {} gencurlist: - desc: "Shows the list of server and channel ids where gc is enabled. Paginated with 9 per page." - args: + desc: Shows the list of server and channel ids where gc is enabled. Paginated with 9 per page. + ex: - "" + params: + - page: + desc: "The current page number for pagination." choose: - desc: "Chooses a thing from a list of things" - args: - - "Get up;Sleep;Sleep more" + desc: Chooses a thing from a list of things + ex: + - Get up;Sleep;Sleep more + params: + - list: + desc: "The type of items in the collection being searched." rps: - desc: "Play a game of Rocket-Paperclip-Scissors with Ellie. You can bet on it. Multiplier is the same as on betflip." - args: - - "r 100" - - "scissors" -linux: - desc: "Prints a customizable Linux interjection" - args: - - "Spyware Windows" + desc: Play a game of Rocket-Paperclip-Scissors with Ellie. You can bet on it. Multiplier is the same as on betflip. + ex: + - r 100 + - scissors + params: + - pick: + desc: "The user's chosen move in the game, such as rock, paper or scissors." + amount: + desc: "The stake to be wagered on the outcome of the game." next: - desc: "Goes to the next song in the queue. You have to be in the same voice channel as the bot" - args: + desc: Goes to the next song in the queue. You have to be in the same voice channel as the bot + ex: - "" + params: + - {} play: - desc: "If no parameters are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command" - args: + desc: If no parameters are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command + ex: - "" - - "5" - - "Dream Of Venice" + - 5 + - Dream Of Venice + params: + - {} + - index: + desc: "The index of the desired song or search result to navigate to." + - query: + desc: "The search query is used to find and play songs matching the specified criteria." stop: - desc: "Stops the music and preserves the current song index. Stays in the channel." - args: + desc: Stops the music and preserves the current song index. Stays in the channel. + ex: - "" + params: + - {} destroy: - desc: "Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour)" - args: + desc: Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) + ex: - "" + params: + - {} pause: - desc: "Pauses or Unpauses the song." - args: + desc: Pauses or Unpauses the song. + ex: - "" + params: + - {} queue: - desc: "Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**." - args: - - "Dream Of Venice" + desc: Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. + ex: + - Dream Of Venice + params: + - query: + desc: "The search term used to identify the song to be queued." queuenext: - desc: "Works the same as `{0}queue` command, except it enqueues the new song after the current one. **You must be in a voice channel**." - args: - - "Dream Of Venice" + desc: Works the same as `{0}queue` command, except it enqueues the new song after the current one. **You must be in a voice channel**. + ex: + - Dream Of Venice + params: + - query: + desc: "The title or name of the next song to be played." queuesearch: - desc: "Search for top 5 youtube song result using keywords, and type the index of the song to play that song. Bot will join your voice channel. **You must be in a voice channel**." - args: - - "Dream Of Venice" -soundcloudqueue: - desc: "Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**." - args: - - "Dream Of Venice" + desc: Search for top 5 youtube song result using keywords, and type the index of the song to play that song. Bot will join your voice channel. **You must be in a voice channel**. + ex: + - Dream Of Venice + params: + - query: + desc: "The search query used to find relevant YouTube songs." listqueue: - desc: "Lists 10 currently queued songs per page. Default page is 1." - args: + desc: Lists 10 currently queued songs per page. Default page is 1. + ex: - "" - - "2" + - 2 + params: + - {} + - page: + desc: "The current page number for the song queue listing." nowplaying: - desc: "Shows the song that the bot is currently playing." - args: + desc: Shows the song that the bot is currently playing. + ex: - "" + params: + - {} volume: - desc: "Sets the music playback volume (0-100%). Persistent server setting. Default 100" - args: - - "50" + desc: Sets the music playback volume (0-100%). Persistent server setting. Default 100 + ex: + - 50 + params: + - vol: + desc: "The level at which the music is played back." playlist: - desc: "Queues up to 500 songs from a youtube playlist specified by a link, or keywords." - args: - - "" -soundcloudpl: - desc: "Queue a Soundcloud playlist using a link." - args: - - "https://soundcloud.com/classical-music-playlist/sets/classical-music-essential-collection" - - "" + desc: Queues up to 500 songs from a youtube playlist specified by a link, or keywords. + ex: + - + params: + - playlistQuery: + desc: "The search query used to find the YouTube playlist." localplaylist: - desc: "Queues all songs from a directory." - args: - - "C:/music/classical" + desc: Queues all songs from a directory. + ex: + - C:/music/classical + params: + - dirPath: + desc: "The path to the directory containing the songs to be queued." radio: desc: "Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: )" - args: - - "radio link here" + ex: + - radio link here + params: + - radioLink: + desc: "The URL of the radio station to be played." local: - desc: "Queues a local file by specifying a full path." - args: - - "C:/music/mysong.mp3" + desc: Queues a local file by specifying a full path. + ex: + - C:/music/mysong.mp3 + params: + - path: + desc: "The directory or location where the file is stored." join: - desc: "Makes the bot join your voice channel." - args: + desc: Makes the bot join your voice channel. + ex: - "" + params: + - {} trackremove: desc: "Remove a song by its # in the queue, or 'all' (or provide no parameter) to remove all songs from the queue." - args: - - "5" - - "all" + ex: + - 5 + - all - "" + params: + - index: + desc: "The position of the song to be removed from the playlist." + - _: + desc: "The number of items to be removed from the list." trackmove: - desc: "Moves a song from one position to another." - args: - - "5 3" -setmaxqueue: - desc: "Sets a maximum queue size. Specify no parameters to have no limit." - args: - - "50" - - "" + desc: Moves a song from one position to another. + ex: + - 5 3 + params: + - from: + desc: "The starting position of the song in the playlist." + to: + desc: "The destination index in the playlist where the song should be moved." queuerepeat: - desc: "Sets music player repeat strategy for this server.\n- `n` / `no` - player will stop once it reaches the end of the queue\n- `s` / `song` - player will repeat current song\n- `q` / `queue` or empty - player will repeat entire music queue" - args: + desc: |- + Sets music player repeat strategy for this server. + - `n` / `no` - player will stop once it reaches the end of the queue + - `s` / `song` - player will repeat current song + - `q` / `queue` or empty - player will repeat entire music queue + ex: - "" - - "n" - - "song" + - n + - song + params: + - type: + desc: "The type of repeat strategy to be set." save: - desc: "Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes." - args: - - "classical1" + desc: Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. + ex: + - classical1 + params: + - name: + desc: "The name provided is used to uniquely identify the saved playlist." streamrole: - desc: "Sets a role which is monitored for streamers (FromRole), and a role to add if a user from 'FromRole' is streaming (AddRole). When a user from 'FromRole' starts streaming, they will receive an 'AddRole'. You can only have 1 Stream Role per server. Provide no parameters to disable" - args: + desc: Sets a role which is monitored for streamers (FromRole), and a role to add if a user from 'FromRole' is streaming (AddRole). When a user from 'FromRole' starts streaming, they will receive an 'AddRole'. You can only have 1 Stream Role per server. Provide no parameters to disable + ex: - '"Eligible Streamers" "Featured Streams"' + params: + - fromRole: + desc: "The role of users being monitored for streamer status." + addRole: + desc: "The role to be added to users when they start streaming." + - {} load: - desc: "Loads a saved playlist using its ID. Use `{0}pls` to list all saved playlists and `{0}save` to save new ones." - args: - - "5" + desc: Loads a saved playlist using its ID. Use `{0}pls` to list all saved playlists and `{0}save` to save new ones. + ex: + - 5 + params: + - id: + desc: "The unique identifier of the playlist to be loaded." playlists: - desc: "Lists all playlists. Paginated, 20 per page." - args: - - "1" + desc: Lists all playlists. Paginated, 20 per page. + ex: + - 1 + params: + - num: + desc: "The number of pages to retrieve." playlistshow: - desc: "Lists all songs in a playlist specified by its id. Paginated, 20 per page." - args: - - "1" + desc: Lists all songs in a playlist specified by its id. Paginated, 20 per page. + ex: + - 1 + params: + - id: + desc: "The unique identifier for the playlist to retrieve songs from." + page: + desc: "The current page number for the pagination." deleteplaylist: - desc: "Deletes a saved playlist using its id. Works only if you made it or if you are the bot owner." - args: - - "5" + desc: Deletes a saved playlist using its id. Works only if you made it or if you are the bot owner. + ex: + - 5 + params: + - id: + desc: "The identifier for the playlist to be deleted." queueautoplay: - desc: "Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs)" - args: + desc: Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs) + ex: - "" + params: + - {} streamadd: - desc: "Notifies this channel when the stream on the specified URL goes online or offline. Offline notifications will only show if you enable `{0}streamoff`. Maximum 10 per server." - args: - - "twitch.tv/someguy" + desc: Notifies this channel when the stream on the specified URL goes online or offline. Offline notifications will only show if you enable `{0}streamoff`. Maximum 10 per server. + ex: + - twitch.tv/someguy + params: + - link: + desc: "The URL of a live streaming service that triggers the notification." streamsclear: - desc: "Removes all followed streams on this server." - args: + desc: Removes all followed streams on this server. + ex: - "" + params: + - {} streamremove: - desc: "Stops following the stream on the specified index. (use `{0}stl` to see indexes)" - args: - - "2" + desc: Stops following the stream on the specified index. (use `{0}stl` to see indexes) + ex: + - 2 + params: + - index: + desc: "The index at which to stop following the stream." streamlist: - desc: "Lists all streams you are following on this server and their respective indexes." - args: + desc: Lists all streams you are following on this server and their respective indexes. + ex: - "" + params: + - page: + desc: "The number of the page to retrieve from the list of followed streams." streamoffline: - desc: "Toggles whether the bot will also notify when added streams go offline." - args: + desc: Toggles whether the bot will also notify when added streams go offline. + ex: - "" + params: + - {} streamonlinedelete: - desc: "Toggles whether the bot will delete stream online message when the stream goes offline." - args: + desc: Toggles whether the bot will delete stream online message when the stream goes offline. + ex: - "" + params: + - {} streammessage: - desc: "Sets the message which will show when the stream on the specified index comes online. You can use %user% and %platform% placeholders." - args: - - "1 Hey @erryone %user% is back online on %platform%!1!!" + desc: Sets the message which will show when the stream on the specified index comes online. You can use %user% and %platform% placeholders. + ex: + - 1 Hey @erryone %user% is back online on %platform%!1!! + params: + - index: + desc: "The index of the stream to set the coming online message for." + message: + desc: "The text to be displayed in the stream's online status message." streammessageall: - desc: "Sets the message which will show when any of the currently followed streams comes online. This does not apply to the streams which get added afterwards. You can use %user% and %platform% placeholders." - args: - - "Hey @erryone %user% is back online!1!!" + desc: Sets the message which will show when any of the currently followed streams comes online. This does not apply to the streams which get added afterwards. You can use %user% and %platform% placeholders. + ex: + - Hey @erryone %user% is back online!1!! + params: + - message: + desc: "The text that appears in the notification when a streamer goes live." streamcheck: - desc: "Retrieves information about a stream." - args: - - "https://twitch.tv/somedude" + desc: Retrieves information about a stream. + ex: + - https://twitch.tv/somedude + params: + - url: + desc: "The URL of the stream being checked." convert: - desc: "Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies." - args: - - "m km 1000" + desc: Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies. + ex: + - m km 1000 + params: + - origin: + desc: "The location or source from which the quantity originates." + target: + desc: "The target unit or currency for the conversion." + value: + desc: "The value to be converted." convertlist: - desc: "List of the convertible dimensions and currencies." - args: + desc: List of the convertible dimensions and currencies. + ex: - "" + params: + - {} wowjoke: - desc: "Get one of penultimate WoW jokes." - args: + desc: Get one of penultimate WoW jokes. + ex: - "" + params: + - {} calculate: - desc: "Evaluate a mathematical expression." - args: - - "1+1" + desc: Evaluate a mathematical expression. + ex: + - 1+1 + params: + - expression: + desc: "The input string represents the mathematical formula to be evaluated." osu: - desc: "Shows osu! stats for a player." - args: - - "Name" - - "Name taiko" + desc: Shows osu! stats for a player. + ex: + - Name + - Name taiko + params: + - user: + desc: "The username of the player whose osu! stats are being retrieved." + mode: + desc: "The type of game mode to display statistics for, such as 'osu' or 'taiko'." gatari: - desc: "Shows osu!gatari stats for a player." - args: - - "Name" - - "Name ctb" + desc: Shows osu!gatari stats for a player. + ex: + - Name + - Name ctb + params: + - user: + desc: "The username of the player whose osu!gatari stats are being retrieved." + mode: + desc: "The type of game mode to display statistics for, such as 'osu' or 'taiko'." osu5: - desc: "Displays a user's top 5 plays." - args: - - "Name" + desc: Displays a user's top 5 plays. + ex: + - Name + params: + - user: + desc: "The username of the player whose top 5 plays are being displayed." + mode: + desc: 'The type of game mode to display the top 5 plays for, such as "osu", "taiko", or "ctb".' pokemon: - desc: "Searches for a pokemon." - args: - - "Sylveon" + desc: Searches for a pokemon. + ex: + - Sylveon + params: + - pokemon: + desc: "The name of the Pokémon to search for." pokemonability: - desc: "Searches for a pokemon ability." - args: - - "overgrow" + desc: Searches for a pokemon ability. + ex: + - overgrow + params: + - ability: + desc: "The type of the Pokémon's special power or trait that can be used in battle." memelist: - desc: "Shows a list of template keys (and their respective names) used for `{0}memegen`." - args: + desc: Shows a list of template keys (and their respective names) used for `{0}memegen`. + ex: - "" + params: + - page: + desc: "The number of pages in the list to be displayed." memegen: - desc: "Generates a meme from memelist with specified text. Separate multiple text values with semicolons. Provide no meme text to see an example meme with that template." - args: - - "biw gets iced coffee;in the winter" - - "ntot" + desc: Generates a meme from memelist with specified text. Separate multiple text values with semicolons. Provide no meme text to see an example meme with that template. + ex: + - biw gets iced coffee;in the winter + - ntot + params: + - meme: + desc: "The caption or punchline of the meme, which can be a single sentence or multiple sentences separated by semicolons." + memeText: + desc: "The user-provided text to be displayed on the generated meme." weather: - desc: "Shows weather data for a specified city. You can also specify a country after a comma." - args: - - "Moscow, RU" + desc: Shows weather data for a specified city. You can also specify a country after a comma. + ex: + - Moscow, RU + params: + - query: + desc: "The location to retrieve weather information for." youtube: - desc: "Searches youtubes and shows the first result" - args: - - "query" + desc: Searches youtubes and shows the first result + ex: + - query + params: + - query: + desc: "The search term or phrase to look for." anime: - desc: "Queries anilist for an anime and shows the first result." - args: - - "aquarion evol" + desc: Queries anilist for an anime and shows the first result. + ex: + - aquarion evol + params: + - query: + desc: "The search term used to find a specific anime on Anilist." steam: - desc: "Returns a store link for a steam game with the specified name. It doesn't work very well because bundles." - args: - - "Sakura Agent" + desc: Returns a store link for a steam game with the specified name. It doesn't work very well because bundles. + ex: + - Sakura Agent + params: + - query: + desc: "The name of the game to search for." movie: - desc: "Queries omdb for movies or series, show first result." - args: - - "Batman vs Superman" + desc: Queries omdb for movies or series, show first result. + ex: + - Batman vs Superman + params: + - query: + desc: "The title of the movie or TV series being searched for." manga: - desc: "Queries anilist for a manga and shows the first result." - args: - - "Shingeki no kyojin" + desc: Queries anilist for a manga and shows the first result. + ex: + - Shingeki no kyojin + params: + - query: + desc: "The title or keywords to search for in Anilist's database." randomcat: - desc: "Shows a random cat image." - args: + desc: Shows a random cat image. + ex: - "" + params: + - {} randomdog: - desc: "Shows a random dog image." - args: + desc: Shows a random dog image. + ex: - "" + params: + - {} randomfood: - desc: "Shows a random food image." - args: + desc: Shows a random food image. + ex: - "" + params: + - {} randombird: - desc: "Shows a random bird image." - args: + desc: Shows a random bird image. + ex: - "" + params: + - {} image: - desc: "Pulls a random image using a search parameter." - args: - - "cute kitten" + desc: Pulls a random image using a search parameter. + ex: + - cute kitten + params: + - query: + desc: "The search term used to retrieve the desired image." lmgtfy: - desc: "Google something for an idiot." - args: - - "query" + desc: Google something for an idiot. + ex: + - query + params: + - ffs: + desc: "The search query to be entered into the search engine." google: - desc: "Get a Google search link for some terms." - args: - - "query" -duckduckgo: - desc: "Get duckduckgo search results." - args: - - "cat pictures" + desc: Get a Google search link for some terms. + ex: + - query + params: + - query: + desc: "The search terms to look up on Google." hearthstone: - desc: "Searches for a Hearthstone card and shows its image. Takes a while to complete." - args: - - "Ysera" + desc: Searches for a Hearthstone card and shows its image. Takes a while to complete. + ex: + - Ysera + params: + - name: + desc: "The name of the Hearthstone card to search for." urbandict: - desc: "Searches Urban Dictionary for a word." - args: - - "Pineapple" + desc: Searches Urban Dictionary for a word. + ex: + - Pineapple + params: + - query: + desc: "The term being searched for in the dictionary." catfact: - desc: "Shows a random catfact from " - args: + desc: Shows a random catfact from + ex: - "" + params: + - {} yomama: - desc: "Shows a random joke from " - args: + desc: Shows a random joke from + ex: - "" + params: + - {} randjoke: - desc: "Shows a random joke." - args: + desc: Shows a random joke. + ex: - "" + params: + - {} chucknorris: - desc: "Shows a random Chuck Norris joke." - args: + desc: Shows a random Chuck Norris joke. + ex: - "" + params: + - {} magicitem: - desc: "Shows a random magic item from " - args: + desc: Shows a random magic item from + ex: - "" -revav: - desc: "Returns a Google reverse image search for someone's avatar." - args: - - "@Someone" -revimg: - desc: "Returns a Google reverse image search for an image from a link." - args: - - "Image link" + params: + - {} wiki: - desc: "Gives you back a wikipedia link" - args: - - "query" + desc: Gives you back a wikipedia link + ex: + - query + params: + - query: + desc: "The search term or phrase to look up on Wikipedia." color: - desc: "Shows you pictures of colors which correspond to the inputted hex values. Max 10." - args: - - "00ff00" - - "f00 0f0 00f" + desc: Shows you pictures of colors which correspond to the inputted hex values. Max 10. + ex: + - 00ff00 + - f00 0f0 00f + params: + - colors: + desc: "The array of colors to display as images." avatar: - desc: "Shows a mentioned person's avatar." - args: + desc: Shows a mentioned person's avatar. + ex: - "@Someone" -hentai: - desc: "Shows a hentai image from a random website (gelbooru, danbooru, konachan or yandere) with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags. Only 1 tag allowed." - args: - - "yuri" -autohentai: - desc: "Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tag groups. Random group will be chosen every time the image is sent. Max 2 tags per group. 20 seconds minimum. Provide no parameters to disable." - args: - - "30 yuri kissing|tail long_hair" - - "" -hentaibomb: - desc: "Shows a total 5 images (from gelbooru, danbooru, konachan and yandere). Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri" -yandere: - desc: "Shows a random image from yandere with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -danbooru: - desc: "Shows a random hentai image from danbooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -derpibooru: - desc: "Shows a random image from derpibooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -gelbooru: - desc: "Shows a random hentai image from gelbooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -sankaku: - desc: "Shows a random hentai image from chan.sankakucomplex.com with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kiss" -rule34: - desc: "Shows a random image from rule34.xx with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -e621: - desc: "Shows a random hentai image from e621.net with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -safebooru: - desc: "Shows a random image from safebooru with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri kissing" -boobs: - desc: "Real adult content." - args: - - "" -butts: - desc: "Real adult content." - args: - - "" + params: + - usr: + desc: "The user whose avatar is being displayed." translate: - desc: "Translates text from the given language to the destination language." - args: - - "en fr Hello" + desc: Translates text from the given language to the destination language. + ex: + - en fr Hello + params: + - fromLang: + desc: "The source language as 'english'" + toLang: + desc: "The target language such as 'english' or 'french'" + text: + desc: "The source text to be translated." translangs: - desc: "Lists the valid languages for translation." - args: + desc: Lists the valid languages for translation. + ex: - "" + params: + - {} guide: - desc: "Sends a readme and a guide links to the channel." - args: + desc: Sends a readme and a guide links to the channel. + ex: - "" + params: + - {} calcops: - desc: "Shows all available operations in the `{0}calc` command" - args: + desc: Shows all available operations in the `{0}calc` command + ex: - "" + params: + - {} delallquotes: - desc: "Deletes all quotes on a specified keyword." - args: - - "kek" + desc: Deletes all quotes on a specified keyword. + ex: + - kek + params: + - keyword: + desc: "The keyword to search for in the text." greetdmmsg: - desc: "Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from instead of a regular text, if you want the message to be embedded." - args: - - "Welcome to the server, %user.mention%" + desc: Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. + ex: + - Welcome to the server, %user.mention% + params: + - text: + desc: "The new join announcement message that will be sent to the user who joined." cash: - desc: "Check how much currency a person has. (Defaults to yourself)" - args: + desc: Check how much currency a person has. If no argument is provided it will check your own balance. + ex: - "" - "@Someone" + params: + - userId: + desc: "Optional user ID of the account holder whose currency balance is being checked." + - user: + desc: "Optional ID of the person whose currency balance is being checked." currencytransactions: - desc: "Shows your currency transactions on the specified page. Bot owner can see other people's transactions too." - args: - - "2" + desc: Shows your currency transactions on the specified page. Bot owner can see other people's transactions too. + ex: + - 2 - "@SomeUser 2" + params: + - page: + desc: "The number of pages to display in the list of currency transactions." + - usr: + desc: "The user whose transactions are being displayed." + - usr: + desc: "The user whose transactions are being displayed." + page: + desc: "The number of pages to display in the list of currency transactions." currencytransaction: - desc: "Shows full details about a currency transaction with the specified ID. You can only check your own transactions." - args: - - "3yvd" + desc: Shows full details about a currency transaction with the specified ID. You can only check your own transactions. + ex: + - 3yvd + params: + - id: + desc: "The unique identifier for the transaction being queried." listperms: - desc: "Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions." - args: + desc: Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. + ex: - "" - - "3" + - 3 + params: + - page: + desc: "The page number for pagination, allowing the retrieval of large permission chains in manageable chunks." allusrmdls: - desc: "Enable or disable all modules for a specific user." - args: - - "enable @Someone" + desc: Enable or disable all modules for a specific user. + ex: + - enable @Someone + params: + - action: + desc: "The type of permission action to take, such as granting or revoking access." + user: + desc: "The user account that the operation is being performed on." moveperm: - desc: "Moves permission from one position to another in the Permissions list." - args: - - "2 4" + desc: Moves permission from one position to another in the Permissions list. + ex: + - 2 4 + params: + - from: + desc: "The starting index of the permission to be moved." + to: + desc: "The index at which to insert or remove the permission." removeperm: - desc: "Removes a permission from a given position in the Permissions list." - args: - - "1" + desc: Removes a permission from a given position in the Permissions list. + ex: + - 1 + params: + - index: + desc: "The position at which to start removing permissions." showemojis: - desc: "Shows a name and a link to every SPECIAL emoji in the message." - args: - - "A message full of SPECIAL emojis" + desc: Shows a name and a link to every SPECIAL emoji in the message. + ex: + - A message full of SPECIAL emojis + params: + - _: + desc: "The text containing the emojis to be processed." emojiadd: desc: |- Adds the specified emoji to this server. @@ -1233,605 +2189,1112 @@ emojiadd: You can specify a name followed by an image link to add a new emoji from an image. You can omit imageUrl and instead upload the image as an attachment. Image size has to be below 256KB. - args: + ex: - ":someonesCustomEmoji:" - "MyEmojiName :someonesCustomEmoji:" - - "owoNice https://cdn.discordapp.com/emojis/587930873811173386.png?size=128" + - owoNice https://cdn.discordapp.com/emojis/587930873811173386.png?size=128 + params: + - name: + desc: "The name of the emoji or the file to be uploaded." + emote: + desc: "The type of emoji being added, such as a smiley face or a thumbs up." + - emote: + desc: "The type of emoji being added, such as a smiley face or a thumbs up." + - name: + desc: "The name of the emoji or the file to be uploaded." + url: + desc: "The URL of an image file to use as the emoji's representation." emojiremove: - desc: "Removes the specified emoji or emojis from this server." - args: + desc: Removes the specified emoji or emojis from this server. + ex: - ":eagleWarrior: :plumedArcher:" + params: + - emotes: + desc: "The list of emojis to be removed from the server." stickeradd: - desc: "Adds the sticker from your message to this server. Send the sticker along with this command (in the same message)." - args: + desc: Adds the sticker from your message to this server. Send the sticker along with this command (in the same message). + ex: - "" - - 'name "description" tag1 tag2 tagN' + - name "description" tag1 tag2 tagN + params: + - name: + desc: "The identifier for the sticker to be added." + description: + desc: "The text that describes the sticker being added." + tags: + desc: "The list of tags associated with the sticker being added." deckshuffle: - desc: "Reshuffles all cards back into the deck." - args: + desc: Reshuffles all cards back into the deck. + ex: - "" + params: + - {} forwardmessages: - desc: "Toggles forwarding of non-command messages sent to bot's DM to the bot owners" - args: + desc: Toggles forwarding of non-command messages sent to bot's DM to the bot owners + ex: - "" + params: + - {} forwardtoall: - desc: "Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the creds.yml file" - args: + desc: Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the creds.yml file + ex: - "" + params: + - {} forwardtochannel: - desc: "Toggles forwarding of non-command messages sent to bot's DM to the current channel" - args: + desc: Toggles forwarding of non-command messages sent to bot's DM to the current channel + ex: - "" + params: + - {} resetperms: - desc: "Resets the bot's permissions module on this server to the default value." - args: + desc: Resets the bot's permissions module on this server to the default value. + ex: - "" + params: + - {} antiraid: desc: "Sets an anti-raid protection on the server. Provide no parameters to disable. First parameter is number of people which will trigger the protection. Second parameter is a time interval in which that number of people needs to join in order to trigger the protection, and third parameter is punishment for those people. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, RemoveRoles, AddRole, Warn, TimeOut" - args: - - "5 20 Kick" - - "7 9 Ban" - - "10 10 Ban 6h30m" + ex: + - 5 20 Kick + - 7 9 Ban + - 10 10 Ban 6h30m - "" + params: + - {} + - userThreshold: + desc: "The number of users that must join the server within a specified time interval to trigger the anti-raid protection." + seconds: + desc: "The time interval in which the specified number of people needs to join before triggering the protection." + action: + desc: "The punishment action specifies the consequence for users who trigger the anti-raid protection." + punishTime: + desc: "The time duration for which the punishment will be applied." + - userThreshold: + desc: "The number of users that must join the server within a specified time interval to trigger the anti-raid protection." + seconds: + desc: "The time interval in which the specified number of people needs to join before triggering the protection." + action: + desc: "The punishment action specifies the consequence for users who trigger the anti-raid protection." antispam: desc: "Stops people from repeating same message X times in a row. Provide no parameters to disable. You can specify to either mute, kick or ban the offenders. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Max message count is 10. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, AddRole, RemoveRoles, Warn, TimeOut" - args: - - "3 Mute" - - "5 Ban" - - "5 Ban 3h30m" + ex: + - 3 Mute + - 5 Ban + - 5 Ban 3h30m - "" + params: + - {} + - messageCount: + desc: "The maximum number of times a user can send the same message before being punished." + action: + desc: "The type of punishment to be applied to the offender." + role: + desc: "The role to apply the punishment to." + - messageCount: + desc: "The maximum number of times a user can send the same message before being punished." + action: + desc: "The type of punishment to be applied to the offender." + punishTime: + desc: "The time period for which the punishment should be enforced." + - messageCount: + desc: "The maximum number of times a user can send the same message before being punished." + action: + desc: "The type of punishment to be applied to the offender." antialt: - desc: "Applies a punishment action to any user whose account is younger than the specified threshold. Specify time after the punishment to have a timed punishment (not all punishments support timers)." - args: - - "1h Ban" - - "3d Mute 1h" + desc: Applies a punishment action to any user whose account is younger than the specified threshold. Specify time after the punishment to have a timed punishment (not all punishments support timers). + ex: + - 1h Ban + - 3d Mute 1h + params: + - {} + - minAge: + desc: "The minimum age of an account for which the punishment should be applied." + action: + desc: "The type of punishment to be applied to users with accounts younger than the specified threshold." + punishTime: + desc: "The amount of time for which the punishment should be applied." + - minAge: + desc: "The minimum age of an account for which the punishment should be applied." + action: + desc: "The type of punishment to be applied to users with accounts younger than the specified threshold." + role: + desc: "The role of the user being punished, used to determine the severity of the punishment." chatmute: - desc: "Prevents a mentioned user from chatting in text channels. You can also specify time string for how long the user should be muted. You can optionally specify a reason." - args: + desc: Prevents a mentioned user from chatting in text channels. You can also specify time string for how long the user should be muted. You can optionally specify a reason. + ex: - "@Someone" - "@Someone stop writing" - - "15m @Someone" - - "1h30m @Someone" - - "1h @Someone chill" + - 15m @Someone + - 1h30m @Someone + - 1h @Someone chill + params: + - user: + desc: "The user to mute, as specified by their ID or mention." + reason: + desc: "The optional reason provided is used to explain why the user was muted." + - time: + desc: "The duration of the mute period." + user: + desc: "The user to mute, as specified by their ID or mention." + reason: + desc: "The optional reason provided is used to explain why the user was muted." voicemute: - desc: "Prevents a mentioned user from speaking in voice channels. User has to be in a voice channel in order for the command to have an effect. You can also specify time string for how long the user should be muted. You can optionally specify a reason." - args: + desc: Prevents a mentioned user from speaking in voice channels. User has to be in a voice channel in order for the command to have an effect. You can also specify time string for how long the user should be muted. You can optionally specify a reason. + ex: - "@Someone" - "@Someone stop talking" - - "15m @Someone" - - "1h30m @Someone" - - "1h @Someone silence" -konachan: - desc: "Shows a random hentai image from konachan with a given tag. Tag(s) are optional but preferred. Maximum is usually 2 tags." - args: - - "yuri" + - 15m @Someone + - 1h30m @Someone + - 1h @Someone silence + params: + - user: + desc: "The user being targeted by this function, whose voice capabilities are intended to be restricted." + reason: + desc: "The optional reason provided is used to explain why the user was muted." + - time: + desc: "The duration of the silence imposed on the mentioned user." + user: + desc: "The user being targeted by this function, whose voice capabilities are intended to be restricted." + reason: + desc: "The optional reason provided is used to explain why the user was muted." muterole: - desc: "Sets a name of the role which will be assigned to people who should be muted. Provide no arguments to see currently set mute role. Default is ellie-mute." - args: + desc: Sets a name of the role which will be assigned to people who should be muted. Provide no arguments to see currently set mute role. Default is ellie-mute. + ex: - "" - - "Silenced" + - Silenced + params: + - role: + desc: "The role that determines whether users are muted or not." adsarm: - desc: "Toggles the automatic deletion of the user's message and Ellie's confirmations for `{0}iam` and `{0}iamn` commands." - args: + desc: Toggles the automatic deletion of the user's message and Ellie's confirmations for `{0}iam` and `{0}iamn` commands. + ex: - "" + params: + - {} setstream: - desc: "Sets the bots stream. First parameter is the twitch link, second parameter is stream name." - args: - - "TWITCHLINK Hello" + desc: Sets the bots stream. First parameter is the twitch link, second parameter is stream name. + ex: + - TWITCHLINK Hello + params: + - url: + desc: "The URL of the Twitch channel's live stream page." + name: + desc: "The name of the stream being set." chatunmute: - desc: "Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels." - args: + desc: Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels. + ex: - "@Someone" + params: + - user: + desc: "The user who was previously muted and is now being unmuted." + reason: + desc: "The reason for the mute being lifted." unmute: - desc: "Unmutes a mentioned user previously muted with `{0}mute` command." - args: + desc: Unmutes a mentioned user previously muted with `{0}mute` command. + ex: - "@Someone" + params: + - user: + desc: "The user who was previously muted and is now being un-muted." + reason: + desc: "The reason for the mute being lifted." xkcd: - desc: 'Shows a XKCD comic. Specify no parameters to retrieve a random one. Number parameter will retrieve a specific comic, and "latest" will get the latest one.' - args: + desc: Shows a XKCD comic. Specify no parameters to retrieve a random one. Number parameter will retrieve a specific comic, and "latest" will get the latest one. + ex: - "" - - "1400" - - "latest" -placelist: - desc: "Shows the list of available tags for the `{0}place` command." - args: - - "" -place: - desc: "Shows a placeholder image of a given tag. Use `{0}placelist` to see all available tags. You can specify the width and height of the image as the last two optional parameters." - args: - - "Cage" - - "steven 500 400" -poll: - desc: "Creates a public poll which requires users to type a number of the voting option in the channel command is ran in." - args: - - "Question?;Answer1;Answ 2;A_3" + - 1400 + - latest + params: + - arg: + desc: 'The URL of the desired comic or "latest" to retrieve the most recent one.' + - num: + desc: "The number of the comic to be retrieved." autotranslang: - desc: "Sets your source and target language to be used with `{0}at`. Specify no parameters to remove previously set value." - args: - - "en fr" + desc: Sets your source and target language to be used with `{0}at`. Specify no parameters to remove previously set value. + ex: + - en fr + params: + - {} + - fromLang: + desc: + toLang: + desc: 'The destination language code, such as "en" for English or "fr" for French.' autotranslate: - desc: 'Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" parameter to automatically delete all translated user messages.' - args: + desc: Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" parameter to automatically delete all translated user messages. + ex: - "" - - "del" + - del + params: + - autoDelete: + desc: "The option to automatically remove translated messages from the chat." listquotes: - desc: "Lists all quotes on the server ordered alphabetically or by ID. 15 Per page." - args: - - "3" - - "3 id" + desc: Lists all quotes on the server ordered alphabetically or by ID. 15 Per page. + ex: + - 3 + - 3 id + params: + - order: + desc: "The order parameter determines how the quotes are sorted and displayed, allowing users to choose between alphabetical or ID-based ordering." + - page: + desc: "The current page number for pagination." + order: + desc: "The order parameter determines how the quotes are sorted and displayed, allowing users to choose between alphabetical or ID-based ordering." typedel: - desc: "Deletes a typing article given the ID." - args: - - "3" + desc: Deletes a typing article given the ID. + ex: + - 3 + params: + - index: + desc: "The identifier for the typing article to be deleted." typelist: - desc: "Lists added typing articles with their IDs. 15 per page." - args: + desc: Lists added typing articles with their IDs. 15 per page. + ex: - "" - - "3" + - 3 + params: + - page: + desc: "The current page number for the list of typing articles." listservers: - desc: "Lists servers the bot is on with some basic info. 15 per page." - args: - - "3" + desc: Lists servers the bot is on with some basic info. 15 per page. + ex: + - 3 + params: + - page: + desc: "The number of pages to retrieve from the server list." cleverbot: - desc: "Toggles cleverbot/chatgpt session. When enabled, the bot will reply to messages starting with bot mention in the server. Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled." - args: + desc: Toggles cleverbot/chatgpt session. When enabled, the bot will reply to messages starting with bot mention in the server. Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled. + ex: - "" + params: + - {} shorten: - desc: "Attempts to shorten an URL, if it fails, returns the input URL." - args: - - "https://google.com" + desc: Attempts to shorten an URL, if it fails, returns the input URL. + ex: + - https://google.com + params: + - query: + desc: "The search term or identifier used to retrieve a shortened version of the URL from a database or service." wikia: - desc: "Gives you back a fandom link" - args: - - "mtg Vigilance" - - "mlp Dashy" + desc: Gives you back a fandom link + ex: + - mtg Vigilance + - mlp Dashy + params: + - target: + desc: "The URL or title of the fandom being linked." + query: + desc: "The search term or phrase to look for on the wiki." magicthegathering: - desc: "Searches for a Magic The Gathering card." - args: - - "about face" + desc: Searches for a Magic The Gathering card. + ex: + - about face + params: + - search: + desc: "The query string used to search for the desired card." hangmanlist: - desc: "Shows a list of hangman question categories." - args: + desc: Shows a list of hangman question categories. + ex: - "" + params: + - {} hangman: - desc: "Starts a game of hangman in the channel. You can optionally select a category `{0}hangmanlist` to see a list of available categories." - args: + desc: Starts a game of hangman in the channel. You can optionally select a category `{0}hangmanlist` to see a list of available categories. + ex: - "" - - "movies" + - movies + params: + - type: + desc: "The language or theme of the word to be guessed." hangmanstop: - desc: "Stops the active hangman game on this channel if it exists." - args: + desc: Stops the active hangman game on this channel if it exists. + ex: - "" + params: + - {} acrophobia: - desc: "Starts an Acrophobia game." - args: + desc: Starts an Acrophobia game. + ex: - "" - - "-s 30" + - -s 30 + params: + - params: + desc: "The list of command-line arguments passed to the game, which may include options or settings for customizing the gameplay experience." logevents: - desc: "Shows a list of all events you can subscribe to with `{0}log`" - args: + desc: Shows a list of all events you can subscribe to with `{0}log` + ex: - "" + params: + - {} log: - desc: "Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to." - args: - - "userpresence" - - "userbanned" -fairplay: - desc: "Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue." - args: + desc: Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to. + ex: + - userpresence + - userbanned + params: + - type: + desc: "The type of log event to toggle." +queuefairplay: + desc: Triggers fairplay. The song queue will be re-ordered in a fair manner. No effect on newly added songs. + ex: - "" + params: + - {} define: - desc: "Finds a definition of a word." - args: - - "heresy" -setmaxplaytime: - desc: "Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit." - args: - - "0" - - "270" + desc: Finds a definition of a word. + ex: + - heresy + params: + - word: + desc: "The word being searched for." activity: - desc: "Checks for spammers." - args: + desc: Checks for spammers. + ex: - "" + params: + - page: + desc: "The number of pages to scan for spam." setstatus: - desc: "Sets the bot's status. (Online/Idle/Dnd/Invisible)" - args: - - "Idle" + desc: Sets the bot's status. (Online/Idle/Dnd/Invisible) + ex: + - Idle + params: + - status: + desc: "The current state or mode of the bot's presence in a chat." invitecreate: - desc: "Creates a new invite which has infinite max uses and never expires." - args: + desc: Creates a new invite which has infinite max uses and never expires. + ex: - "" + params: + - params: + desc: "The recipient's email addresses or usernames." invitelist: - desc: "Lists all invites for this channel. Paginated with 9 per page." - args: + desc: Lists all invites for this channel. Paginated with 9 per page. + ex: - "" - - "3" + - 3 + params: + - page: + desc: "The page number to retrieve, starting from 1." + ch: + desc: "The channel in which the invite list is being retrieved." invitedelete: - desc: "Deletes an invite on the specified index. Use `{0}invitelist` to see the list of invites." - args: - - "2" -pollstats: - desc: "Shows the poll results without stopping the poll on this server." - args: - - "" + desc: Deletes an invite on the specified index. Use `{0}invitelist` to see the list of invites. + ex: + - 2 + params: + - index: + desc: "The index at which the invite is located in the invite list." antilist: - desc: "Shows currently enabled protection features." - args: + desc: Shows currently enabled protection features. + ex: - "" + params: + - {} antispamignore: - desc: "Toggles whether antispam ignores current channel. Antispam must be enabled." - args: + desc: Toggles whether antispam ignores current channel. Antispam must be enabled. + ex: - "" + params: + - {} eventstart: desc: "Starts one of the events seen on public ellie. Events: `reaction`, `gamestatus`" - args: - - "reaction" - - "reaction -d 1 -a 50 --pot-size 1500" + ex: + - reaction + - reaction -d 1 -a 50 --pot-size 1500 + params: + - ev: + desc: "The type of event being started." + options: + desc: "The types of events that can be started." betstats: - desc: "Shows the total stats of several gambling features. Updates once an hour." - args: + desc: Shows the total stats of several gambling features. Updates once an hour. + ex: - "" -slottest: - desc: "Tests to see how much slots payout for X number of plays." - args: - - "1000" + params: + - {} slot: - desc: "Play Ellie slots. 1 second cooldown per user." - args: - - "5" + desc: Play Ellie slots. 1 second cooldown per user. + ex: + - 5 + params: + - amount: + desc: "The number of spins to perform in the game." affinity: - desc: "Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. Provide no parameters to clear your affinity. 30 minutes cooldown." - args: + desc: Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. Provide no parameters to clear your affinity. 30 minutes cooldown. + ex: - "@MyHusband" - "" + params: + - user: + desc: "The user being targeted for a potential claim." waifuclaim: - desc: "Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `{0}affinity` towards you." - args: - - "50 @Himesama" + desc: Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `{0}affinity` towards you. + ex: + - 50 @Himesama + params: + - amount: + desc: "The cost of claiming the waifu." + target: + desc: "The user to whom the claim is being made, allowing the waifu to be claimed from their collection." waifureset: - desc: "Resets your waifu stats, except current waifus." - args: + desc: Resets your waifu stats, except current waifus. + ex: - "" + params: + - {} waifutransfer: - desc: "Transfer the ownership of one of your waifus to another user. You must pay 10% of your waifu's value unless that waifu has affinity towards you, in which case you must pay 60% fee. Transferred waifu's price will be reduced by the fee amount." - args: + desc: Transfer the ownership of one of your waifus to another user. You must pay 10% of your waifu's value unless that waifu has affinity towards you, in which case you must pay 60% fee. Transferred waifu's price will be reduced by the fee amount. + ex: - "@ExWaifu @NewOwner" + params: + - waifuId: + desc: "The ID of the waifu being transferred to a new owner." + newOwner: + desc: "The user to whom ownership of the waifu is being transferred." + - waifu: + desc: "The user to whom the ownership of the waifu is being transferred." + newOwner: + desc: "The user to whom ownership of the waifu is being transferred." waifugift: - desc: -| - Gift an item to someone. This will increase their waifu value by a percentage of the gift's value. - Negative gifts will not show up in waifuinfo. - Provide no parameters to see a list of items that you can gift. - args: + desc: -| Gift an item to someone. This will increase their waifu value by a percentage of the gift's value. Negative gifts will not show up in waifuinfo. Provide no parameters to see a list of items that you can gift. + ex: - "" - - "Rose @Himesama" + - Rose @Himesama + params: + - page: + desc: "The number of pages to display when listing available gifting options." + - itemName: + desc: "The name of an item to be gifted, which is used to determine the percentage increase in waifu value." + waifu: + desc: "The user who is receiving the gift." waifulb: - desc: "Shows top 9 waifus. You can specify another page to show other waifus." - args: + desc: Shows top 9 waifus. You can specify another page to show other waifus. + ex: - "" - - "3" + - 3 + params: + - page: + desc: "The number of the page to display." divorce: - desc: "Releases your claim on a specific waifu. You will get 50% of that waifu's value back, unless that waifu has an affinity towards you, in which case they will be reimbursed instead. 6 hours cooldown." - args: + desc: Releases your claim on a specific waifu. You will get 50% of that waifu's value back, unless that waifu has an affinity towards you, in which case they will be reimbursed instead. 6 hours cooldown. + ex: - "@CheatingSloot" + params: + - target: + desc: "The ID or name of the waifu being released from your claim." + - target: + desc: "The user to release the claim on." + - targetId: + desc: "The ID of the waifu to release your claim on." waifuinfo: - desc: "Shows waifu stats for a target person. Defaults to you if no user is provided." - args: + desc: Shows waifu stats for a target person. Defaults to you if no user is provided. + ex: - "@MyCrush" - "" + params: + - target: + desc: "The user being targeted, whose waifu information will be displayed." + - targetId: + desc: "The ID of the person whose waifu stats are being displayed." mal: - desc: "Shows basic info from a MyAnimeList profile." - args: - - "straysocks" + desc: Shows basic info from a MyAnimeList profile. + ex: + - straysocks + params: + - name: + desc: "The username or identifier for the MyAnimeList account being queried." + - usr: + desc: "The user's guild membership information is used to fetch their anime list and other relevant data." setmusicchannel: - desc: "Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. Persistent server setting." - args: + desc: Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. Persistent server setting. + ex: - "" + params: + - {} unsetmusicchannel: - desc: "Bot will output playing, finished, paused and removed songs to the channel where the first song was queued in. Persistent server setting." - args: + desc: Bot will output playing, finished, paused and removed songs to the channel where the first song was queued in. Persistent server setting. + ex: - "" + params: + - {} musicquality: desc: "Gets or sets the default music player quality. Available settings: Highest, High, Medium, Low. Default is **Highest**. Provide no argument to see current setting." - args: + ex: - "" - - "High" - - "Low" + - High + - Low + params: + - {} + - preset: + desc: "The selected preset determines the level of audio compression and processing applied to the music playback." stringsreload: - desc: "Reloads localized bot strings." - args: + desc: Reloads localized bot strings. + ex: - "" + params: + - {} shardstats: desc: |- Stats for shards. Paginated with 25 shards per page. Format: `[status] | # [shard_id] | [last_heartbeat] | [server_count]` - args: + ex: - "" - - "2" + - 2 + params: + - page: + desc: "The number of pages to retrieve, with each page containing 25 shards." restartshard: - desc: "Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors." - args: - - "2" + desc: Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. + ex: + - 2 + params: + - shardId: + desc: "The ID of the shard to be restarted or reconnected." tictactoe: - desc: "Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play." - args: + desc: Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. + ex: - "" + params: + - params: + desc: "The coordinates for placing an X or O on the board." timezones: - desc: "Lists all timezones available on the system to be used with `{0}timezone`." - args: + desc: Lists all timezones available on the system to be used with `{0}timezone`. + ex: - "" + params: + - page: + desc: "The number of pages to retrieve from the list of available timezones." timezone: - desc: "Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) **Setting timezone requires Administrator server permission.**" - args: + desc: Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) **Setting timezone requires Administrator server permission.** + ex: - "" - - "GMT Standard Time" + - GMT Standard Time + params: + - {} + - id: + desc: "The identifier for a specific timezone region." languagesetdefault: - desc: "Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no parameters to see currently set language." - args: - - "en-US" - - "default" + desc: Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no parameters to see currently set language. + ex: + - en-US + - default + params: + - {} + - name: + desc: "The code page or character encoding for the target audience." languageset: - desc: "Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no parameters to see currently set language." - args: + desc: Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no parameters to see currently set language. + ex: - "de-DE " - - "default" + - default + params: + - {} + - name: + desc: "The locale name for which the response language should be set." languageslist: - desc: "List of languages for which translation (or part of it) exist atm." - args: + desc: List of languages for which translation (or part of it) exist atm. + ex: - "" -rategirl: - desc: "Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart." - args: - - "@SomeGurl" + params: + - {} exprtoggleglobal: - desc: "Toggles whether global expressions are usable on this server." - args: + desc: Toggles whether global expressions are usable on this server. + ex: - "" + params: + - {} exprreact: - desc: "Sets or resets reactions (up to 3) which will be added to the response message of the Expression with the specified ID. Provide no emojis to reset." - args: - - "59 \U0001F44D \U0001F44E " - - "59 " - - "59" + desc: Sets or resets reactions (up to 3) which will be added to the response message of the Expression with the specified ID. Provide no emojis to reset. + ex: + - "59 👍 👎 " + - 59 + - 59 + params: + - id: + desc: "The ID of the expression." + emojiStrs: + desc: "The set of emojis that can be used to react to the expression." exprad: - desc: "Toggles whether the message triggering the expression will be automatically deleted." - args: - - "59" + desc: Toggles whether the message triggering the expression will be automatically deleted. + ex: + - 59 + params: + - id: + desc: "The ID of a message that should be affected by this toggle." exprat: - desc: "Toggles whether the expression will allow extra input after the trigger. For example, with this feature enabled, expression with trigger 'hi' will also be invoked when a user types 'hi there'. This feature is automatically enabled on expressions which have '%target%' in their response." - args: - - "59" + desc: Toggles whether the expression will allow extra input after the trigger. For example, with this feature enabled, expression with trigger 'hi' will also be invoked when a user types 'hi there'. This feature is automatically enabled on expressions which have '%target%' in their response. + ex: + - 59 + params: + - id: + desc: "The ID of the expression to toggle this feature for. It determines which expression's behavior will be modified by this setting." exprdm: - desc: "Toggles whether the response message of the expression will be sent as a direct message." - args: - - "44" + desc: Toggles whether the response message of the expression will be sent as a direct message. + ex: + - 44 + params: + - id: + desc: "The ID of the user who should receive the direct message." exprca: - desc: "Toggles whether the expression will trigger if the triggering message contains the keyword (instead of only starting with it)." - args: - - "44" + desc: Toggles whether the expression will trigger if the triggering message contains the keyword (instead of only starting with it). + ex: + - 44 + params: + - id: + desc: "The identifier of a specific keyword to be matched." exprsreload: - desc: "Reloads all expressions on all shards. Use this if you've made changes to the database while the bot is running, or used `{0}deleteunusedcrnq`" - args: + desc: Reloads all expressions on all shards. Use this if you've made changes to the database while the bot is running, or used `{0}deleteunusedcrnq` + ex: - "" + params: + - {} exprsimport: - desc: "Upload the file or send the raw .yml data with this command to import all expressions from the specified string or file into the current server (or as global expressions in dm)" - args: - - "" + desc: Upload the file or send the raw .yml data with this command to import all expressions from the specified string or file into the current server (or as global expressions in dm) + ex: + - + params: + - input: + desc: "The path to a file containing YAML data or a raw YAML string to be imported." exprsexport: - desc: "Exports expressions from the current server (or global expressions in DMs) into a .yml file" - args: + desc: Exports expressions from the current server (or global expressions in DMs) into a .yml file + ex: - "" + params: + - {} quotesimport: - desc: "Upload the file or send the raw .yml data with this command to import all quotes from the specified string or file into the current server." - args: - - "" + desc: Upload the file or send the raw .yml data with this command to import all quotes from the specified string or file into the current server. + ex: + - + params: + - input: + desc: "The path to a file containing the YAML data to be imported." quotesexport: - desc: "Exports quotes from the current server into a .yml file" - args: + desc: Exports quotes from the current server into a .yml file + ex: - "" + params: + - {} aliaslist: - desc: "Shows the list of currently set aliases. Paginated." - args: + desc: Shows the list of currently set aliases. Paginated. + ex: - "" - - "3" + - 3 + params: + - page: + desc: "The number of pages to display in the result set." alias: - desc: "Create a custom alias for a certain Ellie command. Provide no alias to remove the existing one." - args: - - "allin {0}bf all h" - - '"linux thingy" >loonix Spyware Windows' + desc: Create a custom alias for a certain Ellie command. Provide no alias to remove the existing one. + ex: + - allin {0}bf all h + params: + - trigger: + desc: "The trigger string that will activate this custom alias." + mapping: + desc: "The name or nickname that will be used as an alternative to invoke the original command." warnlog: - desc: "See a list of warnings of a certain user." - args: + desc: See a list of warnings of a certain user. + ex: - "@Someone" + params: + - page: + desc: "The number of pages to display in the warning log." + user: + desc: "The guild member whose warning log is being retrieved." + - user: + desc: "The guild member whose warning log is being retrieved." + - page: + desc: "The number of pages to display in the warning log." + userId: + desc: "The ID of the user whose warning log is being retrieved." + - userId: + desc: "The ID of the user whose warning log is being retrieved." warnlogall: - desc: "See a list of all warnings on the server. 15 users per page." - args: + desc: See a list of all warnings on the server. 15 users per page. + ex: - "" - - "2" + - 2 + params: + - page: + desc: "The current page number for displaying the warning log." warn: desc: |- Warns a user with an optional reason. You can specify a warning weight integer before the user. For example, 3 would mean that this warning counts as 3 warnings. - args: + ex: - "@Someone Very rude person" - - "3 @Someone Very rude person" + - 3 @Someone Very rude person + params: + - user: + desc: "The user to be warned about the issue or situation." + reason: + desc: "The reason for the warning." + - weight: + desc: "The level of severity for the warning." + user: + desc: "The user to be warned about the issue or situation." + reason: + desc: "The reason for the warning." startupcommandadd: - desc: "Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up." - args: + desc: Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. + ex: - "{0}stats" + params: + - cmdText: + desc: "The text of the command that should be recognized and executed when a user types it." autocommandadd: - desc: "Adds a command to the list of commands which will be executed automatically every X seconds." - args: - - "60 {0}prune 1000" + desc: Adds a command to the list of commands which will be executed automatically every X seconds. + ex: + - 60 {0}prune 1000 + params: + - interval: + desc: "The time period between consecutive executions of the added command." + cmdText: + desc: "The text of the command to be executed when triggered." startupcommandremove: - desc: "Removes a startup command on the specified index." - args: - - "3" + desc: Removes a startup command on the specified index. + ex: + - 3 + params: + - index: + desc: "The index at which to remove the startup command from the list." autocommandremove: - desc: "Removes an auto command on the specified index." - args: - - "3" + desc: Removes an auto command on the specified index. + ex: + - 3 + params: + - index: + desc: "The index at which the auto command is located in the list of commands." startupcommandsclear: - desc: "Removes all startup commands." - args: + desc: Removes all startup commands. + ex: - "" + params: + - {} startupcommandslist: - desc: "Lists all startup commands in the order they will be executed in." - args: + desc: Lists all startup commands in the order they will be executed in. + ex: - "" + params: + - page: + desc: "The number of items to display per page." autocommandslist: - desc: "Lists all auto commands and the intervals in which they execute." - args: + desc: Lists all auto commands and the intervals in which they execute. + ex: - "" + params: + - page: + desc: "The number of pages to retrieve from the list of auto commands." unban: - desc: "Unbans a user with the provided user#discrim or id." - args: - - "kwoth#1234" - - "123123123" + desc: Unbans a user with the provided user#discrim or id. + ex: + - kwoth#1234 + - 123123123 + params: + - user: + desc: "The ID of the user being unbanned." + - userId: + desc: "The ID of the user to be unbanned." banmessage: desc: "Sets a ban message template which will be used when a user is banned from this server. You can use embed strings and ban-specific placeholders: %ban.mod%, %ban.user%, %ban.duration% and %ban.reason%. You can disable ban message with `{0}banmsg -`" - args: + ex: - "%ban.user%, you've been banned from %server.name%. Reason: %ban.reason%" - '{{ "description": "%ban.user% you have been banned from %server.name% by %ban.mod%" }}' + params: + - message: + desc: "The custom message to be displayed when a user is banned from the server, allowing for placeholders to be replaced with relevant information." banmessagetest: - desc: "If ban message is not disabled, bot will send you the message as if you were banned by yourself. Used for testing the ban message." - args: - - "No reason" - - "1h Test 1 hour ban message" + desc: If ban message is not disabled, bot will send you the message as if you were banned by yourself. Used for testing the ban message. + ex: + - No reason + - 1h Test 1 hour ban message + params: + - reason: + desc: "The reason why a user was banned." + - duration: + desc: "The time period during which the ban message should be sent." + reason: + desc: "The reason why a user was banned." banmsgreset: - desc: "Resets ban message to default. If you want to completely disable ban messages, use `{0}banmsg -`" - args: + desc: Resets ban message to default. If you want to completely disable ban messages, use `{0}banmsg -` + ex: - "" + params: + - {} banprune: desc: |- Sets how many days of messages will be deleted when a user is banned. Only works if the user is banned via the .ban command or punishment. Allowed values: 0 - 7 - args: - - "3" + ex: + - 3 + params: + - days: + desc: "The number of days to retain messages for a banned user before they are automatically deleted." wait: - desc: "Used only as a startup command. Waits a certain number of milliseconds before continuing the execution of the following startup commands." - args: - - "3000" + desc: Used only as a startup command. Waits a certain number of milliseconds before continuing the execution of the following startup commands. + ex: + - 3000 + params: + - miliseconds: + desc: "The time period to pause for." warnexpire: - desc: "Gets or sets the number of days after which the warnings will be cleared automatically. This setting works retroactively. If you want to delete the warnings instead of clearing them, you can set the `--delete` optional parameter. Provide no parameter to see currently set expiry" - args: + desc: Gets or sets the number of days after which the warnings will be cleared automatically. This setting works retroactively. If you want to delete the warnings instead of clearing them, you can set the `--delete` optional parameter. Provide no parameter to see currently set expiry + ex: - "" - - "3" - - "6 --delete" + - 3 + - 6 --delete + params: + - {} + - days: + desc: "The number of days after which expired warnings will be automatically cleared from the system." + params: + desc: "The list of command-line options or flags that can be passed to customize the behavior of the function." warnclear: - desc: "Clears all warnings from a certain user. You can specify a number to clear a specific one." - args: + desc: Clears all warnings from a certain user. You can specify a number to clear a specific one. + ex: - "@PoorDude 3" - "@PoorDude" + params: + - user: + desc: "The user whose warnings are being cleared." + index: + desc: "The index of the warning to be cleared, or 0 to clear all warnings." + - userId: + desc: "The ID of the user whose warnings are being cleared." + index: + desc: "The index of the warning to be cleared, or 0 to clear all warnings." warnpunishlist: - desc: "Lists punishments for warnings." - args: + desc: Lists punishments for warnings. + ex: - "" + params: + - {} warnpunish: desc: "Sets a punishment for a certain number of warnings. You can specify a time string after 'Ban' or *'Mute' punishments to make it a temporary mute/ban. Provide no punishment to remove. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, AddRole, RemoveRoles" - args: - - "3" - - "5 Ban" - - "5 Mute 2d12h" - - "4 AddRole toxic 1h" + ex: + - 3 + - 5 Ban + - 5 Mute 2d12h + - 4 AddRole toxic 1h + params: + - number: + desc: "The number of warnings that will trigger the specified punishment." + _: + desc: "The role that will be added to the user's roles." + role: + desc: "The role that will be affected by the punishment." + time: + desc: "The duration of the temporary punishment." + - number: + desc: "The number of warnings that will trigger the specified punishment." + punish: + desc: "The type of action to take when the specified number of warnings is reached." + time: + desc: "The duration of the temporary punishment." + - number: + desc: "The number of warnings that will trigger the specified punishment." ping: - desc: "Ping the bot to see if there are latency issues." - args: + desc: Ping the bot to see if there are latency issues. + ex: - "" + params: + - {} time: - desc: "Shows the current time and timezone in the specified location." - args: - - "London, UK" + desc: Shows the current time and timezone in the specified location. + ex: + - London, UK + params: + - query: + desc: "The city or region for which to display the current time and timezone." shop: - desc: "Lists this server's administrators' shop. Paginated." - args: + desc: Lists this server's administrators' shop. Paginated. + ex: - "" - - "2" + - 2 + params: + - page: + desc: "The number of the page to retrieve from the list of administrators' shops." shopadd: - desc: "Adds an item to the shop by specifying type price and name. Available types are role and list. 90% of currency from each purchase will be received by the user who added the item to the shop." - args: - - "role 1000 Rich" + desc: "- Available types are role, list and command.\n- If the item is a role, specify a role id or a role name.\n- If the item is a command, specify the full command, replacing the user with %user% (for a mention) or %user.id% for user id.\n90% of currency from each purchase will be received by the user who added the item to the shop. " + ex: + - role 1000 Rich + - cmd 1000 .setrole %user% Rich + params: + - _: + desc: "The command to be executed when an item is purchased." + price: + desc: "The cost at which the item is available for purchase." + command: + desc: "The full command, replacing the user with %user% (for a mention) or %user.id% for user id. This allows users to specify custom" + - _: + desc: "The role that should be granted to users when they purchase this item." + price: + desc: "The cost at which the item is available for purchase." + role: + desc: "The ID or name of a predefined role in the system, used to specify the type of item being added to the shop." + - _: + desc: "The list of items to be added to the shop." + price: + desc: "The cost at which the item is available for purchase." + name: + desc: "The name of the role, command, or list being added to the shop." shopremove: - desc: "Removes an item from the shop by its ID." - args: - - "1" + desc: Removes an item from the shop by its ID. + ex: + - 1 + params: + - index: + desc: "The position in the list of items to remove." shopreq: - desc: "Sets a role which will be required to buy the item on the specified index. Specify only index to remove the requirement." - args: - - "2 Gamers" - - "2" + desc: Sets a role which will be required to buy the item on the specified index. Specify only index to remove the requirement. + ex: + - 2 Gamers + - 2 + params: + - itemIndex: + desc: "The index of an item in the inventory that must be purchased before this one can be bought." + role: + desc: "The role that must be assigned to the player in order to purchase the item." shopchangename: - desc: "Change the name of a shop entry at the specified index. Only works for non-role items" - args: - - "3 Cool stuff" + desc: Change the name of a shop entry at the specified index. Only works for non-role items + ex: + - 3 Cool stuff + params: + - index: + desc: "The index of the shop entry to modify." + newName: + desc: "The new name given to the shop item, which will replace its original name." shopchangeprice: - desc: "Change the price of a shop entry at the specified index. Specify the index of the entry, followed by the price" - args: - - "1 500" + desc: Change the price of a shop entry at the specified index. Specify the index of the entry, followed by the price + ex: + - 1 500 + params: + - index: + desc: "The index of the entry to be updated with the new price." + price: + desc: "The new price for the item being updated." shopswap: - desc: "Swap the index of two shop entries" - args: - - "1 5" + desc: Swap the index of two shop entries + ex: + - 1 5 + params: + - index1: + desc: "The position in the list where a swap operation should take place." + index2: + desc: "The second index of the entry to swap." shopmove: - desc: "Moves the shop entry from the current index to a new one" - args: - - "2 4" + desc: Moves the shop entry from the current index to a new one + ex: + - 2 4 + params: + - fromIndex: + desc: "The starting position in the list that contains the item to be moved." + toIndex: + desc: "The position in the list where the shop entry should be moved." buy: - desc: "Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you." - args: - - "2" + desc: Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you. + ex: + - 2 + params: + - index: + desc: "The index of the item to be purchased in the shop's inventory." gamevoicechannel: - desc: "Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server." - args: + desc: Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server. + ex: - "" + params: + - {} shoplistadd: - desc: "Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked." - args: - - "1 Uni-que-Steam-Key" + desc: Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked. + ex: + - 1 Uni-que-Steam-Key + params: + - index: + desc: "The position at which to insert the new item in the list of items for sale." + itemText: + desc: "The description or name of the item being added to the list." globalcommand: - desc: "Toggles whether a command can be used on any server." - args: + desc: Toggles whether a command can be used on any server. + ex: - "{0}stats" + params: + - cmd: + desc: "The type of command or expression being toggled." globalmodule: - desc: "Toggles whether a module can be used on any server." - args: - - "nsfw" + desc: Toggles whether a module can be used on any server. + ex: + - nsfw + params: + - module: + desc: "The type of module or configuration information being toggled." globalpermlist: - desc: "Lists global permissions set by the bot owner." - args: + desc: Lists global permissions set by the bot owner. + ex: - "" + params: + - {} resetglobalperms: - desc: "Resets global permissions set by bot owner." - args: + desc: Resets global permissions set by bot owner. + ex: - "" + params: + - {} prefix: - desc: "Sets this server's prefix for all bot commands. Provide no parameters to see the current server prefix. **Setting prefix requires Administrator server permission.**" - args: - - "+" + desc: Sets this server's prefix for all bot commands. Provide no parameters to see the current server prefix. **Setting prefix requires Administrator server permission.** + ex: + - + + params: + - {} + - _: + desc: "The default text that is prepended to all bot command names." + newPrefix: + desc: "The new prefix for all bot commands, allowing users to interact with the bot using a custom keyword." + - toSet: + desc: "The new prefix for all bot commands, allowing users to interact with the bot using a custom keyword." defprefix: - desc: "Sets bot's default prefix for all bot commands. Provide no parameters to see the current default prefix. This will not change this server's current prefix." - args: - - "+" + desc: Sets bot's default prefix for all bot commands. Provide no parameters to see the current default prefix. This will not change this server's current prefix. + ex: + - + + params: + - toSet: + desc: "The new prefix to set as the default for all bot commands." verboseerror: - desc: "Toggles or sets whether the bot should print command errors when a command is incorrectly used." - args: + desc: Toggles or sets whether the bot should print command errors when a command is incorrectly used. + ex: - "" - - "false" + - false + params: + - newstate: + desc: "The state that determines whether error messages are displayed to the user." streamrolekeyword: - desc: "Sets keyword which is required in the stream's title in order for the streamrole to apply. Provide no keyword in order to reset." - args: + desc: Sets keyword which is required in the stream's title in order for the streamrole to apply. Provide no keyword in order to reset. + ex: - "" - - "PUBG" + - PUBG + params: + - keyword: + desc: "The keyword that must be present in a stream's title for the associated role to take effect." streamroleblacklist: - desc: "Adds or removes a blacklisted user. Blacklisted users will never receive the stream role." - args: - - "add @Someone#1234" - - "rem @Someone#1234" + desc: Adds or removes a blacklisted user. Blacklisted users will never receive the stream role. + ex: + - add @Someone#1234 + - rem @Someone#1234 + params: + - action: + desc: "The type of operation to perform on the blacklisted user, either adding them to the list or removing them from it." + user: + desc: "The ID of the user who is being added or removed from the blacklist." streamrolewhitelist: - desc: "Adds or removes a whitelisted user. Whitelisted users will receive the stream role even if they don't have the specified keyword in their stream title." - args: - - "add @Someone#1234" - - "rem @Someone#1234" + desc: Adds or removes a whitelisted user. Whitelisted users will receive the stream role even if they don't have the specified keyword in their stream title. + ex: + - add @Someone#1234 + - rem @Someone#1234 + params: + - action: + desc: "The type of operation to perform on the whitelist, either adding or removing a user." + user: + desc: "The user to be added or removed from the whitelist for receiving the stream role." config: desc: |- Gets or sets configuration values. @@ -1839,167 +3302,304 @@ config: Provide config name to see all properties in that configuration and their values. Provide config name and property name to see that property's description and value. Provide config name, property name and value to set that property to the new value. - args: + ex: - "" - - "bot" - - "bot color.ok" - - "bot color.ok ff0000" + - bot + - bot color.ok + - bot color.ok ff0000 + params: + - name: + desc: "The name of a specific configuration section or category. It is used as an identifier to access its properties and values." + prop: + desc: "The name of a specific configuration property or section. It is used to retrieve or modify its settings." + value: + desc: "The new value for a specific configuration property." configreload: - desc: "Reloads specified configuration" - args: - - "bot" - - "gambling" -nsfwtagblacklist: - desc: "Toggles whether the tag is blacklisted or not in nsfw searches. Provide no parameters to see the list of blacklisted tags." - args: - - "poop" + desc: Reloads specified configuration + ex: + - bot + - gambling + params: + - name: + desc: "The path or identifier of the configuration file or section to reload." experience: - desc: "Shows your xp stats. Specify the user to show that user's stats instead." - args: + desc: Shows your xp stats. Specify the user to show that user's stats instead. + ex: - "" - "@someguy" + params: + - user: + desc: "The ID or handle of a player whose XP statistics are being displayed." xptemplatereload: - desc: "Reloads the xp template file. Xp template file allows you to customize the position and color of elements on the `{0}xp` card." - args: + desc: Reloads the xp template file. Xp template file allows you to customize the position and color of elements on the `{0}xp` card. + ex: - "" + params: + - {} xpexclusionlist: - desc: "Shows the roles and channels excluded from the XP system on this server, as well as whether the whole server is excluded." - args: + desc: Shows the roles and channels excluded from the XP system on this server, as well as whether the whole server is excluded. + ex: - "" + params: + - {} xpexclude: - desc: "Exclude a channel, role or current server from the xp system." - args: - - "Role Excluded-Role" - - "Server" + desc: Exclude a channel, role or current server from the xp system. + ex: + - Role Excluded-Role + - Server + params: + - _: + desc: "The ID of the server to exclude from the XP system." + - _: + desc: "The role that should not receive XP rewards." + role: + desc: "The role that should not receive XP rewards." + - _: + desc: "The ID of the channel to exclude from XP tracking." + channel: + desc: "The ID of the channel to exclude from XP tracking." xpnotify: - desc: "Sets how the bot should notify you when you get a `server` or `global` level. This is a personal setting and affects only how you receive Global or Server level-up notifications. You can set `dm` (for the bot to send you a direct message), `channel` (to get notified in the channel you sent the last message in) or `none` to disable." - args: - - "global dm" - - "server channel" + desc: Sets how the bot should notify you when you get a `server` or `global` level. This is a personal setting and affects only how you receive Global or Server level-up notifications. You can set `dm` (for the bot to send you a direct message), `channel` (to get notified in the channel you sent the last message in) or `none` to disable. + ex: + - global dm + - server channel + params: + - {} + - place: + desc: "The location where notifications should be sent, such as a specific channel or DM." + type: + desc: "The location where notifications for server and global level-ups should be sent." xpleveluprewards: - desc: "Shows currently set level up rewards." - args: + desc: Shows currently set level up rewards. + ex: - "" + params: + - page: + desc: "The page number for which the level up rewards are being displayed." xprewsreset: - desc: "Resets all currently set xp level up rewards." - args: + desc: Resets all currently set xp level up rewards. + ex: - "" + params: + - {} xprolereward: desc: |- Add or remove a role from the user who reaches the specified level. Provide no action and role name in order to remove the role reward. - args: - - "1 rm Newbie" - - "3 add Social" - - "5 add Member" - - "5" + ex: + - 1 rm Newbie + - 3 add Social + - 5 add Member + - 5 + params: + - level: + desc: "The level at which the user should be rewarded with the role." + - level: + desc: "The level at which the user should be rewarded with the role." + action: + desc: "The type of operation to perform on the user's roles, either adding or removing one." + role: + desc: "The type of authority or privilege being granted or revoked." xpcurrencyreward: - desc: "Sets a currency reward on a specified level. Provide no amount in order to remove the reward." - args: - - "3 50" + desc: Sets a currency reward on a specified level. Provide no amount in order to remove the reward. + ex: + - 3 50 + params: + - level: + desc: "The level at which the currency reward is set or removed." + amount: + desc: "The amount of currency to be rewarded when completing this level." xpleaderboard: - desc: "Shows current server's xp leaderboard." - args: + desc: Shows current server's xp leaderboard. + ex: - "" + params: + - params: + desc: "The list of player names or IDs to filter the leaderboard by." + - page: + desc: "The number of pages to display in the leaderboard." + params: + desc: "The list of player names or IDs to filter the leaderboard by." xpgloballeaderboard: - desc: "Shows the global xp leaderboard." - args: + desc: Shows the global xp leaderboard. + ex: - "" + params: + - page: + desc: "The current page number for displaying the leaderboard results." xpadd: - desc: "Adds server XP to a single user or all users role on this server. This does not affect their global ranking. You can use negative values." - args: - - "100 @Someone" - - "500 SomeRoleName" + desc: Adds server XP to a single user or all users role on this server. This does not affect their global ranking. You can use negative values. + ex: + - 100 @Someone + - 500 SomeRoleName + params: + - amount: + desc: "The total experience points to be added." + role: + desc: "The type of account or group that the XP is being added to, such as an administrator or moderator." + - amount: + desc: "The total experience points to be added." + userId: + desc: "The ID of the player whose experience points are being modified." + - amount: + desc: "The total experience points to be added." + user: + desc: "The ID of the user whose XP is being added or modified." clubcreate: - desc: "Creates a club. You must be at least level 5 and not be in the club already." - args: - - "My Brand New Club" + desc: Creates a club. You must be at least level 5 and not be in the club already. + ex: + - My Brand New Club + params: + - clubName: + desc: "The name of the new club being created." clubtransfer: - desc: "Transfers the ownership of the club to another member of the club." - args: + desc: Transfers the ownership of the club to another member of the club. + ex: - "@Someone" + params: + - newOwner: + desc: "The user who will take over the management of the club." clubinformation: - desc: "Shows information about the club." - args: - - "My Brand New Club#23" + desc: Shows information about the club. + ex: + - My Brand New Club#23 + params: + - user: + desc: "The identity of the person requesting the club information." + - clubName: + desc: "The name of a specific club being queried for information." clubapply: - desc: "Apply to join a club. You must meet that club's minimum level requirement, and not be on its ban list." - args: - - "My Brand New Club#23" + desc: Apply to join a club. You must meet that club's minimum level requirement, and not be on its ban list. + ex: + - My Brand New Club#23 + params: + - clubName: + desc: "The name of the club you are trying to join." clubaccept: - desc: "Accept a user who applied to your club." - args: - - "user#1337" + desc: Accept a user who applied to your club. + ex: + - user#1337 + params: + - user: + desc: "The identity of the person being accepted into the club." + - userName: + desc: "The username of the person being accepted into the club." clubreject: - desc: "Reject a user who applied to your club." - args: - - "user#1337" + desc: Reject a user who applied to your club. + ex: + - user#1337 + params: + - user: + desc: "The identity of the person being rejected from the club." + - userName: + desc: "The username of the user being rejected from the club." clubleave: - desc: "Leaves the club you're currently in." - args: + desc: Leaves the club you're currently in. + ex: - "" + params: + - {} clubdisband: - desc: "Disbands the club you're the owner of. This action is irreversible." - args: + desc: Disbands the club you're the owner of. This action is irreversible. + ex: - "" + params: + - {} clubkick: - desc: "Kicks the user from the club. You must be the club owner. They will be able to apply again." - args: - - "user#1337" + desc: Kicks the user from the club. You must be the club owner. They will be able to apply again. + ex: + - user#1337 + params: + - user: + desc: "The current member being kicked from the club." + - userName: + desc: "The username of the user to be kicked from the club." clubban: - desc: "Bans the user from the club. You must be the club owner. They will not be able to apply again." - args: - - "user#1337" + desc: Bans the user from the club. You must be the club owner. They will not be able to apply again. + ex: + - user#1337 + params: + - user: + desc: "The user who is being banned." + - userName: + desc: "The username of the user to ban from the club." clubunban: - desc: "Unbans the previously banned user from the club. You must be the club owner." - args: - - "user#1337" + desc: Unbans the previously banned user from the club. You must be the club owner. + ex: + - user#1337 + params: + - user: + desc: "The user who was previously banned is being restored to membership in the club." + - userName: + desc: "The username of the user being unbanned from the club." clubdescription: - desc: "Sets the club description. Maximum 150 characters. Club owner only." - args: - - "This is the best club please join." + desc: Sets the club description. Maximum 150 characters. Club owner only. + ex: + - This is the best club please join. + params: + - desc: + desc: "The brief summary of the club's purpose and activities." clubicon: - desc: "Sets the club icon." - args: - - "https://i.imgur.com/htfDMfU.png" + desc: Sets the club icon. + ex: + - https://i.imgur.com/htfDMfU.png + params: + - url: + desc: "The URL of an image file to use as the club icon." clubapps: - desc: "Shows the list of users who have applied to your club. Paginated. You must be club owner to use this command." - args: - - "2" + desc: Shows the list of users who have applied to your club. Paginated. You must be club owner to use this command. + ex: + - 2 + params: + - page: + desc: "The number of pages to display in the result set." clubbans: - desc: "Shows the list of users who have banned from your club. Paginated. You must be club owner to use this command." - args: - - "2" + desc: Shows the list of users who have banned from your club. Paginated. You must be club owner to use this command. + ex: + - 2 + params: + - page: + desc: "The number of pages to retrieve in the result set." clubleaderboard: - desc: "Shows club rankings on the specified page." - args: - - "2" + desc: Shows club rankings on the specified page. + ex: + - 2 + params: + - page: + desc: "The page number to display, allowing users to navigate through multiple pages of club rankings." clubadmin: - desc: "Assigns (or unassigns) staff role to the member of the club. Admins can ban, kick and accept applications." - args: + desc: Assigns (or unassigns) staff role to the member of the club. Admins can ban, kick and accept applications. + ex: - "@Someone" -autoboobs: - desc: "Posts a boobs every X seconds. 20 seconds minimum. Provide no parameters to disable." - args: - - "30" - - "" -autobutts: - desc: "Posts a butt every X seconds. 20 seconds minimum. Provide no parameters to disable." - args: - - "30" - - "" + params: + - toAdmin: + desc: "The user who is being assigned or unassigned as an admin." eightball: - desc: "Ask the 8ball a yes/no question." - args: - - "Is b1nzy a nice guy?" + desc: Ask the 8ball a yes/no question. + ex: + - Is b1nzy a nice guy? + params: + - question: + desc: "The user's inquiry or query that they want the 8ball to answer." ytuploadnotif: desc: |- Subscribe to a youtube channel's upload rss feed. Shortcut for `.feed https://www.youtube.com/feeds/videos.xml?channel_id=%3Cyoutube_channel_id` You can optionally specify a message which will be posted with an update. - args: - - "https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow" - - "https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow New video is posted" + ex: + - https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow + - https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow New video is posted + params: + - url: + desc: "The URL of the YouTube channel's RSS feed to subscribe to." + message: + desc: "The text to be displayed in the notification when an upload is detected." + - url: + desc: "The URL of the YouTube channel's RSS feed to subscribe to." + channel: + desc: "The ID of the YouTube channel to subscribe to notifications for, or the text channel where updates will be posted." + message: + desc: "The text to be displayed in the notification when an upload is detected." feed: desc: |- Subscribes to a feed. @@ -2008,313 +3608,596 @@ feed: All feeds must have unique URLs. Set a channel as a second optional parameter to specify where to send the updates. You can optionally specify a message after the channel name which will be posted with an update. - args: - - "https://blog.playstation.com/feed/" + ex: + - https://blog.playstation.com/feed/ - "https://blog.playstation.com/feed/ #updates" - "https://blog.playstation.com/feed/ #updates New playstation rss feed post!" + params: + - url: + desc: "The URL of the feed to subscribe to, used to retrieve new content for posting." + message: + desc: "The text to be sent in the update post." + - url: + desc: "The URL of the feed to subscribe to, used to retrieve new content for posting." + channel: + desc: "The channel where updates will be sent." + message: + desc: "The text to be sent in the update post." feedremove: - desc: "Stops tracking a feed on the given index. Use `{0}feeds` command to see a list of feeds and their indexes." - args: - - "3" + desc: Stops tracking a feed on the given index. Use `{0}feeds` command to see a list of feeds and their indexes. + ex: + - 3 + params: + - index: + desc: "The index of the feed to stop tracking." feedlist: - desc: "Shows the list of feeds you've subscribed to on this server." - args: + desc: Shows the list of feeds you've subscribed to on this server. + ex: - "" + params: + - page: + desc: "The number of items to display per page." expredit: - desc: "Edits the expression's response given its ID." - args: - - "123 I'm a magical girl" + desc: Edits the expression's response given its ID. + ex: + - 123 I'm a magical girl + params: + - id: + desc: "The unique identifier for the expression being edited." + message: + desc: "The text that will replace the original response in the expression's output." say: - desc: "Bot will send the message you typed in the specified channel. If you omit the channel name, it will send the message in the current channel. Supports embeds." - args: - - "hi" + desc: Bot will send the message you typed in the specified channel. If you omit the channel name, it will send the message in the current channel. Supports embeds. + ex: + - hi - "#chat hi" + params: + - channel: + desc: "The destination where the bot will send the message." + message: + desc: "The message to be sent by the bot. It can contain rich text formatting." + - message: + desc: "The message to be sent by the bot. It can contain rich text formatting." sqlexec: - desc: "Executes provided sql command and returns the number of affected rows. Dangerous." - args: - - "UPDATE DiscordUser SET CurrencyAmount=CurrencyAmount+1234" + desc: Executes provided sql command and returns the number of affected rows. Dangerous. + ex: + - UPDATE DiscordUser SET CurrencyAmount=CurrencyAmount+1234 + params: + - sql: + desc: "The SQL query string to execute, which should be carefully crafted to avoid any potential security risks." sqlselect: - desc: "Executes provided sql query and returns the results. Dangerous." - args: - - "SELECT * FROM DiscordUser LIMIT 5" + desc: Executes provided sql query and returns the results. Dangerous. + ex: + - SELECT * FROM DiscordUser LIMIT 5 + params: + - sql: + desc: "The SQL query string that is executed by the function." +sqlselectcsv: + desc: Executes provided sql query and returns the results in a csv file. Dangerous. + ex: + - SELECT * FROM DiscordUser LIMIT 5 + params: + - sql: + desc: "The SQL query string that specifies the data to be retrieved and formatted into a CSV file." deletewaifus: - desc: "Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables." - args: + desc: Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables. + ex: - "" + params: + - {} deletewaifu: - desc: "Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables for the specified user. Also makes specified user's waifus free." - args: + desc: Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables for the specified user. Also makes specified user's waifus free. + ex: - "" + params: + - user: + desc: "The ID of the user whose waifus are to be deleted and set free." + - userId: + desc: "The ID of the user whose waifus are to be deleted and set free." deletecurrency: - desc: "Deletes everything from Currency and CurrencyTransactions." - args: + desc: Deletes everything from Currency and CurrencyTransactions. + ex: - "" + params: + - {} deleteplaylists: - desc: "Deletes everything from MusicPlaylists." - args: + desc: Deletes everything from MusicPlaylists. + ex: - "" + params: + - {} deletexp: - desc: "Deletes everything from UserXpStats, Clubs and sets users' TotalXP to 0." - args: + desc: Deletes everything from UserXpStats, Clubs and sets users' TotalXP to 0. + ex: - "" + params: + - {} discordpermoverride: - desc: "Overrides required user permissions that the command has with the specified ones. You can only use server-level permissions. This action will make the bot ignore user permission requirements which command has by default. Provide no permissions to reset to default." - args: + desc: Overrides required user permissions that the command has with the specified ones. You can only use server-level permissions. This action will make the bot ignore user permission requirements which command has by default. Provide no permissions to reset to default. + ex: - "{0}prune ManageMessages BanMembers" - "{0}prune" + params: + - cmd: + desc: "The command or expression that this override applies to, allowing you to customize permissions for specific commands or actions within your Discord server." + perms: + desc: "The set of permissions that should be used instead of the command's default permissions." discordpermoverridelist: - desc: "Lists all discord permission overrides on this server." - args: + desc: Lists all discord permission overrides on this server. + ex: - "" + params: + - page: + desc: "The number of the page to display in the list of permission overrides." discordpermoverridereset: - desc: "Resets ALL currently set discord permission overrides on this server. This will make all commands have default discord permission requirements." - args: + desc: Resets ALL currently set discord permission overrides on this server. This will make all commands have default discord permission requirements. + ex: - "" + params: + - {} rafflecur: - desc: "Starts or joins a currency raffle with a specified amount. Users who join the raffle will lose the amount of currency specified and add it to the pot. After 30 seconds, random winner will be selected who will receive the whole pot. There is also a `mixed` mode in which the users will be able to join the game with any amount of currency, and have their chances be proportional to the amount they've bet." - args: - - "20" - - "mixed 15" + desc: Starts or joins a currency raffle with a specified amount. Users who join the raffle will lose the amount of currency specified and add it to the pot. After 30 seconds, random winner will be selected who will receive the whole pot. There is also a `mixed` mode in which the users will be able to join the game with any amount of currency, and have their chances be proportional to the amount they've bet. + ex: + - 20 + - mixed 15 + params: + - _: + desc: 'The type of game mode to use, either "fixed" or "mixed".' + amount: + desc: "The minimum or maximum amount of currency that can be used for betting." + - amount: + desc: "The minimum or maximum amount of currency that can be used for betting." + mixed: + desc: 'The parameter determines whether the raffle operates in "fixed" or "proportional" mode.' rip: - desc: "Shows the inevitable fate of someone." - args: + desc: Shows the inevitable fate of someone. + ex: - "@Someone" + params: + - usr: + desc: "The user whose fate is being revealed." autodisconnect: - desc: "Toggles whether the bot should disconnect from the voice channel once it's done playing all of the songs and queue repeat option is set to `none`." - args: + desc: Toggles whether the bot should disconnect from the voice channel once it's done playing all of the songs and queue repeat option is set to `none`. + ex: - "" + params: + - {} timelyset: - desc: "Sets the 'timely' currency allowance amount for users. Second parameter is period in hours, default is 24 hours." - args: - - "100" - - "50 12" + desc: Sets the 'timely' currency allowance amount for users. Second parameter is period in hours, default is 24 hours. + ex: + - 100 + - 50 12 + params: + - amount: + desc: "The maximum amount of currency that can be spent within a given time frame." + period: + desc: "The time period within which a user's timely currency allowance can be used." timely: - desc: "Use to claim your 'timely' currency. Bot owner has to specify the amount and the period on how often you can claim your currency." - args: + desc: Use to claim your 'timely' currency. Bot owner has to specify the amount and the period on how often you can claim your currency. + ex: - "" + params: + - {} timelyreset: - desc: "Resets all user timeouts on `{0}timely` command." - args: + desc: Resets all user timeouts on `{0}timely` command. + ex: - "" + params: + - {} crypto: - desc: "Shows basic stats about a cryptocurrency from coinmarketcap.com. You can use either a name or an abbreviation of the currency." - args: - - "btc" - - "bitcoin" + desc: Shows basic stats about a cryptocurrency from coinmarketcap.com. You can use either a name or an abbreviation of the currency. + ex: + - btc + - bitcoin + params: + - name: + desc: "The symbol or abbreviated name of the cryptocurrency to retrieve statistics for." stock: - desc: "Shows basic information about a stock. You can use a symbol or company name" - args: - - "tsla" - - "advanced micro devices" - - "amd" + desc: Shows basic information about a stock. You can use a symbol or company name + ex: + - tsla + - advanced micro devices + - amd + params: + - query: + desc: "The ticker symbol or company name used to retrieve the stock's information." rolelevelreq: - desc: "Set a level requirement on a self-assignable role." - args: - - "5 SomeRole" + desc: Set a level requirement on a self-assignable role. + ex: + - 5 SomeRole + params: + - level: + desc: "The minimum level required for the role." + role: + desc: "The role that must be assigned before the user can assign this one." massban: - desc: "Bans multiple users at once. Specify a space separated list of IDs of users who you wish to ban." - args: - - "123123123 3333333333 444444444" + desc: Bans multiple users at once. Specify a space separated list of IDs of users who you wish to ban. + ex: + - 123123123 3333333333 444444444 + params: + - userStrings: + desc: "The list of user IDs to ban, provided as a comma-separated string." masskill: - desc: "Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away." - args: - - "BadPerson#1234 Toxic person" + desc: Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away. + ex: + - BadPerson#1234 Toxic person + params: + - people: + desc: "The list of user IDs or usernames to ban from the server and blacklist from the bot." pathofexile: - desc: "Searches characters for a given Path of Exile account. May specify league name to filter results." - args: + desc: Searches characters for a given Path of Exile account. May specify league name to filter results. + ex: - '"Zizaran"' + params: + - usr: + desc: "The username or email address associated with the Path of Exile account being searched." + league: + desc: "The league in which the character is playing, allowing users to focus on a specific game mode or event." + page: + desc: "The number of pages to retrieve from the API." pathofexileleagues: - desc: "Returns a list of the main Path of Exile leagues." - args: + desc: Returns a list of the main Path of Exile leagues. + ex: - "" + params: + - {} pathofexilecurrency: - desc: "Returns the chaos equivalent of a given currency or exchange rate between two currencies." - args: - - 'Standard "Mirror of Kalandra"' + desc: Returns the chaos equivalent of a given currency or exchange rate between two currencies. + ex: + - Standard "Mirror of Kalandra" + params: + - leagueName: + desc: 'The name of the league in which the currency is used, such as "Harbinger" or "Delve".' + currencyName: + desc: "The type of currency being converted." + convertName: + desc: "The type of currency being converted from or to." rollduel: - desc: "Challenge someone to a roll duel by specifying the amount and the user you wish to challenge as the parameters. To accept the challenge, just specify the name of the user who challenged you, without the amount." - args: - - "50 @Someone" + desc: Challenge someone to a roll duel by specifying the amount and the user you wish to challenge as the parameters. To accept the challenge, just specify the name of the user who challenged you, without the amount. + ex: + - 50 @Someone - "@Challenger" -reactionroleadd: + params: + - u: + desc: "The user being challenged or accepting the challenge." + - amount: + desc: "The stakes for the roll duel." + u: + desc: "The user being challenged or accepting the challenge." +reroadd: desc: |- Specify a message id, emote and a role name to have the bot assign the specified role to the user who reacts to the specified message (in this channel) with the specified emoji. You can optionally specify an exclusivity group. Default is group 0 which is non-exclusive. Other groups are exclusive. Exclusive groups will let the user only have one of the roles specified in that group. You can optionally specify a level requirement after a group. Users who don't meet the level requirement will not receive the role. You can have up to 50 reaction roles per server in total. - args: - - 971276352684691466 😊 gamer - - 971276352684691466 😢 emo 1 - - 971276352684691466 🤔 philosopher 5 20 - - 971276352684691466 👨 normie 5 20 -reactionroleslist: - desc: "Lists all ReactionRole messages on this server with their message ids. Clicking/Tapping message ids will send you to that message." - args: + ex: + - "971276352684691466 😊 gamer" + - "971276352684691466 😢 emo 1" + - "971276352684691466 🤔 philosopher 5 20" + - "971276352684691466 👨 normie 5 20" + params: + - messageId: + desc: "The ID of the message that users must react to in order to receive the specified role." + emoteStr: + desc: "The emoji used by users to react and trigger the role assignment." + role: + desc: "The role that is assigned to users who react with the specified emoji." + group: + desc: "The number of the exclusivity group." + levelReq: + desc: "The minimum amount of experience points required for a user to be eligible for the assigned role." +rerolist: + desc: Lists all ReactionRole messages on this server with their message ids. Clicking/Tapping message ids will send you to that message. + ex: - "" -reactionrolesremove: - desc: "Remove all reaction roles from message specified by the id" - args: - - "971276352684691466" -reactionrolesdeleteall: - desc: "Deletes all reaction roles on the server. This action is irreversible." - args: + params: + - page: + desc: "The number of the page to retrieve, starting from 1." +reroremove: + desc: Remove all reaction roles from message specified by the id + ex: + - 971276352684691466 + params: + - messageId: + desc: "The ID of a specific message that contains reaction roles to be removed." +rerodeleteall: + desc: Deletes all reaction roles on the server. This action is irreversible. + ex: - "" -reactionrolestransfer: - desc: "Transfers reaction roles from one message to another by specifying their ids. If the target message has reaction roles specified already, the reaction roles will be MERGED, not overwritten." - args: - - "971276352684691466 971427748448964628" + params: + - {} +rerotransfer: + desc: Transfers reaction roles from one message to another by specifying their ids. If the target message has reaction roles specified already, the reaction roles will be MERGED, not overwritten. + ex: + - 971276352684691466 971427748448964628 + params: + - fromMessageId: + desc: "The ID of the original message containing the reaction roles to be transferred." + toMessageId: + desc: "The ID of the target message where the reaction roles should be transferred." blackjack: - desc: "Start or join a blackjack game. You must specify the amount you're betting. Use `{0}hit`, `{0}stand` and `{0}double` commands to play. Game is played with 4 decks. Dealer hits on soft 17 and wins draws." - args: - - "50" + desc: Start or join a blackjack game. You must specify the amount you're betting. Use `{0}hit`, `{0}stand` and `{0}double` commands to play. Game is played with 4 decks. Dealer hits on soft 17 and wins draws. + ex: + - 50 + params: + - amount: + desc: "The minimum bet required to participate in the game." hit: - desc: "In the blackjack game, ask the dealer for an extra card." - args: + desc: In the blackjack game, ask the dealer for an extra card. + ex: - "" + params: + - {} stand: - desc: "Finish your turn in the blackjack game." - args: + desc: Finish your turn in the blackjack game. + ex: - "" + params: + - {} double: - desc: "In the blackjack game, double your bet in order to receive exactly one more card, and your turn ends." - args: + desc: In the blackjack game, double your bet in order to receive exactly one more card, and your turn ends. + ex: - "" + params: + - {} xpreset: - desc: "Resets specified user's XP, or the XP of all users in the server. You can't reverse this action." - args: + desc: Resets specified user's XP, or the XP of all users in the server. You can't reverse this action. + ex: - "@Someone" - "" + params: + - user: + desc: "The ID of a specific guild member whose XP is being reset." + - userId: + desc: "The ID of a specific player whose experience points are being reset." + - {} xpshop: - desc: "Access the xp shop (if enabled). You can purchase either xp card frames or backgrounds. You can optionally provide a page number" - args: - - "bgs" - - "frames" - - "bgs 3" + desc: Access the xp shop (if enabled). You can purchase either xp card frames or backgrounds. You can optionally provide a page number + ex: + - bgs + - frames + - bgs 3 + params: + - {} + - type: + desc: "The type of item to be purchased, such as an XP card frame or background." + page: + desc: "The page number to display in the XP shop." xpshopbuy: - desc: "Buy an item from the xp shop by specifying the type and the key of the item." - args: - - "bg open_sea" - - "fr gold" + desc: Buy an item from the xp shop by specifying the type and the key of the item. + ex: + - bg open_sea + - fr gold + params: + - type: + desc: "The type of item to purchase, such as a skill or a cosmetic." + key: + desc: "The unique identifier for the item being purchased." xpshopuse: - desc: "Use a previously purchased item from the xp shop by specifying the type and the key of the item." - args: - - "bg synth" - - "fr default" + desc: Use a previously purchased item from the xp shop by specifying the type and the key of the item. + ex: + - bg synth + - fr default + params: + - type: + desc: "The type of item to be used, such as an experience point or a skill upgrade." + key: + desc: "The unique identifier for the item in the XP shop that you want to use." bible: - desc: "Shows bible verse. You need to supply book name and chapter:verse" - args: - - "genesis 3:19" + desc: Shows bible verse. You need to supply book name and chapter:verse + ex: + - genesis 3:19 + params: + - book: + desc: "The name of the biblical book being referenced." + chapterAndVerse: + desc: "The reference to a specific passage in the Bible, such as 'Genesis 3:15'" edit: - desc: "Edits bot's message, you have to specify message ID and new text. You can optionally specify target channel. Supports embeds." - args: - - "7479498384 Hi :^)" + desc: Edits bot's message, you have to specify message ID and new text. You can optionally specify target channel. Supports embeds. + ex: + - 7479498384 Hi :^) - "#other-channel 771562360594628608 New message!" - '#other-channel 771562360594628608 {{"description":"hello"}}' + params: + - messageId: + desc: "The unique identifier of the message being edited." + text: + desc: "The new text content of the edited message." + - channel: + desc: "The target channel where the edited message will be sent or updated in." + messageId: + desc: "The unique identifier of the message being edited." + text: + desc: "The new text content of the edited message." delete: - desc: "Deletes a single message given the channel and message ID. If channel is ommited, message will be searched for in the current channel. You can also specify time parameter after which the message will be deleted (up to 7 days). This timer won't persist through bot restarts." - args: + desc: Deletes a single message given the channel and message ID. If channel is ommited, message will be searched for in the current channel. You can also specify time parameter after which the message will be deleted (up to 7 days). This timer won't persist through bot restarts. + ex: - "#chat 771562360594628608" - - "771562360594628608" - - "771562360594628608 5m" + - 771562360594628608 + - 771562360594628608 5m + params: + - messageId: + desc: "The unique identifier of a specific message within a channel, used to target the deletion operation." + time: + desc: "The duration after which the message should be automatically deleted." + - channel: + desc: "The channel where the message is located or should be searched for." + messageId: + desc: "The unique identifier of a specific message within a channel, used to target the deletion operation." + time: + desc: "The duration after which the message should be automatically deleted." roleid: - desc: "Shows the id of the specified role." - args: - - "Some Role" -nsfwtoggle: - desc: "Toggles the NSFW parameter of the current text channel." - args: + desc: Shows the id of the specified role. + ex: + - Some Role + params: + - role: + desc: "The role that is being referenced." +agerestricttoggle: + desc: Toggles whether the current channel is age-restricted. + ex: - "" + params: + - {} economy: - desc: "Breakdown of the current state of the bot's economy. Updates every 3 minutes." - args: + desc: Breakdown of the current state of the bot's economy. Updates every 3 minutes. + ex: - "" + params: + - {} purgeuser: - desc: "Purge user from the database completely. This includes currency, xp, clubs that user owns, waifu info" - args: + desc: Purge user from the database completely. This includes currency, xp, clubs that user owns, waifu info + ex: - "@Oblivion" + params: + - userId: + desc: "The ID of the user to be purged from the system." + - user: + desc: "The user account being purged." imageonlychannel: - desc: |- - Toggles whether the channel only allows images. - Users who send more than a few non-image messages will be banned from using the channel. - args: + desc: "Toggles whether the channel only allows images.\nUsers who send more than a few non-image messages will be banned from using the channel. " + ex: - "" + params: + - time: + desc: "The amount of time before banning users for sending non-image messages." linkonlychannel: - desc: |- - Toggles whether the channel only allows links. - Users who send more than a few non-link messages will be banned from using the channel. - args: + desc: "Toggles whether the channel only allows links.\nUsers who send more than a few non-link messages will be banned from using the channel. " + ex: - "" + params: + - time: + desc: "The amount of time before a user is banned for sending non-link messages." coordreload: - desc: "Reloads coordinator config" - args: + desc: Reloads coordinator config + ex: - "" + params: + - {} showembed: - desc: "Prints the json equivalent of the embed of the message specified by its Id." - args: - - "820022733172121600" + desc: Prints the json equivalent of the embed of the message specified by its Id. + ex: + - 820022733172121600 - "#some-channel 820022733172121600" + params: + - messageId: + desc: "The ID of a message that contains an embed to be displayed as JSON." + - ch: + desc: "The channel where the message is located that will be used for the embed to be printed as JSON." + messageId: + desc: "The ID of a message that contains an embed to be displayed as JSON." deleteemptyservers: - desc: "Deletes all servers in which the bot is the only member." - args: + desc: Deletes all servers in which the bot is the only member. + ex: - "" + params: + - {} marmaladeload: desc: |- Loads a marmalade with the specified name from the data/marmalades/ folder. Provide no name to see the list of loadable marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) - args: - - "mycoolmarmalade" + ex: + - mycoolmarmalade - "" + params: + - name: + desc: "The name of a pre-existing marmalade to load." marmaladeunload: desc: |- Unloads the previously loaded marmalade. Provide no name to see the list of unloadable marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) - args: - - "mycoolmarmalade" + ex: + - mycoolmarmalade - "" + params: + - name: + desc: "The name of a specific marmalade to be unloaded." marmaladeinfo: desc: |- Shows information about the specified marmalade such as the author, name, description, list of sneks, number of commands etc. Provide no name to see the basic information about all loaded marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) - args: - - "mycoolmarmalade" + ex: + - mycoolmarmalade - "" + params: + - name: + desc: "The author of the specified marmalade." marmaladelist: desc: |- Lists all loaded and unloaded marmalades. Read about the marmalade system [here](https://docs.elliebot.net/v4/) - args: + ex: - "" + params: + - {} +marmaladesearch: + desc: Searches for marmalades online given the search term + ex: + - shrine + params: + - {} bankdeposit: - desc: "Deposits the specified amount of currency into the bank for later use." - args: - - "50" + desc: Deposits the specified amount of currency into the bank for later use. + ex: + - 50 + params: + - amount: + desc: "The total value of funds being transferred or added to the account." bankwithdraw: - desc: "Withdraws the specified amount of currency from the bank if available." - args: - - "49" + desc: Withdraws the specified amount of currency from the bank if available. + ex: + - 49 + params: + - amount: + desc: "The amount of money to be withdrawn." bankbalance: - desc: "Shows your current bank balance available for withdrawal." - args: + desc: Shows your current bank balance available for withdrawal. + ex: - "" + params: + - {} banktake: - desc: "Takes the specified amount of currency from a user's bank" - args: - - "500 @MoniLaunder" + desc: Takes the specified amount of currency from a user's bank + ex: + - 500 @MoniLaunder + params: + - amount: + desc: "The total value of funds being withdrawn." + user: + desc: "The account holder whose funds are being accessed." + - amount: + desc: "The total value of funds being withdrawn." + userId: + desc: "The unique identifier for the user whose account is being accessed." bankaward: - desc: "Award the specified amount of currency to a user's bank" - args: - - "99999 @Bestie" + desc: Award the specified amount of currency to a user's bank + ex: + - 99999 @Bestie + params: + - amount: + desc: "The total value of the award being given." + user: + desc: "The user who is receiving the award." patron: - desc: "Check your patronage status and command usage quota. Bot owners can check targeted user's patronage status." - args: + desc: Check your patronage status and command usage quota. Bot owners can check targeted user's patronage status. + ex: - "" + params: + - {} + - user: + desc: "The ID or handle of the user whose patronage status is being checked." patronmessage: - desc: "Sends a message to all patrons of the specified tier and higher. Supports embeds." - args: - - "x hello" + desc: Sends a message to all patrons of the specified tier and higher. Supports embeds. + ex: + - x hello + params: + - tierAndHigher: + desc: "The tier or level of membership that determines which patrons receive the message." + message: + desc: "The text content of the message being sent to patrons." eval: desc: |- Execute arbitrary C# code and (optionally) return a result. Several namespaces are included by default. @@ -2325,47 +4208,214 @@ eval: `user` - User executing the command `ctx` - Discord.Net command context `services` - Ellie's IServiceProvider - args: - - "123 / 4.5f" - - "await ctx.OkAsync();" - - 'await ctx.SendConfirmAsync("uwu");' + ex: + - 123 / 4.5f + - await ctx.OkAsync(); + - await ctx.Response().Confirm("uwu").SendAsync(); + params: + - scriptText: + desc: "The code to be executed by the function." betdraw: desc: |- Bet on the card value and/or color. Specify the amount followed by your guess. You can specify `r` or `b` for red or black, and `h` or `l` for high or low. You can specify only h/l or only r/b or both. Returns are high but **7 always loses**. - args: - - "50 r" - - "200 b l" - - "1000 h" - - "38 hi black" + ex: + - 50 r + - 200 b l + - 1000 h + - 38 hi black + params: + - amount: + desc: "The stake to be wagered on the bet." + val: + desc: "The value of the card to be guessed." + col: + desc: "The color of the card to be guessed, either red or black." + - amount: + desc: "The stake to be wagered on the bet." + col: + desc: "The color to bet on, either red or black." + val: + desc: "The value of the card to be guessed." bettest: desc: |- Tests a betting command by specifying the name followed by the number of tests. Some have multiple variations. See the list of all tests by specifying no parameters. - args: + ex: - "" - - "betflip 1000" - - "slot 2000" + - betflip 1000 + - slot 2000 + params: + - {} + - target: + desc: "The type of game or wager being tested." + tests: + desc: "The number of times to repeat the test." threadcreate: - desc: "Create a public thread with the specified title. You may optionally reply to a message to have it as a starting point." - args: - - "Q&A" + desc: Create a public thread with the specified title. You may optionally reply to a message to have it as a starting point. + ex: + - Q&A + params: + - name: + desc: "The title of the new thread, which will be displayed in the forum's list of threads." threaddelete: - desc: "Delete a thread with the specified name in this channel. Case insensitive." - args: - - "Q&A" + desc: Delete a thread with the specified name in this channel. Case insensitive. + ex: + - Q&A + params: + - name: + desc: "The name of the thread to delete, allowing users to specify which specific conversation they want to remove from the channel." autopublish: - desc: "Make the bot automatically publish all messages posted in the news channel this command was executed in." - args: + desc: Make the bot automatically publish all messages posted in the news channel this command was executed in. + ex: - "" + params: + - {} doas: - desc: "Execute the command as if you were the target user. Requires bot ownership and server administrator permission." - args: + desc: Execute the command as if you were the target user. Requires bot ownership and server administrator permission. + ex: - "@Thief .give all @Admin" + params: + - user: + desc: "The user whose identity is being impersonated for the command execution." + message: + desc: "The command or script to execute as the target user." +clubrename: + desc: Renames your club. Requires you club ownership or club-admin status. + ex: + - New cool club name + params: + - clubName: + desc: "The name of the new club that will replace the current one." cacheusers: desc: Caches users of a Discord server and saves them to the database. - args: + ex: - "" - - "serverId" + - serverId + params: + - {} + - guild: + desc: "The guild for which user data is being cached." +stickyroles: + desc: Toggles whether the bot will save the leaving users' roles, and reapply them once they re-join. The roles will be stored for up to 30 days. + ex: + - "" + params: + - {} +giveawaystart: + desc: Starts a giveaway. Specify the duration (between 1 minute and 30 days) followed by the prize. + ex: + - 12h We are giving away one copy of our latest album! + - 15m Quick giveaway for a free course! + - 1d Join to win 1000$! + params: + - duration: + desc: "The length of time for which the giveaway will be active." + message: + desc: "The description of the prize being awarded in this giveaway." +giveawayend: + desc: Prematurely ends a giveaway and selects a winner. Specify the ID of the giveaway to end. + ex: + - ab3 + params: + - id: + desc: "The identifier for the giveaway that is being terminated." +giveawaycancel: + desc: Cancels a giveaway. Specify the ID of the giveaway to cancel. The winner will not be chosen. + ex: + - ab3 + params: + - id: + desc: "The identifier for the giveaway being cancelled." +giveawayreroll: + desc: Rerolls a giveaway. Specify the ID of the giveaway to reroll. This is only active within 24h after the giveaway has ended or until the bot restarts. + ex: + - cd3 + params: + - id: + desc: "The identifier for the specific giveaway being rerolled." +giveawaylist: + desc: Lists all active giveaways. + ex: + - "" + params: + - {} +todolist: + desc: Lists all todos. + ex: + - "" + params: + - {} +todoadd: + desc: Adds a new todo. + ex: + - I need to do this + params: + - todo: + desc: "The description or title of the new todo item." +todoedit: + desc: Edits a todo with the specified ID. + ex: + - abc This is an updated entry + params: + - todoId: + desc: "The unique identifier for the todo item being edited." + newMessage: + desc: "The text of a new task description or update to an existing one." +todocomplete: + desc: Marks a todo with the specified ID as done. + ex: + - 4a + params: + - todoId: + desc: "The unique identifier for the todo item being marked as completed." +tododelete: + desc: Deletes a todo with the specified ID. + ex: + - abc + params: + - todoId: + desc: "The unique identifier for the todo item being deleted." +todoclear: + desc: Deletes all unarchived todos. + ex: + - "" + params: + - {} +todoarchiveadd: + desc: Creates a new archive with the specified name using current todos. + ex: + - Day 1 + params: + - name: + desc: "The name of the archive to be created." +todoarchivelist: + desc: Lists all archived todo lists. + ex: + - "" + params: + - page: + desc: "The number of the page to retrieve from the list of archived todo lists." +todoarchiveshow: + desc: Shows the archived todo list with the specified ID. + ex: + - 3c + params: + - todoId: + desc: "The identifier for a specific task or project that has been archived and is being retrieved." +todoshow: + desc: Shows the text of the todo with the specified ID. + ex: + - 4a + params: + - todoId: + desc: "The unique identifier for the todo item being displayed." +todoarchivedelete: + desc: Deletes the archived todo list with the specified ID. + ex: + - 99 + params: + - todoId: + desc: "The identifier for the archived todo item to be deleted." diff --git a/src/EllieBot/data/strings/responses/responses.en-US.json b/src/EllieBot/data/strings/responses/responses.en-US.json index be21798..0487021 100644 --- a/src/EllieBot/data/strings/responses/responses.en-US.json +++ b/src/EllieBot/data/strings/responses/responses.en-US.json @@ -35,6 +35,9 @@ "banned_user": "User Banned", "ban_prune_disabled": "Banned user's messages will no longer be deleted.", "ban_prune": "Bot will prune up to {0} day(s) worth of messages from banned user.", + "prune_cancelled": "Pruning was cancelled.", + "prune_not_found": "No active prune was found on this server.", + "prune_progress": "Pruning... {0}/{1} messages deleted.", "timeoutdm": "You have been timed out in {0} server.\nReason: {1}", "timedout_user": "User Timed Out", "remove_roles_pl": "have had their roles removed", @@ -184,6 +187,7 @@ "setrole": "Successfully added role {0} to user {1}", "setrole_err": "Failed to add role. I have insufficient permissions.", "set_avatar": "New avatar set!", + "set_banner": "New banner set!", "set_channel_name": "New channel name set.", "set_game": "New game set!", "set_stream": "New stream set!", @@ -376,6 +380,7 @@ "id": "Id", "now_playing": "Now playing", "no_player": "No active music player.", + "music_fairplay": "Music queue has been fairly reordered.", "no_search_results": "No search results.", "player_queue": "Player queue - Page {0}/{1}", "playing_track": "Playing track #{0}", @@ -709,6 +714,7 @@ "shop_item_add": "Shop item added", "shop_none": "No shop items found on this page.", "shop_role": "You will get {0} role.", + "shop_command_invalid_context": "Unable to retrieve user, channel or server in order to execute the command.", "type": "Type", "gvc_disabled": "Game Voice Channel feature has been disabled on this server.", "gvc_enabled": "{0} is a Game Voice Channel now.", @@ -838,10 +844,9 @@ "server_leaderboard": "Server XP Leaderboard", "global_leaderboard": "Global XP Leaderboard", "modified": "Modified server XP of the user {0} by {1}", - "club_insuff_lvl": "You're insufficient level to join that club.", + "club_already_applied": "You've already applied to that club.", "club_join_banned": "You're banned from that club.", "club_already_in": "You are already a member of a club.", - "club_create_error_name": "Failed creating the club. A club with that name already exists.", "club_name_too_long": "Club name is too long.", "club_created": "Club {0} successfully created!", "club_create_insuff_lvl": "You don't meet the minimum level requirements in order to create a club.", @@ -876,6 +881,8 @@ "club_apps_for": "Applicants for {0} club", "club_leaderboard": "Club leaderboard - page {0}", "club_kick_hierarchy": "Only club owner can kick club admins. Owner can't be kicked.", + "club_renamed": "Club has been renamed to {0}", + "club_name_taken": "A club with that name already exists.", "template_reloaded": "Xp template has been reloaded.", "expr_edited": "Expression Edited", "self_assign_are_exclusive": "You can only choose 1 role from each group.", @@ -982,7 +989,7 @@ "module_description_gambling": "Bet on dice rolls, blackjack, slots, coinflips and others", "module_description_games": "Play trivia, nunchi, hangman, connect4 and other games", "module_description_nsfw": "NSFW commands.", - "module_description_music": "Play music from youtube, local files soundcloud and radio streams", + "module_description_music": "Play music from youtube, local files and radio streams", "module_description_utility": "Manage custom quotes, repeating messages and check facts about the server", "module_description_administration": "Moderation, punish users, setup self assignable roles and greet messages", "module_description_expressions": "Setup custom bot responses to certain words or phrases", @@ -990,6 +997,7 @@ "module_description_searches": "Search for jokes, images of animals, anime and manga", "module_description_xp": "Gain xp based on chat activity, check users' xp cards", "module_description_marmalade": "**Bot Owner only.** Load, unload and handle dynamic modules. Read more [here](https://docs.elliebot.net/v4/)", + "module_description_patronage": "Commands related to supporting the bot", "module_description_missing": "Description is missing for this module.", "purge_user_confirm": "Are you sure that you want to purge {0} from the database?", "expr_import_no_input": "Invalid input. No valid file upload or input text found.", @@ -1016,7 +1024,7 @@ "commands_count": "Commands ({0})", "no_marmalade_loaded": "There are no loaded marmalades.", "no_marmalade_available": "No marmalade available.", - "loaded_marmalades": "Loaded Marmaladee", + "loaded_marmalades": "Loaded Marmalades", "marmalade_not_loaded": "Marmalade with that name is not loaded.", "marmalade_possibly_cant_unload": "Marmalade is probably not fully unloaded. Please restart the bot if issues arise.", "marmalade_loaded": "Marmalade {0} has been loaded.", @@ -1060,5 +1068,31 @@ "thread_created": "Thread Created", "supported_languages": "Supported Languages", "cache_users_pending": "Updating users, please wait...", - "cache_users_done": "{0} users were added and {1} users were updated." + "cache_users_done": "{0} users were added and {1} users were updated.", + "sticky_roles_enabled": "Sticky roles enabled. Leaving users' roles will be restored when they rejoin the server.", + "sticky_roles_disabled": "Sticky roles disabled.", + "giveaway_duration_invalid": "Giveaway may not be shorter than 1 minute or longer than 30 days", + "giveaway_started": "Giveaway Started!", + "giveaway_max_amount_reached": "You've reached the maximum amount of giveaways you can have on this server.", + "giveaway_not_found": "Giveaway not found.", + "giveaway_ended": "Giveaway ended", + "no_givaways": "There are no active giveaways on this server.", + "giveaway_cancelled": "Giveaway cancelled.", + "giveaway_starting": "Starting giveaway...", + "winner": "Winner", + "giveaway_list": "List of active giveways", + "todo_list_empty": "Your todo list is empty.", + "todo_list": "Todo List", + "todo_stats": "{0} items | {1} completed | {2} remaining", + "todo_add_max_limit": "You'reached the maximum amount of todos you can have.", + "todo_not_found": "Todo not found.", + "todo_cleared": "All unarchived todos have been cleared.", + "todo_no_todos": "There are no todos in your todo list.", + "todo_archive_max_limit": "You've reached the maximum amount of archived todos you can have.", + "todo_archive_empty": "You have no archived todos.", + "todo_archive_list": "Archived Todo Lists", + "todo_archive_not_found": "Archived todo list not found.", + "todo_archived_list": "Archived Todo List", + "search_results": "Search results", + "queue_search_results": "Type the number of the search result to queue up that track." } \ No newline at end of file diff --git a/src/EllieBot/data/units.json b/src/EllieBot/data/units.json index 9de5921..e09dcc1 100644 --- a/src/EllieBot/data/units.json +++ b/src/EllieBot/data/units.json @@ -719,6 +719,17 @@ "UnitType": "time", "Modifier": 60.0 }, + { + "Triggers": [ + "second", + "seconds", + "sec", + "secs", + "s" + ], + "UnitType": "time", + "Modifier": 1 + }, { "Triggers": [ "year", From e58268e3391d3e0c9ce5382cff80f612cc556721 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 16 May 2024 23:14:41 +1200 Subject: [PATCH 37/62] Fixed a few bugs and updated some dependencies --- src/Ellie.Marmalade/Ellie.Marmalade.csproj | 2 +- src/EllieBot.Coordinator/EllieBot.Coordinator.csproj | 2 +- src/EllieBot.Coordinator/Services/CoordinatorRunner.cs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Ellie.Marmalade/Ellie.Marmalade.csproj b/src/Ellie.Marmalade/Ellie.Marmalade.csproj index b01a911..db33025 100644 --- a/src/Ellie.Marmalade/Ellie.Marmalade.csproj +++ b/src/Ellie.Marmalade/Ellie.Marmalade.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj b/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj index af90db3..b4f964d 100644 --- a/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj +++ b/src/EllieBot.Coordinator/EllieBot.Coordinator.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs b/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs index de870ca..780afc4 100644 --- a/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs +++ b/src/EllieBot.Coordinator/Services/CoordinatorRunner.cs @@ -417,8 +417,7 @@ namespace EllieBot.Coordinator { lock (locker) { - if (shardId >= _shardStatuses.Length) - throw new ArgumentOutOfRangeException(nameof(shardId)); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(shardId, _shardStatuses.Length); return _shardStatuses[shardId]; } From 97e81ac0f4b72f1fb17c24f7d9025a7254904934 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sat, 18 May 2024 00:08:52 +1200 Subject: [PATCH 38/62] Added Ellie Common/Abstractions --- .../_common/Abstractions/AsyncLazy.cs | 19 +++ .../Abstractions/Cache/BotCacheExtensions.cs | 46 ++++++ .../_common/Abstractions/Cache/IBotCache.cs | 47 ++++++ .../Abstractions/Cache/MemoryBotCache.cs | 71 +++++++++ .../Collections/ConcurrentHashSet.cs | 88 ++++++++++ .../Collections/IndexedCollections.cs | 148 +++++++++++++++++ .../_common/Abstractions/EllieRandom.cs | 66 ++++++++ .../Extensions/ArrayExtensions.cs | 62 ++++++++ .../Extensions/EnumerableExtensions.cs | 97 +++++++++++ .../Abstractions/Extensions/Extensions.cs | 7 + .../Extensions/HttpClientExtensions.cs | 35 ++++ .../Extensions/OneOfExtensions.cs | 10 ++ .../Abstractions/Extensions/PipeExtensions.cs | 22 +++ .../Extensions/StringExtensions.cs | 150 ++++++++++++++++++ .../_common/Abstractions/Helpers/LogSetup.cs | 35 ++++ .../Helpers/StandardConversions.cs | 7 + src/EllieBot/_common/Abstractions/Kwum.cs | 100 ++++++++++++ .../Abstractions/PubSub/EventPubSub.cs | 80 ++++++++++ .../_common/Abstractions/PubSub/IPubSub.cs | 10 ++ .../_common/Abstractions/PubSub/ISeria.cs | 7 + .../_common/Abstractions/QueueRunner.cs | 61 +++++++ src/EllieBot/_common/Abstractions/TypedKey.cs | 30 ++++ .../_common/Abstractions/YamlHelper.cs | 48 ++++++ .../Abstractions/creds/IBotCredentials.cs | 78 +++++++++ .../Abstractions/creds/IBotCredsProvider.cs | 8 + .../Abstractions/strings/CommandStrings.cs | 35 ++++ .../Abstractions/strings/IBotStrings.cs | 16 ++ .../strings/IBotStringsExtensions.cs | 17 ++ .../strings/IBotStringsProvider.cs | 28 ++++ .../Abstractions/strings/IStringsSource.cs | 17 ++ .../_common/Abstractions/strings/LocStr.cs | 13 ++ 31 files changed, 1458 insertions(+) create mode 100644 src/EllieBot/_common/Abstractions/AsyncLazy.cs create mode 100644 src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Cache/IBotCache.cs create mode 100644 src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs create mode 100644 src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs create mode 100644 src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs create mode 100644 src/EllieBot/_common/Abstractions/EllieRandom.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/Extensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/HttpClientExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/OneOfExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/Helpers/LogSetup.cs create mode 100644 src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs create mode 100644 src/EllieBot/_common/Abstractions/Kwum.cs create mode 100644 src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs create mode 100644 src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs create mode 100644 src/EllieBot/_common/Abstractions/PubSub/ISeria.cs create mode 100644 src/EllieBot/_common/Abstractions/QueueRunner.cs create mode 100644 src/EllieBot/_common/Abstractions/TypedKey.cs create mode 100644 src/EllieBot/_common/Abstractions/YamlHelper.cs create mode 100644 src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs create mode 100644 src/EllieBot/_common/Abstractions/creds/IBotCredsProvider.cs create mode 100644 src/EllieBot/_common/Abstractions/strings/CommandStrings.cs create mode 100644 src/EllieBot/_common/Abstractions/strings/IBotStrings.cs create mode 100644 src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs create mode 100644 src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs create mode 100644 src/EllieBot/_common/Abstractions/strings/IStringsSource.cs create mode 100644 src/EllieBot/_common/Abstractions/strings/LocStr.cs diff --git a/src/EllieBot/_common/Abstractions/AsyncLazy.cs b/src/EllieBot/_common/Abstractions/AsyncLazy.cs new file mode 100644 index 0000000..6c86693 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/AsyncLazy.cs @@ -0,0 +1,19 @@ +using System.Runtime.CompilerServices; + +namespace Ellie.Common; + +public class AsyncLazy : Lazy> +{ + public AsyncLazy(Func valueFactory) + : base(() => Task.Run(valueFactory)) + { + } + + public AsyncLazy(Func> taskFactory) + : base(() => Task.Run(taskFactory)) + { + } + + public TaskAwaiter GetAwaiter() + => Value.GetAwaiter(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs b/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs new file mode 100644 index 0000000..39d5e82 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs @@ -0,0 +1,46 @@ +using OneOf; +using OneOf.Types; + +namespace Ellie.Common; + +public static class BotCacheExtensions +{ + public static async ValueTask GetOrDefaultAsync(this IBotCache cache, TypedKey key) + { + var result = await cache.GetAsync(key); + if (result.TryGetValue(out var val)) + return val; + + return default; + } + + private static TypedKey GetImgKey(Uri uri) + => new($"image:{uri}"); + + public static ValueTask SetImageDataAsync(this IBotCache c, string key, byte[] data) + => c.SetImageDataAsync(new Uri(key), data); + public static async ValueTask SetImageDataAsync(this IBotCache c, Uri key, byte[] data) + => await c.AddAsync(GetImgKey(key), data, expiry: TimeSpan.FromHours(48)); + + public static async ValueTask> GetImageDataAsync(this IBotCache c, Uri key) + => await c.GetAsync(GetImgKey(key)); + + public static async Task GetRatelimitAsync( + this IBotCache c, + TypedKey key, + TimeSpan length) + { + var now = DateTime.UtcNow; + var nowB = now.ToBinary(); + + var cachedValue = await c.GetOrAddAsync(key, + () => Task.FromResult(now.ToBinary()), + expiry: length); + + if (cachedValue == nowB) + return null; + + var diff = now - DateTime.FromBinary(cachedValue); + return length - diff; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs b/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs new file mode 100644 index 0000000..5622c5f --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs @@ -0,0 +1,47 @@ +using OneOf; +using OneOf.Types; + +namespace Ellie.Common; + +public interface IBotCache +{ + /// + /// Adds an item to the cache + /// + /// Key to add + /// Value to add to the cache + /// Optional expiry + /// Whether old value should be overwritten + /// Type of the value + /// Returns whether add was sucessful. Always true unless ovewrite = false + ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true); + + /// + /// Get an element from the cache + /// + /// Key + /// Type of the value + /// Either a value or + ValueTask> GetAsync(TypedKey key); + + /// + /// Remove a key from the cache + /// + /// Key to remove + /// Type of the value + /// Whether there was item + ValueTask RemoveAsync(TypedKey key); + + /// + /// Get the key if it exists or add a new one + /// + /// Key to get and potentially add + /// Value creation factory + /// Optional expiry + /// Type of the value + /// The retrieved or newly added value + ValueTask GetOrAddAsync( + TypedKey key, + Func> createFactory, + TimeSpan? expiry = null); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs b/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs new file mode 100644 index 0000000..caac44f --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.Caching.Memory; +using OneOf; +using OneOf.Types; + +// ReSharper disable InconsistentlySynchronizedField + +namespace Ellie.Common; + +public sealed class MemoryBotCache : IBotCache +{ + // needed for overwrites and Delete return value + private readonly object _cacheLock = new object(); + private readonly MemoryCache _cache; + + public MemoryBotCache() + { + _cache = new MemoryCache(new MemoryCacheOptions()); + } + + public ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) + { + if (overwrite) + { + using var item = _cache.CreateEntry(key.Key); + item.Value = value; + item.AbsoluteExpirationRelativeToNow = expiry; + return new(true); + } + + lock (_cacheLock) + { + if (_cache.TryGetValue(key.Key, out var old) && old is not null) + return new(false); + + using var item = _cache.CreateEntry(key.Key); + item.Value = value; + item.AbsoluteExpirationRelativeToNow = expiry; + return new(true); + } + } + + public async ValueTask GetOrAddAsync( + TypedKey key, + Func> createFactory, + TimeSpan? expiry = null) + => await _cache.GetOrCreateAsync(key.Key, + async ce => + { + ce.AbsoluteExpirationRelativeToNow = expiry; + var val = await createFactory(); + return val; + }); + + public ValueTask> GetAsync(TypedKey key) + { + if (!_cache.TryGetValue(key.Key, out var val) || val is null) + return new(new None()); + + return new((T)val); + } + + public ValueTask RemoveAsync(TypedKey key) + { + lock (_cacheLock) + { + var toReturn = _cache.TryGetValue(key.Key, out var old) && old is not null; + _cache.Remove(key.Key); + return new(toReturn); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs b/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs new file mode 100644 index 0000000..19986be --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs @@ -0,0 +1,88 @@ +using System.Diagnostics; + +namespace System.Collections.Generic; + +[DebuggerDisplay("{_backingStore.Count}")] +public sealed class ConcurrentHashSet : IReadOnlyCollection, ICollection where T : notnull +{ + private readonly ConcurrentDictionary _backingStore; + + public ConcurrentHashSet() + => _backingStore = new(); + + public ConcurrentHashSet(IEnumerable values, IEqualityComparer? comparer = null) + => _backingStore = new(values.Select(x => new KeyValuePair(x, true)), comparer); + + public IEnumerator GetEnumerator() + => _backingStore.Keys.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + /// Adds the specified item to the . + /// + /// The item to add. + /// + /// true if the items was added to the + /// successfully; false if it already exists. + /// + /// + /// The + /// contains too many items. + /// + public bool Add(T item) + => _backingStore.TryAdd(item, true); + + void ICollection.Add(T item) + => Add(item); + + public void Clear() + => _backingStore.Clear(); + + public bool Contains(T item) + => _backingStore.ContainsKey(item); + + public void CopyTo(T[] array, int arrayIndex) + { + ArgumentNullException.ThrowIfNull(array); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + + if (arrayIndex >= array.Length) + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + + CopyToInternal(array, arrayIndex); + } + + private void CopyToInternal(T[] array, int arrayIndex) + { + var len = array.Length; + foreach (var (k, _) in _backingStore) + { + if (arrayIndex >= len) + throw new IndexOutOfRangeException(nameof(arrayIndex)); + + array[arrayIndex++] = k; + } + } + + bool ICollection.Remove(T item) + => TryRemove(item); + + public bool TryRemove(T item) + => _backingStore.TryRemove(item, out _); + + public void RemoveWhere(Func predicate) + { + foreach (var elem in this.Where(predicate)) + TryRemove(elem); + } + + public int Count + => _backingStore.Count; + + public bool IsReadOnly + => false; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs b/src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs new file mode 100644 index 0000000..fe8e2c1 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs @@ -0,0 +1,148 @@ +using System.Collections; + +namespace Ellie.Common; + +public interface IIndexed +{ + int Index { get; set; } +} + +public class IndexedCollection : IList + where T : class, IIndexed +{ + public List Source { get; } + + public int Count + => Source.Count; + + public bool IsReadOnly + => false; + + public virtual T this[int index] + { + get => Source[index]; + set + { + lock (_locker) + { + value.Index = index; + Source[index] = value; + } + } + } + + private readonly object _locker = new(); + + public IndexedCollection() + => Source = new(); + + public IndexedCollection(IEnumerable source) + { + lock (_locker) + { + Source = source.OrderBy(x => x.Index).ToList(); + UpdateIndexes(); + } + } + + public int IndexOf(T item) + => item?.Index ?? -1; + + public IEnumerator GetEnumerator() + => Source.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => Source.GetEnumerator(); + + public void Add(T item) + { + ArgumentNullException.ThrowIfNull(item); + + lock (_locker) + { + item.Index = Source.Count; + Source.Add(item); + } + } + + public virtual void Clear() + { + lock (_locker) + { + Source.Clear(); + } + } + + public bool Contains(T item) + { + lock (_locker) + { + return Source.Contains(item); + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + lock (_locker) + { + Source.CopyTo(array, arrayIndex); + } + } + + public virtual bool Remove(T item) + { + lock (_locker) + { + if (Source.Remove(item)) + { + for (var i = 0; i < Source.Count; i++) + { + if (Source[i].Index != i) + Source[i].Index = i; + } + + return true; + } + } + + return false; + } + + public virtual void Insert(int index, T item) + { + lock (_locker) + { + Source.Insert(index, item); + for (var i = index; i < Source.Count; i++) + Source[i].Index = i; + } + } + + public virtual void RemoveAt(int index) + { + lock (_locker) + { + Source.RemoveAt(index); + for (var i = index; i < Source.Count; i++) + Source[i].Index = i; + } + } + + public void UpdateIndexes() + { + lock (_locker) + { + for (var i = 0; i < Source.Count; i++) + { + if (Source[i].Index != i) + Source[i].Index = i; + } + } + } + + public static implicit operator List(IndexedCollection x) + => x.Source; + + public List ToList() + => Source.ToList(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/EllieRandom.cs b/src/EllieBot/_common/Abstractions/EllieRandom.cs new file mode 100644 index 0000000..0ece259 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/EllieRandom.cs @@ -0,0 +1,66 @@ +#nullable disable +using System.Security.Cryptography; + +namespace Ellie.Common; + +public sealed class EllieRandom : Random +{ + private readonly RandomNumberGenerator _rng; + + public EllieRandom() + => _rng = RandomNumberGenerator.Create(); + + public override int Next() + { + var bytes = new byte[sizeof(int)]; + _rng.GetBytes(bytes); + return Math.Abs(BitConverter.ToInt32(bytes, 0)); + } + + /// + /// Generates a random integer between 0 (inclusive) and + /// a specified exclusive upper bound using a cryptographically strong random number generator. + /// + /// Exclusive max value + /// A random number + public override int Next(int maxValue) + => RandomNumberGenerator.GetInt32(maxValue); + + /// + /// Generates a random integer between a specified inclusive lower bound and a + /// specified exclusive upper bound using a cryptographically strong random number generator. + /// + /// Inclusive min value + /// Exclusive max value + /// A random number + public override int Next(int minValue, int maxValue) + => RandomNumberGenerator.GetInt32(minValue, maxValue); + + public long NextLong(long minValue, long maxValue) + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(minValue, maxValue); + if (minValue == maxValue) + return minValue; + var bytes = new byte[sizeof(long)]; + _rng.GetBytes(bytes); + var sign = Math.Sign(BitConverter.ToInt64(bytes, 0)); + return (sign * BitConverter.ToInt64(bytes, 0) % (maxValue - minValue)) + minValue; + } + + public override void NextBytes(byte[] buffer) + => _rng.GetBytes(buffer); + + protected override double Sample() + { + var bytes = new byte[sizeof(double)]; + _rng.GetBytes(bytes); + return Math.Abs((BitConverter.ToDouble(bytes, 0) / double.MaxValue) + 1); + } + + public override double NextDouble() + { + var bytes = new byte[sizeof(double)]; + _rng.GetBytes(bytes); + return BitConverter.ToDouble(bytes, 0); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs new file mode 100644 index 0000000..dbe2d93 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs @@ -0,0 +1,62 @@ +using System.Security.Cryptography; + +namespace Ellie.Common; + +// made for expressions because they almost never get added +// and they get looped through constantly +public static class ArrayExtensions +{ + /// + /// Create a new array from the old array + new element at the end + /// + /// Input array + /// Item to add to the end of the output array + /// Type of the array + /// A new array with the new element at the end + public static T[] With(this T[] input, T added) + { + var newExprs = new T[input.Length + 1]; + Array.Copy(input, 0, newExprs, 0, input.Length); + newExprs[input.Length] = added; + return newExprs; + } + + /// + /// Creates a new array by applying the specified function to every element in the input array + /// + /// Array to modify + /// Function to apply + /// Orignal type of the elements in the array + /// Output type of the elements of the array + /// New array with updated elements + public static TOut[] Map(this TIn[] arr, Func f) + => Array.ConvertAll(arr, x => f(x)); + + /// + /// Creates a new array by applying the specified function to every element in the input array + /// + /// Array to modify + /// Function to apply + /// Orignal type of the elements in the array + /// Output type of the elements of the array + /// New array with updated elements + public static TOut[] Map(this IReadOnlyCollection col, Func f) + { + var toReturn = new TOut[col.Count]; + + var i = 0; + foreach (var item in col) + toReturn[i++] = f(item); + + return toReturn; + } + + public static T? RandomOrDefault(this T[] data) + { + if (data.Length == 0) + return default; + + var index = RandomNumberGenerator.GetInt32(0, data.Length); + return data[index]; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000..4e4c786 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs @@ -0,0 +1,97 @@ +using System.Security.Cryptography; + +namespace Ellie.Common; + +public static class EnumerableExtensions +{ + /// + /// Concatenates the members of a collection, using the specified separator between each member. + /// + /// Collection to join + /// + /// The character to use as a separator. separator is included in the returned string only if + /// values has more than one element. + /// + /// Optional transformation to apply to each element before concatenation. + /// The type of the members of values. + /// + /// A string that consists of the members of values delimited by the separator character. -or- Empty if values has + /// no elements. + /// + public static string Join(this IEnumerable data, char separator, Func? func = null) + => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); + + /// + /// Concatenates the members of a collection, using the specified separator between each member. + /// + /// Collection to join + /// + /// The string to use as a separator.separator is included in the returned string only if values + /// has more than one element. + /// + /// Optional transformation to apply to each element before concatenation. + /// The type of the members of values. + /// + /// A string that consists of the members of values delimited by the separator character. -or- Empty if values has + /// no elements. + /// + public static string Join(this IEnumerable data, string separator, Func? func = null) + => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); + + /// + /// Randomize element order by performing the Fisher-Yates shuffle + /// + /// Item type + /// Items to shuffle + public static IReadOnlyList Shuffle(this IEnumerable items) + { + var list = items.ToArray(); + var n = list.Length; + while (n-- > 1) + { + var k = RandomNumberGenerator.GetInt32(n); + (list[k], list[n]) = (list[n], list[k]); + } + + return list; + } + + /// + /// Initializes a new instance of the class + /// that contains elements copied from the specified + /// has the default concurrency level, has the default initial capacity, + /// and uses the default comparer for the key type. + /// + /// + /// The whose elements are copied to the new + /// . + /// + /// A new instance of the class + public static ConcurrentDictionary ToConcurrent( + this IEnumerable> dict) + where TKey : notnull + => new(dict); + + public static IndexedCollection ToIndexed(this IEnumerable enumerable) + where T : class, IIndexed + => new(enumerable); + + /// + /// Creates a task that will complete when all of the objects in an enumerable + /// collection have completed + /// + /// The tasks to wait on for completion. + /// The type of the completed task. + /// A task that represents the completion of all of the supplied tasks. + public static Task WhenAll(this IEnumerable> tasks) + => Task.WhenAll(tasks); + + /// + /// Creates a task that will complete when all of the objects in an enumerable + /// collection have completed + /// + /// The tasks to wait on for completion. + /// A task that represents the completion of all of the supplied tasks. + public static Task WhenAll(this IEnumerable tasks) + => Task.WhenAll(tasks); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs b/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs new file mode 100644 index 0000000..487afe7 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs @@ -0,0 +1,7 @@ +namespace Ellie.Common; + +public static class Extensions +{ + public static long ToTimestamp(this in DateTime value) + => (value.Ticks - 621355968000000000) / 10000000; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/HttpClientExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/HttpClientExtensions.cs new file mode 100644 index 0000000..38e6396 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/HttpClientExtensions.cs @@ -0,0 +1,35 @@ +using System.Net.Http.Headers; + +namespace Ellie.Common; + +public static class HttpClientExtensions +{ + public static HttpClient AddFakeHeaders(this HttpClient http) + { + AddFakeHeaders(http.DefaultRequestHeaders); + return http; + } + + public static void AddFakeHeaders(this HttpHeaders dict) + { + dict.Clear(); + dict.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + dict.Add("User-Agent", + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"); + } + + public static bool IsImage(this HttpResponseMessage msg) + => IsImage(msg, out _); + + public static bool IsImage(this HttpResponseMessage msg, out string? mimeType) + { + mimeType = msg.Content.Headers.ContentType?.MediaType; + if (mimeType is "image/png" or "image/jpeg" or "image/gif") + return true; + + return false; + } + + public static long GetContentLength(this HttpResponseMessage msg) + => msg.Content.Headers.ContentLength ?? long.MaxValue; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/OneOfExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/OneOfExtensions.cs new file mode 100644 index 0000000..f9c4cde --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/OneOfExtensions.cs @@ -0,0 +1,10 @@ +using OneOf.Types; +using OneOf; + +namespace Ellie.Common; + +public static class OneOfExtensions +{ + public static bool TryGetValue(this OneOf oneOf, out T value) + => oneOf.TryPickT0(out value, out _); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs new file mode 100644 index 0000000..215a829 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs @@ -0,0 +1,22 @@ +namespace Ellie.Common; + +public delegate TOut PipeFunc(in TIn a); +public delegate TOut PipeFunc(in TIn1 a, in TIn2 b); + +public static class PipeExtensions +{ + public static TOut Pipe(this TIn a, Func fn) + => fn(a); + + public static TOut Pipe(this TIn a, PipeFunc fn) + => fn(a); + + public static TOut Pipe(this (TIn1, TIn2) a, PipeFunc fn) + => fn(a.Item1, a.Item2); + + public static (TIn, TExtra) With(this TIn a, TExtra b) + => (a, b); + + public static async Task Pipe(this Task a, Func fn) + => fn(await a); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs new file mode 100644 index 0000000..95baadb --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs @@ -0,0 +1,150 @@ +using EllieBot.Common.Yml; +using System.Text; +using System.Text.RegularExpressions; + +namespace EllieBot.Extensions; + +public static class StringExtensions +{ + private static readonly HashSet _lettersAndDigits = + [ + ..Enumerable.Range(48, 10) + .Concat(Enumerable.Range(65, 26)) + .Concat(Enumerable.Range(97, 26)) + .Select(x => (char)x) + ]; + + private static readonly Regex _filterRegex = new(@"discord(?:\.gg|\.io|\.me|\.li|(?:app)?\.com\/invite)\/(\w+)", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private static readonly Regex _codePointRegex = + new(@"(\\U(?[a-zA-Z0-9]{8})|\\u(?[a-zA-Z0-9]{4})|\\x(?[a-zA-Z0-9]{2}))", + RegexOptions.Compiled); + + public static string PadBoth(this string str, int length) + { + var spaces = length - str.Length; + var padLeft = (spaces / 2) + str.Length; + return str.PadLeft(padLeft, ' ').PadRight(length, ' '); + } + + public static string StripHtml(this string input) + => Regex.Replace(input, "<.*?>", string.Empty); + + public static string? TrimTo(this string? str, int maxLength, bool hideDots = false) + { + if (hideDots) + { + return str?.Substring(0, Math.Min(str?.Length ?? 0, maxLength)); + } + + if (str is null || str.Length <= maxLength) + return str; + + return string.Concat(str.AsSpan(0, maxLength - 1), "…"); + } + + public static string ToTitleCase(this string str) + { + var tokens = str.Split([" "], StringSplitOptions.RemoveEmptyEntries); + for (var i = 0; i < tokens.Length; i++) + { + var token = tokens[i]; + tokens[i] = token[..1].ToUpperInvariant() + token[1..]; + } + + return tokens.Join(" ").Replace(" Of ", " of ").Replace(" The ", " the "); + } + + //http://www.dotnetperls.com/levenshtein + public static int LevenshteinDistance(this string s, string t) + { + var n = s.Length; + var m = t.Length; + var d = new int[n + 1, m + 1]; + + // Step 1 + if (n == 0) + return m; + + if (m == 0) + return n; + + // Step 2 + for (var i = 0; i <= n; d[i, 0] = i++) + { + } + + for (var j = 0; j <= m; d[0, j] = j++) + { + } + + // Step 3 + for (var i = 1; i <= n; i++) + //Step 4 + for (var j = 1; j <= m; j++) + { + // Step 5 + var cost = t[j - 1] == s[i - 1] ? 0 : 1; + + // Step 6 + d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); + } + + // Step 7 + return d[n, m]; + } + + public static async Task ToStream(this string str) + { + var ms = new MemoryStream(); + var sw = new StreamWriter(ms); + await sw.WriteAsync(str); + await sw.FlushAsync(); + ms.Position = 0; + return ms; + } + + public static bool IsDiscordInvite(this string str) + => _filterRegex.IsMatch(str); + + public static string Unmention(this string str) + => str.Replace("@", "ම", StringComparison.InvariantCulture); + + public static string SanitizeMentions(this string str, bool sanitizeRoleMentions = false) + { + str = str.Replace("@everyone", "@everyοne", StringComparison.InvariantCultureIgnoreCase) + .Replace("@here", "@һere", StringComparison.InvariantCultureIgnoreCase); + if (sanitizeRoleMentions) + str = str.SanitizeRoleMentions(); + + return str; + } + + public static string SanitizeRoleMentions(this string str) + => str.Replace("<@&", "<ම&", StringComparison.InvariantCultureIgnoreCase); + + public static string SanitizeAllMentions(this string str) + => str.SanitizeMentions().SanitizeRoleMentions(); + + public static string ToBase64(this string plainText) + { + var plainTextBytes = Encoding.UTF8.GetBytes(plainText); + return Convert.ToBase64String(plainTextBytes); + } + + public static string GetInitials(this string txt, string glue = "") + => txt.Split(' ').Select(x => x.FirstOrDefault()).Join(glue); + + public static bool IsAlphaNumeric(this string txt) + => txt.All(c => _lettersAndDigits.Contains(c)); + + public static string UnescapeUnicodeCodePoints(this string input) + => _codePointRegex.Replace(input, + me => + { + var str = me.Groups["code"].Value; + var newString = str.UnescapeUnicodeCodePoint(); + return newString; + }); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Helpers/LogSetup.cs b/src/EllieBot/_common/Abstractions/Helpers/LogSetup.cs new file mode 100644 index 0000000..8983740 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Helpers/LogSetup.cs @@ -0,0 +1,35 @@ +using Serilog.Events; +using Serilog.Sinks.SystemConsole.Themes; +using System.Text; + +namespace Ellie.Common; + +public static class LogSetup +{ + public static void SetupLogger(object source) + { + Log.Logger = new LoggerConfiguration().MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .MinimumLevel.Override("System", LogEventLevel.Information) + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.Console(LogEventLevel.Information, + theme: GetTheme(), + outputTemplate: + "[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}") + .Enrich.WithProperty("LogSource", source) + .CreateLogger(); + + Console.OutputEncoding = Encoding.UTF8; + } + + private static ConsoleTheme GetTheme() + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + return AnsiConsoleTheme.Code; +#if DEBUG + return AnsiConsoleTheme.Code; +#else + return ConsoleTheme.None; +#endif + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs b/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs new file mode 100644 index 0000000..143c149 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs @@ -0,0 +1,7 @@ +namespace Ellie.Common; + +public static class StandardConversions +{ + public static double CelsiusToFahrenheit(double cel) + => (cel * 1.8f) + 32; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Kwum.cs b/src/EllieBot/_common/Abstractions/Kwum.cs new file mode 100644 index 0000000..267d38b --- /dev/null +++ b/src/EllieBot/_common/Abstractions/Kwum.cs @@ -0,0 +1,100 @@ +using System.Runtime.CompilerServices; + +namespace Ellie.Common; + +// needs proper invalid input check (character array input out of range) +// needs negative number support +// ReSharper disable once InconsistentNaming +#pragma warning disable CS8981 +public readonly struct kwum : IEquatable +#pragma warning restore CS8981 +{ + private const string VALID_CHARACTERS = "23456789abcdefghijkmnpqrstuvwxyz"; + private readonly int _value; + + public kwum(int num) + => _value = num; + + public kwum(in char c) + { + if (!IsValidChar(c)) + throw new ArgumentException("Character needs to be a valid kwum character.", nameof(c)); + + _value = InternalCharToValue(c); + } + + public kwum(in ReadOnlySpan input) + { + _value = 0; + for (var index = 0; index < input.Length; index++) + { + var c = input[index]; + if (!IsValidChar(c)) + throw new ArgumentException("All characters need to be a valid kwum characters.", nameof(input)); + + _value += VALID_CHARACTERS.IndexOf(c) * (int)Math.Pow(VALID_CHARACTERS.Length, input.Length - index - 1); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int InternalCharToValue(in char c) + => VALID_CHARACTERS.IndexOf(c); + + public static bool TryParse(in ReadOnlySpan input, out kwum value) + { + value = default; + foreach (var c in input) + { + if (!IsValidChar(c)) + return false; + } + + value = new(input); + return true; + } + + public static kwum operator +(kwum left, kwum right) + => new(left._value + right._value); + + public static bool operator ==(kwum left, kwum right) + => left._value == right._value; + + public static bool operator !=(kwum left, kwum right) + => !(left == right); + + public static implicit operator long(kwum kwum) + => kwum._value; + + public static implicit operator int(kwum kwum) + => kwum._value; + + public static implicit operator kwum(int num) + => new(num); + + public static bool IsValidChar(char c) + => VALID_CHARACTERS.Contains(c); + + public override string ToString() + { + var count = VALID_CHARACTERS.Length; + var localValue = _value; + var arrSize = (int)Math.Log(localValue, count) + 1; + Span chars = new char[arrSize]; + while (localValue > 0) + { + localValue = Math.DivRem(localValue, count, out var rem); + chars[--arrSize] = VALID_CHARACTERS[rem]; + } + + return new(chars); + } + + public override bool Equals(object? obj) + => obj is kwum kw && kw == this; + + public bool Equals(kwum other) + => other == this; + + public override int GetHashCode() + => _value.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs b/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs new file mode 100644 index 0000000..a3d753a --- /dev/null +++ b/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs @@ -0,0 +1,80 @@ +namespace Ellie.Common; + +public class EventPubSub : IPubSub +{ + private readonly Dictionary>>> _actions = new(); + private readonly object _locker = new(); + + public Task Sub(in TypedKey key, Func action) + where TData : notnull + { + Func localAction = obj => action((TData)obj); + lock (_locker) + { + if (!_actions.TryGetValue(key.Key, out var keyActions)) + { + keyActions = new(); + _actions[key.Key] = keyActions; + } + + if (!keyActions.TryGetValue(action, out var sameActions)) + { + sameActions = new(); + keyActions[action] = sameActions; + } + + sameActions.Add(localAction); + + return Task.CompletedTask; + } + } + + public Task Pub(in TypedKey key, TData data) + where TData : notnull + { + lock (_locker) + { + if (_actions.TryGetValue(key.Key, out var actions)) + // if this class ever gets used, this needs to be properly implemented + // 1. ignore all valuetasks which are completed + // 2. run all other tasks in parallel + return actions.SelectMany(kvp => kvp.Value).Select(action => action(data).AsTask()).WhenAll(); + + return Task.CompletedTask; + } + } + + public Task Unsub(in TypedKey key, Func action) + { + lock (_locker) + { + // get subscriptions for this action + if (_actions.TryGetValue(key.Key, out var actions)) + // get subscriptions which have the same action hash code + // note: having this as a list allows for multiple subscriptions of + // the same insance's/static method + { + if (actions.TryGetValue(action, out var sameActions)) + { + // remove last subscription + sameActions.RemoveAt(sameActions.Count - 1); + + // if the last subscription was the only subscription + // we can safely remove this action's dictionary entry + if (sameActions.Count == 0) + { + actions.Remove(action); + + // if our dictionary has no more elements after + // removing the entry + // it's safe to remove it from the key's subscriptions + if (actions.Count == 0) + _actions.Remove(key.Key); + } + } + } + + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs b/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs new file mode 100644 index 0000000..ea84b6b --- /dev/null +++ b/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs @@ -0,0 +1,10 @@ +namespace Ellie.Common; + +public interface IPubSub +{ + public Task Pub(in TypedKey key, TData data) + where TData : notnull; + + public Task Sub(in TypedKey key, Func action) + where TData : notnull; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs b/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs new file mode 100644 index 0000000..76094f4 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs @@ -0,0 +1,7 @@ +namespace Ellie.Common; + +public interface ISeria +{ + byte[] Serialize(T data); + T? Deserialize(byte[]? data); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/QueueRunner.cs b/src/EllieBot/_common/Abstractions/QueueRunner.cs new file mode 100644 index 0000000..6e582cc --- /dev/null +++ b/src/EllieBot/_common/Abstractions/QueueRunner.cs @@ -0,0 +1,61 @@ +using System.Threading.Channels; + +namespace Ellie.Common; + +public sealed class QueueRunner +{ + private readonly Channel> _channel; + private readonly int _delayMs; + + public QueueRunner(int delayMs = 0, int maxCapacity = -1) + { + ArgumentOutOfRangeException.ThrowIfNegative(delayMs); + + _delayMs = delayMs; + _channel = maxCapacity switch + { + 0 or < -1 => throw new ArgumentOutOfRangeException(nameof(maxCapacity)), + -1 => Channel.CreateUnbounded>(new UnboundedChannelOptions() + { + SingleReader = true, + SingleWriter = false, + AllowSynchronousContinuations = true, + }), + _ => Channel.CreateBounded>(new BoundedChannelOptions(maxCapacity) + { + Capacity = maxCapacity, + FullMode = BoundedChannelFullMode.DropOldest, + SingleReader = true, + SingleWriter = false, + AllowSynchronousContinuations = true + }) + }; + } + + public async Task RunAsync(CancellationToken cancel = default) + { + while (true) + { + var func = await _channel.Reader.ReadAsync(cancel); + + try + { + await func(); + } + catch (Exception ex) + { + Log.Warning(ex, "Exception executing a staggered func: {ErrorMessage}", ex.Message); + } + finally + { + if (_delayMs != 0) + { + await Task.Delay(_delayMs, cancel); + } + } + } + } + + public ValueTask EnqueueAsync(Func action) + => _channel.Writer.WriteAsync(action); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/TypedKey.cs b/src/EllieBot/_common/Abstractions/TypedKey.cs new file mode 100644 index 0000000..ea3103c --- /dev/null +++ b/src/EllieBot/_common/Abstractions/TypedKey.cs @@ -0,0 +1,30 @@ +namespace Ellie.Common; + +public readonly struct TypedKey +{ + public string Key { get; } + + public TypedKey(in string key) + => Key = key; + + public static implicit operator TypedKey(in string input) + => new(input); + + public static implicit operator string(in TypedKey input) + => input.Key; + + public static bool operator ==(in TypedKey left, in TypedKey right) + => left.Key == right.Key; + + public static bool operator !=(in TypedKey left, in TypedKey right) + => !(left == right); + + public override bool Equals(object? obj) + => obj is TypedKey o && o == this; + + public override int GetHashCode() + => Key?.GetHashCode() ?? 0; + + public override string ToString() + => Key; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/YamlHelper.cs b/src/EllieBot/_common/Abstractions/YamlHelper.cs new file mode 100644 index 0000000..e3c39f0 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/YamlHelper.cs @@ -0,0 +1,48 @@ +#nullable disable +namespace EllieBot.Common.Yml; + +public static class YamlHelper +{ + // https://github.com/aaubry/YamlDotNet/blob/0f4cc205e8b2dd8ef6589d96de32bf608a687c6f/YamlDotNet/Core/Scanner.cs#L1687 + /// + /// This is modified code from yamldotnet's repo which handles parsing unicode code points + /// it is needed as yamldotnet doesn't support unescaped unicode characters + /// + /// Unicode code point + /// Actual character + public static string UnescapeUnicodeCodePoint(this string point) + { + var character = 0; + + // Scan the character value. + + foreach (var c in point) + { + if (!IsHex(c)) + return point; + + character = (character << 4) + AsHex(c); + } + + // Check the value and write the character. + + if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF) + return point; + + return char.ConvertFromUtf32(character); + } + + public static bool IsHex(char c) + => c is (>= '0' and <= '9') or (>= 'A' and <= 'F') or (>= 'a' and <= 'f'); + + public static int AsHex(char c) + { + if (c <= '9') + return c - '0'; + + if (c <= 'F') + return c - 'A' + 10; + + return c - 'a' + 10; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs b/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs new file mode 100644 index 0000000..87db412 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs @@ -0,0 +1,78 @@ +#nullable disable +namespace EllieBot; + +public interface IBotCredentials +{ + string Token { get; } + string GoogleApiKey { get; } + ICollection OwnerIds { get; set; } + bool UsePrivilegedIntents { get; } + string RapidApiKey { get; } + + Creds.DbOptions Db { get; } + string OsuApiKey { get; } + int TotalShards { get; } + Creds.PatreonSettings Patreon { get; } + string CleverbotApiKey { get; } + string Gpt3ApiKey { get; } + RestartConfig RestartCommand { get; } + Creds.VotesSettings Votes { get; } + string BotListToken { get; } + string RedisOptions { get; } + string LocationIqApiKey { get; } + string TimezoneDbApiKey { get; } + string CoinmarketcapApiKey { get; } + string TrovoClientId { get; } + string CoordinatorUrl { get; set; } + string TwitchClientId { get; set; } + string TwitchClientSecret { get; set; } + GoogleApiConfig Google { get; set; } + BotCacheImplemenation BotCache { get; set; } +} + +public interface IVotesSettings +{ + string TopggServiceUrl { get; set; } + string TopggKey { get; set; } + string DiscordsServiceUrl { get; set; } + string DiscordsKey { get; set; } +} + +public interface IPatreonSettings +{ + public string ClientId { get; set; } + public string AccessToken { get; set; } + public string RefreshToken { get; set; } + public string ClientSecret { get; set; } + public string CampaignId { get; set; } +} + +public interface IRestartConfig +{ + string Cmd { get; set; } + string Args { get; set; } +} + +public class RestartConfig : IRestartConfig +{ + public string Cmd { get; set; } + public string Args { get; set; } +} + +public enum BotCacheImplemenation +{ + Memory, + Redis +} + +public interface IDbOptions +{ + string Type { get; set; } + string ConnectionString { get; set; } +} + +public interface IGoogleApiConfig +{ + string SearchId { get; init; } + string ImageSearchId { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/creds/IBotCredsProvider.cs b/src/EllieBot/_common/Abstractions/creds/IBotCredsProvider.cs new file mode 100644 index 0000000..ecc90f0 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/creds/IBotCredsProvider.cs @@ -0,0 +1,8 @@ +namespace EllieBot; + +public interface IBotCredsProvider +{ + public void Reload(); + public IBotCredentials GetCreds(); + public void ModifyCredsFile(Action func); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs b/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs new file mode 100644 index 0000000..6f72ab0 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs @@ -0,0 +1,35 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; + +namespace EllieBot.Services; + +// public sealed record class CommandStrings +// { +// [YamlMember(Alias = "desc")] +// public string Desc { get; set; } +// +// [YamlMember(Alias = "args")] +// public string[] Args { get; set; } +// } + +public sealed record class CommandStrings +{ + [YamlMember(Alias = "desc")] + public string Desc { get; set; } + + [YamlMember(Alias = "ex")] + public string[] Examples { get; set; } + + [YamlMember(Alias = "params")] + public Dictionary[] Params { get; set; } +} + +public sealed record class CommandStringParam +{ + // [YamlMember(Alias = "type", ScalarStyle = ScalarStyle.DoubleQuoted)] + // public string Type { get; set; } + + [YamlMember(Alias = "desc", ScalarStyle = ScalarStyle.DoubleQuoted)] + public string Desc { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs b/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs new file mode 100644 index 0000000..2ded833 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs @@ -0,0 +1,16 @@ +#nullable disable +using System.Globalization; + +namespace EllieBot.Common; + +/// +/// Defines methods to retrieve and reload bot strings +/// +public interface IBotStrings +{ + string GetText(string key, ulong? guildId = null, params object[] data); + string GetText(string key, CultureInfo locale, params object[] data); + void Reload(); + CommandStrings GetCommandStrings(string commandName, ulong? guildId = null); + CommandStrings GetCommandStrings(string commandName, CultureInfo cultureInfo); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs b/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs new file mode 100644 index 0000000..17f9377 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs @@ -0,0 +1,17 @@ +#nullable disable +using System.Globalization; + +namespace EllieBot.Common; + +public static class BotStringsExtensions +{ + // this one is for pipe fun, see PipeExtensions.cs + public static string GetText(this IBotStrings strings, in LocStr str, in ulong guildId) + => strings.GetText(str.Key, guildId, str.Params); + + public static string GetText(this IBotStrings strings, in LocStr str, ulong? guildId = null) + => strings.GetText(str.Key, guildId, str.Params); + + public static string GetText(this IBotStrings strings, in LocStr str, CultureInfo culture) + => strings.GetText(str.Key, culture, str.Params); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs b/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs new file mode 100644 index 0000000..87cab9f --- /dev/null +++ b/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs @@ -0,0 +1,28 @@ +#nullable disable +namespace EllieBot.Services; + +/// +/// Implemented by classes which provide localized strings in their own ways +/// +public interface IBotStringsProvider +{ + /// + /// Gets localized string + /// + /// Language name + /// String key + /// Localized string + string GetText(string localeName, string key); + + /// + /// Reloads string cache + /// + void Reload(); + + /// + /// Gets command arg examples and description + /// + /// Language name + /// Command name + CommandStrings GetCommandStrings(string localeName, string commandName); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs b/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs new file mode 100644 index 0000000..a2715f0 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs @@ -0,0 +1,17 @@ +#nullable disable + +namespace EllieBot.Services; + +/// +/// Basic interface used for classes implementing strings loading mechanism +/// +public interface IStringsSource +{ + /// + /// Gets all response strings + /// + /// Dictionary(localename, Dictionary(key, response)) + Dictionary> GetResponseStrings(); + + Dictionary> GetCommandStrings(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/LocStr.cs b/src/EllieBot/_common/Abstractions/strings/LocStr.cs new file mode 100644 index 0000000..78a8bb7 --- /dev/null +++ b/src/EllieBot/_common/Abstractions/strings/LocStr.cs @@ -0,0 +1,13 @@ +namespace EllieBot; + +public readonly struct LocStr +{ + public readonly string Key; + public readonly object[] Params; + + public LocStr(string key, params object[] data) + { + Key = key; + Params = data; + } +} \ No newline at end of file From 29c0b4acfc1cfdf986e5bf79d1af475673976373 Mon Sep 17 00:00:00 2001 From: Toastie Date: Fri, 14 Jun 2024 00:20:21 +1200 Subject: [PATCH 39/62] Updated Db models I hate working on database stuff --- src/EllieBot/Db/EllieContext.cs | 243 +++++++++++++++--- src/EllieBot/Db/Extensions/ClubExtensions.cs | 2 +- .../Db/Extensions/DiscordUserExtensions.cs | 110 ++++---- .../Db/Extensions/GuildConfigExtensions.cs | 9 +- src/EllieBot/Db/Extensions/QuoteExtensions.cs | 2 +- .../Db/Extensions/UserXpExtensions.cs | 61 +++-- .../Db/Extensions/WarningExtensions.cs | 3 +- src/EllieBot/Db/Helpers/ActivityType.cs | 2 +- src/EllieBot/Db/Helpers/GuildPerm.cs | 4 +- src/EllieBot/Db/LevelStats.cs | 4 +- src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs | 2 + src/EllieBot/Db/Models/DiscordUser.cs | 2 +- src/EllieBot/Db/Models/FeedSub.cs | 2 +- src/EllieBot/Db/Models/FollowedStream.cs | 2 +- src/EllieBot/Db/Models/GuildConfig.cs | 1 + .../Db/Models/IgnoredVoicePresenceChannel.cs | 8 - src/EllieBot/Db/Models/LogSetting.cs | 8 +- src/EllieBot/Db/Models/Permission.cs | 5 +- src/EllieBot/Db/Models/ShopEntry.cs | 2 +- src/EllieBot/Db/Models/StreamRoleSettings.cs | 6 + src/EllieBot/Db/Models/Waifu.cs | 4 +- src/EllieBot/Db/Models/anti/AntiAltSetting.cs | 3 +- .../Db/Models/anti/AntiRaidSetting.cs | 5 +- .../Db/Models/anti/AntiSpamSetting.cs | 3 +- src/EllieBot/Db/Models/club/ClubInfo.cs | 2 +- .../Db/Models/filter/FilterChannelId.cs | 14 - .../Db/Models/filter/FilterWordsChannelId.cs | 17 ++ src/EllieBot/Db/Models/support/PatronQuota.cs | 6 +- src/EllieBot/Db/Models/xp/XpSettings.cs | 2 + src/EllieBot/Db/MysqlContext.cs | 2 +- src/EllieBot/Db/PostgreSqlContext.cs | 4 +- src/EllieBot/Db/SqliteContext.cs | 2 +- 32 files changed, 357 insertions(+), 185 deletions(-) delete mode 100644 src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs create mode 100644 src/EllieBot/Db/Models/filter/FilterWordsChannelId.cs diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs index d61d2f7..263963b 100644 --- a/src/EllieBot/Db/EllieContext.cs +++ b/src/EllieBot/Db/EllieContext.cs @@ -28,7 +28,6 @@ public abstract class EllieContext : DbContext //logging public DbSet LogSettings { get; set; } - public DbSet IgnoredVoicePresenceCHannels { get; set; } public DbSet IgnoredLogChannels { get; set; } public DbSet RotatingStatus { get; set; } @@ -86,15 +85,84 @@ public abstract class EllieContext : DbContext #region GuildConfig var configEntity = modelBuilder.Entity(); + configEntity.HasIndex(c => c.GuildId) .IsUnique(); configEntity.Property(x => x.VerboseErrors) .HasDefaultValue(true); - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting); + modelBuilder.Entity() + .HasMany(x => x.DelMsgOnCmdChannels) + .WithOne() + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting); + modelBuilder.Entity() + .HasMany(x => x.FollowedStreams) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.GenerateCurrencyChannelIds) + .WithOne(x => x.GuildConfig) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.Permissions) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.CommandCooldowns) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.FilterInvitesChannelIds) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.FilterLinksChannelIds) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.FilteredWords) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.FilterWordsChannelIds) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.MutedUsers) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasOne(x => x.AntiRaidSetting) + .WithOne() + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + // start antispam + + modelBuilder.Entity() + .HasOne(x => x.AntiSpamSetting) + .WithOne() + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.IgnoredChannels) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + // end antispam modelBuilder.Entity() .HasOne(x => x.AntiAltSetting) @@ -102,6 +170,98 @@ public abstract class EllieContext : DbContext .HasForeignKey(x => x.GuildConfigId) .OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity() + .HasMany(x => x.UnmuteTimers) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.UnbanTimer) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.UnroleTimer) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.VcRoleInfos) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.CommandAliases) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.WarnPunishments) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.SlowmodeIgnoredRoles) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.SlowmodeIgnoredUsers) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + // start shop + modelBuilder.Entity() + .HasMany(x => x.ShopEntries) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.Items) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + // end shop + + // start streamrole + + modelBuilder.Entity() + .HasOne(x => x.StreamRole) + .WithOne(x => x.GuildConfig) + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.Whitelist) + .WithOne(x => x.StreamRoleSettings) + .HasForeignKey(x => x.StreamRoleSettingsId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.Blacklist) + .WithOne(x => x.StreamRoleSettings) + .HasForeignKey(x => x.StreamRoleSettingsId) + .OnDelete(DeleteBehavior.Cascade); + + // end streamrole + + modelBuilder.Entity() + .HasOne(x => x.XpSettings) + .WithOne(x => x.GuildConfig) + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.FeedSubs) + .WithOne(x => x.GuildConfig) + .HasForeignKey(x => x.GuildConfigId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.SelfAssignableRoleGroupNames) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity() .HasAlternateKey(x => new { @@ -117,11 +277,6 @@ public abstract class EllieContext : DbContext #endregion - #region streamrole - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole); - - #endregion #region Self Assignable Roles @@ -217,12 +372,6 @@ public abstract class EllieContext : DbContext #endregion - #region XpSettings - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings); - - #endregion - #region XpRoleReward modelBuilder.Entity() @@ -233,6 +382,21 @@ public abstract class EllieContext : DbContext }) .IsUnique(); + modelBuilder.Entity() + .HasMany(x => x.RoleRewards) + .WithOne(x => x.XpSettings) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.CurrencyRewards) + .WithOne(x => x.XpSettings) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasMany(x => x.ExclusionList) + .WithOne(x => x.XpSettings) + .OnDelete(DeleteBehavior.Cascade); + #endregion #region Club @@ -331,9 +495,9 @@ public abstract class EllieContext : DbContext modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); modelBuilder.Entity() - .Property(x => x.PruneDays) - .HasDefaultValue(null) - .IsRequired(false); + .Property(x => x.PruneDays) + .HasDefaultValue(null) + .IsRequired(false); #endregion @@ -458,7 +622,7 @@ public abstract class EllieContext : DbContext model.ItemType, model.ItemKey }) - .IsUnique(); + .IsUnique(); }); #endregion @@ -466,16 +630,16 @@ public abstract class EllieContext : DbContext #region AutoPublish modelBuilder.Entity(apc => apc - .HasIndex(x => x.GuildId) - .IsUnique()); + .HasIndex(x => x.GuildId) + .IsUnique()); #endregion #region GamblingStats modelBuilder.Entity(gs => gs - .HasIndex(x => x.Feature) - .IsUnique()); + .HasIndex(x => x.Feature) + .IsUnique()); #endregion @@ -485,7 +649,8 @@ public abstract class EllieContext : DbContext { x.GuildId, x.UserId - }).IsUnique()); + }) + .IsUnique()); #endregion @@ -493,18 +658,18 @@ public abstract class EllieContext : DbContext #region Giveaway modelBuilder.Entity() - .HasMany(x => x.Participants) - .WithOne() - .HasForeignKey(x => x.GiveawayId) - .OnDelete(DeleteBehavior.Cascade); + .HasMany(x => x.Participants) + .WithOne() + .HasForeignKey(x => x.GiveawayId) + .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity(gu => gu - .HasIndex(x => new - { - x.GiveawayId, - x.UserId - }) - .IsUnique()); + .HasIndex(x => new + { + x.GiveawayId, + x.UserId + }) + .IsUnique()); #endregion @@ -514,14 +679,14 @@ public abstract class EllieContext : DbContext .HasKey(x => x.Id); modelBuilder.Entity() - .HasIndex(x => x.UserId) - .IsUnique(false); + .HasIndex(x => x.UserId) + .IsUnique(false); modelBuilder.Entity() - .HasMany(x => x.Items) - .WithOne() - .HasForeignKey(x => x.ArchiveId) - .OnDelete(DeleteBehavior.Cascade); + .HasMany(x => x.Items) + .WithOne() + .HasForeignKey(x => x.ArchiveId) + .OnDelete(DeleteBehavior.Cascade); #endregion } diff --git a/src/EllieBot/Db/Extensions/ClubExtensions.cs b/src/EllieBot/Db/Extensions/ClubExtensions.cs index d8183fc..88a851b 100644 --- a/src/EllieBot/Db/Extensions/ClubExtensions.cs +++ b/src/EllieBot/Db/Extensions/ClubExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Db.Models; diff --git a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs index 6d74316..bdf3c05 100644 --- a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs +++ b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs @@ -20,48 +20,48 @@ public static class DiscordUserExtensions string discrim, string avatarId) => ctx.GetTable() - .InsertOrUpdate( - () => new() - { - UserId = userId, - Username = username, - Discriminator = discrim, - AvatarId = avatarId, - TotalXp = 0, - CurrencyAmount = 0 - }, - old => new() - { - Username = username, - Discriminator = discrim, - AvatarId = avatarId - }, - () => new() - { - UserId = userId - }); + .InsertOrUpdate( + () => new() + { + UserId = userId, + Username = username, + Discriminator = discrim, + AvatarId = avatarId, + TotalXp = 0, + CurrencyAmount = 0 + }, + old => new() + { + Username = username, + Discriminator = discrim, + AvatarId = avatarId + }, + () => new() + { + UserId = userId + }); public static Task EnsureUserCreatedAsync( this DbContext ctx, ulong userId) => ctx.GetTable() - .InsertOrUpdateAsync( - () => new() - { - UserId = userId, - Username = "Unknown", - Discriminator = "????", - AvatarId = string.Empty, - TotalXp = 0, - CurrencyAmount = 0 - }, - old => new() - { - }, - () => new() - { - UserId = userId - }); + .InsertOrUpdateAsync( + () => new() + { + UserId = userId, + Username = "Unknown", + Discriminator = "????", + AvatarId = string.Empty, + TotalXp = 0, + CurrencyAmount = 0 + }, + old => new() + { + }, + () => new() + { + UserId = userId + }); //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown public static DiscordUser GetOrCreateUser( @@ -83,25 +83,29 @@ public static class DiscordUserExtensions public static int GetUserGlobalRank(this DbSet users, ulong id) => users.AsQueryable() - .Where(x => x.TotalXp - > users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault()) - .Count() + .Where(x => x.TotalXp + > users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault()) + .Count() + 1; - public static DiscordUser[] GetUsersXpLeaderboardFor(this DbSet users, int page, int perPage) - => users.AsQueryable().OrderByDescending(x => x.TotalXp).Skip(page * perPage).Take(perPage).AsEnumerable() - .ToArray(); + public static async Task> GetUsersXpLeaderboardFor(this DbSet users, int page, int perPage) + => await users.ToLinqToDBTable() + .OrderByDescending(x => x.TotalXp) + .Skip(page * perPage) + .Take(perPage) + .ToArrayAsyncLinqToDB(); public static Task> GetTopRichest( this DbSet users, ulong botId, - int page = 0, int perPage = 9) + int page = 0, + int perPage = 9) => users.AsQueryable() - .Where(c => c.CurrencyAmount > 0 && botId != c.UserId) - .OrderByDescending(c => c.CurrencyAmount) - .Skip(page * perPage) - .Take(perPage) - .ToListAsyncLinqToDB(); + .Where(c => c.CurrencyAmount > 0 && botId != c.UserId) + .OrderByDescending(c => c.CurrencyAmount) + .Skip(page * perPage) + .Take(perPage) + .ToListAsyncLinqToDB(); public static async Task GetUserCurrencyAsync(this DbSet users, ulong userId) => (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0; @@ -118,8 +122,8 @@ public static class DiscordUserExtensions public static decimal GetTopOnePercentCurrency(this DbSet users, ulong botId) => users.AsQueryable() - .Where(x => x.UserId != botId) - .OrderByDescending(x => x.CurrencyAmount) - .Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100) - .Sum(x => x.CurrencyAmount); + .Where(x => x.UserId != botId) + .OrderByDescending(x => x.CurrencyAmount) + .Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100) + .Sum(x => x.CurrencyAmount); } \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs index bffa943..7d16127 100644 --- a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs +++ b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Db.Models; @@ -7,19 +7,20 @@ namespace EllieBot.Db; public static class GuildConfigExtensions { private static List DefaultWarnPunishments - => new() - { + => + [ new() { Count = 3, Punishment = PunishmentAction.Kick }, + new() { Count = 5, Punishment = PunishmentAction.Ban } - }; + ]; /// /// Gets full stream role settings for the guild with the specified id. diff --git a/src/EllieBot/Db/Extensions/QuoteExtensions.cs b/src/EllieBot/Db/Extensions/QuoteExtensions.cs index 67698e9..a213e6d 100644 --- a/src/EllieBot/Db/Extensions/QuoteExtensions.cs +++ b/src/EllieBot/Db/Extensions/QuoteExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using Microsoft.EntityFrameworkCore; using EllieBot.Db.Models; diff --git a/src/EllieBot/Db/Extensions/UserXpExtensions.cs b/src/EllieBot/Db/Extensions/UserXpExtensions.cs index c7e0f8c..ab3e8bb 100644 --- a/src/EllieBot/Db/Extensions/UserXpExtensions.cs +++ b/src/EllieBot/Db/Extensions/UserXpExtensions.cs @@ -26,33 +26,33 @@ public static class UserXpExtensions return usr; } - public static List GetUsersFor(this DbSet xps, ulong guildId, int page) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId) - .OrderByDescending(x => x.Xp + x.AwardedXp) - .Skip(page * 9) - .Take(9) - .ToList(); + public static async Task> GetUsersFor( + this DbSet xps, + ulong guildId, + int page) + => await xps.ToLinqToDBTable() + .Where(x => x.GuildId == guildId) + .OrderByDescending(x => x.Xp + x.AwardedXp) + .Skip(page * 9) + .Take(9) + .ToArrayAsyncLinqToDB(); - public static List GetTopUserXps(this DbSet xps, ulong guildId, int count) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId) - .OrderByDescending(x => x.Xp + x.AwardedXp) - .Take(count) - .ToList(); + public static async Task> GetTopUserXps(this DbSet xps, ulong guildId, int count) + => await xps.ToLinqToDBTable() + .Where(x => x.GuildId == guildId) + .OrderByDescending(x => x.Xp + x.AwardedXp) + .Take(count) + .ToListAsyncLinqToDB(); - public static int GetUserGuildRanking(this DbSet xps, ulong userId, ulong guildId) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId - && x.Xp + x.AwardedXp - > xps.AsQueryable() - .Where(y => y.UserId == userId && y.GuildId == guildId) - .Select(y => y.Xp + y.AwardedXp) - .FirstOrDefault()) - .Count() + public static async Task GetUserGuildRanking(this DbSet xps, ulong userId, ulong guildId) + => await xps.ToLinqToDBTable() + .Where(x => x.GuildId == guildId + && x.Xp + x.AwardedXp + > xps.AsQueryable() + .Where(y => y.UserId == userId && y.GuildId == guildId) + .Select(y => y.Xp + y.AwardedXp) + .FirstOrDefault()) + .CountAsyncLinqToDB() + 1; public static void ResetGuildUserXp(this DbSet xps, ulong userId, ulong guildId) @@ -62,10 +62,9 @@ public static class UserXpExtensions => xps.Delete(x => x.GuildId == guildId); public static async Task GetLevelDataFor(this ITable userXp, ulong guildId, ulong userId) - => await userXp - .Where(x => x.GuildId == guildId && x.UserId == userId) - .FirstOrDefaultAsyncLinqToDB() is UserXpStats uxs - ? new(uxs.Xp + uxs.AwardedXp) - : new(0); - + => await userXp + .Where(x => x.GuildId == guildId && x.UserId == userId) + .FirstOrDefaultAsyncLinqToDB() is UserXpStats uxs + ? new(uxs.Xp + uxs.AwardedXp) + : new(0); } \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WarningExtensions.cs b/src/EllieBot/Db/Extensions/WarningExtensions.cs index c223f7d..15f1039 100644 --- a/src/EllieBot/Db/Extensions/WarningExtensions.cs +++ b/src/EllieBot/Db/Extensions/WarningExtensions.cs @@ -22,8 +22,7 @@ public static class WarningExtensions string mod, int index) { - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index)); + ArgumentOutOfRangeException.ThrowIfNegative(index); var warn = warnings.AsQueryable() .Where(x => x.GuildId == guildId && x.UserId == userId) diff --git a/src/EllieBot/Db/Helpers/ActivityType.cs b/src/EllieBot/Db/Helpers/ActivityType.cs index 64bdd73..9c71e4b 100644 --- a/src/EllieBot/Db/Helpers/ActivityType.cs +++ b/src/EllieBot/Db/Helpers/ActivityType.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Db; +namespace EllieBot.Db; public enum DbActivityType { diff --git a/src/EllieBot/Db/Helpers/GuildPerm.cs b/src/EllieBot/Db/Helpers/GuildPerm.cs index 4713afa..60c4cde 100644 --- a/src/EllieBot/Db/Helpers/GuildPerm.cs +++ b/src/EllieBot/Db/Helpers/GuildPerm.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Db; +namespace EllieBot.Db; [Flags] public enum GuildPerm : ulong @@ -44,4 +44,4 @@ public enum GuildPerm : ulong SendMessagesInThreads = 274877906944, // 0x0000004000000000 StartEmbeddedActivities = 549755813888, // 0x0000008000000000 ModerateMembers = 1099511627776, // 0x0000010000000000 -} +} \ No newline at end of file diff --git a/src/EllieBot/Db/LevelStats.cs b/src/EllieBot/Db/LevelStats.cs index fbb2e47..0f3e02c 100644 --- a/src/EllieBot/Db/LevelStats.cs +++ b/src/EllieBot/Db/LevelStats.cs @@ -1,10 +1,10 @@ -#nullable disable +#nullable disable namespace EllieBot.Db; public readonly struct LevelStats { public const int XP_REQUIRED_LVL_1 = 36; - + public long Level { get; } public long LevelXp { get; } public long RequiredXp { get; } diff --git a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs index 6cbe756..dd70ed6 100644 --- a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs +++ b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs @@ -3,6 +3,8 @@ namespace EllieBot.Db.Models; public class DelMsgOnCmdChannel : DbEntity { + public int GuildConfigId { get; set; } + public ulong ChannelId { get; set; } public bool State { get; set; } diff --git a/src/EllieBot/Db/Models/DiscordUser.cs b/src/EllieBot/Db/Models/DiscordUser.cs index 83bda60..69eecb6 100644 --- a/src/EllieBot/Db/Models/DiscordUser.cs +++ b/src/EllieBot/Db/Models/DiscordUser.cs @@ -29,7 +29,7 @@ public class DiscordUser : DbEntity { if (string.IsNullOrWhiteSpace(Discriminator) || Discriminator == "0000") return Username; - + return Username + "#" + Discriminator; } } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FeedSub.cs b/src/EllieBot/Db/Models/FeedSub.cs index 66fc6f1..f257f96 100644 --- a/src/EllieBot/Db/Models/FeedSub.cs +++ b/src/EllieBot/Db/Models/FeedSub.cs @@ -8,7 +8,7 @@ public class FeedSub : DbEntity public ulong ChannelId { get; set; } public string Url { get; set; } - + public string Message { get; set; } public override int GetHashCode() diff --git a/src/EllieBot/Db/Models/FollowedStream.cs b/src/EllieBot/Db/Models/FollowedStream.cs index c880a8d..183e0ab 100644 --- a/src/EllieBot/Db/Models/FollowedStream.cs +++ b/src/EllieBot/Db/Models/FollowedStream.cs @@ -29,5 +29,5 @@ public class FollowedStream : DbEntity public override bool Equals(object obj) => obj is FollowedStream fs && Equals(fs); - + } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GuildConfig.cs b/src/EllieBot/Db/Models/GuildConfig.cs index a7b5ac5..a88d3c0 100644 --- a/src/EllieBot/Db/Models/GuildConfig.cs +++ b/src/EllieBot/Db/Models/GuildConfig.cs @@ -3,6 +3,7 @@ namespace EllieBot.Db.Models; public class GuildConfig : DbEntity { + // public bool Keep { get; set; } public ulong GuildId { get; set; } public string Prefix { get; set; } diff --git a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs deleted file mode 100644 index cbbda9e..0000000 --- a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Db.Models; - -public class IgnoredVoicePresenceChannel : DbEntity -{ - public LogSetting LogSetting { get; set; } - public ulong ChannelId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/LogSetting.cs b/src/EllieBot/Db/Models/LogSetting.cs index 677a128..916b1b8 100644 --- a/src/EllieBot/Db/Models/LogSetting.cs +++ b/src/EllieBot/Db/Models/LogSetting.cs @@ -4,7 +4,7 @@ namespace EllieBot.Db.Models; public class LogSetting : DbEntity { public List LogIgnores { get; set; } = new(); - + public ulong GuildId { get; set; } public ulong? LogOtherId { get; set; } public ulong? MessageUpdatedId { get; set; } @@ -19,8 +19,8 @@ public class LogSetting : DbEntity public ulong? ChannelCreatedId { get; set; } public ulong? ChannelDestroyedId { get; set; } public ulong? ChannelUpdatedId { get; set; } - - + + public ulong? ThreadDeletedId { get; set; } public ulong? ThreadCreatedId { get; set; } @@ -32,7 +32,7 @@ public class LogSetting : DbEntity //voicepresence public ulong? LogVoicePresenceId { get; set; } - + public ulong? LogVoicePresenceTTSId { get; set; } public ulong? LogWarnsId { get; set; } } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Permission.cs b/src/EllieBot/Db/Models/Permission.cs index 5670dd8..b926f92 100644 --- a/src/EllieBot/Db/Models/Permission.cs +++ b/src/EllieBot/Db/Models/Permission.cs @@ -33,10 +33,7 @@ public class Permissionv2 : DbEntity, IIndexed }; public static List GetDefaultPermlist - => new() - { - AllowAllPerm - }; + => [AllowAllPerm]; } public enum PrimaryPermissionType diff --git a/src/EllieBot/Db/Models/ShopEntry.cs b/src/EllieBot/Db/Models/ShopEntry.cs index 34cc8fe..a21c7e6 100644 --- a/src/EllieBot/Db/Models/ShopEntry.cs +++ b/src/EllieBot/Db/Models/ShopEntry.cs @@ -25,7 +25,7 @@ public class ShopEntry : DbEntity, IIndexed //list public HashSet Items { get; set; } = new(); public ulong? RoleRequirement { get; set; } - + // command public string Command { get; set; } } diff --git a/src/EllieBot/Db/Models/StreamRoleSettings.cs b/src/EllieBot/Db/Models/StreamRoleSettings.cs index 02674d5..bd36b4c 100644 --- a/src/EllieBot/Db/Models/StreamRoleSettings.cs +++ b/src/EllieBot/Db/Models/StreamRoleSettings.cs @@ -40,6 +40,9 @@ public class StreamRoleSettings : DbEntity public class StreamRoleBlacklistedUser : DbEntity { + public int StreamRoleSettingsId { get; set; } + public StreamRoleSettings StreamRoleSettings { get; set; } + public ulong UserId { get; set; } public string Username { get; set; } @@ -57,6 +60,9 @@ public class StreamRoleBlacklistedUser : DbEntity public class StreamRoleWhitelistedUser : DbEntity { + public int StreamRoleSettingsId { get; set; } + public StreamRoleSettings StreamRoleSettings { get; set; } + public ulong UserId { get; set; } public string Username { get; set; } diff --git a/src/EllieBot/Db/Models/Waifu.cs b/src/EllieBot/Db/Models/Waifu.cs index 78ca0b3..d9f36d9 100644 --- a/src/EllieBot/Db/Models/Waifu.cs +++ b/src/EllieBot/Db/Models/Waifu.cs @@ -1,13 +1,13 @@ #nullable disable using EllieBot.Db.Models; -namespace EllieBot.Services.Database.Models; +namespace NadekoBot.Services.Database.Models; public class WaifuInfo : DbEntity { public int WaifuId { get; set; } public DiscordUser Waifu { get; set; } - + public int? ClaimerId { get; set; } public DiscordUser Claimer { get; set; } diff --git a/src/EllieBot/Db/Models/anti/AntiAltSetting.cs b/src/EllieBot/Db/Models/anti/AntiAltSetting.cs index b9f9e58..cb0da3c 100644 --- a/src/EllieBot/Db/Models/anti/AntiAltSetting.cs +++ b/src/EllieBot/Db/Models/anti/AntiAltSetting.cs @@ -2,8 +2,9 @@ public class AntiAltSetting { - public int Id { get; set; } public int GuildConfigId { get; set; } + + public int Id { get; set; } public TimeSpan MinAge { get; set; } public PunishmentAction Action { get; set; } public int ActionDurationMinutes { get; set; } diff --git a/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs b/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs index aef2658..b5e5f67 100644 --- a/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs +++ b/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs @@ -1,12 +1,13 @@ #nullable disable +using System.ComponentModel.DataAnnotations.Schema; + namespace EllieBot.Db.Models; public class AntiRaidSetting : DbEntity { public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - + public int UserThreshold { get; set; } public int Seconds { get; set; } public PunishmentAction Action { get; set; } diff --git a/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs b/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs index 42c2183..7e19253 100644 --- a/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs +++ b/src/EllieBot/Db/Models/anti/AntiSpamSetting.cs @@ -4,8 +4,7 @@ public class AntiSpamSetting : DbEntity { public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - + public PunishmentAction Action { get; set; } public int MessageThreshold { get; set; } = 3; public int MuteTime { get; set; } diff --git a/src/EllieBot/Db/Models/club/ClubInfo.cs b/src/EllieBot/Db/Models/club/ClubInfo.cs index e5b7407..a7bc16f 100644 --- a/src/EllieBot/Db/Models/club/ClubInfo.cs +++ b/src/EllieBot/Db/Models/club/ClubInfo.cs @@ -9,7 +9,7 @@ public class ClubInfo : DbEntity public string Name { get; set; } public string Description { get; set; } public string ImageUrl { get; set; } = string.Empty; - + public int Xp { get; set; } = 0; public int? OwnerId { get; set; } public DiscordUser Owner { get; set; } diff --git a/src/EllieBot/Db/Models/filter/FilterChannelId.cs b/src/EllieBot/Db/Models/filter/FilterChannelId.cs index fe3b97b..eb1d965 100644 --- a/src/EllieBot/Db/Models/filter/FilterChannelId.cs +++ b/src/EllieBot/Db/Models/filter/FilterChannelId.cs @@ -14,17 +14,3 @@ public class FilterChannelId : DbEntity public override int GetHashCode() => ChannelId.GetHashCode(); } - -public class FilterWordsChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public bool Equals(FilterWordsChannelId other) - => ChannelId == other.ChannelId; - - public override bool Equals(object obj) - => obj is FilterWordsChannelId fci && Equals(fci); - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/filter/FilterWordsChannelId.cs b/src/EllieBot/Db/Models/filter/FilterWordsChannelId.cs new file mode 100644 index 0000000..6921032 --- /dev/null +++ b/src/EllieBot/Db/Models/filter/FilterWordsChannelId.cs @@ -0,0 +1,17 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class FilterWordsChannelId : DbEntity +{ + public int? GuildConfigId { get; set; } + public ulong ChannelId { get; set; } + + public bool Equals(FilterWordsChannelId other) + => ChannelId == other.ChannelId; + + public override bool Equals(object obj) + => obj is FilterWordsChannelId fci && Equals(fci); + + public override int GetHashCode() + => ChannelId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/support/PatronQuota.cs b/src/EllieBot/Db/Models/support/PatronQuota.cs index b87dcbc..1ebd2fd 100644 --- a/src/EllieBot/Db/Models/support/PatronQuota.cs +++ b/src/EllieBot/Db/Models/support/PatronQuota.cs @@ -30,12 +30,12 @@ public class PatronUser public string UniquePlatformUserId { get; set; } public ulong UserId { get; set; } public int AmountCents { get; set; } - + public DateTime LastCharge { get; set; } - + // Date Only component public DateTime ValidThru { get; set; } - + public PatronUser Clone() => new PatronUser() { diff --git a/src/EllieBot/Db/Models/xp/XpSettings.cs b/src/EllieBot/Db/Models/xp/XpSettings.cs index 694b289..50fd5be 100644 --- a/src/EllieBot/Db/Models/xp/XpSettings.cs +++ b/src/EllieBot/Db/Models/xp/XpSettings.cs @@ -51,6 +51,8 @@ public class XpCurrencyReward : DbEntity public class ExcludedItem : DbEntity { + public XpSettings XpSettings { get; set; } + public ulong ItemId { get; set; } public ExcludedItemType ItemType { get; set; } diff --git a/src/EllieBot/Db/MysqlContext.cs b/src/EllieBot/Db/MysqlContext.cs index e8f4eba..7563640 100644 --- a/src/EllieBot/Db/MysqlContext.cs +++ b/src/EllieBot/Db/MysqlContext.cs @@ -28,7 +28,7 @@ public sealed class MysqlContext : EllieContext protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); - + // mysql is case insensitive by default // we can set binary collation to change that modelBuilder.Entity() diff --git a/src/EllieBot/Db/PostgreSqlContext.cs b/src/EllieBot/Db/PostgreSqlContext.cs index aea3e7c..2305d19 100644 --- a/src/EllieBot/Db/PostgreSqlContext.cs +++ b/src/EllieBot/Db/PostgreSqlContext.cs @@ -6,7 +6,7 @@ public sealed class PostgreSqlContext : EllieContext { private readonly string _connStr; - protected override string CurrencyTransactionOtherIdDefaultValue + protected override string CurrencyTransactionOtherIdDefaultValue => "NULL"; public PostgreSqlContext(string connStr = "Host=localhost") @@ -17,7 +17,7 @@ public sealed class PostgreSqlContext : EllieContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); - + base.OnConfiguring(optionsBuilder); optionsBuilder .UseLowerCaseNamingConvention() diff --git a/src/EllieBot/Db/SqliteContext.cs b/src/EllieBot/Db/SqliteContext.cs index e284968..516d445 100644 --- a/src/EllieBot/Db/SqliteContext.cs +++ b/src/EllieBot/Db/SqliteContext.cs @@ -7,7 +7,7 @@ public sealed class SqliteContext : EllieContext { private readonly string _connectionString; - protected override string CurrencyTransactionOtherIdDefaultValue + protected override string CurrencyTransactionOtherIdDefaultValue => "NULL"; public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60) From 7ce7c9b4ffdb95eba101a3145adccceca6343239 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:30:39 +1200 Subject: [PATCH 40/62] Updated data files Some random stuff in these files got changed --- src/EllieBot/data/aliases.yml | 15 +- src/EllieBot/data/bot.yml | 6 +- .../data/strings/commands/commands.en-US.yml | 690 +++++++++--------- .../strings/responses/responses.en-US.json | 29 +- 4 files changed, 398 insertions(+), 342 deletions(-) diff --git a/src/EllieBot/data/aliases.yml b/src/EllieBot/data/aliases.yml index 4ec12e0..8d83875 100644 --- a/src/EllieBot/data/aliases.yml +++ b/src/EllieBot/data/aliases.yml @@ -1,6 +1,6 @@ h: - - help - h + - help gencmdlist: - gencmdlist donate: @@ -37,7 +37,7 @@ boost: boostmsg: - boostmsg boostdel: - - boostde + - boostdel logserver: - logserver logignore: @@ -195,6 +195,12 @@ setname: - newnm setnick: - setnick +setserverbanner: + - setserverbanner + - serverbanner +setservericon: + - setservericon + - servericon setavatar: - setavatar - setav @@ -335,6 +341,9 @@ allcmdcooldowns: quoteadd: - quoteadd - . +quoteedit: + - quoteedit + - qedit quoteprint: - quoteprint - .. @@ -1396,3 +1405,5 @@ todoshow: - see stickyroles: - stickyroles +cleanupguilddata: + - cleanupguilddata \ No newline at end of file diff --git a/src/EllieBot/data/bot.yml b/src/EllieBot/data/bot.yml index 81130d1..55a1d51 100644 --- a/src/EllieBot/data/bot.yml +++ b/src/EllieBot/data/bot.yml @@ -27,7 +27,7 @@ forwardMessages: false forwardToAllOwners: false # Any messages sent by users in Bot's DM to be forwarded to the specified channel. # This option will only work when ForwardToAllOwners is set to false -forwardToChannel: +forwardToChannel: # Should the bot ignore messages from other bots? # Settings this to false might get your bot banned if it gets into a spam loop with another bot. # This will only affect command executions, other features will still block bots from access. @@ -51,7 +51,7 @@ dmHelpTextKeywords: helpText: |- { "title": "To invite me to your server, use this link", - "description": "https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303", + "description": "https://discord.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303", "color": 53380, "thumbnail": "https://cdn.elliebot.net/Ellie.png", "fields": [ @@ -69,7 +69,7 @@ helpText: |- }, { "name": "Ellie Support Server", - "value": "https://discord.gg/etQdZxSyEH", + "value": "https://discord.gg/etQdZxSyEH/ ", "inline": true } ] diff --git a/src/EllieBot/data/strings/commands/commands.en-US.yml b/src/EllieBot/data/strings/commands/commands.en-US.yml index 61d97ee..d64534e 100644 --- a/src/EllieBot/data/strings/commands/commands.en-US.yml +++ b/src/EllieBot/data/strings/commands/commands.en-US.yml @@ -1,8 +1,8 @@ h: desc: Either shows a help for a single command, or DMs you help link if no parameters are specified. ex: - - "{0}cmds" - - "" + - '{0}cmds' + - '' params: - fail: desc: "Fallback parameter if the command is not found." @@ -11,19 +11,19 @@ h: gencmdlist: desc: Generates the command list and sends it to the chat. Optionally also uploads it to DO spaces (not supported). ex: - - "" + - '' params: - {} donate: desc: Instructions for helping the project financially. ex: - - "" + - '' params: - {} modules: desc: Lists all bot modules. ex: - - "" + - '' params: - page: desc: "The number of the page to display in the list of bot modules." @@ -32,7 +32,7 @@ commands: ex: - Admin - Admin --view 1 - - "" + - '' params: - module: desc: "The name of a module to retrieve command information for." @@ -49,14 +49,14 @@ greetdel: greet: desc: Toggles announcements on the current channel when someone joins the server. ex: - - "" + - '' params: - {} greetmsg: desc: |- Sets a new join announcement message which will be shown in the server's channel. Type `%user.mention%` if you want to mention the new member. - Full list of placeholders can be found here + Full list of placeholders can be found here Using it with no message will show the current greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. ex: @@ -67,18 +67,18 @@ greetmsg: bye: desc: Toggles announcements on the current channel when someone leaves the server. ex: - - "" + - '' params: - {} byemsg: desc: |- Sets a new leave announcement message. Type `%user.mention%` if you want to show the name the user who left. - Full list of placeholders can be found here + Full list of placeholders can be found here Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. ex: - - "%user.mention% has left." + - '%user.mention% has left.' params: - text: desc: "The user's farewell message to display when they leave the chat." @@ -93,48 +93,48 @@ byedel: greetdm: desc: Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). ex: - - "" + - '' params: - {} greettest: desc: Sends the greet message in the current channel as if you just joined the server. You can optionally specify a different user. ex: - - "" - - "@SomeoneElse" + - '' + - '@SomeoneElse' params: - user: desc: "The user to impersonate when sending the greeting, or null for the bot's own account." greetdmtest: desc: Sends the greet direct message to you as if you just joined the server. You can optionally specify a different user. ex: - - "" - - "@SomeoneElse" + - '' + - '@SomeoneElse' params: - user: desc: "The recipient of the greeting, which defaults to the caller if not specified." byetest: desc: Sends the bye message in the current channel as if you just left the server. You can optionally specify a different user. ex: - - "" - - "@SomeoneElse" + - '' + - '@SomeoneElse' params: - user: desc: "The user who is leaving the channel, or whose account is being represented as leaving the channel." boost: desc: Toggles announcements on the current channel when someone boosts the server. ex: - - "" + - '' params: - {} boostmsg: desc: |- Sets a new boost announcement message. Type `%user.mention%` if you want to show the name the user who left. - Full list of placeholders can be found here + Full list of placeholders can be found here Using this command with no message will show the current boost message. You can use embed json from instead of a regular text, if you want the message to be embedded. ex: - - "%user.mention% has boosted the server!!!" + - '%user.mention% has boosted the server!!!' params: - text: desc: "The text to set as the new announcement message." @@ -157,9 +157,9 @@ logserver: logignore: desc: Toggles whether the `{0}logserver` command ignores the specified channel or user. Provide no arguments to see the list of currently ignored users and channels ex: - - "" - - "@SomeUser" - - "#some-channel" + - '' + - '@SomeUser' + - '#some-channel' params: - {} - target: @@ -169,7 +169,7 @@ logignore: repeatlist: desc: Shows currently repeating messages and their indexes. ex: - - "" + - '' params: - {} repeatremove: @@ -187,12 +187,19 @@ repeatinvoke: - index: desc: "The index at which to display the repeat message." repeat: - desc: Repeat a message once every specified amount of time in the current channel. You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). If you've specified time of day, you can still override the default daily interval with your own interval. You can have up to 5 repeating messages on the server in total. + desc: |- + Repeat a message once every specified amount of time in the current channel. + You can specify a different channel as the first argument. + You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). + If you've specified time of day, you can still override the default daily interval with your own interval. + You can have up to 5 repeating messages on the server in total. ex: - Hello there - - 1h5m Hello @erryone - - 10:00 Daily have a nice day! This will execute once every 24h. - - 21:00 30m Starting at 21 and every 30 minutes after that i will send this message! + - '#other-channel hello there' + - '1h5m Hello @erryone' + - '10:00 Daily have a nice day! This will execute once every 24h.' + - '#other-channel 10:00 Daily have a nice day! This will execute once every 24h.' + - '21:00 30m Starting at 21 and every 30 minutes after that i will send this message!' params: - message: desc: "The text to be repeated at the specified intervals or times." @@ -204,23 +211,23 @@ repeat: desc: "The amount of time between each repetition." message: desc: "The text to be repeated at the specified intervals or times." - - ch: + - channel: desc: "The channel where the message will be sent." interval: desc: "The amount of time between each repetition." message: desc: "The text to be repeated at the specified intervals or times." - - dt: + - timeOfDay: desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." message: desc: "The text to be repeated at the specified intervals or times." - channel: desc: "The channel where the message will be repeated." - dt: + timeOfDay: desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." message: desc: "The text to be repeated at the specified intervals or times." - - dt: + - timeOfDay: desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." interval: desc: "The amount of time between each repetition." @@ -228,7 +235,7 @@ repeat: desc: "The text to be repeated at the specified intervals or times." - channel: desc: "The channel where the message will be repeated." - dt: + timeOfDay: desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." interval: desc: "The amount of time between each repetition." @@ -251,7 +258,7 @@ repeatskip: rotateplaying: desc: Toggles rotation of playing status of the dynamic strings you previously specified. ex: - - "" + - '' params: - {} addplaying: @@ -267,27 +274,27 @@ addplaying: listplaying: desc: Lists all playing statuses with their corresponding number. ex: - - "" + - '' params: - {} removeplaying: desc: Removes a playing string on a given number. ex: - - "" + - '' params: - index: desc: "The position in the list where the playing string should be removed." vcrolelist: desc: Shows a list of currently set voice channel roles. ex: - - "" + - '' params: - {} vcrole: desc: Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. ex: - SomeRole - - "" + - '' params: - role: desc: "The role that is assigned to new members of the voice channel." @@ -323,7 +330,7 @@ rsar: lsar: desc: Lists self-assignable roles. Shows 20 roles per page. ex: - - "" + - '' - 2 params: - page: @@ -341,7 +348,7 @@ sargn: togglexclsar: desc: Toggles whether the self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group. ex: - - "" + - '' params: - {} iam: @@ -359,16 +366,16 @@ iamnot: - role: desc: "The role being removed from the user's assignment." expradd: - desc: "Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide here: " + desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide here: ' ex: - '"hello" Hi there %user.mention%' params: - - key: + - trigger: desc: "The trigger word that sets off the response when typed by a user." - message: - desc: "The text of the message that triggers the response when typed by a user." + response: + desc: "The text of the message that shows up when a user types the trigger word." expraddserver: - desc: "Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. Guide here: " + desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. Guide here: ' ex: - '"hello" Hi there %user.mention%' params: @@ -415,25 +422,25 @@ exprdeleteserver: exprclear: desc: Deletes all expression on this server. ex: - - "" + - '' params: - {} fwclear: desc: Deletes all filtered words on this server. ex: - - "" + - '' params: - {} filterlist: desc: Lists invite and link filter channels and status. ex: - - "" + - '' params: - {} aliasesclear: desc: Deletes all aliases on this server. ex: - - "" + - '' params: - {} autoassignrole: @@ -443,7 +450,7 @@ autoassignrole: Specifying the role that is already added will remove that role from the list. Provide no parameters to list current roles. ex: - - "" + - '' - RoleName params: - role: @@ -459,7 +466,7 @@ leave: slowmode: desc: Toggles slowmode on the current channel with the specified amount of time. Provide no parameters to disable. ex: - - "" + - '' - 27s - 3h15m5s params: @@ -468,7 +475,7 @@ slowmode: delmsgoncmd: desc: "Toggles the automatic deletion of the user's successful command message to prevent chat flood. You can use it either as a server toggle, channel whitelist, or channel blacklist, as channel option has 3 settings: Enable (always do it on this channel), Disable (never do it on this channel), and Inherit (respect server setting). Use `list` parameter to see the current states." ex: - - "" + - '' - channel enable - ch inherit - list @@ -492,13 +499,13 @@ delmsgoncmd: restart: desc: Restarts the bot. Might not work. ex: - - "" + - '' params: - {} setrole: desc: Gives a role to a user. The role you specify has to be lower in the role hierarchy than your highest role. ex: - - "@User Guest" + - '@User Guest' params: - targetUser: desc: "The user being given the new role, which must have a lower rank than the assistant's highest role." @@ -507,7 +514,7 @@ setrole: removerole: desc: Removes a role from a user. The role you specify has to be lower in the role hierarchy than your highest role. ex: - - "@User Admin" + - '@User Admin' params: - targetUser: desc: "The user account being modified or checked for role eligibility." @@ -525,7 +532,7 @@ renamerole: removeallroles: desc: Removes all roles which are lower than your highest role in the role hierarchy from the user you specify. ex: - - "@User" + - '@User' params: - user: desc: "The user whose roles will be updated to reflect the new role hierarchy." @@ -566,7 +573,7 @@ rolecolor: ban: desc: Bans a user by ID or name with an optional message. You can specify a time string before the user name to ban the user temporarily. ex: - - "@Someone Get out!" + - '@Someone Get out!' - '"Some Guy#1234" Your behaviour is toxic.' - 1d12h @Someone Come back when u chill params: @@ -593,7 +600,7 @@ ban: softban: desc: Bans and then unbans a user by ID or name with an optional message. ex: - - "@Someone Get out!" + - '@Someone Get out!' - '"Some Guy#1234" Your behaviour is toxic.' params: - user: @@ -607,7 +614,7 @@ softban: kick: desc: Kicks a mentioned user. ex: - - "@Someone Get out!" + - '@Someone Get out!' - '"Some Guy#1234" Your behaviour is toxic.' params: - user: @@ -621,8 +628,8 @@ kick: timeout: desc: Times the user out for the specified amount of time. You may optionally specify a reason, which will be sent to the user. ex: - - "@Someone 3h Shut up!" - - "@Someone 1h30m" + - '@Someone 3h Shut up!' + - '@Someone 1h30m' params: - globalUser: desc: "The user's account or identity that is being timed out." @@ -633,8 +640,8 @@ timeout: mute: desc: Mutes a mentioned user both from speaking and chatting. You can also specify time string for how long the user should be muted. You can optionally specify a reason. ex: - - "@Someone" - - "@Someone too noisy" + - '@Someone' + - '@Someone too noisy' - 1h30m @Someone - 1h30m @Someone too noisy params: @@ -651,7 +658,7 @@ mute: voiceunmute: desc: Gives a previously voice-muted user a permission to speak. ex: - - "@Someguy" + - '@Someguy' params: - user: desc: "The user who was previously muted is now able to participate in the conversation again." @@ -718,14 +725,14 @@ setchanlname: prune: desc: "`{0}prune` removes all Ellie's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel." ex: - - "" + - '' - -s - 5 - 5 --safe - - "@Someone" - - "@Someone --safe" - - "@Someone X" - - "@Someone X -s" + - '@Someone' + - '@Someone --safe' + - '@Someone X' + - '@Someone X -s' params: - params: desc: "The list of users, channels or message counts to be removed from the conversation history." @@ -748,13 +755,13 @@ prune: prunecancel: desc: Cancels an active prune if there is any. ex: - - "" + - '' params: - {} die: desc: Shuts the bot down. ex: - - "" + - '' params: - graceful: desc: "The option to perform a controlled shutdown, allowing for any necessary cleanup or notifications before termination." @@ -769,7 +776,7 @@ setnick: desc: Changes the nickname of the bot on this server. You can also target other users to change their nickname. ex: - BotNickname - - "@SomeUser New Nickname" + - '@SomeUser New Nickname' params: - newNick: desc: "The new nickname to be displayed for the bot or targeted user." @@ -780,14 +787,14 @@ setnick: setavatar: desc: Sets a new avatar image for the EllieBot. Parameter is a direct link to an image. ex: - - https://i.imgur.com/xTG3a1I.jpg + - https://cdn.elliebot.net/Ellie.png params: - img: desc: "The URL of the image file to be displayed as the bot's avatar." setbanner: desc: Sets a new banner image for the EllieBot. Parameter is a direct link to an image. Supports gifs. ex: - - https://i.imgur.com/xTG3a1I.jpg + - https://cdn.elliebot.net/Ellie.png params: - img: desc: "The URL of the image file to be displayed as the bot's banner." @@ -802,8 +809,22 @@ setgame: desc: "The activity type determines whether the bot is engaged in a game, listening to audio, or watching a video." game: desc: "The current state of the bot's activity in the game." +setserverbanner: + desc: Sets a new banner image for the current server. Parameter is a direct link to an image. + ex: + - https://cdn.elliebot.net/Ellie.png + params: + - img: + desc: "The URL of the image file to be displayed as the bot's banner." +setservericon: + desc: Sets a new icon image for the current server. Parameter is a direct link to an image. + ex: + - https://cdn.elliebot.net/Ellie.png + params: + - img: + desc: "The URL of the image file to be displayed as the bot's banner." send: - desc: "Sends a message to a channel or user. Channel or user can be " + desc: 'Sends a message to a channel or user. Channel or user can be ' ex: - channel 123123123132312 Stop spamming commands plz - user 1231231232132 I can see in the console what you're doing. @@ -825,7 +846,7 @@ remind: desc: "Sends a message to you or a channel after certain amount of time (max 2 months). First parameter is `me`/`here`/'channelname'. Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third parameter is a (multiword) message. Requires ManageMessages server permission if you're targeting a different channel." ex: - me 1d5h Do something - - "#general 1m Start now!" + - '#general 1m Start now!' params: - meorhere: desc: "The enum value of 'me' if the user wants to be reminded, or 'here' if the user wants to be reminded in the current channel." @@ -870,7 +891,7 @@ serverinfo: channelinfo: desc: Shows info about the channel. If no channel is supplied, it defaults to current one. ex: - - "#some-channel" + - '#some-channel' params: - channel: desc: "The channel where the information will be retrieved from or displayed in." @@ -884,7 +905,7 @@ roleinfo: userinfo: desc: Shows info about the user. If no user is supplied, it defaults a user running the command. ex: - - "@SomeUser" + - '@SomeUser' params: - usr: desc: "The guild user that the information is being retrieved for." @@ -900,7 +921,7 @@ inrole: ex: - RoleName - 5 RoleName - - "" + - '' params: - page: desc: "The starting page number for the result set." @@ -919,34 +940,34 @@ checkperms: stats: desc: Shows some basic stats for Ellie. ex: - - "" + - '' params: - {} userid: desc: Shows user ID. ex: - - "" - - "@Someone" + - '' + - '@Someone' params: - target: desc: "The guild the user is a member of." channelid: desc: Shows current channel ID. ex: - - "" + - '' params: - {} serverid: desc: Shows current server ID. ex: - - "" + - '' params: - {} roles: desc: List roles on this server or roles of a user if specified. Paginated, 20 roles per page. ex: - 2 - - "@Someone" + - '@Someone' params: - target: desc: "The guild or user for which to list the roles." @@ -957,38 +978,38 @@ roles: channeltopic: desc: Sends current channel's topic as a message. ex: - - "" + - '' params: - channel: desc: "The channel where the topic is retrieved from." chnlfilterinv: desc: Toggles automatic deletion of invites posted in the channel. Does not negate the `{0}srvrfilterinv` enabled setting. Does not affect users with the Administrator permission. ex: - - "" + - '' params: - {} srvrfilterinv: desc: Toggles automatic deletion of invites posted in the server. Does not affect users with the Administrator permission. ex: - - "" + - '' params: - {} chnlfilterlin: desc: Toggles automatic deletion of links posted in the channel. Does not negate the `{0}srvrfilterlin` enabled setting. Does not affect users with the Administrator permission. ex: - - "" + - '' params: - {} srvrfilterlin: desc: Toggles automatic deletion of links posted in the server. Does not affect users with the Administrator permission. ex: - - "" + - '' params: - {} chnlfilterwords: desc: Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `{0}srvrfilterwords` enabled setting. Does not affect users with the Administrator permission. ex: - - "" + - '' params: - {} filterword: @@ -1001,13 +1022,13 @@ filterword: srvrfilterwords: desc: Toggles automatic deletion of messages containing filtered words on the server. Does not affect users with the Administrator permission. ex: - - "" + - '' params: - {} lstfilterwords: desc: Shows a list of filtered words. ex: - - "" + - '' params: - page: desc: "The current page number in the list of filtered words." @@ -1024,7 +1045,7 @@ permrole: verbose: desc: Toggles or sets whether to show when a command/module is blocked. ex: - - "" + - '' - true params: - action: @@ -1116,14 +1137,14 @@ usrcmd: allsrvrmdls: desc: Enable or disable all modules for your server. ex: - - "[enable/disable]" + - '[enable/disable]' params: - action: desc: "The type of action to take on the enabled/disabled modules, such as enable or disable." allchnlmdls: desc: Enable or disable all modules in a specified channel. ex: - - "enable #SomeChannel" + - 'enable #SomeChannel' params: - action: desc: "The type of permission action to apply to the module, such as granting or revoking access." @@ -1132,7 +1153,7 @@ allchnlmdls: allrolemdls: desc: Enable or disable all modules for a specific role. ex: - - "[enable/disable] MyRole" + - '[enable/disable] MyRole' params: - action: desc: "The type of permission action to perform, such as granting or revoking access." @@ -1145,7 +1166,7 @@ userblacklist: ex: - add @SomeUser @SomeUser2 @SomeUser3 - rem 12312312313 - - "" + - '' - 4 params: - page: @@ -1165,7 +1186,7 @@ channelblacklist: ex: - add 12312312312 66666666666 - rem 12312312312 - - "" + - '' - 3 params: - page: @@ -1181,7 +1202,7 @@ serverblacklist: ex: - add 12312321312 - rem 12312321312 - - "" + - '' - 2 params: - page: @@ -1211,7 +1232,7 @@ cmdcooldown: allcmdcooldowns: desc: Shows a list of all commands and their respective cooldowns. ex: - - "" + - '' params: - page: desc: "The number of the page to display in the list of command cooldowns." @@ -1224,6 +1245,15 @@ quoteadd: desc: "The name of the quote used to retrieve the quote." text: desc: "The message of the quote." +quoteedit: + desc: Edits a quote with the specified ID. + ex: + - 55 This is the new response. + params: + - quoteId: + desc: "The ID of the quote being edited." + text: + desc: "The new message of the quote." quoteprint: desc: Prints a random quote with a specified name. ex: @@ -1236,10 +1266,10 @@ quoteshow: ex: - 123 params: - - id: + - quoteId: desc: "The unique identifier for the quote being queried." quotesearch: - desc: "Shows a random quote given a search query. Partially matches in several ways: 1) Only content of any quote, 2) only by author, 3) keyword and content, 3) or keyword and author" + desc: 'Shows a random quote given a search query. Partially matches in several ways: 1) Only content of any quote, 2) only by author, 3) keyword and content, 3) or keyword and author' ex: - '"find this long text"' - AuthorName @@ -1257,19 +1287,19 @@ quoteid: ex: - 123456 params: - - id: + - quoteId: desc: "The unique identifier for the quote to be displayed." quotedelete: desc: Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it. ex: - 123456 params: - - id: + - quoteId: desc: "The unique identifier for the quote being deleted." quotedeleteauthor: desc: Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required. ex: - - "@QuoteSpammer" + - '@QuoteSpammer' params: - user: desc: "The user whose quotes are to be deleted." @@ -1278,7 +1308,7 @@ quotedeleteauthor: draw: desc: Draws a card from this server's deck. You can draw up to 10 cards by supplying a number of cards to draw. ex: - - "" + - '' - 5 params: - num: @@ -1286,7 +1316,7 @@ draw: drawnew: desc: Draws a card from the NEW deck of cards. You can draw up to 10 cards by supplying a number of cards to draw. ex: - - "" + - '' - 5 params: - num: @@ -1294,13 +1324,13 @@ drawnew: playlistshuffle: desc: Shuffles the current playlist. ex: - - "" + - '' params: - {} flip: desc: Flips coin(s) - heads or tails, and shows an image. ex: - - "" + - '' - 3 params: - count: @@ -1318,7 +1348,7 @@ betflip: roll: desc: Rolls 0-100. If you supply a number `X` it rolls up to 30 normal dice. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. `Y` can be a letter 'F' if you want to roll fate dice instead of dnd. ex: - - "" + - '' - 7 - 3d5 - 5dF @@ -1331,7 +1361,7 @@ roll: rolluo: desc: Rolls `X` normal dice (up to 30) unordered. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. ex: - - "" + - '' - 7 - 3d5 params: @@ -1350,14 +1380,14 @@ nroll: race: desc: Starts a new animal race. ex: - - "" + - '' params: - params: desc: "The list of commands or actions for the animals in the race." joinrace: desc: Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. ex: - - "" + - '' - 5 params: - amount: @@ -1365,20 +1395,20 @@ joinrace: nunchi: desc: Creates or joins an existing nunchi game. Users have to count up by 1 from the starting number shown by the bot. If someone makes a mistake (types an incorrect number, or repeats the same number) they are out of the game and a new round starts without them. Minimum 3 users required. ex: - - "" + - '' params: - {} connect4: desc: Creates or joins an existing connect4 game. 2 players are required for the game. Objective of the game is to get 4 of your pieces next to each other in a vertical, horizontal or diagonal line. You can specify a bet when you create a game and only users who bet the same amount will be able to join your game. ex: - - "" + - '' params: - params: desc: "The list of command-line arguments passed by the user to customize the game setup or behavior." raffle: desc: Prints a name and ID of a random online user from the server, or from the online user in the specified role. ex: - - "" + - '' - RoleName params: - role: @@ -1386,8 +1416,8 @@ raffle: raffleany: desc: Prints a name and ID of a random user from the server, or from the specified role. ex: - - "" - - " RoleName" + - '' + - ' RoleName' params: - role: desc: "The role that determines which users are eligible for selection." @@ -1468,7 +1498,7 @@ luckyladder: leaderboard: desc: Displays the bot's currency leaderboard. ex: - - "" + - '' params: - params: desc: "The list of player names or IDs to display in the leaderboard." @@ -1479,7 +1509,7 @@ leaderboard: trivia: desc: Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. ex: - - "" + - '' - --timeout 5 -p -w 3 -q 10 params: - params: @@ -1487,26 +1517,26 @@ trivia: tl: desc: Shows a current trivia leaderboard. ex: - - "" + - '' params: - {} tq: desc: Quits current trivia after current question. ex: - - "" + - '' params: - {} typestart: desc: Starts a typing contest. ex: - - "" + - '' params: - params: desc: "The list of words or phrases for the contestants to type." typestop: desc: Stops a typing contest on the current channel. ex: - - "" + - '' params: - {} typeadd: @@ -1519,7 +1549,7 @@ typeadd: pick: desc: Picks the currency planted in this channel. If the plant has a password, you need to specify it. ex: - - "" + - '' - passwd params: - pass: @@ -1537,13 +1567,13 @@ plant: gencurrency: desc: 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%) ex: - - "" + - '' params: - {} gencurlist: desc: Shows the list of server and channel ids where gc is enabled. Paginated with 9 per page. ex: - - "" + - '' params: - page: desc: "The current page number for pagination." @@ -1567,13 +1597,13 @@ rps: next: desc: Goes to the next song in the queue. You have to be in the same voice channel as the bot ex: - - "" + - '' params: - {} play: desc: If no parameters are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command ex: - - "" + - '' - 5 - Dream Of Venice params: @@ -1585,19 +1615,19 @@ play: stop: desc: Stops the music and preserves the current song index. Stays in the channel. ex: - - "" + - '' params: - {} destroy: desc: Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) ex: - - "" + - '' params: - {} pause: desc: Pauses or Unpauses the song. ex: - - "" + - '' params: - {} queue: @@ -1624,7 +1654,7 @@ queuesearch: listqueue: desc: Lists 10 currently queued songs per page. Default page is 1. ex: - - "" + - '' - 2 params: - {} @@ -1633,7 +1663,7 @@ listqueue: nowplaying: desc: Shows the song that the bot is currently playing. ex: - - "" + - '' params: - {} volume: @@ -1658,7 +1688,7 @@ localplaylist: - dirPath: desc: "The path to the directory containing the songs to be queued." radio: - desc: "Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: )" + desc: 'Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: )' ex: - radio link here params: @@ -1674,7 +1704,7 @@ local: join: desc: Makes the bot join your voice channel. ex: - - "" + - '' params: - {} trackremove: @@ -1682,7 +1712,7 @@ trackremove: ex: - 5 - all - - "" + - '' params: - index: desc: "The position of the song to be removed from the playlist." @@ -1704,7 +1734,7 @@ queuerepeat: - `s` / `song` - player will repeat current song - `q` / `queue` or empty - player will repeat entire music queue ex: - - "" + - '' - n - song params: @@ -1760,7 +1790,7 @@ deleteplaylist: queueautoplay: desc: Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs) ex: - - "" + - '' params: - {} streamadd: @@ -1773,7 +1803,7 @@ streamadd: streamsclear: desc: Removes all followed streams on this server. ex: - - "" + - '' params: - {} streamremove: @@ -1786,20 +1816,20 @@ streamremove: streamlist: desc: Lists all streams you are following on this server and their respective indexes. ex: - - "" + - '' params: - page: desc: "The number of the page to retrieve from the list of followed streams." streamoffline: desc: Toggles whether the bot will also notify when added streams go offline. ex: - - "" + - '' params: - {} streamonlinedelete: desc: Toggles whether the bot will delete stream online message when the stream goes offline. ex: - - "" + - '' params: - {} streammessage: @@ -1839,13 +1869,13 @@ convert: convertlist: desc: List of the convertible dimensions and currencies. ex: - - "" + - '' params: - {} wowjoke: desc: Get one of penultimate WoW jokes. ex: - - "" + - '' params: - {} calculate: @@ -1883,7 +1913,7 @@ osu5: - user: desc: "The username of the player whose top 5 plays are being displayed." mode: - desc: 'The type of game mode to display the top 5 plays for, such as "osu", "taiko", or "ctb".' + desc: "The type of game mode to display the top 5 plays for, such as \"osu\", \"taiko\", or \"ctb\"." pokemon: desc: Searches for a pokemon. ex: @@ -1901,7 +1931,7 @@ pokemonability: memelist: desc: Shows a list of template keys (and their respective names) used for `{0}memegen`. ex: - - "" + - '' params: - page: desc: "The number of pages in the list to be displayed." @@ -1960,25 +1990,25 @@ manga: randomcat: desc: Shows a random cat image. ex: - - "" + - '' params: - {} randomdog: desc: Shows a random dog image. ex: - - "" + - '' params: - {} randomfood: desc: Shows a random food image. ex: - - "" + - '' params: - {} randombird: desc: Shows a random bird image. ex: - - "" + - '' params: - {} image: @@ -2019,31 +2049,31 @@ urbandict: catfact: desc: Shows a random catfact from ex: - - "" + - '' params: - {} yomama: desc: Shows a random joke from ex: - - "" + - '' params: - {} randjoke: desc: Shows a random joke. ex: - - "" + - '' params: - {} chucknorris: desc: Shows a random Chuck Norris joke. ex: - - "" + - '' params: - {} magicitem: desc: Shows a random magic item from ex: - - "" + - '' params: - {} wiki: @@ -2064,7 +2094,7 @@ color: avatar: desc: Shows a mentioned person's avatar. ex: - - "@Someone" + - '@Someone' params: - usr: desc: "The user whose avatar is being displayed." @@ -2082,19 +2112,19 @@ translate: translangs: desc: Lists the valid languages for translation. ex: - - "" + - '' params: - {} guide: desc: Sends a readme and a guide links to the channel. ex: - - "" + - '' params: - {} calcops: desc: Shows all available operations in the `{0}calc` command ex: - - "" + - '' params: - {} delallquotes: @@ -2105,17 +2135,17 @@ delallquotes: - keyword: desc: "The keyword to search for in the text." greetdmmsg: - desc: Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. + desc: Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. ex: - Welcome to the server, %user.mention% params: - text: desc: "The new join announcement message that will be sent to the user who joined." cash: - desc: Check how much currency a person has. If no argument is provided it will check your own balance. + desc: Check how much currency a person has. If no argument is provided it will check your own balance. ex: - - "" - - "@Someone" + - '' + - '@Someone' params: - userId: desc: "Optional user ID of the account holder whose currency balance is being checked." @@ -2125,7 +2155,7 @@ currencytransactions: desc: Shows your currency transactions on the specified page. Bot owner can see other people's transactions too. ex: - 2 - - "@SomeUser 2" + - '@SomeUser 2' params: - page: desc: "The number of pages to display in the list of currency transactions." @@ -2145,7 +2175,7 @@ currencytransaction: listperms: desc: Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. ex: - - "" + - '' - 3 params: - page: @@ -2190,8 +2220,8 @@ emojiadd: You can omit imageUrl and instead upload the image as an attachment. Image size has to be below 256KB. ex: - - ":someonesCustomEmoji:" - - "MyEmojiName :someonesCustomEmoji:" + - ':someonesCustomEmoji:' + - 'MyEmojiName :someonesCustomEmoji:' - owoNice https://cdn.discordapp.com/emojis/587930873811173386.png?size=128 params: - name: @@ -2207,14 +2237,14 @@ emojiadd: emojiremove: desc: Removes the specified emoji or emojis from this server. ex: - - ":eagleWarrior: :plumedArcher:" + - ':eagleWarrior: :plumedArcher:' params: - emotes: desc: "The list of emojis to be removed from the server." stickeradd: desc: Adds the sticker from your message to this server. Send the sticker along with this command (in the same message). ex: - - "" + - '' - name "description" tag1 tag2 tagN params: - name: @@ -2226,40 +2256,40 @@ stickeradd: deckshuffle: desc: Reshuffles all cards back into the deck. ex: - - "" + - '' params: - {} forwardmessages: desc: Toggles forwarding of non-command messages sent to bot's DM to the bot owners ex: - - "" + - '' params: - {} forwardtoall: desc: Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the creds.yml file ex: - - "" + - '' params: - {} forwardtochannel: desc: Toggles forwarding of non-command messages sent to bot's DM to the current channel ex: - - "" + - '' params: - {} resetperms: desc: Resets the bot's permissions module on this server to the default value. ex: - - "" + - '' params: - {} antiraid: - desc: "Sets an anti-raid protection on the server. Provide no parameters to disable. First parameter is number of people which will trigger the protection. Second parameter is a time interval in which that number of people needs to join in order to trigger the protection, and third parameter is punishment for those people. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, RemoveRoles, AddRole, Warn, TimeOut" + desc: 'Sets an anti-raid protection on the server. Provide no parameters to disable. First parameter is number of people which will trigger the protection. Second parameter is a time interval in which that number of people needs to join in order to trigger the protection, and third parameter is punishment for those people. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, RemoveRoles, AddRole, Warn, TimeOut' ex: - 5 20 Kick - 7 9 Ban - 10 10 Ban 6h30m - - "" + - '' params: - {} - userThreshold: @@ -2277,12 +2307,12 @@ antiraid: action: desc: "The punishment action specifies the consequence for users who trigger the anti-raid protection." antispam: - desc: "Stops people from repeating same message X times in a row. Provide no parameters to disable. You can specify to either mute, kick or ban the offenders. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Max message count is 10. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, AddRole, RemoveRoles, Warn, TimeOut" + desc: 'Stops people from repeating same message X times in a row. Provide no parameters to disable. You can specify to either mute, kick or ban the offenders. You can specify an additional time argument to do a timed punishment for actions which support it (Ban, Mute, etc) up to 24h. Max message count is 10. Available punishments: Ban, Kick, Softban, Mute, VoiceMute, ChatMute, AddRole, RemoveRoles, Warn, TimeOut' ex: - 3 Mute - 5 Ban - 5 Ban 3h30m - - "" + - '' params: - {} - messageCount: @@ -2323,8 +2353,8 @@ antialt: chatmute: desc: Prevents a mentioned user from chatting in text channels. You can also specify time string for how long the user should be muted. You can optionally specify a reason. ex: - - "@Someone" - - "@Someone stop writing" + - '@Someone' + - '@Someone stop writing' - 15m @Someone - 1h30m @Someone - 1h @Someone chill @@ -2342,8 +2372,8 @@ chatmute: voicemute: desc: Prevents a mentioned user from speaking in voice channels. User has to be in a voice channel in order for the command to have an effect. You can also specify time string for how long the user should be muted. You can optionally specify a reason. ex: - - "@Someone" - - "@Someone stop talking" + - '@Someone' + - '@Someone stop talking' - 15m @Someone - 1h30m @Someone - 1h @Someone silence @@ -2361,7 +2391,7 @@ voicemute: muterole: desc: Sets a name of the role which will be assigned to people who should be muted. Provide no arguments to see currently set mute role. Default is ellie-mute. ex: - - "" + - '' - Silenced params: - role: @@ -2369,7 +2399,7 @@ muterole: adsarm: desc: Toggles the automatic deletion of the user's message and Ellie's confirmations for `{0}iam` and `{0}iamn` commands. ex: - - "" + - '' params: - {} setstream: @@ -2384,7 +2414,7 @@ setstream: chatunmute: desc: Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels. ex: - - "@Someone" + - '@Someone' params: - user: desc: "The user who was previously muted and is now being unmuted." @@ -2393,7 +2423,7 @@ chatunmute: unmute: desc: Unmutes a mentioned user previously muted with `{0}mute` command. ex: - - "@Someone" + - '@Someone' params: - user: desc: "The user who was previously muted and is now being un-muted." @@ -2402,12 +2432,12 @@ unmute: xkcd: desc: Shows a XKCD comic. Specify no parameters to retrieve a random one. Number parameter will retrieve a specific comic, and "latest" will get the latest one. ex: - - "" + - '' - 1400 - latest params: - arg: - desc: 'The URL of the desired comic or "latest" to retrieve the most recent one.' + desc: "The URL of the desired comic or \"latest\" to retrieve the most recent one." - num: desc: "The number of the comic to be retrieved." autotranslang: @@ -2417,13 +2447,13 @@ autotranslang: params: - {} - fromLang: - desc: + desc: toLang: - desc: 'The destination language code, such as "en" for English or "fr" for French.' + desc: "The destination language code, such as \"en\" for English or \"fr\" for French." autotranslate: desc: Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" parameter to automatically delete all translated user messages. ex: - - "" + - '' - del params: - autoDelete: @@ -2450,7 +2480,7 @@ typedel: typelist: desc: Lists added typing articles with their IDs. 15 per page. ex: - - "" + - '' - 3 params: - page: @@ -2465,7 +2495,7 @@ listservers: cleverbot: desc: Toggles cleverbot/chatgpt session. When enabled, the bot will reply to messages starting with bot mention in the server. Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled. ex: - - "" + - '' params: - {} shorten: @@ -2495,13 +2525,13 @@ magicthegathering: hangmanlist: desc: Shows a list of hangman question categories. ex: - - "" + - '' params: - {} hangman: desc: Starts a game of hangman in the channel. You can optionally select a category `{0}hangmanlist` to see a list of available categories. ex: - - "" + - '' - movies params: - type: @@ -2509,13 +2539,13 @@ hangman: hangmanstop: desc: Stops the active hangman game on this channel if it exists. ex: - - "" + - '' params: - {} acrophobia: desc: Starts an Acrophobia game. ex: - - "" + - '' - -s 30 params: - params: @@ -2523,7 +2553,7 @@ acrophobia: logevents: desc: Shows a list of all events you can subscribe to with `{0}log` ex: - - "" + - '' params: - {} log: @@ -2537,7 +2567,7 @@ log: queuefairplay: desc: Triggers fairplay. The song queue will be re-ordered in a fair manner. No effect on newly added songs. ex: - - "" + - '' params: - {} define: @@ -2550,7 +2580,7 @@ define: activity: desc: Checks for spammers. ex: - - "" + - '' params: - page: desc: "The number of pages to scan for spam." @@ -2564,14 +2594,14 @@ setstatus: invitecreate: desc: Creates a new invite which has infinite max uses and never expires. ex: - - "" + - '' params: - params: desc: "The recipient's email addresses or usernames." invitelist: desc: Lists all invites for this channel. Paginated with 9 per page. ex: - - "" + - '' - 3 params: - page: @@ -2588,17 +2618,17 @@ invitedelete: antilist: desc: Shows currently enabled protection features. ex: - - "" + - '' params: - {} antispamignore: desc: Toggles whether antispam ignores current channel. Antispam must be enabled. ex: - - "" + - '' params: - {} eventstart: - desc: "Starts one of the events seen on public ellie. Events: `reaction`, `gamestatus`" + desc: 'Starts one of the events seen on public ellie. Events: `reaction`, `gamestatus`' ex: - reaction - reaction -d 1 -a 50 --pot-size 1500 @@ -2610,7 +2640,7 @@ eventstart: betstats: desc: Shows the total stats of several gambling features. Updates once an hour. ex: - - "" + - '' params: - {} slot: @@ -2623,8 +2653,8 @@ slot: affinity: desc: Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. Provide no parameters to clear your affinity. 30 minutes cooldown. ex: - - "@MyHusband" - - "" + - '@MyHusband' + - '' params: - user: desc: "The user being targeted for a potential claim." @@ -2640,13 +2670,13 @@ waifuclaim: waifureset: desc: Resets your waifu stats, except current waifus. ex: - - "" + - '' params: - {} waifutransfer: desc: Transfer the ownership of one of your waifus to another user. You must pay 10% of your waifu's value unless that waifu has affinity towards you, in which case you must pay 60% fee. Transferred waifu's price will be reduced by the fee amount. ex: - - "@ExWaifu @NewOwner" + - '@ExWaifu @NewOwner' params: - waifuId: desc: "The ID of the waifu being transferred to a new owner." @@ -2659,7 +2689,7 @@ waifutransfer: waifugift: desc: -| Gift an item to someone. This will increase their waifu value by a percentage of the gift's value. Negative gifts will not show up in waifuinfo. Provide no parameters to see a list of items that you can gift. ex: - - "" + - '' - Rose @Himesama params: - page: @@ -2671,7 +2701,7 @@ waifugift: waifulb: desc: Shows top 9 waifus. You can specify another page to show other waifus. ex: - - "" + - '' - 3 params: - page: @@ -2679,7 +2709,7 @@ waifulb: divorce: desc: Releases your claim on a specific waifu. You will get 50% of that waifu's value back, unless that waifu has an affinity towards you, in which case they will be reimbursed instead. 6 hours cooldown. ex: - - "@CheatingSloot" + - '@CheatingSloot' params: - target: desc: "The ID or name of the waifu being released from your claim." @@ -2690,8 +2720,8 @@ divorce: waifuinfo: desc: Shows waifu stats for a target person. Defaults to you if no user is provided. ex: - - "@MyCrush" - - "" + - '@MyCrush' + - '' params: - target: desc: "The user being targeted, whose waifu information will be displayed." @@ -2709,19 +2739,19 @@ mal: setmusicchannel: desc: Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. Persistent server setting. ex: - - "" + - '' params: - {} unsetmusicchannel: desc: Bot will output playing, finished, paused and removed songs to the channel where the first song was queued in. Persistent server setting. ex: - - "" + - '' params: - {} musicquality: - desc: "Gets or sets the default music player quality. Available settings: Highest, High, Medium, Low. Default is **Highest**. Provide no argument to see current setting." + desc: 'Gets or sets the default music player quality. Available settings: Highest, High, Medium, Low. Default is **Highest**. Provide no argument to see current setting.' ex: - - "" + - '' - High - Low params: @@ -2731,7 +2761,7 @@ musicquality: stringsreload: desc: Reloads localized bot strings. ex: - - "" + - '' params: - {} shardstats: @@ -2739,7 +2769,7 @@ shardstats: Stats for shards. Paginated with 25 shards per page. Format: `[status] | # [shard_id] | [last_heartbeat] | [server_count]` ex: - - "" + - '' - 2 params: - page: @@ -2754,21 +2784,21 @@ restartshard: tictactoe: desc: Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. ex: - - "" + - '' params: - params: desc: "The coordinates for placing an X or O on the board." timezones: desc: Lists all timezones available on the system to be used with `{0}timezone`. ex: - - "" + - '' params: - page: desc: "The number of pages to retrieve from the list of available timezones." timezone: desc: Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) **Setting timezone requires Administrator server permission.** ex: - - "" + - '' - GMT Standard Time params: - {} @@ -2786,7 +2816,7 @@ languagesetdefault: languageset: desc: Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no parameters to see currently set language. ex: - - "de-DE " + - 'de-DE ' - default params: - {} @@ -2795,13 +2825,13 @@ languageset: languageslist: desc: List of languages for which translation (or part of it) exist atm. ex: - - "" + - '' params: - {} exprtoggleglobal: desc: Toggles whether global expressions are usable on this server. ex: - - "" + - '' params: - {} exprreact: @@ -2846,7 +2876,7 @@ exprca: exprsreload: desc: Reloads all expressions on all shards. Use this if you've made changes to the database while the bot is running, or used `{0}deleteunusedcrnq` ex: - - "" + - '' params: - {} exprsimport: @@ -2859,7 +2889,7 @@ exprsimport: exprsexport: desc: Exports expressions from the current server (or global expressions in DMs) into a .yml file ex: - - "" + - '' params: - {} quotesimport: @@ -2872,13 +2902,13 @@ quotesimport: quotesexport: desc: Exports quotes from the current server into a .yml file ex: - - "" + - '' params: - {} aliaslist: desc: Shows the list of currently set aliases. Paginated. ex: - - "" + - '' - 3 params: - page: @@ -2895,7 +2925,7 @@ alias: warnlog: desc: See a list of warnings of a certain user. ex: - - "@Someone" + - '@Someone' params: - page: desc: "The number of pages to display in the warning log." @@ -2912,7 +2942,7 @@ warnlog: warnlogall: desc: See a list of all warnings on the server. 15 users per page. ex: - - "" + - '' - 2 params: - page: @@ -2922,7 +2952,7 @@ warn: Warns a user with an optional reason. You can specify a warning weight integer before the user. For example, 3 would mean that this warning counts as 3 warnings. ex: - - "@Someone Very rude person" + - '@Someone Very rude person' - 3 @Someone Very rude person params: - user: @@ -2938,7 +2968,7 @@ warn: startupcommandadd: desc: Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. ex: - - "{0}stats" + - '{0}stats' params: - cmdText: desc: "The text of the command that should be recognized and executed when a user types it." @@ -2968,20 +2998,20 @@ autocommandremove: startupcommandsclear: desc: Removes all startup commands. ex: - - "" + - '' params: - {} startupcommandslist: desc: Lists all startup commands in the order they will be executed in. ex: - - "" + - '' params: - page: desc: "The number of items to display per page." autocommandslist: desc: Lists all auto commands and the intervals in which they execute. ex: - - "" + - '' params: - page: desc: "The number of pages to retrieve from the list of auto commands." @@ -2996,7 +3026,7 @@ unban: - userId: desc: "The ID of the user to be unbanned." banmessage: - desc: "Sets a ban message template which will be used when a user is banned from this server. You can use embed strings and ban-specific placeholders: %ban.mod%, %ban.user%, %ban.duration% and %ban.reason%. You can disable ban message with `{0}banmsg -`" + desc: 'Sets a ban message template which will be used when a user is banned from this server. You can use embed strings and ban-specific placeholders: %ban.mod%, %ban.user%, %ban.duration% and %ban.reason%. You can disable ban message with `{0}banmsg -`' ex: - "%ban.user%, you've been banned from %server.name%. Reason: %ban.reason%" - '{{ "description": "%ban.user% you have been banned from %server.name% by %ban.mod%" }}' @@ -3018,7 +3048,7 @@ banmessagetest: banmsgreset: desc: Resets ban message to default. If you want to completely disable ban messages, use `{0}banmsg -` ex: - - "" + - '' params: - {} banprune: @@ -3041,7 +3071,7 @@ wait: warnexpire: desc: Gets or sets the number of days after which the warnings will be cleared automatically. This setting works retroactively. If you want to delete the warnings instead of clearing them, you can set the `--delete` optional parameter. Provide no parameter to see currently set expiry ex: - - "" + - '' - 3 - 6 --delete params: @@ -3053,8 +3083,8 @@ warnexpire: warnclear: desc: Clears all warnings from a certain user. You can specify a number to clear a specific one. ex: - - "@PoorDude 3" - - "@PoorDude" + - '@PoorDude 3' + - '@PoorDude' params: - user: desc: "The user whose warnings are being cleared." @@ -3067,7 +3097,7 @@ warnclear: warnpunishlist: desc: Lists punishments for warnings. ex: - - "" + - '' params: - {} warnpunish: @@ -3097,7 +3127,7 @@ warnpunish: ping: desc: Ping the bot to see if there are latency issues. ex: - - "" + - '' params: - {} time: @@ -3110,7 +3140,7 @@ time: shop: desc: Lists this server's administrators' shop. Paginated. ex: - - "" + - '' - 2 params: - page: @@ -3202,7 +3232,7 @@ buy: gamevoicechannel: desc: Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server. ex: - - "" + - '' params: - {} shoplistadd: @@ -3217,7 +3247,7 @@ shoplistadd: globalcommand: desc: Toggles whether a command can be used on any server. ex: - - "{0}stats" + - '{0}stats' params: - cmd: desc: "The type of command or expression being toggled." @@ -3231,13 +3261,13 @@ globalmodule: globalpermlist: desc: Lists global permissions set by the bot owner. ex: - - "" + - '' params: - {} resetglobalperms: desc: Resets global permissions set by bot owner. ex: - - "" + - '' params: - {} prefix: @@ -3262,7 +3292,7 @@ defprefix: verboseerror: desc: Toggles or sets whether the bot should print command errors when a command is incorrectly used. ex: - - "" + - '' - false params: - newstate: @@ -3270,7 +3300,7 @@ verboseerror: streamrolekeyword: desc: Sets keyword which is required in the stream's title in order for the streamrole to apply. Provide no keyword in order to reset. ex: - - "" + - '' - PUBG params: - keyword: @@ -3303,7 +3333,7 @@ config: Provide config name and property name to see that property's description and value. Provide config name, property name and value to set that property to the new value. ex: - - "" + - '' - bot - bot color.ok - bot color.ok ff0000 @@ -3325,21 +3355,21 @@ configreload: experience: desc: Shows your xp stats. Specify the user to show that user's stats instead. ex: - - "" - - "@someguy" + - '' + - '@someguy' params: - user: desc: "The ID or handle of a player whose XP statistics are being displayed." xptemplatereload: desc: Reloads the xp template file. Xp template file allows you to customize the position and color of elements on the `{0}xp` card. ex: - - "" + - '' params: - {} xpexclusionlist: desc: Shows the roles and channels excluded from the XP system on this server, as well as whether the whole server is excluded. ex: - - "" + - '' params: - {} xpexclude: @@ -3372,14 +3402,14 @@ xpnotify: xpleveluprewards: desc: Shows currently set level up rewards. ex: - - "" + - '' params: - page: desc: "The page number for which the level up rewards are being displayed." xprewsreset: desc: Resets all currently set xp level up rewards. ex: - - "" + - '' params: - {} xprolereward: @@ -3412,7 +3442,7 @@ xpcurrencyreward: xpleaderboard: desc: Shows current server's xp leaderboard. ex: - - "" + - '' params: - params: desc: "The list of player names or IDs to filter the leaderboard by." @@ -3423,7 +3453,7 @@ xpleaderboard: xpgloballeaderboard: desc: Shows the global xp leaderboard. ex: - - "" + - '' params: - page: desc: "The current page number for displaying the leaderboard results." @@ -3455,7 +3485,7 @@ clubcreate: clubtransfer: desc: Transfers the ownership of the club to another member of the club. ex: - - "@Someone" + - '@Someone' params: - newOwner: desc: "The user who will take over the management of the club." @@ -3496,13 +3526,13 @@ clubreject: clubleave: desc: Leaves the club you're currently in. ex: - - "" + - '' params: - {} clubdisband: desc: Disbands the club you're the owner of. This action is irreversible. ex: - - "" + - '' params: - {} clubkick: @@ -3570,7 +3600,7 @@ clubleaderboard: clubadmin: desc: Assigns (or unassigns) staff role to the member of the club. Admins can ban, kick and accept applications. ex: - - "@Someone" + - '@Someone' params: - toAdmin: desc: "The user who is being assigned or unassigned as an admin." @@ -3610,8 +3640,8 @@ feed: You can optionally specify a message after the channel name which will be posted with an update. ex: - https://blog.playstation.com/feed/ - - "https://blog.playstation.com/feed/ #updates" - - "https://blog.playstation.com/feed/ #updates New playstation rss feed post!" + - 'https://blog.playstation.com/feed/ #updates' + - 'https://blog.playstation.com/feed/ #updates New playstation rss feed post!' params: - url: desc: "The URL of the feed to subscribe to, used to retrieve new content for posting." @@ -3633,7 +3663,7 @@ feedremove: feedlist: desc: Shows the list of feeds you've subscribed to on this server. ex: - - "" + - '' params: - page: desc: "The number of items to display per page." @@ -3650,7 +3680,7 @@ say: desc: Bot will send the message you typed in the specified channel. If you omit the channel name, it will send the message in the current channel. Supports embeds. ex: - hi - - "#chat hi" + - '#chat hi' params: - channel: desc: "The destination where the bot will send the message." @@ -3682,13 +3712,13 @@ sqlselectcsv: deletewaifus: desc: Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables. ex: - - "" + - '' params: - {} deletewaifu: desc: Deletes everything from WaifuUpdates, WaifuItem and WaifuInfo tables for the specified user. Also makes specified user's waifus free. ex: - - "" + - '' params: - user: desc: "The ID of the user whose waifus are to be deleted and set free." @@ -3697,26 +3727,26 @@ deletewaifu: deletecurrency: desc: Deletes everything from Currency and CurrencyTransactions. ex: - - "" + - '' params: - {} deleteplaylists: desc: Deletes everything from MusicPlaylists. ex: - - "" + - '' params: - {} deletexp: desc: Deletes everything from UserXpStats, Clubs and sets users' TotalXP to 0. ex: - - "" + - '' params: - {} discordpermoverride: desc: Overrides required user permissions that the command has with the specified ones. You can only use server-level permissions. This action will make the bot ignore user permission requirements which command has by default. Provide no permissions to reset to default. ex: - - "{0}prune ManageMessages BanMembers" - - "{0}prune" + - '{0}prune ManageMessages BanMembers' + - '{0}prune' params: - cmd: desc: "The command or expression that this override applies to, allowing you to customize permissions for specific commands or actions within your Discord server." @@ -3725,14 +3755,14 @@ discordpermoverride: discordpermoverridelist: desc: Lists all discord permission overrides on this server. ex: - - "" + - '' params: - page: desc: "The number of the page to display in the list of permission overrides." discordpermoverridereset: desc: Resets ALL currently set discord permission overrides on this server. This will make all commands have default discord permission requirements. ex: - - "" + - '' params: - {} rafflecur: @@ -3742,24 +3772,24 @@ rafflecur: - mixed 15 params: - _: - desc: 'The type of game mode to use, either "fixed" or "mixed".' + desc: "The type of game mode to use, either \"fixed\" or \"mixed\"." amount: desc: "The minimum or maximum amount of currency that can be used for betting." - amount: desc: "The minimum or maximum amount of currency that can be used for betting." mixed: - desc: 'The parameter determines whether the raffle operates in "fixed" or "proportional" mode.' + desc: "The parameter determines whether the raffle operates in \"fixed\" or \"proportional\" mode." rip: desc: Shows the inevitable fate of someone. ex: - - "@Someone" + - '@Someone' params: - usr: desc: "The user whose fate is being revealed." autodisconnect: desc: Toggles whether the bot should disconnect from the voice channel once it's done playing all of the songs and queue repeat option is set to `none`. ex: - - "" + - '' params: - {} timelyset: @@ -3775,13 +3805,13 @@ timelyset: timely: desc: Use to claim your 'timely' currency. Bot owner has to specify the amount and the period on how often you can claim your currency. ex: - - "" + - '' params: - {} timelyreset: desc: Resets all user timeouts on `{0}timely` command. ex: - - "" + - '' params: - {} crypto: @@ -3838,7 +3868,7 @@ pathofexile: pathofexileleagues: desc: Returns a list of the main Path of Exile leagues. ex: - - "" + - '' params: - {} pathofexilecurrency: @@ -3847,7 +3877,7 @@ pathofexilecurrency: - Standard "Mirror of Kalandra" params: - leagueName: - desc: 'The name of the league in which the currency is used, such as "Harbinger" or "Delve".' + desc: "The name of the league in which the currency is used, such as \"Harbinger\" or \"Delve\"." currencyName: desc: "The type of currency being converted." convertName: @@ -3856,7 +3886,7 @@ rollduel: desc: Challenge someone to a roll duel by specifying the amount and the user you wish to challenge as the parameters. To accept the challenge, just specify the name of the user who challenged you, without the amount. ex: - 50 @Someone - - "@Challenger" + - '@Challenger' params: - u: desc: "The user being challenged or accepting the challenge." @@ -3889,7 +3919,7 @@ reroadd: rerolist: desc: Lists all ReactionRole messages on this server with their message ids. Clicking/Tapping message ids will send you to that message. ex: - - "" + - '' params: - page: desc: "The number of the page to retrieve, starting from 1." @@ -3903,7 +3933,7 @@ reroremove: rerodeleteall: desc: Deletes all reaction roles on the server. This action is irreversible. ex: - - "" + - '' params: - {} rerotransfer: @@ -3925,26 +3955,26 @@ blackjack: hit: desc: In the blackjack game, ask the dealer for an extra card. ex: - - "" + - '' params: - {} stand: desc: Finish your turn in the blackjack game. ex: - - "" + - '' params: - {} double: desc: In the blackjack game, double your bet in order to receive exactly one more card, and your turn ends. ex: - - "" + - '' params: - {} xpreset: desc: Resets specified user's XP, or the XP of all users in the server. You can't reverse this action. ex: - - "@Someone" - - "" + - '@Someone' + - '' params: - user: desc: "The ID of a specific guild member whose XP is being reset." @@ -3996,7 +4026,7 @@ edit: desc: Edits bot's message, you have to specify message ID and new text. You can optionally specify target channel. Supports embeds. ex: - 7479498384 Hi :^) - - "#other-channel 771562360594628608 New message!" + - '#other-channel 771562360594628608 New message!' - '#other-channel 771562360594628608 {{"description":"hello"}}' params: - messageId: @@ -4012,7 +4042,7 @@ edit: delete: desc: Deletes a single message given the channel and message ID. If channel is ommited, message will be searched for in the current channel. You can also specify time parameter after which the message will be deleted (up to 7 days). This timer won't persist through bot restarts. ex: - - "#chat 771562360594628608" + - '#chat 771562360594628608' - 771562360594628608 - 771562360594628608 5m params: @@ -4036,19 +4066,19 @@ roleid: agerestricttoggle: desc: Toggles whether the current channel is age-restricted. ex: - - "" + - '' params: - {} economy: desc: Breakdown of the current state of the bot's economy. Updates every 3 minutes. ex: - - "" + - '' params: - {} purgeuser: desc: Purge user from the database completely. This includes currency, xp, clubs that user owns, waifu info ex: - - "@Oblivion" + - '@Oblivion' params: - userId: desc: "The ID of the user to be purged from the system." @@ -4057,28 +4087,28 @@ purgeuser: imageonlychannel: desc: "Toggles whether the channel only allows images.\nUsers who send more than a few non-image messages will be banned from using the channel. " ex: - - "" + - '' params: - time: desc: "The amount of time before banning users for sending non-image messages." linkonlychannel: desc: "Toggles whether the channel only allows links.\nUsers who send more than a few non-link messages will be banned from using the channel. " ex: - - "" + - '' params: - time: desc: "The amount of time before a user is banned for sending non-link messages." coordreload: desc: Reloads coordinator config ex: - - "" + - '' params: - {} showembed: desc: Prints the json equivalent of the embed of the message specified by its Id. ex: - 820022733172121600 - - "#some-channel 820022733172121600" + - '#some-channel 820022733172121600' params: - messageId: desc: "The ID of a message that contains an embed to be displayed as JSON." @@ -4089,17 +4119,17 @@ showembed: deleteemptyservers: desc: Deletes all servers in which the bot is the only member. ex: - - "" + - '' params: - {} marmaladeload: desc: |- Loads a marmalade with the specified name from the data/marmalades/ folder. Provide no name to see the list of loadable marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/v4/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/) ex: - mycoolmarmalade - - "" + - '' params: - name: desc: "The name of a pre-existing marmalade to load." @@ -4107,10 +4137,10 @@ marmaladeunload: desc: |- Unloads the previously loaded marmalade. Provide no name to see the list of unloadable marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/v4/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/) ex: - mycoolmarmalade - - "" + - '' params: - name: desc: "The name of a specific marmalade to be unloaded." @@ -4118,19 +4148,19 @@ marmaladeinfo: desc: |- Shows information about the specified marmalade such as the author, name, description, list of sneks, number of commands etc. Provide no name to see the basic information about all loaded marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/v4/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/) ex: - mycoolmarmalade - - "" + - '' params: - name: desc: "The author of the specified marmalade." marmaladelist: desc: |- Lists all loaded and unloaded marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/v4/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/) ex: - - "" + - '' params: - {} marmaladesearch: @@ -4156,7 +4186,7 @@ bankwithdraw: bankbalance: desc: Shows your current bank balance available for withdrawal. ex: - - "" + - '' params: - {} banktake: @@ -4184,7 +4214,7 @@ bankaward: patron: desc: Check your patronage status and command usage quota. Bot owners can check targeted user's patronage status. ex: - - "" + - '' params: - {} - user: @@ -4244,7 +4274,7 @@ bettest: Tests a betting command by specifying the name followed by the number of tests. Some have multiple variations. See the list of all tests by specifying no parameters. ex: - - "" + - '' - betflip 1000 - slot 2000 params: @@ -4270,13 +4300,13 @@ threaddelete: autopublish: desc: Make the bot automatically publish all messages posted in the news channel this command was executed in. ex: - - "" + - '' params: - {} doas: desc: Execute the command as if you were the target user. Requires bot ownership and server administrator permission. ex: - - "@Thief .give all @Admin" + - '@Thief .give all @Admin' params: - user: desc: "The user whose identity is being impersonated for the command execution." @@ -4292,7 +4322,7 @@ clubrename: cacheusers: desc: Caches users of a Discord server and saves them to the database. ex: - - "" + - '' - serverId params: - {} @@ -4301,7 +4331,7 @@ cacheusers: stickyroles: desc: Toggles whether the bot will save the leaving users' roles, and reapply them once they re-join. The roles will be stored for up to 30 days. ex: - - "" + - '' params: - {} giveawaystart: @@ -4339,13 +4369,13 @@ giveawayreroll: giveawaylist: desc: Lists all active giveaways. ex: - - "" + - '' params: - {} todolist: desc: Lists all todos. ex: - - "" + - '' params: - {} todoadd: @@ -4381,7 +4411,7 @@ tododelete: todoclear: desc: Deletes all unarchived todos. ex: - - "" + - '' params: - {} todoarchiveadd: @@ -4394,7 +4424,7 @@ todoarchiveadd: todoarchivelist: desc: Lists all archived todo lists. ex: - - "" + - '' params: - page: desc: "The number of the page to retrieve from the list of archived todo lists." @@ -4419,3 +4449,11 @@ todoarchivedelete: params: - todoId: desc: "The identifier for the archived todo item to be deleted." +cleanupguilddata: + desc: |- + Deletes data for all servers bot is no longer a member of from the database. + This is a highly destructive and irreversible command. + ex: + - '' + params: + - {} \ No newline at end of file diff --git a/src/EllieBot/data/strings/responses/responses.en-US.json b/src/EllieBot/data/strings/responses/responses.en-US.json index 0487021..bbc021b 100644 --- a/src/EllieBot/data/strings/responses/responses.en-US.json +++ b/src/EllieBot/data/strings/responses/responses.en-US.json @@ -188,6 +188,11 @@ "setrole_err": "Failed to add role. I have insufficient permissions.", "set_avatar": "New avatar set!", "set_banner": "New banner set!", + "set_srvr_icon": "New server icon set!", + "set_srvr_banner": "New server banner set!", + "srvr_banner_invalid": "Specified image has an invalid filetype. Make sure you're specifying a direct image url.", + "srvr_banner_too_large": "Specified image is too large! Maximum size is 8MB.", + "srvr_banner_invalid_url": "Specified url is not valid. Make sure you're specifying a direct image url.", "set_channel_name": "New channel name set.", "set_game": "New game set!", "set_stream": "New stream set!", @@ -230,7 +235,7 @@ "user_unbanned": "User unbanned", "presence_updates": "Presence updates", "sb_user": "User soft-banned", - "awarded": "has awarded {0} to {1}", + "awarded": "{2} has awarded {0} to {1}", "better_luck": "Better luck next time ^_^", "br_win": "Congratulations! You won {0} for rolling above {1}", "deck_reshuffled": "Deck reshuffled.", @@ -241,7 +246,7 @@ "cards_left": "{0} cards left in the deck.", "cards": "Cards", "hand_value": "Hand value", - "gifted": "has gifted {0} to {1}", + "gifted": "{2} has gifted {0} to {1}", "has": "{0} has {1}", "heads": "Head", "mass_award": "Awarded {0} to {1} users from {2} role.", @@ -351,7 +356,7 @@ "hangman_running": "Hangman game already running on this channel.", "hangman_types": "List of \"{0}hangman\" term types:", "leaderboard": "Leaderboard", - "picked": "picked {0}", + "picked": "{1} picked {0}", "planted": "{0} planted {1}", "trivia_already_running": "Trivia game is already running on this server.", "trivia_game": "Trivia Game", @@ -366,7 +371,7 @@ "ttt_against_yourself": "You can't play against yourself.", "ttt_already_running": "TicTacToe Game is already running in this channel.", "ttt_a_draw": "A draw!", - "ttt_created": "has created a game of TicTacToe.", + "ttt_created": "{0} has created a game of TicTacToe.", "ttt_has_won": "{0} has won!", "ttt_matched_three": "Matched three", "ttt_no_moves": "No moves left!", @@ -507,7 +512,7 @@ "city_not_found": "City not found.", "magicitems_not_loaded": "Magic Items not loaded.", "mal_profile": "{0}'s MAL profile", - "mashape_api_missing": "Bot owner didn't specify MashapeApiKey. You can't use this functionality.", + "mashape_api_missing": "Bot owner didn't specify RapidApi api key. You can't use this functionality.", "min_max": "Min/Max", "no_channel_found": "No channel found.", "on_hold": "On-hold", @@ -612,6 +617,7 @@ "quotes_remove_none": "No quotes found which you can remove.", "quote_added_new": "Quote #{0} added.", "quote_deleted": "Quote #{0} deleted.", + "quote_edited": "Quote Edited", "region": "Region", "remind": "I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`", "remind_timely": "I will remind you about your timely reward {0}", @@ -875,7 +881,7 @@ "club_disband_error": "Error. You are either not in a club, or you are not the owner of your club.", "club_icon_too_large": "Image is too large.", "club_icon_invalid_filetype": "Specified image has an invalid filetype. Make sure you're specifying a direct image url.", - "club_icon_url_format": "You must specify an absolute image url/.", + "club_icon_url_format": "You must specify an absolute image url.", "club_icon_set": "New club icon set.", "club_bans_for": "Bans for {0} club", "club_apps_for": "Applicants for {0} club", @@ -960,8 +966,8 @@ "perm_override_all_confirm": "Are you sure that you want to remove **ALL** discord permission overrides on this server? This action is irreversible.", "perm_overrides": "Discord Permission Overrides", "perm_override_reset": "Discord Permission Overrides for this command have been cleared.", - "bj_created": "has created a new BlackJack game in this channel.", - "bj_joined": "has joined the BlackJack game", + "bj_created": "{0} has created a new BlackJack game in this channel.", + "bj_joined": "{0} has joined the BlackJack game", "reset": "Xp Reset", "reset_server_confirm": "Are you sure that you want to reset the XP of all users on the server?", "reset_user_confirm": "Are you sure that you want to reset specified user's XP on this server?", @@ -996,7 +1002,7 @@ "module_description_permissions": "Setup perms for commands, filter words and set up command cooldowns", "module_description_searches": "Search for jokes, images of animals, anime and manga", "module_description_xp": "Gain xp based on chat activity, check users' xp cards", - "module_description_marmalade": "**Bot Owner only.** Load, unload and handle dynamic modules. Read more [here](https://docs.elliebot.net/v4/)", + "module_description_marmalade": "**Bot Owner only.** Load, unload and handle dynamic modules. Read more [here](https://docs.elliebot.net/ellie/)", "module_description_patronage": "Commands related to supporting the bot", "module_description_missing": "Description is missing for this module.", "purge_user_confirm": "Are you sure that you want to purge {0} from the database?", @@ -1094,5 +1100,6 @@ "todo_archive_not_found": "Archived todo list not found.", "todo_archived_list": "Archived Todo List", "search_results": "Search results", - "queue_search_results": "Type the number of the search result to queue up that track." -} \ No newline at end of file + "queue_search_results": "Type the number of the search result to queue up that track.", + "overloads": "Overloads" +} From 06f399ff6334563b62f2aa931e5ac8e3181c34d1 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:32:40 +1200 Subject: [PATCH 41/62] Updated Waifu.cs --- src/EllieBot/Db/Models/Waifu.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EllieBot/Db/Models/Waifu.cs b/src/EllieBot/Db/Models/Waifu.cs index d9f36d9..2583afb 100644 --- a/src/EllieBot/Db/Models/Waifu.cs +++ b/src/EllieBot/Db/Models/Waifu.cs @@ -1,7 +1,7 @@ #nullable disable using EllieBot.Db.Models; -namespace NadekoBot.Services.Database.Models; +namespace EllieBot.Services.Database.Models; public class WaifuInfo : DbEntity { From 547aa8b34deccb047ca651d258794bfc0fb22486 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:44:07 +1200 Subject: [PATCH 42/62] Added common files This took way too long --- src/EllieBot/_common/AddRemove.cs | 10 + .../_common/Attributes/AliasesAttribute.cs | 12 + .../_common/Attributes/CmdAttribute.cs | 18 + .../_common/Attributes/DIIgnoreAttribute.cs | 11 + .../Attributes/EllieOptionsAttribute.cs | 7 + .../Attributes/NoPublicBotAttribute.cs | 20 + .../Attributes/OnlyPublicBotAttribute.cs | 21 + .../_common/Attributes/OwnerOnlyAttribute.cs | 19 + .../_common/Attributes/RatelimitAttribute.cs | 37 + .../_common/Attributes/UserPermAttribute.cs | 29 + src/EllieBot/_common/BotCommandTypeReader.cs | 30 + src/EllieBot/_common/CleanupModuleBase.cs | 25 + src/EllieBot/_common/CleverBotResponseStr.cs | 10 + src/EllieBot/_common/CmdStrings.cs | 17 + src/EllieBot/_common/CommandData.cs | 9 + src/EllieBot/_common/CommandNameLoadHelper.cs | 40 + src/EllieBot/_common/Configs/BotConfig.cs | 210 ++++ src/EllieBot/_common/Configs/IConfigSeria.cs | 18 + src/EllieBot/_common/Creds.cs | 272 ++++++ src/EllieBot/_common/Currency/CurrencyType.cs | 6 + src/EllieBot/_common/Currency/IBankService.cs | 10 + .../_common/Currency/ICurrencyService.cs | 43 + src/EllieBot/_common/Currency/ITxTracker.cs | 9 + src/EllieBot/_common/Currency/IWallet.cs | 40 + src/EllieBot/_common/Currency/TxData.cs | 7 + src/EllieBot/_common/DbService.cs | 15 + src/EllieBot/_common/Deck/Deck.cs | 309 ++++++ src/EllieBot/_common/Deck/NewCard.cs | 5 + src/EllieBot/_common/Deck/NewDeck.cs | 54 ++ .../MultipleRegularDeck.cs | 28 + .../_common/Deck/Regular/RegularCard.cs | 4 + .../_common/Deck/Regular/RegularDeck.cs | 15 + .../Deck/Regular/RegularDeckExtensions.cs | 56 ++ .../_common/Deck/Regular/RegularSuit.cs | 9 + .../_common/Deck/Regular/RegularValue.cs | 18 + src/EllieBot/_common/DoAsUserMessage.cs | 154 +++ src/EllieBot/_common/DownloadTracker.cs | 38 + src/EllieBot/_common/EllieModule.cs | 108 +++ src/EllieBot/_common/EllieTypeReader.cs | 14 + .../Gambling/Betdraw/BetdrawColorGuess.cs | 7 + .../_common/Gambling/Betdraw/BetdrawGame.cs | 86 ++ .../_common/Gambling/Betdraw/BetdrawResult.cs | 11 + .../Gambling/Betdraw/BetdrawResultType.cs | 7 + .../Gambling/Betdraw/BetdrawValueGuess.cs | 7 + .../_common/Gambling/Betflip/BetflipGame.cs | 33 + .../_common/Gambling/Betflip/BetflipResult.cs | 8 + .../_common/Gambling/Betroll/BetrollGame.cs | 42 + .../_common/Gambling/Betroll/BetrollResult.cs | 9 + src/EllieBot/_common/Gambling/Rps/RpsGame.cs | 75 ++ .../_common/Gambling/Slot/SlotGame.cs | 116 +++ .../_common/Gambling/Slot/SlotResult.cs | 9 + .../_common/Gambling/Wof/LuLaResult.cs | 9 + src/EllieBot/_common/Gambling/Wof/WofGame.cs | 34 + src/EllieBot/_common/Helpers.cs | 13 + src/EllieBot/_common/IBot.cs | 12 + src/EllieBot/_common/ICloneable.cs | 8 + src/EllieBot/_common/ICurrencyProvider.cs | 29 + .../_common/IDiscordPermOverrideService.cs | 7 + src/EllieBot/_common/IEllieCommandOptions.cs | 7 + src/EllieBot/_common/ILogCommandService.cs | 34 + src/EllieBot/_common/IPermissionChecker.cs | 37 + src/EllieBot/_common/IPlaceholderProvider.cs | 7 + src/EllieBot/_common/ImageUrls.cs | 51 + .../_common/Interaction/EllieInteraction.cs | 164 ++++ .../Interaction/EllieInteractionService.cs | 77 ++ .../Interaction/IEllieInteractionService.cs | 30 + .../_common/Interaction/InteractionHelpers.cs | 7 + .../Models/EllieButtonInteraction.cs | 21 + .../Models/EllieInteractionExtensions.cs | 15 + .../Models/EllieSelectInteraction.cs | 21 + .../JsonConverters/CultureInfoConverter.cs | 14 + .../_common/JsonConverters/Rgba32Converter.cs | 14 + src/EllieBot/_common/LbOpts.cs | 14 + src/EllieBot/_common/Linq2DbExpressions.cs | 16 + src/EllieBot/_common/LoginErrorHandler.cs | 52 + .../Common/Adapters/BehaviorAdapter.cs | 78 ++ .../Common/Adapters/ContextAdapterFactory.cs | 9 + .../Common/Adapters/DmContextAdapter.cs | 47 + .../Common/Adapters/FilterAdapter.cs | 33 + .../Common/Adapters/GuildContextAdapter.cs | 49 + .../Common/Adapters/ParamParserAdapter.cs | 34 + .../Marmalade/Common/CommandContextType.cs | 27 + .../Common/Config/IMarmaladeConfigService.cs | 8 + .../Common/Config/MarmaladeConfig.cs | 20 + .../Common/Config/MarmaladeConfigService.cs | 45 + .../Common/MarmaladeAssemblyLoadContext.cs | 35 + .../Common/MarmaladeIoCKernelModule.cs | 74 ++ .../Common/MarmaladeLoaderService.cs | 916 ++++++++++++++++++ .../Common/Models/CanaryCommandData.cs | 44 + .../Marmalade/Common/Models/CanaryData.cs | 11 + .../Marmalade/Common/Models/ParamData.cs | 10 + .../Common/Models/ResolvedMarmalade.cs | 15 + .../Marmalade/IMarmaladeLoaderService.cs | 24 + .../_common/Marmalade/MarmaladeLoadResult.cs | 10 + .../Marmalade/MarmaladeUnloadResult.cs | 9 + src/EllieBot/_common/MessageType.cs | 8 + .../_common/ModuleBehaviors/IBehavior.cs | 6 + .../_common/ModuleBehaviors/IExecNoCommand.cs | 19 + .../_common/ModuleBehaviors/IExecOnMessage.cs | 21 + .../ModuleBehaviors/IExecPostCommand.cs | 22 + .../ModuleBehaviors/IExecPreCommand.cs | 25 + .../ModuleBehaviors/IInputTransformer.cs | 25 + .../_common/ModuleBehaviors/IReadyExecutor.cs | 13 + .../_common/NinjectKernelExtensions.cs | 51 + src/EllieBot/_common/OldCreds.cs | 45 + src/EllieBot/_common/OptionsParser.cs | 23 + .../_common/Patronage/FeatureLimitKey.cs | 7 + .../_common/Patronage/FeatureQuotaStats.cs | 8 + src/EllieBot/_common/Patronage/IPatronData.cs | 11 + .../_common/Patronage/IPatronageService.cs | 56 ++ .../_common/Patronage/ISubscriptionHandler.cs | 16 + src/EllieBot/_common/Patronage/Patron.cs | 38 + .../_common/Patronage/PatronConfigData.cs | 37 + .../_common/Patronage/PatronExtensions.cs | 39 + src/EllieBot/_common/Patronage/PatronTier.cs | 14 + src/EllieBot/_common/Patronage/QuotaLimit.cs | 66 ++ src/EllieBot/_common/Patronage/QuotaPer.cs | 8 + .../Patronage/SubscriptionChargeStatus.cs | 10 + .../_common/Patronage/UserQuotaStats.cs | 25 + src/EllieBot/_common/Pokemon/PokemonNameId.cs | 8 + src/EllieBot/_common/Pokemon/SearchPokemon.cs | 41 + .../_common/Pokemon/SearchPokemonAbility.cs | 10 + .../Replacements/IReplacementPatternStore.cs | 20 + .../Replacements/IReplacementService.cs | 7 + .../Replacements/Impl/ReplacementContext.cs | 69 ++ .../Replacements/Impl/ReplacementInfo.cs | 57 ++ .../Impl/ReplacementPatternStore.cs | 130 +++ .../Impl/ReplacementRegistrator.default.cs | 113 +++ .../Replacements/Impl/ReplacementService.cs | 137 +++ .../_common/Replacements/Impl/Replacer.cs | 138 +++ ...RequireObjectPropertiesContractResolver.cs | 15 + .../_common/Sender/IMessageSenderService.cs | 12 + .../_common/Sender/MessageSenderService.cs | 57 ++ .../ResponseBuilder.PaginationSender.cs | 153 +++ .../_common/Sender/ResponseBuilder.cs | 492 ++++++++++ .../Sender/ResponseBuilderExtensions.cs | 28 + .../_common/Sender/ResponseMessageModel.cs | 12 + .../_common/ServiceCollectionExtensions.cs | 131 +++ .../_common/Services/CommandHandler.cs | 433 +++++++++ .../Services/Currency/CurrencyService.cs | 116 +++ .../Currency/CurrencyServiceExtensions.cs | 48 + .../Services/Currency/DefaultWallet.cs | 108 +++ .../Services/Currency/GamblingTxTracker.cs | 110 +++ .../_common/Services/IBehaviourHandler.cs | 17 + .../_common/Services/ICommandHandler.cs | 12 + src/EllieBot/_common/Services/ICoordinator.cs | 20 + .../_common/Services/ICustomBehavior.cs | 13 + src/EllieBot/_common/Services/IEService.cs | 9 + .../_common/Services/IGoogleApiService.cs | 18 + .../_common/Services/ILocalDataCache.cs | 13 + .../_common/Services/ILocalization.cs | 19 + .../_common/Services/IRemindService.cs | 15 + .../_common/Services/IStatsService.cs | 70 ++ .../_common/Services/ITimezoneService.cs | 6 + .../_common/Services/Impl/BehaviorExecutor.cs | 302 ++++++ .../_common/Services/Impl/BlacklistService.cs | 141 +++ .../Services/Impl/CommandsUtilityService.cs | 184 ++++ .../Impl/DiscordPermOverrideService.cs | 136 +++ .../_common/Services/Impl/FontProvider.cs | 60 ++ .../_common/Services/Impl/IImageCache.cs | 17 + .../_common/Services/Impl/ImagesConfig.cs | 19 + .../Services/Impl/RedisImageExtensions.cs | 11 + .../Services/Impl/SingleProcessCoordinator.cs | 58 ++ .../Impl/StartingGuildsListService.cs | 18 + .../_common/Services/Impl/StatsService.cs | 222 +++++ .../_common/Services/Impl/YtdlOperation.cs | 77 ++ .../Services/strings/impl/BotStrings.cs | 102 ++ .../strings/impl/LocalFileStringsSource.cs | 73 ++ .../strings/impl/MemoryBotStringsProvider.cs | 38 + .../_common/Settings/BotConfigService.cs | 73 ++ .../_common/Settings/ConfigParsers.cs | 50 + .../_common/Settings/ConfigServiceBase.cs | 201 ++++ .../_common/Settings/IConfigService.cs | 46 + .../_common/Settings/SettingParser.cs | 8 + .../_common/SmartText/SmartEmbedText.cs | 184 ++++ .../_common/SmartText/SmartEmbedTextArray.cs | 34 + .../_common/SmartText/SmartPlainText.cs | 19 + src/EllieBot/_common/SmartText/SmartText.cs | 92 ++ .../_common/SmartText/SmartTextEmbedAuthor.cs | 16 + .../_common/SmartText/SmartTextEmbedField.cs | 9 + .../_common/SmartText/SmartTextEmbedFooter.cs | 14 + src/EllieBot/_common/TriviaQuestionModel.cs | 11 + src/EllieBot/_common/TypeReaderResult.cs | 30 + .../_common/TypeReaders/CommandOrExprInfo.cs | 23 + .../_common/TypeReaders/EmoteTypeReader.cs | 13 + .../TypeReaders/GuildDateTimeTypeReader.cs | 49 + .../_common/TypeReaders/GuildTypeReader.cs | 24 + .../TypeReaders/GuildUserTypeReader.cs | 33 + .../_common/TypeReaders/KwumTypeReader.cs | 19 + .../TypeReaders/Models/PermissionAction.cs | 27 + .../_common/TypeReaders/Models/StoopidTime.cs | 55 ++ .../_common/TypeReaders/ModuleTypeReader.cs | 52 + .../TypeReaders/PermissionActionTypeReader.cs | 39 + .../_common/TypeReaders/Rgba32TypeReader.cs | 20 + .../TypeReaders/StoopidTimeTypeReader.cs | 22 + src/EllieBot/_common/Yml/CommentAttribute.cs | 11 + .../Yml/CommentGatheringTypeInspector.cs | 65 ++ .../_common/Yml/CommentsObjectDescriptor.cs | 30 + .../_common/Yml/CommentsObjectGraphVisitor.cs | 29 + .../Yml/MultilineScalarFlowStyleEmitter.cs | 36 + src/EllieBot/_common/Yml/Rgba32Converter.cs | 47 + src/EllieBot/_common/Yml/UriConverter.cs | 25 + src/EllieBot/_common/Yml/Yaml.cs | 30 + .../_Extensions/BotCredentialsExtensions.cs | 10 + .../_Extensions/CommandContextExtensions.cs | 30 + .../_common/_Extensions/DbExtensions.cs | 11 + .../_common/_Extensions/Extensions.cs | 237 +++++ .../_Extensions/ImagesharpExtensions.cs | 97 ++ .../_Extensions/LinkedListExtensions.cs | 18 + .../_common/_Extensions/NumberExtensions.cs | 7 + .../_Extensions/ReflectionExtensions.cs | 23 + .../_common/_Extensions/Rgba32Extensions.cs | 57 ++ .../SocketMessageComponentExtensions.cs | 33 + .../_common/_Extensions/UserExtensions.cs | 21 + 214 files changed, 11046 insertions(+) create mode 100644 src/EllieBot/_common/AddRemove.cs create mode 100644 src/EllieBot/_common/Attributes/AliasesAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/CmdAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/NoPublicBotAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/RatelimitAttribute.cs create mode 100644 src/EllieBot/_common/Attributes/UserPermAttribute.cs create mode 100644 src/EllieBot/_common/BotCommandTypeReader.cs create mode 100644 src/EllieBot/_common/CleanupModuleBase.cs create mode 100644 src/EllieBot/_common/CleverBotResponseStr.cs create mode 100644 src/EllieBot/_common/CmdStrings.cs create mode 100644 src/EllieBot/_common/CommandData.cs create mode 100644 src/EllieBot/_common/CommandNameLoadHelper.cs create mode 100644 src/EllieBot/_common/Configs/BotConfig.cs create mode 100644 src/EllieBot/_common/Configs/IConfigSeria.cs create mode 100644 src/EllieBot/_common/Creds.cs create mode 100644 src/EllieBot/_common/Currency/CurrencyType.cs create mode 100644 src/EllieBot/_common/Currency/IBankService.cs create mode 100644 src/EllieBot/_common/Currency/ICurrencyService.cs create mode 100644 src/EllieBot/_common/Currency/ITxTracker.cs create mode 100644 src/EllieBot/_common/Currency/IWallet.cs create mode 100644 src/EllieBot/_common/Currency/TxData.cs create mode 100644 src/EllieBot/_common/DbService.cs create mode 100644 src/EllieBot/_common/Deck/Deck.cs create mode 100644 src/EllieBot/_common/Deck/NewCard.cs create mode 100644 src/EllieBot/_common/Deck/NewDeck.cs create mode 100644 src/EllieBot/_common/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs create mode 100644 src/EllieBot/_common/Deck/Regular/RegularCard.cs create mode 100644 src/EllieBot/_common/Deck/Regular/RegularDeck.cs create mode 100644 src/EllieBot/_common/Deck/Regular/RegularDeckExtensions.cs create mode 100644 src/EllieBot/_common/Deck/Regular/RegularSuit.cs create mode 100644 src/EllieBot/_common/Deck/Regular/RegularValue.cs create mode 100644 src/EllieBot/_common/DoAsUserMessage.cs create mode 100644 src/EllieBot/_common/DownloadTracker.cs create mode 100644 src/EllieBot/_common/EllieModule.cs create mode 100644 src/EllieBot/_common/EllieTypeReader.cs create mode 100644 src/EllieBot/_common/Gambling/Betdraw/BetdrawColorGuess.cs create mode 100644 src/EllieBot/_common/Gambling/Betdraw/BetdrawGame.cs create mode 100644 src/EllieBot/_common/Gambling/Betdraw/BetdrawResult.cs create mode 100644 src/EllieBot/_common/Gambling/Betdraw/BetdrawResultType.cs create mode 100644 src/EllieBot/_common/Gambling/Betdraw/BetdrawValueGuess.cs create mode 100644 src/EllieBot/_common/Gambling/Betflip/BetflipGame.cs create mode 100644 src/EllieBot/_common/Gambling/Betflip/BetflipResult.cs create mode 100644 src/EllieBot/_common/Gambling/Betroll/BetrollGame.cs create mode 100644 src/EllieBot/_common/Gambling/Betroll/BetrollResult.cs create mode 100644 src/EllieBot/_common/Gambling/Rps/RpsGame.cs create mode 100644 src/EllieBot/_common/Gambling/Slot/SlotGame.cs create mode 100644 src/EllieBot/_common/Gambling/Slot/SlotResult.cs create mode 100644 src/EllieBot/_common/Gambling/Wof/LuLaResult.cs create mode 100644 src/EllieBot/_common/Gambling/Wof/WofGame.cs create mode 100644 src/EllieBot/_common/Helpers.cs create mode 100644 src/EllieBot/_common/IBot.cs create mode 100644 src/EllieBot/_common/ICloneable.cs create mode 100644 src/EllieBot/_common/ICurrencyProvider.cs create mode 100644 src/EllieBot/_common/IDiscordPermOverrideService.cs create mode 100644 src/EllieBot/_common/IEllieCommandOptions.cs create mode 100644 src/EllieBot/_common/ILogCommandService.cs create mode 100644 src/EllieBot/_common/IPermissionChecker.cs create mode 100644 src/EllieBot/_common/IPlaceholderProvider.cs create mode 100644 src/EllieBot/_common/ImageUrls.cs create mode 100644 src/EllieBot/_common/Interaction/EllieInteraction.cs create mode 100644 src/EllieBot/_common/Interaction/EllieInteractionService.cs create mode 100644 src/EllieBot/_common/Interaction/IEllieInteractionService.cs create mode 100644 src/EllieBot/_common/Interaction/InteractionHelpers.cs create mode 100644 src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs create mode 100644 src/EllieBot/_common/Interaction/Models/EllieInteractionExtensions.cs create mode 100644 src/EllieBot/_common/Interaction/Models/EllieSelectInteraction.cs create mode 100644 src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs create mode 100644 src/EllieBot/_common/JsonConverters/Rgba32Converter.cs create mode 100644 src/EllieBot/_common/LbOpts.cs create mode 100644 src/EllieBot/_common/Linq2DbExpressions.cs create mode 100644 src/EllieBot/_common/LoginErrorHandler.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Adapters/BehaviorAdapter.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Adapters/ContextAdapterFactory.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Adapters/DmContextAdapter.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Adapters/FilterAdapter.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Adapters/GuildContextAdapter.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Adapters/ParamParserAdapter.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/CommandContextType.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Config/IMarmaladeConfigService.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfig.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfigService.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/MarmaladeAssemblyLoadContext.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/MarmaladeIoCKernelModule.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/MarmaladeLoaderService.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Models/CanaryCommandData.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Models/CanaryData.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Models/ParamData.cs create mode 100644 src/EllieBot/_common/Marmalade/Common/Models/ResolvedMarmalade.cs create mode 100644 src/EllieBot/_common/Marmalade/IMarmaladeLoaderService.cs create mode 100644 src/EllieBot/_common/Marmalade/MarmaladeLoadResult.cs create mode 100644 src/EllieBot/_common/Marmalade/MarmaladeUnloadResult.cs create mode 100644 src/EllieBot/_common/MessageType.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IBehavior.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs create mode 100644 src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs create mode 100644 src/EllieBot/_common/NinjectKernelExtensions.cs create mode 100644 src/EllieBot/_common/OldCreds.cs create mode 100644 src/EllieBot/_common/OptionsParser.cs create mode 100644 src/EllieBot/_common/Patronage/FeatureLimitKey.cs create mode 100644 src/EllieBot/_common/Patronage/FeatureQuotaStats.cs create mode 100644 src/EllieBot/_common/Patronage/IPatronData.cs create mode 100644 src/EllieBot/_common/Patronage/IPatronageService.cs create mode 100644 src/EllieBot/_common/Patronage/ISubscriptionHandler.cs create mode 100644 src/EllieBot/_common/Patronage/Patron.cs create mode 100644 src/EllieBot/_common/Patronage/PatronConfigData.cs create mode 100644 src/EllieBot/_common/Patronage/PatronExtensions.cs create mode 100644 src/EllieBot/_common/Patronage/PatronTier.cs create mode 100644 src/EllieBot/_common/Patronage/QuotaLimit.cs create mode 100644 src/EllieBot/_common/Patronage/QuotaPer.cs create mode 100644 src/EllieBot/_common/Patronage/SubscriptionChargeStatus.cs create mode 100644 src/EllieBot/_common/Patronage/UserQuotaStats.cs create mode 100644 src/EllieBot/_common/Pokemon/PokemonNameId.cs create mode 100644 src/EllieBot/_common/Pokemon/SearchPokemon.cs create mode 100644 src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs create mode 100644 src/EllieBot/_common/Replacements/IReplacementPatternStore.cs create mode 100644 src/EllieBot/_common/Replacements/IReplacementService.cs create mode 100644 src/EllieBot/_common/Replacements/Impl/ReplacementContext.cs create mode 100644 src/EllieBot/_common/Replacements/Impl/ReplacementInfo.cs create mode 100644 src/EllieBot/_common/Replacements/Impl/ReplacementPatternStore.cs create mode 100644 src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs create mode 100644 src/EllieBot/_common/Replacements/Impl/ReplacementService.cs create mode 100644 src/EllieBot/_common/Replacements/Impl/Replacer.cs create mode 100644 src/EllieBot/_common/RequireObjectPropertiesContractResolver.cs create mode 100644 src/EllieBot/_common/Sender/IMessageSenderService.cs create mode 100644 src/EllieBot/_common/Sender/MessageSenderService.cs create mode 100644 src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs create mode 100644 src/EllieBot/_common/Sender/ResponseBuilder.cs create mode 100644 src/EllieBot/_common/Sender/ResponseBuilderExtensions.cs create mode 100644 src/EllieBot/_common/Sender/ResponseMessageModel.cs create mode 100644 src/EllieBot/_common/ServiceCollectionExtensions.cs create mode 100644 src/EllieBot/_common/Services/CommandHandler.cs create mode 100644 src/EllieBot/_common/Services/Currency/CurrencyService.cs create mode 100644 src/EllieBot/_common/Services/Currency/CurrencyServiceExtensions.cs create mode 100644 src/EllieBot/_common/Services/Currency/DefaultWallet.cs create mode 100644 src/EllieBot/_common/Services/Currency/GamblingTxTracker.cs create mode 100644 src/EllieBot/_common/Services/IBehaviourHandler.cs create mode 100644 src/EllieBot/_common/Services/ICommandHandler.cs create mode 100644 src/EllieBot/_common/Services/ICoordinator.cs create mode 100644 src/EllieBot/_common/Services/ICustomBehavior.cs create mode 100644 src/EllieBot/_common/Services/IEService.cs create mode 100644 src/EllieBot/_common/Services/IGoogleApiService.cs create mode 100644 src/EllieBot/_common/Services/ILocalDataCache.cs create mode 100644 src/EllieBot/_common/Services/ILocalization.cs create mode 100644 src/EllieBot/_common/Services/IRemindService.cs create mode 100644 src/EllieBot/_common/Services/IStatsService.cs create mode 100644 src/EllieBot/_common/Services/ITimezoneService.cs create mode 100644 src/EllieBot/_common/Services/Impl/BehaviorExecutor.cs create mode 100644 src/EllieBot/_common/Services/Impl/BlacklistService.cs create mode 100644 src/EllieBot/_common/Services/Impl/CommandsUtilityService.cs create mode 100644 src/EllieBot/_common/Services/Impl/DiscordPermOverrideService.cs create mode 100644 src/EllieBot/_common/Services/Impl/FontProvider.cs create mode 100644 src/EllieBot/_common/Services/Impl/IImageCache.cs create mode 100644 src/EllieBot/_common/Services/Impl/ImagesConfig.cs create mode 100644 src/EllieBot/_common/Services/Impl/RedisImageExtensions.cs create mode 100644 src/EllieBot/_common/Services/Impl/SingleProcessCoordinator.cs create mode 100644 src/EllieBot/_common/Services/Impl/StartingGuildsListService.cs create mode 100644 src/EllieBot/_common/Services/Impl/StatsService.cs create mode 100644 src/EllieBot/_common/Services/Impl/YtdlOperation.cs create mode 100644 src/EllieBot/_common/Services/strings/impl/BotStrings.cs create mode 100644 src/EllieBot/_common/Services/strings/impl/LocalFileStringsSource.cs create mode 100644 src/EllieBot/_common/Services/strings/impl/MemoryBotStringsProvider.cs create mode 100644 src/EllieBot/_common/Settings/BotConfigService.cs create mode 100644 src/EllieBot/_common/Settings/ConfigParsers.cs create mode 100644 src/EllieBot/_common/Settings/ConfigServiceBase.cs create mode 100644 src/EllieBot/_common/Settings/IConfigService.cs create mode 100644 src/EllieBot/_common/Settings/SettingParser.cs create mode 100644 src/EllieBot/_common/SmartText/SmartEmbedText.cs create mode 100644 src/EllieBot/_common/SmartText/SmartEmbedTextArray.cs create mode 100644 src/EllieBot/_common/SmartText/SmartPlainText.cs create mode 100644 src/EllieBot/_common/SmartText/SmartText.cs create mode 100644 src/EllieBot/_common/SmartText/SmartTextEmbedAuthor.cs create mode 100644 src/EllieBot/_common/SmartText/SmartTextEmbedField.cs create mode 100644 src/EllieBot/_common/SmartText/SmartTextEmbedFooter.cs create mode 100644 src/EllieBot/_common/TriviaQuestionModel.cs create mode 100644 src/EllieBot/_common/TypeReaderResult.cs create mode 100644 src/EllieBot/_common/TypeReaders/CommandOrExprInfo.cs create mode 100644 src/EllieBot/_common/TypeReaders/EmoteTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/GuildDateTimeTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/GuildTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/GuildUserTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/KwumTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/Models/PermissionAction.cs create mode 100644 src/EllieBot/_common/TypeReaders/Models/StoopidTime.cs create mode 100644 src/EllieBot/_common/TypeReaders/ModuleTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/PermissionActionTypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/Rgba32TypeReader.cs create mode 100644 src/EllieBot/_common/TypeReaders/StoopidTimeTypeReader.cs create mode 100644 src/EllieBot/_common/Yml/CommentAttribute.cs create mode 100644 src/EllieBot/_common/Yml/CommentGatheringTypeInspector.cs create mode 100644 src/EllieBot/_common/Yml/CommentsObjectDescriptor.cs create mode 100644 src/EllieBot/_common/Yml/CommentsObjectGraphVisitor.cs create mode 100644 src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs create mode 100644 src/EllieBot/_common/Yml/Rgba32Converter.cs create mode 100644 src/EllieBot/_common/Yml/UriConverter.cs create mode 100644 src/EllieBot/_common/Yml/Yaml.cs create mode 100644 src/EllieBot/_common/_Extensions/BotCredentialsExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/CommandContextExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/DbExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/Extensions.cs create mode 100644 src/EllieBot/_common/_Extensions/ImagesharpExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/LinkedListExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/NumberExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/ReflectionExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/Rgba32Extensions.cs create mode 100644 src/EllieBot/_common/_Extensions/SocketMessageComponentExtensions.cs create mode 100644 src/EllieBot/_common/_Extensions/UserExtensions.cs diff --git a/src/EllieBot/_common/AddRemove.cs b/src/EllieBot/_common/AddRemove.cs new file mode 100644 index 0000000..bb3862e --- /dev/null +++ b/src/EllieBot/_common/AddRemove.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Common; + +public enum AddRemove +{ + Add = int.MinValue, + Remove = int.MinValue + 1, + Rem = int.MinValue + 1, + Rm = int.MinValue + 1 +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/AliasesAttribute.cs b/src/EllieBot/_common/Attributes/AliasesAttribute.cs new file mode 100644 index 0000000..bef833e --- /dev/null +++ b/src/EllieBot/_common/Attributes/AliasesAttribute.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class AliasesAttribute : AliasAttribute +{ + public AliasesAttribute([CallerMemberName] string memberName = "") + : base(CommandNameLoadHelper.GetAliasesFor(memberName)) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/CmdAttribute.cs b/src/EllieBot/_common/Attributes/CmdAttribute.cs new file mode 100644 index 0000000..a02fd1e --- /dev/null +++ b/src/EllieBot/_common/Attributes/CmdAttribute.cs @@ -0,0 +1,18 @@ +using System.Runtime.CompilerServices; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class CmdAttribute : CommandAttribute +{ + public string MethodName { get; } + + public CmdAttribute([CallerMemberName] string memberName = "") + : base(CommandNameLoadHelper.GetCommandNameFor(memberName)) + { + MethodName = memberName.ToLowerInvariant(); + Aliases = CommandNameLoadHelper.GetAliasesFor(memberName); + Remarks = memberName.ToLowerInvariant(); + Summary = memberName.ToLowerInvariant(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs b/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs new file mode 100644 index 0000000..7be799a --- /dev/null +++ b/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Common; + +/// +/// Classed marked with this attribute will not be added to the service provider +/// +[AttributeUsage(AttributeTargets.Class)] +public class DIIgnoreAttribute : Attribute +{ + +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs b/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs new file mode 100644 index 0000000..c94b109 --- /dev/null +++ b/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class EllieOptionsAttribute : Attribute + where TOption: IEllieCommandOptions +{ +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/NoPublicBotAttribute.cs b/src/EllieBot/_common/Attributes/NoPublicBotAttribute.cs new file mode 100644 index 0000000..2ce8ccc --- /dev/null +++ b/src/EllieBot/_common/Attributes/NoPublicBotAttribute.cs @@ -0,0 +1,20 @@ +#nullable disable +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Common; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public sealed class NoPublicBotAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { +#if GLOBAL_ELLIE + return Task.FromResult(PreconditionResult.FromError("Not available on the public bot. To learn how to selfhost a private bot, click [here](https://docs.elliebot.net/ellie/).")); +#else + return Task.FromResult(PreconditionResult.FromSuccess()); +#endif + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs b/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs new file mode 100644 index 0000000..6ae9408 --- /dev/null +++ b/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs @@ -0,0 +1,21 @@ +#nullable disable +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Common; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +[SuppressMessage("Style", "IDE0022:Use expression body for methods")] +public sealed class OnlyPublicBotAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { +#if GLOBAL_ELLIE || DEBUG + return Task.FromResult(PreconditionResult.FromSuccess()); +#else + return Task.FromResult(PreconditionResult.FromError("Only available on the public bot.")); +#endif + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs b/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs new file mode 100644 index 0000000..7aa9317 --- /dev/null +++ b/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public sealed class OwnerOnlyAttribute : PreconditionAttribute +{ + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + var creds = services.GetRequiredService().GetCreds(); + + return Task.FromResult(creds.IsOwner(context.User) || context.Client.CurrentUser.Id == context.User.Id + ? PreconditionResult.FromSuccess() + : PreconditionResult.FromError("Not owner")); + } +} diff --git a/src/EllieBot/_common/Attributes/RatelimitAttribute.cs b/src/EllieBot/_common/Attributes/RatelimitAttribute.cs new file mode 100644 index 0000000..7fcf9c8 --- /dev/null +++ b/src/EllieBot/_common/Attributes/RatelimitAttribute.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace EllieBot.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class RatelimitAttribute : PreconditionAttribute +{ + public int Seconds { get; } + + public RatelimitAttribute(int seconds) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(seconds); + + Seconds = seconds; + } + + public override async Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + if (Seconds == 0) + return PreconditionResult.FromSuccess(); + + var cache = services.GetRequiredService(); + var rem = await cache.GetRatelimitAsync( + new($"precondition:{context.User.Id}:{command.Name}"), + Seconds.Seconds()); + + if (rem is null) + return PreconditionResult.FromSuccess(); + + var msgContent = $"You can use this command again in {rem.Value.TotalSeconds:F1}s."; + + return PreconditionResult.FromError(msgContent); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/UserPermAttribute.cs b/src/EllieBot/_common/Attributes/UserPermAttribute.cs new file mode 100644 index 0000000..1b4ee75 --- /dev/null +++ b/src/EllieBot/_common/Attributes/UserPermAttribute.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Discord; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public class UserPermAttribute : RequireUserPermissionAttribute +{ + public UserPermAttribute(GuildPerm permission) + : base(permission) + { + } + + public UserPermAttribute(ChannelPerm permission) + : base(permission) + { + } + + public override Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + var permService = services.GetRequiredService(); + if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out _)) + return Task.FromResult(PreconditionResult.FromSuccess()); + + return base.CheckPermissionsAsync(context, command, services); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/BotCommandTypeReader.cs b/src/EllieBot/_common/BotCommandTypeReader.cs new file mode 100644 index 0000000..fc839bd --- /dev/null +++ b/src/EllieBot/_common/BotCommandTypeReader.cs @@ -0,0 +1,30 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public sealed class CommandTypeReader : EllieTypeReader +{ + private readonly CommandService _cmds; + private readonly ICommandHandler _handler; + + public CommandTypeReader(ICommandHandler handler, CommandService cmds) + { + _handler = handler; + _cmds = cmds; + } + + public override ValueTask> ReadAsync(ICommandContext ctx, string input) + { + input = input.ToUpperInvariant(); + var prefix = _handler.GetPrefix(ctx.Guild); + if (!input.StartsWith(prefix.ToUpperInvariant(), StringComparison.InvariantCulture)) + return new(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found.")); + + input = input[prefix.Length..]; + + var cmd = _cmds.Commands.FirstOrDefault(c => c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input)); + if (cmd is null) + return new(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found.")); + + return new(TypeReaderResult.FromSuccess(cmd)); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/CleanupModuleBase.cs b/src/EllieBot/_common/CleanupModuleBase.cs new file mode 100644 index 0000000..1e97a66 --- /dev/null +++ b/src/EllieBot/_common/CleanupModuleBase.cs @@ -0,0 +1,25 @@ +#nullable disable +namespace EllieBot.Common; + +public abstract class CleanupModuleBase : EllieModule +{ + protected async Task ConfirmActionInternalAsync(string name, Func action) + { + try + { + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.sql_confirm_exec)) + .WithDescription(name); + + if (!await PromptUserConfirmAsync(embed)) + return; + + await action(); + await ctx.OkAsync(); + } + catch (Exception ex) + { + await Response().Error(ex.ToString()).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/CleverBotResponseStr.cs b/src/EllieBot/_common/CleverBotResponseStr.cs new file mode 100644 index 0000000..6675a41 --- /dev/null +++ b/src/EllieBot/_common/CleverBotResponseStr.cs @@ -0,0 +1,10 @@ +#nullable disable +using System.Runtime.InteropServices; + +namespace EllieBot.Modules.Permissions; + +[StructLayout(LayoutKind.Sequential, Size = 1)] +public readonly struct CleverBotResponseStr +{ + public const string CLEVERBOT_RESPONSE = "cleverbot:response"; +} \ No newline at end of file diff --git a/src/EllieBot/_common/CmdStrings.cs b/src/EllieBot/_common/CmdStrings.cs new file mode 100644 index 0000000..c28ed1a --- /dev/null +++ b/src/EllieBot/_common/CmdStrings.cs @@ -0,0 +1,17 @@ +#nullable disable +using Newtonsoft.Json; + +namespace EllieBot.Common; + +public class CmdStrings +{ + public string[] Usages { get; } + public string Description { get; } + + [JsonConstructor] + public CmdStrings([JsonProperty("args")] string[] usages, [JsonProperty("desc")] string description) + { + Usages = usages; + Description = description; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/CommandData.cs b/src/EllieBot/_common/CommandData.cs new file mode 100644 index 0000000..f0514da --- /dev/null +++ b/src/EllieBot/_common/CommandData.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Common; + +public class CommandData +{ + public string Cmd { get; set; } + public string Desc { get; set; } + public string[] Usage { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/CommandNameLoadHelper.cs b/src/EllieBot/_common/CommandNameLoadHelper.cs new file mode 100644 index 0000000..3d69f2e --- /dev/null +++ b/src/EllieBot/_common/CommandNameLoadHelper.cs @@ -0,0 +1,40 @@ +using EllieBot.Common.Yml; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Attributes; + +public static class CommandNameLoadHelper +{ + private static readonly IDeserializer _deserializer = new Deserializer(); + + private static readonly Lazy> _lazyCommandAliases + = new(() => LoadAliases()); + + public static Dictionary LoadAliases(string aliasesFilePath = "data/aliases.yml") + { + var text = File.ReadAllText(aliasesFilePath); + return _deserializer.Deserialize>(text); + } + + public static Dictionary LoadCommandStrings( + string commandsFilePath = "data/strings/commands.yml") + { + var text = File.ReadAllText(commandsFilePath); + + return Yaml.Deserializer.Deserialize>(text); + } + + public static string[] GetAliasesFor(string methodName) + => _lazyCommandAliases.Value.TryGetValue(methodName.ToLowerInvariant(), out var aliases) && aliases.Length > 1 + ? aliases.ToArray() + : Array.Empty(); + + public static string GetCommandNameFor(string methodName) + { + methodName = methodName.ToLowerInvariant(); + var toReturn = _lazyCommandAliases.Value.TryGetValue(methodName, out var aliases) && aliases.Length > 0 + ? aliases[0] + : methodName; + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Configs/BotConfig.cs b/src/EllieBot/_common/Configs/BotConfig.cs new file mode 100644 index 0000000..0715701 --- /dev/null +++ b/src/EllieBot/_common/Configs/BotConfig.cs @@ -0,0 +1,210 @@ +#nullable disable +using Cloneable; +using EllieBot.Common.Yml; +using SixLabors.ImageSharp.PixelFormats; +using System.Globalization; +using YamlDotNet.Core; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Configs; + +[Cloneable] +public sealed partial class BotConfig : ICloneable +{ + [Comment("""DO NOT CHANGE""")] + public int Version { get; set; } = 7; + + [Comment(""" + Most commands, when executed, have a small colored line + next to the response. The color depends whether the command + is completed, errored or in progress (pending) + Color settings below are for the color of those lines. + To get color's hex, you can go here https://htmlcolorcodes.com/ + and copy the hex code fo your selected color (marked as #) + """)] + public ColorConfig Color { get; set; } + + [Comment("Default bot language. It has to be in the list of supported languages (.langli)")] + public CultureInfo DefaultLocale { get; set; } + + [Comment(""" + Style in which executed commands will show up in the console. + Allowed values: Simple, Normal, None + """)] + public ConsoleOutputType ConsoleOutputType { get; set; } + + [Comment("""Whether the bot will check for new releases every hour""")] + public bool CheckForUpdates { get; set; } = true; + + [Comment("""Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?""")] + public bool ForwardMessages { get; set; } + + [Comment(""" + Do you want the message to be forwarded only to the first owner specified in the list of owners (in creds.yml), + or all owners? (this might cause the bot to lag if there's a lot of owners specified) + """)] + public bool ForwardToAllOwners { get; set; } + + [Comment(""" + Any messages sent by users in Bot's DM to be forwarded to the specified channel. + This option will only work when ForwardToAllOwners is set to false + """)] + public ulong? ForwardToChannel { get; set; } + + [Comment(""" + Should the bot ignore messages from other bots? + Settings this to false might get your bot banned if it gets into a spam loop with another bot. + This will only affect command executions, other features will still block bots from access. + Default true + """)] + public bool IgnoreOtherBots { get; set; } + + [Comment(""" + When a user DMs the bot with a message which is not a command + they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. + Supports embeds. How it looks: https://puu.sh/B0BLV.png + """)] + [YamlMember(ScalarStyle = ScalarStyle.Literal)] + public string DmHelpText { get; set; } + + [Comment(""" + Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response. + Case insensitive. + Leave empty to reply with DmHelpText to every DM. + """)] + public List DmHelpTextKeywords { get; set; } + + [Comment("""This is the response for the .h command""")] + [YamlMember(ScalarStyle = ScalarStyle.Literal)] + public string HelpText { get; set; } + + [Comment("""List of modules and commands completely blocked on the bot""")] + public BlockedConfig Blocked { get; set; } + + [Comment("""Which string will be used to recognize the commands""")] + public string Prefix { get; set; } + + [Comment(""" + Toggles whether your bot will group greet/bye messages into a single message every 5 seconds. + 1st user who joins will get greeted immediately + If more users join within the next 5 seconds, they will be greeted in groups of 5. + This will cause %user.mention% and other placeholders to be replaced with multiple users. + Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail, + it will become invalid, as it will resolve to a list of avatars of grouped users. + note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some + servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited, + and (slightly) reduce the greet spam in those servers. + """)] + public bool GroupGreets { get; set; } + + [Comment(""" + Whether the bot will rotate through all specified statuses. + This setting can be changed via .ropl command. + See RotatingStatuses submodule in Administration. + """)] + public bool RotateStatuses { get; set; } + + public BotConfig() + { + var color = new ColorConfig(); + Color = color; + DefaultLocale = new("en-US"); + ConsoleOutputType = ConsoleOutputType.Normal; + ForwardMessages = false; + ForwardToAllOwners = false; + DmHelpText = """{"description": "Type `%prefix%h` for help."}"""; + HelpText = """ + { + "title": "To invite me to your server, use this link", + "description": "https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303", + "color": 53380, + "thumbnail": "https://cdn.elliebot.net/Ellie.png", + "fields": [ + { + "name": "Useful help commands", + "value": "`%bot.prefix%modules` Lists all bot modules. + `%prefix%h CommandName` Shows some help about a specific command. + `%prefix%commands ModuleName` Lists all commands in a module.", + "inline": false + }, + { + "name": "List of all Commands", + "value": "https://commands.elliebot.net/", + "inline": false + }, + { + "name": "Ellie Support Server", + "value": "https://discord.gg/etQdZxSyEH ", + "inline": true + } + ] + } + """; + var blocked = new BlockedConfig(); + Blocked = blocked; + Prefix = "."; + RotateStatuses = false; + GroupGreets = false; + DmHelpTextKeywords = + [ + "help", + "commands", + "cmds", + "module", + "can you do" + ]; + } + + // [Comment(@"Whether the prefix will be a suffix, or prefix. + // For example, if your prefix is ! you will run a command called 'cash' by typing either + // '!cash @Someone' if your prefixIsSuffix: false or + // 'cash @Someone!' if your prefixIsSuffix: true")] + // public bool PrefixIsSuffix { get; set; } + + // public string Prefixed(string text) => PrefixIsSuffix + // ? text + Prefix + // : Prefix + text; + + public string Prefixed(string text) + => Prefix + text; +} + +[Cloneable] +public sealed partial class BlockedConfig +{ + public HashSet Commands { get; set; } + public HashSet Modules { get; set; } + + public BlockedConfig() + { + Modules = []; + Commands = []; + } +} + +[Cloneable] +public partial class ColorConfig +{ + [Comment("""Color used for embed responses when command successfully executes""")] + public Rgba32 Ok { get; set; } + + [Comment("""Color used for embed responses when command has an error""")] + public Rgba32 Error { get; set; } + + [Comment("""Color used for embed responses while command is doing work or is in progress""")] + public Rgba32 Pending { get; set; } + + public ColorConfig() + { + Ok = Rgba32.ParseHex("00e584"); + Error = Rgba32.ParseHex("ee281f"); + Pending = Rgba32.ParseHex("faa61a"); + } +} + +public enum ConsoleOutputType +{ + Normal = 0, + Simple = 1, + None = 2 +} \ No newline at end of file diff --git a/src/EllieBot/_common/Configs/IConfigSeria.cs b/src/EllieBot/_common/Configs/IConfigSeria.cs new file mode 100644 index 0000000..1f96850 --- /dev/null +++ b/src/EllieBot/_common/Configs/IConfigSeria.cs @@ -0,0 +1,18 @@ +namespace EllieBot.Common.Configs; + +/// +/// Base interface for available config serializers +/// +public interface IConfigSeria +{ + /// + /// Serialize the object to string + /// + public string Serialize(T obj) + where T : notnull; + + /// + /// Deserialize string data into an object of the specified type + /// + public T Deserialize(string data); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Creds.cs b/src/EllieBot/_common/Creds.cs new file mode 100644 index 0000000..f6aef5d --- /dev/null +++ b/src/EllieBot/_common/Creds.cs @@ -0,0 +1,272 @@ +#nullable disable +using EllieBot.Common.Yml; + +namespace Ellie.Common; + +public sealed class Creds : IBotCredentials +{ + [Comment("""DO NOT CHANGE""")] + public int Version { get; set; } + + [Comment("""Bot token. Do not share with anyone ever -> https://discordapp.com/developers/applications/""")] + public string Token { get; set; } + + [Comment(""" + List of Ids of the users who have bot owner permissions + **DO NOT ADD PEOPLE YOU DON'T TRUST** + """)] + public ICollection OwnerIds { get; set; } + + [Comment("Keep this on 'true' unless you're sure your bot shouldn't use privileged intents or you're waiting to be accepted")] + public bool UsePrivilegedIntents { get; set; } + + [Comment(""" + The number of shards that the bot will be running on. + Leave at 1 if you don't know what you're doing. + + note: If you are planning to have more than one shard, then you must change botCache to 'redis'. + Also, in that case you should be using EllieBot.Coordinator to start the bot, and it will correctly override this value. + """)] + public int TotalShards { get; set; } + + [Comment( + """ + Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it. + Then, go to APIs and Services -> Credentials and click Create credentials -> API key. + Used only for Youtube Data Api (at the moment). + """)] + public string GoogleApiKey { get; set; } + + [Comment( + """ + Create a new custom search here https://programmablesearchengine.google.com/cse/create/new + Enable SafeSearch + Remove all Sites to Search + Enable Search the entire web + Copy the 'Search Engine ID' to the SearchId field + + Do all steps again but enable image search for the ImageSearchId + """)] + public GoogleApiConfig Google { get; set; } + + [Comment("""Settings for voting system for discordbots. Meant for use on global Ellie.""")] + public VotesSettings Votes { get; set; } + + [Comment(""" + Patreon auto reward system settings. + go to https://www.patreon.com/portal -> my clients -> create client + """)] + public PatreonSettings Patreon { get; set; } + + [Comment("""Api key for sending stats to DiscordBotList.""")] + public string BotListToken { get; set; } + + [Comment("""Official cleverbot api key.""")] + public string CleverbotApiKey { get; set; } + + [Comment(@"Official GPT-3 api key.")] + public string Gpt3ApiKey { get; set; } + + [Comment(""" + Which cache implementation should bot use. + 'memory' - Cache will be in memory of the bot's process itself. Only use this on bots with a single shard. When the bot is restarted the cache is reset. + 'redis' - Uses redis (which needs to be separately downloaded and installed). The cache will persist through bot restarts. You can configure connection string in creds.yml + """)] + public BotCacheImplemenation BotCache { get; set; } + + [Comment(""" + Redis connection string. Don't change if you don't know what you're doing. + Only used if botCache is set to 'redis' + """)] + public string RedisOptions { get; set; } + + [Comment("""Database options. Don't change if you don't know what you're doing. Leave null for default values""")] + public DbOptions Db { get; set; } + + [Comment(""" + Address and port of the coordinator endpoint. Leave empty for default. + Change only if you've changed the coordinator address or port. + """)] + public string CoordinatorUrl { get; set; } + + [Comment( + """Api key obtained on https://rapidapi.com (go to MyApps -> Add New App -> Enter Name -> Application key)""")] + public string RapidApiKey { get; set; } + + [Comment(""" + https://locationiq.com api key (register and you will receive the token in the email). + Used only for .time command. + """)] + public string LocationIqApiKey { get; set; } + + [Comment(""" + https://timezonedb.com api key (register and you will receive the token in the email). + Used only for .time command + """)] + public string TimezoneDbApiKey { get; set; } + + [Comment(""" + https://pro.coinmarketcap.com/account/ api key. There is a free plan for personal use. + Used for cryptocurrency related commands. + """)] + public string CoinmarketcapApiKey { get; set; } + + // [Comment(@"https://polygon.io/dashboard/api-keys api key. Free plan allows for 5 queries per minute. + // Used for stocks related commands.")] + // public string PolygonIoApiKey { get; set; } + + [Comment("""Api key used for Osu related commands. Obtain this key at https://osu.ppy.sh/p/api""")] + public string OsuApiKey { get; set; } + + [Comment(""" + Optional Trovo client id. + You should use this if Trovo stream notifications stopped working or you're getting ratelimit errors. + """)] + public string TrovoClientId { get; set; } + + [Comment("""Obtain by creating an application at https://dev.twitch.tv/console/apps""")] + public string TwitchClientId { get; set; } + + [Comment("""Obtain by creating an application at https://dev.twitch.tv/console/apps""")] + public string TwitchClientSecret { get; set; } + + [Comment(""" + Command and args which will be used to restart the bot. + Only used if bot is executed directly (NOT through the coordinator) + placeholders: + {0} -> shard id + {1} -> total shards + Linux default + cmd: dotnet + args: "EllieBot.dll -- {0}" + Windows default + cmd: EllieBot.exe + args: "{0}" + """)] + public RestartConfig RestartCommand { get; set; } + + public Creds() + { + Version = 7; + Token = string.Empty; + UsePrivilegedIntents = true; + OwnerIds = new List(); + TotalShards = 1; + GoogleApiKey = string.Empty; + Votes = new VotesSettings(string.Empty, string.Empty, string.Empty, string.Empty); + Patreon = new PatreonSettings(string.Empty, string.Empty, string.Empty, string.Empty); + BotListToken = string.Empty; + CleverbotApiKey = string.Empty; + Gpt3ApiKey = string.Empty; + BotCache = BotCacheImplemenation.Memory; + RedisOptions = "localhost:6379,syncTimeout=30000,responseTimeout=30000,allowAdmin=true,password="; + Db = new DbOptions() + { + Type = "sqlite", + ConnectionString = "Data Source=data/EllieBot.db" + }; + + CoordinatorUrl = "http://localhost:3442"; + + RestartCommand = new RestartConfig(); + Google = new GoogleApiConfig(); + } + + public class DbOptions + : IDbOptions + { + [Comment(""" + Database type. "sqlite", "mysql" and "postgresql" are supported. + Default is "sqlite" + """)] + public string Type { get; set; } + + [Comment(""" + Database connection string. + You MUST change this if you're not using "sqlite" type. + Default is "Data Source=data/EllieBot.db" + Example for mysql: "Server=localhost;Port=3306;Uid=root;Pwd=my_super_secret_mysql_password;Database=ellie" + Example for postgresql: "Server=localhost;Port=5432;User Id=postgres;Password=my_super_secret_postgres_password;Database=ellie;" + """)] + public string ConnectionString { get; set; } + } + + public sealed record PatreonSettings : IPatreonSettings + { + public string ClientId { get; set; } + public string AccessToken { get; set; } + public string RefreshToken { get; set; } + public string ClientSecret { get; set; } + + [Comment( + """Campaign ID of your patreon page. Go to your patreon page (make sure you're logged in) and type "prompt('Campaign ID', window.patreon.bootstrap.creator.data.id);" in the console. (ctrl + shift + i)""")] + public string CampaignId { get; set; } + + public PatreonSettings( + string accessToken, + string refreshToken, + string clientSecret, + string campaignId) + { + AccessToken = accessToken; + RefreshToken = refreshToken; + ClientSecret = clientSecret; + CampaignId = campaignId; + } + + public PatreonSettings() + { + } + } + + public sealed record VotesSettings : IVotesSettings + { + [Comment(""" + top.gg votes service url + This is the url of your instance of the EllieBot.Votes api + Example: https://votes.my.cool.bot.com + """)] + public string TopggServiceUrl { get; set; } + + [Comment(""" + Authorization header value sent to the TopGG service url with each request + This should be equivalent to the TopggKey in your EllieBot.Votes api appsettings.json file + """)] + public string TopggKey { get; set; } + + [Comment(""" + discords.com votes service url + This is the url of your instance of the EllieBot.Votes api + Example: https://votes.my.cool.bot.com + """)] + public string DiscordsServiceUrl { get; set; } + + [Comment(""" + Authorization header value sent to the Discords service url with each request + This should be equivalent to the DiscordsKey in your EllieBot.Votes api appsettings.json file + """)] + public string DiscordsKey { get; set; } + + public VotesSettings() + { + } + + public VotesSettings( + string topggServiceUrl, + string topggKey, + string discordsServiceUrl, + string discordsKey) + { + TopggServiceUrl = topggServiceUrl; + TopggKey = topggKey; + DiscordsServiceUrl = discordsServiceUrl; + DiscordsKey = discordsKey; + } + } +} + +public class GoogleApiConfig : IGoogleApiConfig +{ + public string SearchId { get; init; } + public string ImageSearchId { get; init; } +} diff --git a/src/EllieBot/_common/Currency/CurrencyType.cs b/src/EllieBot/_common/Currency/CurrencyType.cs new file mode 100644 index 0000000..1037fa4 --- /dev/null +++ b/src/EllieBot/_common/Currency/CurrencyType.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Services.Currency; + +public enum CurrencyType +{ + Default +} \ No newline at end of file diff --git a/src/EllieBot/_common/Currency/IBankService.cs b/src/EllieBot/_common/Currency/IBankService.cs new file mode 100644 index 0000000..f563fb9 --- /dev/null +++ b/src/EllieBot/_common/Currency/IBankService.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Modules.Gambling.Bank; + +public interface IBankService +{ + Task DepositAsync(ulong userId, long amount); + Task WithdrawAsync(ulong userId, long amount); + Task GetBalanceAsync(ulong userId); + Task AwardAsync(ulong userId, long amount); + Task TakeAsync(ulong userId, long amount); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Currency/ICurrencyService.cs b/src/EllieBot/_common/Currency/ICurrencyService.cs new file mode 100644 index 0000000..35e8273 --- /dev/null +++ b/src/EllieBot/_common/Currency/ICurrencyService.cs @@ -0,0 +1,43 @@ +using EllieBot.Db.Models; +using EllieBot.Services.Currency; + +namespace EllieBot.Services; + +public interface ICurrencyService +{ + Task GetWalletAsync(ulong userId, CurrencyType type = CurrencyType.Default); + + Task AddBulkAsync( + IReadOnlyCollection userIds, + long amount, + TxData? txData, + CurrencyType type = CurrencyType.Default); + + Task RemoveBulkAsync( + IReadOnlyCollection userIds, + long amount, + TxData? txData, + CurrencyType type = CurrencyType.Default); + + Task AddAsync( + ulong userId, + long amount, + TxData? txData); + + Task AddAsync( + IUser user, + long amount, + TxData? txData); + + Task RemoveAsync( + ulong userId, + long amount, + TxData? txData); + + Task RemoveAsync( + IUser user, + long amount, + TxData? txData); + + Task> GetTopRichest(ulong ignoreId, int page = 0, int perPage = 9); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Currency/ITxTracker.cs b/src/EllieBot/_common/Currency/ITxTracker.cs new file mode 100644 index 0000000..d7cad66 --- /dev/null +++ b/src/EllieBot/_common/Currency/ITxTracker.cs @@ -0,0 +1,9 @@ +using EllieBot.Services.Currency; + +namespace EllieBot.Services; + +public interface ITxTracker +{ + Task TrackAdd(long amount, TxData? txData); + Task TrackRemove(long amount, TxData? txData); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Currency/IWallet.cs b/src/EllieBot/_common/Currency/IWallet.cs new file mode 100644 index 0000000..39018e9 --- /dev/null +++ b/src/EllieBot/_common/Currency/IWallet.cs @@ -0,0 +1,40 @@ +namespace EllieBot.Services.Currency; + +public interface IWallet +{ + public ulong UserId { get; } + + public Task GetBalance(); + public Task Take(long amount, TxData? txData); + public Task Add(long amount, TxData? txData); + + public async Task Transfer( + long amount, + IWallet to, + TxData? txData) + { + if (amount <= 0) + throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0."); + + if (txData is not null) + txData = txData with + { + OtherId = to.UserId + }; + + var succ = await Take(amount, txData); + + if (!succ) + return false; + + if (txData is not null) + txData = txData with + { + OtherId = UserId + }; + + await to.Add(amount, txData); + + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Currency/TxData.cs b/src/EllieBot/_common/Currency/TxData.cs new file mode 100644 index 0000000..06dbab2 --- /dev/null +++ b/src/EllieBot/_common/Currency/TxData.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Services.Currency; + +public record class TxData( + string Type, + string Extra, + string? Note = "", + ulong? OtherId = null); \ No newline at end of file diff --git a/src/EllieBot/_common/DbService.cs b/src/EllieBot/_common/DbService.cs new file mode 100644 index 0000000..cdff91f --- /dev/null +++ b/src/EllieBot/_common/DbService.cs @@ -0,0 +1,15 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Services; + +public abstract class DbService +{ + /// + /// Call this to apply all migrations + /// + public abstract Task SetupAsync(); + + public abstract DbContext CreateRawDbContext(string dbType, string connString); + public abstract DbContext GetDbContext(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/Deck.cs b/src/EllieBot/_common/Deck/Deck.cs new file mode 100644 index 0000000..3398d3c --- /dev/null +++ b/src/EllieBot/_common/Deck/Deck.cs @@ -0,0 +1,309 @@ +#nullable disable +namespace Ellie.Econ; + +public class Deck +{ + public enum CardSuit + { + Spades = 1, + Hearts = 2, + Diamonds = 3, + Clubs = 4 + } + + private static readonly Dictionary _cardNames = new() + { + { 1, "Ace" }, + { 2, "Two" }, + { 3, "Three" }, + { 4, "Four" }, + { 5, "Five" }, + { 6, "Six" }, + { 7, "Seven" }, + { 8, "Eight" }, + { 9, "Nine" }, + { 10, "Ten" }, + { 11, "Jack" }, + { 12, "Queen" }, + { 13, "King" } + }; + + private static Dictionary, bool>> handValues; + + public List CardPool { get; set; } + private readonly Random _r = new EllieRandom(); + + static Deck() + => InitHandValues(); + + /// + /// Creates a new instance of the BlackJackGame, this allows you to create multiple games running at one time. + /// + public Deck() + => RefillPool(); + + /// + /// Restart the game of blackjack. It will only refill the pool for now. Probably wont be used, unless you want to have + /// only 1 bjg running at one time, + /// then you will restart the same game every time. + /// + public void Restart() + => RefillPool(); + + /// + /// Removes all cards from the pool and refills the pool with all of the possible cards. NOTE: I think this is too + /// expensive. + /// We should probably make it so it copies another premade list with all the cards, or something. + /// + protected virtual void RefillPool() + { + CardPool = new(52); + //foreach suit + for (var j = 1; j < 14; j++) + // and number + for (var i = 1; i < 5; i++) + //generate a card of that suit and number and add it to the pool + + // the pool will go from ace of spades,hears,diamonds,clubs all the way to the king of spades. hearts, ... + CardPool.Add(new((CardSuit)i, j)); + } + + /// + /// Take a card from the pool, you either take it from the top if the deck is shuffled, or from a random place if the + /// deck is in the default order. + /// + /// A card from the pool + public Card Draw() + { + if (CardPool.Count == 0) + Restart(); + //you can either do this if your deck is not shuffled + + var num = _r.Next(0, CardPool.Count); + var c = CardPool[num]; + CardPool.RemoveAt(num); + return c; + + // if you want to shuffle when you fill, then take the first one + /* + Card c = cardPool[0]; + cardPool.RemoveAt(0); + return c; + */ + } + + /// + /// Shuffles the deck. Use this if you want to take cards from the top of the deck, instead of randomly. See DrawACard + /// method. + /// + private void Shuffle() + { + if (CardPool.Count <= 1) + return; + var orderedPool = CardPool.Shuffle(); + CardPool ??= orderedPool.ToList(); + } + + public override string ToString() + => string.Concat(CardPool.Select(c => c.ToString())) + Environment.NewLine; + + private static void InitHandValues() + { + bool HasPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 1; + } + + bool IsPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 3) == 0 && HasPair(cards); + } + + bool IsTwoPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 2; + } + + bool IsStraight(List cards) + { + if (cards.GroupBy(card => card.Number).Count() != cards.Count()) + return false; + var toReturn = cards.Max(card => card.Number) - cards.Min(card => card.Number) == 4; + if (toReturn || cards.All(c => c.Number != 1)) + return toReturn; + + var newCards = cards.Select(c => c.Number == 1 ? new(c.Suit, 14) : c).ToArray(); + return newCards.Max(card => card.Number) - newCards.Min(card => card.Number) == 4; + } + + bool HasThreeOfKind(List cards) + { + return cards.GroupBy(card => card.Number).Any(group => group.Count() == 3); + } + + bool IsThreeOfKind(List cards) + { + return HasThreeOfKind(cards) && !HasPair(cards); + } + + bool IsFlush(List cards) + { + return cards.GroupBy(card => card.Suit).Count() == 1; + } + + bool IsFourOfKind(List cards) + { + return cards.GroupBy(card => card.Number).Any(group => group.Count() == 4); + } + + bool IsFullHouse(List cards) + { + return HasPair(cards) && HasThreeOfKind(cards); + } + + bool HasStraightFlush(List cards) + { + return IsFlush(cards) && IsStraight(cards); + } + + bool IsRoyalFlush(List cards) + { + return cards.Min(card => card.Number) == 1 + && cards.Max(card => card.Number) == 13 + && HasStraightFlush(cards); + } + + bool IsStraightFlush(List cards) + { + return HasStraightFlush(cards) && !IsRoyalFlush(cards); + } + + handValues = new() + { + { "Royal Flush", IsRoyalFlush }, + { "Straight Flush", IsStraightFlush }, + { "Four Of A Kind", IsFourOfKind }, + { "Full House", IsFullHouse }, + { "Flush", IsFlush }, + { "Straight", IsStraight }, + { "Three Of A Kind", IsThreeOfKind }, + { "Two Pairs", IsTwoPair }, + { "A Pair", IsPair } + }; + } + + public static string GetHandValue(List cards) + { + if (handValues is null) + InitHandValues(); + + foreach (var kvp in handValues.Where(x => x.Value(cards))) + return kvp.Key; + return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetValueText() ?? cards.Max().GetValueText()); + } + + public class Card : IComparable + { + private static readonly IReadOnlyDictionary _suitToSuitChar = new Dictionary + { + { CardSuit.Diamonds, "♦" }, + { CardSuit.Clubs, "♣" }, + { CardSuit.Spades, "♠" }, + { CardSuit.Hearts, "♥" } + }; + + private static readonly IReadOnlyDictionary _suitCharToSuit = new Dictionary + { + { "♦", CardSuit.Diamonds }, + { "d", CardSuit.Diamonds }, + { "♣", CardSuit.Clubs }, + { "c", CardSuit.Clubs }, + { "♠", CardSuit.Spades }, + { "s", CardSuit.Spades }, + { "♥", CardSuit.Hearts }, + { "h", CardSuit.Hearts } + }; + + private static readonly IReadOnlyDictionary _numberCharToNumber = new Dictionary + { + { 'a', 1 }, + { '2', 2 }, + { '3', 3 }, + { '4', 4 }, + { '5', 5 }, + { '6', 6 }, + { '7', 7 }, + { '8', 8 }, + { '9', 9 }, + { 't', 10 }, + { 'j', 11 }, + { 'q', 12 }, + { 'k', 13 } + }; + + public CardSuit Suit { get; } + public int Number { get; } + + public string FullName + { + get + { + var str = string.Empty; + + if (Number is <= 10 and > 1) + str += "_" + Number; + else + str += GetValueText().ToLowerInvariant(); + return str + "_of_" + Suit.ToString().ToLowerInvariant(); + } + } + + private readonly string[] _regIndicators = + [ + "🇦", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":keycap_ten:", + "🇯", "🇶", "🇰" + ]; + + public Card(CardSuit s, int cardNum) + { + Suit = s; + Number = cardNum; + } + + public string GetValueText() + => _cardNames[Number]; + + public override string ToString() + => _cardNames[Number] + " Of " + Suit; + + public int CompareTo(object obj) + { + if (obj is not Card card) + return 0; + return Number - card.Number; + } + + public static Card Parse(string input) + { + if (string.IsNullOrWhiteSpace(input)) + throw new ArgumentNullException(nameof(input)); + + if (input.Length != 2 + || !_numberCharToNumber.TryGetValue(input[0], out var n) + || !_suitCharToSuit.TryGetValue(input[1].ToString(), out var s)) + throw new ArgumentException("Invalid input", nameof(input)); + + return new(s, n); + } + + public string GetEmojiString() + { + var str = string.Empty; + + str += _regIndicators[Number - 1]; + str += _suitToSuitChar[Suit]; + + return str; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/NewCard.cs b/src/EllieBot/_common/Deck/NewCard.cs new file mode 100644 index 0000000..4a091a4 --- /dev/null +++ b/src/EllieBot/_common/Deck/NewCard.cs @@ -0,0 +1,5 @@ +namespace Ellie.Econ; + +public abstract record class NewCard(TSuit Suit, TValue Value) + where TSuit : struct, Enum + where TValue : struct, Enum; \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/NewDeck.cs b/src/EllieBot/_common/Deck/NewDeck.cs new file mode 100644 index 0000000..a71406c --- /dev/null +++ b/src/EllieBot/_common/Deck/NewDeck.cs @@ -0,0 +1,54 @@ +namespace Ellie.Econ; + +public abstract class NewDeck + where TCard: NewCard + where TSuit : struct, Enum + where TValue : struct, Enum +{ + protected static readonly TSuit[] _suits = Enum.GetValues(); + protected static readonly TValue[] _values = Enum.GetValues(); + + public virtual int CurrentCount + => _cards.Count; + + public virtual int TotalCount { get; } + + protected readonly LinkedList _cards = new(); + public NewDeck() + { + TotalCount = _suits.Length * _values.Length; + } + + public virtual TCard? Draw() + { + var first = _cards.First; + if (first is not null) + { + _cards.RemoveFirst(); + return first.Value; + } + + return null; + } + + public virtual TCard? Peek(int x = 0) + { + var card = _cards.First; + for (var i = 0; i < x; i++) + { + card = card?.Next; + } + + return card?.Value; + } + + public virtual void Shuffle() + { + var cards = _cards.ToList(); + var newCards = cards.Shuffle(); + + _cards.Clear(); + foreach (var card in newCards) + _cards.AddFirst(card); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs b/src/EllieBot/_common/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs new file mode 100644 index 0000000..2a7e7df --- /dev/null +++ b/src/EllieBot/_common/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs @@ -0,0 +1,28 @@ +namespace Ellie.Econ; + +public class MultipleRegularDeck : NewDeck +{ + private int Decks { get; } + + public override int TotalCount { get; } + + public MultipleRegularDeck(int decks = 1) + { + if (decks < 1) + throw new ArgumentOutOfRangeException(nameof(decks), "Has to be more than 0"); + + Decks = decks; + TotalCount = base.TotalCount * decks; + + for (var i = 0; i < Decks; i++) + { + foreach (var suit in _suits) + { + foreach (var val in _values) + { + _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); + } + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/Regular/RegularCard.cs b/src/EllieBot/_common/Deck/Regular/RegularCard.cs new file mode 100644 index 0000000..337a1ff --- /dev/null +++ b/src/EllieBot/_common/Deck/Regular/RegularCard.cs @@ -0,0 +1,4 @@ +namespace Ellie.Econ; + +public sealed record class RegularCard(RegularSuit Suit, RegularValue Value) + : NewCard(Suit, Value); \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/Regular/RegularDeck.cs b/src/EllieBot/_common/Deck/Regular/RegularDeck.cs new file mode 100644 index 0000000..6997623 --- /dev/null +++ b/src/EllieBot/_common/Deck/Regular/RegularDeck.cs @@ -0,0 +1,15 @@ +namespace Ellie.Econ; + +public sealed class RegularDeck : NewDeck +{ + public RegularDeck() + { + foreach (var suit in _suits) + { + foreach (var val in _values) + { + _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/Regular/RegularDeckExtensions.cs b/src/EllieBot/_common/Deck/Regular/RegularDeckExtensions.cs new file mode 100644 index 0000000..98c880c --- /dev/null +++ b/src/EllieBot/_common/Deck/Regular/RegularDeckExtensions.cs @@ -0,0 +1,56 @@ +namespace Ellie.Econ; + +public static class RegularDeckExtensions +{ + public static string GetEmoji(this RegularSuit suit) + => suit switch + { + RegularSuit.Hearts => "♥️", + RegularSuit.Spades => "♠️", + RegularSuit.Diamonds => "♦️", + _ => "♣️", + }; + + public static string GetEmoji(this RegularValue value) + => value switch + { + RegularValue.Ace => "🇦", + RegularValue.Two => "2️⃣", + RegularValue.Three => "3️⃣", + RegularValue.Four => "4️⃣", + RegularValue.Five => "5️⃣", + RegularValue.Six => "6️⃣", + RegularValue.Seven => "7️⃣", + RegularValue.Eight => "8️⃣", + RegularValue.Nine => "9️⃣", + RegularValue.Ten => "🔟", + RegularValue.Jack => "🇯", + RegularValue.Queen => "🇶", + _ => "🇰", + }; + + public static string GetEmoji(this RegularCard card) + => $"{card.Value.GetEmoji()} {card.Suit.GetEmoji()}"; + + public static string GetName(this RegularValue value) + => value.ToString(); + + public static string GetName(this RegularSuit suit) + => suit.ToString(); + + public static string GetName(this RegularCard card) + => $"{card.Value.ToString()} of {card.Suit.GetName()}"; +} + + + + + + + + + + + + + diff --git a/src/EllieBot/_common/Deck/Regular/RegularSuit.cs b/src/EllieBot/_common/Deck/Regular/RegularSuit.cs new file mode 100644 index 0000000..dc4167b --- /dev/null +++ b/src/EllieBot/_common/Deck/Regular/RegularSuit.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ; + +public enum RegularSuit +{ + Hearts, + Diamonds, + Clubs, + Spades +} \ No newline at end of file diff --git a/src/EllieBot/_common/Deck/Regular/RegularValue.cs b/src/EllieBot/_common/Deck/Regular/RegularValue.cs new file mode 100644 index 0000000..8aa9171 --- /dev/null +++ b/src/EllieBot/_common/Deck/Regular/RegularValue.cs @@ -0,0 +1,18 @@ +namespace Ellie.Econ; + +public enum RegularValue +{ + Ace = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, + Eight = 8, + Nine = 9, + Ten = 10, + Jack = 12, + Queen = 13, + King = 14, +} \ No newline at end of file diff --git a/src/EllieBot/_common/DoAsUserMessage.cs b/src/EllieBot/_common/DoAsUserMessage.cs new file mode 100644 index 0000000..f8fba27 --- /dev/null +++ b/src/EllieBot/_common/DoAsUserMessage.cs @@ -0,0 +1,154 @@ +using MessageType = Discord.MessageType; + +namespace EllieBot.Modules.Administration; + +public sealed class DoAsUserMessage : IUserMessage +{ + private readonly string _message; + private IUserMessage _msg; + private readonly IUser _user; + + public DoAsUserMessage(SocketUserMessage msg, IUser user, string message) + { + _msg = msg; + _user = user; + _message = message; + } + + public ulong Id => _msg.Id; + + public DateTimeOffset CreatedAt => _msg.CreatedAt; + + public Task DeleteAsync(RequestOptions? options = null) + { + return _msg.DeleteAsync(options); + } + + public Task AddReactionAsync(IEmote emote, RequestOptions? options = null) + { + return _msg.AddReactionAsync(emote, options); + } + + public Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions? options = null) + { + return _msg.RemoveReactionAsync(emote, user, options); + } + + public Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions? options = null) + { + return _msg.RemoveReactionAsync(emote, userId, options); + } + + public Task RemoveAllReactionsAsync(RequestOptions? options = null) + { + return _msg.RemoveAllReactionsAsync(options); + } + + public Task RemoveAllReactionsForEmoteAsync(IEmote emote, RequestOptions? options = null) + { + return _msg.RemoveAllReactionsForEmoteAsync(emote, options); + } + + public IAsyncEnumerable> GetReactionUsersAsync( + IEmote emoji, + int limit, + RequestOptions? options = null, + ReactionType type = ReactionType.Normal) + => _msg.GetReactionUsersAsync(emoji, limit, options, type); + + public IAsyncEnumerable> GetReactionUsersAsync(IEmote emoji, int limit, + RequestOptions? options = null) + { + return _msg.GetReactionUsersAsync(emoji, limit, options); + } + + public MessageType Type => _msg.Type; + + public MessageSource Source => _msg.Source; + + public bool IsTTS => _msg.IsTTS; + + public bool IsPinned => _msg.IsPinned; + + public bool IsSuppressed => _msg.IsSuppressed; + + public bool MentionedEveryone => _msg.MentionedEveryone; + + public string Content => _message; + + public string CleanContent => _msg.CleanContent; + + public DateTimeOffset Timestamp => _msg.Timestamp; + + public DateTimeOffset? EditedTimestamp => _msg.EditedTimestamp; + + public IMessageChannel Channel => _msg.Channel; + + public IUser Author => _user; + + public IThreadChannel Thread => _msg.Thread; + + public IReadOnlyCollection Attachments => _msg.Attachments; + + public IReadOnlyCollection Embeds => _msg.Embeds; + + public IReadOnlyCollection Tags => _msg.Tags; + + public IReadOnlyCollection MentionedChannelIds => _msg.MentionedChannelIds; + + public IReadOnlyCollection MentionedRoleIds => _msg.MentionedRoleIds; + + public IReadOnlyCollection MentionedUserIds => _msg.MentionedUserIds; + + public MessageActivity Activity => _msg.Activity; + + public MessageApplication Application => _msg.Application; + + public MessageReference Reference => _msg.Reference; + + public IReadOnlyDictionary Reactions => _msg.Reactions; + + public IReadOnlyCollection Components => _msg.Components; + + public IReadOnlyCollection Stickers => _msg.Stickers; + + public MessageFlags? Flags => _msg.Flags; + + [Obsolete("Obsolete in favor of InteractionMetadata")] + public IMessageInteraction Interaction => _msg.Interaction; + public MessageRoleSubscriptionData RoleSubscriptionData => _msg.RoleSubscriptionData; + + public Task ModifyAsync(Action func, RequestOptions? options = null) + { + return _msg.ModifyAsync(func, options); + } + + public Task PinAsync(RequestOptions? options = null) + { + return _msg.PinAsync(options); + } + + public Task UnpinAsync(RequestOptions? options = null) + { + return _msg.UnpinAsync(options); + } + + public Task CrosspostAsync(RequestOptions? options = null) + { + return _msg.CrosspostAsync(options); + } + + public string Resolve(TagHandling userHandling = TagHandling.Name, TagHandling channelHandling = TagHandling.Name, + TagHandling roleHandling = TagHandling.Name, + TagHandling everyoneHandling = TagHandling.Ignore, TagHandling emojiHandling = TagHandling.Name) + { + return _msg.Resolve(userHandling, channelHandling, roleHandling, everyoneHandling, emojiHandling); + } + + public MessageResolvedData ResolvedData => _msg.ResolvedData; + + public IUserMessage ReferencedMessage => _msg.ReferencedMessage; + + public IMessageInteractionMetadata InteractionMetadata + => _msg.InteractionMetadata; +} \ No newline at end of file diff --git a/src/EllieBot/_common/DownloadTracker.cs b/src/EllieBot/_common/DownloadTracker.cs new file mode 100644 index 0000000..51d7cc6 --- /dev/null +++ b/src/EllieBot/_common/DownloadTracker.cs @@ -0,0 +1,38 @@ +#nullable disable +namespace EllieBot.Common; + +public class DownloadTracker : IEService +{ + private ConcurrentDictionary LastDownloads { get; } = new(); + private readonly SemaphoreSlim _downloadUsersSemaphore = new(1, 1); + + /// + /// Ensures all users on the specified guild were downloaded within the last hour. + /// + /// Guild to check and potentially download users from + /// Task representing download state + public async Task EnsureUsersDownloadedAsync(IGuild guild) + { +#if GLOBAL_ELLIE + return; +#endif + await _downloadUsersSemaphore.WaitAsync(); + try + { + var now = DateTime.UtcNow; + + // download once per hour at most + var added = LastDownloads.AddOrUpdate(guild.Id, + now, + (_, old) => now - old > TimeSpan.FromHours(1) ? now : old); + + // means that this entry was just added - download the users + if (added == now) + await guild.DownloadUsersAsync(); + } + finally + { + _downloadUsersSemaphore.Release(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/EllieModule.cs b/src/EllieBot/_common/EllieModule.cs new file mode 100644 index 0000000..ba52708 --- /dev/null +++ b/src/EllieBot/_common/EllieModule.cs @@ -0,0 +1,108 @@ +#nullable disable +using System.Globalization; + +// ReSharper disable InconsistentNaming + +namespace EllieBot.Common; + +[UsedImplicitly(ImplicitUseTargetFlags.Default + | ImplicitUseTargetFlags.WithInheritors + | ImplicitUseTargetFlags.WithMembers)] +public abstract class EllieModule : ModuleBase +{ + protected CultureInfo Culture { get; set; } + + // Injected by Discord.net + public IBotStrings Strings { get; set; } + public ICommandHandler _cmdHandler { get; set; } + public ILocalization _localization { get; set; } + public IEllieInteractionService _inter { get; set; } + public IReplacementService repSvc { get; set; } + public IMessageSenderService _sender { get; set; } + public BotConfigService _bcs { get; set; } + + protected string prefix + => _cmdHandler.GetPrefix(ctx.Guild); + + protected ICommandContext ctx + => Context; + + public ResponseBuilder Response() + => new ResponseBuilder(Strings, _bcs, (DiscordSocketClient)ctx.Client) + .Context(ctx); + + protected override void BeforeExecute(CommandInfo command) + => Culture = _localization.GetCultureInfo(ctx.Guild?.Id); + + protected string GetText(in LocStr data) + => Strings.GetText(data, Culture); + + // localized normal + public async Task PromptUserConfirmAsync(EmbedBuilder embed) + { + embed.WithPendingColor() + .WithFooter("yes/no"); + + var msg = await Response().Embed(embed).SendAsync(); + try + { + var input = await GetUserInputAsync(ctx.User.Id, ctx.Channel.Id); + input = input?.ToUpperInvariant(); + + if (input != "YES" && input != "Y") + return false; + + return true; + } + finally + { + _ = Task.Run(() => msg.DeleteAsync()); + } + } + + // TypeConverter typeConverter = TypeDescriptor.GetConverter(propType); ? + public async Task GetUserInputAsync(ulong userId, ulong channelId, Func validate = null) + { + var userInputTask = new TaskCompletionSource(); + var dsc = (DiscordSocketClient)ctx.Client; + try + { + dsc.MessageReceived += MessageReceived; + + if (await Task.WhenAny(userInputTask.Task, Task.Delay(10000)) != userInputTask.Task) + return null; + + return await userInputTask.Task; + } + finally + { + dsc.MessageReceived -= MessageReceived; + } + + Task MessageReceived(SocketMessage arg) + { + _ = Task.Run(() => + { + if (arg is not SocketUserMessage userMsg + || userMsg.Channel is not ITextChannel + || userMsg.Author.Id != userId + || userMsg.Channel.Id != channelId) + return Task.CompletedTask; + + if (validate is not null && !validate(arg.Content)) + return Task.CompletedTask; + + if (userInputTask.TrySetResult(arg.Content)) + userMsg.DeleteAfter(1); + + return Task.CompletedTask; + }); + return Task.CompletedTask; + } + } +} + +public abstract class EllieModule : EllieModule +{ + public TService _service { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/EllieTypeReader.cs b/src/EllieBot/_common/EllieTypeReader.cs new file mode 100644 index 0000000..bab013e --- /dev/null +++ b/src/EllieBot/_common/EllieTypeReader.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +[MeansImplicitUse(ImplicitUseTargetFlags.Default | ImplicitUseTargetFlags.WithInheritors)] +public abstract class EllieTypeReader : TypeReader +{ + public abstract ValueTask> ReadAsync(ICommandContext ctx, string input); + + public override async Task ReadAsync( + ICommandContext ctx, + string input, + IServiceProvider services) + => await ReadAsync(ctx, input); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betdraw/BetdrawColorGuess.cs b/src/EllieBot/_common/Gambling/Betdraw/BetdrawColorGuess.cs new file mode 100644 index 0000000..8b95530 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betdraw/BetdrawColorGuess.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Gambling.Betdraw; + +public enum BetdrawColorGuess +{ + Red, + Black +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betdraw/BetdrawGame.cs b/src/EllieBot/_common/Gambling/Betdraw/BetdrawGame.cs new file mode 100644 index 0000000..5ebcb6c --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betdraw/BetdrawGame.cs @@ -0,0 +1,86 @@ +using Ellie.Econ; + +namespace EllieBot.Modules.Gambling.Betdraw; + +public sealed class BetdrawGame +{ + private static readonly EllieRandom _rng = new(); + private readonly RegularDeck _deck; + + private const decimal SINGLE_GUESS_MULTI = 2.075M; + private const decimal DOUBLE_GUESS_MULTI = 4.15M; + + public BetdrawGame() + { + _deck = new RegularDeck(); + } + + public BetdrawResult Draw(BetdrawValueGuess? val, BetdrawColorGuess? col, decimal amount) + { + if (val is null && col is null) + throw new ArgumentNullException(nameof(val)); + + var card = _deck.Peek(_rng.Next(0, 52))!; + + var realVal = (int)card.Value < 7 + ? BetdrawValueGuess.Low + : BetdrawValueGuess.High; + + var realCol = card.Suit is RegularSuit.Diamonds or RegularSuit.Hearts + ? BetdrawColorGuess.Red + : BetdrawColorGuess.Black; + + // if card is 7, autoloss + if (card.Value == RegularValue.Seven) + { + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card, + }; + } + + byte win = 0; + if (val is BetdrawValueGuess valGuess) + { + if (realVal != valGuess) + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card + }; + + ++win; + } + + if (col is BetdrawColorGuess colGuess) + { + if (realCol != colGuess) + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card + }; + + ++win; + } + + var multi = win == 1 + ? SINGLE_GUESS_MULTI + : DOUBLE_GUESS_MULTI; + + return new() + { + Won = amount * multi, + Multiplier = multi, + ResultType = BetdrawResultType.Win, + Card = card + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betdraw/BetdrawResult.cs b/src/EllieBot/_common/Gambling/Betdraw/BetdrawResult.cs new file mode 100644 index 0000000..a491985 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betdraw/BetdrawResult.cs @@ -0,0 +1,11 @@ +using Ellie.Econ; + +namespace EllieBot.Modules.Gambling.Betdraw; + +public readonly struct BetdrawResult +{ + public decimal Won { get; init; } + public decimal Multiplier { get; init; } + public BetdrawResultType ResultType { get; init; } + public RegularCard Card { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betdraw/BetdrawResultType.cs b/src/EllieBot/_common/Gambling/Betdraw/BetdrawResultType.cs new file mode 100644 index 0000000..cc7ab51 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betdraw/BetdrawResultType.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Gambling.Betdraw; + +public enum BetdrawResultType +{ + Win, + Lose +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betdraw/BetdrawValueGuess.cs b/src/EllieBot/_common/Gambling/Betdraw/BetdrawValueGuess.cs new file mode 100644 index 0000000..204cc46 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betdraw/BetdrawValueGuess.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Gambling.Betdraw; + +public enum BetdrawValueGuess +{ + High, + Low, +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betflip/BetflipGame.cs b/src/EllieBot/_common/Gambling/Betflip/BetflipGame.cs new file mode 100644 index 0000000..f704025 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betflip/BetflipGame.cs @@ -0,0 +1,33 @@ +namespace EllieBot.Modules.Gambling; + +public sealed class BetflipGame +{ + private readonly decimal _winMulti; + private static readonly EllieRandom _rng = new EllieRandom(); + + public BetflipGame(decimal winMulti) + { + _winMulti = winMulti; + } + + public BetflipResult Flip(byte guess, decimal amount) + { + var side = (byte)_rng.Next(0, 2); + if (side == guess) + { + return new BetflipResult() + { + Side = side, + Won = amount * _winMulti, + Multiplier = _winMulti + }; + } + + return new BetflipResult() + { + Side = side, + Won = 0, + Multiplier = 0, + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betflip/BetflipResult.cs b/src/EllieBot/_common/Gambling/Betflip/BetflipResult.cs new file mode 100644 index 0000000..e87f2f8 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betflip/BetflipResult.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Gambling; + +public readonly struct BetflipResult +{ + public decimal Won { get; init; } + public byte Side { get; init; } + public decimal Multiplier { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betroll/BetrollGame.cs b/src/EllieBot/_common/Gambling/Betroll/BetrollGame.cs new file mode 100644 index 0000000..7937538 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betroll/BetrollGame.cs @@ -0,0 +1,42 @@ +namespace EllieBot.Modules.Gambling; + +public sealed class BetrollGame +{ + private readonly (int WhenAbove, decimal MultiplyBy)[] _thresholdPairs; + private readonly EllieRandom _rng; + + public BetrollGame(IReadOnlyList<(int WhenAbove, decimal MultiplyBy)> pairs) + { + _thresholdPairs = pairs.OrderByDescending(x => x.WhenAbove).ToArray(); + _rng = new(); + } + + public BetrollResult Roll(decimal amount = 0) + { + var roll = _rng.Next(1, 101); + + for (var i = 0; i < _thresholdPairs.Length; i++) + { + ref var pair = ref _thresholdPairs[i]; + + if (pair.WhenAbove < roll) + { + return new() + { + Multiplier = pair.MultiplyBy, + Roll = roll, + Threshold = pair.WhenAbove, + Won = amount * pair.MultiplyBy + }; + } + } + + return new() + { + Multiplier = 0, + Roll = roll, + Threshold = -1, + Won = 0, + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Betroll/BetrollResult.cs b/src/EllieBot/_common/Gambling/Betroll/BetrollResult.cs new file mode 100644 index 0000000..b107f36 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Betroll/BetrollResult.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Gambling; + +public readonly struct BetrollResult +{ + public int Roll { get; init; } + public decimal Multiplier { get; init; } + public decimal Threshold { get; init; } + public decimal Won { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Rps/RpsGame.cs b/src/EllieBot/_common/Gambling/Rps/RpsGame.cs new file mode 100644 index 0000000..976a67a --- /dev/null +++ b/src/EllieBot/_common/Gambling/Rps/RpsGame.cs @@ -0,0 +1,75 @@ +namespace EllieBot.Modules.Gambling.Rps; + +public sealed class RpsGame +{ + private static readonly EllieRandom _rng = new EllieRandom(); + + private const decimal WIN_MULTI = 1.95m; + private const decimal DRAW_MULTI = 1m; + private const decimal LOSE_MULTI = 0m; + + public RpsGame() + { + + } + + public RpsResult Play(RpsPick pick, decimal amount) + { + var compPick = (RpsPick)_rng.Next(0, 3); + if (compPick == pick) + { + return new() + { + Won = amount * DRAW_MULTI, + Multiplier = DRAW_MULTI, + ComputerPick = compPick, + Result = RpsResultType.Draw, + }; + } + + if ((compPick == RpsPick.Paper && pick == RpsPick.Rock) + || (compPick == RpsPick.Rock && pick == RpsPick.Scissors) + || (compPick == RpsPick.Scissors && pick == RpsPick.Paper)) + { + return new() + { + Won = amount * LOSE_MULTI, + Multiplier = LOSE_MULTI, + Result = RpsResultType.Lose, + ComputerPick = compPick, + }; + } + + return new() + { + Won = amount * WIN_MULTI, + Multiplier = WIN_MULTI, + Result = RpsResultType.Win, + ComputerPick = compPick, + }; + } +} + +public enum RpsPick : byte +{ + Rock = 0, + Paper = 1, + Scissors = 2, +} + +public enum RpsResultType : byte +{ + Win, + Draw, + Lose +} + + + +public readonly struct RpsResult +{ + public decimal Won { get; init; } + public decimal Multiplier { get; init; } + public RpsResultType Result { get; init; } + public RpsPick ComputerPick { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Slot/SlotGame.cs b/src/EllieBot/_common/Gambling/Slot/SlotGame.cs new file mode 100644 index 0000000..83e92eb --- /dev/null +++ b/src/EllieBot/_common/Gambling/Slot/SlotGame.cs @@ -0,0 +1,116 @@ +namespace EllieBot.Modules.Gambling; + +//here is a payout chart +//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg +//thanks to judge for helping me with this +public class SlotGame +{ + private static readonly EllieRandom _rng = new EllieRandom(); + + public SlotResult Spin(decimal bet) + { + var rolls = new[] + { + (byte)_rng.Next(0, 6), + (byte)_rng.Next(0, 6), + (byte)_rng.Next(0, 6) + }; + + ref var a = ref rolls[0]; + ref var b = ref rolls[1]; + ref var c = ref rolls[2]; + + var multi = 0; + var winType = SlotWinType.None; + if (a == b && b == c) + { + if (a == 5) + { + winType = SlotWinType.TrippleJoker; + multi = 30; + } + else + { + winType = SlotWinType.TrippleNormal; + multi = 10; + } + } + else if (a == 5 && (b == 5 || c == 5) + || (b == 5 && c == 5)) + { + winType = SlotWinType.DoubleJoker; + multi = 4; + } + else if (a == 5 || b == 5 || c == 5) + { + winType = SlotWinType.SingleJoker; + multi = 1; + } + + return new() + { + Won = bet * multi, + WinType = winType, + Multiplier = multi, + Rolls = rolls, + }; + } +} + +public enum SlotWinType : byte +{ + None, + SingleJoker, + DoubleJoker, + TrippleNormal, + TrippleJoker, +} + +/* +var rolls = new[] + { + _rng.Next(default(byte), 6), + _rng.Next(default(byte), 6), + _rng.Next(default(byte), 6) + }; + + var multi = 0; + var winType = SlotWinType.None; + + ref var a = ref rolls[0]; + ref var b = ref rolls[1]; + ref var c = ref rolls[2]; + if (a == b && b == c) + { + if (a == 5) + { + winType = SlotWinType.TrippleJoker; + multi = 30; + } + else + { + winType = SlotWinType.TrippleNormal; + multi = 10; + } + } + else if (a == 5 && (b == 5 || c == 5) + || (b == 5 && c == 5)) + { + winType = SlotWinType.DoubleJoker; + multi = 4; + } + else if (rolls.Any(x => x == 5)) + { + winType = SlotWinType.SingleJoker; + multi = 1; + } + + return new() + { + Won = bet * multi, + WinType = winType, + Multiplier = multi, + Rolls = rolls, + }; + } +*/ \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Slot/SlotResult.cs b/src/EllieBot/_common/Gambling/Slot/SlotResult.cs new file mode 100644 index 0000000..d88a706 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Slot/SlotResult.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Gambling; + +public readonly struct SlotResult +{ + public decimal Multiplier { get; init; } + public byte[] Rolls { get; init; } + public decimal Won { get; init; } + public SlotWinType WinType { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Wof/LuLaResult.cs b/src/EllieBot/_common/Gambling/Wof/LuLaResult.cs new file mode 100644 index 0000000..cec8cca --- /dev/null +++ b/src/EllieBot/_common/Gambling/Wof/LuLaResult.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Gambling; + +public readonly struct LuLaResult +{ + public int Index { get; init; } + public decimal Multiplier { get; init; } + public decimal Won { get; init; } + public IReadOnlyList Multipliers { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Gambling/Wof/WofGame.cs b/src/EllieBot/_common/Gambling/Wof/WofGame.cs new file mode 100644 index 0000000..0922271 --- /dev/null +++ b/src/EllieBot/_common/Gambling/Wof/WofGame.cs @@ -0,0 +1,34 @@ +namespace EllieBot.Modules.Gambling; + +public sealed class LulaGame +{ + private static readonly IReadOnlyList DEFAULT_MULTIPLIERS = new[] { 1.7M, 1.5M, 0.2M, 0.1M, 0.3M, 0.5M, 1.2M, 2.4M }; + + private readonly IReadOnlyList _multipliers; + private static readonly EllieRandom _rng = new(); + + public LulaGame(IReadOnlyList multipliers) + { + _multipliers = multipliers; + } + + public LulaGame() : this(DEFAULT_MULTIPLIERS) + { + } + + public LuLaResult Spin(long bet) + { + var result = _rng.Next(0, _multipliers.Count); + + var multi = _multipliers[result]; + var amount = bet * multi; + + return new() + { + Index = result, + Multiplier = multi, + Won = amount, + Multipliers = _multipliers.ToArray(), + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Helpers.cs b/src/EllieBot/_common/Helpers.cs new file mode 100644 index 0000000..a7d458f --- /dev/null +++ b/src/EllieBot/_common/Helpers.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Common; + +public static class Helpers +{ + public static void ReadErrorAndExit(int exitCode) + { + if (!Console.IsInputRedirected) + Console.ReadKey(); + + Environment.Exit(exitCode); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/IBot.cs b/src/EllieBot/_common/IBot.cs new file mode 100644 index 0000000..c6c5a06 --- /dev/null +++ b/src/EllieBot/_common/IBot.cs @@ -0,0 +1,12 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot; + +public interface IBot +{ + IReadOnlyList GetCurrentGuildIds(); + event Func JoinedGuild; + IReadOnlyCollection AllGuildConfigs { get; } + bool IsReady { get; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/ICloneable.cs b/src/EllieBot/_common/ICloneable.cs new file mode 100644 index 0000000..c8d3fa8 --- /dev/null +++ b/src/EllieBot/_common/ICloneable.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Common; + +public interface ICloneable + where T : new() +{ + public T Clone(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ICurrencyProvider.cs b/src/EllieBot/_common/ICurrencyProvider.cs new file mode 100644 index 0000000..0cca0ae --- /dev/null +++ b/src/EllieBot/_common/ICurrencyProvider.cs @@ -0,0 +1,29 @@ +using System.Globalization; +using System.Numerics; + +namespace EllieBot.Common; + +public interface ICurrencyProvider +{ + string GetCurrencySign(); +} + +public static class CurrencyHelper +{ + public static string N(T cur, IFormatProvider format) + where T : INumber + => cur.ToString("C0", format); + + public static string N(T cur, CultureInfo culture, string currencySign) + where T : INumber + => N(cur, GetCurrencyFormat(culture, currencySign)); + + private static IFormatProvider GetCurrencyFormat(CultureInfo culture, string currencySign) + { + var flowersCurrencyCulture = (CultureInfo)culture.Clone(); + flowersCurrencyCulture.NumberFormat.CurrencySymbol = currencySign; + flowersCurrencyCulture.NumberFormat.CurrencyNegativePattern = 5; + + return flowersCurrencyCulture; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/IDiscordPermOverrideService.cs b/src/EllieBot/_common/IDiscordPermOverrideService.cs new file mode 100644 index 0000000..b8471c3 --- /dev/null +++ b/src/EllieBot/_common/IDiscordPermOverrideService.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace Ellie.Common; + +public interface IDiscordPermOverrideService +{ + bool TryGetOverrides(ulong guildId, string commandName, out EllieBot.Db.GuildPerm? perm); +} \ No newline at end of file diff --git a/src/EllieBot/_common/IEllieCommandOptions.cs b/src/EllieBot/_common/IEllieCommandOptions.cs new file mode 100644 index 0000000..bb758b5 --- /dev/null +++ b/src/EllieBot/_common/IEllieCommandOptions.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace EllieBot.Common; + +public interface IEllieCommandOptions +{ + void NormalizeOptions(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ILogCommandService.cs b/src/EllieBot/_common/ILogCommandService.cs new file mode 100644 index 0000000..344be96 --- /dev/null +++ b/src/EllieBot/_common/ILogCommandService.cs @@ -0,0 +1,34 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Common; + +public interface ILogCommandService +{ + void AddDeleteIgnore(ulong xId); + Task LogServer(ulong guildId, ulong channelId, bool actionValue); + bool LogIgnore(ulong guildId, ulong itemId, IgnoredItemType itemType); + LogSetting? GetGuildLogSettings(ulong guildId); + bool Log(ulong guildId, ulong? channelId, LogType type); +} + +public enum LogType +{ + Other, + MessageUpdated, + MessageDeleted, + UserJoined, + UserLeft, + UserBanned, + UserUnbanned, + UserUpdated, + ChannelCreated, + ChannelDestroyed, + ChannelUpdated, + UserPresence, + VoicePresence, + UserMuted, + UserWarned, + + ThreadDeleted, + ThreadCreated +} \ No newline at end of file diff --git a/src/EllieBot/_common/IPermissionChecker.cs b/src/EllieBot/_common/IPermissionChecker.cs new file mode 100644 index 0000000..81aaa64 --- /dev/null +++ b/src/EllieBot/_common/IPermissionChecker.cs @@ -0,0 +1,37 @@ +using OneOf; + +namespace EllieBot.Common; + +public interface IPermissionChecker +{ + Task CheckPermsAsync(IGuild guild, + IMessageChannel channel, + IUser author, + string module, + string? cmd); +} + +[GenerateOneOf] +public partial class PermCheckResult + : OneOfBase +{ + public bool IsAllowed + => IsT0; + + public bool IsCooldown + => IsT1; + + public bool IsGlobalBlock + => IsT2; + + public bool IsDisallowed + => IsT3; +} + +public readonly record struct PermAllowed; + +public readonly record struct PermCooldown; + +public readonly record struct PermGlobalBlock; + +public readonly record struct PermDisallowed(int PermIndex, string PermText, bool IsVerbose); \ No newline at end of file diff --git a/src/EllieBot/_common/IPlaceholderProvider.cs b/src/EllieBot/_common/IPlaceholderProvider.cs new file mode 100644 index 0000000..1766577 --- /dev/null +++ b/src/EllieBot/_common/IPlaceholderProvider.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace EllieBot.Common; + +public interface IPlaceholderProvider +{ + public IEnumerable<(string Name, Func Func)> GetPlaceholders(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ImageUrls.cs b/src/EllieBot/_common/ImageUrls.cs new file mode 100644 index 0000000..7274e60 --- /dev/null +++ b/src/EllieBot/_common/ImageUrls.cs @@ -0,0 +1,51 @@ +#nullable disable +using EllieBot.Common.Yml; +using Cloneable; + +namespace EllieBot.Common; + +[Cloneable] +public partial class ImageUrls : ICloneable +{ + [Comment("DO NOT CHANGE")] + public int Version { get; set; } = 3; + + public CoinData Coins { get; set; } + public Uri[] Currency { get; set; } + public Uri[] Dice { get; set; } + public RategirlData Rategirl { get; set; } + public XpData Xp { get; set; } + + //new + public RipData Rip { get; set; } + public SlotData Slots { get; set; } + + public class RipData + { + public Uri Bg { get; set; } + public Uri Overlay { get; set; } + } + + public class SlotData + { + public Uri[] Emojis { get; set; } + public Uri Bg { get; set; } + } + + public class CoinData + { + public Uri[] Heads { get; set; } + public Uri[] Tails { get; set; } + } + + public class RategirlData + { + public Uri Matrix { get; set; } + public Uri Dot { get; set; } + } + + public class XpData + { + public Uri Bg { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/EllieInteraction.cs b/src/EllieBot/_common/Interaction/EllieInteraction.cs new file mode 100644 index 0000000..89e2103 --- /dev/null +++ b/src/EllieBot/_common/Interaction/EllieInteraction.cs @@ -0,0 +1,164 @@ +namespace EllieBot; + +public abstract class EllieInteractionBase +{ + private readonly ulong _authorId; + private readonly Func _onAction; + private readonly bool _onlyAuthor; + public DiscordSocketClient Client { get; } + + private readonly TaskCompletionSource _interactionCompletedSource; + + private IUserMessage message = null!; + private readonly string _customId; + private readonly bool _singleUse; + + public EllieInteractionBase( + DiscordSocketClient client, + ulong authorId, + string customId, + Func onAction, + bool onlyAuthor, + bool singleUse = true) + { + _authorId = authorId; + _customId = customId; + _onAction = onAction; + _onlyAuthor = onlyAuthor; + _singleUse = singleUse; + _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + + Client = client; + } + + public async Task RunAsync(IUserMessage msg) + { + message = msg; + + Client.InteractionCreated += OnInteraction; + if (_singleUse) + await Task.WhenAny(Task.Delay(30_000), _interactionCompletedSource.Task); + else + await Task.Delay(30_000); + Client.InteractionCreated -= OnInteraction; + + await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); + } + + private Task OnInteraction(SocketInteraction arg) + { + if (arg is not SocketMessageComponent smc) + return Task.CompletedTask; + + if (smc.Message.Id != message.Id) + return Task.CompletedTask; + + if (_onlyAuthor && smc.User.Id != _authorId) + return Task.CompletedTask; + + if (smc.Data.CustomId != _customId) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + try + { + _interactionCompletedSource.TrySetResult(true); + await ExecuteOnActionAsync(smc); + + if (!smc.HasResponded) + { + await smc.DeferAsync(); + } + } + catch (Exception ex) + { + Log.Warning(ex, "An exception occured while handling an interaction: {Message}", ex.Message); + } + }); + + return Task.CompletedTask; + } + + + public abstract void AddTo(ComponentBuilder cb); + + public Task ExecuteOnActionAsync(SocketMessageComponent smc) + => _onAction(smc); +} + +public sealed class EllieModalSubmitHandler +{ + private readonly ulong _authorId; + private readonly Func _onAction; + private readonly bool _onlyAuthor; + public DiscordSocketClient Client { get; } + + private readonly TaskCompletionSource _interactionCompletedSource; + + private IUserMessage message = null!; + private readonly string _customId; + + public EllieModalSubmitHandler( + DiscordSocketClient client, + ulong authorId, + string customId, + Func onAction, + bool onlyAuthor) + { + _authorId = authorId; + _customId = customId; + _onAction = onAction; + _onlyAuthor = onlyAuthor; + _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + + Client = client; + } + + public async Task RunAsync(IUserMessage msg) + { + message = msg; + + Client.ModalSubmitted += OnInteraction; + await Task.WhenAny(Task.Delay(300_000), _interactionCompletedSource.Task); + Client.ModalSubmitted -= OnInteraction; + + await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); + } + + private Task OnInteraction(SocketModal sm) + { + if (sm.Message.Id != message.Id) + return Task.CompletedTask; + + if (_onlyAuthor && sm.User.Id != _authorId) + return Task.CompletedTask; + + if (sm.Data.CustomId != _customId) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + try + { + _interactionCompletedSource.TrySetResult(true); + await ExecuteOnActionAsync(sm); + + if (!sm.HasResponded) + { + await sm.DeferAsync(); + } + } + catch (Exception ex) + { + Log.Warning(ex, "An exception occured while handling a: {Message}", ex.Message); + } + }); + + return Task.CompletedTask; + } + + + public Task ExecuteOnActionAsync(SocketModal smd) + => _onAction(smd); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/EllieInteractionService.cs b/src/EllieBot/_common/Interaction/EllieInteractionService.cs new file mode 100644 index 0000000..115c417 --- /dev/null +++ b/src/EllieBot/_common/Interaction/EllieInteractionService.cs @@ -0,0 +1,77 @@ +namespace EllieBot; + +public class EllieInteractionService : IEllieInteractionService, IEService +{ + private readonly DiscordSocketClient _client; + + public EllieInteractionService(DiscordSocketClient client) + { + _client = client; + } + + public EllieInteractionBase Create( + ulong userId, + ButtonBuilder button, + Func onTrigger, + bool singleUse = true) + => new EllieButtonInteractionHandler(_client, + userId, + button, + onTrigger, + onlyAuthor: true, + singleUse: singleUse); + + public EllieInteractionBase Create( + ulong userId, + ButtonBuilder button, + Func onTrigger, + in T state, + bool singleUse = true) + => Create(userId, + button, + ((Func>)((data) + => smc => onTrigger(smc, data)))(state), + singleUse); + + public EllieInteractionBase Create( + ulong userId, + SelectMenuBuilder menu, + Func onTrigger, + bool singleUse = true) + => new EllieButtonSelectInteractionHandler(_client, + userId, + menu, + onTrigger, + onlyAuthor: true, + singleUse: singleUse); + + + /// + /// Create an interaction which opens a modal + /// + /// Id of the author + /// Button builder for the button that will open the modal + /// Modal + /// The function that will be called when the modal is submitted + /// Whether the button is single use + /// + public EllieInteractionBase Create( + ulong userId, + ButtonBuilder button, + ModalBuilder modal, + Func onTrigger, + bool singleUse = true) + => Create(userId, + button, + async (smc) => + { + await smc.RespondWithModalAsync(modal.Build()); + var modalHandler = new EllieModalSubmitHandler(_client, + userId, + modal.CustomId, + onTrigger, + true); + await modalHandler.RunAsync(smc.Message); + }, + singleUse: singleUse); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/IEllieInteractionService.cs b/src/EllieBot/_common/Interaction/IEllieInteractionService.cs new file mode 100644 index 0000000..967e91d --- /dev/null +++ b/src/EllieBot/_common/Interaction/IEllieInteractionService.cs @@ -0,0 +1,30 @@ +namespace EllieBot; + +public interface IEllieInteractionService +{ + public EllieInteractionBase Create( + ulong userId, + ButtonBuilder button, + Func onTrigger, + bool singleUse = true); + + public EllieInteractionBase Create( + ulong userId, + ButtonBuilder button, + Func onTrigger, + in T state, + bool singleUse = true); + + EllieInteractionBase Create( + ulong userId, + SelectMenuBuilder menu, + Func onTrigger, + bool singleUse = true); + + EllieInteractionBase Create( + ulong userId, + ButtonBuilder button, + ModalBuilder modal, + Func onTrigger, + bool singleUse = true); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/InteractionHelpers.cs b/src/EllieBot/_common/Interaction/InteractionHelpers.cs new file mode 100644 index 0000000..0bac67f --- /dev/null +++ b/src/EllieBot/_common/Interaction/InteractionHelpers.cs @@ -0,0 +1,7 @@ +namespace EllieBot; + +public static class InteractionHelpers +{ + public static readonly IEmote ArrowLeft = Emote.Parse("<:x:1232256519844790302>"); + public static readonly IEmote ArrowRight = Emote.Parse("<:x:1232256515298295838>"); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs b/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs new file mode 100644 index 0000000..3e65c1c --- /dev/null +++ b/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs @@ -0,0 +1,21 @@ +namespace EllieBot; + +public sealed class EllieButtonInteractionHandler : EllieInteractionBase +{ + public EllieButtonInteractionHandler( + DiscordSocketClient client, + ulong authorId, + ButtonBuilder button, + Func onAction, + bool onlyAuthor, + bool singleUse = true) + : base(client, authorId, button.CustomId, onAction, onlyAuthor, singleUse) + { + Button = button; + } + + public ButtonBuilder Button { get; } + + public override void AddTo(ComponentBuilder cb) + => cb.WithButton(Button); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/Models/EllieInteractionExtensions.cs b/src/EllieBot/_common/Interaction/Models/EllieInteractionExtensions.cs new file mode 100644 index 0000000..cf54f9e --- /dev/null +++ b/src/EllieBot/_common/Interaction/Models/EllieInteractionExtensions.cs @@ -0,0 +1,15 @@ +namespace EllieBot; + +public static class EllieInteractionExtensions +{ + public static MessageComponent CreateComponent( + this EllieInteractionBase ellieInteractionBase + ) + { + var cb = new ComponentBuilder(); + + ellieInteractionBase.AddTo(cb); + + return cb.Build(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Interaction/Models/EllieSelectInteraction.cs b/src/EllieBot/_common/Interaction/Models/EllieSelectInteraction.cs new file mode 100644 index 0000000..7100f01 --- /dev/null +++ b/src/EllieBot/_common/Interaction/Models/EllieSelectInteraction.cs @@ -0,0 +1,21 @@ +namespace EllieBot; + +public sealed class EllieButtonSelectInteractionHandler : EllieInteractionBase +{ + public EllieButtonSelectInteractionHandler( + DiscordSocketClient client, + ulong authorId, + SelectMenuBuilder menu, + Func onAction, + bool onlyAuthor, + bool singleUse = true) + : base(client, authorId, menu.CustomId, onAction, onlyAuthor, singleUse) + { + Menu = menu; + } + + public SelectMenuBuilder Menu { get; } + + public override void AddTo(ComponentBuilder cb) + => cb.WithSelectMenu(Menu); +} \ No newline at end of file diff --git a/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs b/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs new file mode 100644 index 0000000..28167d6 --- /dev/null +++ b/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs @@ -0,0 +1,14 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Common.JsonConverters; + +public class CultureInfoConverter : JsonConverter +{ + public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => new(reader.GetString() ?? "en_US"); + + public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) + => writer.WriteStringValue(value.Name); +} \ No newline at end of file diff --git a/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs b/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs new file mode 100644 index 0000000..ef619a6 --- /dev/null +++ b/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs @@ -0,0 +1,14 @@ +using SixLabors.ImageSharp.PixelFormats; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Common.JsonConverters; + +public class Rgba32Converter : JsonConverter +{ + public override Rgba32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => Rgba32.ParseHex(reader.GetString()); + + public override void Write(Utf8JsonWriter writer, Rgba32 value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToHex()); +} \ No newline at end of file diff --git a/src/EllieBot/_common/LbOpts.cs b/src/EllieBot/_common/LbOpts.cs new file mode 100644 index 0000000..5df4986 --- /dev/null +++ b/src/EllieBot/_common/LbOpts.cs @@ -0,0 +1,14 @@ +#nullable disable +using CommandLine; + +namespace EllieBot.Common; + +public class LbOpts : IEllieCommandOptions +{ + [Option('c', "clean", Default = false, HelpText = "Only show users who are on the server.")] + public bool Clean { get; set; } + + public void NormalizeOptions() + { + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Linq2DbExpressions.cs b/src/EllieBot/_common/Linq2DbExpressions.cs new file mode 100644 index 0000000..a724652 --- /dev/null +++ b/src/EllieBot/_common/Linq2DbExpressions.cs @@ -0,0 +1,16 @@ +#nullable disable +using LinqToDB; +using System.Linq.Expressions; + +namespace EllieBot.Common; + +public static class Linq2DbExpressions +{ + [ExpressionMethod(nameof(GuildOnShardExpression))] + public static bool GuildOnShard(ulong guildId, int totalShards, int shardId) + => throw new NotSupportedException(); + + private static Expression> GuildOnShardExpression() + => (guildId, totalShards, shardId) + => guildId / 4194304 % (ulong)totalShards == (ulong)shardId; +} \ No newline at end of file diff --git a/src/EllieBot/_common/LoginErrorHandler.cs b/src/EllieBot/_common/LoginErrorHandler.cs new file mode 100644 index 0000000..bbdc9ce --- /dev/null +++ b/src/EllieBot/_common/LoginErrorHandler.cs @@ -0,0 +1,52 @@ +#nullable disable +using System.Net; +using System.Runtime.CompilerServices; + +namespace EllieBot.Common; + +public class LoginErrorHandler +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Handle(Exception ex) + => Log.Fatal(ex, "A fatal error has occurred while attempting to connect to Discord"); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Handle(HttpException ex) + { + switch (ex.HttpCode) + { + case HttpStatusCode.Unauthorized: + Log.Error("Your bot token is wrong.\n" + + "You can find the bot token under the Bot tab in the developer page.\n" + + "Fix your token in the credentials file and restart the bot"); + break; + + case HttpStatusCode.BadRequest: + Log.Error("Something has been incorrectly formatted in your credentials file.\n" + + "Use the JSON Guide as reference to fix it and restart the bot"); + Log.Error("If you are on Linux, make sure Redis is installed and running"); + break; + + case HttpStatusCode.RequestTimeout: + Log.Error("The request timed out. Make sure you have no external program blocking the bot " + + "from connecting to the internet"); + break; + + case HttpStatusCode.ServiceUnavailable: + case HttpStatusCode.InternalServerError: + Log.Error("Discord is having internal issues. Please, try again later"); + break; + + case HttpStatusCode.TooManyRequests: + Log.Error("Your bot has been ratelimited by Discord. Please, try again later.\n" + + "Global ratelimits usually last for an hour"); + break; + + default: + Log.Warning("An error occurred while attempting to connect to Discord"); + break; + } + + Log.Fatal(ex, "Fatal error occurred while loading credentials"); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Adapters/BehaviorAdapter.cs b/src/EllieBot/_common/Marmalade/Common/Adapters/BehaviorAdapter.cs new file mode 100644 index 0000000..d76137f --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Adapters/BehaviorAdapter.cs @@ -0,0 +1,78 @@ +using EllieBot.Marmalade; + +[DIIgnore] +public sealed class BehaviorAdapter : ICustomBehavior +{ + private readonly WeakReference _canaryWr; + private readonly IMarmaladeStrings _strings; + private readonly IServiceProvider _services; + private readonly string _name; + + public string Name => _name; + + // unused + public int Priority + => 0; + + public BehaviorAdapter(WeakReference canaryWr, IMarmaladeStrings strings, IServiceProvider services) + { + _canaryWr = canaryWr; + _strings = strings; + _services = services; + + _name = canaryWr.TryGetTarget(out var canary) + ? $"canary/{canary.GetType().Name}" + : "unknown"; + } + + public async Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return false; + + return await canary.ExecPreCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), + moduleName, + command.Name); + } + + public async Task ExecOnMessageAsync(IGuild? guild, IUserMessage msg) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return false; + + return await canary.ExecOnMessageAsync(guild, msg); + } + + public async Task TransformInput( + IGuild guild, + IMessageChannel channel, + IUser user, + string input) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return null; + + return await canary.ExecInputTransformAsync(guild, channel, user, input); + } + + public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return; + + await canary.ExecOnNoCommandAsync(guild, msg); + } + + public async ValueTask ExecPostCommandAsync(ICommandContext context, string moduleName, string commandName) + { + if (!_canaryWr.TryGetTarget(out var canary)) + return; + + await canary.ExecPostCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), + moduleName, + commandName); + } + + public override string ToString() + => _name; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Adapters/ContextAdapterFactory.cs b/src/EllieBot/_common/Marmalade/Common/Adapters/ContextAdapterFactory.cs new file mode 100644 index 0000000..38c1ad9 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Adapters/ContextAdapterFactory.cs @@ -0,0 +1,9 @@ +using EllieBot.Marmalade; + +internal class ContextAdapterFactory +{ + public static AnyContext CreateNew(ICommandContext context, IMarmaladeStrings strings, IServiceProvider services) + => context.Guild is null + ? new DmContextAdapter(context, strings, services) + : new GuildContextAdapter(context, strings, services); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Adapters/DmContextAdapter.cs b/src/EllieBot/_common/Marmalade/Common/Adapters/DmContextAdapter.cs new file mode 100644 index 0000000..1f2d1cf --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Adapters/DmContextAdapter.cs @@ -0,0 +1,47 @@ +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Marmalade; + +public sealed class DmContextAdapter : DmContext +{ + public override IMarmaladeStrings Strings { get; } + public override IDMChannel Channel { get; } + public override IUserMessage Message { get; } + public override ISelfUser Bot { get; } + public override IUser User + => Message.Author; + + + private readonly IServiceProvider _services; + private readonly Lazy _botStrings; + private readonly Lazy _localization; + + public DmContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) + { + if (ctx is not { Channel: IDMChannel ch }) + { + throw new ArgumentException("Can't use non-dm context to create DmContextAdapter", nameof(ctx)); + } + + Strings = strings; + + _services = services; + + Channel = ch; + Message = ctx.Message; + Bot = ctx.Client.CurrentUser; + + + _botStrings = new(_services.GetRequiredService); + _localization = new(_services.GetRequiredService()); + } + + public override string GetText(string key, object[]? args = null) + { + var cultureInfo = _localization.Value.GetCultureInfo(default(ulong?)); + var output = Strings.GetText(key, cultureInfo, args ?? Array.Empty()); + if (!string.IsNullOrWhiteSpace(output)) + return output; + + return _botStrings.Value.GetText(key, cultureInfo, args); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Adapters/FilterAdapter.cs b/src/EllieBot/_common/Marmalade/Common/Adapters/FilterAdapter.cs new file mode 100644 index 0000000..a23ceec --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Adapters/FilterAdapter.cs @@ -0,0 +1,33 @@ +using EllieBot.Marmalade; + +namespace Ellie.Marmalade.Adapters; + +public class FilterAdapter : PreconditionAttribute +{ + private readonly FilterAttribute _filterAttribute; + private readonly IMarmaladeStrings _strings; + + public FilterAdapter(FilterAttribute filterAttribute, + IMarmaladeStrings strings) + { + _filterAttribute = filterAttribute; + _strings = strings; + } + + public override async Task CheckPermissionsAsync( + ICommandContext context, + CommandInfo command, + IServiceProvider services) + { + var medusaContext = ContextAdapterFactory.CreateNew(context, + _strings, + services); + + var result = await _filterAttribute.CheckAsync(medusaContext); + + if (!result) + return PreconditionResult.FromError($"Precondition '{_filterAttribute.GetType().Name}' failed."); + + return PreconditionResult.FromSuccess(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Adapters/GuildContextAdapter.cs b/src/EllieBot/_common/Marmalade/Common/Adapters/GuildContextAdapter.cs new file mode 100644 index 0000000..8b0c294 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Adapters/GuildContextAdapter.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Marmalade; + +public sealed class GuildContextAdapter : GuildContext +{ + private readonly IServiceProvider _services; + private readonly ICommandContext _ctx; + private readonly Lazy _botStrings; + private readonly Lazy _localization; + + public override IMarmaladeStrings Strings { get; } + public override IGuild Guild { get; } + public override ITextChannel Channel { get; } + public override ISelfUser Bot { get; } + public override IUserMessage Message + => _ctx.Message; + + public override IGuildUser User { get; } + + public GuildContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) + { + if (ctx.Guild is not IGuild guild || ctx.Channel is not ITextChannel channel) + { + throw new ArgumentException("Can't use non-guild context to create GuildContextAdapter", nameof(ctx)); + } + + Strings = strings; + User = (IGuildUser)ctx.User; + Bot = ctx.Client.CurrentUser; + + _services = services; + _botStrings = new(_services.GetRequiredService); + _localization = new(_services.GetRequiredService()); + + (_ctx, Guild, Channel) = (ctx, guild, channel); + } + + public override string GetText(string key, object[]? args = null) + { + args ??= Array.Empty(); + + var cultureInfo = _localization.Value.GetCultureInfo(_ctx.Guild.Id); + var output = Strings.GetText(key, cultureInfo, args); + if (!string.IsNullOrWhiteSpace(output)) + return output; + + return _botStrings.Value.GetText(key, cultureInfo, args); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Adapters/ParamParserAdapter.cs b/src/EllieBot/_common/Marmalade/Common/Adapters/ParamParserAdapter.cs new file mode 100644 index 0000000..707abbb --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Adapters/ParamParserAdapter.cs @@ -0,0 +1,34 @@ +using EllieBot.Marmalade; + +public sealed class ParamParserAdapter : TypeReader +{ + private readonly ParamParser _parser; + private readonly IMarmaladeStrings _strings; + private readonly IServiceProvider _services; + + public ParamParserAdapter(ParamParser parser, + IMarmaladeStrings strings, + IServiceProvider services) + { + _parser = parser; + _strings = strings; + _services = services; + } + + public override async Task ReadAsync( + ICommandContext context, + string input, + IServiceProvider services) + { + var marmaladeContext = ContextAdapterFactory.CreateNew(context, + _strings, + _services); + + var result = await _parser.TryParseAsync(marmaladeContext, input); + + if(result.IsSuccess) + return Discord.Commands.TypeReaderResult.FromSuccess(result.Data); + + return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, "Invalid input"); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/CommandContextType.cs b/src/EllieBot/_common/Marmalade/Common/CommandContextType.cs new file mode 100644 index 0000000..c517510 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/CommandContextType.cs @@ -0,0 +1,27 @@ +namespace EllieBot.Marmalade; + +/// +/// Enum specifying in which context the command can be executed +/// +public enum CommandContextType +{ + /// + /// Command can only be executed in a guild + /// + Guild, + + /// + /// Command can only be executed in DMs + /// + Dm, + + /// + /// Command can be executed anywhere + /// + Any, + + /// + /// Command can be executed anywhere, and it doesn't require context to be passed to it + /// + Unspecified +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Config/IMarmaladeConfigService.cs b/src/EllieBot/_common/Marmalade/Common/Config/IMarmaladeConfigService.cs new file mode 100644 index 0000000..5cb14fc --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Config/IMarmaladeConfigService.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Marmalade; + +public interface IMarmaladeConfigService +{ + IReadOnlyCollection GetLoadedMarmalades(); + void AddLoadedMarmalade(string name); + void RemoveLoadedMarmalade(string name); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfig.cs b/src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfig.cs new file mode 100644 index 0000000..c14e893 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfig.cs @@ -0,0 +1,20 @@ +#nullable enable +using Cloneable; +using EllieBot.Common.Yml; + +namespace EllieBot.Marmalade; + +[Cloneable] +public sealed partial class MarmaladeConfig : ICloneable +{ + [Comment("""DO NOT CHANGE""")] + public int Version { get; set; } = 1; + + [Comment("""List of marmalades automatically loaded at startup""")] + public List? Loaded { get; set; } + + public MarmaladeConfig() + { + Loaded = new(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfigService.cs b/src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfigService.cs new file mode 100644 index 0000000..43f3a26 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Config/MarmaladeConfigService.cs @@ -0,0 +1,45 @@ +using EllieBot.Common.Configs; + +namespace EllieBot.Marmalade; + +public sealed class MarmaladeConfigService : ConfigServiceBase, IMarmaladeConfigService +{ + private const string FILE_PATH = "data/marmalades/marmalade.yml"; + private static readonly TypedKey _changeKey = new("config.marmalade.updated"); + + public override string Name + => "marmalade"; + + public MarmaladeConfigService( + IConfigSeria serializer, + IPubSub pubSub) + : base(FILE_PATH, serializer, pubSub, _changeKey) + { + } + + public IReadOnlyCollection GetLoadedMarmalades() + => Data.Loaded?.ToList() ?? new List(); + + public void AddLoadedMarmalade(string name) + { + ModifyConfig(conf => + { + if (conf.Loaded is null) + conf.Loaded = new(); + + if(!conf.Loaded.Contains(name)) + conf.Loaded.Add(name); + }); + } + + public void RemoveLoadedMarmalade(string name) + { + ModifyConfig(conf => + { + if (conf.Loaded is null) + conf.Loaded = new(); + + conf.Loaded.Remove(name); + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/MarmaladeAssemblyLoadContext.cs b/src/EllieBot/_common/Marmalade/Common/MarmaladeAssemblyLoadContext.cs new file mode 100644 index 0000000..f07f7b5 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/MarmaladeAssemblyLoadContext.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.Loader; + +namespace EllieBot.Marmalade; + +public class MarmaladeAssemblyLoadContext : AssemblyLoadContext +{ + private readonly AssemblyDependencyResolver _resolver; + + public MarmaladeAssemblyLoadContext(string folderPath) : base(isCollectible: true) + => _resolver = new(folderPath); + + // public Assembly MainAssembly { get; private set; } + + protected override Assembly? Load(AssemblyName assemblyName) + { + var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + { + var assembly = LoadFromAssemblyPath(assemblyPath); + LoadDependencies(assembly); + return assembly; + } + + return null; + } + + public void LoadDependencies(Assembly assembly) + { + foreach (var reference in assembly.GetReferencedAssemblies()) + { + Load(reference); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/MarmaladeIoCKernelModule.cs b/src/EllieBot/_common/Marmalade/Common/MarmaladeIoCKernelModule.cs new file mode 100644 index 0000000..e55ddff --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/MarmaladeIoCKernelModule.cs @@ -0,0 +1,74 @@ +using DryIoc; +using System.Reflection; +using System.Text.Json; + +namespace EllieBot.Marmalade; + +public interface IIocModule +{ + public string Name { get; } + public void Load(); + public void Unload(); +} + +public sealed class MarmaladeNinjectIocModule : IIocModule, IDisposable +{ + public string Name { get; } + private volatile bool isLoaded = false; + private readonly Dictionary _types; + private readonly IContainer _cont; + + public MarmaladeNinjectIocModule(IContainer cont, Assembly assembly, string name) + { + Name = name; + _cont = cont; + _types = assembly.GetExportedTypes() + .Where(t => t.IsClass) + .Where(t => t.GetCustomAttribute() is not null) + .ToDictionary(x => x, + type => type.GetInterfaces().ToArray()); + } + + public void Load() + { + if (isLoaded) + return; + + foreach (var (type, data) in _types) + { + var attribute = type.GetCustomAttribute()!; + + var reuse = attribute.Lifetime == Lifetime.Singleton + ? Reuse.Singleton + : Reuse.Transient; + + _cont.RegisterMany([type], reuse); + } + + isLoaded = true; + } + + public void Unload() + { + if (!isLoaded) + return; + + foreach (var type in _types.Keys) + { + _cont.Unregister(type); + } + + _types.Clear(); + + // in case the library uses System.Text.Json + var assembly = typeof(JsonSerializerOptions).Assembly; + var updateHandlerType = assembly.GetType("System.Text.Json.JsonSerializerOptionsUpdateHandler"); + var clearCacheMethod = updateHandlerType?.GetMethod("ClearCache", BindingFlags.Static | BindingFlags.Public); + clearCacheMethod?.Invoke(null, [null]); + + isLoaded = false; + } + + public void Dispose() + => _types.Clear(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/MarmaladeLoaderService.cs b/src/EllieBot/_common/Marmalade/Common/MarmaladeLoaderService.cs new file mode 100644 index 0000000..a17e05a --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/MarmaladeLoaderService.cs @@ -0,0 +1,916 @@ +using Discord.Commands.Builders; +using DryIoc; +using Microsoft.Extensions.DependencyInjection; +using Ellie.Common.Marmalade; +using Ellie.Marmalade.Adapters; +using EllieBot.Common.ModuleBehaviors; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace EllieBot.Marmalade; + +// ReSharper disable RedundantAssignment +public sealed class MarmaladeLoaderService : IMarmaladeLoaderService, IReadyExecutor, IEService +{ + private readonly CommandService _cmdService; + private readonly IBehaviorHandler _behHandler; + private readonly IPubSub _pubSub; + private readonly IMarmaladeConfigService _marmaladeConfig; + private readonly IContainer _cont; + + private readonly ConcurrentDictionary _resolved = new(); + private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); + + private readonly TypedKey _loadKey = new("marmalade:load"); + private readonly TypedKey _unloadKey = new("marmalade:unload"); + + private readonly TypedKey _stringsReload = new("marmalade:reload_strings"); + + private const string BASE_DIR = "data/marmalades"; + + public MarmaladeLoaderService( + CommandService cmdService, + IContainer cont, + IBehaviorHandler behHandler, + IPubSub pubSub, + IMarmaladeConfigService marmaladeConfig) + { + _cmdService = cmdService; + _behHandler = behHandler; + _pubSub = pubSub; + _marmaladeConfig = marmaladeConfig; + _cont = cont; + + // has to be done this way to support this feature on sharded bots + _pubSub.Sub(_loadKey, async name => await InternalLoadAsync(name)); + _pubSub.Sub(_unloadKey, async name => await InternalUnloadAsync(name)); + + _pubSub.Sub(_stringsReload, async _ => await ReloadStringsInternal()); + } + + public IReadOnlyCollection GetAllMarmalades() + { + if (!Directory.Exists(BASE_DIR)) + return Array.Empty(); + + return Directory.GetDirectories(BASE_DIR) + .Select(x => Path.GetRelativePath(BASE_DIR, x)) + .ToArray(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public IReadOnlyCollection GetLoadedMarmalades(CultureInfo? culture) + { + var toReturn = new List(_resolved.Count); + foreach (var (name, resolvedData) in _resolved) + { + var canaries = new List(resolvedData.CanaryInfos.Count); + + foreach (var canaryInfos in resolvedData.CanaryInfos.Concat(resolvedData.CanaryInfos.SelectMany(x => x.Subcanaries))) + { + var commands = new List(); + + foreach (var command in canaryInfos.Commands) + { + commands.Add(new CanaryCommandStats(command.Aliases.First())); + } + + canaries.Add(new CanaryStats(canaryInfos.Name, canaryInfos.Instance.Prefix, commands)); + } + + toReturn.Add(new MarmaladeStats(name, resolvedData.Strings.GetDescription(culture), canaries)); + } + + return toReturn; + } + + public async Task OnReadyAsync() + { + foreach (var name in _marmaladeConfig.GetLoadedMarmalades()) + { + var result = await InternalLoadAsync(name); + if (result != MarmaladeLoadResult.Success) + Log.Warning("Unable to load '{MarmaladeName}' marmalade", name); + else + Log.Warning("Loaded marmalade '{MarmaladeName}'", name); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public async Task LoadMarmaladeAsync(string marmaladeName) + { + // try loading on this shard first to see if it works + var res = await InternalLoadAsync(marmaladeName); + if (res == MarmaladeLoadResult.Success) + { + // if it does publish it so that other shards can load the marmalade too + // this method will be ran twice on this shard but it doesn't matter as + // the second attempt will be ignored + await _pubSub.Pub(_loadKey, marmaladeName); + } + + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public async Task UnloadMarmaladeAsync(string marmaladeName) + { + var res = await InternalUnloadAsync(marmaladeName); + if (res == MarmaladeUnloadResult.Success) + { + await _pubSub.Pub(_unloadKey, marmaladeName); + } + + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string[] GetCommandExampleArgs(string marmaladeName, string commandName, CultureInfo culture) + { + if (!_resolved.TryGetValue(marmaladeName, out var data)) + return Array.Empty(); + + return data.Strings.GetCommandStrings(commandName, culture).Args + ?? data.CanaryInfos + .SelectMany(x => x.Commands) + .FirstOrDefault(x => x.Aliases.Any(alias + => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) + ?.OptionalStrings + .Args + ?? [string.Empty]; + } + + public Task ReloadStrings() + => _pubSub.Pub(_stringsReload, true); + + [MethodImpl(MethodImplOptions.NoInlining)] + private void ReloadStringsSync() + { + foreach (var resolved in _resolved.Values) + { + resolved.Strings.Reload(); + } + } + + private async Task ReloadStringsInternal() + { + await _lock.WaitAsync(); + try + { + ReloadStringsSync(); + } + finally + { + _lock.Release(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetCommandDescription(string marmaladeName, string commandName, CultureInfo culture) + { + if (!_resolved.TryGetValue(marmaladeName, out var data)) + return string.Empty; + + return data.Strings.GetCommandStrings(commandName, culture).Desc + ?? data.CanaryInfos + .SelectMany(x => x.Commands) + .FirstOrDefault(x => x.Aliases.Any(alias + => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) + ?.OptionalStrings + .Desc + ?? string.Empty; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async ValueTask InternalLoadAsync(string name) + { + if (_resolved.ContainsKey(name)) + return MarmaladeLoadResult.AlreadyLoaded; + + var safeName = Uri.EscapeDataString(name); + + await _lock.WaitAsync(); + try + { + if (LoadAssemblyInternal(safeName, + out var ctx, + out var canaryData, + out var iocModule, + out var strings, + out var typeReaders)) + { + var moduleInfos = new List(); + + LoadTypeReadersInternal(typeReaders); + + foreach (var point in canaryData) + { + try + { + // initialize canary and subcanaries + await point.Instance.InitializeAsync(); + foreach (var sub in point.Subcanaries) + { + await sub.Instance.InitializeAsync(); + } + + var module = await LoadModuleInternalAsync(name, point, strings, iocModule); + moduleInfos.Add(module); + } + catch (Exception ex) + { + Log.Warning(ex, + "Error loading canary {CanaryName}", + point.Name); + } + } + + var execs = GetExecsInternal(canaryData, strings); + await _behHandler.AddRangeAsync(execs); + + _resolved[name] = new(LoadContext: ctx, + ModuleInfos: moduleInfos.ToImmutableArray(), + CanaryInfos: canaryData.ToImmutableArray(), + strings, + typeReaders, + execs) + { + IocModule = iocModule + }; + + + _marmaladeConfig.AddLoadedMarmalade(safeName); + return MarmaladeLoadResult.Success; + } + + return MarmaladeLoadResult.Empty; + } + catch (Exception ex) when (ex is FileNotFoundException or BadImageFormatException) + { + return MarmaladeLoadResult.NotFound; + } + catch (Exception ex) + { + Log.Error(ex, "An error occurred loading a marmalade"); + return MarmaladeLoadResult.UnknownError; + } + finally + { + _lock.Release(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private IReadOnlyCollection GetExecsInternal( + IReadOnlyCollection canaryData, + IMarmaladeStrings strings) + { + var behs = new List(); + foreach (var canary in canaryData) + { + behs.Add(new BehaviorAdapter(new(canary.Instance), strings, _cont)); + + foreach (var sub in canary.Subcanaries) + { + behs.Add(new BehaviorAdapter(new(sub.Instance), strings, _cont)); + } + } + + + return behs; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void LoadTypeReadersInternal(Dictionary typeReaders) + { + var notAddedTypeReaders = new List(); + foreach (var (type, typeReader) in typeReaders) + { + // if type reader for this type already exists, it will not be replaced + if (_cmdService.TypeReaders.Contains(type)) + { + notAddedTypeReaders.Add(type); + continue; + } + + _cmdService.AddTypeReader(type, typeReader); + } + + // remove the ones that were not added + // to prevent them from being unloaded later + // as they didn't come from this marmalade + foreach (var toRemove in notAddedTypeReaders) + { + typeReaders.Remove(toRemove); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool LoadAssemblyInternal( + string safeName, + [NotNullWhen(true)] out WeakReference? ctxWr, + [NotNullWhen(true)] out IReadOnlyCollection? canaryData, + [NotNullWhen(true)] out IIocModule? iocModule, + out IMarmaladeStrings strings, + out Dictionary typeReaders) + { + ctxWr = null; + canaryData = null; + + var path = Path.GetFullPath($"{BASE_DIR}/{safeName}/{safeName}.dll"); + var dir = Path.GetFullPath($"{BASE_DIR}/{safeName}"); + + if (!Directory.Exists(dir)) + throw new DirectoryNotFoundException($"Marmalade folder not found: {dir}"); + + if (!File.Exists(path)) + throw new FileNotFoundException($"Marmalade dll not found: {path}"); + + strings = MarmaladeStrings.CreateDefault(dir); + var ctx = new MarmaladeAssemblyLoadContext(Path.GetDirectoryName(path)!); + var a = ctx.LoadFromAssemblyPath(Path.GetFullPath(path)); + ctx.LoadDependencies(a); + + // load services + iocModule = new MarmaladeNinjectIocModule(_cont, a, safeName); + iocModule.Load(); + + var sis = LoadCanariesFromAssembly(safeName, a); + typeReaders = LoadTypeReadersFromAssembly(a, strings); + + if (sis.Count == 0) + { + iocModule.Unload(); + return false; + } + + ctxWr = new(ctx); + canaryData = sis; + + return true; + } + + private static readonly Type _paramParserType = typeof(ParamParser<>); + + [MethodImpl(MethodImplOptions.NoInlining)] + private Dictionary LoadTypeReadersFromAssembly( + Assembly assembly, + IMarmaladeStrings strings) + { + var paramParsers = assembly.GetExportedTypes() + .Where(x => x.IsClass + && !x.IsAbstract + && x.BaseType is not null + && x.BaseType.IsGenericType + && x.BaseType.GetGenericTypeDefinition() == _paramParserType); + + var typeReaders = new Dictionary(); + foreach (var parserType in paramParsers) + { + var parserObj = ActivatorUtilities.CreateInstance(_cont, parserType); + + var targetType = parserType.BaseType!.GetGenericArguments()[0]; + var typeReaderInstance = (TypeReader)Activator.CreateInstance( + typeof(ParamParserAdapter<>).MakeGenericType(targetType), + args: [parserObj, strings, _cont])!; + + typeReaders.Add(targetType, typeReaderInstance); + } + + return typeReaders; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task LoadModuleInternalAsync( + string marmaladeName, + CanaryInfo canaryInfo, + IMarmaladeStrings strings, + IIocModule services) + { + var module = await _cmdService.CreateModuleAsync(canaryInfo.Instance.Prefix, + CreateModuleFactory(marmaladeName, canaryInfo, strings, services)); + + return module; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private Action CreateModuleFactory( + string marmaladeName, + CanaryInfo canaryInfo, + IMarmaladeStrings strings, + IIocModule iocModule) + => mb => + { + var m = mb.WithName(canaryInfo.Name); + + foreach (var f in canaryInfo.Filters) + { + m.AddPrecondition(new FilterAdapter(f, strings)); + } + + foreach (var cmd in canaryInfo.Commands) + { + m.AddCommand(cmd.Aliases.First(), + CreateCallback(cmd.ContextType, + new(canaryInfo), + new(cmd), + strings), + CreateCommandFactory(marmaladeName, cmd, strings)); + } + + foreach (var subInfo in canaryInfo.Subcanaries) + m.AddModule(subInfo.Instance.Prefix, CreateModuleFactory(marmaladeName, subInfo, strings, iocModule)); + }; + + private static readonly RequireContextAttribute _reqGuild = new RequireContextAttribute(ContextType.Guild); + private static readonly RequireContextAttribute _reqDm = new RequireContextAttribute(ContextType.DM); + + private Action CreateCommandFactory(string marmaladeName, CanaryCommandData cmd, IMarmaladeStrings strings) + => (cb) => + { + cb.AddAliases(cmd.Aliases.Skip(1).ToArray()); + + if (cmd.ContextType == CommandContextType.Guild) + cb.AddPrecondition(_reqGuild); + else if (cmd.ContextType == CommandContextType.Dm) + cb.AddPrecondition(_reqDm); + + foreach (var f in cmd.Filters) + cb.AddPrecondition(new FilterAdapter(f, strings)); + + foreach (var ubp in cmd.UserAndBotPerms) + { + if (ubp is user_permAttribute up) + { + if (up.GuildPerm is { } gp) + cb.AddPrecondition(new UserPermAttribute(gp)); + else if (up.ChannelPerm is { } cp) + cb.AddPrecondition(new UserPermAttribute(cp)); + } + else if (ubp is bot_permAttribute bp) + { + if (bp.GuildPerm is { } gp) + cb.AddPrecondition(new BotPermAttribute(gp)); + else if (bp.ChannelPerm is { } cp) + cb.AddPrecondition(new BotPermAttribute(cp)); + } + else if (ubp is bot_owner_onlyAttribute) + { + cb.AddPrecondition(new OwnerOnlyAttribute()); + } + } + + cb.WithPriority(cmd.Priority); + + // using summary to save method name + // method name is used to retrieve desc/usages + cb.WithRemarks($"marmalade///{marmaladeName}"); + cb.WithSummary(cmd.MethodInfo.Name.ToLowerInvariant()); + + foreach (var param in cmd.Parameters) + { + cb.AddParameter(param.Name, param.Type, CreateParamFactory(param)); + } + }; + + private Action CreateParamFactory(ParamData paramData) + => (pb) => + { + pb.WithIsMultiple(paramData.IsParams) + .WithIsOptional(paramData.IsOptional) + .WithIsRemainder(paramData.IsLeftover); + + if (paramData.IsOptional) + pb.WithDefault(paramData.DefaultValue); + }; + + [MethodImpl(MethodImplOptions.NoInlining)] + private Func CreateCallback( + CommandContextType contextType, + WeakReference canaryDataWr, + WeakReference canaryCommandDataWr, + IMarmaladeStrings strings) + => async ( + context, + parameters, + svcs, + _) => + { + if (!canaryCommandDataWr.TryGetTarget(out var cmdData) + || !canaryDataWr.TryGetTarget(out var canaryData)) + { + Log.Warning("Attempted to run an unloaded canary's command"); + return; + } + + var paramObjs = ParamObjs(contextType, cmdData, parameters, context, svcs, _cont, strings); + + try + { + var methodInfo = cmdData.MethodInfo; + if (methodInfo.ReturnType == typeof(Task) + || (methodInfo.ReturnType.IsGenericType + && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))) + { + await (Task)methodInfo.Invoke(canaryData.Instance, paramObjs)!; + } + else if (methodInfo.ReturnType == typeof(ValueTask)) + { + await ((ValueTask)methodInfo.Invoke(canaryData.Instance, paramObjs)!).AsTask(); + } + else // if (methodInfo.ReturnType == typeof(void)) + { + methodInfo.Invoke(canaryData.Instance, paramObjs); + } + } + finally + { + paramObjs = null; + cmdData = null; + + canaryData = null; + } + }; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static object[] ParamObjs( + CommandContextType contextType, + CanaryCommandData cmdData, + object[] parameters, + ICommandContext context, + IServiceProvider svcs, + IServiceProvider svcProvider, + IMarmaladeStrings strings) + { + var extraParams = contextType == CommandContextType.Unspecified ? 0 : 1; + extraParams += cmdData.InjectedParams.Count; + + var paramObjs = new object[parameters.Length + extraParams]; + + var startAt = 0; + if (contextType != CommandContextType.Unspecified) + { + paramObjs[0] = ContextAdapterFactory.CreateNew(context, strings, svcs); + + startAt = 1; + } + + for (var i = 0; i < cmdData.InjectedParams.Count; i++) + { + var svc = svcProvider.GetService(cmdData.InjectedParams[i]); + if (svc is null) + { + throw new ArgumentException($"Cannot inject a service of type {cmdData.InjectedParams[i]}"); + } + + paramObjs[i + startAt] = svc; + + svc = null; + } + + startAt += cmdData.InjectedParams.Count; + + for (var i = 0; i < parameters.Length; i++) + paramObjs[startAt + i] = parameters[i]; + + return paramObjs; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task InternalUnloadAsync(string name) + { + if (!_resolved.Remove(name, out var lsi)) + return MarmaladeUnloadResult.NotLoaded; + + await _lock.WaitAsync(); + try + { + UnloadTypeReaders(lsi.TypeReaders); + + foreach (var mi in lsi.ModuleInfos) + { + await _cmdService.RemoveModuleAsync(mi); + } + + await _behHandler.RemoveRangeAsync(lsi.Execs); + + await DisposeCanaryInstances(lsi); + + var lc = lsi.LoadContext; + var km = lsi.IocModule; + + lsi.IocModule.Unload(); + lsi.IocModule = null!; + + if (km is IDisposable d) + d.Dispose(); + + lsi = null; + + _marmaladeConfig.RemoveLoadedMarmalade(name); + return UnloadInternal(lc) + ? MarmaladeUnloadResult.Success + : MarmaladeUnloadResult.PossiblyUnable; + } + finally + { + _lock.Release(); + } + } + + private void UnloadTypeReaders(Dictionary valueTypeReaders) + { + foreach (var tr in valueTypeReaders) + { + _cmdService.TryRemoveTypeReader(tr.Key, false, out _); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task DisposeCanaryInstances(ResolvedMarmalade marmalade) + { + foreach (var si in marmalade.CanaryInfos) + { + try + { + await si.Instance.DisposeAsync(); + foreach (var sub in si.Subcanaries) + { + await sub.Instance.DisposeAsync(); + } + } + catch (Exception ex) + { + Log.Warning(ex, + "Failed cleanup of Canary {CanaryName}. This marmalade might not unload correctly", + si.Instance.Name); + } + } + + // marmalades = null; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool UnloadInternal(WeakReference lsi) + { + UnloadContext(lsi); + GcCleanup(); + + return !lsi.TryGetTarget(out _); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void UnloadContext(WeakReference lsiLoadContext) + { + if (lsiLoadContext.TryGetTarget(out var ctx)) + { + ctx.Unload(); + } + } + + private void GcCleanup() + { + // cleanup + for (var i = 0; i < 10; i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.WaitForFullGCComplete(); + GC.Collect(); + } + } + + private static readonly Type _canaryType = typeof(Canary); + + // [MethodImpl(MethodImplOptions.NoInlining)] + // private MarmaladeIoCKernelModule LoadMarmaladeServicesInternal(string name, Assembly a) + // => new MarmaladeIoCKernelModule(name, a); + + + [MethodImpl(MethodImplOptions.NoInlining)] + public IReadOnlyCollection LoadCanariesFromAssembly(string name, Assembly a) + { + // find all types in teh assembly + var types = a.GetExportedTypes(); + // canary is always a public non abstract class + var classes = types.Where(static x => x.IsClass + && (x.IsNestedPublic || x.IsPublic) + && !x.IsAbstract + && x.BaseType == _canaryType + && (x.DeclaringType is null || x.DeclaringType.IsAssignableTo(_canaryType))) + .ToList(); + + var topModules = new Dictionary(); + + foreach (var cl in classes) + { + if (cl.DeclaringType is not null) + continue; + + // get module data, and add it to the topModules dictionary + var module = GetModuleData(cl); + topModules.Add(cl, module); + } + + foreach (var c in classes) + { + if (c.DeclaringType is not Type dt) + continue; + + // if there is no top level module which this module is a child of + // just print a warning and skip it + if (!topModules.TryGetValue(dt, out var parentData)) + { + Log.Warning("Can't load submodule {SubName} because parent module {Name} does not exist", + c.Name, + dt.Name); + continue; + } + + GetModuleData(c, parentData); + } + + return topModules.Values.ToArray(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private CanaryInfo GetModuleData(Type type, CanaryInfo? parentData = null) + { + var filters = type.GetCustomAttributes(true) + .ToArray(); + + var instance = (Canary)ActivatorUtilities.CreateInstance(_cont, type); + + var module = new CanaryInfo(instance.Name, + parentData, + instance, + GetCommands(instance, type), + filters); + + if (parentData is not null) + parentData.Subcanaries.Add(module); + + return module; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private IReadOnlyCollection GetCommands(Canary instance, Type type) + { + var methodInfos = type + .GetMethods(BindingFlags.Instance + | BindingFlags.DeclaredOnly + | BindingFlags.Public) + .Where(static x => + { + if (x.GetCustomAttribute(true) is null) + return false; + + if (x.ReturnType.IsGenericType) + { + var genericType = x.ReturnType.GetGenericTypeDefinition(); + if (genericType == typeof(Task<>)) + return true; + + // if (genericType == typeof(ValueTask<>)) + // return true; + + Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", + x.Name, + x.ReturnType); + + return false; + } + + var succ = x.ReturnType == typeof(Task) + || x.ReturnType == typeof(ValueTask) + || x.ReturnType == typeof(void); + + if (!succ) + { + Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", + x.Name, + x.ReturnType); + } + + return succ; + }); + + + var cmds = new List(); + foreach (var method in methodInfos) + { + var filters = method.GetCustomAttributes(true).ToArray(); + var userAndBotPerms = method.GetCustomAttributes(true) + .ToArray(); + var prio = method.GetCustomAttribute(true)?.Priority ?? 0; + + var paramInfos = method.GetParameters(); + var cmdParams = new List(); + var diParams = new List(); + var cmdContext = CommandContextType.Unspecified; + var canInject = false; + for (var paramCounter = 0; paramCounter < paramInfos.Length; paramCounter++) + { + var pi = paramInfos[paramCounter]; + + var paramName = pi.Name ?? "unnamed"; + var isContext = paramCounter == 0 && pi.ParameterType.IsAssignableTo(typeof(AnyContext)); + + var leftoverAttribute = pi.GetCustomAttribute(true); + var hasDefaultValue = pi.HasDefaultValue; + var defaultValue = pi.DefaultValue; + var isLeftover = leftoverAttribute != null; + var isParams = pi.GetCustomAttribute() is not null; + var paramType = pi.ParameterType; + var isInjected = pi.GetCustomAttribute(true) is not null; + + if (isContext) + { + if (hasDefaultValue || leftoverAttribute != null || isParams) + throw new ArgumentException( + "IContext parameter cannot be optional, leftover, constant or params. " + + GetErrorPath(method, pi)); + + if (paramCounter != 0) + throw new ArgumentException($"IContext parameter has to be first. {GetErrorPath(method, pi)}"); + + canInject = true; + + if (paramType.IsAssignableTo(typeof(GuildContext))) + cmdContext = CommandContextType.Guild; + else if (paramType.IsAssignableTo(typeof(DmContext))) + cmdContext = CommandContextType.Dm; + else + cmdContext = CommandContextType.Any; + + continue; + } + + if (isInjected) + { + if (!canInject && paramCounter != 0) + throw new ArgumentException($"Parameters marked as [Injected] have to come after IContext"); + + canInject = true; + + diParams.Add(paramType); + continue; + } + + canInject = false; + + if (isParams) + { + if (hasDefaultValue) + throw new NotSupportedException("Params can't have const values at the moment. " + + GetErrorPath(method, pi)); + // if it's params, it means it's an array, and i only need a parser for the actual type, + // as the parser will run on each array element, it can't be null + paramType = paramType.GetElementType()!; + } + + // leftover can only be the last parameter. + if (isLeftover && paramCounter != paramInfos.Length - 1) + { + var path = GetErrorPath(method, pi); + Log.Error("Only one parameter can be marked [Leftover] and it has to be the last one. {Path} ", + path); + throw new ArgumentException("Leftover attribute error."); + } + + cmdParams.Add(new ParamData(paramType, paramName, hasDefaultValue, defaultValue, isLeftover, isParams)); + } + + + var cmdAttribute = method.GetCustomAttribute(true)!; + var aliases = cmdAttribute.Aliases; + if (aliases.Length == 0) + aliases = [method.Name.ToLowerInvariant()]; + + cmds.Add(new( + aliases, + method, + instance, + filters, + userAndBotPerms, + cmdContext, + diParams, + cmdParams, + new(cmdAttribute.desc, cmdAttribute.args), + prio + )); + } + + return cmds; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private string GetErrorPath(MethodInfo m, System.Reflection.ParameterInfo pi) + => $@"Module: {m.DeclaringType?.Name} +Command: {m.Name} +ParamName: {pi.Name} +ParamType: {pi.ParameterType.Name}"; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Models/CanaryCommandData.cs b/src/EllieBot/_common/Marmalade/Common/Models/CanaryCommandData.cs new file mode 100644 index 0000000..8244576 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Models/CanaryCommandData.cs @@ -0,0 +1,44 @@ +using EllieBot.Marmalade; +using System.Reflection; + +namespace EllieBot.Marmalade; + +public sealed class CanaryCommandData +{ + public CanaryCommandData( + IReadOnlyCollection aliases, + MethodInfo methodInfo, + Canary module, + FilterAttribute[] filters, + MarmaladePermAttribute[] userAndBotPerms, + CommandContextType contextType, + IReadOnlyList injectedParams, + IReadOnlyList parameters, + CommandStrings strings, + int priority) + { + Aliases = aliases; + MethodInfo = methodInfo; + Module = module; + Filters = filters; + UserAndBotPerms = userAndBotPerms; + ContextType = contextType; + InjectedParams = injectedParams; + Parameters = parameters; + Priority = priority; + OptionalStrings = strings; + } + + public MarmaladePermAttribute[] UserAndBotPerms { get; set; } + + public CommandStrings OptionalStrings { get; set; } + + public IReadOnlyCollection Aliases { get; } + public MethodInfo MethodInfo { get; set; } + public Canary Module { get; set; } + public FilterAttribute[] Filters { get; set; } + public CommandContextType ContextType { get; } + public IReadOnlyList InjectedParams { get; } + public IReadOnlyList Parameters { get; } + public int Priority { get; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Models/CanaryData.cs b/src/EllieBot/_common/Marmalade/Common/Models/CanaryData.cs new file mode 100644 index 0000000..4ccb93d --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Models/CanaryData.cs @@ -0,0 +1,11 @@ +namespace EllieBot.Marmalade; + +public sealed record CanaryInfo( + string Name, + CanaryInfo? Parent, + Canary Instance, + IReadOnlyCollection Commands, + IReadOnlyCollection Filters) +{ + public List Subcanaries { get; set; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Models/ParamData.cs b/src/EllieBot/_common/Marmalade/Common/Models/ParamData.cs new file mode 100644 index 0000000..5b3e222 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Models/ParamData.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Marmalade; + +public sealed record ParamData( + Type Type, + string Name, + bool IsOptional, + object? DefaultValue, + bool IsLeftover, + bool IsParams +); \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/Common/Models/ResolvedMarmalade.cs b/src/EllieBot/_common/Marmalade/Common/Models/ResolvedMarmalade.cs new file mode 100644 index 0000000..7441d90 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/Common/Models/ResolvedMarmalade.cs @@ -0,0 +1,15 @@ +using System.Collections.Immutable; + +namespace EllieBot.Marmalade; + +public sealed record ResolvedMarmalade( + WeakReference LoadContext, + IImmutableList ModuleInfos, + IImmutableList CanaryInfos, + IMarmaladeStrings Strings, + Dictionary TypeReaders, + IReadOnlyCollection Execs +) +{ + public required IIocModule IocModule { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/IMarmaladeLoaderService.cs b/src/EllieBot/_common/Marmalade/IMarmaladeLoaderService.cs new file mode 100644 index 0000000..3a17339 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/IMarmaladeLoaderService.cs @@ -0,0 +1,24 @@ +using System.Globalization; + +namespace Ellie.Common.Marmalade; + +public interface IMarmaladeLoaderService +{ + Task LoadMarmaladeAsync(string marmaladeName); + Task UnloadMarmaladeAsync(string marmaladeName); + string GetCommandDescription(string marmaladeName, string commandName, CultureInfo culture); + string[] GetCommandExampleArgs(string marmaladeName, string commandName, CultureInfo culture); + Task ReloadStrings(); + IReadOnlyCollection GetAllMarmalades(); + IReadOnlyCollection GetLoadedMarmalades(CultureInfo? cultureInfo = null); +} + +public sealed record MarmaladeStats(string Name, + string? Description, + IReadOnlyCollection Canaries); + +public sealed record CanaryStats(string Name, + string? Prefix, + IReadOnlyCollection Commands); + +public sealed record CanaryCommandStats(string Name); \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/MarmaladeLoadResult.cs b/src/EllieBot/_common/Marmalade/MarmaladeLoadResult.cs new file mode 100644 index 0000000..826f4c5 --- /dev/null +++ b/src/EllieBot/_common/Marmalade/MarmaladeLoadResult.cs @@ -0,0 +1,10 @@ +namespace Ellie.Common.Marmalade; + +public enum MarmaladeLoadResult +{ + Success, + NotFound, + AlreadyLoaded, + Empty, + UnknownError, +} \ No newline at end of file diff --git a/src/EllieBot/_common/Marmalade/MarmaladeUnloadResult.cs b/src/EllieBot/_common/Marmalade/MarmaladeUnloadResult.cs new file mode 100644 index 0000000..f07569e --- /dev/null +++ b/src/EllieBot/_common/Marmalade/MarmaladeUnloadResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Common.Marmalade; + +public enum MarmaladeUnloadResult +{ + Success, + NotLoaded, + PossiblyUnable, + NotFound, +} \ No newline at end of file diff --git a/src/EllieBot/_common/MessageType.cs b/src/EllieBot/_common/MessageType.cs new file mode 100644 index 0000000..ada8d99 --- /dev/null +++ b/src/EllieBot/_common/MessageType.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Common; + +public enum MsgType +{ + Ok, + Pending, + Error +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IBehavior.cs b/src/EllieBot/_common/ModuleBehaviors/IBehavior.cs new file mode 100644 index 0000000..5fdcc5c --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IBehavior.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Common.ModuleBehaviors; + +public interface IBehavior +{ + public virtual string Name => this.GetType().Name; +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs b/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs new file mode 100644 index 0000000..4ceeaaf --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs @@ -0,0 +1,19 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// Executed if no command was found for this message +/// +public interface IExecNoCommand : IBehavior +{ + /// + /// Executed at the end of the lifecycle if no command was found + /// → + /// → + /// → + /// [ | **] + /// + /// + /// + /// A task representing completion + Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs b/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs new file mode 100644 index 0000000..7b37a24 --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs @@ -0,0 +1,21 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// Implemented by modules to handle non-bot messages received +/// +public interface IExecOnMessage : IBehavior +{ + int Priority { get; } + + /// + /// Ran after a non-bot message was received + /// ** → + /// → + /// → + /// [ | ] + /// + /// Guild where the message was sent + /// The message that was received + /// Whether further processing of this message should be blocked + Task ExecOnMessageAsync(IGuild guild, IUserMessage msg); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs b/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs new file mode 100644 index 0000000..ccb949c --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs @@ -0,0 +1,22 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// This interface's method is executed after the command successfully finished execution. +/// ***There is no support for this method in EllieBot services.*** +/// It is only meant to be used in marmalade system +/// +public interface IExecPostCommand : IBehavior +{ + /// + /// Executed after a command was successfully executed + /// → + /// → + /// → + /// [** | ] + /// + /// Command context + /// Module name + /// Command name + /// A task representing completion + ValueTask ExecPostCommandAsync(ICommandContext ctx, string moduleName, string commandName); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs b/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs new file mode 100644 index 0000000..438cbd0 --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs @@ -0,0 +1,25 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// This interface's method is executed after a command was found but before it was executed. +/// Able to block further processing of a command +/// +public interface IExecPreCommand : IBehavior +{ + public int Priority { get; } + + /// + /// + /// Ran after a command was found but before execution. + /// + /// → + /// → + /// ** → + /// [ | ] + /// + /// Command context + /// Name of the module + /// Command info + /// Whether further processing of the command is blocked + Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs b/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs new file mode 100644 index 0000000..957e659 --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs @@ -0,0 +1,25 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// Implemented by services which may transform input before a command is searched for +/// +public interface IInputTransformer : IBehavior +{ + /// + /// Ran after a non-bot message was received + /// -> + /// ** -> + /// -> + /// [ OR ] + /// + /// Guild + /// Channel in which the message was sent + /// User who sent the message + /// Content of the message + /// New input, if any, otherwise null + Task TransformInput( + IGuild guild, + IMessageChannel channel, + IUser user, + string input); +} \ No newline at end of file diff --git a/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs b/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs new file mode 100644 index 0000000..f0a200b --- /dev/null +++ b/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs @@ -0,0 +1,13 @@ +namespace EllieBot.Common.ModuleBehaviors; + +/// +/// All services which need to execute something after +/// the bot is ready should implement this interface +/// +public interface IReadyExecutor : IBehavior +{ + /// + /// Executed when bot is ready + /// + public Task OnReadyAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/NinjectKernelExtensions.cs b/src/EllieBot/_common/NinjectKernelExtensions.cs new file mode 100644 index 0000000..36b4fa8 --- /dev/null +++ b/src/EllieBot/_common/NinjectKernelExtensions.cs @@ -0,0 +1,51 @@ +using DryIoc; + +namespace EllieBot.Extensions; + +public static class DryIocExtensions +{ + public static IContainer AddSingleton(this IContainer container) + where TImpl : TSvc + { + container.Register(Reuse.Singleton); + + return container; + } + + public static IContainer AddSingleton(this IContainer container, TImpl obj) + where TImpl : TSvc + { + container.RegisterInstance(obj); + + return container; + } + + public static IContainer AddSingleton(this IContainer container, Func factory) + where TImpl : TSvc + { + container.RegisterDelegate(factory, Reuse.Singleton); + + return container; + } + + public static IContainer AddSingleton(this IContainer container) + { + container.Register(Reuse.Singleton); + + return container; + } + + public static IContainer AddSingleton(this IContainer container, TImpl obj) + { + container.RegisterInstance(obj); + + return container; + } + + public static IContainer AddSingleton(this IContainer container, Func factory) + { + container.RegisterDelegate(factory); + + return container; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/OldCreds.cs b/src/EllieBot/_common/OldCreds.cs new file mode 100644 index 0000000..b06e15a --- /dev/null +++ b/src/EllieBot/_common/OldCreds.cs @@ -0,0 +1,45 @@ +#nullable disable +namespace EllieBot.Common; + +public class OldCreds +{ + public string Token { get; set; } = string.Empty; + public ulong[] OwnerIds { get; set; } = new ulong[1]; + public string LoLApiKey { get; set; } = string.Empty; + public string GoogleApiKey { get; set; } = string.Empty; + public string MashapeKey { get; set; } = string.Empty; + public string OsuApiKey { get; set; } = string.Empty; + public string CleverbotApiKey { get; set; } = string.Empty; + public string CarbonKey { get; set; } = string.Empty; + public int TotalShards { get; set; } = 1; + public string PatreonAccessToken { get; set; } = string.Empty; + public string PatreonCampaignId { get; set; } = "334038"; + public RestartConfig RestartCommand { get; set; } + + public string ShardRunCommand { get; set; } = string.Empty; + public string ShardRunArguments { get; set; } = string.Empty; + public int? ShardRunPort { get; set; } + public string MiningProxyUrl { get; set; } = string.Empty; + public string MiningProxyCreds { get; set; } = string.Empty; + + public string BotListToken { get; set; } = string.Empty; + public string TwitchClientId { get; set; } = string.Empty; + public string VotesToken { get; set; } = string.Empty; + public string VotesUrl { get; set; } = string.Empty; + public string RedisOptions { get; set; } = string.Empty; + public string LocationIqApiKey { get; set; } = string.Empty; + public string TimezoneDbApiKey { get; set; } = string.Empty; + public string CoinmarketcapApiKey { get; set; } = string.Empty; + + public class RestartConfig + { + public string Cmd { get; set; } + public string Args { get; set; } + + public RestartConfig(string cmd, string args) + { + Cmd = cmd; + Args = args; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/OptionsParser.cs b/src/EllieBot/_common/OptionsParser.cs new file mode 100644 index 0000000..6908c8f --- /dev/null +++ b/src/EllieBot/_common/OptionsParser.cs @@ -0,0 +1,23 @@ +using CommandLine; + +namespace EllieBot.Common; + +public static class OptionsParser +{ + public static T ParseFrom(string[]? args) + where T : IEllieCommandOptions, new() + => ParseFrom(new T(), args).Item1; + + public static (T, bool) ParseFrom(T options, string[]? args) + where T : IEllieCommandOptions + { + using var p = new Parser(x => + { + x.HelpWriter = null; + }); + var res = p.ParseArguments(args); + var output = res.MapResult(x => x, _ => options); + output.NormalizeOptions(); + return (output, res.Tag == ParserResultType.Parsed); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/FeatureLimitKey.cs b/src/EllieBot/_common/Patronage/FeatureLimitKey.cs new file mode 100644 index 0000000..9aa8a46 --- /dev/null +++ b/src/EllieBot/_common/Patronage/FeatureLimitKey.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Patronage; + +public readonly struct FeatureLimitKey +{ + public string PrettyName { get; init; } + public string Key { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/FeatureQuotaStats.cs b/src/EllieBot/_common/Patronage/FeatureQuotaStats.cs new file mode 100644 index 0000000..02db5d3 --- /dev/null +++ b/src/EllieBot/_common/Patronage/FeatureQuotaStats.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Patronage; + +public readonly struct FeatureQuotaStats +{ + public (uint Cur, uint Max) Hourly { get; init; } + public (uint Cur, uint Max) Daily { get; init; } + public (uint Cur, uint Max) Monthly { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/IPatronData.cs b/src/EllieBot/_common/Patronage/IPatronData.cs new file mode 100644 index 0000000..8cd99e0 --- /dev/null +++ b/src/EllieBot/_common/Patronage/IPatronData.cs @@ -0,0 +1,11 @@ +namespace EllieBot.Modules.Patronage; + +public interface ISubscriberData +{ + public string UniquePlatformUserId { get; } + public ulong UserId { get; } + public int Cents { get; } + + public DateTime? LastCharge { get; } + public SubscriptionChargeStatus ChargeStatus { get; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/IPatronageService.cs b/src/EllieBot/_common/Patronage/IPatronageService.cs new file mode 100644 index 0000000..77fed4b --- /dev/null +++ b/src/EllieBot/_common/Patronage/IPatronageService.cs @@ -0,0 +1,56 @@ +using EllieBot.Db.Models; +using OneOf; + +namespace EllieBot.Modules.Patronage; + +/// +/// Manages patrons and provides access to their data +/// +public interface IPatronageService +{ + /// + /// Called when the payment is made. + /// Either as a single payment for that patron, + /// or as a recurring monthly donation. + /// + public event Func OnNewPatronPayment; + + /// + /// Called when the patron changes the pledge amount + /// (Patron old, Patron new) => Task + /// + public event Func OnPatronUpdated; + + /// + /// Called when the patron refunds the purchase or it's marked as fraud + /// + public event Func OnPatronRefunded; + + /// + /// Gets a Patron with the specified userId + /// + /// UserId for which to get the patron data for. + /// A patron with the specifeid userId + public Task GetPatronAsync(ulong userId); + + /// + /// Gets the quota statistic for the user/patron specified by the userId + /// + /// UserId of the user for which to get the quota statistic for + /// Quota stats for the specified user + Task GetUserQuotaStatistic(ulong userId); + + + Task TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue); + + ValueTask> TryIncrementQuotaCounterAsync( + ulong userId, + bool isSelf, + FeatureType featureType, + string featureName, + uint? maybeHourly, + uint? maybeDaily, + uint? maybeMonthly); + + PatronConfigData GetConfig(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/ISubscriptionHandler.cs b/src/EllieBot/_common/Patronage/ISubscriptionHandler.cs new file mode 100644 index 0000000..95160f7 --- /dev/null +++ b/src/EllieBot/_common/Patronage/ISubscriptionHandler.cs @@ -0,0 +1,16 @@ +#nullable disable +namespace EllieBot.Modules.Patronage; + +/// +/// Services implementing this interface are handling pledges/subscriptions/payments coming +/// from a payment platform. +/// +public interface ISubscriptionHandler +{ + /// + /// Get Current patrons in batches. + /// This will only return patrons who have their discord account connected + /// + /// Batched patrons + public IAsyncEnumerable> GetPatronsAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/Patron.cs b/src/EllieBot/_common/Patronage/Patron.cs new file mode 100644 index 0000000..a7c9d97 --- /dev/null +++ b/src/EllieBot/_common/Patronage/Patron.cs @@ -0,0 +1,38 @@ +namespace EllieBot.Modules.Patronage; + +public readonly struct Patron +{ + /// + /// Unique id assigned to this patron by the payment platform + /// + public string UniquePlatformUserId { get; init; } + + /// + /// Discord UserId to which this is connected to + /// + public ulong UserId { get; init; } + + /// + /// Amount the Patron is currently pledging or paid + /// + public int Amount { get; init; } + + /// + /// Current Tier of the patron + /// (do not question it in consumer classes, as the calculation should be always internal and may change) + /// + public PatronTier Tier { get; init; } + + /// + /// When was the last time this was paid + /// + public DateTime PaidAt { get; init; } + + /// + /// After which date does the user's Patronage benefit end + /// + public DateTime ValidThru { get; init; } + + public bool IsActive + => !ValidThru.IsBeforeToday(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/PatronConfigData.cs b/src/EllieBot/_common/Patronage/PatronConfigData.cs new file mode 100644 index 0000000..09ed100 --- /dev/null +++ b/src/EllieBot/_common/Patronage/PatronConfigData.cs @@ -0,0 +1,37 @@ +using EllieBot.Common.Yml; +using Cloneable; + +namespace EllieBot.Modules.Patronage; + +[Cloneable] +public partial class PatronConfigData : ICloneable +{ + [Comment("DO NOT CHANGE")] + public int Version { get; set; } = 2; + + [Comment("Whether the patronage feature is enabled")] + public bool IsEnabled { get; set; } + + [Comment("List of patron only features and relevant quota data")] + public FeatureQuotas Quotas { get; set; } + + public PatronConfigData() + { + Quotas = new(); + } + + public class FeatureQuotas + { + [Comment("Dictionary of feature names with their respective limits. Set to null for unlimited")] + public Dictionary> Features { get; set; } = new(); + + [Comment("Dictionary of commands with their respective quota data")] + public Dictionary?>> Commands { get; set; } = new(); + + [Comment("Dictionary of groups with their respective quota data")] + public Dictionary?>> Groups { get; set; } = new(); + + [Comment("Dictionary of modules with their respective quota data")] + public Dictionary?>> Modules { get; set; } = new(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/PatronExtensions.cs b/src/EllieBot/_common/Patronage/PatronExtensions.cs new file mode 100644 index 0000000..b422b73 --- /dev/null +++ b/src/EllieBot/_common/Patronage/PatronExtensions.cs @@ -0,0 +1,39 @@ +namespace EllieBot.Modules.Patronage; + +public static class PatronExtensions +{ + public static string ToFullName(this PatronTier tier) + => tier switch + { + _ => $"Patron Tier {tier}", + }; + + public static string ToFullName(this QuotaPer per) + => per switch + { + QuotaPer.PerDay => "per day", + QuotaPer.PerHour => "per hour", + QuotaPer.PerMonth => "per month", + _ => "Unknown", + }; + + public static DateTime DayOfNextMonth(this DateTime date, int day) + { + var nextMonth = date.AddMonths(1); + var dt = DateTime.SpecifyKind(new(nextMonth.Year, nextMonth.Month, day), DateTimeKind.Utc); + return dt; + } + + public static DateTime FirstOfNextMonth(this DateTime date) + => date.DayOfNextMonth(1); + + public static DateTime SecondOfNextMonth(this DateTime date) + => date.DayOfNextMonth(2); + + public static string ToShortAndRelativeTimestampTag(this DateTime date) + { + var fullResetStr = TimestampTag.FromDateTime(date, TimestampTagStyles.ShortDateTime); + var relativeResetStr = TimestampTag.FromDateTime(date, TimestampTagStyles.Relative); + return $"{fullResetStr}\n{relativeResetStr}"; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/PatronTier.cs b/src/EllieBot/_common/Patronage/PatronTier.cs new file mode 100644 index 0000000..0bbe804 --- /dev/null +++ b/src/EllieBot/_common/Patronage/PatronTier.cs @@ -0,0 +1,14 @@ +// ReSharper disable InconsistentNaming +namespace EllieBot.Modules.Patronage; + +public enum PatronTier +{ + None, + I, + V, + X, + XX, + L, + C, + ComingSoon +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/QuotaLimit.cs b/src/EllieBot/_common/Patronage/QuotaLimit.cs new file mode 100644 index 0000000..b40017c --- /dev/null +++ b/src/EllieBot/_common/Patronage/QuotaLimit.cs @@ -0,0 +1,66 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Patronage; + +/// +/// Represents information about why the user has triggered a quota limit +/// +public readonly struct QuotaLimit +{ + /// + /// Amount of usages reached, which is the limit + /// + public uint Quota { get; init; } + + /// + /// Which period is this quota limit for (hourly, daily, monthly, etc...) + /// + public QuotaPer QuotaPeriod { get; init; } + + /// + /// When does this quota limit reset + /// + public DateTime ResetsAt { get; init; } + + /// + /// Type of the feature this quota limit is for + /// + public FeatureType FeatureType { get; init; } + + /// + /// Name of the feature this quota limit is for + /// + public string Feature { get; init; } + + /// + /// Whether it is the user's own quota (true), or server owners (false) + /// + public bool IsOwnQuota { get; init; } +} + + +/// +/// Respresent information about the feature limit +/// +public readonly struct FeatureLimit +{ + + /// + /// Whether this limit comes from the patronage system + /// + public bool IsPatronLimit { get; init; } = false; + + /// + /// Maximum limit allowed + /// + public int? Quota { get; init; } = null; + + /// + /// Name of the limit + /// + public string Name { get; init; } = string.Empty; + + public FeatureLimit() + { + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/QuotaPer.cs b/src/EllieBot/_common/Patronage/QuotaPer.cs new file mode 100644 index 0000000..c6080ac --- /dev/null +++ b/src/EllieBot/_common/Patronage/QuotaPer.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Patronage; + +public enum QuotaPer +{ + PerHour, + PerDay, + PerMonth, +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/SubscriptionChargeStatus.cs b/src/EllieBot/_common/Patronage/SubscriptionChargeStatus.cs new file mode 100644 index 0000000..7ef541f --- /dev/null +++ b/src/EllieBot/_common/Patronage/SubscriptionChargeStatus.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Modules.Patronage; + +public enum SubscriptionChargeStatus +{ + Paid, + Refunded, + Unpaid, + Other, +} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/UserQuotaStats.cs b/src/EllieBot/_common/Patronage/UserQuotaStats.cs new file mode 100644 index 0000000..a9e33e4 --- /dev/null +++ b/src/EllieBot/_common/Patronage/UserQuotaStats.cs @@ -0,0 +1,25 @@ +namespace EllieBot.Modules.Patronage; + +public readonly struct UserQuotaStats +{ + private static readonly IReadOnlyDictionary _emptyDictionary + = new Dictionary(); + public PatronTier Tier { get; init; } + = PatronTier.None; + + public IReadOnlyDictionary Features { get; init; } + = _emptyDictionary; + + public IReadOnlyDictionary Commands { get; init; } + = _emptyDictionary; + + public IReadOnlyDictionary Groups { get; init; } + = _emptyDictionary; + + public IReadOnlyDictionary Modules { get; init; } + = _emptyDictionary; + + public UserQuotaStats() + { + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Pokemon/PokemonNameId.cs b/src/EllieBot/_common/Pokemon/PokemonNameId.cs new file mode 100644 index 0000000..341b5c2 --- /dev/null +++ b/src/EllieBot/_common/Pokemon/PokemonNameId.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Common.Pokemon; + +public class PokemonNameId +{ + public int Id { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Pokemon/SearchPokemon.cs b/src/EllieBot/_common/Pokemon/SearchPokemon.cs new file mode 100644 index 0000000..b4ecae1 --- /dev/null +++ b/src/EllieBot/_common/Pokemon/SearchPokemon.cs @@ -0,0 +1,41 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Common.Pokemon; + +public class SearchPokemon +{ + [JsonPropertyName("num")] + public int Id { get; set; } + + public string Species { get; set; } + public string[] Types { get; set; } + public GenderRatioClass GenderRatio { get; set; } + public BaseStatsClass BaseStats { get; set; } + public Dictionary Abilities { get; set; } + public float HeightM { get; set; } + public float WeightKg { get; set; } + public string Color { get; set; } + public string[] Evos { get; set; } + public string[] EggGroups { get; set; } + + public class GenderRatioClass + { + public float M { get; set; } + public float F { get; set; } + } + + public class BaseStatsClass + { + public int Hp { get; set; } + public int Atk { get; set; } + public int Def { get; set; } + public int Spa { get; set; } + public int Spd { get; set; } + public int Spe { get; set; } + + public override string ToString() + => $@"💚**HP:** {Hp,-4} ⚔**ATK:** {Atk,-4} 🛡**DEF:** {Def,-4} +✨**SPA:** {Spa,-4} 🎇**SPD:** {Spd,-4} 💨**SPE:** {Spe,-4}"; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs b/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs new file mode 100644 index 0000000..c3f8f36 --- /dev/null +++ b/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Common.Pokemon; + +public class SearchPokemonAbility +{ + public string Desc { get; set; } + public string ShortDesc { get; set; } + public string Name { get; set; } + public float Rating { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/IReplacementPatternStore.cs b/src/EllieBot/_common/Replacements/IReplacementPatternStore.cs new file mode 100644 index 0000000..0a6483a --- /dev/null +++ b/src/EllieBot/_common/Replacements/IReplacementPatternStore.cs @@ -0,0 +1,20 @@ +using System.Text.RegularExpressions; + +namespace EllieBot.Common; + +public interface IReplacementPatternStore : IEService +{ + IReadOnlyDictionary Replacements { get; } + IReadOnlyDictionary RegexReplacements { get; } + + ValueTask Register(string token, Func> repFactory); + ValueTask Register(string token, Func> repFactory); + ValueTask Register(string token, Func> repFactory); + + ValueTask Register(string token, Func repFactory); + ValueTask Register(string token, Func repFactory); + ValueTask Register(string token, Func repFactory); + + ValueTask Register(Regex regex, Func repFactory); + ValueTask Register(Regex regex, Func repFactory); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/IReplacementService.cs b/src/EllieBot/_common/Replacements/IReplacementService.cs new file mode 100644 index 0000000..66a0896 --- /dev/null +++ b/src/EllieBot/_common/Replacements/IReplacementService.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Common; + +public interface IReplacementService +{ + ValueTask ReplaceAsync(string input, ReplacementContext repCtx); + ValueTask ReplaceAsync(SmartText input, ReplacementContext repCtx); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementContext.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementContext.cs new file mode 100644 index 0000000..b321941 --- /dev/null +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementContext.cs @@ -0,0 +1,69 @@ +using System.Text.RegularExpressions; + +namespace EllieBot.Common; + +public sealed class ReplacementContext +{ + public DiscordSocketClient? Client { get; } + public IGuild? Guild { get; } + public IMessageChannel? Channel { get; } + public IUser[]? Users { get; } + + private readonly List _overrides = new(); + private readonly HashSet _tokens = new(); + + public IReadOnlyList Overrides + => _overrides.AsReadOnly(); + + private readonly List _regexOverrides = new(); + private readonly HashSet _regexPatterns = new(); + + public IReadOnlyList RegexOverrides + => _regexOverrides.AsReadOnly(); + + public ReplacementContext(ICommandContext cmdContext) : this(cmdContext.Client as DiscordSocketClient, + cmdContext.Guild, + cmdContext.Channel, + cmdContext.User) + { + } + + public ReplacementContext( + DiscordSocketClient? client = null, + IGuild? guild = null, + IMessageChannel? channel = null, + params IUser[]? users) + { + Client = client; + Guild = guild; + Channel = channel; + Users = users; + } + + public ReplacementContext WithOverride(string key, Func> repFactory) + { + if (_tokens.Add(key)) + { + _overrides.Add(new(key, repFactory)); + } + + return this; + } + + public ReplacementContext WithOverride(string key, Func repFactory) + => WithOverride(key, () => new ValueTask(repFactory())); + + + public ReplacementContext WithOverride(Regex regex, Func> repFactory) + { + if (_regexPatterns.Add(regex.ToString())) + { + _regexOverrides.Add(new(regex, repFactory)); + } + + return this; + } + + public ReplacementContext WithOverride(Regex regex, Func repFactory) + => WithOverride(regex, (Match m) => new ValueTask(repFactory(m))); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementInfo.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementInfo.cs new file mode 100644 index 0000000..254de96 --- /dev/null +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementInfo.cs @@ -0,0 +1,57 @@ +using System.Reflection; +using System.Text.RegularExpressions; + +namespace EllieBot.Common; + +public sealed class ReplacementInfo +{ + private readonly Delegate _del; + public IReadOnlyCollection InputTypes { get; } + public string Token { get; } + + private static readonly Func> _falllbackFunc = static () => default; + + public ReplacementInfo(string token, Delegate del) + { + _del = del; + InputTypes = del.GetMethodInfo().GetParameters().Select(x => x.ParameterType).ToArray().AsReadOnly(); + Token = token; + } + + public async Task GetValueAsync(params object?[]? objs) + => await (ValueTask)(_del.DynamicInvoke(objs) ?? _falllbackFunc); + + public override int GetHashCode() + => Token.GetHashCode(); + + public override bool Equals(object? obj) + => obj is ReplacementInfo ri && ri.Token == Token; +} + +public sealed class RegexReplacementInfo +{ + private readonly Delegate _del; + public IReadOnlyCollection InputTypes { get; } + + public Regex Regex { get; } + public string Pattern { get; } + + private static readonly Func> _falllbackFunc = static _ => default; + + public RegexReplacementInfo(Regex regex, Delegate del) + { + _del = del; + InputTypes = del.GetMethodInfo().GetParameters().Select(x => x.ParameterType).ToArray().AsReadOnly(); + Regex = regex; + Pattern = Regex.ToString(); + } + + public async Task GetValueAsync(Match m, params object?[]? objs) + => await ((Func>)(_del.DynamicInvoke(objs) ?? _falllbackFunc))(m); + + public override int GetHashCode() + => Regex.GetHashCode(); + + public override bool Equals(object? obj) + => obj is RegexReplacementInfo ri && ri.Pattern == Pattern; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementPatternStore.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementPatternStore.cs new file mode 100644 index 0000000..3692184 --- /dev/null +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementPatternStore.cs @@ -0,0 +1,130 @@ +using System.Text.RegularExpressions; +using OneOf; + +namespace EllieBot.Common; + +public sealed partial class ReplacementPatternStore : IReplacementPatternStore, IEService +{ + private readonly ConcurrentDictionary> _guids = new(); + + private readonly ConcurrentDictionary _defaultReplacements = new(); + private readonly ConcurrentDictionary _regexReplacements = new(); + + public IReadOnlyDictionary Replacements + => _defaultReplacements.AsReadOnly(); + + public IReadOnlyDictionary RegexReplacements + => _regexReplacements.AsReadOnly(); + + public ReplacementPatternStore() + { + WithClient(); + WithChannel(); + WithServer(); + WithUsers(); + WithDefault(); + WithRegex(); + } + + // private async ValueTask InternalReplace(string input, ReplacementContexta repCtx) + // { + // // multiple executions vs single execution per replacement + // var minIndex = -1; + // var index = -1; + // foreach (var rep in _replacements) + // { + // while ((index = input.IndexOf(rep.Key, StringComparison.InvariantCulture)) != -1 && index > minIndex) + // { + // var valueToInsert = await rep.Value(repCtx); + // input = input[..index] + valueToInsert +input[(index + rep.Key.Length)..]; + // minIndex = (index + valueToInsert.Length); + // } + // } + // + // return input; + // } + + private ValueTask InternalRegister(string token, Delegate repFactory) + { + if (!token.StartsWith('%') || !token.EndsWith('%')) + { + Log.Warning( + """ + Invalid replacement token: {Token} + Tokens have to start and end with a '%', ex: %mytoken% + """, + token); + return new(default(Guid?)); + } + + if (_defaultReplacements.TryAdd(token, new ReplacementInfo(token, repFactory))) + { + var guid = Guid.NewGuid(); + _guids[guid] = token; + return new(guid); + } + + return new(default(Guid?)); + } + + public ValueTask Register(string token, Func> repFactory) + => InternalRegister(token, repFactory); + + public ValueTask Register(string token, Func> repFactory) + => InternalRegister(token, repFactory); + + public ValueTask Register(string token, Func> repFactory) + => InternalRegister(token, repFactory); + + public ValueTask Register(string token, Func repFactory) + => InternalRegister(token, () => new ValueTask(repFactory())); + + public ValueTask Register(string token, Func repFactory) + => InternalRegister(token, (T1 a) => new ValueTask(repFactory(a))); + + public ValueTask Register(string token, Func repFactory) + => InternalRegister(token, (T1 a, T2 b) => new ValueTask(repFactory(a, b))); + + + private ValueTask InternalRegexRegister(Regex regex, Delegate repFactory) + { + var regexPattern = regex.ToString(); + if (!regexPattern.StartsWith('%') || !regexPattern.EndsWith('%')) + { + Log.Warning( + """ + Invalid replacement pattern: {Token} + Tokens have to start and end with a '%', ex: %mytoken% + """, + regex); + return new(default(Guid?)); + } + + if (_regexReplacements.TryAdd(regexPattern, new RegexReplacementInfo(regex, repFactory))) + { + var guid = Guid.NewGuid(); + _guids[guid] = regex; + return new(guid); + } + + return new(default(Guid?)); + } + + public ValueTask Register(Regex regex, Func repFactory) + => InternalRegexRegister(regex, () => (Match m) => new ValueTask(repFactory(m))); + + public ValueTask Register(Regex regex, Func repFactory) + => InternalRegexRegister(regex, (T1 a) => (Match m) => new ValueTask(repFactory(m, a))); + + public bool Unregister(Guid guid) + { + if (_guids.TryRemove(guid, out var pattern)) + { + return pattern.Match( + token => _defaultReplacements.TryRemove(token, out _), + regex => _regexReplacements.TryRemove(regex.ToString(), out _)); + } + + return false; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs new file mode 100644 index 0000000..d42bba6 --- /dev/null +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs @@ -0,0 +1,113 @@ +using System.Text.RegularExpressions; + +namespace EllieBot.Common; + +public sealed partial class ReplacementPatternStore +{ + private static readonly Regex _rngRegex = new(@"%rng(?:(?(?:-)?\d+)-(?(?:-)?\d+))?%", + RegexOptions.Compiled); + + + private void WithDefault() + { + Register("%bot.time%", + static () + => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials())); + } + + private void WithClient() + { + Register("%bot.status%", static (DiscordSocketClient client) => client.Status.ToString()); + Register("%bot.latency%", static (DiscordSocketClient client) => client.Latency.ToString()); + Register("%bot.name%", static (DiscordSocketClient client) => client.CurrentUser.Username); + Register("%bot.fullname%", static (DiscordSocketClient client) => client.CurrentUser.ToString()); + Register("%bot.discrim%", static (DiscordSocketClient client) => client.CurrentUser.Discriminator); + Register("%bot.id%", static (DiscordSocketClient client) => client.CurrentUser.Id.ToString()); + Register("%bot.avatar%", + static (DiscordSocketClient client) => client.CurrentUser.RealAvatarUrl().ToString()); + + Register("%bot.mention%", static (DiscordSocketClient client) => client.CurrentUser.Mention); + + Register("%shard.servercount%", static (DiscordSocketClient c) => c.Guilds.Count.ToString()); + Register("%shard.usercount%", + static (DiscordSocketClient c) => c.Guilds.Sum(g => g.MemberCount).ToString()); + Register("%shard.id%", static (DiscordSocketClient c) => c.ShardId.ToString()); + } + + private void WithServer() + { + Register("%server%", static (IGuild g) => g.Name); + Register("%server.id%", static (IGuild g) => g.Id.ToString()); + Register("%server.name%", static (IGuild g) => g.Name); + Register("%server.icon%", static (IGuild g) => g.IconUrl); + Register("%server.members%", static (IGuild g) => (g as SocketGuild)?.MemberCount.ToString() ?? "?"); + Register("%server.boosters%", static (IGuild g) => g.PremiumSubscriptionCount.ToString()); + Register("%server.boost_level%", static (IGuild g) => ((int)g.PremiumTier).ToString()); + } + + private void WithChannel() + { + Register("%channel%", static (IMessageChannel ch) => ch.Name); + Register("%channel.mention%", + static (IMessageChannel ch) => (ch as ITextChannel)?.Mention ?? "#" + ch.Name); + Register("%channel.name%", static (IMessageChannel ch) => ch.Name); + Register("%channel.id%", static (IMessageChannel ch) => ch.Id.ToString()); + Register("%channel.created%", + static (IMessageChannel ch) => ch.CreatedAt.ToString("HH:mm dd.MM.yyyy")); + Register("%channel.nsfw%", + static (IMessageChannel ch) => (ch as ITextChannel)?.IsNsfw.ToString() ?? "-"); + Register("%channel.topic%", static (IMessageChannel ch) => (ch as ITextChannel)?.Topic ?? "-"); + } + + private void WithUsers() + { + Register("%user%", + static (IUser[] users) => string.Join(" ", users.Select(user => user.Mention))); + Register("%user.mention%", + static (IUser[] users) => string.Join(" ", users.Select(user => user.Mention))); + Register("%user.fullname%", + static (IUser[] users) => string.Join(" ", users.Select(user => user.ToString()))); + Register("%user.name%", + static (IUser[] users) => string.Join(" ", users.Select(user => user.Username))); + Register("%user.discrim%", + static (IUser[] users) => string.Join(" ", users.Select(user => user.Discriminator))); + Register("%user.avatar%", + static (IUser[] users) + => string.Join(" ", users.Select(user => user.RealAvatarUrl().ToString()))); + Register("%user.id%", + static (IUser[] users) => string.Join(" ", users.Select(user => user.Id.ToString()))); + Register("%user.created_time%", + static (IUser[] users) + => string.Join(" ", users.Select(user => user.CreatedAt.ToString("HH:mm")))); + Register("%user.created_date%", + static (IUser[] users) + => string.Join(" ", users.Select(user => user.CreatedAt.ToString("dd.MM.yyyy")))); + Register("%user.joined_time%", + static (IUser[] users) => string.Join(" ", + users.Select(user => (user as IGuildUser)?.JoinedAt?.ToString("HH:mm") ?? "-"))); + Register("%user.joined_date%", + static (IUser[] users) => string.Join(" ", + users.Select(user => (user as IGuildUser)?.JoinedAt?.ToString("dd.MM.yyyy") ?? "-"))); + } + + private void WithRegex() + { + Register(_rngRegex, + match => + { + var rng = new EllieRandom(); + if (!int.TryParse(match.Groups["from"].ToString(), out var from)) + from = 0; + if (!int.TryParse(match.Groups["to"].ToString(), out var to)) + to = 0; + + if (from == 0 && to == 0) + return rng.Next(0, 11).ToString(); + + if (from >= to) + return string.Empty; + + return rng.Next(from, to + 1).ToString(); + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementService.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementService.cs new file mode 100644 index 0000000..4d17213 --- /dev/null +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementService.cs @@ -0,0 +1,137 @@ +namespace EllieBot.Common; + +public sealed class ReplacementService : IReplacementService, IEService +{ + private readonly IReplacementPatternStore _repReg; + + public ReplacementService(IReplacementPatternStore repReg) + { + _repReg = repReg; + } + + public async ValueTask ReplaceAsync(SmartText input, ReplacementContext repCtx) + { + var reps = GetReplacementsForContext(repCtx); + var regReps = GetRegexReplacementsForContext(repCtx); + + var inputData = GetInputData(repCtx); + var rep = new Replacer(reps.Values, regReps.Values, inputData); + + return await rep.ReplaceAsync(input); + } + + public async ValueTask ReplaceAsync(string input, ReplacementContext repCtx) + { + var reps = GetReplacementsForContext(repCtx); + var regReps = GetRegexReplacementsForContext(repCtx); + + var inputData = GetInputData(repCtx); + var rep = new Replacer(reps.Values, regReps.Values, inputData); + + return await rep.ReplaceAsync(input); + } + + private object[] GetInputData(ReplacementContext repCtx) + { + var obj = new List(); + if (repCtx.Client is not null) + obj.Add(repCtx.Client); + + if (repCtx.Guild is not null) + obj.Add(repCtx.Guild); + + if (repCtx.Users is not null) + obj.Add(repCtx.Users); + + if (repCtx.Channel is not null) + obj.Add(repCtx.Channel); + + return obj.ToArray(); + } + + private IDictionary GetReplacementsForContext(ReplacementContext repCtx) + { + var reps = GetOriginalReplacementsForContext(repCtx); + foreach (var ovrd in repCtx.Overrides) + { + reps.Remove(ovrd.Token); + reps.TryAdd(ovrd.Token, ovrd); + } + + return reps; + } + + private IDictionary GetRegexReplacementsForContext(ReplacementContext repCtx) + { + var reps = GetOriginalRegexReplacementsForContext(repCtx); + foreach (var ovrd in repCtx.RegexOverrides) + { + reps.Remove(ovrd.Pattern); + reps.TryAdd(ovrd.Pattern, ovrd); + } + + return reps; + } + + private IDictionary GetOriginalReplacementsForContext(ReplacementContext repCtx) + { + var objs = new List(); + if (repCtx.Client is not null) + { + objs.Add(repCtx.Client); + } + + if (repCtx.Channel is not null) + { + objs.Add(repCtx.Channel); + } + + if (repCtx.Users is not null) + { + objs.Add(repCtx.Users); + } + + if (repCtx.Guild is not null) + { + objs.Add(repCtx.Guild); + } + + var types = objs.Map(x => x.GetType()).OrderBy(x => x.Name).ToHashSet(); + + return _repReg.Replacements + .Values + .Where(rep => rep.InputTypes.All(t => types.Any(x => x.IsAssignableTo((t))))) + .ToDictionary(rep => rep.Token, rep => rep); + } + + private IDictionary GetOriginalRegexReplacementsForContext(ReplacementContext repCtx) + { + var objs = new List(); + if (repCtx.Client is not null) + { + objs.Add(repCtx.Client); + } + + if (repCtx.Channel is not null) + { + objs.Add(repCtx.Channel); + } + + if (repCtx.Users is not null) + { + objs.Add(repCtx.Users); + } + + if (repCtx.Guild is not null) + { + objs.Add(repCtx.Guild); + } + + var types = objs.Map(x => x.GetType()).OrderBy(x => x.Name).ToHashSet(); + + return _repReg.RegexReplacements + .Values + .Where(rep => rep.InputTypes.All(t => types.Any(x => x.IsAssignableTo((t))))) + .ToDictionary(rep => rep.Pattern, rep => rep); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Replacements/Impl/Replacer.cs b/src/EllieBot/_common/Replacements/Impl/Replacer.cs new file mode 100644 index 0000000..9b43331 --- /dev/null +++ b/src/EllieBot/_common/Replacements/Impl/Replacer.cs @@ -0,0 +1,138 @@ +using System.Text; +using System.Text.RegularExpressions; + +namespace EllieBot.Common; + +public sealed partial class Replacer +{ + private readonly IEnumerable _reps; + private readonly IEnumerable _regexReps; + private readonly object[] _inputData; + + [GeneratedRegex(@"\%[\p{L}\p{N}\._]*[\p{L}\p{N}]+[\p{L}\p{N}\._]*\%")] + private static partial Regex TokenExtractionRegex(); + + public Replacer(IEnumerable reps, IEnumerable regexReps, object[] inputData) + { + _reps = reps; + _inputData = inputData; + _regexReps = regexReps; + } + + public async ValueTask ReplaceAsync(string? input) + { + if (string.IsNullOrWhiteSpace(input)) + return input; + + var matches = TokenExtractionRegex().IsMatch(input); + + if (matches) + { + foreach (var rep in _reps) + { + if (input.Contains(rep.Token, StringComparison.InvariantCulture)) + { + var objs = GetParams(rep.InputTypes); + input = input.Replace(rep.Token, await rep.GetValueAsync(objs), StringComparison.InvariantCulture); + } + } + } + + foreach (var rep in _regexReps) + { + var sb = new StringBuilder(); + + var objs = GetParams(rep.InputTypes); + var match = rep.Regex.Match(input); + if (match.Success) + { + sb.Append(input, 0, match.Index) + .Append(await rep.GetValueAsync(match, objs)); + + var lastIndex = match.Index + match.Length; + sb.Append(input, lastIndex, input.Length - lastIndex); + input = sb.ToString(); + } + } + + return input; + } + + private object?[]? GetParams(IReadOnlyCollection inputTypes) + { + if (inputTypes.Count == 0) + return null; + + var objs = new List(); + foreach (var t in inputTypes) + { + var datum = _inputData.FirstOrDefault(x => x.GetType().IsAssignableTo(t)); + if (datum is not null) + objs.Add(datum); + } + + return objs.ToArray(); + } + + public async ValueTask ReplaceAsync(SmartText data) + => data switch + { + SmartEmbedText embedData => await ReplaceAsync(embedData) with + { + PlainText = await ReplaceAsync(embedData.PlainText), + Color = embedData.Color + }, + SmartPlainText plain => await ReplaceAsync(plain), + SmartEmbedTextArray arr => await ReplaceAsync(arr), + _ => throw new ArgumentOutOfRangeException(nameof(data), "Unsupported argument type") + }; + + private async Task ReplaceAsync(SmartEmbedTextArray embedArr) + => new() + { + Embeds = await embedArr.Embeds.Map(async e => await ReplaceAsync(e) with + { + Color = e.Color + }).WhenAll(), + Content = await ReplaceAsync(embedArr.Content) + }; + + private async ValueTask ReplaceAsync(SmartPlainText plain) + => await ReplaceAsync(plain.Text); + + private async Task ReplaceAsync(T embedData) where T : SmartEmbedTextBase, new() + { + var newEmbedData = new T + { + Description = await ReplaceAsync(embedData.Description), + Title = await ReplaceAsync(embedData.Title), + Thumbnail = await ReplaceAsync(embedData.Thumbnail), + Image = await ReplaceAsync(embedData.Image), + Url = await ReplaceAsync(embedData.Url), + Author = embedData.Author is null + ? null + : new() + { + Name = await ReplaceAsync(embedData.Author.Name), + IconUrl = await ReplaceAsync(embedData.Author.IconUrl) + }, + Fields = await Task.WhenAll(embedData + .Fields? + .Map(async f => new SmartTextEmbedField + { + Name = await ReplaceAsync(f.Name), + Value = await ReplaceAsync(f.Value), + Inline = f.Inline + }) ?? []), + Footer = embedData.Footer is null + ? null + : new() + { + Text = await ReplaceAsync(embedData.Footer.Text), + IconUrl = await ReplaceAsync(embedData.Footer.IconUrl) + } + }; + + return newEmbedData; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/RequireObjectPropertiesContractResolver.cs b/src/EllieBot/_common/RequireObjectPropertiesContractResolver.cs new file mode 100644 index 0000000..74a0367 --- /dev/null +++ b/src/EllieBot/_common/RequireObjectPropertiesContractResolver.cs @@ -0,0 +1,15 @@ +#nullable disable +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace EllieBot.Common; + +public class RequireObjectPropertiesContractResolver : DefaultContractResolver +{ + protected override JsonObjectContract CreateObjectContract(Type objectType) + { + var contract = base.CreateObjectContract(objectType); + contract.ItemRequired = Required.DisallowNull; + return contract; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Sender/IMessageSenderService.cs b/src/EllieBot/_common/Sender/IMessageSenderService.cs new file mode 100644 index 0000000..ccc8c0f --- /dev/null +++ b/src/EllieBot/_common/Sender/IMessageSenderService.cs @@ -0,0 +1,12 @@ +namespace EllieBot.Extensions; + +public interface IMessageSenderService +{ + ResponseBuilder Response(IMessageChannel channel); + ResponseBuilder Response(ICommandContext ctx); + ResponseBuilder Response(IUser user); + + ResponseBuilder Response(SocketMessageComponent smc); + + EllieEmbedBuilder CreateEmbed(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Sender/MessageSenderService.cs b/src/EllieBot/_common/Sender/MessageSenderService.cs new file mode 100644 index 0000000..f91f1ab --- /dev/null +++ b/src/EllieBot/_common/Sender/MessageSenderService.cs @@ -0,0 +1,57 @@ +using EllieBot.Common.Configs; +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Extensions; + +public sealed class MessageSenderService : IMessageSenderService, IEService +{ + private readonly IBotStrings _bs; + private readonly BotConfigService _bcs; + private readonly DiscordSocketClient _client; + + public MessageSenderService(IBotStrings bs, BotConfigService bcs, DiscordSocketClient client) + { + _bs = bs; + _bcs = bcs; + _client = client; + } + + + public ResponseBuilder Response(IMessageChannel channel) + => new ResponseBuilder(_bs, _bcs, _client) + .Channel(channel); + + public ResponseBuilder Response(ICommandContext ctx) + => new ResponseBuilder(_bs, _bcs, _client) + .Context(ctx); + + public ResponseBuilder Response(IUser user) + => new ResponseBuilder(_bs, _bcs, _client) + .User(user); + + public ResponseBuilder Response(SocketMessageComponent smc) + => new ResponseBuilder(_bs, _bcs, _client) + .Channel(smc.Channel); + + public EllieEmbedBuilder CreateEmbed() + => new EllieEmbedBuilder(_bcs); +} + +public class EllieEmbedBuilder : EmbedBuilder +{ + private readonly BotConfig _bc; + + public EllieEmbedBuilder(BotConfigService bcs) + { + _bc = bcs.Data; + } + + public EmbedBuilder WithOkColor() + => WithColor(_bc.Color.Ok.ToDiscordColor()); + + public EmbedBuilder WithErrorColor() + => WithColor(_bc.Color.Error.ToDiscordColor()); + + public EmbedBuilder WithPendingColor() + => WithColor(_bc.Color.Pending.ToDiscordColor()); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs b/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs new file mode 100644 index 0000000..a1dee4d --- /dev/null +++ b/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs @@ -0,0 +1,153 @@ +namespace EllieBot.Extensions; + +public partial class ResponseBuilder +{ + public class PaginationSender + { + private const string BUTTON_LEFT = "BUTTON_LEFT"; + private const string BUTTON_RIGHT = "BUTTON_RIGHT"; + + private readonly SourcedPaginatedResponseBuilder _paginationBuilder; + private readonly ResponseBuilder _builder; + private readonly DiscordSocketClient _client; + private int currentPage; + + public PaginationSender( + SourcedPaginatedResponseBuilder paginationBuilder, + ResponseBuilder builder) + { + _paginationBuilder = paginationBuilder; + _builder = builder; + + _client = builder.Client; + currentPage = paginationBuilder.InitialPage; + } + + public async Task SendAsync(bool ephemeral = false) + { + var lastPage = (_paginationBuilder.Elems - 1) + / _paginationBuilder.ItemsPerPage; + + var items = (await _paginationBuilder.ItemsFunc(currentPage)).ToArray(); + var embed = await _paginationBuilder.PageFunc(items, currentPage); + + if (_paginationBuilder.AddPaginatedFooter) + embed.AddPaginatedFooter(currentPage, lastPage); + + EllieInteractionBase? maybeInter = null; + + var model = await _builder.BuildAsync(ephemeral); + + async Task<(EllieButtonInteractionHandler left, EllieInteractionBase? extra, EllieButtonInteractionHandler right)> + GetInteractions() + { + var leftButton = new ButtonBuilder() + .WithStyle(ButtonStyle.Primary) + .WithCustomId(BUTTON_LEFT) + .WithEmote(InteractionHelpers.ArrowLeft) + .WithDisabled(lastPage == 0 || currentPage <= 0); + + var leftBtnInter = new EllieButtonInteractionHandler(_client, + model.User?.Id ?? 0, + leftButton, + (smc) => + { + try + { + if (currentPage > 0) + currentPage--; + + _ = UpdatePageAsync(smc); + } + catch (Exception ex) + { + Log.Error(ex, "Error in pagination: {ErrorMessage}", ex.Message); + } + + return Task.CompletedTask; + }, + true, + singleUse: false); + + if (_paginationBuilder.InteractionFunc is not null) + { + maybeInter = await _paginationBuilder.InteractionFunc(currentPage); + } + + var rightButton = new ButtonBuilder() + .WithStyle(ButtonStyle.Primary) + .WithCustomId(BUTTON_RIGHT) + .WithEmote(InteractionHelpers.ArrowRight) + .WithDisabled(lastPage == 0 || currentPage >= lastPage); + + var rightBtnInter = new EllieButtonInteractionHandler(_client, + model.User?.Id ?? 0, + rightButton, + (smc) => + { + try + { + if (currentPage >= lastPage) + return Task.CompletedTask; + + currentPage++; + + _ = UpdatePageAsync(smc); + } + catch (Exception ex) + { + Log.Error(ex, "Error in pagination: {ErrorMessage}", ex.Message); + } + + return Task.CompletedTask; + }, + true, + singleUse: false); + + return (leftBtnInter, maybeInter, rightBtnInter); + } + + async Task UpdatePageAsync(SocketMessageComponent smc) + { + var pageItems = (await _paginationBuilder.ItemsFunc(currentPage)).ToArray(); + var toSend = await _paginationBuilder.PageFunc(pageItems, currentPage); + if (_paginationBuilder.AddPaginatedFooter) + toSend.AddPaginatedFooter(currentPage, lastPage); + + var (left, extra, right) = (await GetInteractions()); + + var cb = new ComponentBuilder(); + left.AddTo(cb); + right.AddTo(cb); + extra?.AddTo(cb); + + await smc.ModifyOriginalResponseAsync(x => + { + x.Embed = toSend.Build(); + x.Components = cb.Build(); + }); + } + + var (left, extra, right) = await GetInteractions(); + + var cb = new ComponentBuilder(); + left.AddTo(cb); + right.AddTo(cb); + extra?.AddTo(cb); + + var msg = await model.TargetChannel + .SendMessageAsync(model.Text, + embed: embed.Build(), + components: cb.Build(), + allowedMentions: model.SanitizeMentions, + messageReference: model.MessageReference); + + if (lastPage == 0 && _paginationBuilder.InteractionFunc is null) + return; + + await Task.WhenAll(left.RunAsync(msg), extra?.RunAsync(msg) ?? Task.CompletedTask, right.RunAsync(msg)); + + await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build()); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Sender/ResponseBuilder.cs b/src/EllieBot/_common/Sender/ResponseBuilder.cs new file mode 100644 index 0000000..60783de --- /dev/null +++ b/src/EllieBot/_common/Sender/ResponseBuilder.cs @@ -0,0 +1,492 @@ +using EllieBot.Common.Configs; +using EllieBot.Db.Models; +using System.Collections.ObjectModel; + +namespace EllieBot.Extensions; + +public sealed partial class ResponseBuilder +{ + private ICommandContext? ctx; + private IMessageChannel? channel; + private string? plainText; + private IReadOnlyCollection? embeds; + private IUserMessage? msg; + private IUser? user; + private bool sanitizeMentions = true; + private LocStr? locTxt; + private object[] locParams = []; + private bool shouldReply = true; + private readonly IBotStrings _bs; + private readonly BotConfigService _bcs; + private EmbedBuilder? embedBuilder; + private EllieInteractionBase? inter; + private Stream? fileStream; + private string? fileName; + private EmbedColor color = EmbedColor.Ok; + private LocStr? embedLocDesc; + + public DiscordSocketClient Client { get; set; } + + public ResponseBuilder(IBotStrings bs, BotConfigService bcs, DiscordSocketClient client) + { + _bs = bs; + _bcs = bcs; + Client = client; + } + + + private MessageReference? CreateMessageReference(IMessageChannel targetChannel) + { + if (!shouldReply) + return null; + + var replyTo = msg ?? ctx?.Message; + // what message are we replying to + if (replyTo is null) + return null; + + // we have to have a channel where we are sending the message in order to know whether we can reply to it + if (targetChannel.Id != replyTo.Channel.Id) + return null; + + return new(replyTo.Id, + replyTo.Channel.Id, + (replyTo.Channel as ITextChannel)?.GuildId, + failIfNotExists: false); + } + + public async Task BuildAsync(bool ephemeral) + { + var targetChannel = await InternalResolveChannel() ?? throw new ArgumentNullException(nameof(channel)); + var msgReference = CreateMessageReference(targetChannel); + + var txt = GetText(locTxt, targetChannel); + + if (embedLocDesc is LocStr ls) + { + InternalCreateEmbed(null, GetText(ls, targetChannel)); + } + + if (embedBuilder is not null) + PaintEmbedInternal(embedBuilder); + + var finalEmbed = embedBuilder?.Build(); + + + var buildModel = new ResponseMessageModel() + { + TargetChannel = targetChannel, + MessageReference = msgReference, + Text = txt, + User = user ?? ctx?.User, + Embed = finalEmbed, + Embeds = embeds?.Map(x => x.Build()), + SanitizeMentions = sanitizeMentions ? new(AllowedMentionTypes.Users) : AllowedMentions.All, + Ephemeral = ephemeral, + Interaction = inter + }; + + return buildModel; + } + + public async Task SendAsync(bool ephemeral = false) + { + var model = await BuildAsync(ephemeral); + var sentMsg = await SendAsync(model); + + + return sentMsg; + } + + public async Task SendAsync(ResponseMessageModel model) + { + IUserMessage sentMsg; + if (fileStream is Stream stream) + { + sentMsg = await model.TargetChannel.SendFileAsync(stream, + filename: fileName, + model.Text, + embed: model.Embed, + components: inter?.CreateComponent(), + allowedMentions: model.SanitizeMentions, + messageReference: model.MessageReference); + } + else + { + sentMsg = await model.TargetChannel.SendMessageAsync( + model.Text, + embed: model.Embed, + embeds: model.Embeds, + components: inter?.CreateComponent(), + allowedMentions: model.SanitizeMentions, + messageReference: model.MessageReference); + } + + if (model.Interaction is not null) + { + await model.Interaction.RunAsync(sentMsg); + } + + return sentMsg; + } + + private EmbedBuilder PaintEmbedInternal(EmbedBuilder eb) + => color switch + { + EmbedColor.Ok => eb.WithOkColor(), + EmbedColor.Pending => eb.WithPendingColor(), + EmbedColor.Error => eb.WithErrorColor(), + _ => throw new NotSupportedException() + }; + + private ulong? InternalResolveGuildId(IMessageChannel? targetChannel) + => ctx?.Guild?.Id ?? (targetChannel as ITextChannel)?.GuildId; + + private async Task InternalResolveChannel() + { + if (user is not null) + { + var ch = await user.CreateDMChannelAsync(); + + if (ch is not null) + { + return ch; + } + } + + return channel ?? ctx?.Channel ?? msg?.Channel; + } + + private string? GetText(LocStr? locStr, IMessageChannel targetChannel) + { + var guildId = InternalResolveGuildId(targetChannel); + return locStr is LocStr ls ? _bs.GetText(ls.Key, guildId, locParams) : plainText; + } + + private string GetText(LocStr locStr, IMessageChannel targetChannel) + { + var guildId = InternalResolveGuildId(targetChannel); + return _bs.GetText(locStr.Key, guildId, locStr.Params); + } + + public ResponseBuilder Text(LocStr str) + { + locTxt = str; + return this; + } + + public ResponseBuilder Text(SmartText text) + { + if (text is SmartPlainText spt) + plainText = spt.Text; + else if (text is SmartEmbedText set) + { + plainText = set.PlainText ?? plainText; + embedBuilder = set.GetEmbed(); + } + else if (text is SmartEmbedTextArray ser) + { + plainText = ser.Content ?? plainText; + embeds = ser.GetEmbedBuilders(); + } + + return this; + } + + private void InternalCreateEmbed( + string? title, + string text, + string? url = null, + string? footer = null) + { + var eb = new EllieEmbedBuilder(_bcs) + .WithDescription(text); + + if (!string.IsNullOrWhiteSpace(title)) + eb.WithTitle(title); + + if (!string.IsNullOrWhiteSpace(url)) + eb = eb.WithUrl(url); + + if (!string.IsNullOrWhiteSpace(footer)) + eb = eb.WithFooter(footer); + + embedBuilder = eb; + } + + public ResponseBuilder Confirm( + string? title, + string text, + string? url = null, + string? footer = null) + { + InternalCreateEmbed(title, text, url, footer); + color = EmbedColor.Ok; + return this; + } + + public ResponseBuilder Error( + string? title, + string text, + string? url = null, + string? footer = null) + { + InternalCreateEmbed(title, text, url, footer); + color = EmbedColor.Error; + return this; + } + + public ResponseBuilder Pending( + string? title, + string text, + string? url = null, + string? footer = null) + { + InternalCreateEmbed(title, text, url, footer); + color = EmbedColor.Pending; + return this; + } + + public ResponseBuilder Confirm(string text) + { + InternalCreateEmbed(null, text); + color = EmbedColor.Ok; + return this; + } + + public ResponseBuilder Confirm(LocStr str) + { + embedLocDesc = str; + color = EmbedColor.Ok; + return this; + } + + public ResponseBuilder Pending(string text) + { + InternalCreateEmbed(null, text); + color = EmbedColor.Pending; + return this; + } + + public ResponseBuilder Pending(LocStr str) + { + embedLocDesc = str; + color = EmbedColor.Pending; + return this; + } + + public ResponseBuilder Error(string text) + { + InternalCreateEmbed(null, text); + color = EmbedColor.Error; + return this; + } + + public ResponseBuilder Error(LocStr str) + { + embedLocDesc = str; + color = EmbedColor.Error; + return this; + } + + public ResponseBuilder UserBasedMentions() + { + sanitizeMentions = !((InternalResolveUser() as IGuildUser)?.GuildPermissions.MentionEveryone ?? false); + return this; + } + + private IUser? InternalResolveUser() + => ctx?.User ?? user ?? msg?.Author; + + public ResponseBuilder Embed(EmbedBuilder eb) + { + embedBuilder = eb; + return this; + } + + public ResponseBuilder Channel(IMessageChannel ch) + { + channel = ch; + return this; + } + + public ResponseBuilder Sanitize(bool shouldSantize = true) + { + sanitizeMentions = shouldSantize; + return this; + } + + public ResponseBuilder Context(ICommandContext context) + { + ctx = context; + return this; + } + + public ResponseBuilder Message(IUserMessage message) + { + msg = message; + return this; + } + + public ResponseBuilder User(IUser usr) + { + user = usr; + return this; + } + + public ResponseBuilder NoReply() + { + shouldReply = false; + return this; + } + + public ResponseBuilder Interaction(EllieInteractionBase? interaction) + { + inter = interaction; + return this; + } + + public ResponseBuilder Embeds(IReadOnlyCollection inputEmbeds) + { + embeds = inputEmbeds; + return this; + } + + public ResponseBuilder File(Stream stream, string name) + { + fileStream = stream; + fileName = name; + return this; + } + + public PaginatedResponseBuilder Paginated() + => new(this); +} + +public class PaginatedResponseBuilder +{ + protected readonly ResponseBuilder _builder; + + public PaginatedResponseBuilder(ResponseBuilder builder) + { + _builder = builder; + } + + public SourcedPaginatedResponseBuilder Items(IReadOnlyCollection items) + => new SourcedPaginatedResponseBuilder(_builder) + .Items(items); + + public SourcedPaginatedResponseBuilder PageItems(Func>> items) + => new SourcedPaginatedResponseBuilder(_builder) + .PageItems(items); +} + +public sealed class SourcedPaginatedResponseBuilder : PaginatedResponseBuilder +{ + private IReadOnlyCollection? items; + + public Func, int, Task> PageFunc { get; private set; } = static delegate + { + return Task.FromResult(new()); + }; + + public Func>> ItemsFunc { get; set; } = static delegate + { + return Task.FromResult>(ReadOnlyCollection.Empty); + }; + + public Func>? InteractionFunc { get; private set; } + + public int? Elems { get; private set; } = 1; + public int ItemsPerPage { get; private set; } = 9; + public bool AddPaginatedFooter { get; private set; } = true; + public bool IsEphemeral { get; private set; } + + public int InitialPage { get; set; } + + public SourcedPaginatedResponseBuilder(ResponseBuilder builder) + : base(builder) + { + } + + public SourcedPaginatedResponseBuilder Items(IReadOnlyCollection col) + { + items = col; + Elems = col.Count; + ItemsFunc = (i) => Task.FromResult(items.Skip(i * ItemsPerPage).Take(ItemsPerPage).ToArray() as IReadOnlyCollection); + return this; + } + + public SourcedPaginatedResponseBuilder TotalElements(int i) + { + Elems = i; + return this; + } + + public SourcedPaginatedResponseBuilder PageItems(Func>> func) + { + Elems = null; + ItemsFunc = func; + return this; + } + + + public SourcedPaginatedResponseBuilder PageSize(int i) + { + ItemsPerPage = i; + return this; + } + + public SourcedPaginatedResponseBuilder CurrentPage(int i) + { + InitialPage = i; + return this; + } + + + public SourcedPaginatedResponseBuilder Page(Func, int, EmbedBuilder> pageFunc) + { + PageFunc = (xs, x) => Task.FromResult(pageFunc(xs, x)); + return this; + } + + public SourcedPaginatedResponseBuilder Page(Func, int, Task> pageFunc) + { + PageFunc = pageFunc; + return this; + } + + public SourcedPaginatedResponseBuilder AddFooter(bool addFooter = true) + { + AddPaginatedFooter = addFooter; + return this; + } + + public SourcedPaginatedResponseBuilder Ephemeral() + { + IsEphemeral = true; + return this; + } + + + public Task SendAsync() + { + var paginationSender = new ResponseBuilder.PaginationSender( + this, + _builder); + + return paginationSender.SendAsync(IsEphemeral); + } + + public SourcedPaginatedResponseBuilder Interaction(Func> func) + { + InteractionFunc = func; //async (i) => await func(i); + return this; + } + + public SourcedPaginatedResponseBuilder Interaction(EllieInteractionBase inter) + { + InteractionFunc = _ => Task.FromResult(inter); + return this; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Sender/ResponseBuilderExtensions.cs b/src/EllieBot/_common/Sender/ResponseBuilderExtensions.cs new file mode 100644 index 0000000..40123a6 --- /dev/null +++ b/src/EllieBot/_common/Sender/ResponseBuilderExtensions.cs @@ -0,0 +1,28 @@ +namespace EllieBot.Extensions; + +public static class ResponseBuilderExtensions +{ + public static EmbedBuilder WithPendingColor(this EmbedBuilder eb) + { + if (eb is EllieEmbedBuilder neb) + return neb.WithPendingColor(); + + return eb; + } + + public static EmbedBuilder WithOkColor(this EmbedBuilder eb) + { + if (eb is EllieEmbedBuilder neb) + return neb.WithOkColor(); + + return eb; + } + + public static EmbedBuilder WithErrorColor(this EmbedBuilder eb) + { + if (eb is EllieEmbedBuilder neb) + return neb.WithErrorColor(); + + return eb; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Sender/ResponseMessageModel.cs b/src/EllieBot/_common/Sender/ResponseMessageModel.cs new file mode 100644 index 0000000..675cd09 --- /dev/null +++ b/src/EllieBot/_common/Sender/ResponseMessageModel.cs @@ -0,0 +1,12 @@ +public class ResponseMessageModel +{ + public required IMessageChannel TargetChannel { get; set; } + public MessageReference? MessageReference { get; set; } + public string? Text { get; set; } + public Embed? Embed { get; set; } + public Embed[]? Embeds { get; set; } + public required AllowedMentions SanitizeMentions { get; set; } + public IUser? User { get; set; } + public bool Ephemeral { get; set; } + public EllieInteractionBase? Interaction { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/ServiceCollectionExtensions.cs b/src/EllieBot/_common/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..4b468d2 --- /dev/null +++ b/src/EllieBot/_common/ServiceCollectionExtensions.cs @@ -0,0 +1,131 @@ +using DryIoc; +using LinqToDB.Extensions; +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Modules.Music; +using EllieBot.Modules.Music.Resolvers; +using EllieBot.Modules.Music.Services; +using StackExchange.Redis; +using System.Net; +using System.Reflection; +using EllieBot.Common.ModuleBehaviors; + +namespace EllieBot.Extensions; + +public static class ServiceCollectionExtensions +{ + public static IContainer AddBotStringsServices(this IContainer svcs, BotCacheImplemenation botCache) + { + if (botCache == BotCacheImplemenation.Memory) + { + svcs.AddSingleton(); + svcs.AddSingleton(); + } + else + { + svcs.AddSingleton(); + svcs.AddSingleton(); + } + + svcs.AddSingleton(); + + return svcs; + } + + public static IContainer AddConfigServices(this IContainer svcs, Assembly a) + { + + foreach (var type in a.GetTypes() + .Where(x => !x.IsAbstract && x.IsAssignableToGenericType(typeof(ConfigServiceBase<>)))) + { + svcs.RegisterMany([type], + getServiceTypes: type => type.GetImplementedTypes(ReflectionTools.AsImplementedType.SourceType), + getImplFactory: type => ReflectionFactory.Of(type, Reuse.Singleton)); + } + + return svcs; + } + + + public static IContainer AddMusic(this IContainer svcs) + { + svcs.RegisterMany(Reuse.Singleton); + + svcs.AddSingleton(); + svcs.AddSingleton(); + svcs.AddSingleton(); + svcs.AddSingleton(); + svcs.AddSingleton(); + + return svcs; + } + + public static IContainer AddCache(this IContainer cont, IBotCredentials creds) + { + if (creds.BotCache == BotCacheImplemenation.Redis) + { + var conf = ConfigurationOptions.Parse(creds.RedisOptions); + cont.AddSingleton(ConnectionMultiplexer.Connect(conf)); + cont.AddSingleton(); + cont.AddSingleton(); + } + else + { + cont.AddSingleton(); + cont.AddSingleton(); + } + + return cont + .AddBotStringsServices(creds.BotCache); + } + + public static IContainer AddHttpClients(this IContainer svcs) + { + IServiceCollection proxySvcs = new ServiceCollection(); + proxySvcs.AddHttpClient(); + proxySvcs.AddHttpClient("memelist") + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler + { + AllowAutoRedirect = false + }); + + proxySvcs.AddHttpClient("google:search") + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() + { + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }); + + var prov = proxySvcs.BuildServiceProvider(); + + svcs.RegisterDelegate(_ => prov.GetRequiredService()); + svcs.RegisterDelegate(_ => prov.GetRequiredService()); + + return svcs; + } + + public static IContainer AddLifetimeServices(this IContainer svcs, Assembly a) + { + Type[] types = + [ + typeof(IExecOnMessage), + typeof(IExecPreCommand), + typeof(IExecPostCommand), + typeof(IExecNoCommand), + typeof(IInputTransformer), + typeof(IEService) + ]; + + foreach (var svc in a.GetTypes() + .Where(type => type.IsClass && types.Any(t => type.IsAssignableTo(t)) && !type.HasAttribute() +#if GLOBAL_ELLIE + && !type.HasAttribute() +#endif + )) + { + svcs.RegisterMany([svc], + getServiceTypes: type => type.GetImplementedTypes(ReflectionTools.AsImplementedType.SourceType), + getImplFactory: type => ReflectionFactory.Of(type, Reuse.Singleton)); + } + + return svcs; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/CommandHandler.cs b/src/EllieBot/_common/Services/CommandHandler.cs new file mode 100644 index 0000000..c058887 --- /dev/null +++ b/src/EllieBot/_common/Services/CommandHandler.cs @@ -0,0 +1,433 @@ +#nullable disable +using EllieBot.Common.Configs; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using ExecuteResult = Discord.Commands.ExecuteResult; +using PreconditionResult = Discord.Commands.PreconditionResult; + +namespace EllieBot.Services; + +public class CommandHandler : IEService, IReadyExecutor, ICommandHandler +{ + private const int GLOBAL_COMMANDS_COOLDOWN = 750; + + private const float ONE_THOUSANDTH = 1.0f / 1000; + + public event Func CommandExecuted = delegate { return Task.CompletedTask; }; + public event Func CommandErrored = delegate { return Task.CompletedTask; }; + + //userid/msg count + public ConcurrentDictionary UserMessagesSent { get; } = new(); + + public ConcurrentHashSet UsersOnShortCooldown { get; } = new(); + + private readonly DiscordSocketClient _client; + private readonly CommandService _commandService; + private readonly BotConfigService _bcs; + private readonly IBot _bot; + private readonly IBehaviorHandler _behaviorHandler; + private readonly IServiceProvider _services; + + private readonly ConcurrentDictionary _prefixes; + + private readonly DbService _db; + + private readonly BotConfig _bc; + // private readonly InteractionService _interactions; + + public CommandHandler( + DiscordSocketClient client, + DbService db, + CommandService commandService, + BotConfigService bcs, + IBot bot, + IBehaviorHandler behaviorHandler, + // InteractionService interactions, + IServiceProvider services) + { + _client = client; + _commandService = commandService; + _bc = bcs.Data; + _bcs = bcs; + _bot = bot; + _behaviorHandler = behaviorHandler; + _db = db; + _services = services; + // _interactions = interactions; + + _prefixes = bot.AllGuildConfigs.Where(x => x.Prefix is not null) + .ToDictionary(x => x.GuildId, x => x.Prefix) + .ToConcurrent(); + } + + public async Task OnReadyAsync() + { + // clear users on short cooldown every GLOBAL_COMMANDS_COOLDOWN miliseconds + using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(GLOBAL_COMMANDS_COOLDOWN)); + while (await timer.WaitForNextTickAsync()) + UsersOnShortCooldown.Clear(); + } + + public string GetPrefix(IGuild guild) + => GetPrefix(guild?.Id); + + public string GetPrefix(ulong? id = null) + { + if (id is null || !_prefixes.TryGetValue(id.Value, out var prefix)) + return _bcs.Data.Prefix; + + return prefix; + } + + public string SetDefaultPrefix(string prefix) + { + if (string.IsNullOrWhiteSpace(prefix)) + throw new ArgumentNullException(nameof(prefix)); + + _bcs.ModifyConfig(bs => + { + bs.Prefix = prefix; + }); + + return prefix; + } + + public string SetPrefix(IGuild guild, string prefix) + { + ArgumentNullException.ThrowIfNullOrWhiteSpace(prefix); + ArgumentNullException.ThrowIfNull(guild); + + using (var uow = _db.GetDbContext()) + { + var gc = uow.GuildConfigsForId(guild.Id, set => set); + gc.Prefix = prefix; + uow.SaveChanges(); + } + + _prefixes[guild.Id] = prefix; + + return prefix; + } + + public async Task ExecuteExternal(ulong? guildId, ulong channelId, string commandText) + { + if (guildId is not null) + { + var guild = _client.GetGuild(guildId.Value); + if (guild?.GetChannel(channelId) is not SocketTextChannel channel) + { + Log.Warning("Channel for external execution not found"); + return; + } + + try + { + IUserMessage msg = await channel.SendMessageAsync(commandText); + msg = (IUserMessage)await channel.GetMessageAsync(msg.Id); + await TryRunCommand(guild, channel, msg); + //msg.DeleteAfter(5); + } + catch { } + } + } + + public Task StartHandling() + { + _client.MessageReceived += MessageReceivedHandler; + // _client.SlashCommandExecuted += SlashCommandExecuted; + return Task.CompletedTask; + } + + // private async Task SlashCommandExecuted(SocketSlashCommand arg) + // { + // var ctx = new SocketInteractionContext(_client, arg); + // await _interactions.ExecuteCommandAsync(ctx, _services); + // } + + private Task LogSuccessfulExecution(IUserMessage usrMsg, ITextChannel channel, params int[] execPoints) + { + if (_bcs.Data.ConsoleOutputType == ConsoleOutputType.Normal) + { + Log.Information(""" + Command Executed after {ExecTime}s + User: {User} + Server: {Server} + Channel: {Channel} + Message: {Message} + """, + string.Join("/", execPoints.Select(x => (x * ONE_THOUSANDTH).ToString("F3"))), + usrMsg.Author + " [" + usrMsg.Author.Id + "]", + channel is null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]", + channel is null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]", + usrMsg.Content); + } + else + { + Log.Information("Succ | g:{GuildId} | c: {ChannelId} | u: {UserId} | msg: {Message}", + channel?.Guild.Id.ToString() ?? "-", + channel?.Id.ToString() ?? "-", + usrMsg.Author.Id, + usrMsg.Content.TrimTo(10)); + } + + return Task.CompletedTask; + } + + private void LogErroredExecution( + string errorMessage, + IUserMessage usrMsg, + ITextChannel channel, + params int[] execPoints) + { + if (_bcs.Data.ConsoleOutputType == ConsoleOutputType.Normal) + { + Log.Warning(""" + Command Errored after {ExecTime}s + User: {User} + Server: {Guild} + Channel: {Channel} + Message: {Message} + Error: {ErrorMessage} + """, + string.Join("/", execPoints.Select(x => (x * ONE_THOUSANDTH).ToString("F3"))), + usrMsg.Author + " [" + usrMsg.Author.Id + "]", + channel is null ? "DM" : channel.Guild.Name + " [" + channel.Guild.Id + "]", + channel is null ? "DM" : channel.Name + " [" + channel.Id + "]", + usrMsg.Content, + errorMessage); + } + else + { + Log.Warning(""" + Err | g:{GuildId} | c: {ChannelId} | u: {UserId} | msg: {Message} + Err: {ErrorMessage} + """, + channel?.Guild.Id.ToString() ?? "-", + channel?.Id.ToString() ?? "-", + usrMsg.Author.Id, + usrMsg.Content.TrimTo(10), + errorMessage); + } + } + + private Task MessageReceivedHandler(SocketMessage msg) + { + if (!_bot.IsReady) + return Task.CompletedTask; + + if (_bc.IgnoreOtherBots) + { + if (msg.Author.IsBot) + return Task.CompletedTask; + } + else if (msg.Author.Id == _client.CurrentUser.Id) + return Task.CompletedTask; + + if (msg is not SocketUserMessage usrMsg) + return Task.CompletedTask; + + Task.Run(async () => + { + try + { +#if !GLOBAL_ELLIE + // track how many messages each user is sending + UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (_, old) => ++old); +#endif + + var channel = msg.Channel; + var guild = (msg.Channel as SocketTextChannel)?.Guild; + + await TryRunCommand(guild, channel, usrMsg); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in CommandHandler"); + if (ex.InnerException is not null) + Log.Warning(ex.InnerException, "Inner Exception of the error in CommandHandler"); + } + }); + + return Task.CompletedTask; + } + + public async Task TryRunCommand(SocketGuild guild, ISocketMessageChannel channel, IUserMessage usrMsg) + { + var startTime = Environment.TickCount; + + var blocked = await _behaviorHandler.RunExecOnMessageAsync(guild, usrMsg); + if (blocked) + return; + + var blockTime = Environment.TickCount - startTime; + + var messageContent = await _behaviorHandler.RunInputTransformersAsync(guild, usrMsg); + + var prefix = GetPrefix(guild?.Id); + var isPrefixCommand = messageContent.StartsWith(".prefix", StringComparison.InvariantCultureIgnoreCase); + // execute the command and measure the time it took + if (isPrefixCommand || messageContent.StartsWith(prefix, StringComparison.InvariantCulture)) + { + var context = new CommandContext(_client, usrMsg); + var (success, error, info) = await ExecuteCommandAsync(context, + messageContent, + isPrefixCommand ? 1 : prefix.Length, + _services, + MultiMatchHandling.Best); + + startTime = Environment.TickCount - startTime; + + // if a command is found + if (info is not null) + { + // if it successfully executed + if (success) + { + await LogSuccessfulExecution(usrMsg, channel as ITextChannel, blockTime, startTime); + await CommandExecuted(usrMsg, info); + await _behaviorHandler.RunPostCommandAsync(context, info.Module.GetTopLevelModule().Name, info); + return; + } + + // if it errored + if (error is not null) + { + error = HumanizeError(error); + LogErroredExecution(error, usrMsg, channel as ITextChannel, blockTime, startTime); + + if (guild is not null) + await CommandErrored(info, channel as ITextChannel, error); + + return; + } + } + } + + await _behaviorHandler.RunOnNoCommandAsync(guild, usrMsg); + } + + private string HumanizeError(string error) + { + if (error.Contains("parse int", StringComparison.OrdinalIgnoreCase) + || error.Contains("parse float")) + return "Invalid number specified. Make sure you're specifying parameters in the correct order."; + + return error; + } + + public Task<(bool Success, string Error, CommandInfo Info)> ExecuteCommandAsync( + ICommandContext context, + string input, + int argPos, + IServiceProvider serviceProvider, + MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) + => ExecuteCommand(context, input[argPos..], serviceProvider, multiMatchHandling); + + + public async Task<(bool Success, string Error, CommandInfo Info)> ExecuteCommand( + ICommandContext context, + string input, + IServiceProvider services, + MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) + { + var searchResult = _commandService.Search(context, input); + if (!searchResult.IsSuccess) + return (false, null, null); + + var commands = searchResult.Commands; + var preconditionResults = new Dictionary(); + + foreach (var match in commands) + preconditionResults[match] = await match.Command.CheckPreconditionsAsync(context, services); + + var successfulPreconditions = preconditionResults.Where(x => x.Value.IsSuccess).ToArray(); + + if (successfulPreconditions.Length == 0) + { + //All preconditions failed, return the one from the highest priority command + var bestCandidate = preconditionResults.OrderByDescending(x => x.Key.Command.Priority) + .FirstOrDefault(x => !x.Value.IsSuccess); + return (false, bestCandidate.Value.ErrorReason, commands[0].Command); + } + + var parseResultsDict = new Dictionary(); + foreach (var pair in successfulPreconditions) + { + var parseResult = await pair.Key.ParseAsync(context, searchResult, pair.Value, services); + + if (parseResult.Error == CommandError.MultipleMatches) + { + IReadOnlyList argList, paramList; + switch (multiMatchHandling) + { + case MultiMatchHandling.Best: + argList = parseResult.ArgValues + .Map(x => x.Values.MaxBy(y => y.Score)); + paramList = parseResult.ParamValues + .Map(x => x.Values.MaxBy(y => y.Score)); + parseResult = ParseResult.FromSuccess(argList, paramList); + break; + } + } + + parseResultsDict[pair.Key] = parseResult; + } + + // Calculates the 'score' of a command given a parse result + float CalculateScore(CommandMatch match, ParseResult parseResult) + { + float argValuesScore = 0, paramValuesScore = 0; + + if (match.Command.Parameters.Count > 0) + { + var argValuesSum = + parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) + ?? 0; + var paramValuesSum = + parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) + ?? 0; + + argValuesScore = argValuesSum / match.Command.Parameters.Count; + paramValuesScore = paramValuesSum / match.Command.Parameters.Count; + } + + var totalArgsScore = (argValuesScore + paramValuesScore) / 2; + return match.Command.Priority + (totalArgsScore * 0.99f); + } + + //Order the parse results by their score so that we choose the most likely result to execute + var parseResults = parseResultsDict.OrderByDescending(x => CalculateScore(x.Key, x.Value)).ToList(); + + var successfulParses = parseResults.Where(x => x.Value.IsSuccess).ToArray(); + + if (successfulParses.Length == 0) + { + //All parses failed, return the one from the highest priority command, using score as a tie breaker + var bestMatch = parseResults.FirstOrDefault(x => !x.Value.IsSuccess); + return (false, bestMatch.Value.ErrorReason, commands[0].Command); + } + + var cmd = successfulParses[0].Key.Command; + + // Bot will ignore commands which are ran more often than what specified by + // GlobalCommandsCooldown constant (miliseconds) + if (!UsersOnShortCooldown.Add(context.Message.Author.Id)) + return (false, null, cmd); + //return SearchResult.FromError(CommandError.Exception, "You are on a global cooldown."); + + var blocked = await _behaviorHandler.RunPreCommandAsync(context, cmd); + if (blocked) + return (false, null, cmd); + + //If we get this far, at least one parse was successful. Execute the most likely overload. + var chosenOverload = successfulParses[0]; + var execResult = (ExecuteResult)await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services); + + if (execResult.Exception is not null + && (execResult.Exception is not HttpException he + || he.DiscordCode != DiscordErrorCode.InsufficientPermissions)) + Log.Warning(execResult.Exception, "Command Error"); + + return (true, null, cmd); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Currency/CurrencyService.cs b/src/EllieBot/_common/Services/Currency/CurrencyService.cs new file mode 100644 index 0000000..9cb4037 --- /dev/null +++ b/src/EllieBot/_common/Services/Currency/CurrencyService.cs @@ -0,0 +1,116 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Services.Currency; + +namespace EllieBot.Services; + +public sealed class CurrencyService : ICurrencyService, IEService +{ + private readonly DbService _db; + private readonly ITxTracker _txTracker; + + public CurrencyService(DbService db, ITxTracker txTracker) + { + _db = db; + _txTracker = txTracker; + } + + public Task GetWalletAsync(ulong userId, CurrencyType type = CurrencyType.Default) + { + if (type == CurrencyType.Default) + return Task.FromResult(new DefaultWallet(userId, _db)); + + throw new ArgumentOutOfRangeException(nameof(type)); + } + + public async Task AddBulkAsync( + IReadOnlyCollection userIds, + long amount, + TxData txData, + CurrencyType type = CurrencyType.Default) + { + if (type == CurrencyType.Default) + { + foreach (var userId in userIds) + { + var wallet = await GetWalletAsync(userId); + await wallet.Add(amount, txData); + } + + return; + } + + throw new ArgumentOutOfRangeException(nameof(type)); + } + + public async Task RemoveBulkAsync( + IReadOnlyCollection userIds, + long amount, + TxData txData, + CurrencyType type = CurrencyType.Default) + { + if (type == CurrencyType.Default) + { + await using var ctx = _db.GetDbContext(); + await ctx + .GetTable() + .Where(x => userIds.Contains(x.UserId)) + .UpdateAsync(du => new() + { + CurrencyAmount = du.CurrencyAmount >= amount + ? du.CurrencyAmount - amount + : 0 + }); + await ctx.SaveChangesAsync(); + return; + } + + throw new ArgumentOutOfRangeException(nameof(type)); + } + + public async Task AddAsync( + ulong userId, + long amount, + TxData txData) + { + var wallet = await GetWalletAsync(userId); + await wallet.Add(amount, txData); + await _txTracker.TrackAdd(amount, txData); + } + + public async Task AddAsync( + IUser user, + long amount, + TxData txData) + => await AddAsync(user.Id, amount, txData); + + public async Task RemoveAsync( + ulong userId, + long amount, + TxData txData) + { + if (amount == 0) + return true; + + var wallet = await GetWalletAsync(userId); + var result = await wallet.Take(amount, txData); + if (result) + await _txTracker.TrackRemove(amount, txData); + return result; + } + + public async Task RemoveAsync( + IUser user, + long amount, + TxData txData) + => await RemoveAsync(user.Id, amount, txData); + + public async Task> GetTopRichest(ulong ignoreId, int page = 0, int perPage = 9) + { + await using var uow = _db.GetDbContext(); + return await uow.Set().GetTopRichest(ignoreId, page, perPage); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Currency/CurrencyServiceExtensions.cs b/src/EllieBot/_common/Services/Currency/CurrencyServiceExtensions.cs new file mode 100644 index 0000000..7007ee4 --- /dev/null +++ b/src/EllieBot/_common/Services/Currency/CurrencyServiceExtensions.cs @@ -0,0 +1,48 @@ +using EllieBot.Services.Currency; + +namespace EllieBot.Services; + +public static class CurrencyServiceExtensions +{ + public static async Task GetBalanceAsync(this ICurrencyService cs, ulong userId) + { + var wallet = await cs.GetWalletAsync(userId); + return await wallet.GetBalance(); + } + + // FUTURE should be a transaction + public static async Task TransferAsync( + this ICurrencyService cs, + IMessageSenderService sender, + IUser from, + IUser to, + long amount, + string? note, + string formattedAmount) + { + var fromWallet = await cs.GetWalletAsync(from.Id); + var toWallet = await cs.GetWalletAsync(to.Id); + + var extra = new TxData("gift", from.ToString()!, note, from.Id); + + if (await fromWallet.Transfer(amount, toWallet, extra)) + { + try + { + await sender.Response(to) + .Confirm(string.IsNullOrWhiteSpace(note) + ? $"Received {formattedAmount} from {from} " + : $"Received {formattedAmount} from {from}: {note}") + .SendAsync(); + } + catch + { + //ignored + } + + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Currency/DefaultWallet.cs b/src/EllieBot/_common/Services/Currency/DefaultWallet.cs new file mode 100644 index 0000000..a556985 --- /dev/null +++ b/src/EllieBot/_common/Services/Currency/DefaultWallet.cs @@ -0,0 +1,108 @@ +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Services.Currency; + +public class DefaultWallet : IWallet +{ + private readonly DbService _db; + public ulong UserId { get; } + + public DefaultWallet(ulong userId, DbService db) + { + UserId = userId; + _db = db; + } + + public async Task GetBalance() + { + await using var ctx = _db.GetDbContext(); + var userId = UserId; + return await ctx + .GetTable() + .Where(x => x.UserId == userId) + .Select(x => x.CurrencyAmount) + .FirstOrDefaultAsync(); + } + + public async Task Take(long amount, TxData? txData) + { + if (amount < 0) + throw new ArgumentOutOfRangeException(nameof(amount), "Amount to take must be non negative."); + + await using var ctx = _db.GetDbContext(); + + var userId = UserId; + var changed = await ctx + .GetTable() + .Where(x => x.UserId == userId && x.CurrencyAmount >= amount) + .UpdateAsync(x => new() + { + CurrencyAmount = x.CurrencyAmount - amount + }); + + if (changed == 0) + return false; + + if (txData is not null) + { + await ctx + .GetTable() + .InsertAsync(() => new() + { + Amount = -amount, + Note = txData.Note, + UserId = userId, + Type = txData.Type, + Extra = txData.Extra, + OtherId = txData.OtherId, + DateAdded = DateTime.UtcNow + }); + } + + return true; + } + + public async Task Add(long amount, TxData? txData) + { + if (amount <= 0) + throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0."); + + await using var ctx = _db.GetDbContext(); + var userId = UserId; + + + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + UserId = userId, + Username = "Unknown", + Discriminator = "????", + CurrencyAmount = amount, + }, + (old) => new() + { + CurrencyAmount = old.CurrencyAmount + amount + }, + () => new() + { + UserId = userId + }); + + if (txData is not null) + { + await ctx.GetTable() + .InsertAsync(() => new() + { + Amount = amount, + UserId = userId, + Note = txData.Note, + Type = txData.Type, + Extra = txData.Extra, + OtherId = txData.OtherId, + DateAdded = DateTime.UtcNow + }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Currency/GamblingTxTracker.cs b/src/EllieBot/_common/Services/Currency/GamblingTxTracker.cs new file mode 100644 index 0000000..5751281 --- /dev/null +++ b/src/EllieBot/_common/Services/Currency/GamblingTxTracker.cs @@ -0,0 +1,110 @@ +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Services.Currency; +using EllieBot.Db.Models; + +namespace EllieBot.Services; + +public sealed class GamblingTxTracker : ITxTracker, IEService, IReadyExecutor +{ + private static readonly IReadOnlySet _gamblingTypes = new HashSet(new[] + { + "lula", + "betroll", + "betflip", + "blackjack", + "betdraw", + "slot", + }); + + private ConcurrentDictionary _stats = new(); + + private readonly DbService _db; + + public GamblingTxTracker(DbService db) + { + _db = db; + } + + public async Task OnReadyAsync() + { + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + while (await timer.WaitForNextTickAsync()) + { + await using var ctx = _db.GetDbContext(); + await using var trans = await ctx.Database.BeginTransactionAsync(); + + try + { + var keys = _stats.Keys; + foreach (var key in keys) + { + if (_stats.TryRemove(key, out var stat)) + { + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + Feature = key, + Bet = stat.Bet, + PaidOut = stat.PaidOut, + DateAdded = DateTime.UtcNow + }, old => new() + { + Bet = old.Bet + stat.Bet, + PaidOut = old.PaidOut + stat.PaidOut, + }, () => new() + { + Feature = key + }); + } + } + } + catch (Exception ex) + { + Log.Error(ex, "An error occurred in gambling tx tracker"); + } + finally + { + await trans.CommitAsync(); + } + } + } + + public Task TrackAdd(long amount, TxData? txData) + { + if (txData is null) + return Task.CompletedTask; + + if (_gamblingTypes.Contains(txData.Type)) + { + _stats.AddOrUpdate(txData.Type, + _ => (0, amount), + (_, old) => (old.Bet, old.PaidOut + amount)); + } + + return Task.CompletedTask; + } + + public Task TrackRemove(long amount, TxData? txData) + { + if (txData is null) + return Task.CompletedTask; + + if (_gamblingTypes.Contains(txData.Type)) + { + _stats.AddOrUpdate(txData.Type, + _ => (amount, 0), + (_, old) => (old.Bet + amount, old.PaidOut)); + } + + return Task.CompletedTask; + } + + public async Task> GetAllAsync() + { + await using var ctx = _db.GetDbContext(); + return await ctx.Set() + .ToListAsyncEF(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/IBehaviourHandler.cs b/src/EllieBot/_common/Services/IBehaviourHandler.cs new file mode 100644 index 0000000..79e8e5a --- /dev/null +++ b/src/EllieBot/_common/Services/IBehaviourHandler.cs @@ -0,0 +1,17 @@ +#nullable disable +namespace EllieBot.Services; + +public interface IBehaviorHandler +{ + Task AddAsync(ICustomBehavior behavior); + Task AddRangeAsync(IEnumerable behavior); + Task RemoveAsync(ICustomBehavior behavior); + Task RemoveRangeAsync(IEnumerable behs); + + Task RunExecOnMessageAsync(SocketGuild guild, IUserMessage usrMsg); + Task RunInputTransformersAsync(SocketGuild guild, IUserMessage usrMsg); + Task RunPreCommandAsync(ICommandContext context, CommandInfo cmd); + ValueTask RunPostCommandAsync(ICommandContext ctx, string moduleName, CommandInfo cmd); + Task RunOnNoCommandAsync(SocketGuild guild, IUserMessage usrMsg); + void Initialize(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/ICommandHandler.cs b/src/EllieBot/_common/Services/ICommandHandler.cs new file mode 100644 index 0000000..f838743 --- /dev/null +++ b/src/EllieBot/_common/Services/ICommandHandler.cs @@ -0,0 +1,12 @@ +namespace EllieBot.Services; + +public interface ICommandHandler +{ + string GetPrefix(IGuild ctxGuild); + string GetPrefix(ulong? id = null); + string SetDefaultPrefix(string toSet); + string SetPrefix(IGuild ctxGuild, string toSet); + ConcurrentDictionary UserMessagesSent { get; } + + Task TryRunCommand(SocketGuild guild, ISocketMessageChannel channel, IUserMessage usrMsg); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/ICoordinator.cs b/src/EllieBot/_common/Services/ICoordinator.cs new file mode 100644 index 0000000..10ec4ae --- /dev/null +++ b/src/EllieBot/_common/Services/ICoordinator.cs @@ -0,0 +1,20 @@ +#nullable disable +namespace EllieBot.Services; + +public interface ICoordinator +{ + bool RestartBot(); + void Die(bool graceful); + bool RestartShard(int shardId); + IList GetAllShardStatuses(); + int GetGuildCount(); + Task Reload(); +} + +public class ShardStatus +{ + public ConnectionState ConnectionState { get; set; } + public DateTime LastUpdate { get; set; } + public int ShardId { get; set; } + public int GuildCount { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/ICustomBehavior.cs b/src/EllieBot/_common/Services/ICustomBehavior.cs new file mode 100644 index 0000000..2e4bedb --- /dev/null +++ b/src/EllieBot/_common/Services/ICustomBehavior.cs @@ -0,0 +1,13 @@ +using EllieBot.Common.ModuleBehaviors; + +namespace EllieBot.Services; + +public interface ICustomBehavior + : IExecOnMessage, + IInputTransformer, + IExecPreCommand, + IExecNoCommand, + IExecPostCommand +{ + +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/IEService.cs b/src/EllieBot/_common/Services/IEService.cs new file mode 100644 index 0000000..944d8cc --- /dev/null +++ b/src/EllieBot/_common/Services/IEService.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Services; + +/// +/// All services must implement this interface in order to be auto-discovered by the DI system +/// +public interface IEService +{ +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/IGoogleApiService.cs b/src/EllieBot/_common/Services/IGoogleApiService.cs new file mode 100644 index 0000000..856bd51 --- /dev/null +++ b/src/EllieBot/_common/Services/IGoogleApiService.cs @@ -0,0 +1,18 @@ +#nullable disable +namespace EllieBot.Services; + +public interface IGoogleApiService +{ + IReadOnlyDictionary Languages { get; } + + Task> GetVideoLinksByKeywordAsync(string keywords, int count = 1); + Task> GetVideoInfosByKeywordAsync(string keywords, int count = 1); + Task> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1); + Task> GetRelatedVideosAsync(string id, int count = 1, string user = null); + Task> GetPlaylistTracksAsync(string playlistId, int count = 50); + Task> GetVideoDurationsAsync(IEnumerable videoIds); + Task Translate(string sourceText, string sourceLanguage, string targetLanguage); + + Task ShortenUrl(string url); + Task ShortenUrl(Uri url); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/ILocalDataCache.cs b/src/EllieBot/_common/Services/ILocalDataCache.cs new file mode 100644 index 0000000..e6977e3 --- /dev/null +++ b/src/EllieBot/_common/Services/ILocalDataCache.cs @@ -0,0 +1,13 @@ +#nullable disable +using EllieBot.Common.Pokemon; +using EllieBot.Modules.Games.Common.Trivia; + +namespace EllieBot.Services; + +public interface ILocalDataCache +{ + Task> GetPokemonsAsync(); + Task> GetPokemonAbilitiesAsync(); + Task GetTriviaQuestionsAsync(); + Task> GetPokemonMapAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/ILocalization.cs b/src/EllieBot/_common/Services/ILocalization.cs new file mode 100644 index 0000000..3fa7c5e --- /dev/null +++ b/src/EllieBot/_common/Services/ILocalization.cs @@ -0,0 +1,19 @@ +#nullable disable +using System.Globalization; + +namespace EllieBot.Services; + +public interface ILocalization +{ + CultureInfo DefaultCultureInfo { get; } + IDictionary GuildCultureInfos { get; } + + CultureInfo GetCultureInfo(IGuild guild); + CultureInfo GetCultureInfo(ulong? guildId); + void RemoveGuildCulture(IGuild guild); + void RemoveGuildCulture(ulong guildId); + void ResetDefaultCulture(); + void SetDefaultCulture(CultureInfo ci); + void SetGuildCulture(IGuild guild, CultureInfo ci); + void SetGuildCulture(ulong guildId, CultureInfo ci); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/IRemindService.cs b/src/EllieBot/_common/Services/IRemindService.cs new file mode 100644 index 0000000..5a057c8 --- /dev/null +++ b/src/EllieBot/_common/Services/IRemindService.cs @@ -0,0 +1,15 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Utility.Services; + +public interface IRemindService +{ + Task AddReminderAsync(ulong userId, + ulong targetId, + ulong? guildId, + bool isPrivate, + DateTime time, + string message, + ReminderType reminderType); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/IStatsService.cs b/src/EllieBot/_common/Services/IStatsService.cs new file mode 100644 index 0000000..3dee0a6 --- /dev/null +++ b/src/EllieBot/_common/Services/IStatsService.cs @@ -0,0 +1,70 @@ +#nullable disable +namespace EllieBot.Services; + +public interface IStatsService +{ + /// + /// The author of the bot. + /// + string Author { get; } + + /// + /// The total amount of commands ran since startup. + /// + long CommandsRan { get; } + + /// + /// The amount of messages seen by the bot since startup. + /// + long MessageCounter { get; } + + /// + /// The rate of messages the bot sees every second. + /// + double MessagesPerSecond { get; } + + /// + /// The total amount of text channels the bot can see. + /// + long TextChannels { get; } + + /// + /// The total amount of voice channels the bot can see. + /// + long VoiceChannels { get; } + + /// + /// Gets for how long the bot has been up since startup. + /// + TimeSpan GetUptime(); + + /// + /// Gets a formatted string of how long the bot has been up since startup. + /// + /// The formatting separator. + string GetUptimeString(string separator = ", "); + + /// + /// Gets total amount of private memory currently in use by the bot, in Megabytes. + /// + double GetPrivateMemoryMegabytes(); + + GuildInfo GetGuildInfo(string name); + GuildInfo GetGuildInfo(ulong id); +} + +public record struct GuildInfo +{ + public required string Name { get; init; } + public required string IconUrl { get; init; } + public required string Owner { get; init; } + public required ulong OwnerId { get; init; } + public required ulong Id { get; init; } + public required int TextChannels { get; init; } + public required int VoiceChannels { get; init; } + public required DateTime CreatedAt { get; init; } + public required IReadOnlyList Features { get; init; } + public required IReadOnlyList Emojis { get; init; } + public required IReadOnlyList Roles { get; init; } + public int MemberCount { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/ITimezoneService.cs b/src/EllieBot/_common/Services/ITimezoneService.cs new file mode 100644 index 0000000..aa8cbff --- /dev/null +++ b/src/EllieBot/_common/Services/ITimezoneService.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Common; + +public interface ITimezoneService +{ + TimeZoneInfo GetTimeZoneOrUtc(ulong? guildId); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/BehaviorExecutor.cs b/src/EllieBot/_common/Services/Impl/BehaviorExecutor.cs new file mode 100644 index 0000000..7e471a0 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/BehaviorExecutor.cs @@ -0,0 +1,302 @@ +#nullable disable +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Common.ModuleBehaviors; + +namespace EllieBot.Services; + +// should be renamed to handler as it's not only executing +public sealed class BehaviorHandler : IBehaviorHandler +{ + private readonly IServiceProvider _services; + + private IReadOnlyCollection noCommandExecs; + private IReadOnlyCollection preCommandExecs; + private IReadOnlyCollection onMessageExecs; + private IReadOnlyCollection inputTransformers; + + private readonly SemaphoreSlim _customLock = new(1, 1); + private readonly List _customExecs = new(); + + public BehaviorHandler(IServiceProvider services) + { + _services = services; + } + + public void Initialize() + { + noCommandExecs = _services.GetServices().ToArray(); + preCommandExecs = _services.GetServices().OrderByDescending(x => x.Priority).ToArray(); + onMessageExecs = _services.GetServices().OrderByDescending(x => x.Priority).ToArray(); + inputTransformers = _services.GetServices().ToArray(); + } + + #region Add/Remove + + public async Task AddRangeAsync(IEnumerable execs) + { + await _customLock.WaitAsync(); + try + { + foreach (var exe in execs) + { + if (_customExecs.Contains(exe)) + continue; + + _customExecs.Add(exe); + } + } + finally + { + _customLock.Release(); + } + } + + public async Task AddAsync(ICustomBehavior behavior) + { + await _customLock.WaitAsync(); + try + { + if (_customExecs.Contains(behavior)) + return false; + + _customExecs.Add(behavior); + return true; + } + finally + { + _customLock.Release(); + } + } + + public async Task RemoveAsync(ICustomBehavior behavior) + { + await _customLock.WaitAsync(); + try + { + return _customExecs.Remove(behavior); + } + finally + { + _customLock.Release(); + } + } + + public async Task RemoveRangeAsync(IEnumerable behs) + { + await _customLock.WaitAsync(); + try + { + foreach(var beh in behs) + _customExecs.Remove(beh); + } + finally + { + _customLock.Release(); + } + } + + #endregion + + #region Running + + public async Task RunExecOnMessageAsync(SocketGuild guild, IUserMessage usrMsg) + { + async Task Exec(IReadOnlyCollection execs) + where T : IExecOnMessage + { + foreach (var exec in execs) + { + try + { + if (await exec.ExecOnMessageAsync(guild, usrMsg)) + { + Log.Information("{TypeName} blocked message g:{GuildId} u:{UserId} c:{ChannelId} msg:{Message}", + GetExecName(exec), + guild?.Id, + usrMsg.Author.Id, + usrMsg.Channel.Id, + usrMsg.Content?.TrimTo(10)); + + return true; + } + } + catch (Exception ex) + { + Log.Error(ex, + "An error occurred in {TypeName} late blocker: {ErrorMessage}", + GetExecName(exec), + ex.Message); + } + } + + return false; + } + + if (await Exec(onMessageExecs)) + { + return true; + } + + await _customLock.WaitAsync(); + try + { + if (await Exec(_customExecs)) + return true; + } + finally + { + _customLock.Release(); + } + + return false; + } + + private string GetExecName(IBehavior exec) + => exec.Name; + + public async Task RunPreCommandAsync(ICommandContext ctx, CommandInfo cmd) + { + async Task Exec(IReadOnlyCollection execs) where T: IExecPreCommand + { + foreach (var exec in execs) + { + try + { + if (await exec.ExecPreCommandAsync(ctx, cmd.Module.GetTopLevelModule().Name, cmd)) + { + Log.Information("{TypeName} Pre-Command blocked [{User}] Command: [{Command}]", + GetExecName(exec), + ctx.User, + cmd.Aliases[0]); + return true; + } + } + catch (Exception ex) + { + Log.Error(ex, + "An error occurred in {TypeName} PreCommand: {ErrorMessage}", + GetExecName(exec), + ex.Message); + } + } + + return false; + } + + if (await Exec(preCommandExecs)) + return true; + + await _customLock.WaitAsync(); + try + { + if (await Exec(_customExecs)) + return true; + } + finally + { + _customLock.Release(); + } + + return false; + } + + public async Task RunOnNoCommandAsync(SocketGuild guild, IUserMessage usrMsg) + { + async Task Exec(IReadOnlyCollection execs) where T : IExecNoCommand + { + foreach (var exec in execs) + { + try + { + await exec.ExecOnNoCommandAsync(guild, usrMsg); + } + catch (Exception ex) + { + Log.Error(ex, + "An error occurred in {TypeName} OnNoCommand: {ErrorMessage}", + GetExecName(exec), + ex.Message); + } + } + } + + await Exec(noCommandExecs); + + await _customLock.WaitAsync(); + try + { + await Exec(_customExecs); + } + finally + { + _customLock.Release(); + } + } + + public async Task RunInputTransformersAsync(SocketGuild guild, IUserMessage usrMsg) + { + async Task Exec(IReadOnlyCollection execs, string content) + where T : IInputTransformer + { + foreach (var exec in execs) + { + try + { + var newContent = await exec.TransformInput(guild, usrMsg.Channel, usrMsg.Author, content); + if (newContent is not null) + { + Log.Information("{ExecName} transformed content {OldContent} -> {NewContent}", + GetExecName(exec), + content, + newContent); + return newContent; + } + } + catch (Exception ex) + { + Log.Warning(ex, "An error occured during InputTransform handling: {ErrorMessage}", ex.Message); + } + } + + return null; + } + + var newContent = await Exec(inputTransformers, usrMsg.Content); + if (newContent is not null) + return newContent; + + await _customLock.WaitAsync(); + try + { + newContent = await Exec(_customExecs, usrMsg.Content); + if (newContent is not null) + return newContent; + } + finally + { + _customLock.Release(); + } + + return usrMsg.Content; + } + + public async ValueTask RunPostCommandAsync(ICommandContext ctx, string moduleName, CommandInfo cmd) + { + foreach (var exec in _customExecs) + { + try + { + await exec.ExecPostCommandAsync(ctx, moduleName, cmd.Name); + } + catch (Exception ex) + { + Log.Warning(ex, + "An error occured during PostCommand handling in {ExecName}: {ErrorMessage}", + GetExecName(exec), + ex.Message); + } + } + } + + #endregion +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/BlacklistService.cs b/src/EllieBot/_common/Services/Impl/BlacklistService.cs new file mode 100644 index 0000000..ac01491 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/BlacklistService.cs @@ -0,0 +1,141 @@ +#nullable disable +using LinqToDB; +using LinqToDB.Data; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions.Services; + +public sealed class BlacklistService : IExecOnMessage +{ + public int Priority + => int.MaxValue; + + private readonly DbService _db; + private readonly IPubSub _pubSub; + private readonly IBotCredentials _creds; + private IReadOnlyList blacklist; + + private readonly TypedKey _blPubKey = new("blacklist.reload"); + + public BlacklistService(DbService db, IPubSub pubSub, IBotCredentials creds) + { + _db = db; + _pubSub = pubSub; + _creds = creds; + + Reload(false); + _pubSub.Sub(_blPubKey, OnReload); + } + + private ValueTask OnReload(BlacklistEntry[] newBlacklist) + { + blacklist = newBlacklist; + return default; + } + + public Task ExecOnMessageAsync(IGuild guild, IUserMessage usrMsg) + { + foreach (var bl in blacklist) + { + if (guild is not null && bl.Type == BlacklistType.Server && bl.ItemId == guild.Id) + { + Log.Information("Blocked input from blacklisted guild: {GuildName} [{GuildId}]", guild.Name, guild.Id); + + return Task.FromResult(true); + } + + if (bl.Type == BlacklistType.Channel && bl.ItemId == usrMsg.Channel.Id) + { + Log.Information("Blocked input from blacklisted channel: {ChannelName} [{ChannelId}]", + usrMsg.Channel.Name, + usrMsg.Channel.Id); + + return Task.FromResult(true); + } + + if (bl.Type == BlacklistType.User && bl.ItemId == usrMsg.Author.Id) + { + Log.Information("Blocked input from blacklisted user: {UserName} [{UserId}]", + usrMsg.Author.ToString(), + usrMsg.Author.Id); + + return Task.FromResult(true); + } + } + + return Task.FromResult(false); + } + + public IReadOnlyList GetBlacklist() + => blacklist; + + public void Reload(bool publish = true) + { + using var uow = _db.GetDbContext(); + var toPublish = uow.GetTable().ToArray(); + blacklist = toPublish; + if (publish) + _pubSub.Pub(_blPubKey, toPublish); + } + + public async Task Blacklist(BlacklistType type, ulong id) + { + if (_creds.OwnerIds.Contains(id)) + return; + + await using var uow = _db.GetDbContext(); + + await uow + .GetTable() + .InsertAsync(() => new() + { + ItemId = id, + Type = type, + }); + + if (type == BlacklistType.User) + { + await uow.GetTable() + .Where(x => x.UserId == id) + .UpdateAsync(_ => new() + { + CurrencyAmount = 0 + }); + } + + Reload(); + } + + public async Task UnBlacklist(BlacklistType type, ulong id) + { + await using var uow = _db.GetDbContext(); + await uow.GetTable() + .Where(bi => bi.ItemId == id && bi.Type == type) + .DeleteAsync(); + + Reload(); + } + + public async Task BlacklistUsers(IReadOnlyCollection toBlacklist) + { + await using var uow = _db.GetDbContext(); + var bc = uow.GetTable(); + await bc.BulkCopyAsync(toBlacklist.Select(uid => new BlacklistEntry + { + ItemId = uid, + Type = BlacklistType.User + })); + + var blList = toBlacklist.ToList(); + await uow.GetTable() + .Where(x => blList.Contains(x.UserId)) + .UpdateAsync(_ => new() + { + CurrencyAmount = 0 + }); + + Reload(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/CommandsUtilityService.cs b/src/EllieBot/_common/Services/Impl/CommandsUtilityService.cs new file mode 100644 index 0000000..ed57096 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/CommandsUtilityService.cs @@ -0,0 +1,184 @@ +using CommandLine; +using Ellie.Common.Marmalade; + +namespace EllieBot.Common; + +public sealed class CommandsUtilityService : ICommandsUtilityService, IEService +{ + private readonly CommandHandler _ch; + private readonly IBotStrings _strings; + private readonly DiscordPermOverrideService _dpos; + private readonly IMessageSenderService _sender; + private readonly ILocalization _loc; + private readonly IMarmaladeLoaderService _marmalades; + + public CommandsUtilityService( + CommandHandler ch, + IBotStrings strings, + DiscordPermOverrideService dpos, + IMessageSenderService sender, + ILocalization loc, + IMarmaladeLoaderService marmalades) + { + _ch = ch; + _strings = strings; + _dpos = dpos; + _sender = sender; + _loc = loc; + _marmalades = marmalades; + } + + public EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild) + { + var prefix = _ch.GetPrefix(guild); + + var str = $"**`{prefix + com.Aliases.First()}`**"; + var alias = com.Aliases.Skip(1).FirstOrDefault(); + if (alias is not null) + str += $" **| `{prefix + alias}`**"; + + var culture = _loc.GetCultureInfo(guild); + + var em = _sender.CreateEmbed() + .AddField(str, $"{com.RealSummary(_strings, _marmalades, culture, prefix)}", true); + + _dpos.TryGetOverrides(guild?.Id ?? 0, com.Name, out var overrides); + var reqs = GetCommandRequirements(com, (GuildPermission?)overrides); + if (reqs.Any()) + em.AddField(GetText(strs.requires, guild), string.Join("\n", reqs)); + + var paramList = _strings.GetCommandStrings(com.Name, culture)?.Params; + em + .WithOkColor() + .AddField(_strings.GetText(strs.usage), + string.Join("\n", com.RealRemarksArr(_strings, _marmalades, culture, prefix).Map(arg => Format.Code(arg)))) + .WithFooter(GetText(strs.module(com.Module.GetTopLevelModule().Name), guild)); + + if (paramList is not null and not []) + { + var pl = paramList + .Select(x => Format.Code($"{prefix}{com.Name} {x.Keys.Select(y => $"<{y}>").Join(' ')}")) + .Join('\n'); + + em.AddField(GetText(strs.overloads, guild), pl); + } + + var opt = GetEllieOptionType(com.Attributes); + if (opt is not null) + { + var hs = GetCommandOptionHelp(opt); + if (!string.IsNullOrWhiteSpace(hs)) + em.AddField(GetText(strs.options, guild), hs); + } + + return em; + } + + public static string GetCommandOptionHelp(Type opt) + { + var strs = GetCommandOptionHelpList(opt); + + return string.Join("\n", strs); + } + + public static List GetCommandOptionHelpList(Type opt) + { + var strs = opt.GetProperties() + .Select(x => x.GetCustomAttributes(true).FirstOrDefault(a => a is OptionAttribute)) + .Where(x => x is not null) + .Cast() + .Select(x => + { + var toReturn = $"`--{x.LongName}`"; + + if (!string.IsNullOrWhiteSpace(x.ShortName)) + toReturn += $" (`-{x.ShortName}`)"; + + toReturn += $" {x.HelpText} "; + return toReturn; + }) + .ToList(); + + return strs; + } + + public static Type? GetEllieOptionType(IEnumerable attributes) + => attributes + .Select(a => a.GetType()) + .Where(a => a.IsGenericType + && a.GetGenericTypeDefinition() == typeof(EllieOptionsAttribute<>)) + .Select(a => a.GenericTypeArguments[0]) + .FirstOrDefault(); + + public static string[] GetCommandRequirements(CommandInfo cmd, GuildPerm? overrides = null) + { + var toReturn = new List(); + + if (cmd.Preconditions.Any(x => x is OwnerOnlyAttribute)) + toReturn.Add("Bot Owner Only"); + + if (cmd.Preconditions.Any(x => x is NoPublicBotAttribute) + || cmd.Module + .Preconditions + .Any(x => x is NoPublicBotAttribute) + || cmd.Module.GetTopLevelModule() + .Preconditions + .Any(x => x is NoPublicBotAttribute)) + toReturn.Add("No Public Bot"); + + if (cmd.Preconditions + .Any(x => x is OnlyPublicBotAttribute) + || cmd.Module + .Preconditions + .Any(x => x is OnlyPublicBotAttribute) + || cmd.Module.GetTopLevelModule() + .Preconditions + .Any(x => x is OnlyPublicBotAttribute)) + toReturn.Add("Only Public Bot"); + + var userPermString = cmd.Preconditions + .Where(ca => ca is UserPermAttribute) + .Cast() + .Select(userPerm => + { + if (userPerm.ChannelPermission is { } cPerm) + return GetPreconditionString(cPerm); + + if (userPerm.GuildPermission is { } gPerm) + return GetPreconditionString(gPerm); + + return string.Empty; + }) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Join('\n'); + + if (overrides is null) + { + if (!string.IsNullOrWhiteSpace(userPermString)) + toReturn.Add(userPermString); + } + else + { + if (!string.IsNullOrWhiteSpace(userPermString)) + toReturn.Add(Format.Strikethrough(userPermString)); + + toReturn.Add(GetPreconditionString(overrides.Value)); + } + + return toReturn.ToArray(); + } + + public static string GetPreconditionString(ChannelPerm perm) + => (perm + " Channel Permission").Replace("Guild", "Server"); + + public static string GetPreconditionString(GuildPerm perm) + => (perm + " Server Permission").Replace("Guild", "Server"); + + public string GetText(LocStr str, IGuild? guild) + => _strings.GetText(str, guild?.Id); +} + +public interface ICommandsUtilityService +{ + EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/DiscordPermOverrideService.cs b/src/EllieBot/_common/Services/Impl/DiscordPermOverrideService.cs new file mode 100644 index 0000000..2eb7093 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/DiscordPermOverrideService.cs @@ -0,0 +1,136 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; + +namespace EllieBot.Services; + +public class DiscordPermOverrideService : IEService, IExecPreCommand, IDiscordPermOverrideService +{ + public int Priority { get; } = int.MaxValue; + private readonly DbService _db; + private readonly IServiceProvider _services; + + private readonly ConcurrentDictionary<(ulong, string), DiscordPermOverride> _overrides; + + public DiscordPermOverrideService(DbService db, IServiceProvider services) + { + _db = db; + _services = services; + using var uow = _db.GetDbContext(); + _overrides = uow.Set() + .AsNoTracking() + .AsEnumerable() + .ToDictionary(o => (o.GuildId ?? 0, o.Command), o => o) + .ToConcurrent(); + } + + public bool TryGetOverrides(ulong guildId, string commandName, out EllieBot.Db.GuildPerm? perm) + { + commandName = commandName.ToLowerInvariant(); + if (_overrides.TryGetValue((guildId, commandName), out var dpo)) + { + perm = dpo.Perm; + return true; + } + + perm = null; + return false; + } + + public Task ExecuteOverrides( + ICommandContext ctx, + CommandInfo command, + GuildPerm perms, + IServiceProvider services) + { + var rupa = new RequireUserPermissionAttribute(perms); + return rupa.CheckPermissionsAsync(ctx, command, services); + } + + public async Task AddOverride(ulong guildId, string commandName, GuildPerm perm) + { + commandName = commandName.ToLowerInvariant(); + await using var uow = _db.GetDbContext(); + var over = await uow.Set() + .AsQueryable() + .FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command); + + if (over is null) + { + uow.Set() + .Add(over = new() + { + Command = commandName, + Perm = (EllieBot.Db.GuildPerm)perm, + GuildId = guildId + }); + } + else + over.Perm = (EllieBot.Db.GuildPerm)perm; + + _overrides[(guildId, commandName)] = over; + + await uow.SaveChangesAsync(); + } + + public async Task ClearAllOverrides(ulong guildId) + { + await using var uow = _db.GetDbContext(); + var overrides = await uow.Set() + .AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .ToListAsync(); + + uow.RemoveRange(overrides); + await uow.SaveChangesAsync(); + + foreach (var over in overrides) + _overrides.TryRemove((guildId, over.Command), out _); + } + + public async Task RemoveOverride(ulong guildId, string commandName) + { + commandName = commandName.ToLowerInvariant(); + + await using var uow = _db.GetDbContext(); + var over = await uow.Set() + .AsQueryable() + .AsNoTracking() + .FirstOrDefaultAsync(x => x.GuildId == guildId && x.Command == commandName); + + if (over is null) + return; + + uow.Remove(over); + await uow.SaveChangesAsync(); + + _overrides.TryRemove((guildId, commandName), out _); + } + + public async Task> GetAllOverrides(ulong guildId) + { + await using var uow = _db.GetDbContext(); + return await uow.Set() + .AsQueryable() + .AsNoTracking() + .Where(x => x.GuildId == guildId) + .ToListAsync(); + } + + public async Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command) + { + if (TryGetOverrides(context.Guild?.Id ?? 0, command.Name, out var perm) && perm is not null) + { + var result = + await new RequireUserPermissionAttribute((GuildPermission)perm).CheckPermissionsAsync(context, + command, + _services); + + return !result.IsSuccess; + } + + return false; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/FontProvider.cs b/src/EllieBot/_common/Services/Impl/FontProvider.cs new file mode 100644 index 0000000..543f23c --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/FontProvider.cs @@ -0,0 +1,60 @@ +#nullable disable +using SixLabors.Fonts; + +namespace EllieBot.Services; + +public class FontProvider : IEService +{ + public FontFamily DottyFont { get; } + + public FontFamily UniSans { get; } + + public FontFamily NotoSans { get; } + //public FontFamily Emojis { get; } + + /// + /// Font used for .rip command + /// + public Font RipFont { get; } + + public List FallBackFonts { get; } + private readonly FontCollection _fonts; + + public FontProvider() + { + _fonts = new(); + + NotoSans = _fonts.Add("data/fonts/NotoSans-Bold.ttf"); + UniSans = _fonts.Add("data/fonts/Uni Sans.ttf"); + + FallBackFonts = new(); + + //FallBackFonts.Add(_fonts.Install("data/fonts/OpenSansEmoji.ttf")); + + // try loading some emoji and jap fonts on windows as fallback fonts + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + try + { + var fontsfolder = Environment.GetFolderPath(Environment.SpecialFolder.Fonts); + FallBackFonts.Add(_fonts.Add(Path.Combine(fontsfolder, "seguiemj.ttf"))); + FallBackFonts.AddRange(_fonts.AddCollection(Path.Combine(fontsfolder, "msgothic.ttc"))); + FallBackFonts.AddRange(_fonts.AddCollection(Path.Combine(fontsfolder, "segoe.ttc"))); + } + catch { } + } + + // any fonts present in data/fonts should be added as fallback fonts + // this will allow support for special characters when drawing text + foreach (var font in Directory.GetFiles(@"data/fonts")) + { + if (font.EndsWith(".ttf")) + FallBackFonts.Add(_fonts.Add(font)); + else if (font.EndsWith(".ttc")) + FallBackFonts.AddRange(_fonts.AddCollection(font)); + } + + RipFont = NotoSans.CreateFont(20, FontStyle.Bold); + DottyFont = FallBackFonts.First(x => x.Name == "dotty"); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/IImageCache.cs b/src/EllieBot/_common/Services/Impl/IImageCache.cs new file mode 100644 index 0000000..8c8ff32 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/IImageCache.cs @@ -0,0 +1,17 @@ +namespace EllieBot.Services; + +public interface IImageCache +{ + Task GetHeadsImageAsync(); + Task GetTailsImageAsync(); + Task GetCurrencyImageAsync(); + Task GetXpBackgroundImageAsync(); + Task GetRategirlBgAsync(); + Task GetRategirlDotAsync(); + Task GetDiceAsync(int num); + Task GetSlotEmojiAsync(int number); + Task GetSlotBgAsync(); + Task GetRipBgAsync(); + Task GetRipOverlayAsync(); + Task GetImageDataAsync(Uri url); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/ImagesConfig.cs b/src/EllieBot/_common/Services/Impl/ImagesConfig.cs new file mode 100644 index 0000000..821d717 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/ImagesConfig.cs @@ -0,0 +1,19 @@ +using EllieBot.Common.Configs; + +namespace EllieBot.Services; + +public sealed class ImagesConfig : ConfigServiceBase +{ + private const string PATH = "data/images.yml"; + + private static readonly TypedKey _changeKey = + new("config.images.updated"); + + public override string Name + => "images"; + + public ImagesConfig(IConfigSeria serializer, IPubSub pubSub) + : base(PATH, serializer, pubSub, _changeKey) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/RedisImageExtensions.cs b/src/EllieBot/_common/Services/Impl/RedisImageExtensions.cs new file mode 100644 index 0000000..79d501b --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/RedisImageExtensions.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Services; + +public static class RedisImageExtensions +{ + private const string OLD_CDN_URL = "nadeko-pictures.nyc3.digitaloceanspaces.com"; + private const string NEW_CDN_URL = "cdn.nadeko.bot"; + + public static Uri ToNewCdn(this Uri uri) + => new(uri.ToString().Replace(OLD_CDN_URL, NEW_CDN_URL)); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/SingleProcessCoordinator.cs b/src/EllieBot/_common/Services/Impl/SingleProcessCoordinator.cs new file mode 100644 index 0000000..0784fc7 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/SingleProcessCoordinator.cs @@ -0,0 +1,58 @@ +#nullable disable +using System.Diagnostics; + +namespace EllieBot.Services; + +public class SingleProcessCoordinator : ICoordinator +{ + private readonly IBotCredentials _creds; + private readonly DiscordSocketClient _client; + + public SingleProcessCoordinator(IBotCredentials creds, DiscordSocketClient client) + { + _creds = creds; + _client = client; + } + + public bool RestartBot() + { + if (string.IsNullOrWhiteSpace(_creds.RestartCommand?.Cmd) + || string.IsNullOrWhiteSpace(_creds.RestartCommand?.Args)) + { + Log.Error("You must set RestartCommand.Cmd and RestartCommand.Args in creds.yml"); + return false; + } + + Process.Start(_creds.RestartCommand.Cmd, _creds.RestartCommand.Args); + _ = Task.Run(async () => + { + await Task.Delay(2000); + Die(); + }); + return true; + } + + public void Die(bool graceful = false) + => Environment.Exit(5); + + public bool RestartShard(int shardId) + => RestartBot(); + + public IList GetAllShardStatuses() + => new[] + { + new ShardStatus + { + ConnectionState = _client.ConnectionState, + GuildCount = _client.Guilds.Count, + LastUpdate = DateTime.UtcNow, + ShardId = _client.ShardId + } + }; + + public int GetGuildCount() + => _client.Guilds.Count; + + public Task Reload() + => Task.CompletedTask; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/StartingGuildsListService.cs b/src/EllieBot/_common/Services/Impl/StartingGuildsListService.cs new file mode 100644 index 0000000..3d102cc --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/StartingGuildsListService.cs @@ -0,0 +1,18 @@ +#nullable disable +using System.Collections; + +namespace EllieBot.Services; + +public class StartingGuildsService : IEnumerable, IEService +{ + private readonly IReadOnlyList _guilds; + + public StartingGuildsService(DiscordSocketClient client) + => _guilds = client.Guilds.Select(x => x.Id).ToList(); + + public IEnumerator GetEnumerator() + => _guilds.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => _guilds.GetEnumerator(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/Impl/StatsService.cs b/src/EllieBot/_common/Services/Impl/StatsService.cs new file mode 100644 index 0000000..ef7ea80 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/StatsService.cs @@ -0,0 +1,222 @@ +#nullable disable +using EllieBot.Common.ModuleBehaviors; +using System.Diagnostics; + +namespace EllieBot.Services; + +public sealed class StatsService : IStatsService, IReadyExecutor, IEService +{ + public static string BotVersion + => typeof(Bot).Assembly.GetName().Version?.ToString(3) ?? "Custom"; + + public string Author + => "toastie_t0ast"; + + public double MessagesPerSecond + => MessageCounter / GetUptime().TotalSeconds; + + public long TextChannels + => Interlocked.Read(ref textChannels); + + public long VoiceChannels + => Interlocked.Read(ref voiceChannels); + + public long MessageCounter + => Interlocked.Read(ref messageCounter); + + public long CommandsRan + => Interlocked.Read(ref commandsRan); + + private readonly Process _currentProcess = Process.GetCurrentProcess(); + private readonly DiscordSocketClient _client; + private readonly IBotCredentials _creds; + private readonly DateTime _started; + + private long textChannels; + private long voiceChannels; + private long messageCounter; + private long commandsRan; + + private readonly IHttpClientFactory _httpFactory; + + public StatsService( + DiscordSocketClient client, + CommandHandler cmdHandler, + IBotCredentials creds, + IHttpClientFactory factory) + { + _client = client; + _creds = creds; + _httpFactory = factory; + + _started = DateTime.UtcNow; + _client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref messageCounter)); + cmdHandler.CommandExecuted += (_, _) => Task.FromResult(Interlocked.Increment(ref commandsRan)); + + _client.ChannelCreated += c => + { + _ = Task.Run(() => + { + if (c is ITextChannel) + Interlocked.Increment(ref textChannels); + else if (c is IVoiceChannel) + Interlocked.Increment(ref voiceChannels); + }); + + return Task.CompletedTask; + }; + + _client.ChannelDestroyed += c => + { + _ = Task.Run(() => + { + if (c is ITextChannel) + Interlocked.Decrement(ref textChannels); + else if (c is IVoiceChannel) + Interlocked.Decrement(ref voiceChannels); + }); + + return Task.CompletedTask; + }; + + _client.GuildAvailable += g => + { + _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref textChannels, tc); + Interlocked.Add(ref voiceChannels, vc); + }); + return Task.CompletedTask; + }; + + _client.JoinedGuild += g => + { + _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref textChannels, tc); + Interlocked.Add(ref voiceChannels, vc); + }); + return Task.CompletedTask; + }; + + _client.GuildUnavailable += g => + { + _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref textChannels, -tc); + Interlocked.Add(ref voiceChannels, -vc); + }); + + return Task.CompletedTask; + }; + + _client.LeftGuild += g => + { + _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref textChannels, -tc); + Interlocked.Add(ref voiceChannels, -vc); + }); + + return Task.CompletedTask; + }; + } + + private void InitializeChannelCount() + { + var guilds = _client.Guilds; + textChannels = guilds.Sum(static g => g.Channels.Count(static cx => cx is ITextChannel)); + voiceChannels = guilds.Sum(static g => g.Channels.Count(static cx => cx is IVoiceChannel)); + } + + public async Task OnReadyAsync() + { + InitializeChannelCount(); + + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + do + { + if (string.IsNullOrWhiteSpace(_creds.BotListToken)) + continue; + + try + { + using var http = _httpFactory.CreateClient(); + using var content = new FormUrlEncodedContent(new Dictionary + { + { "shard_count", _creds.TotalShards.ToString() }, + { "shard_id", _client.ShardId.ToString() }, + { "server_count", _client.Guilds.Count().ToString() } + }); + content.Headers.Clear(); + content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); + http.DefaultRequestHeaders.Add("Authorization", _creds.BotListToken); + + using var res = await http.PostAsync( + new Uri($"https://discordbots.org/api/bots/{_client.CurrentUser.Id}/stats"), + content); + } + catch (Exception ex) + { + Log.Error(ex, "Error in botlist post"); + } + } while (await timer.WaitForNextTickAsync()); + } + + public TimeSpan GetUptime() + => DateTime.UtcNow - _started; + + public string GetUptimeString(string separator = ", ") + { + var time = GetUptime(); + + if (time.Days > 0) + return $"{time.Days}d {time.Hours}h {time.Minutes}m"; + + if (time.Hours > 0) + return $"{time.Hours}h {time.Minutes}m"; + + if (time.Minutes > 0) + return $"{time.Minutes}m {time.Seconds}s"; + + return $"{time.Seconds}s"; + } + + public double GetPrivateMemoryMegabytes() + { + _currentProcess.Refresh(); + return _currentProcess.PrivateMemorySize64 / 1.Megabytes(); + } + + public GuildInfo GetGuildInfo(string name) + => throw new NotImplementedException(); + + public GuildInfo GetGuildInfo(ulong id) + { + var g = _client.GetGuild(id); + + return new GuildInfo() + { + Id = g.Id, + IconUrl = g.IconUrl, + Name = g.Name, + Owner = g.Owner.Username, + OwnerId = g.OwnerId, + CreatedAt = g.CreatedAt.UtcDateTime, + VoiceChannels = g.VoiceChannels.Count, + TextChannels = g.TextChannels.Count, + Features = g.Features.Value.ToString().Split(","), + Emojis = g.Emotes.ToArray(), + Roles = g.Roles.OrderByDescending(x => x.Position).ToArray(), + MemberCount = g.MemberCount, + }; + } +} diff --git a/src/EllieBot/_common/Services/Impl/YtdlOperation.cs b/src/EllieBot/_common/Services/Impl/YtdlOperation.cs new file mode 100644 index 0000000..f302ab7 --- /dev/null +++ b/src/EllieBot/_common/Services/Impl/YtdlOperation.cs @@ -0,0 +1,77 @@ +#nullable disable +using System.ComponentModel; +using System.Diagnostics; +using System.Text; + +namespace EllieBot.Services; + +public class YtdlOperation +{ + private readonly string _baseArgString; + private readonly bool _isYtDlp; + + public YtdlOperation(string baseArgString, bool isYtDlp = false) + { + _baseArgString = baseArgString; + _isYtDlp = isYtDlp; + } + + private Process CreateProcess(string[] args) + { + var newArgs = args.Map(arg => (object)arg.Replace("\"", "")); + return new() + { + StartInfo = new() + { + FileName = _isYtDlp ? "yt-dlp" : "youtube-dl", + Arguments = string.Format(_baseArgString, newArgs), + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + CreateNoWindow = true + } + }; + } + + public async Task GetDataAsync(params string[] args) + { + try + { + using var process = CreateProcess(args); + + Log.Debug("Executing {FileName} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); + process.Start(); + + var str = await process.StandardOutput.ReadToEndAsync(); + var err = await process.StandardError.ReadToEndAsync(); + if (!string.IsNullOrEmpty(err)) + Log.Warning("YTDL warning: {YtdlWarning}", err); + + return str; + } + catch (Win32Exception) + { + Log.Error("youtube-dl is likely not installed. " + "Please install it before running the command again"); + return default; + } + catch (Exception ex) + { + Log.Error(ex, "Exception running youtube-dl: {ErrorMessage}", ex.Message); + return default; + } + } + + public async IAsyncEnumerable EnumerateDataAsync(params string[] args) + { + using var process = CreateProcess(args); + + Log.Debug("Executing {FileName} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); + process.Start(); + + string line; + while ((line = await process.StandardOutput.ReadLineAsync()) is not null) + yield return line; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/strings/impl/BotStrings.cs b/src/EllieBot/_common/Services/strings/impl/BotStrings.cs new file mode 100644 index 0000000..45bbd6e --- /dev/null +++ b/src/EllieBot/_common/Services/strings/impl/BotStrings.cs @@ -0,0 +1,102 @@ +#nullable disable +using System.Globalization; + +namespace EllieBot.Services; + +public class BotStrings : IBotStrings +{ + /// + /// Used as failsafe in case response key doesn't exist in the selected or default language. + /// + private readonly CultureInfo _usCultureInfo = new("en-US"); + + private readonly ILocalization _localization; + private readonly IBotStringsProvider _stringsProvider; + + public BotStrings(ILocalization loc, IBotStringsProvider stringsProvider) + { + _localization = loc; + _stringsProvider = stringsProvider; + } + + private string GetString(string key, CultureInfo cultureInfo) + => _stringsProvider.GetText(cultureInfo.Name, key); + + public string GetText(string key, ulong? guildId = null, params object[] data) + => GetText(key, _localization.GetCultureInfo(guildId), data); + + public string GetText(string key, CultureInfo cultureInfo) + { + var text = GetString(key, cultureInfo); + + if (string.IsNullOrWhiteSpace(text)) + { + Log.Warning("'{Key}' key is missing from '{LanguageName}' response strings. You may ignore this message", + key, + cultureInfo.Name); + text = GetString(key, _usCultureInfo) ?? $"Error: dkey {key} not found!"; + if (string.IsNullOrWhiteSpace(text)) + { + return + "I can't tell you if the command is executed, because there was an error printing out the response." + + $" Key '{key}' is missing from resources. You may ignore this message."; + } + } + + return text; + } + + public string GetText(string key, CultureInfo cultureInfo, params object[] data) + { + try + { + return string.Format(GetText(key, cultureInfo), data); + } + catch (FormatException) + { + Log.Warning( + " Key '{Key}' is not properly formatted in '{LanguageName}' response strings. Please report this", + key, + cultureInfo.Name); + if (cultureInfo.Name != _usCultureInfo.Name) + return GetText(key, _usCultureInfo, data); + return + "I can't tell you if the command is executed, because there was an error printing out the response.\n" + + $"Key '{key}' is not properly formatted. Please report this."; + } + } + + public CommandStrings GetCommandStrings(string commandName, ulong? guildId = null) + => GetCommandStrings(commandName, _localization.GetCultureInfo(guildId)); + + public CommandStrings GetCommandStrings(string commandName, CultureInfo cultureInfo) + { + var cmdStrings = _stringsProvider.GetCommandStrings(cultureInfo.Name, commandName); + if (cmdStrings is null) + { + if (cultureInfo.Name == _usCultureInfo.Name) + { + Log.Warning("'{CommandName}' doesn't exist in 'en-US' command strings. Please report this", + commandName); + + return new CommandStrings() + { + Examples = [""], + Desc = "?", + Params = [] + }; + } + +// Log.Warning(@"'{CommandName}' command strings don't exist in '{LanguageName}' culture. +// This message is safe to ignore, however you can ask in Ellie support server how you can contribute command translations", +// commandName, cultureInfo.Name); + + return GetCommandStrings(commandName, _usCultureInfo); + } + + return cmdStrings; + } + + public void Reload() + => _stringsProvider.Reload(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/strings/impl/LocalFileStringsSource.cs b/src/EllieBot/_common/Services/strings/impl/LocalFileStringsSource.cs new file mode 100644 index 0000000..12b6ba9 --- /dev/null +++ b/src/EllieBot/_common/Services/strings/impl/LocalFileStringsSource.cs @@ -0,0 +1,73 @@ +#nullable disable +using Newtonsoft.Json; +using YamlDotNet.Serialization; + +namespace EllieBot.Services; + +/// +/// Loads strings from the local default filepath +/// +public class LocalFileStringsSource : IStringsSource +{ + private readonly string _responsesPath = "data/strings/responses"; + private readonly string _commandsPath = "data/strings/commands"; + + public LocalFileStringsSource( + string responsesPath = "data/strings/responses", + string commandsPath = "data/strings/commands") + { + _responsesPath = responsesPath; + _commandsPath = commandsPath; + } + + public Dictionary> GetResponseStrings() + { + var outputDict = new Dictionary>(); + foreach (var file in Directory.GetFiles(_responsesPath)) + { + try + { + var langDict = JsonConvert.DeserializeObject>(File.ReadAllText(file)); + var localeName = GetLocaleName(file); + outputDict[localeName] = langDict; + } + catch (Exception ex) + { + Log.Error(ex, "Error loading {FileName} response strings: {ErrorMessage}", file, ex.Message); + } + } + + return outputDict; + } + + public Dictionary> GetCommandStrings() + { + var deserializer = new DeserializerBuilder().Build(); + + var outputDict = new Dictionary>(); + foreach (var file in Directory.GetFiles(_commandsPath)) + { + try + { + var text = File.ReadAllText(file); + var langDict = deserializer.Deserialize>(text); + var localeName = GetLocaleName(file); + outputDict[localeName] = langDict; + } + catch (Exception ex) + { + Log.Error(ex, "Error loading {FileName} command strings: {ErrorMessage}", file, ex.Message); + } + } + + return outputDict; + } + + private static string GetLocaleName(string fileName) + { + fileName = Path.GetFileName(fileName); + var dotIndex = fileName.IndexOf('.') + 1; + var secondDotIndex = fileName.LastIndexOf('.'); + return fileName.Substring(dotIndex, secondDotIndex - dotIndex); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Services/strings/impl/MemoryBotStringsProvider.cs b/src/EllieBot/_common/Services/strings/impl/MemoryBotStringsProvider.cs new file mode 100644 index 0000000..6676dd8 --- /dev/null +++ b/src/EllieBot/_common/Services/strings/impl/MemoryBotStringsProvider.cs @@ -0,0 +1,38 @@ +#nullable disable +namespace EllieBot.Services; + +public class MemoryBotStringsProvider : IBotStringsProvider +{ + private readonly IStringsSource _source; + private IReadOnlyDictionary> responseStrings; + private IReadOnlyDictionary> commandStrings; + + public MemoryBotStringsProvider(IStringsSource source) + { + _source = source; + Reload(); + } + + public string GetText(string localeName, string key) + { + if (responseStrings.TryGetValue(localeName, out var langStrings) && langStrings.TryGetValue(key, out var text)) + return text; + + return null; + } + + public void Reload() + { + responseStrings = _source.GetResponseStrings(); + commandStrings = _source.GetCommandStrings(); + } + + public CommandStrings GetCommandStrings(string localeName, string commandName) + { + if (commandStrings.TryGetValue(localeName, out var langStrings) + && langStrings.TryGetValue(commandName, out var strings)) + return strings; + + return null; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Settings/BotConfigService.cs b/src/EllieBot/_common/Settings/BotConfigService.cs new file mode 100644 index 0000000..952f402 --- /dev/null +++ b/src/EllieBot/_common/Settings/BotConfigService.cs @@ -0,0 +1,73 @@ +#nullable disable +using EllieBot.Common.Configs; +using SixLabors.ImageSharp.PixelFormats; + +namespace EllieBot.Services; + +/// +/// Settings service for bot-wide configuration. +/// +public sealed class BotConfigService : ConfigServiceBase +{ + private const string FILE_PATH = "data/bot.yml"; + private static readonly TypedKey _changeKey = new("config.bot.updated"); + public override string Name { get; } = "bot"; + + public BotConfigService(IConfigSeria serializer, IPubSub pubSub) + : base(FILE_PATH, serializer, pubSub, _changeKey) + { + AddParsedProp("color.ok", bs => bs.Color.Ok, Rgba32.TryParseHex, ConfigPrinters.Color); + AddParsedProp("color.error", bs => bs.Color.Error, Rgba32.TryParseHex, ConfigPrinters.Color); + AddParsedProp("color.pending", bs => bs.Color.Pending, Rgba32.TryParseHex, ConfigPrinters.Color); + AddParsedProp("help.text", bs => bs.HelpText, ConfigParsers.String, ConfigPrinters.ToString); + AddParsedProp("help.dmtext", bs => bs.DmHelpText, ConfigParsers.String, ConfigPrinters.ToString); + AddParsedProp("console.type", bs => bs.ConsoleOutputType, Enum.TryParse, ConfigPrinters.ToString); + AddParsedProp("locale", bs => bs.DefaultLocale, ConfigParsers.Culture, ConfigPrinters.Culture); + AddParsedProp("prefix", bs => bs.Prefix, ConfigParsers.String, ConfigPrinters.ToString); + AddParsedProp("checkforupdates", bs => bs.CheckForUpdates, bool.TryParse, ConfigPrinters.ToString); + + Migrate(); + } + + private void Migrate() + { + if (data.Version < 2) + ModifyConfig(c => c.Version = 2); + + if (data.Version < 3) + { + ModifyConfig(c => + { + c.Version = 3; + c.Blocked.Modules = c.Blocked.Modules?.Select(static x + => string.Equals(x, + "ActualCustomReactions", + StringComparison.InvariantCultureIgnoreCase) + ? "ACTUALEXPRESSIONS" + : x) + .Distinct() + .ToHashSet(); + }); + } + + if (data.Version < 4) + ModifyConfig(c => + { + c.Version = 4; + c.CheckForUpdates = true; + }); + + if (data.Version < 5) + ModifyConfig(c => + { + c.Version = 5; + }); + + if (data.Version < 7) + ModifyConfig(c => + { + c.Version = 7; + c.IgnoreOtherBots = true; + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Settings/ConfigParsers.cs b/src/EllieBot/_common/Settings/ConfigParsers.cs new file mode 100644 index 0000000..c32b7ca --- /dev/null +++ b/src/EllieBot/_common/Settings/ConfigParsers.cs @@ -0,0 +1,50 @@ +#nullable disable +using SixLabors.ImageSharp.PixelFormats; +using System.Globalization; + +namespace EllieBot.Services; + +/// +/// Custom setting value parsers for types which don't have them by default +/// +public static class ConfigParsers +{ + /// + /// Default string parser. Passes input to output and returns true. + /// + public static bool String(string input, out string output) + { + output = input; + return true; + } + + public static bool Culture(string input, out CultureInfo output) + { + try + { + output = new(input); + return true; + } + catch + { + output = null; + return false; + } + } + + public static bool InsensitiveEnum(string input, out T output) + where T : struct + => Enum.TryParse(input, true, out output); +} + +public static class ConfigPrinters +{ + public static string ToString(TAny input) + => input.ToString(); + + public static string Culture(CultureInfo culture) + => culture.Name; + + public static string Color(Rgba32 color) + => ((uint)((color.B << 0) | (color.G << 8) | (color.R << 16))).ToString("X6"); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Settings/ConfigServiceBase.cs b/src/EllieBot/_common/Settings/ConfigServiceBase.cs new file mode 100644 index 0000000..bdf76d8 --- /dev/null +++ b/src/EllieBot/_common/Settings/ConfigServiceBase.cs @@ -0,0 +1,201 @@ +using EllieBot.Common.Configs; +using EllieBot.Common.Yml; +using System.Linq.Expressions; +using System.Reflection; + +namespace EllieBot.Services; + +/// +/// Base service for all settings services +/// +/// Type of the settings +public abstract class ConfigServiceBase : IConfigService + where TSettings : ICloneable, new() +{ + // FUTURE config arrays are not copied - they're not protected from mutations + public TSettings Data + => data.Clone(); + + public abstract string Name { get; } + protected readonly string _filePath; + protected readonly IConfigSeria _serializer; + protected readonly IPubSub _pubSub; + private readonly TypedKey _changeKey; + + protected TSettings data; + + private readonly Dictionary> _propSetters = new(); + private readonly Dictionary> _propSelectors = new(); + private readonly Dictionary> _propPrinters = new(); + private readonly Dictionary _propComments = new(); + + /// + /// Initialized an instance of + /// + /// Path to the file where the settings are serialized/deserialized to and from + /// Serializer which will be used + /// Pubsub implementation for signaling when settings are updated + /// Key used to signal changed event + protected ConfigServiceBase( + string filePath, + IConfigSeria serializer, + IPubSub pubSub, + TypedKey changeKey) + { + _filePath = filePath; + _serializer = serializer; + _pubSub = pubSub; + _changeKey = changeKey; + + data = new(); + Load(); + _pubSub.Sub(_changeKey, OnChangePublished); + } + + private void PublishChange() + => _pubSub.Pub(_changeKey, data); + + private ValueTask OnChangePublished(TSettings newData) + { + data = newData; + OnStateUpdate(); + return default; + } + + /// + /// Loads data from disk. If file doesn't exist, it will be created with default values + /// + protected void Load() + { + // if file is deleted, regenerate it with default values + if (!File.Exists(_filePath)) + { + data = new(); + Save(); + } + + data = _serializer.Deserialize(File.ReadAllText(_filePath)); + } + + /// + /// Loads new data and publishes the new state + /// + public void Reload() + { + Load(); + _pubSub.Pub(_changeKey, data); + } + + /// + /// Doesn't do anything by default. This method will be executed after + /// is reloaded from or new data is recieved + /// from the publish event + /// + protected virtual void OnStateUpdate() + { + } + + private void Save() + { + var strData = _serializer.Serialize(data); + File.WriteAllText(_filePath, strData); + } + + protected void AddParsedProp( + string key, + Expression> selector, + SettingParser parser, + Func printer, + Func? checker = null) + { + checker ??= _ => true; + key = key.ToLowerInvariant(); + _propPrinters[key] = obj => printer((TProp)obj); + _propSelectors[key] = () => selector.Compile()(data)!; + _propSetters[key] = Magic(selector, parser, checker); + _propComments[key] = ((MemberExpression)selector.Body).Member.GetCustomAttribute()?.Comment; + } + + private Func Magic( + Expression> selector, + SettingParser parser, + Func checker) + => (target, input) => + { + if (!parser(input, out var value)) + return false; + + if (!checker(value)) + return false; + + object targetObject = target; + var expr = (MemberExpression)selector.Body; + var prop = (PropertyInfo)expr.Member; + + var expressions = new List(); + + while (true) + { + expr = expr.Expression as MemberExpression; + if (expr is null) + break; + + expressions.Add(expr); + } + + foreach (var memberExpression in expressions.AsEnumerable().Reverse()) + { + var localProp = (PropertyInfo)memberExpression.Member; + targetObject = localProp.GetValue(targetObject)!; + } + + prop.SetValue(targetObject, value, null); + return true; + }; + + public IReadOnlyList GetSettableProps() + => _propSetters.Keys.ToList(); + + public string? GetSetting(string prop) + { + prop = prop.ToLowerInvariant(); + if (!_propSelectors.TryGetValue(prop, out var selector) || !_propPrinters.TryGetValue(prop, out var printer)) + return null; + + return printer(selector()); + } + + public string? GetComment(string prop) + { + if (_propComments.TryGetValue(prop, out var comment)) + return comment; + + return null; + } + + private bool SetProperty(TSettings target, string key, string value) + => _propSetters.TryGetValue(key.ToLowerInvariant(), out var magic) && magic(target, value); + + public bool SetSetting(string prop, string newValue) + { + var success = true; + ModifyConfig(bs => + { + success = SetProperty(bs, prop, newValue); + }); + + if (success) + PublishChange(); + + return success; + } + + public void ModifyConfig(Action action) + { + var copy = Data; + action(copy); + data = copy; + Save(); + PublishChange(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Settings/IConfigService.cs b/src/EllieBot/_common/Settings/IConfigService.cs new file mode 100644 index 0000000..69ac966 --- /dev/null +++ b/src/EllieBot/_common/Settings/IConfigService.cs @@ -0,0 +1,46 @@ +#nullable disable +namespace EllieBot.Services; + +/// +/// Interface that all services which deal with configs should implement +/// +public interface IConfigService +{ + /// + /// Name of the config + /// + public string Name { get; } + + /// + /// Loads new data and publishes the new state + /// + void Reload(); + + /// + /// Gets the list of props you can set + /// + /// List of props + IReadOnlyList GetSettableProps(); + + /// + /// Gets the value of the specified property + /// + /// Prop name + /// Value of the prop + string GetSetting(string prop); + + /// + /// Gets the value of the specified property + /// + /// Prop name + /// Value of the prop + string GetComment(string prop); + + /// + /// Sets the value of the specified property + /// + /// Property to set + /// Value to set the property to + /// Success + bool SetSetting(string prop, string newValue); +} \ No newline at end of file diff --git a/src/EllieBot/_common/Settings/SettingParser.cs b/src/EllieBot/_common/Settings/SettingParser.cs new file mode 100644 index 0000000..06a8e75 --- /dev/null +++ b/src/EllieBot/_common/Settings/SettingParser.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Services; + +/// +/// Delegate which describes a parser which can convert string input into given data type +/// +/// Data type to convert string to +public delegate bool SettingParser(string input, out TData output); \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartEmbedText.cs b/src/EllieBot/_common/SmartText/SmartEmbedText.cs new file mode 100644 index 0000000..b52c0cb --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartEmbedText.cs @@ -0,0 +1,184 @@ +#nullable disable warnings +using SixLabors.ImageSharp.PixelFormats; +using System.Text.Json.Serialization; + +namespace EllieBot; + +public sealed record SmartEmbedArrayElementText : SmartEmbedTextBase +{ + public string Color { get; init; } = string.Empty; + + public SmartEmbedArrayElementText() + { + + } + + public SmartEmbedArrayElementText(IEmbed eb) : base(eb) + { + Color = eb.Color is { } c ? new Rgba32(c.R, c.G, c.B).ToHex() : string.Empty; + } + + protected override EmbedBuilder GetEmbedInternal() + { + var embed = base.GetEmbedInternal(); + if (Rgba32.TryParseHex(Color, out var color)) + return embed.WithColor(color.ToDiscordColor()); + + return embed; + } +} + +public sealed record SmartEmbedText : SmartEmbedTextBase +{ + public string? PlainText { get; init; } + + public uint Color { get; init; } = 7458112; + + public SmartEmbedText() + { + } + + private SmartEmbedText(IEmbed eb, string? plainText = null) + : base(eb) + => (PlainText, Color) = (plainText, eb.Color?.RawValue ?? 0); + + public static SmartEmbedText FromEmbed(IEmbed eb, string? plainText = null) + => new(eb, plainText); + + protected override EmbedBuilder GetEmbedInternal() + { + var embed = base.GetEmbedInternal(); + return embed.WithColor(Color); + } +} + +public abstract record SmartEmbedTextBase : SmartText +{ + public string? Title { get; init; } + public string? Description { get; init; } + public string? Url { get; init; } + public string? Thumbnail { get; init; } + public string? Image { get; init; } + + public SmartTextEmbedAuthor? Author { get; init; } + public SmartTextEmbedFooter? Footer { get; init; } + public SmartTextEmbedField[]? Fields { get; init; } + + [JsonIgnore] + public bool IsValid + => !string.IsNullOrWhiteSpace(Title) + || !string.IsNullOrWhiteSpace(Description) + || !string.IsNullOrWhiteSpace(Url) + || !string.IsNullOrWhiteSpace(Thumbnail) + || !string.IsNullOrWhiteSpace(Image) + || (Footer is not null + && (!string.IsNullOrWhiteSpace(Footer.Text) || !string.IsNullOrWhiteSpace(Footer.IconUrl))) + || Fields is { Length: > 0 }; + + protected SmartEmbedTextBase() + { + + } + + protected SmartEmbedTextBase(IEmbed eb) + { + Title = eb.Title; + Description = eb.Description; + Url = eb.Url; + Thumbnail = eb.Thumbnail?.Url; + Image = eb.Image?.Url; + Author = eb.Author is { } ea + ? new() + { + Name = ea.Name, + Url = ea.Url, + IconUrl = ea.IconUrl + } + : null; + Footer = eb.Footer is { } ef + ? new() + { + Text = ef.Text, + IconUrl = ef.IconUrl + } + : null; + + if (eb.Fields.Length > 0) + { + Fields = eb.Fields.Select(field + => new SmartTextEmbedField + { + Inline = field.Inline, + Name = field.Name, + Value = field.Value + }) + .ToArray(); + } + } + + public EmbedBuilder GetEmbed() + => GetEmbedInternal(); + + protected virtual EmbedBuilder GetEmbedInternal() + { + var embed = new EmbedBuilder(); + + if (!string.IsNullOrWhiteSpace(Title)) + embed.WithTitle(Title); + + if (!string.IsNullOrWhiteSpace(Description)) + embed.WithDescription(Description); + + if (Url is not null && Uri.IsWellFormedUriString(Url, UriKind.Absolute)) + embed.WithUrl(Url); + + if (Footer is not null) + { + embed.WithFooter(efb => + { + efb.WithText(Footer.Text); + if (Uri.IsWellFormedUriString(Footer.IconUrl, UriKind.Absolute)) + efb.WithIconUrl(Footer.IconUrl); + }); + } + + if (Thumbnail is not null && Uri.IsWellFormedUriString(Thumbnail, UriKind.Absolute)) + embed.WithThumbnailUrl(Thumbnail); + + if (Image is not null && Uri.IsWellFormedUriString(Image, UriKind.Absolute)) + embed.WithImageUrl(Image); + + if (Author is not null && !string.IsNullOrWhiteSpace(Author.Name)) + { + if (!Uri.IsWellFormedUriString(Author.IconUrl, UriKind.Absolute)) + Author.IconUrl = null; + if (!Uri.IsWellFormedUriString(Author.Url, UriKind.Absolute)) + Author.Url = null; + + embed.WithAuthor(Author.Name, Author.IconUrl, Author.Url); + } + + if (Fields is not null) + { + foreach (var f in Fields) + { + if (!string.IsNullOrWhiteSpace(f.Name) && !string.IsNullOrWhiteSpace(f.Value)) + embed.AddField(f.Name, f.Value, f.Inline); + } + } + + return embed; + } + + public void NormalizeFields() + { + if (Fields is { Length: > 0 }) + { + foreach (var f in Fields) + { + f.Name = f.Name.TrimTo(256); + f.Value = f.Value.TrimTo(1024); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartEmbedTextArray.cs b/src/EllieBot/_common/SmartText/SmartEmbedTextArray.cs new file mode 100644 index 0000000..3147132 --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartEmbedTextArray.cs @@ -0,0 +1,34 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot; + +public sealed record SmartEmbedTextArray : SmartText +{ + public string Content { get; set; } + public SmartEmbedArrayElementText[] Embeds { get; set; } + + [JsonIgnore] + public bool IsValid + => Embeds?.All(x => x.IsValid) ?? false; + + public EmbedBuilder[] GetEmbedBuilders() + { + if (Embeds is null) + return Array.Empty(); + + return Embeds + .Where(x => x.IsValid) + .Select(em => em.GetEmbed()) + .ToArray(); + } + + public void NormalizeFields() + { + if (Embeds is null) + return; + + foreach(var eb in Embeds) + eb.NormalizeFields(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartPlainText.cs b/src/EllieBot/_common/SmartText/SmartPlainText.cs new file mode 100644 index 0000000..0da4a35 --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartPlainText.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot; + +public sealed record SmartPlainText : SmartText +{ + public string Text { get; init; } + + public SmartPlainText(string text) + => Text = text; + + public static implicit operator SmartPlainText(string input) + => new(input); + + public static implicit operator string(SmartPlainText input) + => input.Text; + + public override string ToString() + => Text; +} \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartText.cs b/src/EllieBot/_common/SmartText/SmartText.cs new file mode 100644 index 0000000..74aee76 --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartText.cs @@ -0,0 +1,92 @@ +#nullable disable +using Newtonsoft.Json.Linq; +using System.Text.Json.Serialization; + +namespace EllieBot; + +public abstract record SmartText +{ + [JsonIgnore] + public bool IsEmbed + => this is SmartEmbedText; + + [JsonIgnore] + public bool IsPlainText + => this is SmartPlainText; + + [JsonIgnore] + public bool IsEmbedArray + => this is SmartEmbedTextArray; + + public static implicit operator SmartText(string input) + => new SmartPlainText(input); + + public static SmartText operator +(SmartText text, string input) + => text switch + { + SmartEmbedText set => set with + { + PlainText = set.PlainText + input + }, + SmartPlainText spt => new SmartPlainText(spt.Text + input), + SmartEmbedTextArray arr => arr with + { + Content = arr.Content + input + }, + _ => throw new ArgumentOutOfRangeException(nameof(text)) + }; + + public static SmartText operator +(string input, SmartText text) + => text switch + { + SmartEmbedText set => set with + { + PlainText = input + set.PlainText + }, + SmartPlainText spt => new SmartPlainText(input + spt.Text), + SmartEmbedTextArray arr => arr with + { + Content = input + arr.Content + }, + _ => throw new ArgumentOutOfRangeException(nameof(text)) + }; + + public static SmartText CreateFrom(string input) + { + if (string.IsNullOrWhiteSpace(input)) + return new SmartPlainText(input); + + try + { + var doc = JObject.Parse(input); + var root = doc.Root; + if (root.Type == JTokenType.Object) + { + if (((JObject)root).TryGetValue("embeds", out _)) + { + var arr = root.ToObject(); + + if (arr is null) + return new SmartPlainText(input); + + arr!.NormalizeFields(); + return arr; + } + + var obj = root.ToObject(); + + if (obj is null || !(obj.IsValid || !string.IsNullOrWhiteSpace(obj.PlainText))) + return new SmartPlainText(input); + + obj.NormalizeFields(); + return obj; + } + + return new SmartPlainText(input); + } + catch + { + return new SmartPlainText(input); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartTextEmbedAuthor.cs b/src/EllieBot/_common/SmartText/SmartTextEmbedAuthor.cs new file mode 100644 index 0000000..9d3cc1c --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartTextEmbedAuthor.cs @@ -0,0 +1,16 @@ +#nullable disable +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace EllieBot; + +public class SmartTextEmbedAuthor +{ + public string Name { get; set; } + + [JsonProperty("icon_url")] + [JsonPropertyName("icon_url")] + public string IconUrl { get; set; } + + public string Url { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartTextEmbedField.cs b/src/EllieBot/_common/SmartText/SmartTextEmbedField.cs new file mode 100644 index 0000000..7989b32 --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartTextEmbedField.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot; + +public class SmartTextEmbedField +{ + public string Name { get; set; } + public string Value { get; set; } + public bool Inline { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/SmartText/SmartTextEmbedFooter.cs b/src/EllieBot/_common/SmartText/SmartTextEmbedFooter.cs new file mode 100644 index 0000000..6b06223 --- /dev/null +++ b/src/EllieBot/_common/SmartText/SmartTextEmbedFooter.cs @@ -0,0 +1,14 @@ +#nullable disable +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace EllieBot; + +public class SmartTextEmbedFooter +{ + public string Text { get; set; } + + [JsonProperty("icon_url")] + [JsonPropertyName("icon_url")] + public string IconUrl { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TriviaQuestionModel.cs b/src/EllieBot/_common/TriviaQuestionModel.cs new file mode 100644 index 0000000..ddd92d3 --- /dev/null +++ b/src/EllieBot/_common/TriviaQuestionModel.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Modules.Games.Common.Trivia; + +public sealed class TriviaQuestionModel +{ + public string Category { get; init; } + public string Question { get; init; } + public string ImageUrl { get; init; } + public string AnswerImageUrl { get; init; } + public string Answer { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaderResult.cs b/src/EllieBot/_common/TypeReaderResult.cs new file mode 100644 index 0000000..309ed7b --- /dev/null +++ b/src/EllieBot/_common/TypeReaderResult.cs @@ -0,0 +1,30 @@ +namespace EllieBot.Common.TypeReaders; + +public readonly struct TypeReaderResult +{ + public bool IsSuccess + => _result.IsSuccess; + + public IReadOnlyCollection Values + => _result.Values; + + private readonly Discord.Commands.TypeReaderResult _result; + + private TypeReaderResult(in Discord.Commands.TypeReaderResult result) + => _result = result; + + public static implicit operator TypeReaderResult(in Discord.Commands.TypeReaderResult result) + => new(result); + + public static implicit operator Discord.Commands.TypeReaderResult(in TypeReaderResult wrapper) + => wrapper._result; +} + +public static class TypeReaderResult +{ + public static TypeReaderResult FromError(CommandError error, string reason) + => Discord.Commands.TypeReaderResult.FromError(error, reason); + + public static TypeReaderResult FromSuccess(in T value) + => Discord.Commands.TypeReaderResult.FromSuccess(value); +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/CommandOrExprInfo.cs b/src/EllieBot/_common/TypeReaders/CommandOrExprInfo.cs new file mode 100644 index 0000000..18d9184 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/CommandOrExprInfo.cs @@ -0,0 +1,23 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public class CommandOrExprInfo +{ + public enum Type + { + Normal, + Custom + } + + public string Name { get; set; } + public Type CmdType { get; set; } + + public bool IsCustom + => CmdType == Type.Custom; + + public CommandOrExprInfo(string input, Type type) + { + Name = input; + CmdType = type; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/EmoteTypeReader.cs b/src/EllieBot/_common/TypeReaders/EmoteTypeReader.cs new file mode 100644 index 0000000..e473e49 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/EmoteTypeReader.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public sealed class EmoteTypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync(ICommandContext ctx, string input) + { + if (!Emote.TryParse(input, out var emote)) + return new(TypeReaderResult.FromError(CommandError.ParseFailed, "Input is not a valid emote")); + + return new(TypeReaderResult.FromSuccess(emote)); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/GuildDateTimeTypeReader.cs b/src/EllieBot/_common/TypeReaders/GuildDateTimeTypeReader.cs new file mode 100644 index 0000000..97f9eb4 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/GuildDateTimeTypeReader.cs @@ -0,0 +1,49 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public sealed class GuildDateTimeTypeReader : EllieTypeReader +{ + private readonly ITimezoneService _gts; + + public GuildDateTimeTypeReader(ITimezoneService gts) + => _gts = gts; + + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + var gdt = Parse(context.Guild.Id, input); + if (gdt is null) + { + return new(TypeReaderResult.FromError(CommandError.ParseFailed, + "Input string is in an incorrect format.")); + } + + return new(TypeReaderResult.FromSuccess(gdt)); + } + + private GuildDateTime Parse(ulong guildId, string input) + { + if (!DateTime.TryParse(input, out var dt)) + return null; + + var tz = _gts.GetTimeZoneOrUtc(guildId); + + return new(tz, dt); + } +} + +public class GuildDateTime +{ + public TimeZoneInfo Timezone { get; } + public DateTime CurrentGuildTime { get; } + public DateTime InputTime { get; } + public DateTime InputTimeUtc { get; } + + public GuildDateTime(TimeZoneInfo guildTimezone, DateTime inputTime) + { + var now = DateTime.UtcNow; + Timezone = guildTimezone; + CurrentGuildTime = TimeZoneInfo.ConvertTime(now, TimeZoneInfo.Utc, Timezone); + InputTime = inputTime; + InputTimeUtc = TimeZoneInfo.ConvertTime(inputTime, Timezone, TimeZoneInfo.Utc); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/GuildTypeReader.cs b/src/EllieBot/_common/TypeReaders/GuildTypeReader.cs new file mode 100644 index 0000000..9a29f95 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/GuildTypeReader.cs @@ -0,0 +1,24 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public sealed class GuildTypeReader : EllieTypeReader +{ + private readonly DiscordSocketClient _client; + + public GuildTypeReader(DiscordSocketClient client) + => _client = client; + + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + input = input.Trim().ToUpperInvariant(); + var guilds = _client.Guilds; + IGuild guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToUpperInvariant() == input) //by id + ?? guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == input); //by name + + if (guild is not null) + return new(TypeReaderResult.FromSuccess(guild)); + + return new( + TypeReaderResult.FromError(CommandError.ParseFailed, "No guild by that name or Id found")); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/GuildUserTypeReader.cs b/src/EllieBot/_common/TypeReaders/GuildUserTypeReader.cs new file mode 100644 index 0000000..6c4b9d6 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/GuildUserTypeReader.cs @@ -0,0 +1,33 @@ +namespace EllieBot.Common.TypeReaders; + +public sealed class GuildUserTypeReader : EllieTypeReader +{ + public override async ValueTask> ReadAsync(ICommandContext ctx, string input) + { + if (ctx.Guild is null) + return TypeReaderResult.FromError(CommandError.Unsuccessful, "Must be in a guild."); + + input = input.Trim(); + IGuildUser? user = null; + if (MentionUtils.TryParseUser(input, out var id)) + user = await ctx.Guild.GetUserAsync(id, CacheMode.AllowDownload); + + if (ulong.TryParse(input, out id)) + user = await ctx.Guild.GetUserAsync(id, CacheMode.AllowDownload); + + if (user is null) + { + var users = await ctx.Guild.GetUsersAsync(CacheMode.CacheOnly); + user = users.FirstOrDefault(x => x.Username == input) + ?? users.FirstOrDefault(x => + string.Equals(x.ToString(), input, StringComparison.InvariantCultureIgnoreCase)) + ?? users.FirstOrDefault(x => + string.Equals(x.Username, input, StringComparison.InvariantCultureIgnoreCase)); + } + + if (user is null) + return TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found."); + + return TypeReaderResult.FromSuccess(user); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/KwumTypeReader.cs b/src/EllieBot/_common/TypeReaders/KwumTypeReader.cs new file mode 100644 index 0000000..608a852 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/KwumTypeReader.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public sealed class KwumTypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + if (kwum.TryParse(input, out var val)) + return new(TypeReaderResult.FromSuccess(val)); + + return new(TypeReaderResult.FromError(CommandError.ParseFailed, "Input is not a valid kwum")); + } +} + +public sealed class SmartTextTypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync(ICommandContext ctx, string input) + => new(TypeReaderResult.FromSuccess(SmartText.CreateFrom(input))); +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/Models/PermissionAction.cs b/src/EllieBot/_common/TypeReaders/Models/PermissionAction.cs new file mode 100644 index 0000000..1aec85b --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/Models/PermissionAction.cs @@ -0,0 +1,27 @@ +#nullable disable +namespace EllieBot.Common.TypeReaders.Models; + +public class PermissionAction +{ + public static PermissionAction Enable + => new(true); + + public static PermissionAction Disable + => new(false); + + public bool Value { get; } + + public PermissionAction(bool value) + => Value = value; + + public override bool Equals(object obj) + { + if (obj is null || GetType() != obj.GetType()) + return false; + + return Value == ((PermissionAction)obj).Value; + } + + public override int GetHashCode() + => Value.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/Models/StoopidTime.cs b/src/EllieBot/_common/TypeReaders/Models/StoopidTime.cs new file mode 100644 index 0000000..08c69b8 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/Models/StoopidTime.cs @@ -0,0 +1,55 @@ +#nullable disable +using System.Text.RegularExpressions; + +namespace EllieBot.Common.TypeReaders.Models; + +public class StoopidTime +{ + private static readonly Regex _regex = new( + @"^(?:(?\d)mo)?(?:(?\d{1,2})w)?(?:(?\d{1,2})d)?(?:(?\d{1,4})h)?(?:(?\d{1,5})m)?(?:(?\d{1,6})s)?$", + RegexOptions.Compiled | RegexOptions.Multiline); + + public string Input { get; set; } + public TimeSpan Time { get; set; } + + private StoopidTime() { } + + public static StoopidTime FromInput(string input) + { + var m = _regex.Match(input); + + if (m.Length == 0) + throw new ArgumentException("Invalid string input format."); + + var namesAndValues = new Dictionary(); + + foreach (var groupName in _regex.GetGroupNames()) + { + if (groupName == "0") + continue; + if (!int.TryParse(m.Groups[groupName].Value, out var value)) + { + namesAndValues[groupName] = 0; + continue; + } + + if (value < 1) + throw new ArgumentException($"Invalid {groupName} value."); + + namesAndValues[groupName] = value; + } + + var ts = new TimeSpan((30 * namesAndValues["months"]) + (7 * namesAndValues["weeks"]) + namesAndValues["days"], + namesAndValues["hours"], + namesAndValues["minutes"], + namesAndValues["seconds"]); + if (ts > TimeSpan.FromDays(90)) + throw new ArgumentException("Time is too long."); + + return new() + { + Input = input, + Time = ts + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/ModuleTypeReader.cs b/src/EllieBot/_common/TypeReaders/ModuleTypeReader.cs new file mode 100644 index 0000000..fbbaff0 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/ModuleTypeReader.cs @@ -0,0 +1,52 @@ +#nullable disable +using EllieBot.Modules.Permissions; + +namespace EllieBot.Common.TypeReaders; + +public sealed class ModuleTypeReader : EllieTypeReader +{ + private readonly CommandService _cmds; + + public ModuleTypeReader(CommandService cmds) + => _cmds = cmds; + + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + input = input.ToUpperInvariant(); + var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()) + .FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input) + ?.Key; + if (module is null) + return new(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found.")); + + return new(TypeReaderResult.FromSuccess(module)); + } +} + +public sealed class ModuleOrExprTypeReader : EllieTypeReader +{ + private readonly CommandService _cmds; + + public ModuleOrExprTypeReader(CommandService cmds) + => _cmds = cmds; + + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + input = input.ToUpperInvariant(); + var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule()) + .FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input) + ?.Key; + if (module is null && input != "ACTUALEXPRESSIONS" && input != CleverBotResponseStr.CLEVERBOT_RESPONSE) + return new(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found.")); + + return new(TypeReaderResult.FromSuccess(new ModuleOrExpr + { + Name = input + })); + } +} + +public sealed class ModuleOrExpr +{ + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/PermissionActionTypeReader.cs b/src/EllieBot/_common/TypeReaders/PermissionActionTypeReader.cs new file mode 100644 index 0000000..168cceb --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/PermissionActionTypeReader.cs @@ -0,0 +1,39 @@ +#nullable disable +using EllieBot.Common.TypeReaders.Models; + +namespace EllieBot.Common.TypeReaders; + +/// +/// Used instead of bool for more flexible keywords for true/false only in the permission module +/// +public sealed class PermissionActionTypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + input = input.ToUpperInvariant(); + switch (input) + { + case "1": + case "T": + case "TRUE": + case "ENABLE": + case "ENABLED": + case "ALLOW": + case "PERMIT": + case "UNBAN": + return new(TypeReaderResult.FromSuccess(PermissionAction.Enable)); + case "0": + case "F": + case "FALSE": + case "DENY": + case "DISABLE": + case "DISABLED": + case "DISALLOW": + case "BAN": + return new(TypeReaderResult.FromSuccess(PermissionAction.Disable)); + default: + return new(TypeReaderResult.FromError(CommandError.ParseFailed, + "Did not receive a valid boolean value")); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/Rgba32TypeReader.cs b/src/EllieBot/_common/TypeReaders/Rgba32TypeReader.cs new file mode 100644 index 0000000..77e7c6a --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/Rgba32TypeReader.cs @@ -0,0 +1,20 @@ +using Color = SixLabors.ImageSharp.Color; + +#nullable disable +namespace EllieBot.Common.TypeReaders; + +public sealed class Rgba32TypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + input = input.Replace("#", "", StringComparison.InvariantCulture); + try + { + return ValueTask.FromResult(TypeReaderResult.FromSuccess(Color.ParseHex(input))); + } + catch + { + return ValueTask.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Parameter is not a valid color hex.")); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/TypeReaders/StoopidTimeTypeReader.cs b/src/EllieBot/_common/TypeReaders/StoopidTimeTypeReader.cs new file mode 100644 index 0000000..c5b9418 --- /dev/null +++ b/src/EllieBot/_common/TypeReaders/StoopidTimeTypeReader.cs @@ -0,0 +1,22 @@ +#nullable disable +using EllieBot.Common.TypeReaders.Models; + +namespace EllieBot.Common.TypeReaders; + +public sealed class StoopidTimeTypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync(ICommandContext context, string input) + { + if (string.IsNullOrWhiteSpace(input)) + return new(TypeReaderResult.FromError(CommandError.Unsuccessful, "Input is empty.")); + try + { + var time = StoopidTime.FromInput(input); + return new(TypeReaderResult.FromSuccess(time)); + } + catch (Exception ex) + { + return new(TypeReaderResult.FromError(CommandError.Exception, ex.Message)); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/CommentAttribute.cs b/src/EllieBot/_common/Yml/CommentAttribute.cs new file mode 100644 index 0000000..7c04bea --- /dev/null +++ b/src/EllieBot/_common/Yml/CommentAttribute.cs @@ -0,0 +1,11 @@ +#nullable disable +namespace EllieBot.Common.Yml; + +[AttributeUsage(AttributeTargets.Property)] +public class CommentAttribute : Attribute +{ + public string Comment { get; } + + public CommentAttribute(string comment) + => Comment = comment; +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/CommentGatheringTypeInspector.cs b/src/EllieBot/_common/Yml/CommentGatheringTypeInspector.cs new file mode 100644 index 0000000..f9f5739 --- /dev/null +++ b/src/EllieBot/_common/Yml/CommentGatheringTypeInspector.cs @@ -0,0 +1,65 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.TypeInspectors; + +namespace EllieBot.Common.Yml; + +public class CommentGatheringTypeInspector : TypeInspectorSkeleton +{ + private readonly ITypeInspector _innerTypeDescriptor; + + public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor) + => _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor)); + + public override IEnumerable GetProperties(Type type, object container) + => _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d)); + + private sealed class CommentsPropertyDescriptor : IPropertyDescriptor + { + public string Name { get; } + + public Type Type + => _baseDescriptor.Type; + + public Type TypeOverride + { + get => _baseDescriptor.TypeOverride; + set => _baseDescriptor.TypeOverride = value; + } + + public int Order { get; set; } + + public ScalarStyle ScalarStyle + { + get => _baseDescriptor.ScalarStyle; + set => _baseDescriptor.ScalarStyle = value; + } + + public bool CanWrite + => _baseDescriptor.CanWrite; + + private readonly IPropertyDescriptor _baseDescriptor; + + public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor) + { + _baseDescriptor = baseDescriptor; + Name = baseDescriptor.Name; + } + + public void Write(object target, object value) + => _baseDescriptor.Write(target, value); + + public T GetCustomAttribute() + where T : Attribute + => _baseDescriptor.GetCustomAttribute(); + + public IObjectDescriptor Read(object target) + { + var comment = _baseDescriptor.GetCustomAttribute(); + return comment is not null + ? new CommentsObjectDescriptor(_baseDescriptor.Read(target), comment.Comment) + : _baseDescriptor.Read(target); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/CommentsObjectDescriptor.cs b/src/EllieBot/_common/Yml/CommentsObjectDescriptor.cs new file mode 100644 index 0000000..ce54758 --- /dev/null +++ b/src/EllieBot/_common/Yml/CommentsObjectDescriptor.cs @@ -0,0 +1,30 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Yml; + +public sealed class CommentsObjectDescriptor : IObjectDescriptor +{ + public string Comment { get; } + + public object Value + => _innerDescriptor.Value; + + public Type Type + => _innerDescriptor.Type; + + public Type StaticType + => _innerDescriptor.StaticType; + + public ScalarStyle ScalarStyle + => _innerDescriptor.ScalarStyle; + + private readonly IObjectDescriptor _innerDescriptor; + + public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment) + { + _innerDescriptor = innerDescriptor; + Comment = comment; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/CommentsObjectGraphVisitor.cs b/src/EllieBot/_common/Yml/CommentsObjectGraphVisitor.cs new file mode 100644 index 0000000..1c89a95 --- /dev/null +++ b/src/EllieBot/_common/Yml/CommentsObjectGraphVisitor.cs @@ -0,0 +1,29 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.ObjectGraphVisitors; + +namespace EllieBot.Common.Yml; + +public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor +{ + public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) + : base(nextVisitor) + { + } + + public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) + { + if (value is CommentsObjectDescriptor commentsDescriptor + && !string.IsNullOrWhiteSpace(commentsDescriptor.Comment)) + { + var parts = commentsDescriptor.Comment.Split('\n'); + + foreach (var part in parts) + context.Emit(new Comment(part.Trim(), false)); + } + + return base.EnterMapping(key, value, context); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs b/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs new file mode 100644 index 0000000..e2cfd97 --- /dev/null +++ b/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs @@ -0,0 +1,36 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.EventEmitters; + +namespace EllieBot.Common.Yml; + + +public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter +{ + public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter) + : base(nextEmitter) + { + } + + public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) + { + if (typeof(string).IsAssignableFrom(eventInfo.Source.Type)) + { + var value = eventInfo.Source.Value as string; + if (!string.IsNullOrEmpty(value)) + { + var isMultiLine = value.IndexOfAny(['\r', '\n', '\x85', '\x2028', '\x2029']) >= 0; + if (isMultiLine) + { + eventInfo = new(eventInfo.Source) + { + Style = ScalarStyle.Literal + }; + } + } + } + + nextEmitter.Emit(eventInfo, emitter); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/Rgba32Converter.cs b/src/EllieBot/_common/Yml/Rgba32Converter.cs new file mode 100644 index 0000000..12f6cf9 --- /dev/null +++ b/src/EllieBot/_common/Yml/Rgba32Converter.cs @@ -0,0 +1,47 @@ +#nullable disable +using SixLabors.ImageSharp.PixelFormats; +using System.Globalization; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Yml; + +public class Rgba32Converter : IYamlTypeConverter +{ + public bool Accepts(Type type) + => type == typeof(Rgba32); + + public object ReadYaml(IParser parser, Type type) + { + var scalar = parser.Consume(); + var result = Rgba32.ParseHex(scalar.Value); + return result; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var color = (Rgba32)value; + var val = (uint)((color.B << 0) | (color.G << 8) | (color.R << 16)); + emitter.Emit(new Scalar(val.ToString("X6").ToLower())); + } +} + +public class CultureInfoConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) + => type == typeof(CultureInfo); + + public object ReadYaml(IParser parser, Type type) + { + var scalar = parser.Consume(); + var result = new CultureInfo(scalar.Value); + return result; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var ci = (CultureInfo)value; + emitter.Emit(new Scalar(ci.Name)); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/UriConverter.cs b/src/EllieBot/_common/Yml/UriConverter.cs new file mode 100644 index 0000000..66e2ca0 --- /dev/null +++ b/src/EllieBot/_common/Yml/UriConverter.cs @@ -0,0 +1,25 @@ +#nullable disable +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace EllieBot.Common.Yml; + +public class UriConverter : IYamlTypeConverter +{ + public bool Accepts(Type type) + => type == typeof(Uri); + + public object ReadYaml(IParser parser, Type type) + { + var scalar = parser.Consume(); + var result = new Uri(scalar.Value); + return result; + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var uri = (Uri)value; + emitter.Emit(new Scalar(uri.ToString())); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/Yml/Yaml.cs b/src/EllieBot/_common/Yml/Yaml.cs new file mode 100644 index 0000000..c4779cc --- /dev/null +++ b/src/EllieBot/_common/Yml/Yaml.cs @@ -0,0 +1,30 @@ +#nullable disable +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace EllieBot.Common.Yml; + +public class Yaml +{ + public static ISerializer Serializer + => new SerializerBuilder() + .WithTypeInspector(inner => new CommentGatheringTypeInspector(inner)) + .DisableAliases() + .WithEmissionPhaseObjectGraphVisitor(args + => new CommentsObjectGraphVisitor(args.InnerVisitor)) + .WithEventEmitter(args => new MultilineScalarFlowStyleEmitter(args)) + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .WithIndentedSequences() + .WithTypeConverter(new Rgba32Converter()) + .WithTypeConverter(new CultureInfoConverter()) + .WithTypeConverter(new UriConverter()) + .Build(); + + public static IDeserializer Deserializer + => new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance) + .WithTypeConverter(new Rgba32Converter()) + .WithTypeConverter(new CultureInfoConverter()) + .WithTypeConverter(new UriConverter()) + .IgnoreUnmatchedProperties() + .Build(); +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/BotCredentialsExtensions.cs b/src/EllieBot/_common/_Extensions/BotCredentialsExtensions.cs new file mode 100644 index 0000000..890bab3 --- /dev/null +++ b/src/EllieBot/_common/_Extensions/BotCredentialsExtensions.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Extensions; + +public static class BotCredentialsExtensions +{ + public static bool IsOwner(this IBotCredentials creds, IUser user) + => creds.IsOwner(user.Id); + + public static bool IsOwner(this IBotCredentials creds, ulong userId) + => creds.OwnerIds.Contains(userId); +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs b/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs new file mode 100644 index 0000000..7f90d78 --- /dev/null +++ b/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs @@ -0,0 +1,30 @@ +namespace EllieBot.Extensions; + +public static class CommandContextExtensions +{ + private static readonly Emoji _okEmoji = new Emoji("✅"); + private static readonly Emoji _warnEmoji = new Emoji("⚠️"); + private static readonly Emoji _errorEmoji = new Emoji("❌"); + + public static Task ReactAsync(this ICommandContext ctx, MsgType type) + { + var emoji = type switch + { + MsgType.Error => _errorEmoji, + MsgType.Pending => _warnEmoji, + MsgType.Ok => _okEmoji, + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + + return ctx.Message.AddReactionAsync(emoji); + } + + public static Task OkAsync(this ICommandContext ctx) + => ctx.ReactAsync(MsgType.Ok); + + public static Task ErrorAsync(this ICommandContext ctx) + => ctx.ReactAsync(MsgType.Error); + + public static Task WarningAsync(this ICommandContext ctx) + => ctx.ReactAsync(MsgType.Pending); +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/DbExtensions.cs b/src/EllieBot/_common/_Extensions/DbExtensions.cs new file mode 100644 index 0000000..58a9abd --- /dev/null +++ b/src/EllieBot/_common/_Extensions/DbExtensions.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Extensions; + +public static class DbExtensions +{ + public static DiscordUser GetOrCreateUser(this DbContext ctx, IUser original, Func, IQueryable>? includes = null) + => ctx.GetOrCreateUser(original.Id, original.Username, original.Discriminator, original.AvatarId, includes); +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/Extensions.cs b/src/EllieBot/_common/_Extensions/Extensions.cs new file mode 100644 index 0000000..27341ad --- /dev/null +++ b/src/EllieBot/_common/_Extensions/Extensions.cs @@ -0,0 +1,237 @@ +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; +using System.Text.RegularExpressions; +using Ellie.Common.Marmalade; + +namespace EllieBot.Extensions; + +public static class Extensions +{ + private static readonly Regex _urlRegex = + new(@"^(https?|ftp)://(?[^\s/$.?#].[^\s]*)$", RegexOptions.Compiled); + + /// + /// Converts to + /// + /// The to convert. + /// The . + public static DateOnly ToDateOnly(this DateTime dateTime) + => DateOnly.FromDateTime(dateTime); + + /// + /// Determines if is before today + /// + /// The to check. + /// True if is before today. + public static bool IsBeforeToday(this DateTime date) + => date < DateTime.UtcNow.Date; + + public static Task EditAsync(this IUserMessage msg, SmartText text) + => text switch + { + SmartEmbedText set => msg.ModifyAsync(x => + { + x.Embed = set.IsValid ? set.GetEmbed().Build() : null; + x.Content = set.PlainText?.SanitizeMentions() ?? ""; + }), + SmartEmbedTextArray set => msg.ModifyAsync(x => + { + x.Embeds = set.GetEmbedBuilders().Map(eb => eb.Build()); + x.Content = set.Content?.SanitizeMentions() ?? ""; + }), + SmartPlainText spt => msg.ModifyAsync(x => + { + x.Content = spt.Text.SanitizeMentions(); + x.Embed = null; + }), + _ => throw new ArgumentOutOfRangeException(nameof(text)) + }; + + public static ulong[] GetGuildIds(this DiscordSocketClient client) + => client.Guilds + .Map(x => x.Id); + + /// + /// Generates a string in the format HHH:mm if timespan is >= 2m. + /// Generates a string in the format 00:mm:ss if timespan is less than 2m. + /// + /// Timespan to convert to string + /// Formatted duration string + public static string ToPrettyStringHm(this TimeSpan span) + { + if(span > TimeSpan.FromHours(24)) + return $"{span.Days:00}d:{span.Hours:00}h"; + + if (span > TimeSpan.FromMinutes(2)) + return $"{span.Hours:00}h:{span.Minutes:00}m"; + + return $"{span.Minutes:00}m:{span.Seconds:00}s"; + } + + public static double Megabytes(this int mb) + => mb * 1024d * 1024; + + public static TimeSpan Hours(this int hours) + => TimeSpan.FromHours(hours); + + public static TimeSpan Minutes(this int minutes) + => TimeSpan.FromMinutes(minutes); + + public static TimeSpan Days(this int days) + => TimeSpan.FromDays(days); + + public static TimeSpan Seconds(this int seconds) + => TimeSpan.FromSeconds(seconds); + + public static bool TryGetUrlPath(this string input, out string path) + { + var match = _urlRegex.Match(input); + if (match.Success) + { + path = match.Groups["path"].Value; + return true; + } + + path = string.Empty; + return false; + } + + public static IEmote ToIEmote(this string emojiStr) + => Emote.TryParse(emojiStr, out var maybeEmote) ? maybeEmote : new Emoji(emojiStr); + + + /// + /// First 10 characters of teh bot token. + /// + public static string RedisKey(this IBotCredentials bc) + => bc.Token[..10]; + + public static bool IsAuthor(this IMessage msg, IDiscordClient client) + => msg.Author?.Id == client.CurrentUser.Id; + + public static string RealSummary( + this CommandInfo cmd, + IBotStrings strings, + IMarmaladeLoaderService marmalades, + CultureInfo culture, + string prefix) + { + string description; + if (cmd.Remarks?.StartsWith("marmalade///") ?? false) + { + // command method name is kept in Summary + // marmalade/// is kept in remarks + // this way I can find the name of the marmalade, and then name of the command for which + // the description should be loaded + var marmaladeName = cmd.Remarks.Split("///")[1]; + description = marmalades.GetCommandDescription(marmaladeName, cmd.Summary, culture); + } + else + { + description = strings.GetCommandStrings(cmd.Summary, culture).Desc; + } + + return string.Format(description, prefix); + } + + public static string[] RealRemarksArr( + this CommandInfo cmd, + IBotStrings strings, + IMarmaladeLoaderService marmalades, + CultureInfo culture, + string prefix) + { + string[] args; + if (cmd.Remarks?.StartsWith("marmalade///") ?? false) + { + // command method name is kept in Summary + // marmalade/// is kept in remarks + // this way I can find the name of the marmalade, + // and command for which data should be loaded + var marmaladeName = cmd.Remarks.Split("///")[1]; + args = marmalades.GetCommandExampleArgs(marmaladeName, cmd.Summary, culture); + } + else + { + args = strings.GetCommandStrings(cmd.Summary, culture).Examples; + } + + return args.Map(arg => GetFullUsage(cmd.Aliases.First(), arg, prefix)); + } + + private static string GetFullUsage(string commandName, string args, string prefix) + => $"{prefix}{commandName} {string.Format(args, prefix)}".TrimEnd(); + + public static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage) + { + if (lastPage is not null) + return embed.WithFooter($"{curPage + 1} / {lastPage + 1}"); + + return embed.WithFooter((curPage + 1).ToString()); + } + + // public static EmbedBuilder WithOkColor(this EmbedBuilder eb) + // => eb.WithColor(EmbedColor.Ok); + // + // public static EmbedBuilder WithPendingColor(this EmbedBuilder eb) + // => eb.WithColor(EmbedColor.Pending); + // + // public static EmbedBuilder WithErrorColor(this EmbedBuilder eb) + // => eb.WithColor(EmbedColor.Error); + // + public static IMessage DeleteAfter(this IUserMessage msg, float seconds, ILogCommandService? logService = null) + { + Task.Run(async () => + { + await Task.Delay((int)(seconds * 1000)); + if (logService is not null) + logService.AddDeleteIgnore(msg.Id); + + try + { + await msg.DeleteAsync(); + } + catch + { + } + }); + return msg; + } + + public static ModuleInfo GetTopLevelModule(this ModuleInfo module) + { + while (module.Parent is not null) + module = module.Parent; + + return module; + } + + public static string GetGroupName(this ModuleInfo module) + => module.Name.Replace("Commands", "", StringComparison.InvariantCulture); + + public static async Task> GetMembersAsync(this IRole role) + { + var users = await role.Guild.GetUsersAsync(CacheMode.CacheOnly); + return users.Where(u => u.RoleIds.Contains(role.Id)); + } + + public static string ToJson(this T any, JsonSerializerOptions? options = null) + => JsonSerializer.Serialize(any, options); + + public static Stream ToStream(this IEnumerable bytes, bool canWrite = false) + { + var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite); + ms.Seek(0, SeekOrigin.Begin); + return ms; + } + + public static IEnumerable GetRoles(this IGuildUser user) + => user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r is not null); + + public static void Lap(this Stopwatch sw, string checkpoint) + { + Log.Information("Checkpoint {CheckPoint}: {Time}ms", checkpoint, sw.Elapsed.TotalMilliseconds); + sw.Restart(); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/ImagesharpExtensions.cs b/src/EllieBot/_common/_Extensions/ImagesharpExtensions.cs new file mode 100644 index 0000000..e8414dd --- /dev/null +++ b/src/EllieBot/_common/_Extensions/ImagesharpExtensions.cs @@ -0,0 +1,97 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using Color = Discord.Color; + +namespace EllieBot.Extensions; + +public static class ImagesharpExtensions +{ + // https://github.com/SixLabors/Samples/blob/master/ImageSharp/AvatarWithRoundedCorner/Program.cs + public static IImageProcessingContext ApplyRoundedCorners(this IImageProcessingContext ctx, float cornerRadius) + { + var size = ctx.GetCurrentSize(); + var corners = BuildCorners(size.Width, size.Height, cornerRadius); + + ctx.SetGraphicsOptions(new GraphicsOptions + { + Antialias = true, + // enforces that any part of this shape that has color is punched out of the background + AlphaCompositionMode = PixelAlphaCompositionMode.DestOut + }); + + foreach (var c in corners) + ctx = ctx.Fill(SixLabors.ImageSharp.Color.Red, c); + + return ctx; + } + + private static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius) + { + // first create a square + var rect = new RectangularPolygon(-0.5f, -0.5f, cornerRadius, cornerRadius); + + // then cut out of the square a circle so we are left with a corner + var cornerTopLeft = rect.Clip(new EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius)); + + // corner is now a corner shape positions top left + //lets make 3 more positioned correctly, we can do that by translating the original around the center of the image + + var rightPos = imageWidth - cornerTopLeft.Bounds.Width + 1; + var bottomPos = imageHeight - cornerTopLeft.Bounds.Height + 1; + + // move it across the width of the image - the width of the shape + var cornerTopRight = cornerTopLeft.RotateDegree(90).Translate(rightPos, 0); + var cornerBottomLeft = cornerTopLeft.RotateDegree(-90).Translate(0, bottomPos); + var cornerBottomRight = cornerTopLeft.RotateDegree(180).Translate(rightPos, bottomPos); + + return new PathCollection(cornerTopLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight); + } + + public static Color ToDiscordColor(this Rgba32 color) + => new(color.R, color.G, color.B); + + public static MemoryStream ToStream(this Image img, IImageFormat? format = null) + { + var imageStream = new MemoryStream(); + if (format?.Name == "GIF") + img.SaveAsGif(imageStream); + else + { + img.SaveAsPng(imageStream, + new() + { + ColorType = PngColorType.RgbWithAlpha, + CompressionLevel = PngCompressionLevel.DefaultCompression + }); + } + + imageStream.Position = 0; + return imageStream; + } + + public static async Task ToStreamAsync(this Image img, IImageFormat? format = null) + { + var imageStream = new MemoryStream(); + if (format?.Name == "GIF") + { + await img.SaveAsGifAsync(imageStream); + } + else + { + await img.SaveAsPngAsync(imageStream, + new PngEncoder() + { + ColorType = PngColorType.RgbWithAlpha, + CompressionLevel = PngCompressionLevel.DefaultCompression + }); + } + + imageStream.Position = 0; + return imageStream; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/LinkedListExtensions.cs b/src/EllieBot/_common/_Extensions/LinkedListExtensions.cs new file mode 100644 index 0000000..018359e --- /dev/null +++ b/src/EllieBot/_common/_Extensions/LinkedListExtensions.cs @@ -0,0 +1,18 @@ +namespace EllieBot.Extensions; + +public static class LinkedListExtensions +{ + public static LinkedListNode? FindNode(this LinkedList list, Func predicate) + { + var node = list.First; + while (node is not null) + { + if (predicate(node.Value)) + return node; + + node = node.Next; + } + + return null; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/NumberExtensions.cs b/src/EllieBot/_common/_Extensions/NumberExtensions.cs new file mode 100644 index 0000000..3e0f703 --- /dev/null +++ b/src/EllieBot/_common/_Extensions/NumberExtensions.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Extensions; + +public static class NumberExtensions +{ + public static DateTimeOffset ToUnixTimestamp(this double number) + => new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero).AddSeconds(number); +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/ReflectionExtensions.cs b/src/EllieBot/_common/_Extensions/ReflectionExtensions.cs new file mode 100644 index 0000000..49be90e --- /dev/null +++ b/src/EllieBot/_common/_Extensions/ReflectionExtensions.cs @@ -0,0 +1,23 @@ +namespace EllieBot.Extensions; + +public static class ReflectionExtensions +{ + public static bool IsAssignableToGenericType(this Type givenType, Type genericType) + { + var interfaceTypes = givenType.GetInterfaces(); + + foreach (var it in interfaceTypes) + { + if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType) + return true; + } + + if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType) + return true; + + var baseType = givenType.BaseType; + if (baseType == null) return false; + + return IsAssignableToGenericType(baseType, genericType); + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/Rgba32Extensions.cs b/src/EllieBot/_common/_Extensions/Rgba32Extensions.cs new file mode 100644 index 0000000..a0cd408 --- /dev/null +++ b/src/EllieBot/_common/_Extensions/Rgba32Extensions.cs @@ -0,0 +1,57 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace EllieBot.Extensions; + +public static class Rgba32Extensions +{ + public static Image Merge(this IEnumerable> images) + => images.Merge(out _); + + public static Image Merge(this IEnumerable> images, out IImageFormat format) + { + format = PngFormat.Instance; + + void DrawFrame(IList> imgArray, Image imgFrame, int frameNumber) + { + var xOffset = 0; + for (var i = 0; i < imgArray.Count; i++) + { + using var frame = imgArray[i].Frames.CloneFrame(frameNumber % imgArray[i].Frames.Count); + var offset = xOffset; + imgFrame.Mutate(x => x.DrawImage(frame, new Point(offset, 0), new GraphicsOptions())); + xOffset += imgArray[i].Bounds().Width; + } + } + + var imgs = images.ToList(); + var frames = imgs.Max(x => x.Frames.Count); + + var width = imgs.Sum(img => img.Width); + var height = imgs.Max(img => img.Height); + var canvas = new Image(width, height); + if (frames == 1) + { + DrawFrame(imgs, canvas, 0); + return canvas; + } + + format = GifFormat.Instance; + for (var j = 0; j < frames; j++) + { + using var imgFrame = new Image(width, height); + DrawFrame(imgs, imgFrame, j); + + var frameToAdd = imgFrame.Frames[0]; + frameToAdd.Metadata.GetGifMetadata().DisposalMethod = GifDisposalMethod.RestoreToBackground; + canvas.Frames.AddFrame(frameToAdd); + } + + canvas.Frames.RemoveFrame(0); + return canvas; + } +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/SocketMessageComponentExtensions.cs b/src/EllieBot/_common/_Extensions/SocketMessageComponentExtensions.cs new file mode 100644 index 0000000..1b99fa7 --- /dev/null +++ b/src/EllieBot/_common/_Extensions/SocketMessageComponentExtensions.cs @@ -0,0 +1,33 @@ +namespace EllieBot.Extensions; + +public static class SocketMessageComponentExtensions +{ + public static async Task RespondAsync( + this SocketMessageComponent ch, + IMessageSenderService sender, + string text, + MsgType type, + bool ephemeral = false) + { + var embed = sender.CreateEmbed().WithDescription(text); + + embed = (type switch + { + MsgType.Error => embed.WithErrorColor(), + MsgType.Ok => embed.WithOkColor(), + MsgType.Pending => embed.WithPendingColor(), + _ => throw new ArgumentOutOfRangeException(nameof(type)) + }); + + await ch.RespondAsync(embeds: [embed.Build()], ephemeral: ephemeral); + } + + // embed title and optional footer overloads + + public static Task RespondConfirmAsync( + this SocketMessageComponent smc, + IMessageSenderService sender, + string text, + bool ephemeral = false) + => smc.RespondAsync(sender, text, MsgType.Ok, ephemeral); +} \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/UserExtensions.cs b/src/EllieBot/_common/_Extensions/UserExtensions.cs new file mode 100644 index 0000000..8f81f61 --- /dev/null +++ b/src/EllieBot/_common/_Extensions/UserExtensions.cs @@ -0,0 +1,21 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Extensions; + +public static class UserExtensions +{ + // This method is used by everything that fetches the avatar from a user + public static Uri RealAvatarUrl(this IUser usr, ushort size = 256) + => usr.AvatarId is null ? new(usr.GetDefaultAvatarUrl()) : new Uri(usr.GetAvatarUrl(ImageFormat.Auto, size)); + + // This method is only used for the xp card + public static Uri? RealAvatarUrl(this DiscordUser usr) + { + if (!string.IsNullOrWhiteSpace(usr.AvatarId)) + return new Uri(CDN.GetUserAvatarUrl(usr.UserId, usr.AvatarId, 128, ImageFormat.Png)); + + return Uri.TryCreate(CDN.GetDefaultUserAvatarUrl(usr.UserId), UriKind.Absolute, out var uri) + ? uri + : null; + } +} \ No newline at end of file From 34eb87b13d3f2a774fa5e336bf295b71f6ad52e0 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:45:23 +1200 Subject: [PATCH 43/62] Updated base project files --- src/EllieBot/Bot.cs | 230 ++++++++++++--------------- src/EllieBot/Directory.Build.props | 7 - src/EllieBot/EllieBot.csproj | 245 +++++++++++++++-------------- 3 files changed, 226 insertions(+), 256 deletions(-) delete mode 100644 src/EllieBot/Directory.Build.props diff --git a/src/EllieBot/Bot.cs b/src/EllieBot/Bot.cs index d6ab91a..1ce8774 100644 --- a/src/EllieBot/Bot.cs +++ b/src/EllieBot/Bot.cs @@ -1,28 +1,26 @@ #nullable disable +using DryIoc; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using EllieBot.Common.Configs; using EllieBot.Common.ModuleBehaviors; -using EllieBot.Db; -using EllieBot.Modules.Utility; -using EllieBot.Services.Database.Models; +using EllieBot.Db.Models; using System.Collections.Immutable; using System.Diagnostics; -using System.Net; using System.Reflection; using RunMode = Discord.Commands.RunMode; namespace EllieBot; -public sealed class Bot +public sealed class Bot : IBot { public event Func JoinedGuild = delegate { return Task.CompletedTask; }; public DiscordSocketClient Client { get; } - public ImmutableArray AllGuildConfigs { get; private set; } + public IReadOnlyCollection AllGuildConfigs { get; private set; } - private IServiceProvider Services { get; set; } + private IContainer Services { get; set; } - public string Mention { get; private set; } public bool IsReady { get; private set; } public int ShardId { get; set; } @@ -31,18 +29,19 @@ public sealed class Bot private readonly DbService _db; private readonly IBotCredsProvider _credsProvider; + + private readonly Assembly[] _loadedAssemblies; // private readonly InteractionService _interactionService; public Bot(int shardId, int? totalShards, string credPath = null) { - if (shardId < 0) - throw new ArgumentOutOfRangeException(nameof(shardId)); + ArgumentOutOfRangeException.ThrowIfLessThan(shardId, 0); ShardId = shardId; _credsProvider = new BotCredsProvider(totalShards, credPath); _creds = _credsProvider.GetCreds(); - _db = new(_credsProvider); + _db = new EllieDbService(_credsProvider); var messageCacheSize = #if GLOBAL_ELLIE @@ -51,9 +50,9 @@ public sealed class Bot 50; #endif - if(!_creds.UsePrivilegedIntents) + if (!_creds.UsePrivilegedIntents) Log.Warning("You are not using privileged intents. Some features will not work properly"); - + Client = new(new() { MessageCacheSize = messageCacheSize, @@ -81,10 +80,14 @@ public sealed class Bot // _interactionService = new(Client.Rest); Client.Log += Client_Log; + _loadedAssemblies = + [ + typeof(Bot).Assembly // bot + ]; } - public List GetCurrentGuildIds() + public IReadOnlyList GetCurrentGuildIds() => Client.Guilds.Select(x => x.Id).ToList(); private void AddServices() @@ -96,120 +99,89 @@ public sealed class Bot using (var uow = _db.GetDbContext()) { uow.EnsureUserCreated(bot.Id, bot.Username, bot.Discriminator, bot.AvatarId); - AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); + AllGuildConfigs = uow.Set().GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); } - var svcs = new ServiceCollection().AddTransient(_ => _credsProvider.GetCreds()) // bot creds - .AddSingleton(_credsProvider) - .AddSingleton(_db) // database - .AddSingleton(Client) // discord socket client - .AddSingleton(_commandService) - // .AddSingleton(_interactionService) - .AddSingleton(this) - .AddSingleton() - .AddSingleton() - .AddConfigServices() - .AddConfigMigrators() - .AddMemoryCache() - // music - .AddMusic() - // cache - .AddCache(_creds); - + // var svcs = new StandardKernel(new NinjectSettings() + // { + // // ThrowOnGetServiceNotFound = true, + // ActivationCacheDisabled = true, + // }); - svcs.AddHttpClient(); - svcs.AddHttpClient("memelist") - .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler - { - AllowAutoRedirect = false - }); - - svcs.AddHttpClient("google:search") - .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() - { - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate - }); + var svcs = new Container(); - if (Environment.GetEnvironmentVariable("ELLIE_IS_COORDINATED") != "1") + // this is required in order for medusa unloading to work + // svcs.Components.Remove(); + // svcs.Components.Add(); + + svcs.AddSingleton(_ => _credsProvider.GetCreds()); + svcs.AddSingleton(_db); + svcs.AddSingleton(_credsProvider); + svcs.AddSingleton(Client); + svcs.AddSingleton(_commandService); + svcs.AddSingleton(this); + svcs.AddSingleton(this); + + svcs.AddSingleton(); + svcs.AddSingleton(); + svcs.AddSingleton(new MemoryCache(new MemoryCacheOptions())); + svcs.AddSingleton(); + svcs.AddSingleton(); + + + foreach (var a in _loadedAssemblies) + { + svcs.AddConfigServices(a) + .AddLifetimeServices(a); + } + + svcs.AddMusic() + .AddCache(_creds) + .AddHttpClients(); + + if (Environment.GetEnvironmentVariable("ELLIEBOT_IS_COORDINATED") != "1") + { svcs.AddSingleton(); + } else { - svcs.AddSingleton() - .AddSingleton(x => x.GetRequiredService()) - .AddSingleton(x => x.GetRequiredService()); + svcs.AddSingleton(); + svcs.AddSingleton(_ => svcs.GetRequiredService()); + svcs.AddSingleton(_ => svcs.GetRequiredService()); } - svcs.Scan(scan => scan.FromAssemblyOf() - .AddClasses(classes => classes.AssignableToAny( - // services - typeof(IEService), - - // behaviours - typeof(IExecOnMessage), - typeof(IInputTransformer), - typeof(IExecPreCommand), - typeof(IExecPostCommand), - typeof(IExecNoCommand)) - .WithoutAttribute() -#if GLOBAL_ELLIE - .WithoutAttribute() -#endif - ) - .AsSelfWithInterfaces() - .WithSingletonLifetime()); + svcs.AddSingleton(svcs); //initialize Services - Services = svcs.BuildServiceProvider(); + Services = svcs; Services.GetRequiredService().Initialize(); - Services.GetRequiredService(); - if (Client.ShardId == 0) - ApplyConfigMigrations(); - - _ = LoadTypeReaders(typeof(Bot).Assembly); + foreach (var a in _loadedAssemblies) + { + LoadTypeReaders(a); + } sw.Stop(); - Log.Information( "All services loaded in {ServiceLoadTime:F2}s", sw.Elapsed.TotalSeconds); + Log.Information("All services loaded in {ServiceLoadTime:F2}s", sw.Elapsed.TotalSeconds); } - private void ApplyConfigMigrations() + private void LoadTypeReaders(Assembly assembly) { - // execute all migrators - var migrators = Services.GetServices(); - foreach (var migrator in migrators) - migrator.EnsureMigrated(); - } - - private IEnumerable LoadTypeReaders(Assembly assembly) - { - Type[] allTypes; - try - { - allTypes = assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - Log.Warning(ex.LoaderExceptions[0], "Error getting types"); - return Enumerable.Empty(); - } - - var filteredTypes = allTypes.Where(x => x.IsSubclassOf(typeof(TypeReader)) + var filteredTypes = assembly.GetExportedTypes() + .Where(x => x.IsSubclassOf(typeof(TypeReader)) && x.BaseType?.GetGenericArguments().Length > 0 && !x.IsAbstract); - var toReturn = new List(); foreach (var ft in filteredTypes) { - var x = (TypeReader)ActivatorUtilities.CreateInstance(Services, ft); var baseType = ft.BaseType; if (baseType is null) continue; - var typeArgs = baseType.GetGenericArguments(); - _commandService.AddTypeReader(typeArgs[0], x); - toReturn.Add(x); - } - return toReturn; + var typeReader = (TypeReader)ActivatorUtilities.CreateInstance(Services, ft); + var typeArgs = baseType.GetGenericArguments(); + _commandService.AddTypeReader(typeArgs[0], typeReader); + } } private async Task LoginAsync(string token) @@ -249,10 +221,10 @@ public sealed class Bot LoginErrorHandler.Handle(ex); Helpers.ReadErrorAndExit(4); } - + await clientReady.Task.ConfigureAwait(false); Client.Ready -= SetClientReady; - + Client.JoinedGuild += Client_JoinedGuild; Client.LeftGuild += Client_LeftGuild; @@ -286,12 +258,11 @@ public sealed class Bot { if (ShardId == 0) await _db.SetupAsync(); - + var sw = Stopwatch.StartNew(); await LoginAsync(_creds.Token); - Mention = Client.CurrentUser.Mention; Log.Information("Shard {ShardId} loading services...", Client.ShardId); try { @@ -310,7 +281,11 @@ public sealed class Bot // start handling messages received in commandhandler await commandHandler.StartHandling(); - await _commandService.AddModulesAsync(typeof(Bot).Assembly, Services); + foreach (var a in _loadedAssemblies) + { + await _commandService.AddModulesAsync(a, Services); + } + // await _interactionService.AddModulesAsync(typeof(Bot).Assembly, Services); IsReady = true; @@ -364,29 +339,30 @@ public sealed class Bot if (arg.Exception is { InnerException: WebSocketClosedException { CloseCode: 4014 } }) { - Log.Error(@" -Login failed. - -*** Please enable privileged intents *** - -Certain Ellie features require Discord's privileged gateway intents. -These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding. - -How to enable privileged intents: -1. Head over to the Discord Developer Portal https://discord.com/developers/applications/ -2. Select your Application. -3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section. -4. Enable all intents. -5. Restart your bot. - -Read this only if your bot is in 100 or more servers: - -You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal. -Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before. -While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the ellie's features"); + Log.Error(""" + Login failed. + + *** Please enable privileged intents *** + + Certain Ellie features require Discord's privileged gateway intents. + These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding. + + How to enable privileged intents: + 1. Head over to the Discord Developer Portal https://discord.com/developers/applications/ + 2. Select your Application. + 3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section. + 4. Enable all intents. + 5. Restart your bot. + + Read this only if your bot is in 100 or more servers: + + You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal. + Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before. + While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the ellie's features + """); return Task.CompletedTask; } - + #if GLOBAL_ELLIE || DEBUG if (arg.Exception is not null) Log.Warning(arg.Exception, "{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message); diff --git a/src/EllieBot/Directory.Build.props b/src/EllieBot/Directory.Build.props deleted file mode 100644 index 1623cb0..0000000 --- a/src/EllieBot/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - all - - - \ No newline at end of file diff --git a/src/EllieBot/EllieBot.csproj b/src/EllieBot/EllieBot.csproj index 5f4dbb0..2c605d4 100644 --- a/src/EllieBot/EllieBot.csproj +++ b/src/EllieBot/EllieBot.csproj @@ -1,142 +1,143 @@  - - net6.0 - preview - enable - true - true + net8.0 + enable + true + en + 5.0.8 - - $(MSBuildProjectDirectory) - exe - ellie_icon.ico + + $(MSBuildProjectDirectory) + exe + ellie_icon.ico - - - - CS1066 - + + + + CS1066;CS8981 - - - all - True - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + true + embedded - - - - - - - - - - - - - - - - - - - - - - - - + - - all - True - + + + all + True + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - + + + - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + - + + + + + + + - - - + + + + + + + + + + - - + + + + + + + - - - - - + - - - - - - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - - - Protos\coordinator.proto - - - PreserveNewest - - - PreserveNewest - - - Always - - + - - 4.0.0 - $(VersionPrefix).$(VersionSuffix) - $(VersionPrefix) - + + + - - - false - GLOBAL_ELLIE - $(NoWarn);CS1573;CS1591 - true - portable - false - + + + + + + + + + + + + + + + + + + + + + + Protos\coordinator.proto + + + true + PreserveNewest + + + true + Always + + + true + Always + + + + + + false + GLOBAL_ELLIE + $(NoWarn);CS1573;CS1591 + true + portable + false + From a61b98a0f53e165549b036869f6e1019010b72fd Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:46:10 +1200 Subject: [PATCH 44/62] Updated services files --- .../Services/Impl/BotCredsProvider.cs | 204 ++++++++++++++++ .../Services/Impl/GoogleApiService.cs | 229 ++++++++++++++++++ .../GoogleApiService_SupportedLanguages.cs | 160 ++++++++++++ src/EllieBot/Services/Impl/ImageCache.cs | 83 +++++++ src/EllieBot/Services/Impl/LocalDataCache.cs | 108 +++++++++ src/EllieBot/Services/Impl/Localization.cs | 121 +++++++++ .../Services/Impl/PubSub/JsonSeria.cs | 27 +++ .../Services/Impl/PubSub/RedisPubSub.cs | 57 +++++ .../Services/Impl/PubSub/YamlSeria.cs | 39 +++ src/EllieBot/Services/Impl/RedisBotCache.cs | 119 +++++++++ .../Services/Impl/RedisBotStringsProvider.cs | 91 +++++++ .../Services/Impl/RemoteGrpcCoordinator.cs | 132 ++++++++++ 12 files changed, 1370 insertions(+) create mode 100644 src/EllieBot/Services/Impl/BotCredsProvider.cs create mode 100644 src/EllieBot/Services/Impl/GoogleApiService.cs create mode 100644 src/EllieBot/Services/Impl/GoogleApiService_SupportedLanguages.cs create mode 100644 src/EllieBot/Services/Impl/ImageCache.cs create mode 100644 src/EllieBot/Services/Impl/LocalDataCache.cs create mode 100644 src/EllieBot/Services/Impl/Localization.cs create mode 100644 src/EllieBot/Services/Impl/PubSub/JsonSeria.cs create mode 100644 src/EllieBot/Services/Impl/PubSub/RedisPubSub.cs create mode 100644 src/EllieBot/Services/Impl/PubSub/YamlSeria.cs create mode 100644 src/EllieBot/Services/Impl/RedisBotCache.cs create mode 100644 src/EllieBot/Services/Impl/RedisBotStringsProvider.cs create mode 100644 src/EllieBot/Services/Impl/RemoteGrpcCoordinator.cs diff --git a/src/EllieBot/Services/Impl/BotCredsProvider.cs b/src/EllieBot/Services/Impl/BotCredsProvider.cs new file mode 100644 index 0000000..3d2638e --- /dev/null +++ b/src/EllieBot/Services/Impl/BotCredsProvider.cs @@ -0,0 +1,204 @@ +#nullable disable +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Primitives; +using EllieBot.Common.Yml; +using Newtonsoft.Json; + +namespace EllieBot.Services; + +public sealed class BotCredsProvider : IBotCredsProvider +{ + private const string CREDS_FILE_NAME = "creds.yml"; + private const string CREDS_EXAMPLE_FILE_NAME = "creds_example.yml"; + + private string CredsPath { get; } + + private string CredsExamplePath { get; } + + private readonly int? _totalShards; + + + private readonly Creds _creds = new(); + private readonly IConfigurationRoot _config; + + + private readonly object _reloadLock = new(); + private readonly IDisposable _changeToken; + + public BotCredsProvider(int? totalShards = null, string credPath = null) + { + _totalShards = totalShards; + + if (!string.IsNullOrWhiteSpace(credPath)) + { + CredsPath = credPath; + CredsExamplePath = Path.Combine(Path.GetDirectoryName(credPath), CREDS_EXAMPLE_FILE_NAME); + } + else + { + CredsPath = Path.Combine(Directory.GetCurrentDirectory(), CREDS_FILE_NAME); + CredsExamplePath = Path.Combine(Directory.GetCurrentDirectory(), CREDS_EXAMPLE_FILE_NAME); + } + + try + { + if (!File.Exists(CredsExamplePath)) + File.WriteAllText(CredsExamplePath, Yaml.Serializer.Serialize(_creds)); + } + catch + { + // this can fail in docker containers + } + + MigrateCredentials(); + + if (!File.Exists(CredsPath)) + { + Log.Warning( + "{CredsPath} is missing. Attempting to load creds from environment variables prefixed with 'EllieBot_'. Example is in {CredsExamplePath}", + CredsPath, + CredsExamplePath); + } + + try + { + _config = new ConfigurationBuilder().AddYamlFile(CredsPath, false, true) + .AddEnvironmentVariables("EllieBot_") + .Build(); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + } + + _changeToken = ChangeToken.OnChange(() => _config.GetReloadToken(), Reload); + Reload(); + } + + public void Reload() + { + lock (_reloadLock) + { + _creds.OwnerIds.Clear(); + _config.Bind(_creds); + + if (string.IsNullOrWhiteSpace(_creds.Token)) + { + Log.Error("Token is missing from creds.yml or Environment variables.\nAdd it and restart the program"); + Helpers.ReadErrorAndExit(5); + return; + } + + if (string.IsNullOrWhiteSpace(_creds.RestartCommand?.Cmd) + || string.IsNullOrWhiteSpace(_creds.RestartCommand?.Args)) + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + _creds.RestartCommand = new RestartConfig() + { + Args = "dotnet", + Cmd = "EllieBot.dll -- {0}" + }; + } + else + { + _creds.RestartCommand = new RestartConfig() + { + Args = "EllieBot.exe", + Cmd = "{0}" + }; + } + } + + if (string.IsNullOrWhiteSpace(_creds.RedisOptions)) + _creds.RedisOptions = "127.0.0.1,syncTimeout=3000"; + + // replace the old generated key with the shared key + if (string.IsNullOrWhiteSpace(_creds.CoinmarketcapApiKey) + || _creds.CoinmarketcapApiKey.StartsWith("e79ec505-0913")) + _creds.CoinmarketcapApiKey = "3077537c-7dfb-4d97-9a60-56fc9a9f5035"; + + _creds.TotalShards = _totalShards ?? _creds.TotalShards; + } + } + + public void ModifyCredsFile(Action func) + { + var ymlData = File.ReadAllText(CREDS_FILE_NAME); + var creds = Yaml.Deserializer.Deserialize(ymlData); + + func(creds); + + ymlData = Yaml.Serializer.Serialize(creds); + File.WriteAllText(CREDS_FILE_NAME, ymlData); + } + + private string OldCredsJsonPath + => Path.Combine(Directory.GetCurrentDirectory(), "credentials.json"); + + private string OldCredsJsonBackupPath + => Path.Combine(Directory.GetCurrentDirectory(), "credentials.json.bak"); + + private void MigrateCredentials() + { + if (File.Exists(OldCredsJsonPath)) + { + Log.Information("Migrating old creds..."); + var jsonCredentialsFileText = File.ReadAllText(OldCredsJsonPath); + var oldCreds = JsonConvert.DeserializeObject(jsonCredentialsFileText); + + if (oldCreds is null) + { + Log.Error("Error while reading old credentials file. Make sure that the file is formatted correctly"); + return; + } + + var creds = new Creds + { + Version = 1, + Token = oldCreds.Token, + OwnerIds = oldCreds.OwnerIds.Distinct().ToHashSet(), + GoogleApiKey = oldCreds.GoogleApiKey, + RapidApiKey = oldCreds.MashapeKey, + OsuApiKey = oldCreds.OsuApiKey, + CleverbotApiKey = oldCreds.CleverbotApiKey, + TotalShards = oldCreds.TotalShards <= 1 ? 1 : oldCreds.TotalShards, + Patreon = new Creds.PatreonSettings(oldCreds.PatreonAccessToken, null, null, oldCreds.PatreonCampaignId), + Votes = new Creds.VotesSettings(oldCreds.VotesUrl, oldCreds.VotesToken, string.Empty, string.Empty), + BotListToken = oldCreds.BotListToken, + RedisOptions = oldCreds.RedisOptions, + LocationIqApiKey = oldCreds.LocationIqApiKey, + TimezoneDbApiKey = oldCreds.TimezoneDbApiKey, + CoinmarketcapApiKey = oldCreds.CoinmarketcapApiKey + }; + + File.Move(OldCredsJsonPath, OldCredsJsonBackupPath, true); + File.WriteAllText(CredsPath, Yaml.Serializer.Serialize(creds)); + + Log.Warning( + "Data from credentials.json has been moved to creds.yml\nPlease inspect your creds.yml for correctness"); + } + + if (File.Exists(CREDS_FILE_NAME)) + { + var creds = Yaml.Deserializer.Deserialize(File.ReadAllText(CREDS_FILE_NAME)); + if (creds.Version <= 5) + { + creds.BotCache = BotCacheImplemenation.Redis; + } + if (creds.Version <= 6) + { + creds.Version = 7; + File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds)); + } + } + } + + public IBotCredentials GetCreds() + { + lock (_reloadLock) + { + return _creds; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/GoogleApiService.cs b/src/EllieBot/Services/Impl/GoogleApiService.cs new file mode 100644 index 0000000..9d4a494 --- /dev/null +++ b/src/EllieBot/Services/Impl/GoogleApiService.cs @@ -0,0 +1,229 @@ +#nullable disable +using Google; +using Google.Apis.Services; +using Google.Apis.Urlshortener.v1; +using Google.Apis.YouTube.v3; +using Newtonsoft.Json.Linq; +using System.Net; +using System.Text.RegularExpressions; +using System.Xml; + +namespace EllieBot.Services; + +public sealed partial class GoogleApiService : IGoogleApiService, IEService +{ + private static readonly Regex + _plRegex = new(@"(?:youtu\.be\/|list=)(?[\da-zA-Z\-_]*)", RegexOptions.Compiled); + + + private readonly YouTubeService _yt; + private readonly UrlshortenerService _sh; + + //private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?[a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); + private readonly IBotCredsProvider _creds; + private readonly IHttpClientFactory _httpFactory; + + public GoogleApiService(IBotCredsProvider creds, IHttpClientFactory factory) : this() + { + _creds = creds; + _httpFactory = factory; + + var bcs = new BaseClientService.Initializer + { + ApplicationName = "Ellie Bot", + ApiKey = _creds.GetCreds().GoogleApiKey + }; + + _yt = new(bcs); + _sh = new(bcs); + } + + public async Task> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1) + { + if (string.IsNullOrWhiteSpace(keywords)) + throw new ArgumentNullException(nameof(keywords)); + + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count); + + var match = _plRegex.Match(keywords); + if (match.Length > 1) + return new[] { match.Groups["id"].Value }; + var query = _yt.Search.List("snippet"); + query.MaxResults = count; + query.Type = "playlist"; + query.Q = keywords; + + return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId); + } + + public async Task> GetRelatedVideosAsync(string id, int count = 2, string user = null) + { + if (string.IsNullOrWhiteSpace(id)) + throw new ArgumentNullException(nameof(id)); + + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count); + + var query = _yt.Search.List("snippet"); + query.MaxResults = count; + query.Q = id; + // query.RelatedToVideoId = id; + query.Type = "video"; + query.QuotaUser = user; + // bad workaround as there's no replacement for related video querying right now. + // Query youtube with the id of the video, take a second video in the results + // skip the first one as that's probably the same video. + return (await query.ExecuteAsync()).Items.Select(i => "https://www.youtube.com/watch?v=" + i.Id.VideoId).Skip(1); + } + + public async Task> GetVideoLinksByKeywordAsync(string keywords, int count = 1) + { + if (string.IsNullOrWhiteSpace(keywords)) + throw new ArgumentNullException(nameof(keywords)); + + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count); + + var query = _yt.Search.List("snippet"); + query.MaxResults = count; + query.Q = keywords; + query.Type = "video"; + query.SafeSearch = SearchResource.ListRequest.SafeSearchEnum.Strict; + return (await query.ExecuteAsync()).Items.Select(i => "https://www.youtube.com/watch?v=" + i.Id.VideoId); + } + + public async Task> GetVideoInfosByKeywordAsync( + string keywords, + int count = 1) + { + if (string.IsNullOrWhiteSpace(keywords)) + throw new ArgumentNullException(nameof(keywords)); + + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count); + + var query = _yt.Search.List("snippet"); + query.MaxResults = count; + query.Q = keywords; + query.Type = "video"; + return (await query.ExecuteAsync()).Items.Select(i + => (i.Snippet.Title.TrimTo(50), + i.Id.VideoId, + "https://www.youtube.com/watch?v=" + i.Id.VideoId, + i.Snippet.Thumbnails.High.Url)); + } + + public Task ShortenUrl(Uri url) + => ShortenUrl(url.ToString()); + + public async Task ShortenUrl(string url) + { + if (string.IsNullOrWhiteSpace(url)) + throw new ArgumentNullException(nameof(url)); + + if (string.IsNullOrWhiteSpace(_creds.GetCreds().GoogleApiKey)) + return url; + + try + { + var response = await _sh.Url.Insert(new() + { + LongUrl = url + }) + .ExecuteAsync(); + return response.Id; + } + catch (GoogleApiException ex) when (ex.HttpStatusCode == HttpStatusCode.Forbidden) + { + return url; + } + catch (Exception ex) + { + Log.Warning(ex, "Error shortening URL"); + return url; + } + } + + public async Task> GetPlaylistTracksAsync(string playlistId, int count = 50) + { + if (string.IsNullOrWhiteSpace(playlistId)) + throw new ArgumentNullException(nameof(playlistId)); + + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count); + + string nextPageToken = null; + + var toReturn = new List(count); + + do + { + var toGet = count > 50 ? 50 : count; + count -= toGet; + + var query = _yt.PlaylistItems.List("contentDetails"); + query.MaxResults = toGet; + query.PlaylistId = playlistId; + query.PageToken = nextPageToken; + + var data = await query.ExecuteAsync(); + + toReturn.AddRange(data.Items.Select(i => i.ContentDetails.VideoId)); + nextPageToken = data.NextPageToken; + } while (count > 0 && !string.IsNullOrWhiteSpace(nextPageToken)); + + return toReturn; + } + + public async Task> GetVideoDurationsAsync(IEnumerable videoIds) + { + var videoIdsList = videoIds as List ?? videoIds.ToList(); + + var toReturn = new Dictionary(); + + if (!videoIdsList.Any()) + return toReturn; + var remaining = videoIdsList.Count; + + do + { + var toGet = remaining > 50 ? 50 : remaining; + remaining -= toGet; + + var q = _yt.Videos.List("contentDetails"); + q.Id = string.Join(",", videoIdsList.Take(toGet)); + videoIdsList = videoIdsList.Skip(toGet).ToList(); + var items = (await q.ExecuteAsync()).Items; + foreach (var i in items) + toReturn.Add(i.Id, XmlConvert.ToTimeSpan(i.ContentDetails.Duration)); + } while (remaining > 0); + + return toReturn; + } + + public async Task Translate(string sourceText, string sourceLanguage, string targetLanguage) + { + string text; + + if (!Languages.ContainsKey(sourceLanguage) || !Languages.ContainsKey(targetLanguage)) + throw new ArgumentException(nameof(sourceLanguage) + "/" + nameof(targetLanguage)); + + + var url = new Uri(string.Format( + "https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", + ConvertToLanguageCode(sourceLanguage), + ConvertToLanguageCode(targetLanguage), + WebUtility.UrlEncode(sourceText))); + using (var http = _httpFactory.CreateClient()) + { + http.DefaultRequestHeaders.Add("user-agent", + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); + text = await http.GetStringAsync(url); + } + + return string.Concat(JArray.Parse(text)[0].Select(x => x[0])); + } + + private string ConvertToLanguageCode(string language) + { + Languages.TryGetValue(language, out var mode); + return mode; + } +} + diff --git a/src/EllieBot/Services/Impl/GoogleApiService_SupportedLanguages.cs b/src/EllieBot/Services/Impl/GoogleApiService_SupportedLanguages.cs new file mode 100644 index 0000000..b4aa70a --- /dev/null +++ b/src/EllieBot/Services/Impl/GoogleApiService_SupportedLanguages.cs @@ -0,0 +1,160 @@ +namespace EllieBot.Services; + +public sealed partial class GoogleApiService +{ + private const string SUPPORTED = """ + afrikaans af + albanian sq + amharic am + arabic ar + armenian hy + assamese as + aymara ay + azerbaijani az + bambara bm + basque eu + belarusian be + bengali bn + bhojpuri bho + bosnian bs + bulgarian bg + catalan ca + cebuano ceb + chinese zh-CN + chinese-trad zh-TW + corsican co + croatian hr + czech cs + danish da + dhivehi dv + dogri doi + dutch nl + english en + esperanto eo + estonian et + ewe ee + filipino fil + finnish fi + french fr + frisian fy + galician gl + georgian ka + german de + greek el + guarani gn + gujarati gu + haitian ht + hausa ha + hawaiian haw + hebrew he + hindi hi + hmong hmn + hungarian hu + icelandic is + igbo ig + ilocano ilo + indonesian id + irish ga + italian it + japanese ja + javanese jv + kannada kn + kazakh kk + khmer km + kinyarwanda rw + konkani gom + korean ko + krio kri + kurdish ku + kurdish-sor ckb + kyrgyz ky + lao lo + latin la + latvian lv + lingala ln + lithuanian lt + luganda lg + luxembourgish lb + macedonian mk + maithili mai + malagasy mg + malay ms + malayalam ml + maltese mt + maori mi + marathi mr + meiteilon mni-Mtei + mizo lus + mongolian mn + myanmar my + nepali ne + norwegian no + nyanja ny + odia or + oromo om + pashto ps + persian fa + polish pl + portuguese pt + punjabi pa + quechua qu + romanian ro + russian ru + samoan sm + sanskrit sa + scots gd + sepedi nso + serbian sr + sesotho st + shona sn + sindhi sd + sinhala si + slovak sk + slovenian sl + somali so + spanish es + sundanese su + swahili sw + swedish sv + tagalog tl + tajik tg + tamil ta + tatar tt + telugu te + thai th + tigrinya ti + tsonga ts + turkish tr + turkmen tk + twi ak + ukrainian uk + urdu ur + uyghur ug + uzbek uz + vietnamese vi + welsh cy + xhosa xh + yiddish yi + yoruba yo + zulu zu + """; + + + public IReadOnlyDictionary Languages { get; } + + private GoogleApiService() + { + var langs = SUPPORTED.Split("\n") + .Select(x => x.Split(' ')) + .ToDictionary(x => x[0].Trim(), x => x[1].Trim()); + + foreach (var (_, v) in langs.ToArray()) + { + langs.Add(v, v); + } + + Languages = langs; + + } + +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/ImageCache.cs b/src/EllieBot/Services/Impl/ImageCache.cs new file mode 100644 index 0000000..12ec051 --- /dev/null +++ b/src/EllieBot/Services/Impl/ImageCache.cs @@ -0,0 +1,83 @@ +namespace EllieBot.Services; + +public sealed class ImageCache : IImageCache, IEService +{ + private readonly IBotCache _cache; + private readonly ImagesConfig _ic; + private readonly Random _rng; + private readonly IHttpClientFactory _httpFactory; + + public ImageCache( + IBotCache cache, + ImagesConfig ic, + IHttpClientFactory httpFactory) + { + _cache = cache; + _ic = ic; + _httpFactory = httpFactory; + _rng = new EllieRandom(); + } + + private static TypedKey GetImageKey(Uri url) + => new($"image:{url}"); + + public async Task GetImageDataAsync(Uri url) + => await _cache.GetOrAddAsync( + GetImageKey(url), + async () => + { + if (url.IsFile) + { + return await File.ReadAllBytesAsync(url.LocalPath); + } + + using var http = _httpFactory.CreateClient(); + var bytes = await http.GetByteArrayAsync(url); + return bytes; + }, + expiry: TimeSpan.FromHours(48)); + + private async Task GetRandomImageDataAsync(Uri[] urls) + { + if (urls.Length == 0) + return null; + + var url = urls[_rng.Next(0, urls.Length)]; + + var data = await GetImageDataAsync(url); + return data; + } + + public Task GetHeadsImageAsync() + => GetRandomImageDataAsync(_ic.Data.Coins.Heads); + + public Task GetTailsImageAsync() + => GetRandomImageDataAsync(_ic.Data.Coins.Tails); + + public Task GetCurrencyImageAsync() + => GetRandomImageDataAsync(_ic.Data.Currency); + + public Task GetXpBackgroundImageAsync() + => GetImageDataAsync(_ic.Data.Xp.Bg); + + public Task GetRategirlBgAsync() + => GetImageDataAsync(_ic.Data.Rategirl.Matrix); + + public Task GetRategirlDotAsync() + => GetImageDataAsync(_ic.Data.Rategirl.Dot); + + public Task GetDiceAsync(int num) + => GetImageDataAsync(_ic.Data.Dice[num]); + + public Task GetSlotEmojiAsync(int number) + => GetImageDataAsync(_ic.Data.Slots.Emojis[number]); + + public Task GetSlotBgAsync() + => GetImageDataAsync(_ic.Data.Slots.Bg); + + public Task GetRipBgAsync() + => GetImageDataAsync(_ic.Data.Rip.Bg); + + public Task GetRipOverlayAsync() + => GetImageDataAsync(_ic.Data.Rip.Overlay); +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/LocalDataCache.cs b/src/EllieBot/Services/Impl/LocalDataCache.cs new file mode 100644 index 0000000..111fd7a --- /dev/null +++ b/src/EllieBot/Services/Impl/LocalDataCache.cs @@ -0,0 +1,108 @@ +using EllieBot.Common.Pokemon; +using EllieBot.Modules.Games.Common.Trivia; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class LocalDataCache : ILocalDataCache, IEService +{ + private const string POKEMON_ABILITIES_FILE = "data/pokemon/pokemon_abilities.json"; + private const string POKEMON_LIST_FILE = "data/pokemon/pokemon_list.json"; + private const string POKEMON_MAP_PATH = "data/pokemon/name-id_map.json"; + private const string QUESTIONS_FILE = "data/trivia_questions.json"; + + private readonly IBotCache _cache; + + private readonly JsonSerializerOptions _opts = new JsonSerializerOptions() + { + AllowTrailingCommas = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + PropertyNameCaseInsensitive = true + }; + + public LocalDataCache(IBotCache cache) + => _cache = cache; + + private async Task GetOrCreateCachedDataAsync( + TypedKey key, + string fileName) + => await _cache.GetOrAddAsync(key, + async () => + { + if (!File.Exists(fileName)) + { + Log.Warning($"{fileName} is missing. Relevant data can't be loaded"); + return default; + } + + try + { + await using var stream = File.OpenRead(fileName); + return await JsonSerializer.DeserializeAsync(stream, _opts); + } + catch (Exception ex) + { + Log.Error(ex, + "Error reading {FileName} file: {ErrorMessage}", + fileName, + ex.Message); + + return default; + } + }); + + + private static TypedKey> _pokemonListKey + = new("pokemon:list"); + + public async Task?> GetPokemonsAsync() + => await GetOrCreateCachedDataAsync(_pokemonListKey, POKEMON_LIST_FILE); + + + private static TypedKey> _pokemonAbilitiesKey + = new("pokemon:abilities"); + + public async Task?> GetPokemonAbilitiesAsync() + => await GetOrCreateCachedDataAsync(_pokemonAbilitiesKey, POKEMON_ABILITIES_FILE); + + + private static TypedKey> _pokeMapKey + = new("pokemon:ab_map2"); // 2 because ab_map was storing arrays + + public async Task?> GetPokemonMapAsync() + => await _cache.GetOrAddAsync(_pokeMapKey, + async () => + { + var fileName = POKEMON_MAP_PATH; + if (!File.Exists(fileName)) + { + Log.Warning($"{fileName} is missing. Relevant data can't be loaded"); + return default; + } + + try + { + await using var stream = File.OpenRead(fileName); + var arr = await JsonSerializer.DeserializeAsync(stream, _opts); + + return (IReadOnlyDictionary?)arr?.ToDictionary(x => x.Id, x => x.Name); + } + catch (Exception ex) + { + Log.Error(ex, + "Error reading {FileName} file: {ErrorMessage}", + fileName, + ex.Message); + + return default; + } + }); + + + private static TypedKey _triviaKey + = new("trivia:questions"); + + public async Task GetTriviaQuestionsAsync() + => await GetOrCreateCachedDataAsync(_triviaKey, QUESTIONS_FILE); +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/Localization.cs b/src/EllieBot/Services/Impl/Localization.cs new file mode 100644 index 0000000..3c2cb5b --- /dev/null +++ b/src/EllieBot/Services/Impl/Localization.cs @@ -0,0 +1,121 @@ +#nullable disable +using EllieBot.Db; +using Newtonsoft.Json; +using System.Globalization; + +namespace EllieBot.Services; + +public class Localization : ILocalization +{ + private static readonly Dictionary _commandData = + JsonConvert.DeserializeObject>( + File.ReadAllText("./data/strings/commands/commands.en-US.json")); + + private readonly ConcurrentDictionary _guildCultureInfos; + + public IDictionary GuildCultureInfos + => _guildCultureInfos; + + public CultureInfo DefaultCultureInfo + => _bss.Data.DefaultLocale; + + private readonly BotConfigService _bss; + private readonly DbService _db; + + public Localization(BotConfigService bss, Bot bot, DbService db) + { + _bss = bss; + _db = db; + + var cultureInfoNames = bot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale); + + _guildCultureInfos = new(cultureInfoNames + .ToDictionary(x => x.Key, + x => + { + CultureInfo cultureInfo = null; + try + { + if (x.Value is null) + return null; + cultureInfo = new(x.Value); + } + catch { } + + return cultureInfo; + }) + .Where(x => x.Value is not null)); + } + + public void SetGuildCulture(IGuild guild, CultureInfo ci) + => SetGuildCulture(guild.Id, ci); + + public void SetGuildCulture(ulong guildId, CultureInfo ci) + { + if (ci.Name == _bss.Data.DefaultLocale.Name) + { + RemoveGuildCulture(guildId); + return; + } + + using (var uow = _db.GetDbContext()) + { + var gc = uow.GuildConfigsForId(guildId, set => set); + gc.Locale = ci.Name; + uow.SaveChanges(); + } + + _guildCultureInfos.AddOrUpdate(guildId, ci, (_, _) => ci); + } + + public void RemoveGuildCulture(IGuild guild) + => RemoveGuildCulture(guild.Id); + + public void RemoveGuildCulture(ulong guildId) + { + if (_guildCultureInfos.TryRemove(guildId, out _)) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + gc.Locale = null; + uow.SaveChanges(); + } + } + + public void SetDefaultCulture(CultureInfo ci) + => _bss.ModifyConfig(bs => + { + bs.DefaultLocale = ci; + }); + + public void ResetDefaultCulture() + => SetDefaultCulture(CultureInfo.CurrentCulture); + + public CultureInfo GetCultureInfo(IGuild guild) + => GetCultureInfo(guild?.Id); + + public CultureInfo GetCultureInfo(ulong? guildId) + { + if (guildId is null || !GuildCultureInfos.TryGetValue(guildId.Value, out var info) || info is null) + return _bss.Data.DefaultLocale; + + return info; + } + + public static CommandData LoadCommand(string key) + { + _commandData.TryGetValue(key, out var toReturn); + + if (toReturn is null) + { + return new() + { + Cmd = key, + Desc = key, + Usage = [key] + }; + } + + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/PubSub/JsonSeria.cs b/src/EllieBot/Services/Impl/PubSub/JsonSeria.cs new file mode 100644 index 0000000..413b8f8 --- /dev/null +++ b/src/EllieBot/Services/Impl/PubSub/JsonSeria.cs @@ -0,0 +1,27 @@ +using EllieBot.Common.JsonConverters; +using System.Text.Json; + +namespace EllieBot.Common; + +public class JsonSeria : ISeria +{ + private readonly JsonSerializerOptions _serializerOptions = new() + { + Converters = + { + new Rgba32Converter(), + new CultureInfoConverter() + } + }; + + public byte[] Serialize(T data) + => JsonSerializer.SerializeToUtf8Bytes(data, _serializerOptions); + + public T? Deserialize(byte[]? data) + { + if (data is null) + return default; + + return JsonSerializer.Deserialize(data, _serializerOptions); + } +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/PubSub/RedisPubSub.cs b/src/EllieBot/Services/Impl/PubSub/RedisPubSub.cs new file mode 100644 index 0000000..fd4a36c --- /dev/null +++ b/src/EllieBot/Services/Impl/PubSub/RedisPubSub.cs @@ -0,0 +1,57 @@ +using StackExchange.Redis; + +namespace EllieBot.Common; + +public sealed class RedisPubSub : IPubSub +{ + private readonly IBotCredentials _creds; + private readonly ConnectionMultiplexer _multi; + private readonly ISeria _serializer; + + public RedisPubSub(ConnectionMultiplexer multi, ISeria serializer, IBotCredentials creds) + { + _multi = multi; + _serializer = serializer; + _creds = creds; + } + + public Task Pub(in TypedKey key, TData data) + where TData : notnull + { + var serialized = _serializer.Serialize(data); + return _multi.GetSubscriber() + .PublishAsync(new RedisChannel($"{_creds.RedisKey()}:{key.Key}", RedisChannel.PatternMode.Literal), + serialized, + CommandFlags.FireAndForget); + } + + public Task Sub(in TypedKey key, Func action) + where TData : notnull + { + var eventName = key.Key; + + async void OnSubscribeHandler(RedisChannel _, RedisValue data) + { + try + { + var dataObj = _serializer.Deserialize(data); + if (dataObj is not null) + await action(dataObj); + else + { + Log.Warning("Publishing event {EventName} with a null value. This is not allowed", + eventName); + } + } + catch (Exception ex) + { + Log.Error("Error handling the event {EventName}: {ErrorMessage}", eventName, ex.Message); + } + } + + return _multi.GetSubscriber() + .SubscribeAsync( + new RedisChannel($"{_creds.RedisKey()}:{eventName}", RedisChannel.PatternMode.Literal), + OnSubscribeHandler); + } +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/PubSub/YamlSeria.cs b/src/EllieBot/Services/Impl/PubSub/YamlSeria.cs new file mode 100644 index 0000000..bedd0fa --- /dev/null +++ b/src/EllieBot/Services/Impl/PubSub/YamlSeria.cs @@ -0,0 +1,39 @@ +using EllieBot.Common.Configs; +using EllieBot.Common.Yml; +using System.Text.RegularExpressions; +using YamlDotNet.Serialization; + +namespace EllieBot.Common; + +public class YamlSeria : IConfigSeria +{ + private static readonly Regex _codePointRegex = + new(@"(\\U(?[a-zA-Z0-9]{8})|\\u(?[a-zA-Z0-9]{4})|\\x(?[a-zA-Z0-9]{2}))", + RegexOptions.Compiled); + + private readonly IDeserializer _deserializer; + private readonly ISerializer _serializer; + + public YamlSeria() + { + _serializer = Yaml.Serializer; + _deserializer = Yaml.Deserializer; + } + + public string Serialize(T obj) + where T : notnull + { + var escapedOutput = _serializer.Serialize(obj); + var output = _codePointRegex.Replace(escapedOutput, + me => + { + var str = me.Groups["code"].Value; + var newString = str.UnescapeUnicodeCodePoint(); + return newString; + }); + return output; + } + + public T Deserialize(string data) + => _deserializer.Deserialize(data); +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/RedisBotCache.cs b/src/EllieBot/Services/Impl/RedisBotCache.cs new file mode 100644 index 0000000..fffc727 --- /dev/null +++ b/src/EllieBot/Services/Impl/RedisBotCache.cs @@ -0,0 +1,119 @@ +using OneOf; +using OneOf.Types; +using StackExchange.Redis; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Common; + +public sealed class RedisBotCache : IBotCache +{ + private static readonly Type[] _supportedTypes = + [ + typeof(bool), typeof(int), typeof(uint), typeof(long), + typeof(ulong), typeof(float), typeof(double), + typeof(string), typeof(byte[]), typeof(ReadOnlyMemory), typeof(Memory), + typeof(RedisValue) + ]; + + private static readonly JsonSerializerOptions _opts = new() + { + PropertyNameCaseInsensitive = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + AllowTrailingCommas = true, + IgnoreReadOnlyProperties = false, + }; + private readonly ConnectionMultiplexer _conn; + + public RedisBotCache(ConnectionMultiplexer conn) + { + _conn = conn; + } + + public async ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) + { + // if a null value is passed, remove the key + if (value is null) + { + await RemoveAsync(key); + return false; + } + + var db = _conn.GetDatabase(); + RedisValue val = IsSupportedType(typeof(T)) + ? RedisValue.Unbox(value) + : JsonSerializer.Serialize(value, _opts); + + var success = await db.StringSetAsync(key.Key, + val, + expiry: expiry, + when: overwrite ? When.Always : When.NotExists); + + return success; + } + + public bool IsSupportedType(Type type) + { + if (type.IsGenericType) + { + var typeDef = type.GetGenericTypeDefinition(); + if (typeDef == typeof(Nullable<>)) + return IsSupportedType(type.GenericTypeArguments[0]); + } + + foreach (var t in _supportedTypes) + { + if (type == t) + return true; + } + + return false; + } + + public async ValueTask> GetAsync(TypedKey key) + { + var db = _conn.GetDatabase(); + var val = await db.StringGetAsync(key.Key); + if (val == default) + return new None(); + + if (IsSupportedType(typeof(T))) + return (T)((IConvertible)val).ToType(typeof(T), null); + + return JsonSerializer.Deserialize(val.ToString(), _opts)!; + } + + public async ValueTask RemoveAsync(TypedKey key) + { + var db = _conn.GetDatabase(); + + return await db.KeyDeleteAsync(key.Key); + } + + public async ValueTask GetOrAddAsync(TypedKey key, Func> createFactory, TimeSpan? expiry = null) + { + var result = await GetAsync(key); + + return await result.Match>( + v => Task.FromResult(v), + async _ => + { + var factoryValue = await createFactory(); + + if (factoryValue is null) + return default; + + await AddAsync(key, factoryValue, expiry); + + // get again to make sure it's the cached value + // and not the late factory value, in case there's a race condition + + var newResult = await GetAsync(key); + + // it's fine to do this, it should blow up if something went wrong. + return newResult.Match( + v => v, + _ => default); + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/RedisBotStringsProvider.cs b/src/EllieBot/Services/Impl/RedisBotStringsProvider.cs new file mode 100644 index 0000000..c0bef49 --- /dev/null +++ b/src/EllieBot/Services/Impl/RedisBotStringsProvider.cs @@ -0,0 +1,91 @@ +#nullable disable +using StackExchange.Redis; +using System.Text.Json; +using System.Web; + +namespace EllieBot.Services; + +/// +/// Uses to load strings into redis hash (only on Shard 0) +/// and retrieves them from redis via +/// +public class RedisBotStringsProvider : IBotStringsProvider +{ + private const string COMMANDS_KEY = "commands_v5"; + + private readonly ConnectionMultiplexer _redis; + private readonly IStringsSource _source; + private readonly IBotCredentials _creds; + + public RedisBotStringsProvider( + ConnectionMultiplexer redis, + DiscordSocketClient discordClient, + IStringsSource source, + IBotCredentials creds) + { + _redis = redis; + _source = source; + _creds = creds; + + if (discordClient.ShardId == 0) + Reload(); + } + + public string GetText(string localeName, string key) + { + var value = _redis.GetDatabase().HashGet($"{_creds.RedisKey()}:responses:{localeName}", key); + return value; + } + + public CommandStrings GetCommandStrings(string localeName, string commandName) + { + string examplesStr = _redis.GetDatabase() + .HashGet($"{_creds.RedisKey()}:{COMMANDS_KEY}:{localeName}", + $"{commandName}::examples"); + if (examplesStr == default) + return null; + + var descStr = _redis.GetDatabase() + .HashGet($"{_creds.RedisKey()}:{COMMANDS_KEY}:{localeName}", $"{commandName}::desc"); + if (descStr == default) + return null; + + var ex = examplesStr.Split('&').Map(HttpUtility.UrlDecode); + + var paramsStr = _redis.GetDatabase() + .HashGet($"{_creds.RedisKey()}:{COMMANDS_KEY}:{localeName}", $"{commandName}::params"); + if (paramsStr == default) + return null; + + return new() + { + Examples = ex, + Params = JsonSerializer.Deserialize[]>(paramsStr), + Desc = descStr + }; + } + + public void Reload() + { + var redisDb = _redis.GetDatabase(); + foreach (var (localeName, localeStrings) in _source.GetResponseStrings()) + { + var hashFields = localeStrings.Select(x => new HashEntry(x.Key, x.Value)).ToArray(); + + redisDb.HashSet($"{_creds.RedisKey()}:responses:{localeName}", hashFields); + } + + foreach (var (localeName, localeStrings) in _source.GetCommandStrings()) + { + var hashFields = localeStrings + .Select(x => new HashEntry($"{x.Key}::examples", + string.Join('&', x.Value.Examples.Map(HttpUtility.UrlEncode)))) + .Concat(localeStrings.Select(x => new HashEntry($"{x.Key}::desc", x.Value.Desc))) + .Concat(localeStrings.Select(x + => new HashEntry($"{x.Key}::params", JsonSerializer.Serialize(x.Value.Params)))) + .ToArray(); + + redisDb.HashSet($"{_creds.RedisKey()}:{COMMANDS_KEY}:{localeName}", hashFields); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Services/Impl/RemoteGrpcCoordinator.cs b/src/EllieBot/Services/Impl/RemoteGrpcCoordinator.cs new file mode 100644 index 0000000..de56a39 --- /dev/null +++ b/src/EllieBot/Services/Impl/RemoteGrpcCoordinator.cs @@ -0,0 +1,132 @@ +#nullable disable +using Grpc.Core; +using Grpc.Net.Client; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Coordinator; + +namespace EllieBot.Services; + +public class RemoteGrpcCoordinator : ICoordinator, IReadyExecutor +{ + private readonly Coordinator.Coordinator.CoordinatorClient _coordClient; + private readonly DiscordSocketClient _client; + + public RemoteGrpcCoordinator(IBotCredentials creds, DiscordSocketClient client) + { + var coordUrl = string.IsNullOrWhiteSpace(creds.CoordinatorUrl) ? "http://localhost:3442" : creds.CoordinatorUrl; + + var channel = GrpcChannel.ForAddress(coordUrl); + _coordClient = new(channel); + _client = client; + } + + public bool RestartBot() + { + _coordClient.RestartAllShards(new()); + + return true; + } + + public void Die(bool graceful) + => _coordClient.Die(new() + { + Graceful = graceful + }); + + public bool RestartShard(int shardId) + { + _coordClient.RestartShard(new() + { + ShardId = shardId + }); + + return true; + } + + public IList GetAllShardStatuses() + { + var res = _coordClient.GetAllStatuses(new()); + + return res.Statuses.ToArray() + .Map(s => new ShardStatus + { + ConnectionState = FromCoordConnState(s.State), + GuildCount = s.GuildCount, + ShardId = s.ShardId, + LastUpdate = s.LastUpdate.ToDateTime() + }); + } + + public int GetGuildCount() + { + var res = _coordClient.GetAllStatuses(new()); + + return res.Statuses.Sum(x => x.GuildCount); + } + + public async Task Reload() + => await _coordClient.ReloadAsync(new()); + + public Task OnReadyAsync() + { + Task.Run(async () => + { + var gracefulImminent = false; + while (true) + { + try + { + var reply = await _coordClient.HeartbeatAsync(new() + { + State = ToCoordConnState(_client.ConnectionState), + GuildCount = + _client.ConnectionState == ConnectionState.Connected ? _client.Guilds.Count : 0, + ShardId = _client.ShardId + }, + deadline: DateTime.UtcNow + TimeSpan.FromSeconds(10)); + gracefulImminent = reply.GracefulImminent; + } + catch (RpcException ex) + { + if (!gracefulImminent) + { + Log.Warning(ex, + "Hearbeat failed and graceful shutdown was not expected: {Message}", + ex.Message); + break; + } + + Log.Information("Coordinator is restarting gracefully. Waiting..."); + await Task.Delay(30_000); + } + catch (Exception ex) + { + Log.Error(ex, "Unexpected heartbeat exception: {Message}", ex.Message); + break; + } + + await Task.Delay(7500); + } + + Environment.Exit(5); + }); + + return Task.CompletedTask; + } + + private ConnState ToCoordConnState(ConnectionState state) + => state switch + { + ConnectionState.Connecting => ConnState.Connecting, + ConnectionState.Connected => ConnState.Connected, + _ => ConnState.Disconnected + }; + + private ConnectionState FromCoordConnState(ConnState state) + => state switch + { + ConnState.Connecting => ConnectionState.Connecting, + ConnState.Connected => ConnectionState.Connected, + _ => ConnectionState.Disconnected + }; +} \ No newline at end of file From 044e4c87d9364980c92543618ac03bf8c55d2856 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:48:54 +1200 Subject: [PATCH 45/62] Added Core repo files --- .dockerignore | 13 ++++++++++++ Dockerfile | 46 +++++++++++++++++++++++++++++++++++++++++++ EllieBot.sln | 17 +++++++++------- NuGet.Config | 6 ++++++ README.md | 2 ++ docker-entrypoint.sh | 28 ++++++++++++++++++++++++++ migrate.ps1 | 9 +++++++++ remove-migrations.ps1 | 3 +++ 8 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 .dockerignore create mode 100644 NuGet.Config create mode 100644 docker-entrypoint.sh create mode 100644 migrate.ps1 create mode 100644 remove-migrations.ps1 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c84eea1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +# Ignore all files +* + +# Don't ignore nugetconfig +!./NuGet.Config + +# Don't ignore src projects +!src/** +!docker-entrypoint.sh + +# ignore bin and obj folders in projects +src/**/bin/* +src/**/obj/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index e69de29..dcdedcf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -0,0 +1,46 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /source + +COPY src/Ellie.Marmalade/*.csproj src/Ellie.Marmalade/ +COPY src/EllieBot/*.csproj src/EllieBot/ +COPY src/EllieBot.Coordinator/*.csproj src/EllieBot.Coordinator/ +COPY src/EllieBot.Generators/*.csproj src/EllieBot.Generators/ +COPY src/EllieBot.Voice/*.csproj src/EllieBot.Voice/ +COPY NuGet.Config ./ +RUN dotnet restore src/EllieBot/ + +COPY . . +WORKDIR /source/src/EllieBot +RUN set -xe; \ + dotnet --version; \ + dotnet publish -c Release -o /app --no-restore; \ + mv /app/data /app/data_init; \ + rm -Rf libopus* libsodium* opus.* runtimes/win* runtimes/osx* runtimes/linux-arm* runtimes/linux-mips*; \ + find /app -type f -exec chmod -x {} \; ;\ + chmod +x /app/EllieBot + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime:6.0 +WORKDIR /app + +RUN set -xe; \ + useradd -m ellie; \ + apt-get update; \ + apt-get install -y --no-install-recommends libopus0 libsodium23 libsqlite3-0 curl ffmpeg python3 sudo; \ + update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1; \ + echo 'Defaults>ellie env_keep+="ASPNETCORE_* DOTNET_* EllieBot_* shard_id total_shards TZ"' > /etc/sudoers.d/ellie; \ + curl -Lo /usr/local/bin/yt-dlp https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp; \ + chmod a+rx /usr/local/bin/yt-dlp; \ + apt-get autoremove -y; \ + apt-get autoclean -y + +COPY --from=build /app ./ +COPY docker-entrypoint.sh /usr/local/sbin + +ENV shard_id=0 +ENV total_shards=1 +ENV EllieBot__creds=/app/data/creds.yml + +VOLUME [" /app/data "] +ENTRYPOINT [ "/usr/local/sbin/docker-entrypoint.sh" ] +CMD dotnet EllieBot.dll "$shard_id" "$total_shards" diff --git a/EllieBot.sln b/EllieBot.sln index 5a74f26..be95d55 100644 --- a/EllieBot.sln +++ b/EllieBot.sln @@ -10,11 +10,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution CHANGELOG.md = CHANGELOG.md Dockerfile = Dockerfile LICENSE = LICENSE + migrate.ps1 = migrate.ps1 + NuGet.Config = NuGet.Config README.md = README.md + remove-migrations.ps1 = remove-migrations.ps1 TODO.md = TODO.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot", "src\EllieBot\EllieBot.csproj", "{BCB21472-84D2-4B63-B5DD-31E6A3EC9791}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot", "src\EllieBot\EllieBot.csproj", "{4D9001F7-B3E8-48FE-97AA-CFD36DA65A64}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Tests", "src\EllieBot.Tests\EllieBot.Tests.csproj", "{179DF3B3-AD32-4335-8231-9818338DF3A2}" EndProject @@ -26,7 +29,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.VotesApi", "src\El EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ellie.Marmalade", "src\Ellie.Marmalade\Ellie.Marmalade.csproj", "{76AC715D-12FF-4CBE-9585-A861139A2D0C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EllieBot.Voice", "src\EllieBot.Voice\EllieBot.Voice.csproj", "{1D93CE3C-80B4-49C7-A9A2-99988920AAEC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EllieBot.Voice", "src\EllieBot.Voice\EllieBot.Voice.csproj", "{1D93CE3C-80B4-49C7-A9A2-99988920AAEC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,10 +37,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BCB21472-84D2-4B63-B5DD-31E6A3EC9791}.Release|Any CPU.Build.0 = Release|Any CPU + {4D9001F7-B3E8-48FE-97AA-CFD36DA65A64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D9001F7-B3E8-48FE-97AA-CFD36DA65A64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D9001F7-B3E8-48FE-97AA-CFD36DA65A64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D9001F7-B3E8-48FE-97AA-CFD36DA65A64}.Release|Any CPU.Build.0 = Release|Any CPU {179DF3B3-AD32-4335-8231-9818338DF3A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {179DF3B3-AD32-4335-8231-9818338DF3A2}.Debug|Any CPU.Build.0 = Debug|Any CPU {179DF3B3-AD32-4335-8231-9818338DF3A2}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -67,7 +70,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {BCB21472-84D2-4B63-B5DD-31E6A3EC9791} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} + {4D9001F7-B3E8-48FE-97AA-CFD36DA65A64} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {179DF3B3-AD32-4335-8231-9818338DF3A2} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {A631DDF0-3AD1-4CB9-8458-314B1320868A} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} {CB1A5307-DD85-4795-8A8A-A25D36DADC51} = {B28FB883-9688-41EB-BF5A-945F4A4EB628} diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..7e64704 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + diff --git a/README.md b/README.md index 0f9c1bd..452254f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Ellie +[![Please don't upload to GitHub](https://nogithub.codeberg.page/badge.svg)](https://nogithub.codeberg.page) + ## Small disclaimer All the code in this repo may not be production ready yet and if you want to try and run a version of this by yourself you are on your own. diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..3f3fbd3 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/sh +set -e; + +data_init=/app/data_init +data=/app/data + +# populate /app/data if empty +for i in $(ls $data_init) +do + if [ ! -e "$data/$i" ]; then + [ -f "$data_init/$i" ] && cp "$data_init/$i" "$data/$i" + [ -d "$data_init/$i" ] && cp -r "$data_init/$i" "$data/$i" + fi +done + +# creds.yml migration +if [ -f /app/creds.yml ]; then + echo "Default location for creds.yml is now /app/data/creds.yml." + echo "Please move your creds.yml and update your docker-compose.yml accordingly." + + export Ellie_creds=/app/creds.yml +fi + +# ensure ellie can write on /app/data +chown -R ellie:ellie "$data" + +# drop to regular user and launch command +exec sudo -u ellie "$@" \ No newline at end of file diff --git a/migrate.ps1 b/migrate.ps1 new file mode 100644 index 0000000..a5ff6c4 --- /dev/null +++ b/migrate.ps1 @@ -0,0 +1,9 @@ +if ($args.Length -eq 0) { + Write-Host "Please provide a migration name." -ForegroundColor Red +} +else { + $migrationName = $args[0] + dotnet ef migrations add $migrationName -c SqliteContext -p src/EllieBot/EllieBot.csproj + dotnet ef migrations add $migrationName -c PostgreSqlContext -p src/EllieBot/EllieBot.csproj + dotnet ef migrations add $migrationName -c MysqlContext -p src/EllieBot/EllieBot.csproj +} \ No newline at end of file diff --git a/remove-migrations.ps1 b/remove-migrations.ps1 new file mode 100644 index 0000000..5445dbb --- /dev/null +++ b/remove-migrations.ps1 @@ -0,0 +1,3 @@ +dotnet ef migrations remove -c SqliteContext -f -p src/EllieBot/EllieBot.csproj +dotnet ef migrations remove -c PostgreSqlContext -f -p src/EllieBot/EllieBot.csproj +dotnet ef migrations remove -c MysqlContext -f -p src/EllieBot/EllieBot.csproj \ No newline at end of file From eebc1acbb329e1b54b14bb3f2a2118819f22c83e Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:50:02 +1200 Subject: [PATCH 46/62] Added Administration module --- .../Modules/Administration/Administration.cs | 499 +++++++ .../Administration/AdministrationService.cs | 206 +++ .../AutoAssignRoleCommands.cs | 60 + .../AutoAssignRoleService.cs | 159 ++ .../Administration/AutoPublishService.cs | 87 ++ .../DangerousCommands/CleanupCommands.cs | 31 + .../DangerousCommands/CleanupService.cs | 106 ++ .../DangerousCommands/DangerousCommands.cs | 164 +++ .../DangerousCommandsService.cs | 103 ++ .../DangerousCommands/_common/CleanupId.cs | 9 + .../_common/ICleanupService.cs | 6 + .../DangerousCommands/_common/KeepReport.cs | 7 + .../DangerousCommands/_common/KeepResult.cs | 6 + .../GameVoiceChannelCommands.cs | 36 + .../GameVoiceChannelService.cs | 127 ++ .../Administration/GreetBye/GreetCommands.cs | 229 +++ .../Administration/GreetBye/GreetGrouper.cs | 71 + .../Administration/GreetBye/GreetService.cs | 662 +++++++++ .../Administration/GreetBye/GreetSettings.cs | 45 + .../Administration/ImageOnlyChannelService.cs | 235 +++ .../Administration/LocalizationCommands.cs | 264 ++++ .../Administration/Mute/MuteCommands.cs | 231 +++ .../Administration/Mute/MuteService.cs | 504 +++++++ .../DiscordPermOverrideCommands.cs | 83 ++ .../PlayingRotate/PlayingRotateCommands.cs | 62 + .../PlayingRotate/PlayingRotateService.cs | 109 ++ .../Administration/Prefix/PrefixCommands.cs | 57 + .../Protection/ProtectionCommands.cs | 292 ++++ .../Protection/ProtectionService.cs | 499 +++++++ .../Protection/ProtectionStats.cs | 52 + .../Protection/PunishQueueItem.cs | 13 + .../Protection/UserSpamStats.cs | 64 + .../Administration/Prune/PruneCommands.cs | 198 +++ .../Administration/Prune/PruneService.cs | 101 ++ .../Role/IReactionRoleService.cs | 52 + .../Role/ReactionRoleCommands.cs | 176 +++ .../Role/ReactionRolesService.cs | 408 ++++++ .../Administration/Role/RoleCommands.cs | 209 +++ .../Administration/Role/StickyRolesService.cs | 139 ++ .../Self/CheckForUpdatesService.cs | 169 +++ .../Administration/Self/SelfCommands.cs | 586 ++++++++ .../Administration/Self/SelfService.cs | 485 ++++++ .../SelfAssignedRolesCommands.cs | 239 +++ .../SelfAssignedRolesService.cs | 234 +++ .../ServerLog/DummyLogCommandService.cs | 25 + .../ServerLog/ServerLogCommandService.cs | 1297 +++++++++++++++++ .../ServerLog/ServerLogCommands.cs | 175 +++ .../Timezone/GuildTimezoneService.cs | 95 ++ .../Timezone/TimeZoneCommands.cs | 78 + .../UserPunish/UserPunishCommands.cs | 960 ++++++++++++ .../UserPunish/UserPunishService.cs | 597 ++++++++ .../Administration/VcRole/VcRoleCommands.cs | 77 + .../Administration/VcRole/VcRoleService.cs | 208 +++ .../_common/SetServerBannerResult.cs | 9 + .../_common/SetServerIconResult.cs | 8 + 55 files changed, 11603 insertions(+) create mode 100644 src/EllieBot/Modules/Administration/Administration.cs create mode 100644 src/EllieBot/Modules/Administration/AdministrationService.cs create mode 100644 src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleCommands.cs create mode 100644 src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleService.cs create mode 100644 src/EllieBot/Modules/Administration/AutoPublishService.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/CleanupCommands.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommands.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommandsService.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/_common/CleanupId.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/_common/ICleanupService.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepReport.cs create mode 100644 src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepResult.cs create mode 100644 src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelCommands.cs create mode 100644 src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelService.cs create mode 100644 src/EllieBot/Modules/Administration/GreetBye/GreetCommands.cs create mode 100644 src/EllieBot/Modules/Administration/GreetBye/GreetGrouper.cs create mode 100644 src/EllieBot/Modules/Administration/GreetBye/GreetService.cs create mode 100644 src/EllieBot/Modules/Administration/GreetBye/GreetSettings.cs create mode 100644 src/EllieBot/Modules/Administration/ImageOnlyChannelService.cs create mode 100644 src/EllieBot/Modules/Administration/LocalizationCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Mute/MuteCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Mute/MuteService.cs create mode 100644 src/EllieBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs create mode 100644 src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateCommands.cs create mode 100644 src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateService.cs create mode 100644 src/EllieBot/Modules/Administration/Prefix/PrefixCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Protection/ProtectionCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Protection/ProtectionService.cs create mode 100644 src/EllieBot/Modules/Administration/Protection/ProtectionStats.cs create mode 100644 src/EllieBot/Modules/Administration/Protection/PunishQueueItem.cs create mode 100644 src/EllieBot/Modules/Administration/Protection/UserSpamStats.cs create mode 100644 src/EllieBot/Modules/Administration/Prune/PruneCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Prune/PruneService.cs create mode 100644 src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs create mode 100644 src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs create mode 100644 src/EllieBot/Modules/Administration/Role/RoleCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Role/StickyRolesService.cs create mode 100644 src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs create mode 100644 src/EllieBot/Modules/Administration/Self/SelfCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Self/SelfService.cs create mode 100644 src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs create mode 100644 src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesService.cs create mode 100644 src/EllieBot/Modules/Administration/ServerLog/DummyLogCommandService.cs create mode 100644 src/EllieBot/Modules/Administration/ServerLog/ServerLogCommandService.cs create mode 100644 src/EllieBot/Modules/Administration/ServerLog/ServerLogCommands.cs create mode 100644 src/EllieBot/Modules/Administration/Timezone/GuildTimezoneService.cs create mode 100644 src/EllieBot/Modules/Administration/Timezone/TimeZoneCommands.cs create mode 100644 src/EllieBot/Modules/Administration/UserPunish/UserPunishCommands.cs create mode 100644 src/EllieBot/Modules/Administration/UserPunish/UserPunishService.cs create mode 100644 src/EllieBot/Modules/Administration/VcRole/VcRoleCommands.cs create mode 100644 src/EllieBot/Modules/Administration/VcRole/VcRoleService.cs create mode 100644 src/EllieBot/Modules/Administration/_common/SetServerBannerResult.cs create mode 100644 src/EllieBot/Modules/Administration/_common/SetServerIconResult.cs diff --git a/src/EllieBot/Modules/Administration/Administration.cs b/src/EllieBot/Modules/Administration/Administration.cs new file mode 100644 index 0000000..9e18e8b --- /dev/null +++ b/src/EllieBot/Modules/Administration/Administration.cs @@ -0,0 +1,499 @@ +#nullable disable +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Modules.Administration._common.results; +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration : EllieModule +{ + public enum Channel + { + Channel, + Ch, + Chnl, + Chan + } + + public enum List + { + List = 0, + Ls = 0 + } + + public enum Server + { + Server + } + + public enum State + { + Enable, + Disable, + Inherit + } + + private readonly SomethingOnlyChannelService _somethingOnly; + private readonly AutoPublishService _autoPubService; + + public Administration(SomethingOnlyChannelService somethingOnly, AutoPublishService autoPubService) + { + _somethingOnly = somethingOnly; + _autoPubService = autoPubService; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageGuild)] + public async Task ImageOnlyChannel(StoopidTime time = null) + { + var newValue = await _somethingOnly.ToggleImageOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id); + if (newValue) + await Response().Confirm(strs.imageonly_enable).SendAsync(); + else + await Response().Pending(strs.imageonly_disable).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageGuild)] + public async Task LinkOnlyChannel(StoopidTime time = null) + { + var newValue = await _somethingOnly.ToggleLinkOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id); + if (newValue) + await Response().Confirm(strs.linkonly_enable).SendAsync(); + else + await Response().Pending(strs.linkonly_disable).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageChannels)] + [BotPerm(ChannelPerm.ManageChannels)] + public async Task Slowmode(StoopidTime time = null) + { + var seconds = (int?)time?.Time.TotalSeconds ?? 0; + if (time is not null && (time.Time < TimeSpan.FromSeconds(0) || time.Time > TimeSpan.FromHours(6))) + return; + + await ((ITextChannel)ctx.Channel).ModifyAsync(tcp => + { + tcp.SlowModeInterval = seconds; + }); + + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageMessages)] + [Priority(2)] + public async Task Delmsgoncmd(List _) + { + var guild = (SocketGuild)ctx.Guild; + var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id); + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.server_delmsgoncmd)) + .WithDescription(enabled ? "✅" : "❌"); + + var str = string.Join("\n", + channels.Select(x => + { + var ch = guild.GetChannel(x.ChannelId)?.ToString() ?? x.ChannelId.ToString(); + var prefixSign = x.State ? "✅ " : "❌ "; + return prefixSign + ch; + })); + + if (string.IsNullOrWhiteSpace(str)) + str = "-"; + + embed.AddField(GetText(strs.channel_delmsgoncmd), str); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageMessages)] + [Priority(1)] + public async Task Delmsgoncmd(Server _ = Server.Server) + { + if (_service.ToggleDeleteMessageOnCommand(ctx.Guild.Id)) + { + _service.DeleteMessagesOnCommand.Add(ctx.Guild.Id); + await Response().Confirm(strs.delmsg_on).SendAsync(); + } + else + { + _service.DeleteMessagesOnCommand.TryRemove(ctx.Guild.Id); + await Response().Confirm(strs.delmsg_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageMessages)] + [Priority(0)] + public Task Delmsgoncmd(Channel _, State s, ITextChannel ch) + => Delmsgoncmd(_, s, ch.Id); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageMessages)] + [Priority(1)] + public async Task Delmsgoncmd(Channel _, State s, ulong? chId = null) + { + var actualChId = chId ?? ctx.Channel.Id; + await _service.SetDelMsgOnCmdState(ctx.Guild.Id, actualChId, s); + + if (s == State.Disable) + await Response().Confirm(strs.delmsg_channel_off).SendAsync(); + else if (s == State.Enable) + await Response().Confirm(strs.delmsg_channel_on).SendAsync(); + else + await Response().Confirm(strs.delmsg_channel_inherit).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.DeafenMembers)] + [BotPerm(GuildPerm.DeafenMembers)] + public async Task Deafen(params IGuildUser[] users) + { + await _service.DeafenUsers(true, users); + await Response().Confirm(strs.deafen).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.DeafenMembers)] + [BotPerm(GuildPerm.DeafenMembers)] + public async Task UnDeafen(params IGuildUser[] users) + { + await _service.DeafenUsers(false, users); + await Response().Confirm(strs.undeafen).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task DelVoiChanl([Leftover] IVoiceChannel voiceChannel) + { + await voiceChannel.DeleteAsync(); + await Response().Confirm(strs.delvoich(Format.Bold(voiceChannel.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task CreatVoiChanl([Leftover] string channelName) + { + var ch = await ctx.Guild.CreateVoiceChannelAsync(channelName); + await Response().Confirm(strs.createvoich(Format.Bold(ch.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task DelTxtChanl([Leftover] ITextChannel toDelete) + { + await toDelete.DeleteAsync(new RequestOptions() + { + AuditLogReason = $"Deleted by {ctx.User.Username}" + }); + await Response().Confirm(strs.deltextchan(Format.Bold(toDelete.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task CreaTxtChanl([Leftover] string channelName) + { + var txtCh = await ctx.Guild.CreateTextChannelAsync(channelName); + await Response().Confirm(strs.createtextchan(Format.Bold(txtCh.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task SetTopic([Leftover] string topic = null) + { + var channel = (ITextChannel)ctx.Channel; + topic ??= ""; + await channel.ModifyAsync(c => c.Topic = topic); + await Response().Confirm(strs.set_topic).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task SetChanlName([Leftover] string name) + { + var channel = (ITextChannel)ctx.Channel; + await channel.ModifyAsync(c => c.Name = name); + await Response().Confirm(strs.set_channel_name).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageChannels)] + [BotPerm(GuildPerm.ManageChannels)] + public async Task AgeRestrictToggle() + { + var channel = (ITextChannel)ctx.Channel; + var isEnabled = channel.IsNsfw; + + await channel.ModifyAsync(c => c.IsNsfw = !isEnabled); + + if (isEnabled) + await Response().Confirm(strs.nsfw_set_false).SendAsync(); + else + await Response().Confirm(strs.nsfw_set_true).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageMessages)] + [Priority(0)] + public Task Edit(ulong messageId, [Leftover] string text) + => Edit((ITextChannel)ctx.Channel, messageId, text); + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task Edit(ITextChannel channel, ulong messageId, [Leftover] string text) + { + var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel); + var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel); + if (!userPerms.Has(ChannelPermission.ManageMessages)) + { + await Response().Error(strs.insuf_perms_u).SendAsync(); + return; + } + + if (!botPerms.Has(ChannelPermission.ViewChannel)) + { + await Response().Error(strs.insuf_perms_i).SendAsync(); + return; + } + + await _service.EditMessage(ctx, channel, messageId, text); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageMessages)] + [BotPerm(ChannelPerm.ManageMessages)] + public Task Delete(ulong messageId, StoopidTime time = null) + => Delete((ITextChannel)ctx.Channel, messageId, time); + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Delete(ITextChannel channel, ulong messageId, StoopidTime time = null) + => await InternalMessageAction(channel, messageId, time, msg => msg.DeleteAsync()); + + private async Task InternalMessageAction( + ITextChannel channel, + ulong messageId, + StoopidTime time, + Func func) + { + var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel); + var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel); + if (!userPerms.Has(ChannelPermission.ManageMessages)) + { + await Response().Error(strs.insuf_perms_u).SendAsync(); + return; + } + + if (!botPerms.Has(ChannelPermission.ManageMessages)) + { + await Response().Error(strs.insuf_perms_i).SendAsync(); + return; + } + + + var msg = await channel.GetMessageAsync(messageId); + if (msg is null) + { + await Response().Error(strs.msg_not_found).SendAsync(); + return; + } + + if (time is null) + await msg.DeleteAsync(); + else if (time.Time <= TimeSpan.FromDays(7)) + { + _ = Task.Run(async () => + { + await Task.Delay(time.Time); + await msg.DeleteAsync(); + }); + } + else + { + await Response().Error(strs.time_too_long).SendAsync(); + return; + } + + await ctx.OkAsync(); + } + + [Cmd] + [BotPerm(ChannelPermission.CreatePublicThreads)] + [UserPerm(ChannelPermission.CreatePublicThreads)] + public async Task ThreadCreate([Leftover] string name) + { + if (ctx.Channel is not SocketTextChannel stc) + return; + + await stc.CreateThreadAsync(name, message: ctx.Message.ReferencedMessage); + await ctx.OkAsync(); + } + + [Cmd] + [BotPerm(ChannelPermission.ManageThreads)] + [UserPerm(ChannelPermission.ManageThreads)] + public async Task ThreadDelete([Leftover] string name) + { + if (ctx.Channel is not SocketTextChannel stc) + return; + + var t = stc.Threads.FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase)); + + if (t is null) + { + await Response().Error(strs.not_found).SendAsync(); + return; + } + + await t.DeleteAsync(); + await ctx.OkAsync(); + } + + [Cmd] + [UserPerm(ChannelPerm.ManageMessages)] + public async Task AutoPublish() + { + if (ctx.Channel.GetChannelType() != ChannelType.News) + { + await Response().Error(strs.req_announcement_channel).SendAsync(); + return; + } + + var newState = await _autoPubService.ToggleAutoPublish(ctx.Guild.Id, ctx.Channel.Id); + + if (newState) + { + await Response().Confirm(strs.autopublish_enable).SendAsync(); + } + else + { + await Response().Confirm(strs.autopublish_disable).SendAsync(); + } + } + + [Cmd] + [UserPerm(GuildPerm.ManageNicknames)] + [BotPerm(GuildPerm.ChangeNickname)] + [Priority(0)] + public async Task SetNick([Leftover] string newNick = null) + { + if (string.IsNullOrWhiteSpace(newNick)) + return; + var curUser = await ctx.Guild.GetCurrentUserAsync(); + await curUser.ModifyAsync(u => u.Nickname = newNick); + + await Response().Confirm(strs.bot_nick(Format.Bold(newNick) ?? "-")).SendAsync(); + } + + [Cmd] + [BotPerm(GuildPerm.ManageNicknames)] + [UserPerm(GuildPerm.ManageNicknames)] + [Priority(1)] + public async Task SetNick(IGuildUser gu, [Leftover] string newNick = null) + { + var sg = (SocketGuild)ctx.Guild; + if (sg.OwnerId == gu.Id + || gu.GetRoles().Max(r => r.Position) >= sg.CurrentUser.GetRoles().Max(r => r.Position)) + { + await Response().Error(strs.insuf_perms_i).SendAsync(); + return; + } + + await gu.ModifyAsync(u => u.Nickname = newNick); + + await Response() + .Confirm(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-")) + .SendAsync(); + } + + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPermission.ManageGuild)] + [BotPerm(GuildPermission.ManageGuild)] + public async Task SetServerBanner([Leftover] string img = null) + { + // Tier2 or higher is required to set a banner. + if (ctx.Guild.PremiumTier is PremiumTier.Tier1 or PremiumTier.None) return; + + var result = await _service.SetServerBannerAsync(ctx.Guild, img); + + switch (result) + { + case SetServerBannerResult.Success: + await Response().Confirm(strs.set_srvr_banner).SendAsync(); + break; + case SetServerBannerResult.InvalidFileType: + await Response().Error(strs.srvr_banner_invalid).SendAsync(); + break; + case SetServerBannerResult.Toolarge: + await Response().Error(strs.srvr_banner_too_large).SendAsync(); + break; + case SetServerBannerResult.InvalidURL: + await Response().Error(strs.srvr_banner_invalid_url).SendAsync(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPermission.ManageGuild)] + [BotPerm(GuildPermission.ManageGuild)] + public async Task SetServerIcon([Leftover] string img = null) + { + var result = await _service.SetServerIconAsync(ctx.Guild, img); + + switch (result) + { + case SetServerIconResult.Success: + await Response().Confirm(strs.set_srvr_icon).SendAsync(); + break; + case SetServerIconResult.InvalidFileType: + await Response().Error(strs.srvr_banner_invalid).SendAsync(); + break; + case SetServerIconResult.InvalidURL: + await Response().Error(strs.srvr_banner_invalid_url).SendAsync(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/AdministrationService.cs b/src/EllieBot/Modules/Administration/AdministrationService.cs new file mode 100644 index 0000000..de037bd --- /dev/null +++ b/src/EllieBot/Modules/Administration/AdministrationService.cs @@ -0,0 +1,206 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Administration._common.results; + +namespace EllieBot.Modules.Administration.Services; + +public class AdministrationService : IEService +{ + public ConcurrentHashSet DeleteMessagesOnCommand { get; } + public ConcurrentDictionary DeleteMessagesOnCommandChannels { get; } + + private readonly DbService _db; + private readonly IReplacementService _repSvc; + private readonly ILogCommandService _logService; + private readonly IHttpClientFactory _httpFactory; + + public AdministrationService( + IBot bot, + CommandHandler cmdHandler, + DbService db, + IReplacementService repSvc, + ILogCommandService logService, + IHttpClientFactory factory) + { + _db = db; + _repSvc = repSvc; + _logService = logService; + _httpFactory = factory; + + DeleteMessagesOnCommand = new(bot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId)); + + DeleteMessagesOnCommandChannels = new(bot.AllGuildConfigs.SelectMany(x => x.DelMsgOnCmdChannels) + .ToDictionary(x => x.ChannelId, x => x.State) + .ToConcurrent()); + + cmdHandler.CommandExecuted += DelMsgOnCmd_Handler; + } + + public (bool DelMsgOnCmd, IEnumerable channels) GetDelMsgOnCmdData(ulong guildId) + { + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.DelMsgOnCmdChannels)); + + return (conf.DeleteMessageOnCommand, conf.DelMsgOnCmdChannels); + } + + private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd) + { + if (msg.Channel is not ITextChannel channel) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + //wat ?! + if (DeleteMessagesOnCommandChannels.TryGetValue(channel.Id, out var state)) + { + if (state && cmd.Name != "prune" && cmd.Name != "pick") + { + _logService.AddDeleteIgnore(msg.Id); + try { await msg.DeleteAsync(); } + catch { } + } + //if state is false, that means do not do it + } + else if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick") + { + _logService.AddDeleteIgnore(msg.Id); + try { await msg.DeleteAsync(); } + catch { } + } + }); + return Task.CompletedTask; + } + + public bool ToggleDeleteMessageOnCommand(ulong guildId) + { + bool enabled; + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + enabled = conf.DeleteMessageOnCommand = !conf.DeleteMessageOnCommand; + + uow.SaveChanges(); + return enabled; + } + + public async Task SetDelMsgOnCmdState(ulong guildId, ulong chId, Administration.State newState) + { + await using (var uow = _db.GetDbContext()) + { + var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.DelMsgOnCmdChannels)); + + var old = conf.DelMsgOnCmdChannels.FirstOrDefault(x => x.ChannelId == chId); + if (newState == Administration.State.Inherit) + { + if (old is not null) + { + conf.DelMsgOnCmdChannels.Remove(old); + uow.Remove(old); + } + } + else + { + if (old is null) + { + old = new() + { + ChannelId = chId + }; + conf.DelMsgOnCmdChannels.Add(old); + } + + old.State = newState == Administration.State.Enable; + DeleteMessagesOnCommandChannels[chId] = newState == Administration.State.Enable; + } + + await uow.SaveChangesAsync(); + } + + if (newState == Administration.State.Disable) + { + } + else if (newState == Administration.State.Enable) + DeleteMessagesOnCommandChannels[chId] = true; + else + DeleteMessagesOnCommandChannels.TryRemove(chId, out _); + } + + public async Task DeafenUsers(bool value, params IGuildUser[] users) + { + if (!users.Any()) + return; + foreach (var u in users) + { + try + { + await u.ModifyAsync(usr => usr.Deaf = value); + } + catch + { + // ignored + } + } + } + + public async Task EditMessage( + ICommandContext context, + ITextChannel chanl, + ulong messageId, + string input) + { + var msg = await chanl.GetMessageAsync(messageId); + + if (msg is not IUserMessage umsg || msg.Author.Id != context.Client.CurrentUser.Id) + return; + + var repCtx = new ReplacementContext(context); + + var text = SmartText.CreateFrom(input); + text = await _repSvc.ReplaceAsync(text, repCtx); + + await umsg.EditAsync(text); + } + + public async Task SetServerBannerAsync(IGuild guild, string img) + { + if (!IsValidUri(img)) return SetServerBannerResult.InvalidURL; + + var uri = new Uri(img); + + using var http = _httpFactory.CreateClient(); + using var sr = await http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); + + if (!sr.IsImage()) return SetServerBannerResult.InvalidFileType; + + if (sr.GetContentLength() > 8.Megabytes()) + { + return SetServerBannerResult.Toolarge; + } + + await using var imageStream = await sr.Content.ReadAsStreamAsync(); + + await guild.ModifyAsync(x => x.Banner = new Image(imageStream)); + return SetServerBannerResult.Success; + } + + public async Task SetServerIconAsync(IGuild guild, string img) + { + if (!IsValidUri(img)) return SetServerIconResult.InvalidURL; + + var uri = new Uri(img); + + using var http = _httpFactory.CreateClient(); + using var sr = await http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); + + if (!sr.IsImage()) return SetServerIconResult.InvalidFileType; + + await using var imageStream = await sr.Content.ReadAsStreamAsync(); + + await guild.ModifyAsync(x => x.Icon = new Image(imageStream)); + return SetServerIconResult.Success; + } + + private bool IsValidUri(string img) => !string.IsNullOrWhiteSpace(img) && Uri.IsWellFormedUriString(img, UriKind.Absolute); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleCommands.cs b/src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleCommands.cs new file mode 100644 index 0000000..dc687cc --- /dev/null +++ b/src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleCommands.cs @@ -0,0 +1,60 @@ +#nullable disable +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class AutoAssignRoleCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task AutoAssignRole([Leftover] IRole role) + { + var guser = (IGuildUser)ctx.User; + if (role.Id == ctx.Guild.EveryoneRole.Id) + return; + + // the user can't aar the role which is higher or equal to his highest role + if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + { + await Response().Error(strs.hierarchy).SendAsync(); + return; + } + + var roles = await _service.ToggleAarAsync(ctx.Guild.Id, role.Id); + if (roles.Count == 0) + await Response().Confirm(strs.aar_disabled).SendAsync(); + else if (roles.Contains(role.Id)) + await AutoAssignRole(); + else + await Response().Confirm(strs.aar_role_removed(Format.Bold(role.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task AutoAssignRole() + { + if (!_service.TryGetRoles(ctx.Guild.Id, out var roles)) + { + await Response().Confirm(strs.aar_none).SendAsync(); + return; + } + + var existing = roles.Select(rid => ctx.Guild.GetRole(rid)).Where(r => r is not null).ToList(); + + if (existing.Count != roles.Count) + await _service.SetAarRolesAsync(ctx.Guild.Id, existing.Select(x => x.Id)); + + await Response() + .Confirm(strs.aar_roles( + '\n' + existing.Select(x => Format.Bold(x.ToString())).Join(",\n"))) + .SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleService.cs b/src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleService.cs new file mode 100644 index 0000000..f373d45 --- /dev/null +++ b/src/EllieBot/Modules/Administration/AutoAssignableRoles/AutoAssignRoleService.cs @@ -0,0 +1,159 @@ +#nullable disable +using EllieBot.Db.Models; +using System.Net; +using System.Threading.Channels; +using LinqToDB; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; + +namespace EllieBot.Modules.Administration.Services; + +public sealed class AutoAssignRoleService : IEService +{ + private readonly DiscordSocketClient _client; + private readonly DbService _db; + + //guildid/roleid + private readonly ConcurrentDictionary> _autoAssignableRoles; + + private readonly Channel _assignQueue = Channel.CreateBounded( + new BoundedChannelOptions(100) + { + FullMode = BoundedChannelFullMode.DropOldest, + SingleReader = true, + SingleWriter = false + }); + + public AutoAssignRoleService(DiscordSocketClient client, IBot bot, DbService db) + { + _client = client; + _db = db; + + _autoAssignableRoles = bot.AllGuildConfigs.Where(x => !string.IsNullOrWhiteSpace(x.AutoAssignRoleIds)) + .ToDictionary>(k => k.GuildId, + v => v.GetAutoAssignableRoles()) + .ToConcurrent(); + + _ = Task.Run(async () => + { + while (true) + { + var user = await _assignQueue.Reader.ReadAsync(); + if (!_autoAssignableRoles.TryGetValue(user.Guild.Id, out var savedRoleIds)) + continue; + + try + { + var roleIds = savedRoleIds.Select(roleId => user.Guild.GetRole(roleId)) + .Where(x => x is not null) + .ToList(); + + if (roleIds.Any()) + { + await user.AddRolesAsync(roleIds); + await Task.Delay(250); + } + else + { + Log.Warning( + "Disabled 'Auto assign role' feature on {GuildName} [{GuildId}] server the roles dont exist", + user.Guild.Name, + user.Guild.Id); + + await DisableAarAsync(user.Guild.Id); + } + } + catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden) + { + Log.Warning( + "Disabled 'Auto assign role' feature on {GuildName} [{GuildId}] server because I don't have role management permissions", + user.Guild.Name, + user.Guild.Id); + + await DisableAarAsync(user.Guild.Id); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in aar. Probably one of the roles doesn't exist"); + } + } + }); + + _client.UserJoined += OnClientOnUserJoined; + _client.RoleDeleted += OnClientRoleDeleted; + } + + private async Task OnClientRoleDeleted(SocketRole role) + { + if (_autoAssignableRoles.TryGetValue(role.Guild.Id, out var roles) && roles.Contains(role.Id)) + await ToggleAarAsync(role.Guild.Id, role.Id); + } + + private async Task OnClientOnUserJoined(SocketGuildUser user) + { + if (_autoAssignableRoles.TryGetValue(user.Guild.Id, out _)) + await _assignQueue.Writer.WriteAsync(user); + } + + public async Task> ToggleAarAsync(ulong guildId, ulong roleId) + { + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + var roles = gc.GetAutoAssignableRoles(); + if (!roles.Remove(roleId) && roles.Count < 3) + roles.Add(roleId); + + gc.SetAutoAssignableRoles(roles); + await uow.SaveChangesAsync(); + + if (roles.Count > 0) + _autoAssignableRoles[guildId] = roles; + else + _autoAssignableRoles.TryRemove(guildId, out _); + + return roles; + } + + public async Task DisableAarAsync(ulong guildId) + { + await using var uow = _db.GetDbContext(); + + await uow.Set().AsNoTracking() + .Where(x => x.GuildId == guildId) + .UpdateAsync(_ => new() + { + AutoAssignRoleIds = null + }); + + _autoAssignableRoles.TryRemove(guildId, out _); + + await uow.SaveChangesAsync(); + } + + public async Task SetAarRolesAsync(ulong guildId, IEnumerable newRoles) + { + await using var uow = _db.GetDbContext(); + + var gc = uow.GuildConfigsForId(guildId, set => set); + gc.SetAutoAssignableRoles(newRoles); + + await uow.SaveChangesAsync(); + } + + public bool TryGetRoles(ulong guildId, out IReadOnlyList roles) + => _autoAssignableRoles.TryGetValue(guildId, out roles); +} + +public static class GuildConfigExtensions +{ + public static List GetAutoAssignableRoles(this GuildConfig gc) + { + if (string.IsNullOrWhiteSpace(gc.AutoAssignRoleIds)) + return new(); + + return gc.AutoAssignRoleIds.Split(',').Select(ulong.Parse).ToList(); + } + + public static void SetAutoAssignableRoles(this GuildConfig gc, IEnumerable roles) + => gc.AutoAssignRoleIds = roles.Join(','); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/AutoPublishService.cs b/src/EllieBot/Modules/Administration/AutoPublishService.cs new file mode 100644 index 0000000..8f29495 --- /dev/null +++ b/src/EllieBot/Modules/Administration/AutoPublishService.cs @@ -0,0 +1,87 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public class AutoPublishService : IExecNoCommand, IReadyExecutor, IEService +{ + private readonly DbService _db; + private readonly DiscordSocketClient _client; + private readonly IBotCredsProvider _creds; + private ConcurrentDictionary _enabled; + + public AutoPublishService(DbService db, DiscordSocketClient client, IBotCredsProvider creds) + { + _db = db; + _client = client; + _creds = creds; + } + + public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg) + { + if (guild is null) + return; + + if (msg.Channel.GetChannelType() != ChannelType.News) + return; + + if (!_enabled.TryGetValue(guild.Id, out var cid) || cid != msg.Channel.Id) + return; + + await msg.CrosspostAsync(new RequestOptions() + { + RetryMode = RetryMode.AlwaysFail + }); + } + + public async Task OnReadyAsync() + { + var creds = _creds.GetCreds(); + + await using var ctx = _db.GetDbContext(); + var items = await ctx.GetTable() + .Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId, creds.TotalShards, _client.ShardId)) + .ToListAsyncLinqToDB(); + + _enabled = items + .ToDictionary(x => x.GuildId, x => x.ChannelId) + .ToConcurrent(); + } + + public async Task ToggleAutoPublish(ulong guildId, ulong channelId) + { + await using var ctx = _db.GetDbContext(); + var deleted = await ctx.GetTable() + .DeleteAsync(x => x.GuildId == guildId && x.ChannelId == channelId); + + if (deleted != 0) + { + _enabled.TryRemove(guildId, out _); + return false; + } + + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + GuildId = guildId, + ChannelId = channelId, + DateAdded = DateTime.UtcNow, + }, + old => new() + { + ChannelId = channelId, + DateAdded = DateTime.UtcNow, + }, + () => new() + { + GuildId = guildId + }); + + _enabled[guildId] = channelId; + + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/CleanupCommands.cs b/src/EllieBot/Modules/Administration/DangerousCommands/CleanupCommands.cs new file mode 100644 index 0000000..8fee8a3 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/CleanupCommands.cs @@ -0,0 +1,31 @@ +namespace EllieBot.Modules.Administration.DangerousCommands; + +public partial class Administration +{ + [Group] + public class CleanupCommands : CleanupModuleBase + { + private readonly ICleanupService _svc; + + public CleanupCommands(ICleanupService svc) + => _svc = svc; + + [Cmd] + [OwnerOnly] + [RequireContext(ContextType.DM)] + public async Task CleanupGuildData() + { + var result = await _svc.DeleteMissingGuildDataAsync(); + + if (result is null) + { + await ctx.ErrorAsync(); + return; + } + + await Response() + .Confirm($"{result.GuildCount} guilds' data remain in the database.") + .SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs b/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs new file mode 100644 index 0000000..3555a61 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs @@ -0,0 +1,106 @@ +using LinqToDB; +using LinqToDB.Data; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.DangerousCommands; + +public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService +{ + private readonly IPubSub _pubSub; + private TypedKey _keepReportKey = new("cleanup:report"); + private TypedKey _keepTriggerKey = new("cleanup:trigger"); + private readonly DiscordSocketClient _client; + private ConcurrentDictionary guildIds = new(); + private readonly IBotCredsProvider _creds; + private readonly DbService _db; + + public CleanupService( + IPubSub pubSub, + DiscordSocketClient client, + IBotCredsProvider creds, + DbService db) + { + _pubSub = pubSub; + _client = client; + _creds = creds; + _db = db; + } + + public async Task DeleteMissingGuildDataAsync() + { + guildIds = new(); + var totalShards = _creds.GetCreds().TotalShards; + await _pubSub.Pub(_keepTriggerKey, true); + var counter = 0; + while (guildIds.Keys.Count < totalShards) + { + await Task.Delay(1000); + counter++; + + if (counter >= 5) + break; + } + + if (guildIds.Keys.Count < totalShards) + return default; + + var allIds = guildIds.SelectMany(x => x.Value) + .ToArray(); + + await using var ctx = _db.GetDbContext(); + await using var linqCtx = ctx.CreateLinqToDBContext(); + await using var tempTable = linqCtx.CreateTempTable(); + + foreach (var chunk in allIds.Chunk(20000)) + { + await tempTable.BulkCopyAsync(chunk.Select(x => new CleanupId() + { + GuildId = x + })); + } + + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + return new() + { + GuildCount = guildIds.Keys.Count, + }; + } + + private ValueTask OnKeepReport(KeepReport report) + { + guildIds[report.ShardId] = report.GuildIds; + return default; + } + + public async Task OnReadyAsync() + { + await _pubSub.Sub(_keepTriggerKey, OnKeepTrigger); + + if (_client.ShardId == 0) + await _pubSub.Sub(_keepReportKey, OnKeepReport); + } + + private ValueTask OnKeepTrigger(bool arg) + { + _pubSub.Pub(_keepReportKey, + new KeepReport() + { + ShardId = _client.ShardId, + GuildIds = _client.GetGuildIds(), + }); + + return default; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommands.cs b/src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommands.cs new file mode 100644 index 0000000..80484c3 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommands.cs @@ -0,0 +1,164 @@ +#nullable disable +using System.Globalization; +using CsvHelper; +using CsvHelper.Configuration; +using EllieBot.Modules.Gambling; +using EllieBot.Modules.Administration.Services; +using EllieBot.Modules.Xp; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + [OwnerOnly] + [NoPublicBot] + public partial class DangerousCommands : CleanupModuleBase + { + private readonly DangerousCommandsService _ds; + private readonly IGamblingCleanupService _gcs; + private readonly IXpCleanupService _xcs; + + public DangerousCommands( + DangerousCommandsService ds, + IGamblingCleanupService gcs, + IXpCleanupService xcs) + { + _ds = ds; + _gcs = gcs; + _xcs = xcs; + } + + [Cmd] + [OwnerOnly] + public Task SqlSelect([Leftover] string sql) + { + var result = _ds.SelectSql(sql); + + return Response() + .Paginated() + .Items(result.Results) + .PageSize(20) + .Page((items, _) => + { + if (!items.Any()) + return _sender.CreateEmbed().WithErrorColor().WithFooter(sql).WithDescription("-"); + + return _sender.CreateEmbed() + .WithOkColor() + .WithFooter(sql) + .WithTitle(string.Join(" ║ ", result.ColumnNames)) + .WithDescription(string.Join('\n', items.Select(x => string.Join(" ║ ", x)))); + }) + .SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task SqlSelectCsv([Leftover] string sql) + { + var result = _ds.SelectSql(sql); + + // create a file stream and write the data as csv + using var ms = new MemoryStream(); + await using var sw = new StreamWriter(ms); + await using var csv = new CsvWriter(sw, + new CsvConfiguration(CultureInfo.InvariantCulture) + { + Delimiter = "," + }); + + foreach (var cn in result.ColumnNames) + { + csv.WriteField(cn); + } + + await csv.NextRecordAsync(); + + foreach (var row in result.Results) + { + foreach (var field in row) + { + csv.WriteField(field); + } + + await csv.NextRecordAsync(); + } + + + await csv.FlushAsync(); + ms.Position = 0; + + // send the file + await ctx.Channel.SendFileAsync(ms, $"query_result_{DateTime.UtcNow.Ticks}.csv"); + } + + [Cmd] + [OwnerOnly] + public async Task SqlExec([Leftover] string sql) + { + try + { + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.sql_confirm_exec)) + .WithDescription(Format.Code(sql)); + + if (!await PromptUserConfirmAsync(embed)) + return; + + var res = await _ds.ExecuteSql(sql); + await Response().Confirm(res.ToString()).SendAsync(); + } + catch (Exception ex) + { + await Response().Error(ex.ToString()).SendAsync(); + } + } + + [Cmd] + [OwnerOnly] + public async Task PurgeUser(ulong userId) + { + var embed = _sender.CreateEmbed() + .WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString())))); + + if (!await PromptUserConfirmAsync(embed)) + return; + + await _ds.PurgeUserAsync(userId); + await ctx.OkAsync(); + } + + [Cmd] + [OwnerOnly] + public Task PurgeUser([Leftover] IUser user) + => PurgeUser(user.Id); + + [Cmd] + [OwnerOnly] + public Task DeleteXp() + => ConfirmActionInternalAsync("Delete Xp", () => _xcs.DeleteXp()); + + + [Cmd] + [OwnerOnly] + public Task DeleteWaifus() + => ConfirmActionInternalAsync("Delete Waifus", () => _gcs.DeleteWaifus()); + + [Cmd] + [OwnerOnly] + public async Task DeleteWaifu(IUser user) + => await DeleteWaifu(user.Id); + + [Cmd] + [OwnerOnly] + public Task DeleteWaifu(ulong userId) + => ConfirmActionInternalAsync($"Delete Waifu {userId}", () => _gcs.DeleteWaifu(userId)); + + + [Cmd] + [OwnerOnly] + public Task DeleteCurrency() + => ConfirmActionInternalAsync("Delete Currency", () => _gcs.DeleteCurrency()); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommandsService.cs b/src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommandsService.cs new file mode 100644 index 0000000..bbea48b --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/DangerousCommandsService.cs @@ -0,0 +1,103 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public class DangerousCommandsService : IEService +{ + private readonly DbService _db; + + public DangerousCommandsService(DbService db) + => _db = db; + + public async Task ExecuteSql(string sql) + { + int res; + await using var uow = _db.GetDbContext(); + res = await uow.Database.ExecuteSqlRawAsync(sql); + return res; + } + + public SelectResult SelectSql(string sql) + { + var result = new SelectResult + { + ColumnNames = new(), + Results = new() + }; + + using var uow = _db.GetDbContext(); + var conn = uow.Database.GetDbConnection(); + conn.Open(); + using var cmd = conn.CreateCommand(); + cmd.CommandText = sql; + using var reader = cmd.ExecuteReader(); + if (reader.HasRows) + { + for (var i = 0; i < reader.FieldCount; i++) + result.ColumnNames.Add(reader.GetName(i)); + while (reader.Read()) + { + var obj = new object[reader.FieldCount]; + reader.GetValues(obj); + result.Results.Add(obj.Select(x => x.ToString()).ToArray()); + } + } + + return result; + } + + public async Task PurgeUserAsync(ulong userId) + { + await using var uow = _db.GetDbContext(); + + // get waifu info + var wi = await uow.Set().FirstOrDefaultAsyncEF(x => x.Waifu.UserId == userId); + + // if it exists, delete waifu related things + if (wi is not null) + { + // remove updates which have new or old as this waifu + await uow.Set().DeleteAsync(wu => wu.New.UserId == userId || wu.Old.UserId == userId); + + // delete all items this waifu owns + await uow.Set().DeleteAsync(x => x.WaifuInfoId == wi.Id); + + // all waifus this waifu claims are released + await uow.Set() + .AsQueryable() + .Where(x => x.Claimer.UserId == userId) + .UpdateAsync(x => new() + { + ClaimerId = null + }); + + // all affinities set to this waifu are reset + await uow.Set() + .AsQueryable() + .Where(x => x.Affinity.UserId == userId) + .UpdateAsync(x => new() + { + AffinityId = null + }); + } + + // delete guild xp + await uow.Set().DeleteAsync(x => x.UserId == userId); + + // delete currency transactions + await uow.Set().DeleteAsync(x => x.UserId == userId); + + // delete user, currency, and clubs go away with it + await uow.Set().DeleteAsync(u => u.UserId == userId); + } + + public class SelectResult + { + public List ColumnNames { get; set; } + public List Results { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/_common/CleanupId.cs b/src/EllieBot/Modules/Administration/DangerousCommands/_common/CleanupId.cs new file mode 100644 index 0000000..cd6d742 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/_common/CleanupId.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; + +namespace EllieBot.Modules.Administration.DangerousCommands; + +public sealed class CleanupId +{ + [Key] + public ulong GuildId { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/_common/ICleanupService.cs b/src/EllieBot/Modules/Administration/DangerousCommands/_common/ICleanupService.cs new file mode 100644 index 0000000..a396082 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/_common/ICleanupService.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Administration.DangerousCommands; + +public interface ICleanupService +{ + Task DeleteMissingGuildDataAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepReport.cs b/src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepReport.cs new file mode 100644 index 0000000..44ecee2 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepReport.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Administration.DangerousCommands; + +public sealed class KeepReport +{ + public required int ShardId { get; init; } + public required ulong[] GuildIds { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepResult.cs b/src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepResult.cs new file mode 100644 index 0000000..52c8051 --- /dev/null +++ b/src/EllieBot/Modules/Administration/DangerousCommands/_common/KeepResult.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Administration.DangerousCommands; + +public sealed class KeepResult +{ + public required int GuildCount { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelCommands.cs b/src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelCommands.cs new file mode 100644 index 0000000..8099573 --- /dev/null +++ b/src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelCommands.cs @@ -0,0 +1,36 @@ +#nullable disable +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class GameVoiceChannelCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.MoveMembers)] + public async Task GameVoiceChannel() + { + var vch = ((IGuildUser)ctx.User).VoiceChannel; + + if (vch is null) + { + await Response().Error(strs.not_in_voice).SendAsync(); + return; + } + + var id = _service.ToggleGameVoiceChannel(ctx.Guild.Id, vch.Id); + + if (id is null) + await Response().Confirm(strs.gvc_disabled).SendAsync(); + else + { + _service.GameVoiceChannels.Add(vch.Id); + await Response().Confirm(strs.gvc_enabled(Format.Bold(vch.Name))).SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelService.cs b/src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelService.cs new file mode 100644 index 0000000..54f9870 --- /dev/null +++ b/src/EllieBot/Modules/Administration/GameVoiceChannel/GameVoiceChannelService.cs @@ -0,0 +1,127 @@ +#nullable disable +using EllieBot.Db; + +namespace EllieBot.Modules.Administration.Services; + +public class GameVoiceChannelService : IEService +{ + public ConcurrentHashSet GameVoiceChannels { get; } + + private readonly DbService _db; + private readonly DiscordSocketClient _client; + + public GameVoiceChannelService(DiscordSocketClient client, DbService db, IBot bot) + { + _db = db; + _client = client; + + GameVoiceChannels = new(bot.AllGuildConfigs + .Where(gc => gc.GameVoiceChannel is not null) + .Select(gc => gc.GameVoiceChannel!.Value)); + + _client.UserVoiceStateUpdated += OnUserVoiceStateUpdated; + _client.PresenceUpdated += OnPresenceUpdate; + } + + private Task OnPresenceUpdate(SocketUser socketUser, SocketPresence before, SocketPresence after) + { + _ = Task.Run(async () => + { + try + { + if (socketUser is not SocketGuildUser newUser) + return; + // if the user is in the voice channel and that voice channel is gvc + + if (newUser.VoiceChannel is not { } vc + || !GameVoiceChannels.Contains(vc.Id)) + return; + + //if the activity has changed, and is a playi1ng activity + foreach (var activity in after.Activities) + { + if (activity is { Type: ActivityType.Playing }) + //trigger gvc + { + if (await TriggerGvc(newUser, activity.Name)) + return; + } + } + } + catch (Exception ex) + { + Log.Warning(ex, "Error running GuildMemberUpdated in gvc"); + } + }); + return Task.CompletedTask; + } + + public ulong? ToggleGameVoiceChannel(ulong guildId, ulong vchId) + { + ulong? id; + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + + if (gc.GameVoiceChannel == vchId) + { + GameVoiceChannels.TryRemove(vchId); + id = gc.GameVoiceChannel = null; + } + else + { + if (gc.GameVoiceChannel is not null) + GameVoiceChannels.TryRemove(gc.GameVoiceChannel.Value); + GameVoiceChannels.Add(vchId); + id = gc.GameVoiceChannel = vchId; + } + + uow.SaveChanges(); + return id; + } + + private Task OnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState) + { + _ = Task.Run(async () => + { + try + { + if (usr is not SocketGuildUser gUser) + return; + + if (newState.VoiceChannel is null) + return; + + if (!GameVoiceChannels.Contains(newState.VoiceChannel.Id)) + return; + + foreach (var game in gUser.Activities.Select(x => x.Name)) + { + if (await TriggerGvc(gUser, game)) + return; + } + } + catch (Exception ex) + { + Log.Warning(ex, "Error running VoiceStateUpdate in gvc"); + } + }); + + return Task.CompletedTask; + } + + private async Task TriggerGvc(SocketGuildUser gUser, string game) + { + if (string.IsNullOrWhiteSpace(game)) + return false; + + game = game.TrimTo(50)!.ToLowerInvariant(); + var vch = gUser.Guild.VoiceChannels.FirstOrDefault(x => x.Name.ToLowerInvariant() == game); + + if (vch is null) + return false; + + await Task.Delay(1000); + await gUser.ModifyAsync(gu => gu.Channel = vch); + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/GreetBye/GreetCommands.cs b/src/EllieBot/Modules/Administration/GreetBye/GreetCommands.cs new file mode 100644 index 0000000..53dd058 --- /dev/null +++ b/src/EllieBot/Modules/Administration/GreetBye/GreetCommands.cs @@ -0,0 +1,229 @@ +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class GreetCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task Boost() + { + var enabled = await _service.ToggleBoost(ctx.Guild.Id, ctx.Channel.Id); + + if (enabled) + await Response().Confirm(strs.boost_on).SendAsync(); + else + await Response().Pending(strs.boost_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task BoostDel(int timer = 30) + { + if (timer is < 0 or > 600) + return; + + await _service.SetBoostDel(ctx.Guild.Id, timer); + + if (timer > 0) + await Response().Confirm(strs.boostdel_on(timer)).SendAsync(); + else + await Response().Pending(strs.boostdel_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task BoostMsg([Leftover] string? text = null) + { + if (string.IsNullOrWhiteSpace(text)) + { + var boostMessage = _service.GetBoostMessage(ctx.Guild.Id); + await Response().Confirm(strs.boostmsg_cur(boostMessage?.SanitizeMentions())).SendAsync(); + return; + } + + var sendBoostEnabled = _service.SetBoostMessage(ctx.Guild.Id, ref text); + + await Response().Confirm(strs.boostmsg_new).SendAsync(); + if (!sendBoostEnabled) + await Response().Pending(strs.boostmsg_enable($"`{prefix}boost`")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task GreetDel(int timer = 30) + { + if (timer is < 0 or > 600) + return; + + await _service.SetGreetDel(ctx.Guild.Id, timer); + + if (timer > 0) + await Response().Confirm(strs.greetdel_on(timer)).SendAsync(); + else + await Response().Pending(strs.greetdel_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task Greet() + { + var enabled = await _service.SetGreet(ctx.Guild.Id, ctx.Channel.Id); + + if (enabled) + await Response().Confirm(strs.greet_on).SendAsync(); + else + await Response().Pending(strs.greet_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task GreetMsg([Leftover] string? text = null) + { + if (string.IsNullOrWhiteSpace(text)) + { + var greetMsg = _service.GetGreetMsg(ctx.Guild.Id); + await Response().Confirm(strs.greetmsg_cur(greetMsg?.SanitizeMentions())).SendAsync(); + return; + } + + var sendGreetEnabled = _service.SetGreetMessage(ctx.Guild.Id, ref text); + + await Response().Confirm(strs.greetmsg_new).SendAsync(); + + if (!sendGreetEnabled) + await Response().Pending(strs.greetmsg_enable($"`{prefix}greet`")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task GreetDm() + { + var enabled = await _service.SetGreetDm(ctx.Guild.Id); + + if (enabled) + await Response().Confirm(strs.greetdm_on).SendAsync(); + else + await Response().Confirm(strs.greetdm_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task GreetDmMsg([Leftover] string? text = null) + { + if (string.IsNullOrWhiteSpace(text)) + { + var dmGreetMsg = _service.GetDmGreetMsg(ctx.Guild.Id); + await Response().Confirm(strs.greetdmmsg_cur(dmGreetMsg?.SanitizeMentions())).SendAsync(); + return; + } + + var sendGreetEnabled = _service.SetGreetDmMessage(ctx.Guild.Id, ref text); + + await Response().Confirm(strs.greetdmmsg_new).SendAsync(); + if (!sendGreetEnabled) + await Response().Pending(strs.greetdmmsg_enable($"`{prefix}greetdm`")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task Bye() + { + var enabled = await _service.SetBye(ctx.Guild.Id, ctx.Channel.Id); + + if (enabled) + await Response().Confirm(strs.bye_on).SendAsync(); + else + await Response().Confirm(strs.bye_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task ByeMsg([Leftover] string? text = null) + { + if (string.IsNullOrWhiteSpace(text)) + { + var byeMsg = _service.GetByeMessage(ctx.Guild.Id); + await Response().Confirm(strs.byemsg_cur(byeMsg?.SanitizeMentions())).SendAsync(); + return; + } + + var sendByeEnabled = _service.SetByeMessage(ctx.Guild.Id, ref text); + + await Response().Confirm(strs.byemsg_new).SendAsync(); + if (!sendByeEnabled) + await Response().Pending(strs.byemsg_enable($"`{prefix}bye`")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + public async Task ByeDel(int timer = 30) + { + await _service.SetByeDel(ctx.Guild.Id, timer); + + if (timer > 0) + await Response().Confirm(strs.byedel_on(timer)).SendAsync(); + else + await Response().Pending(strs.byedel_off).SendAsync(); + } + + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + [Ratelimit(5)] + public async Task ByeTest([Leftover] IGuildUser? user = null) + { + user ??= (IGuildUser)ctx.User; + + await _service.ByeTest((ITextChannel)ctx.Channel, user); + var enabled = _service.GetByeEnabled(ctx.Guild.Id); + if (!enabled) + await Response().Pending(strs.byemsg_enable($"`{prefix}bye`")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + [Ratelimit(5)] + public async Task GreetTest([Leftover] IGuildUser? user = null) + { + user ??= (IGuildUser)ctx.User; + + await _service.GreetTest((ITextChannel)ctx.Channel, user); + var enabled = _service.GetGreetEnabled(ctx.Guild.Id); + if (!enabled) + await Response().Pending(strs.greetmsg_enable($"`{prefix}greet`")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageGuild)] + [Ratelimit(5)] + public async Task GreetDmTest([Leftover] IGuildUser? user = null) + { + user ??= (IGuildUser)ctx.User; + + var success = await _service.GreetDmTest(user); + if (success) + await ctx.OkAsync(); + else + await ctx.WarningAsync(); + var enabled = _service.GetGreetDmEnabled(ctx.Guild.Id); + if (!enabled) + await Response().Pending(strs.greetdmmsg_enable($"`{prefix}greetdm`")).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/GreetBye/GreetGrouper.cs b/src/EllieBot/Modules/Administration/GreetBye/GreetGrouper.cs new file mode 100644 index 0000000..a92256e --- /dev/null +++ b/src/EllieBot/Modules/Administration/GreetBye/GreetGrouper.cs @@ -0,0 +1,71 @@ +namespace EllieBot.Services; + +public class GreetGrouper +{ + private readonly Dictionary> _group; + private readonly object _locker = new(); + + public GreetGrouper() + => _group = new(); + + + /// + /// Creates a group, if group already exists, adds the specified user + /// + /// Id of the server for which to create group for + /// User to add if group already exists + /// + public bool CreateOrAdd(ulong guildId, T toAddIfExists) + { + lock (_locker) + { + if (_group.TryGetValue(guildId, out var list)) + { + list.Add(toAddIfExists); + return false; + } + + _group[guildId] = new(); + return true; + } + } + + /// + /// Remove the specified amount of items from the group. If all items are removed, group will be removed. + /// + /// Id of the group + /// Maximum number of items to retrieve + /// Items retrieved + /// Whether the group has no more items left and is deleted + public bool ClearGroup(ulong guildId, int count, out IReadOnlyCollection items) + { + lock (_locker) + { + if (_group.TryGetValue(guildId, out var set)) + { + // if we want more than there are, return everything + if (count >= set.Count) + { + items = set; + _group.Remove(guildId); + return true; + } + + // if there are more in the group than what's needed + // take the requested number, remove them from the set + // and return them + var toReturn = set.TakeWhile(_ => count-- != 0).ToList(); + foreach (var item in toReturn) + set.Remove(item); + + items = toReturn; + // returning falsemeans group is not yet deleted + // because there are items left + return false; + } + + items = Array.Empty(); + return true; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/GreetBye/GreetService.cs b/src/EllieBot/Modules/Administration/GreetBye/GreetService.cs new file mode 100644 index 0000000..aec7e9e --- /dev/null +++ b/src/EllieBot/Modules/Administration/GreetBye/GreetService.cs @@ -0,0 +1,662 @@ +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Db.Models; +using System.Threading.Channels; + +namespace EllieBot.Services; + +public class GreetService : IEService, IReadyExecutor +{ + public bool GroupGreets + => _bss.Data.GroupGreets; + + private readonly DbService _db; + + private readonly ConcurrentDictionary _guildConfigsCache; + private readonly DiscordSocketClient _client; + + private readonly GreetGrouper _greets = new(); + private readonly GreetGrouper _byes = new(); + private readonly BotConfigService _bss; + private readonly IReplacementService _repSvc; + private readonly IMessageSenderService _sender; + + public GreetService( + DiscordSocketClient client, + IBot bot, + DbService db, + BotConfigService bss, + IMessageSenderService sender, + IReplacementService repSvc) + { + _db = db; + _client = client; + _bss = bss; + _repSvc = repSvc; + _sender = sender; + + _guildConfigsCache = new(bot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create)); + + _client.UserJoined += OnUserJoined; + _client.UserLeft += OnUserLeft; + + bot.JoinedGuild += OnBotJoinedGuild; + _client.LeftGuild += OnClientLeftGuild; + + _client.GuildMemberUpdated += ClientOnGuildMemberUpdated; + } + + public async Task OnReadyAsync() + { + while (true) + { + var (conf, user, compl) = await _greetDmQueue.Reader.ReadAsync(); + var res = await GreetDmUserInternal(conf, user); + compl.TrySetResult(res); + await Task.Delay(2000); + } + } + + private Task ClientOnGuildMemberUpdated(Cacheable optOldUser, SocketGuildUser newUser) + { + // if user is a new booster + // or boosted again the same server + if ((optOldUser.Value is { PremiumSince: null } && newUser is { PremiumSince: not null }) + || (optOldUser.Value?.PremiumSince is { } oldDate + && newUser.PremiumSince is { } newDate + && newDate > oldDate)) + { + var conf = GetOrAddSettingsForGuild(newUser.Guild.Id); + if (!conf.SendBoostMessage) + return Task.CompletedTask; + + _ = Task.Run(TriggerBoostMessage(conf, newUser)); + } + + return Task.CompletedTask; + } + + private Func TriggerBoostMessage(GreetSettings conf, SocketGuildUser user) + => async () => + { + var channel = user.Guild.GetTextChannel(conf.BoostMessageChannelId); + if (channel is null) + return; + + await SendBoostMessage(conf, user, channel); + }; + + private async Task SendBoostMessage(GreetSettings conf, IGuildUser user, ITextChannel channel) + { + if (string.IsNullOrWhiteSpace(conf.BoostMessage)) + return false; + + var toSend = SmartText.CreateFrom(conf.BoostMessage); + + try + { + var newContent = await _repSvc.ReplaceAsync(toSend, + new(client: _client, guild: user.Guild, channel: channel, users: user)); + var toDelete = await _sender.Response(channel).Text(newContent).Sanitize(false).SendAsync(); + if (conf.BoostMessageDeleteAfter > 0) + toDelete.DeleteAfter(conf.BoostMessageDeleteAfter); + + return true; + } + catch (Exception ex) + { + Log.Error(ex, "Error sending boost message"); + } + + return false; + } + + private Task OnClientLeftGuild(SocketGuild arg) + { + _guildConfigsCache.TryRemove(arg.Id, out _); + return Task.CompletedTask; + } + + private Task OnBotJoinedGuild(GuildConfig gc) + { + _guildConfigsCache[gc.GuildId] = GreetSettings.Create(gc); + return Task.CompletedTask; + } + + private Task OnUserLeft(SocketGuild guild, SocketUser user) + { + _ = Task.Run(async () => + { + try + { + var conf = GetOrAddSettingsForGuild(guild.Id); + + if (!conf.SendChannelByeMessage) + return; + var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ByeMessageChannelId); + + if (channel is null) //maybe warn the server owner that the channel is missing + return; + + if (GroupGreets) + { + // if group is newly created, greet that user right away, + // but any user which joins in the next 5 seconds will + // be greeted in a group greet + if (_byes.CreateOrAdd(guild.Id, user)) + { + // greet single user + await ByeUsers(conf, channel, new[] { user }); + var groupClear = false; + while (!groupClear) + { + await Task.Delay(5000); + groupClear = _byes.ClearGroup(guild.Id, 5, out var toBye); + await ByeUsers(conf, channel, toBye); + } + } + } + else + await ByeUsers(conf, channel, new[] { user }); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + public string? GetDmGreetMsg(ulong id) + { + using var uow = _db.GetDbContext(); + return uow.GuildConfigsForId(id, set => set).DmGreetMessageText; + } + + public string? GetGreetMsg(ulong gid) + { + using var uow = _db.GetDbContext(); + return uow.GuildConfigsForId(gid, set => set).ChannelGreetMessageText; + } + + public string? GetBoostMessage(ulong gid) + { + using var uow = _db.GetDbContext(); + return uow.GuildConfigsForId(gid, set => set).BoostMessage; + } + + public GreetSettings GetGreetSettings(ulong gid) + { + if (_guildConfigsCache.TryGetValue(gid, out var gs)) + return gs; + + using var uow = _db.GetDbContext(); + return GreetSettings.Create(uow.GuildConfigsForId(gid, set => set)); + } + + private Task ByeUsers(GreetSettings conf, ITextChannel channel, IUser user) + => ByeUsers(conf, channel, new[] { user }); + + private async Task ByeUsers(GreetSettings conf, ITextChannel channel, IReadOnlyCollection users) + { + if (!users.Any()) + return; + + var repCtx = new ReplacementContext(client: _client, + guild: channel.Guild, + channel: channel, + users: users.ToArray()); + + var text = SmartText.CreateFrom(conf.ChannelByeMessageText); + text = await _repSvc.ReplaceAsync(text, repCtx); + try + { + var toDelete = await _sender.Response(channel).Text(text).Sanitize(false).SendAsync(); + if (conf.AutoDeleteByeMessagesTimer > 0) + toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); + } + catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions + || ex.DiscordCode == DiscordErrorCode.MissingPermissions + || ex.DiscordCode == DiscordErrorCode.UnknownChannel) + { + Log.Warning(ex, + "Missing permissions to send a bye message, the bye message will be disabled on server: {GuildId}", + channel.GuildId); + await SetBye(channel.GuildId, channel.Id, false); + } + catch (Exception ex) + { + Log.Warning(ex, "Error embeding bye message"); + } + } + + private Task GreetUsers(GreetSettings conf, ITextChannel channel, IGuildUser user) + => GreetUsers(conf, channel, new[] { user }); + + private async Task GreetUsers(GreetSettings conf, ITextChannel channel, IReadOnlyCollection users) + { + if (users.Count == 0) + return; + + var repCtx = new ReplacementContext(client: _client, + guild: channel.Guild, + channel: channel, + users: users.ToArray()); + + var text = SmartText.CreateFrom(conf.ChannelGreetMessageText); + text = await _repSvc.ReplaceAsync(text, repCtx); + try + { + var toDelete = await _sender.Response(channel).Text(text).Sanitize(false).SendAsync(); + if (conf.AutoDeleteGreetMessagesTimer > 0) + toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); + } + catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions + || ex.DiscordCode == DiscordErrorCode.MissingPermissions + || ex.DiscordCode == DiscordErrorCode.UnknownChannel) + { + Log.Warning(ex, + "Missing permissions to send a bye message, the greet message will be disabled on server: {GuildId}", + channel.GuildId); + await SetGreet(channel.GuildId, channel.Id, false); + } + catch (Exception ex) + { + Log.Warning(ex, "Error embeding greet message"); + } + } + + private readonly Channel<(GreetSettings, IGuildUser, TaskCompletionSource)> _greetDmQueue = + Channel.CreateBounded<(GreetSettings, IGuildUser, TaskCompletionSource)>(new BoundedChannelOptions(60) + { + // The limit of 60 users should be only hit when there's a raid. In that case + // probably the best thing to do is to drop newest (raiding) users + FullMode = BoundedChannelFullMode.DropNewest + }); + + + private async Task GreetDmUser(GreetSettings conf, IGuildUser user) + { + var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + await _greetDmQueue.Writer.WriteAsync((conf, user, completionSource)); + return await completionSource.Task; + } + + private async Task GreetDmUserInternal(GreetSettings conf, IGuildUser user) + { + try + { + // var rep = new ReplacementBuilder() + // .WithUser(user) + // .WithServer(_client, (SocketGuild)user.Guild) + // .Build(); + + var repCtx = new ReplacementContext(client: _client, guild: user.Guild, users: user); + var smartText = SmartText.CreateFrom(conf.DmGreetMessageText); + smartText = await _repSvc.ReplaceAsync(smartText, repCtx); + + if (smartText is SmartPlainText pt) + { + smartText = new SmartEmbedText() + { + Description = pt.Text + }; + } + + if (smartText is SmartEmbedText set) + { + smartText = set with + { + Footer = CreateFooterSource(user) + }; + } + else if (smartText is SmartEmbedTextArray seta) + { + // if the greet dm message is a text array + var ebElem = seta.Embeds.LastOrDefault(); + if (ebElem is null) + { + // if there are no embeds, add an embed with the footer + smartText = seta with + { + Embeds = + [ + new SmartEmbedArrayElementText() + { + Footer = CreateFooterSource(user) + } + ] + }; + } + else + { + // if the maximum amount of embeds is reached, edit the last embed + if (seta.Embeds.Length >= 10) + { + seta.Embeds[^1] = seta.Embeds[^1] with + { + Footer = CreateFooterSource(user) + }; + } + else + { + // if there is less than 10 embeds, add an embed with footer only + seta.Embeds = seta.Embeds.Append(new SmartEmbedArrayElementText() + { + Footer = CreateFooterSource(user) + }) + .ToArray(); + } + } + } + + await _sender.Response(user).Text(smartText).Sanitize(false).SendAsync(); + } + catch + { + return false; + } + + return true; + } + + private static SmartTextEmbedFooter CreateFooterSource(IGuildUser user) + => new() + { + Text = $"This message was sent from {user.Guild} server.", + IconUrl = user.Guild.IconUrl + }; + + private Task OnUserJoined(IGuildUser user) + { + _ = Task.Run(async () => + { + try + { + var conf = GetOrAddSettingsForGuild(user.GuildId); + + if (conf.SendChannelGreetMessage) + { + var channel = await user.Guild.GetTextChannelAsync(conf.GreetMessageChannelId); + if (channel is not null) + { + if (GroupGreets) + { + // if group is newly created, greet that user right away, + // but any user which joins in the next 5 seconds will + // be greeted in a group greet + if (_greets.CreateOrAdd(user.GuildId, user)) + { + // greet single user + await GreetUsers(conf, channel, new[] { user }); + var groupClear = false; + while (!groupClear) + { + await Task.Delay(5000); + groupClear = _greets.ClearGroup(user.GuildId, 5, out var toGreet); + await GreetUsers(conf, channel, toGreet); + } + } + } + else + await GreetUsers(conf, channel, new[] { user }); + } + } + + if (conf.SendDmGreetMessage) + await GreetDmUser(conf, user); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + public string? GetByeMessage(ulong gid) + { + using var uow = _db.GetDbContext(); + return uow.GuildConfigsForId(gid, set => set).ChannelByeMessageText; + } + + public GreetSettings GetOrAddSettingsForGuild(ulong guildId) + { + if (_guildConfigsCache.TryGetValue(guildId, out var settings)) + return settings; + + using (var uow = _db.GetDbContext()) + { + var gc = uow.GuildConfigsForId(guildId, set => set); + settings = GreetSettings.Create(gc); + } + + _guildConfigsCache.TryAdd(guildId, settings); + return settings; + } + + public async Task SetGreet(ulong guildId, ulong channelId, bool? value = null) + { + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + var enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage; + conf.GreetMessageChannelId = channelId; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + await uow.SaveChangesAsync(); + return enabled; + } + + public bool SetGreetMessage(ulong guildId, ref string message) + { + message = message.SanitizeMentions(); + + if (string.IsNullOrWhiteSpace(message)) + throw new ArgumentNullException(nameof(message)); + + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.ChannelGreetMessageText = message; + var greetMsgEnabled = conf.SendChannelGreetMessage; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache.AddOrUpdate(guildId, toAdd, (_, _) => toAdd); + + uow.SaveChanges(); + return greetMsgEnabled; + } + + public async Task SetGreetDm(ulong guildId, bool? value = null) + { + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + var enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + await uow.SaveChangesAsync(); + return enabled; + } + + public bool SetGreetDmMessage(ulong guildId, ref string? message) + { + message = message?.SanitizeMentions(); + + if (string.IsNullOrWhiteSpace(message)) + throw new ArgumentNullException(nameof(message)); + + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.DmGreetMessageText = message; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + uow.SaveChanges(); + return conf.SendDmGreetMessage; + } + + public async Task SetBye(ulong guildId, ulong channelId, bool? value = null) + { + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + var enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage; + conf.ByeMessageChannelId = channelId; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + await uow.SaveChangesAsync(); + return enabled; + } + + public bool SetByeMessage(ulong guildId, ref string? message) + { + message = message?.SanitizeMentions(); + + if (string.IsNullOrWhiteSpace(message)) + throw new ArgumentNullException(nameof(message)); + + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.ChannelByeMessageText = message; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + uow.SaveChanges(); + return conf.SendChannelByeMessage; + } + + public async Task SetByeDel(ulong guildId, int timer) + { + if (timer is < 0 or > 600) + return; + + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.AutoDeleteByeMessagesTimer = timer; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + await uow.SaveChangesAsync(); + } + + public async Task SetGreetDel(ulong guildId, int timer) + { + if (timer is < 0 or > 600) + return; + + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.AutoDeleteGreetMessagesTimer = timer; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + await uow.SaveChangesAsync(); + } + + public bool SetBoostMessage(ulong guildId, ref string message) + { + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.BoostMessage = message; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + uow.SaveChanges(); + return conf.SendBoostMessage; + } + + public async Task SetBoostDel(ulong guildId, int timer) + { + if (timer is < 0 or > 600) + throw new ArgumentOutOfRangeException(nameof(timer)); + + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + conf.BoostMessageDeleteAfter = timer; + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + + await uow.SaveChangesAsync(); + } + + public async Task ToggleBoost(ulong guildId, ulong channelId, bool? forceState = null) + { + await using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + + if (forceState is not bool fs) + conf.SendBoostMessage = !conf.SendBoostMessage; + else + conf.SendBoostMessage = fs; + + conf.BoostMessageChannelId = channelId; + await uow.SaveChangesAsync(); + + var toAdd = GreetSettings.Create(conf); + _guildConfigsCache[guildId] = toAdd; + return conf.SendBoostMessage; + } + + #region Get Enabled Status + + public bool GetGreetDmEnabled(ulong guildId) + { + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + return conf.SendDmGreetMessage; + } + + public bool GetGreetEnabled(ulong guildId) + { + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + return conf.SendChannelGreetMessage; + } + + public bool GetByeEnabled(ulong guildId) + { + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set); + return conf.SendChannelByeMessage; + } + + #endregion + + #region Test Messages + + public Task ByeTest(ITextChannel channel, IGuildUser user) + { + var conf = GetOrAddSettingsForGuild(user.GuildId); + return ByeUsers(conf, channel, user); + } + + public Task GreetTest(ITextChannel channel, IGuildUser user) + { + var conf = GetOrAddSettingsForGuild(user.GuildId); + return GreetUsers(conf, channel, user); + } + + public Task GreetDmTest(IGuildUser user) + { + var conf = GetOrAddSettingsForGuild(user.GuildId); + return GreetDmUser(conf, user); + } + + public Task BoostTest(ITextChannel channel, IGuildUser user) + { + var conf = GetOrAddSettingsForGuild(user.GuildId); + return SendBoostMessage(conf, user, channel); + } + + #endregion +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/GreetBye/GreetSettings.cs b/src/EllieBot/Modules/Administration/GreetBye/GreetSettings.cs new file mode 100644 index 0000000..6e4f8ed --- /dev/null +++ b/src/EllieBot/Modules/Administration/GreetBye/GreetSettings.cs @@ -0,0 +1,45 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Services; + +public class GreetSettings +{ + public int AutoDeleteGreetMessagesTimer { get; set; } + public int AutoDeleteByeMessagesTimer { get; set; } + + public ulong GreetMessageChannelId { get; set; } + public ulong ByeMessageChannelId { get; set; } + + public bool SendDmGreetMessage { get; set; } + public string? DmGreetMessageText { get; set; } + + public bool SendChannelGreetMessage { get; set; } + public string? ChannelGreetMessageText { get; set; } + + public bool SendChannelByeMessage { get; set; } + public string? ChannelByeMessageText { get; set; } + + public bool SendBoostMessage { get; set; } + public string? BoostMessage { get; set; } + public int BoostMessageDeleteAfter { get; set; } + public ulong BoostMessageChannelId { get; set; } + + public static GreetSettings Create(GuildConfig g) + => new() + { + AutoDeleteByeMessagesTimer = g.AutoDeleteByeMessagesTimer, + AutoDeleteGreetMessagesTimer = g.AutoDeleteGreetMessagesTimer, + GreetMessageChannelId = g.GreetMessageChannelId, + ByeMessageChannelId = g.ByeMessageChannelId, + SendDmGreetMessage = g.SendDmGreetMessage, + DmGreetMessageText = g.DmGreetMessageText, + SendChannelGreetMessage = g.SendChannelGreetMessage, + ChannelGreetMessageText = g.ChannelGreetMessageText, + SendChannelByeMessage = g.SendChannelByeMessage, + ChannelByeMessageText = g.ChannelByeMessageText, + SendBoostMessage = g.SendBoostMessage, + BoostMessage = g.BoostMessage, + BoostMessageDeleteAfter = g.BoostMessageDeleteAfter, + BoostMessageChannelId = g.BoostMessageChannelId + }; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/ImageOnlyChannelService.cs b/src/EllieBot/Modules/Administration/ImageOnlyChannelService.cs new file mode 100644 index 0000000..1b45cc6 --- /dev/null +++ b/src/EllieBot/Modules/Administration/ImageOnlyChannelService.cs @@ -0,0 +1,235 @@ +#nullable disable +using LinqToDB; +using Microsoft.Extensions.Caching.Memory; +using EllieBot.Common.ModuleBehaviors; +using System.Net; +using System.Threading.Channels; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public sealed class SomethingOnlyChannelService : IExecOnMessage +{ + public int Priority { get; } = 0; + private readonly IMemoryCache _ticketCache; + private readonly DiscordSocketClient _client; + private readonly DbService _db; + private readonly ConcurrentDictionary> _imageOnly; + private readonly ConcurrentDictionary> _linkOnly; + + private readonly Channel _deleteQueue = Channel.CreateBounded( + new BoundedChannelOptions(100) + { + FullMode = BoundedChannelFullMode.DropOldest, + SingleReader = true, + SingleWriter = false + }); + + + public SomethingOnlyChannelService(IMemoryCache ticketCache, DiscordSocketClient client, DbService db) + { + _ticketCache = ticketCache; + _client = client; + _db = db; + + using var uow = _db.GetDbContext(); + _imageOnly = uow.Set() + .Where(x => x.Type == OnlyChannelType.Image) + .ToList() + .GroupBy(x => x.GuildId) + .ToDictionary(x => x.Key, x => new ConcurrentHashSet(x.Select(y => y.ChannelId))) + .ToConcurrent(); + + _linkOnly = uow.Set() + .Where(x => x.Type == OnlyChannelType.Link) + .ToList() + .GroupBy(x => x.GuildId) + .ToDictionary(x => x.Key, x => new ConcurrentHashSet(x.Select(y => y.ChannelId))) + .ToConcurrent(); + + _ = Task.Run(DeleteQueueRunner); + + _client.ChannelDestroyed += ClientOnChannelDestroyed; + } + + private async Task ClientOnChannelDestroyed(SocketChannel ch) + { + if (ch is not IGuildChannel gch) + return; + + if (_imageOnly.TryGetValue(gch.GuildId, out var channels) && channels.TryRemove(ch.Id)) + await ToggleImageOnlyChannelAsync(gch.GuildId, ch.Id, true); + } + + private async Task DeleteQueueRunner() + { + while (true) + { + var toDelete = await _deleteQueue.Reader.ReadAsync(); + try + { + await toDelete.DeleteAsync(); + await Task.Delay(1000); + } + catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden) + { + // disable if bot can't delete messages in the channel + await ToggleImageOnlyChannelAsync(((ITextChannel)toDelete.Channel).GuildId, toDelete.Channel.Id, true); + } + } + } + + public async Task ToggleImageOnlyChannelAsync(ulong guildId, ulong channelId, bool forceDisable = false) + { + var newState = false; + await using var uow = _db.GetDbContext(); + if (forceDisable || (_imageOnly.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId))) + { + await uow.Set().DeleteAsync(x => x.ChannelId == channelId && x.Type == OnlyChannelType.Image); + } + else + { + await uow.Set().DeleteAsync(x => x.ChannelId == channelId); + uow.Set().Add(new() + { + GuildId = guildId, + ChannelId = channelId, + Type = OnlyChannelType.Image + }); + + if (_linkOnly.TryGetValue(guildId, out var chs)) + chs.TryRemove(channelId); + + channels = _imageOnly.GetOrAdd(guildId, new ConcurrentHashSet()); + channels.Add(channelId); + newState = true; + } + + await uow.SaveChangesAsync(); + return newState; + } + + public async Task ToggleLinkOnlyChannelAsync(ulong guildId, ulong channelId, bool forceDisable = false) + { + var newState = false; + await using var uow = _db.GetDbContext(); + if (forceDisable || (_linkOnly.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId))) + { + await uow.Set().DeleteAsync(x => x.ChannelId == channelId && x.Type == OnlyChannelType.Link); + } + else + { + await uow.Set().DeleteAsync(x => x.ChannelId == channelId); + uow.Set().Add(new() + { + GuildId = guildId, + ChannelId = channelId, + Type = OnlyChannelType.Link + }); + + if (_imageOnly.TryGetValue(guildId, out var chs)) + chs.TryRemove(channelId); + + channels = _linkOnly.GetOrAdd(guildId, new ConcurrentHashSet()); + channels.Add(channelId); + newState = true; + } + + await uow.SaveChangesAsync(); + return newState; + } + + public async Task ExecOnMessageAsync(IGuild guild, IUserMessage msg) + { + if (msg.Channel is not ITextChannel tch) + return false; + + if (_imageOnly.TryGetValue(tch.GuildId, out var chs) && chs.Contains(msg.Channel.Id)) + return await HandleOnlyChannel(tch, msg, OnlyChannelType.Image); + + if (_linkOnly.TryGetValue(tch.GuildId, out chs) && chs.Contains(msg.Channel.Id)) + return await HandleOnlyChannel(tch, msg, OnlyChannelType.Link); + + return false; + } + + private async Task HandleOnlyChannel(ITextChannel tch, IUserMessage msg, OnlyChannelType type) + { + if (type == OnlyChannelType.Image) + { + if (msg.Attachments.Any(x => x is { Height: > 0, Width: > 0 })) + return false; + } + else + { + if (msg.Content.TryGetUrlPath(out _)) + return false; + } + + var user = await tch.Guild.GetUserAsync(msg.Author.Id) + ?? await _client.Rest.GetGuildUserAsync(tch.GuildId, msg.Author.Id); + + if (user is null) + return false; + + // ignore owner and admin + if (user.Id == tch.Guild.OwnerId || user.GuildPermissions.Administrator) + { + Log.Information("{Type}-Only Channel: Ignoring owner or admin ({ChannelId})", type, msg.Channel.Id); + return false; + } + + // ignore users higher in hierarchy + var botUser = await tch.Guild.GetCurrentUserAsync(); + if (user.GetRoles().Max(x => x.Position) >= botUser.GetRoles().Max(x => x.Position)) + return false; + + if (!botUser.GetPermissions(tch).ManageChannel) + { + if(type == OnlyChannelType.Image) + await ToggleImageOnlyChannelAsync(tch.GuildId, tch.Id, true); + else + await ToggleImageOnlyChannelAsync(tch.GuildId, tch.Id, true); + + return false; + } + + var shouldLock = AddUserTicket(tch.GuildId, msg.Author.Id); + if (shouldLock) + { + await tch.AddPermissionOverwriteAsync(msg.Author, new(sendMessages: PermValue.Deny)); + Log.Warning("{Type}-Only Channel: User {User} [{UserId}] has been banned from typing in the channel [{ChannelId}]", + type, + msg.Author, + msg.Author.Id, + msg.Channel.Id); + } + + try + { + await _deleteQueue.Writer.WriteAsync(msg); + } + catch (Exception ex) + { + Log.Error(ex, "Error deleting message {MessageId} in image-only channel {ChannelId}", msg.Id, tch.Id); + } + + return true; + } + + private bool AddUserTicket(ulong guildId, ulong userId) + { + var old = _ticketCache.GetOrCreate($"{guildId}_{userId}", + entry => + { + entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1); + return 0; + }); + + _ticketCache.Set($"{guildId}_{userId}", ++old); + + // if this is the third time that the user posts a + // non image in an image-only channel on this server + return old > 2; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/LocalizationCommands.cs b/src/EllieBot/Modules/Administration/LocalizationCommands.cs new file mode 100644 index 0000000..9715d0b --- /dev/null +++ b/src/EllieBot/Modules/Administration/LocalizationCommands.cs @@ -0,0 +1,264 @@ +#nullable disable +using System.Globalization; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class LocalizationCommands : EllieModule + { + private static readonly IReadOnlyDictionary _supportedLocales = new Dictionary + { + { "ar", "العربية" }, + { "zh-TW", "繁體中文, 台灣" }, + { "zh-CN", "简体中文, 中华人民共和国" }, + { "nl-NL", "Nederlands, Nederland" }, + { "en-US", "English, United States" }, + { "fr-FR", "Français, France" }, + { "cs-CZ", "Čeština, Česká republika" }, + { "da-DK", "Dansk, Danmark" }, + { "de-DE", "Deutsch, Deutschland" }, + { "he-IL", "עברית, ישראל" }, + { "hu-HU", "Magyar, Magyarország" }, + { "id-ID", "Bahasa Indonesia, Indonesia" }, + { "it-IT", "Italiano, Italia" }, + { "ja-JP", "日本語, 日本" }, + { "ko-KR", "한국어, 대한민국" }, + { "nb-NO", "Norsk, Norge" }, + { "pl-PL", "Polski, Polska" }, + { "pt-BR", "Português Brasileiro, Brasil" }, + { "ro-RO", "Română, România" }, + { "ru-RU", "Русский, Россия" }, + { "sr-Cyrl-RS", "Српски, Србија" }, + { "es-ES", "Español, España" }, + { "sv-SE", "Svenska, Sverige" }, + { "tr-TR", "Türkçe, Türkiye" }, + { "ts-TS", "Tsundere, You Baka" }, + { "uk-UA", "Українська, Україна" } + }; + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public async Task LanguageSet() + => await Response().Confirm(strs.lang_set_show(Format.Bold(Culture.ToString()), + Format.Bold(Culture.NativeName))).SendAsync(); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(1)] + public async Task LanguageSet(string name) + { + try + { + CultureInfo ci; + if (name.Trim().ToLowerInvariant() == "default") + { + _localization.RemoveGuildCulture(ctx.Guild); + ci = _localization.DefaultCultureInfo; + } + else + { + ci = new CultureInfo(name); + if (!_supportedLocales.ContainsKey(ci.Name)) + { + await LanguagesList(); + return; + } + + _localization.SetGuildCulture(ctx.Guild, ci); + } + + var nativeName = ci.NativeName; + if (ci.Name == "ts-TS") + nativeName = _supportedLocales[ci.Name]; + await Response().Confirm(strs.lang_set(Format.Bold(ci.ToString()), Format.Bold(nativeName))).SendAsync(); + } + catch (Exception) + { + await Response().Error(strs.lang_set_fail).SendAsync(); + } + } + + [Cmd] + public async Task LanguageSetDefault() + { + var cul = _localization.DefaultCultureInfo; + await Response().Error(strs.lang_set_bot_show(cul, cul.NativeName)).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task LanguageSetDefault(string name) + { + try + { + CultureInfo ci; + if (name.Trim().ToLowerInvariant() == "default") + { + _localization.ResetDefaultCulture(); + ci = _localization.DefaultCultureInfo; + } + else + { + ci = new CultureInfo(name); + if (!_supportedLocales.ContainsKey(ci.Name)) + { + await LanguagesList(); + return; + } + _localization.SetDefaultCulture(ci); + } + + await Response().Confirm(strs.lang_set_bot(Format.Bold(ci.ToString()), + Format.Bold(ci.NativeName))).SendAsync(); + } + catch (Exception) + { + await Response().Error(strs.lang_set_fail).SendAsync(); + } + } + + [Cmd] + public async Task LanguagesList() + => await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.lang_list)) + .WithDescription(string.Join("\n", + _supportedLocales.Select( + x => $"{Format.Code(x.Key),-10} => {x.Value}")))).SendAsync(); + } +} +/* list of language codes for reference. + * taken from https://github.com/dotnet/coreclr/blob/ee5862c6a257e60e263537d975ab6c513179d47f/src/mscorlib/src/System/Globalization/CultureData.cs#L192 + { "029", "en-029" }, + { "AE", "ar-AE" }, + { "AF", "prs-AF" }, + { "AL", "sq-AL" }, + { "AM", "hy-AM" }, + { "AR", "es-AR" }, + { "AT", "de-AT" }, + { "AU", "en-AU" }, + { "AZ", "az-Cyrl-AZ" }, + { "BA", "bs-Latn-BA" }, + { "BD", "bn-BD" }, + { "BE", "nl-BE" }, + { "BG", "bg-BG" }, + { "BH", "ar-BH" }, + { "BN", "ms-BN" }, + { "BO", "es-BO" }, + { "BR", "pt-BR" }, + { "BY", "be-BY" }, + { "BZ", "en-BZ" }, + { "CA", "en-CA" }, + { "CH", "it-CH" }, + { "CL", "es-CL" }, + { "CN", "zh-CN" }, + { "CO", "es-CO" }, + { "CR", "es-CR" }, + { "CS", "sr-Cyrl-CS" }, + { "CZ", "cs-CZ" }, + { "DE", "de-DE" }, + { "DK", "da-DK" }, + { "DO", "es-DO" }, + { "DZ", "ar-DZ" }, + { "EC", "es-EC" }, + { "EE", "et-EE" }, + { "EG", "ar-EG" }, + { "ES", "es-ES" }, + { "ET", "am-ET" }, + { "FI", "fi-FI" }, + { "FO", "fo-FO" }, + { "FR", "fr-FR" }, + { "GB", "en-GB" }, + { "GE", "ka-GE" }, + { "GL", "kl-GL" }, + { "GR", "el-GR" }, + { "GT", "es-GT" }, + { "HK", "zh-HK" }, + { "HN", "es-HN" }, + { "HR", "hr-HR" }, + { "HU", "hu-HU" }, + { "ID", "id-ID" }, + { "IE", "en-IE" }, + { "IL", "he-IL" }, + { "IN", "hi-IN" }, + { "IQ", "ar-IQ" }, + { "IR", "fa-IR" }, + { "IS", "is-IS" }, + { "IT", "it-IT" }, + { "IV", "" }, + { "JM", "en-JM" }, + { "JO", "ar-JO" }, + { "JP", "ja-JP" }, + { "KE", "sw-KE" }, + { "KG", "ky-KG" }, + { "KH", "km-KH" }, + { "KR", "ko-KR" }, + { "KW", "ar-KW" }, + { "KZ", "kk-KZ" }, + { "LA", "lo-LA" }, + { "LB", "ar-LB" }, + { "LI", "de-LI" }, + { "LK", "si-LK" }, + { "LT", "lt-LT" }, + { "LU", "lb-LU" }, + { "LV", "lv-LV" }, + { "LY", "ar-LY" }, + { "MA", "ar-MA" }, + { "MC", "fr-MC" }, + { "ME", "sr-Latn-ME" }, + { "MK", "mk-MK" }, + { "MN", "mn-MN" }, + { "MO", "zh-MO" }, + { "MT", "mt-MT" }, + { "MV", "dv-MV" }, + { "MX", "es-MX" }, + { "MY", "ms-MY" }, + { "NG", "ig-NG" }, + { "NI", "es-NI" }, + { "NL", "nl-NL" }, + { "NO", "nn-NO" }, + { "NP", "ne-NP" }, + { "NZ", "en-NZ" }, + { "OM", "ar-OM" }, + { "PA", "es-PA" }, + { "PE", "es-PE" }, + { "PH", "en-PH" }, + { "PK", "ur-PK" }, + { "PL", "pl-PL" }, + { "PR", "es-PR" }, + { "PT", "pt-PT" }, + { "PY", "es-PY" }, + { "QA", "ar-QA" }, + { "RO", "ro-RO" }, + { "RS", "sr-Latn-RS" }, + { "RU", "ru-RU" }, + { "RW", "rw-RW" }, + { "SA", "ar-SA" }, + { "SE", "sv-SE" }, + { "SG", "zh-SG" }, + { "SI", "sl-SI" }, + { "SK", "sk-SK" }, + { "SN", "wo-SN" }, + { "SV", "es-SV" }, + { "SY", "ar-SY" }, + { "TH", "th-TH" }, + { "TJ", "tg-Cyrl-TJ" }, + { "TM", "tk-TM" }, + { "TN", "ar-TN" }, + { "TR", "tr-TR" }, + { "TT", "en-TT" }, + { "TW", "zh-TW" }, + { "UA", "uk-UA" }, + { "US", "en-US" }, + { "UY", "es-UY" }, + { "UZ", "uz-Cyrl-UZ" }, + { "VE", "es-VE" }, + { "VN", "vi-VN" }, + { "YE", "ar-YE" }, + { "ZA", "af-ZA" }, + { "ZW", "en-ZW" } + */ \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Mute/MuteCommands.cs b/src/EllieBot/Modules/Administration/Mute/MuteCommands.cs new file mode 100644 index 0000000..94e797a --- /dev/null +++ b/src/EllieBot/Modules/Administration/Mute/MuteCommands.cs @@ -0,0 +1,231 @@ +#nullable disable +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class MuteCommands : EllieModule + { + private async Task VerifyMutePermissions(IGuildUser runnerUser, IGuildUser targetUser) + { + var runnerUserRoles = runnerUser.GetRoles(); + var targetUserRoles = targetUser.GetRoles(); + if (runnerUser.Id != ctx.Guild.OwnerId + && runnerUserRoles.Max(x => x.Position) <= targetUserRoles.Max(x => x.Position)) + { + await Response().Error(strs.mute_perms).SendAsync(); + return false; + } + + return true; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + public async Task MuteRole([Leftover] IRole role = null) + { + if (role is null) + { + var muteRole = await _service.GetMuteRole(ctx.Guild); + await Response().Confirm(strs.mute_role(Format.Code(muteRole.Name))).SendAsync(); + return; + } + + if (ctx.User.Id != ctx.Guild.OwnerId + && role.Position >= ((SocketGuildUser)ctx.User).Roles.Max(x => x.Position)) + { + await Response().Error(strs.insuf_perms_u).SendAsync(); + return; + } + + await _service.SetMuteRoleAsync(ctx.Guild.Id, role.Name); + + await Response().Confirm(strs.mute_role_set).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)] + [Priority(0)] + public async Task Mute(IGuildUser target, [Leftover] string reason = "") + { + try + { + if (!await VerifyMutePermissions((IGuildUser)ctx.User, target)) + return; + + await _service.MuteUser(target, ctx.User, reason: reason); + await Response().Confirm(strs.user_muted(Format.Bold(target.ToString()))).SendAsync(); + } + catch (Exception ex) + { + Log.Warning(ex, "Exception in the mute command"); + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)] + [Priority(1)] + public async Task Mute(StoopidTime time, IGuildUser user, [Leftover] string reason = "") + { + if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49)) + return; + try + { + if (!await VerifyMutePermissions((IGuildUser)ctx.User, user)) + return; + + await _service.TimedMute(user, ctx.User, time.Time, reason: reason); + await Response().Confirm(strs.user_muted_time(Format.Bold(user.ToString()), + (int)time.Time.TotalMinutes)).SendAsync(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in mute command"); + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)] + public async Task Unmute(IGuildUser user, [Leftover] string reason = "") + { + try + { + await _service.UnmuteUser(user.GuildId, user.Id, ctx.User, reason: reason); + await Response().Confirm(strs.user_unmuted(Format.Bold(user.ToString()))).SendAsync(); + } + catch + { + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [Priority(0)] + public async Task ChatMute(IGuildUser user, [Leftover] string reason = "") + { + try + { + if (!await VerifyMutePermissions((IGuildUser)ctx.User, user)) + return; + + await _service.MuteUser(user, ctx.User, MuteType.Chat, reason); + await Response().Confirm(strs.user_chat_mute(Format.Bold(user.ToString()))).SendAsync(); + } + catch (Exception ex) + { + Log.Warning(ex, "Exception in the chatmute command"); + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [Priority(1)] + public async Task ChatMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "") + { + if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49)) + return; + try + { + if (!await VerifyMutePermissions((IGuildUser)ctx.User, user)) + return; + + await _service.TimedMute(user, ctx.User, time.Time, MuteType.Chat, reason); + await Response().Confirm(strs.user_chat_mute_time(Format.Bold(user.ToString()), + (int)time.Time.TotalMinutes)).SendAsync(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in chatmute command"); + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + public async Task ChatUnmute(IGuildUser user, [Leftover] string reason = "") + { + try + { + await _service.UnmuteUser(user.Guild.Id, user.Id, ctx.User, MuteType.Chat, reason); + await Response().Confirm(strs.user_chat_unmute(Format.Bold(user.ToString()))).SendAsync(); + } + catch + { + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.MuteMembers)] + [Priority(0)] + public async Task VoiceMute(IGuildUser user, [Leftover] string reason = "") + { + try + { + if (!await VerifyMutePermissions((IGuildUser)ctx.User, user)) + return; + + await _service.MuteUser(user, ctx.User, MuteType.Voice, reason); + await Response().Confirm(strs.user_voice_mute(Format.Bold(user.ToString()))).SendAsync(); + } + catch + { + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.MuteMembers)] + [Priority(1)] + public async Task VoiceMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "") + { + if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49)) + return; + try + { + if (!await VerifyMutePermissions((IGuildUser)ctx.User, user)) + return; + + await _service.TimedMute(user, ctx.User, time.Time, MuteType.Voice, reason); + await Response().Confirm(strs.user_voice_mute_time(Format.Bold(user.ToString()), + (int)time.Time.TotalMinutes)).SendAsync(); + } + catch + { + await Response().Error(strs.mute_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.MuteMembers)] + public async Task VoiceUnmute(IGuildUser user, [Leftover] string reason = "") + { + try + { + await _service.UnmuteUser(user.GuildId, user.Id, ctx.User, MuteType.Voice, reason); + await Response().Confirm(strs.user_voice_unmute(Format.Bold(user.ToString()))).SendAsync(); + } + catch + { + await Response().Error(strs.mute_error).SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Mute/MuteService.cs b/src/EllieBot/Modules/Administration/Mute/MuteService.cs new file mode 100644 index 0000000..a3fbea3 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Mute/MuteService.cs @@ -0,0 +1,504 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public enum MuteType +{ + Voice, + Chat, + All +} + +public class MuteService : IEService +{ + public enum TimerType { Mute, Ban, AddRole } + + private static readonly OverwritePermissions _denyOverwrite = new(addReactions: PermValue.Deny, + sendMessages: PermValue.Deny, + sendMessagesInThreads: PermValue.Deny, + attachFiles: PermValue.Deny); + + public event Action UserMuted = delegate { }; + public event Action UserUnmuted = delegate { }; + + public ConcurrentDictionary GuildMuteRoles { get; } + public ConcurrentDictionary> MutedUsers { get; } + + public ConcurrentDictionary> UnTimers { get; } = new(); + + private readonly DiscordSocketClient _client; + private readonly DbService _db; + private readonly IMessageSenderService _sender; + + public MuteService(DiscordSocketClient client, DbService db, IMessageSenderService sender) + { + _client = client; + _db = db; + _sender = sender; + + using (var uow = db.GetDbContext()) + { + var guildIds = client.Guilds.Select(x => x.Id).ToList(); + var configs = uow.Set() + .AsNoTracking() + .AsSplitQuery() + .Include(x => x.MutedUsers) + .Include(x => x.UnbanTimer) + .Include(x => x.UnmuteTimers) + .Include(x => x.UnroleTimer) + .Where(x => guildIds.Contains(x.GuildId)) + .ToList(); + + GuildMuteRoles = configs.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName)) + .ToDictionary(c => c.GuildId, c => c.MuteRoleName) + .ToConcurrent(); + + MutedUsers = new(configs.ToDictionary(k => k.GuildId, + v => new ConcurrentHashSet(v.MutedUsers.Select(m => m.UserId)))); + + var max = TimeSpan.FromDays(49); + + foreach (var conf in configs) + { + foreach (var x in conf.UnmuteTimers) + { + TimeSpan after; + if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow) + after = TimeSpan.FromMinutes(2); + else + { + var unmute = x.UnmuteAt - DateTime.UtcNow; + after = unmute > max ? max : unmute; + } + + StartUn_Timer(conf.GuildId, x.UserId, after, TimerType.Mute); + } + + foreach (var x in conf.UnbanTimer) + { + TimeSpan after; + if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow) + after = TimeSpan.FromMinutes(2); + else + { + var unban = x.UnbanAt - DateTime.UtcNow; + after = unban > max ? max : unban; + } + + StartUn_Timer(conf.GuildId, x.UserId, after, TimerType.Ban); + } + + foreach (var x in conf.UnroleTimer) + { + TimeSpan after; + if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow) + after = TimeSpan.FromMinutes(2); + else + { + var unban = x.UnbanAt - DateTime.UtcNow; + after = unban > max ? max : unban; + } + + StartUn_Timer(conf.GuildId, x.UserId, after, TimerType.AddRole, x.RoleId); + } + } + + _client.UserJoined += Client_UserJoined; + } + + UserMuted += OnUserMuted; + UserUnmuted += OnUserUnmuted; + } + + private void OnUserMuted( + IGuildUser user, + IUser mod, + MuteType type, + string reason) + { + if (string.IsNullOrWhiteSpace(reason)) + return; + + _ = Task.Run(() => _sender.Response(user) + .Embed(_sender.CreateEmbed() + .WithDescription($"You've been muted in {user.Guild} server") + .AddField("Mute Type", type.ToString()) + .AddField("Moderator", mod.ToString()) + .AddField("Reason", reason)) + .SendAsync()); + } + + private void OnUserUnmuted( + IGuildUser user, + IUser mod, + MuteType type, + string reason) + { + if (string.IsNullOrWhiteSpace(reason)) + return; + + _ = Task.Run(() => _sender.Response(user) + .Embed(_sender.CreateEmbed() + .WithDescription($"You've been unmuted in {user.Guild} server") + .AddField("Unmute Type", type.ToString()) + .AddField("Moderator", mod.ToString()) + .AddField("Reason", reason)) + .SendAsync()); + } + + private Task Client_UserJoined(IGuildUser usr) + { + try + { + MutedUsers.TryGetValue(usr.Guild.Id, out var muted); + + if (muted is null || !muted.Contains(usr.Id)) + return Task.CompletedTask; + _ = Task.Run(() => MuteUser(usr, _client.CurrentUser, reason: "Sticky mute")); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in MuteService UserJoined event"); + } + + return Task.CompletedTask; + } + + public async Task SetMuteRoleAsync(ulong guildId, string name) + { + await using var uow = _db.GetDbContext(); + var config = uow.GuildConfigsForId(guildId, set => set); + config.MuteRoleName = name; + GuildMuteRoles.AddOrUpdate(guildId, name, (_, _) => name); + await uow.SaveChangesAsync(); + } + + public async Task MuteUser( + IGuildUser usr, + IUser mod, + MuteType type = MuteType.All, + string reason = "") + { + if (type == MuteType.All) + { + try { await usr.ModifyAsync(x => x.Mute = true); } + catch { } + + var muteRole = await GetMuteRole(usr.Guild); + if (!usr.RoleIds.Contains(muteRole.Id)) + await usr.AddRoleAsync(muteRole); + StopTimer(usr.GuildId, usr.Id, TimerType.Mute); + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(usr.Guild.Id, + set => set.Include(gc => gc.MutedUsers).Include(gc => gc.UnmuteTimers)); + config.MutedUsers.Add(new() + { + UserId = usr.Id + }); + if (MutedUsers.TryGetValue(usr.Guild.Id, out var muted)) + muted.Add(usr.Id); + + config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id); + + await uow.SaveChangesAsync(); + } + + UserMuted(usr, mod, MuteType.All, reason); + } + else if (type == MuteType.Voice) + { + try + { + await usr.ModifyAsync(x => x.Mute = true); + UserMuted(usr, mod, MuteType.Voice, reason); + } + catch { } + } + else if (type == MuteType.Chat) + { + await usr.AddRoleAsync(await GetMuteRole(usr.Guild)); + UserMuted(usr, mod, MuteType.Chat, reason); + } + } + + public async Task UnmuteUser( + ulong guildId, + ulong usrId, + IUser mod, + MuteType type = MuteType.All, + string reason = "") + { + var usr = _client.GetGuild(guildId)?.GetUser(usrId); + if (type == MuteType.All) + { + StopTimer(guildId, usrId, TimerType.Mute); + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(guildId, + set => set.Include(gc => gc.MutedUsers).Include(gc => gc.UnmuteTimers)); + var match = new MutedUserId + { + UserId = usrId + }; + var toRemove = config.MutedUsers.FirstOrDefault(x => x.Equals(match)); + if (toRemove is not null) + uow.Remove(toRemove); + if (MutedUsers.TryGetValue(guildId, out var muted)) + muted.TryRemove(usrId); + + config.UnmuteTimers.RemoveWhere(x => x.UserId == usrId); + + await uow.SaveChangesAsync(); + } + + if (usr is not null) + { + try { await usr.ModifyAsync(x => x.Mute = false); } + catch { } + + try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)); } + catch + { + /*ignore*/ + } + + UserUnmuted(usr, mod, MuteType.All, reason); + } + } + else if (type == MuteType.Voice) + { + if (usr is null) + return; + try + { + await usr.ModifyAsync(x => x.Mute = false); + UserUnmuted(usr, mod, MuteType.Voice, reason); + } + catch { } + } + else if (type == MuteType.Chat) + { + if (usr is null) + return; + await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)); + UserUnmuted(usr, mod, MuteType.Chat, reason); + } + } + + public async Task GetMuteRole(IGuild guild) + { + ArgumentNullException.ThrowIfNull(guild); + + const string defaultMuteRoleName = "ellie-mute"; + + var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName); + + var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName); + if (muteRole is null) + //if it doesn't exist, create it + { + try { muteRole = await guild.CreateRoleAsync(muteRoleName, isMentionable: false); } + catch + { + //if creations fails, maybe the name is not correct, find default one, if doesn't work, create default one + muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) + ?? await guild.CreateRoleAsync(defaultMuteRoleName, isMentionable: false); + } + } + + foreach (var toOverwrite in await guild.GetTextChannelsAsync()) + { + try + { + if (!toOverwrite.PermissionOverwrites.Any(x => x.TargetId == muteRole.Id + && x.TargetType == PermissionTarget.Role)) + { + await toOverwrite.AddPermissionOverwriteAsync(muteRole, _denyOverwrite); + + await Task.Delay(200); + } + } + catch + { + // ignored + } + } + + return muteRole; + } + + public async Task TimedMute( + IGuildUser user, + IUser mod, + TimeSpan after, + MuteType muteType = MuteType.All, + string reason = "") + { + await MuteUser(user, mod, muteType, reason); // mute the user. This will also remove any previous unmute timers + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(user.GuildId, set => set.Include(x => x.UnmuteTimers)); + config.UnmuteTimers.Add(new() + { + UserId = user.Id, + UnmuteAt = DateTime.UtcNow + after + }); // add teh unmute timer to the database + uow.SaveChanges(); + } + + StartUn_Timer(user.GuildId, user.Id, after, TimerType.Mute); // start the timer + } + + public async Task TimedBan( + IGuild guild, + ulong userId, + TimeSpan after, + string reason, + int pruneDays) + { + await guild.AddBanAsync(userId, pruneDays, reason); + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(guild.Id, set => set.Include(x => x.UnbanTimer)); + config.UnbanTimer.Add(new() + { + UserId = userId, + UnbanAt = DateTime.UtcNow + after + }); // add teh unmute timer to the database + await uow.SaveChangesAsync(); + } + + StartUn_Timer(guild.Id, userId, after, TimerType.Ban); // start the timer + } + + public async Task TimedRole( + IGuildUser user, + TimeSpan after, + string reason, + IRole role) + { + await user.AddRoleAsync(role); + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(user.GuildId, set => set.Include(x => x.UnroleTimer)); + config.UnroleTimer.Add(new() + { + UserId = user.Id, + UnbanAt = DateTime.UtcNow + after, + RoleId = role.Id + }); // add teh unmute timer to the database + uow.SaveChanges(); + } + + StartUn_Timer(user.GuildId, user.Id, after, TimerType.AddRole, role.Id); // start the timer + } + + public void StartUn_Timer( + ulong guildId, + ulong userId, + TimeSpan after, + TimerType type, + ulong? roleId = null) + { + //load the unmute timers for this guild + var userUnTimers = UnTimers.GetOrAdd(guildId, new ConcurrentDictionary<(ulong, TimerType), Timer>()); + + //unmute timer to be added + var toAdd = new Timer(async _ => + { + if (type == TimerType.Ban) + { + try + { + RemoveTimerFromDb(guildId, userId, type); + StopTimer(guildId, userId, type); + var guild = _client.GetGuild(guildId); // load the guild + if (guild is not null) + await guild.RemoveBanAsync(userId); + } + catch (Exception ex) + { + Log.Warning(ex, "Couldn't unban user {UserId} in guild {GuildId}", userId, guildId); + } + } + else if (type == TimerType.AddRole) + { + try + { + if (roleId is null) + return; + + RemoveTimerFromDb(guildId, userId, type); + StopTimer(guildId, userId, type); + var guild = _client.GetGuild(guildId); + var user = guild?.GetUser(userId); + var role = guild?.GetRole(roleId.Value); + if (guild is not null && user is not null && user.Roles.Contains(role)) + await user.RemoveRoleAsync(role); + } + catch (Exception ex) + { + Log.Warning(ex, "Couldn't remove role from user {UserId} in guild {GuildId}", userId, guildId); + } + } + else + { + try + { + // unmute the user, this will also remove the timer from the db + await UnmuteUser(guildId, userId, _client.CurrentUser, reason: "Timed mute expired"); + } + catch (Exception ex) + { + RemoveTimerFromDb(guildId, userId, type); // if unmute errored, just remove unmute from db + Log.Warning(ex, "Couldn't unmute user {UserId} in guild {GuildId}", userId, guildId); + } + } + }, + null, + after, + Timeout.InfiniteTimeSpan); + + //add it, or stop the old one and add this one + userUnTimers.AddOrUpdate((userId, type), + _ => toAdd, + (_, old) => + { + old.Change(Timeout.Infinite, Timeout.Infinite); + return toAdd; + }); + } + + public void StopTimer(ulong guildId, ulong userId, TimerType type) + { + if (!UnTimers.TryGetValue(guildId, out var userTimer)) + return; + + if (userTimer.TryRemove((userId, type), out var removed)) + removed.Change(Timeout.Infinite, Timeout.Infinite); + } + + private void RemoveTimerFromDb(ulong guildId, ulong userId, TimerType type) + { + using var uow = _db.GetDbContext(); + object toDelete; + if (type == TimerType.Mute) + { + var config = uow.GuildConfigsForId(guildId, set => set.Include(x => x.UnmuteTimers)); + toDelete = config.UnmuteTimers.FirstOrDefault(x => x.UserId == userId); + } + else + { + var config = uow.GuildConfigsForId(guildId, set => set.Include(x => x.UnbanTimer)); + toDelete = config.UnbanTimer.FirstOrDefault(x => x.UserId == userId); + } + + if (toDelete is not null) + uow.Remove(toDelete); + uow.SaveChanges(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs b/src/EllieBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs new file mode 100644 index 0000000..cc43b31 --- /dev/null +++ b/src/EllieBot/Modules/Administration/PermOverrides/DiscordPermOverrideCommands.cs @@ -0,0 +1,83 @@ +#nullable disable +using EllieBot.Common.TypeReaders; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class DiscordPermOverrideCommands : EllieModule + { + // override stats, it should require that the user has managessages guild permission + // .po 'stats' add user guild managemessages + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task DiscordPermOverride(CommandOrExprInfo cmd, params GuildPerm[] perms) + { + if (perms is null || perms.Length == 0) + { + await _service.RemoveOverride(ctx.Guild.Id, cmd.Name); + await Response().Confirm(strs.perm_override_reset).SendAsync(); + return; + } + + var aggregatePerms = perms.Aggregate((acc, seed) => seed | acc); + await _service.AddOverride(ctx.Guild.Id, cmd.Name, aggregatePerms); + + await Response() + .Confirm(strs.perm_override(Format.Bold(aggregatePerms.ToString()), + Format.Code(cmd.Name))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task DiscordPermOverrideReset() + { + var result = await PromptUserConfirmAsync(_sender.CreateEmbed() + .WithOkColor() + .WithDescription(GetText(strs.perm_override_all_confirm))); + + if (!result) + return; + + await _service.ClearAllOverrides(ctx.Guild.Id); + + await Response().Confirm(strs.perm_override_all).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task DiscordPermOverrideList(int page = 1) + { + if (--page < 0) + return; + + var allOverrides = await _service.GetAllOverrides(ctx.Guild.Id); + + await Response() + .Paginated() + .Items(allOverrides) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + var eb = _sender.CreateEmbed().WithTitle(GetText(strs.perm_overrides)).WithOkColor(); + + if (items.Count == 0) + eb.WithDescription(GetText(strs.perm_override_page_none)); + else + { + eb.WithDescription(items.Select(ov => $"{ov.Command} => {ov.Perm.ToString()}") + .Join("\n")); + } + + return eb; + }) + .SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateCommands.cs b/src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateCommands.cs new file mode 100644 index 0000000..bf4909e --- /dev/null +++ b/src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateCommands.cs @@ -0,0 +1,62 @@ +#nullable disable +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class PlayingRotateCommands : EllieModule + { + [Cmd] + [OwnerOnly] + public async Task RotatePlaying() + { + if (_service.ToggleRotatePlaying()) + await Response().Confirm(strs.ropl_enabled).SendAsync(); + else + await Response().Confirm(strs.ropl_disabled).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task AddPlaying(ActivityType t, [Leftover] string status) + { + await _service.AddPlaying(t, status); + + await Response().Confirm(strs.ropl_added).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task ListPlaying() + { + var statuses = _service.GetRotatingStatuses(); + + if (!statuses.Any()) + await Response().Error(strs.ropl_not_set).SendAsync(); + else + { + var i = 1; + await Response() + .Confirm(strs.ropl_list(string.Join("\n\t", + statuses.Select(rs => $"`{i++}.` *{rs.Type}* {rs.Status}")))) + .SendAsync(); + } + } + + [Cmd] + [OwnerOnly] + public async Task RemovePlaying(int index) + { + index -= 1; + + var msg = await _service.RemovePlayingAsync(index); + + if (msg is null) + return; + + await Response().Confirm(strs.reprm(msg)).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateService.cs b/src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateService.cs new file mode 100644 index 0000000..edf6843 --- /dev/null +++ b/src/EllieBot/Modules/Administration/PlayingRotate/PlayingRotateService.cs @@ -0,0 +1,109 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public sealed class PlayingRotateService : IEService, IReadyExecutor +{ + private readonly BotConfigService _bss; + private readonly SelfService _selfService; + private readonly IReplacementService _repService; + // private readonly Replacer _rep; + private readonly DbService _db; + private readonly DiscordSocketClient _client; + + public PlayingRotateService( + DiscordSocketClient client, + DbService db, + BotConfigService bss, + IEnumerable phProviders, + SelfService selfService, + IReplacementService repService) + { + _db = db; + _bss = bss; + _selfService = selfService; + _repService = repService; + _client = client; + + } + + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1)); + var index = 0; + while (await timer.WaitForNextTickAsync()) + { + try + { + if (!_bss.Data.RotateStatuses) + continue; + + IReadOnlyList rotatingStatuses; + await using (var uow = _db.GetDbContext()) + { + rotatingStatuses = uow.Set().AsNoTracking().OrderBy(x => x.Id).ToList(); + } + + if (rotatingStatuses.Count == 0) + continue; + + var playingStatus = index >= rotatingStatuses.Count + ? rotatingStatuses[index = 0] + : rotatingStatuses[index++]; + + var statusText = await _repService.ReplaceAsync(playingStatus.Status, new (client: _client)); + await _selfService.SetGameAsync(statusText, (ActivityType)playingStatus.Type); + } + catch (Exception ex) + { + Log.Warning(ex, "Rotating playing status errored: {ErrorMessage}", ex.Message); + } + } + } + + public async Task RemovePlayingAsync(int index) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + + await using var uow = _db.GetDbContext(); + var toRemove = await uow.Set().AsQueryable().AsNoTracking().Skip(index).FirstOrDefaultAsync(); + + if (toRemove is null) + return null; + + uow.Remove(toRemove); + await uow.SaveChangesAsync(); + return toRemove.Status; + } + + public async Task AddPlaying(ActivityType activityType, string status) + { + await using var uow = _db.GetDbContext(); + var toAdd = new RotatingPlayingStatus + { + Status = status, + Type = (EllieBot.Db.DbActivityType)activityType + }; + uow.Add(toAdd); + await uow.SaveChangesAsync(); + } + + public bool ToggleRotatePlaying() + { + var enabled = false; + _bss.ModifyConfig(bs => { enabled = bs.RotateStatuses = !bs.RotateStatuses; }); + return enabled; + } + + public IReadOnlyList GetRotatingStatuses() + { + using var uow = _db.GetDbContext(); + return uow.Set().AsNoTracking().ToList(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Prefix/PrefixCommands.cs b/src/EllieBot/Modules/Administration/Prefix/PrefixCommands.cs new file mode 100644 index 0000000..3b8ea72 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Prefix/PrefixCommands.cs @@ -0,0 +1,57 @@ +#nullable disable +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class PrefixCommands : EllieModule + { + public enum Set + { + Set + } + + [Cmd] + [Priority(1)] + public async Task Prefix() + => await Response().Confirm(strs.prefix_current(Format.Code(_cmdHandler.GetPrefix(ctx.Guild)))).SendAsync(); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(0)] + public Task Prefix(Set _, [Leftover] string newPrefix) + => Prefix(newPrefix); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(0)] + public async Task Prefix([Leftover] string toSet) + { + if (string.IsNullOrWhiteSpace(prefix)) + return; + + var oldPrefix = prefix; + var newPrefix = _cmdHandler.SetPrefix(ctx.Guild, toSet); + + await Response().Confirm(strs.prefix_new(Format.Code(oldPrefix), Format.Code(newPrefix))).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task DefPrefix([Leftover] string toSet = null) + { + if (string.IsNullOrWhiteSpace(toSet)) + { + await Response().Confirm(strs.defprefix_current(_cmdHandler.GetPrefix())).SendAsync(); + return; + } + + var oldPrefix = _cmdHandler.GetPrefix(); + var newPrefix = _cmdHandler.SetDefaultPrefix(toSet); + + await Response().Confirm(strs.defprefix_new(Format.Code(oldPrefix), Format.Code(newPrefix))).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Protection/ProtectionCommands.cs b/src/EllieBot/Modules/Administration/Protection/ProtectionCommands.cs new file mode 100644 index 0000000..64648b8 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Protection/ProtectionCommands.cs @@ -0,0 +1,292 @@ +#nullable disable +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Modules.Administration.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class ProtectionCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task AntiAlt() + { + if (await _service.TryStopAntiAlt(ctx.Guild.Id)) + { + await Response().Confirm(strs.prot_disable("Anti-Alt")).SendAsync(); + return; + } + + await Response().Confirm(strs.protection_not_running("Anti-Alt")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task AntiAlt( + StoopidTime minAge, + PunishmentAction action, + [Leftover] StoopidTime punishTime = null) + { + var minAgeMinutes = (int)minAge.Time.TotalMinutes; + var punishTimeMinutes = (int?)punishTime?.Time.TotalMinutes ?? 0; + + if (minAgeMinutes < 1 || punishTimeMinutes < 0) + return; + + var minutes = (int?)punishTime?.Time.TotalMinutes ?? 0; + if (action is PunishmentAction.TimeOut && minutes < 1) + minutes = 1; + + await _service.StartAntiAltAsync(ctx.Guild.Id, + minAgeMinutes, + action, + minutes); + + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task AntiAlt(StoopidTime minAge, PunishmentAction action, [Leftover] IRole role) + { + var minAgeMinutes = (int)minAge.Time.TotalMinutes; + + if (minAgeMinutes < 1) + return; + + if (action == PunishmentAction.TimeOut) + return; + + await _service.StartAntiAltAsync(ctx.Guild.Id, minAgeMinutes, action, roleId: role.Id); + + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public Task AntiRaid() + { + if (_service.TryStopAntiRaid(ctx.Guild.Id)) + return Response().Confirm(strs.prot_disable("Anti-Raid")).SendAsync(); + return Response().Pending(strs.protection_not_running("Anti-Raid")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(1)] + public Task AntiRaid( + int userThreshold, + int seconds, + PunishmentAction action, + [Leftover] StoopidTime punishTime) + => InternalAntiRaid(userThreshold, seconds, action, punishTime); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(2)] + public Task AntiRaid(int userThreshold, int seconds, PunishmentAction action) + => InternalAntiRaid(userThreshold, seconds, action); + + private async Task InternalAntiRaid( + int userThreshold, + int seconds = 10, + PunishmentAction action = PunishmentAction.Mute, + StoopidTime punishTime = null) + { + if (action == PunishmentAction.AddRole) + { + await Response().Error(strs.punishment_unsupported(action)).SendAsync(); + return; + } + + if (userThreshold is < 2 or > 30) + { + await Response().Error(strs.raid_cnt(2, 30)).SendAsync(); + return; + } + + if (seconds is < 2 or > 300) + { + await Response().Error(strs.raid_time(2, 300)).SendAsync(); + return; + } + + if (punishTime is not null) + { + if (!_service.IsDurationAllowed(action)) + await Response().Error(strs.prot_cant_use_time).SendAsync(); + } + + var time = (int?)punishTime?.Time.TotalMinutes ?? 0; + if (time is < 0 or > 60 * 24) + return; + + if (action is PunishmentAction.TimeOut && time < 1) + return; + + var stats = await _service.StartAntiRaidAsync(ctx.Guild.Id, userThreshold, seconds, action, time); + + if (stats is null) + return; + + await Response() + .Confirm(GetText(strs.prot_enable("Anti-Raid")), + $"{ctx.User.Mention} {GetAntiRaidString(stats)}") + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public Task AntiSpam() + { + if (_service.TryStopAntiSpam(ctx.Guild.Id)) + return Response().Confirm(strs.prot_disable("Anti-Spam")).SendAsync(); + return Response().Pending(strs.protection_not_running("Anti-Spam")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(0)] + public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] IRole role) + { + if (action != PunishmentAction.AddRole) + return Task.CompletedTask; + + return InternalAntiSpam(messageCount, action, null, role); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(1)] + public Task AntiSpam(int messageCount, PunishmentAction action, [Leftover] StoopidTime punishTime) + => InternalAntiSpam(messageCount, action, punishTime); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(2)] + public Task AntiSpam(int messageCount, PunishmentAction action) + => InternalAntiSpam(messageCount, action); + + private async Task InternalAntiSpam( + int messageCount, + PunishmentAction action, + StoopidTime timeData = null, + IRole role = null) + { + if (messageCount is < 2 or > 10) + return; + + if (timeData is not null) + { + if (!_service.IsDurationAllowed(action)) + await Response().Error(strs.prot_cant_use_time).SendAsync(); + } + + var time = (int?)timeData?.Time.TotalMinutes ?? 0; + if (time is < 0 or > 60 * 24) + return; + + if (action is PunishmentAction.TimeOut && time < 1) + return; + + var stats = await _service.StartAntiSpamAsync(ctx.Guild.Id, messageCount, action, time, role?.Id); + + await Response() + .Confirm(GetText(strs.prot_enable("Anti-Spam")), + $"{ctx.User.Mention} {GetAntiSpamString(stats)}") + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task AntispamIgnore() + { + var added = await _service.AntiSpamIgnoreAsync(ctx.Guild.Id, ctx.Channel.Id); + + if (added is null) + { + await Response().Error(strs.protection_not_running("Anti-Spam")).SendAsync(); + return; + } + + if (added.Value) + await Response().Confirm(strs.spam_ignore("Anti-Spam")).SendAsync(); + else + await Response().Confirm(strs.spam_not_ignore("Anti-Spam")).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AntiList() + { + var (spam, raid, alt) = _service.GetAntiStats(ctx.Guild.Id); + + if (spam is null && raid is null && alt is null) + { + await Response().Confirm(strs.prot_none).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.prot_active)); + + if (spam is not null) + embed.AddField("Anti-Spam", GetAntiSpamString(spam).TrimTo(1024), true); + + if (raid is not null) + embed.AddField("Anti-Raid", GetAntiRaidString(raid).TrimTo(1024), true); + + if (alt is not null) + embed.AddField("Anti-Alt", GetAntiAltString(alt), true); + + await Response().Embed(embed).SendAsync(); + } + + private string GetAntiAltString(AntiAltStats alt) + => GetText(strs.anti_alt_status(Format.Bold(alt.MinAge.ToString(@"dd\d\ hh\h\ mm\m\ ")), + Format.Bold(alt.Action.ToString()), + Format.Bold(alt.Counter.ToString()))); + + private string GetAntiSpamString(AntiSpamStats stats) + { + var settings = stats.AntiSpamSettings; + var ignoredString = string.Join(", ", settings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>")); + + if (string.IsNullOrWhiteSpace(ignoredString)) + ignoredString = "none"; + + var add = string.Empty; + if (settings.MuteTime > 0) + add = $" ({TimeSpan.FromMinutes(settings.MuteTime):hh\\hmm\\m})"; + + return GetText(strs.spam_stats(Format.Bold(settings.MessageThreshold.ToString()), + Format.Bold(settings.Action + add), + ignoredString)); + } + + private string GetAntiRaidString(AntiRaidStats stats) + { + var actionString = Format.Bold(stats.AntiRaidSettings.Action.ToString()); + + if (stats.AntiRaidSettings.PunishDuration > 0) + actionString += $" **({TimeSpan.FromMinutes(stats.AntiRaidSettings.PunishDuration):hh\\hmm\\m})**"; + + return GetText(strs.raid_stats(Format.Bold(stats.AntiRaidSettings.UserThreshold.ToString()), + Format.Bold(stats.AntiRaidSettings.Seconds.ToString()), + actionString)); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Protection/ProtectionService.cs b/src/EllieBot/Modules/Administration/Protection/ProtectionService.cs new file mode 100644 index 0000000..c28d3c4 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Protection/ProtectionService.cs @@ -0,0 +1,499 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; +using System.Threading.Channels; + +namespace EllieBot.Modules.Administration.Services; + +public class ProtectionService : IEService +{ + public event Func OnAntiProtectionTriggered = delegate + { + return Task.CompletedTask; + }; + + private readonly ConcurrentDictionary _antiRaidGuilds = new(); + + private readonly ConcurrentDictionary _antiSpamGuilds = new(); + + private readonly ConcurrentDictionary _antiAltGuilds = new(); + + private readonly DiscordSocketClient _client; + private readonly MuteService _mute; + private readonly DbService _db; + private readonly UserPunishService _punishService; + + private readonly Channel _punishUserQueue = + Channel.CreateUnbounded(new() + { + SingleReader = true, + SingleWriter = false + }); + + public ProtectionService( + DiscordSocketClient client, + IBot bot, + MuteService mute, + DbService db, + UserPunishService punishService) + { + _client = client; + _mute = mute; + _db = db; + _punishService = punishService; + + var ids = client.GetGuildIds(); + using (var uow = db.GetDbContext()) + { + var configs = uow.Set() + .AsQueryable() + .Include(x => x.AntiRaidSetting) + .Include(x => x.AntiSpamSetting) + .ThenInclude(x => x.IgnoredChannels) + .Include(x => x.AntiAltSetting) + .Where(x => ids.Contains(x.GuildId)) + .ToList(); + + foreach (var gc in configs) + Initialize(gc); + } + + _client.MessageReceived += HandleAntiSpam; + _client.UserJoined += HandleUserJoined; + + bot.JoinedGuild += _bot_JoinedGuild; + _client.LeftGuild += _client_LeftGuild; + + _ = Task.Run(RunQueue); + } + + private async Task RunQueue() + { + while (true) + { + var item = await _punishUserQueue.Reader.ReadAsync(); + + var muteTime = item.MuteTime; + var gu = item.User; + try + { + await _punishService.ApplyPunishment(gu.Guild, + gu, + _client.CurrentUser, + item.Action, + muteTime, + item.RoleId, + $"{item.Type} Protection"); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in punish queue: {Message}", ex.Message); + } + finally + { + await Task.Delay(1000); + } + } + } + + private Task _client_LeftGuild(SocketGuild guild) + { + _ = Task.Run(async () => + { + TryStopAntiRaid(guild.Id); + TryStopAntiSpam(guild.Id); + await TryStopAntiAlt(guild.Id); + }); + return Task.CompletedTask; + } + + private Task _bot_JoinedGuild(GuildConfig gc) + { + using var uow = _db.GetDbContext(); + var gcWithData = uow.GuildConfigsForId(gc.GuildId, + set => set.Include(x => x.AntiRaidSetting) + .Include(x => x.AntiAltSetting) + .Include(x => x.AntiSpamSetting) + .ThenInclude(x => x.IgnoredChannels)); + + Initialize(gcWithData); + return Task.CompletedTask; + } + + private void Initialize(GuildConfig gc) + { + var raid = gc.AntiRaidSetting; + var spam = gc.AntiSpamSetting; + + if (raid is not null) + { + var raidStats = new AntiRaidStats + { + AntiRaidSettings = raid + }; + _antiRaidGuilds[gc.GuildId] = raidStats; + } + + if (spam is not null) + { + _antiSpamGuilds[gc.GuildId] = new() + { + AntiSpamSettings = spam + }; + } + + var alt = gc.AntiAltSetting; + if (alt is not null) + _antiAltGuilds[gc.GuildId] = new(alt); + } + + private Task HandleUserJoined(SocketGuildUser user) + { + if (user.IsBot) + return Task.CompletedTask; + + _antiRaidGuilds.TryGetValue(user.Guild.Id, out var maybeStats); + _antiAltGuilds.TryGetValue(user.Guild.Id, out var maybeAlts); + + if (maybeStats is null && maybeAlts is null) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + if (maybeAlts is { } alts) + { + if (user.CreatedAt != default) + { + var diff = DateTime.UtcNow - user.CreatedAt.UtcDateTime; + if (diff < alts.MinAge) + { + alts.Increment(); + + await PunishUsers(alts.Action, + ProtectionType.Alting, + alts.ActionDurationMinutes, + alts.RoleId, + user); + + return; + } + } + } + + try + { + if (maybeStats is not { } stats || !stats.RaidUsers.Add(user)) + return; + + ++stats.UsersCount; + + if (stats.UsersCount >= stats.AntiRaidSettings.UserThreshold) + { + var users = stats.RaidUsers.ToArray(); + stats.RaidUsers.Clear(); + var settings = stats.AntiRaidSettings; + + await PunishUsers(settings.Action, ProtectionType.Raiding, settings.PunishDuration, null, users); + } + + await Task.Delay(1000 * stats.AntiRaidSettings.Seconds); + + stats.RaidUsers.TryRemove(user); + --stats.UsersCount; + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task HandleAntiSpam(SocketMessage arg) + { + if (arg is not SocketUserMessage msg || msg.Author.IsBot) + return Task.CompletedTask; + + if (msg.Channel is not ITextChannel channel) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + try + { + if (!_antiSpamGuilds.TryGetValue(channel.Guild.Id, out var spamSettings) + || spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new() + { + ChannelId = channel.Id + })) + return; + + var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, + _ => new(msg), + (_, old) => + { + old.ApplyNextMessage(msg); + return old; + }); + + if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold) + { + if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) + { + var settings = spamSettings.AntiSpamSettings; + await PunishUsers(settings.Action, + ProtectionType.Spamming, + settings.MuteTime, + settings.RoleId, + (IGuildUser)msg.Author); + } + } + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private async Task PunishUsers( + PunishmentAction action, + ProtectionType pt, + int muteTime, + ulong? roleId, + params IGuildUser[] gus) + { + Log.Information("[{PunishType}] - Punishing [{Count}] users with [{PunishAction}] in {GuildName} guild", + pt, + gus.Length, + action, + gus[0].Guild.Name); + + foreach (var gu in gus) + { + await _punishUserQueue.Writer.WriteAsync(new() + { + Action = action, + Type = pt, + User = gu, + MuteTime = muteTime, + RoleId = roleId + }); + } + + _ = OnAntiProtectionTriggered(action, pt, gus); + } + + public async Task StartAntiRaidAsync( + ulong guildId, + int userThreshold, + int seconds, + PunishmentAction action, + int minutesDuration) + { + var g = _client.GetGuild(guildId); + await _mute.GetMuteRole(g); + + if (action == PunishmentAction.AddRole) + return null; + + if (!IsDurationAllowed(action)) + minutesDuration = 0; + + var stats = new AntiRaidStats + { + AntiRaidSettings = new() + { + Action = action, + Seconds = seconds, + UserThreshold = userThreshold, + PunishDuration = minutesDuration + } + }; + + _antiRaidGuilds.AddOrUpdate(guildId, stats, (_, _) => stats); + + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiRaidSetting)); + + gc.AntiRaidSetting = stats.AntiRaidSettings; + await uow.SaveChangesAsync(); + + return stats; + } + + public bool TryStopAntiRaid(ulong guildId) + { + if (_antiRaidGuilds.TryRemove(guildId, out _)) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiRaidSetting)); + + gc.AntiRaidSetting = null; + uow.SaveChanges(); + return true; + } + + return false; + } + + public bool TryStopAntiSpam(ulong guildId) + { + if (_antiSpamGuilds.TryRemove(guildId, out _)) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, + set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels)); + + gc.AntiSpamSetting = null; + uow.SaveChanges(); + return true; + } + + return false; + } + + public async Task StartAntiSpamAsync( + ulong guildId, + int messageCount, + PunishmentAction action, + int punishDurationMinutes, + ulong? roleId) + { + var g = _client.GetGuild(guildId); + await _mute.GetMuteRole(g); + + if (!IsDurationAllowed(action)) + punishDurationMinutes = 0; + + var stats = new AntiSpamStats + { + AntiSpamSettings = new() + { + Action = action, + MessageThreshold = messageCount, + MuteTime = punishDurationMinutes, + RoleId = roleId + } + }; + + stats = _antiSpamGuilds.AddOrUpdate(guildId, + stats, + (_, old) => + { + stats.AntiSpamSettings.IgnoredChannels = old.AntiSpamSettings.IgnoredChannels; + return stats; + }); + + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiSpamSetting)); + + if (gc.AntiSpamSetting is not null) + { + gc.AntiSpamSetting.Action = stats.AntiSpamSettings.Action; + gc.AntiSpamSetting.MessageThreshold = stats.AntiSpamSettings.MessageThreshold; + gc.AntiSpamSetting.MuteTime = stats.AntiSpamSettings.MuteTime; + gc.AntiSpamSetting.RoleId = stats.AntiSpamSettings.RoleId; + } + else + gc.AntiSpamSetting = stats.AntiSpamSettings; + + await uow.SaveChangesAsync(); + return stats; + } + + public async Task AntiSpamIgnoreAsync(ulong guildId, ulong channelId) + { + var obj = new AntiSpamIgnore + { + ChannelId = channelId + }; + bool added; + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, + set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels)); + var spam = gc.AntiSpamSetting; + if (spam is null) + return null; + + if (spam.IgnoredChannels.Add(obj)) // if adding to db is successful + { + if (_antiSpamGuilds.TryGetValue(guildId, out var temp)) + temp.AntiSpamSettings.IgnoredChannels.Add(obj); // add to local cache + + added = true; + } + else + { + var toRemove = spam.IgnoredChannels.First(x => x.ChannelId == channelId); + uow.Set().Remove(toRemove); // remove from db + if (_antiSpamGuilds.TryGetValue(guildId, out var temp)) + temp.AntiSpamSettings.IgnoredChannels.Remove(toRemove); // remove from local cache + + added = false; + } + + await uow.SaveChangesAsync(); + return added; + } + + public (AntiSpamStats, AntiRaidStats, AntiAltStats) GetAntiStats(ulong guildId) + { + _antiRaidGuilds.TryGetValue(guildId, out var antiRaidStats); + _antiSpamGuilds.TryGetValue(guildId, out var antiSpamStats); + _antiAltGuilds.TryGetValue(guildId, out var antiAltStats); + + return (antiSpamStats, antiRaidStats, antiAltStats); + } + + public bool IsDurationAllowed(PunishmentAction action) + { + switch (action) + { + case PunishmentAction.Ban: + case PunishmentAction.Mute: + case PunishmentAction.ChatMute: + case PunishmentAction.VoiceMute: + case PunishmentAction.AddRole: + case PunishmentAction.TimeOut: + return true; + default: + return false; + } + } + + public async Task StartAntiAltAsync( + ulong guildId, + int minAgeMinutes, + PunishmentAction action, + int actionDurationMinutes = 0, + ulong? roleId = null) + { + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiAltSetting)); + gc.AntiAltSetting = new() + { + Action = action, + ActionDurationMinutes = actionDurationMinutes, + MinAge = TimeSpan.FromMinutes(minAgeMinutes), + RoleId = roleId + }; + + await uow.SaveChangesAsync(); + _antiAltGuilds[guildId] = new(gc.AntiAltSetting); + } + + public async Task TryStopAntiAlt(ulong guildId) + { + if (!_antiAltGuilds.TryRemove(guildId, out _)) + return false; + + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.AntiAltSetting)); + gc.AntiAltSetting = null; + await uow.SaveChangesAsync(); + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Protection/ProtectionStats.cs b/src/EllieBot/Modules/Administration/Protection/ProtectionStats.cs new file mode 100644 index 0000000..f45db4e --- /dev/null +++ b/src/EllieBot/Modules/Administration/Protection/ProtectionStats.cs @@ -0,0 +1,52 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public enum ProtectionType +{ + Raiding, + Spamming, + Alting +} + +public class AntiRaidStats +{ + public AntiRaidSetting AntiRaidSettings { get; set; } + public int UsersCount { get; set; } + public ConcurrentHashSet RaidUsers { get; set; } = new(); +} + +public class AntiSpamStats +{ + public AntiSpamSetting AntiSpamSettings { get; set; } + public ConcurrentDictionary UserStats { get; set; } = new(); +} + +public class AntiAltStats +{ + public PunishmentAction Action + => _setting.Action; + + public int ActionDurationMinutes + => _setting.ActionDurationMinutes; + + public ulong? RoleId + => _setting.RoleId; + + public TimeSpan MinAge + => _setting.MinAge; + + public int Counter + => counter; + + private readonly AntiAltSetting _setting; + + private int counter; + + public AntiAltStats(AntiAltSetting setting) + => _setting = setting; + + public void Increment() + => Interlocked.Increment(ref counter); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Protection/PunishQueueItem.cs b/src/EllieBot/Modules/Administration/Protection/PunishQueueItem.cs new file mode 100644 index 0000000..9cff02e --- /dev/null +++ b/src/EllieBot/Modules/Administration/Protection/PunishQueueItem.cs @@ -0,0 +1,13 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public class PunishQueueItem +{ + public PunishmentAction Action { get; set; } + public ProtectionType Type { get; set; } + public int MuteTime { get; set; } + public ulong? RoleId { get; set; } + public IGuildUser User { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Protection/UserSpamStats.cs b/src/EllieBot/Modules/Administration/Protection/UserSpamStats.cs new file mode 100644 index 0000000..ad4a9bf --- /dev/null +++ b/src/EllieBot/Modules/Administration/Protection/UserSpamStats.cs @@ -0,0 +1,64 @@ +#nullable disable +namespace EllieBot.Modules.Administration; + +public sealed class UserSpamStats +{ + public int Count + { + get + { + lock (_applyLock) + { + Cleanup(); + return _messageTracker.Count; + } + } + } + + private string lastMessage; + + private readonly Queue _messageTracker; + + private readonly object _applyLock = new(); + + private readonly TimeSpan _maxTime = TimeSpan.FromMinutes(30); + + public UserSpamStats(IUserMessage msg) + { + lastMessage = msg.Content.ToUpperInvariant(); + _messageTracker = new(); + + ApplyNextMessage(msg); + } + + public void ApplyNextMessage(IUserMessage message) + { + var upperMsg = message.Content.ToUpperInvariant(); + + lock (_applyLock) + { + if (upperMsg != lastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any())) + { + // if it's a new message, reset spam counter + lastMessage = upperMsg; + _messageTracker.Clear(); + } + + _messageTracker.Enqueue(DateTime.UtcNow); + } + } + + private void Cleanup() + { + lock (_applyLock) + { + while (_messageTracker.TryPeek(out var dateTime)) + { + if (DateTime.UtcNow - dateTime < _maxTime) + break; + + _messageTracker.Dequeue(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs b/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs new file mode 100644 index 0000000..58b586e --- /dev/null +++ b/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs @@ -0,0 +1,198 @@ +#nullable disable +using CommandLine; +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class PruneCommands : EllieModule + { + private static readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14); + + public sealed class PruneOptions : IEllieCommandOptions + { + [Option(shortName: 's', + longName: "safe", + Default = false, + HelpText = "Whether pinned messages should be deleted.", + Required = false)] + public bool Safe { get; set; } + + [Option(shortName: 'a', + longName: "after", + Default = null, + HelpText = "Prune only messages after the specified message ID.", + Required = false)] + public ulong? After { get; set; } + + public void NormalizeOptions() + { + } + } + + //deletes her own messages, no perm required + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + public async Task Prune(params string[] args) + { + var (opts, _) = OptionsParser.ParseFrom(new PruneOptions(), args); + + var user = await ctx.Guild.GetCurrentUserAsync(); + + var progressMsg = await Response().Pending(strs.prune_progress(0, 100)).SendAsync(); + var progress = GetProgressTracker(progressMsg); + + if (opts.Safe) + await _service.PruneWhere((ITextChannel)ctx.Channel, + 100, + x => x.Author.Id == user.Id && !x.IsPinned, + progress, + opts.After); + else + await _service.PruneWhere((ITextChannel)ctx.Channel, + 100, + x => x.Author.Id == user.Id, + progress, + opts.After); + + ctx.Message.DeleteAfter(3); + await progressMsg.DeleteAsync(); + } + + // prune x + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageMessages)] + [BotPerm(ChannelPerm.ManageMessages)] + [EllieOptions] + [Priority(1)] + public async Task Prune(int count, params string[] args) + { + count++; + if (count < 1) + return; + + if (count > 1000) + count = 1000; + + var (opts, _) = OptionsParser.ParseFrom(new PruneOptions(), args); + + var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync(); + var progress = GetProgressTracker(progressMsg); + + if (opts.Safe) + await _service.PruneWhere((ITextChannel)ctx.Channel, + count, + x => !x.IsPinned && x.Id != progressMsg.Id, + progress, + opts.After); + else + await _service.PruneWhere((ITextChannel)ctx.Channel, + count, + x => x.Id != progressMsg.Id, + progress, + opts.After); + + await progressMsg.DeleteAsync(); + } + + private IProgress<(int, int)> GetProgressTracker(IUserMessage progressMsg) + { + var progress = new Progress<(int, int)>(async (x) => + { + var (deleted, total) = x; + try + { + await progressMsg.ModifyAsync(props => + { + props.Embed = _sender.CreateEmbed() + .WithPendingColor() + .WithDescription(GetText(strs.prune_progress(deleted, total))) + .Build(); + }); + } + catch + { + } + }); + + return progress; + } + + //prune @user [x] + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageMessages)] + [BotPerm(ChannelPerm.ManageMessages)] + [EllieOptions] + [Priority(0)] + public Task Prune(IGuildUser user, int count = 100, params string[] args) + => Prune(user.Id, count, args); + + //prune userid [x] + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageMessages)] + [BotPerm(ChannelPerm.ManageMessages)] + [EllieOptions] + [Priority(0)] + public async Task Prune(ulong userId, int count = 100, params string[] args) + { + if (userId == ctx.User.Id) + count++; + + if (count < 1) + return; + + if (count > 1000) + count = 1000; + + var (opts, _) = OptionsParser.ParseFrom(new PruneOptions(), args); + + var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync(); + var progress = GetProgressTracker(progressMsg); + + if (opts.Safe) + { + await _service.PruneWhere((ITextChannel)ctx.Channel, + count, + m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned, + progress, + opts.After + ); + } + else + { + await _service.PruneWhere((ITextChannel)ctx.Channel, + count, + m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks, + progress, + opts.After + ); + } + + await progressMsg.DeleteAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(ChannelPerm.ManageMessages)] + [BotPerm(ChannelPerm.ManageMessages)] + public async Task PruneCancel() + { + var ok = await _service.CancelAsync(ctx.Guild.Id); + + if (!ok) + { + await Response().Error(strs.prune_not_found).SendAsync(); + return; + } + + + await Response().Confirm(strs.prune_cancelled).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Prune/PruneService.cs b/src/EllieBot/Modules/Administration/Prune/PruneService.cs new file mode 100644 index 0000000..006f9e8 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Prune/PruneService.cs @@ -0,0 +1,101 @@ +#nullable disable +namespace EllieBot.Modules.Administration.Services; + +public class PruneService : IEService +{ + //channelids where prunes are currently occuring + private readonly ConcurrentDictionary _pruningGuilds = new(); + private readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14); + private readonly ILogCommandService _logService; + + public PruneService(ILogCommandService logService) + => _logService = logService; + + public async Task PruneWhere( + ITextChannel channel, + int amount, + Func predicate, + IProgress<(int deleted, int total)> progress, + ulong? after = null + ) + { + ArgumentNullException.ThrowIfNull(channel, nameof(channel)); + + var originalAmount = amount; + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); + + using var cancelSource = new CancellationTokenSource(); + if (!_pruningGuilds.TryAdd(channel.GuildId, cancelSource)) + return; + + try + { + var now = DateTime.UtcNow; + IMessage[] msgs; + IMessage lastMessage = null; + + while (amount > 0 && !cancelSource.IsCancellationRequested) + { + var dled = lastMessage is null + ? await channel.GetMessagesAsync(50).FlattenAsync() + : await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).FlattenAsync(); + + msgs = dled + .Where(predicate) + .Where(x => after is not ulong a || x.Id > a) + .Take(amount) + .ToArray(); + + if (!msgs.Any()) + return; + + lastMessage = msgs[^1]; + + var bulkDeletable = new List(); + var singleDeletable = new List(); + foreach (var x in msgs) + { + _logService.AddDeleteIgnore(x.Id); + + if (now - x.CreatedAt < _twoWeeks) + bulkDeletable.Add(x); + else + singleDeletable.Add(x); + } + + if (bulkDeletable.Count > 0) + { + await channel.DeleteMessagesAsync(bulkDeletable); + amount -= msgs.Length; + progress.Report((originalAmount - amount, originalAmount)); + await Task.Delay(2000, cancelSource.Token); + } + + foreach (var group in singleDeletable.Chunk(5)) + { + await group.Select(x => x.DeleteAsync()).WhenAll(); + amount -= 5; + progress.Report((originalAmount - amount, originalAmount)); + await Task.Delay(5000, cancelSource.Token); + } + } + } + catch + { + //ignore + } + finally + { + _pruningGuilds.TryRemove(channel.GuildId, out _); + } + } + + public async Task CancelAsync(ulong guildId) + { + if (!_pruningGuilds.TryRemove(guildId, out var source)) + return false; + + await source.CancelAsync(); + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs b/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs new file mode 100644 index 0000000..85f7945 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs @@ -0,0 +1,52 @@ +#nullable disable +using EllieBot.Modules.Patronage; +using EllieBot.Db.Models; +using OneOf; +using OneOf.Types; + +namespace EllieBot.Modules.Administration.Services; + +public interface IReactionRoleService +{ + /// + /// Adds a single reaction role + /// + /// Guild where to add a reaction role + /// Message to which to add a reaction role + /// + /// + /// + /// + /// The result of the operation + Task> AddReactionRole( + IGuild guild, + IMessage msg, + string emote, + IRole role, + int group = 0, + int levelReq = 0); + + /// + /// Get all reaction roles on the specified server + /// + /// + /// + Task> GetReactionRolesAsync(ulong guildId); + + /// + /// Remove reaction roles on the specified message + /// + /// + /// + /// + Task RemoveReactionRoles(ulong guildId, ulong messageId); + + /// + /// Remove all reaction roles in the specified server + /// + /// + /// + Task RemoveAllReactionRoles(ulong guildId); + + Task> TransferReactionRolesAsync(ulong guildId, ulong fromMessageId, ulong toMessageId); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs b/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs new file mode 100644 index 0000000..800512a --- /dev/null +++ b/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs @@ -0,0 +1,176 @@ +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + public partial class ReactionRoleCommands : EllieModule + { + private readonly IReactionRoleService _rero; + + public ReactionRoleCommands(IReactionRoleService rero) + { + _rero = rero; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task ReRoAdd( + ulong messageId, + string emoteStr, + IRole role, + int group = 0, + int levelReq = 0) + { + if (group < 0) + return; + + if (levelReq < 0) + return; + + var msg = await ctx.Channel.GetMessageAsync(messageId); + if (msg is null) + { + await Response().Error(strs.not_found).SendAsync(); + return; + } + + if (ctx.User.Id != ctx.Guild.OwnerId + && ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position) <= role.Position) + { + await Response().Error(strs.hierarchy).SendAsync(); + return; + } + + var emote = emoteStr.ToIEmote(); + await msg.AddReactionAsync(emote); + var res = await _rero.AddReactionRole(ctx.Guild, + msg, + emoteStr, + role, + group, + levelReq); + + await res.Match( + _ => ctx.OkAsync(), + fl => + { + _ = msg.RemoveReactionAsync(emote, ctx.Client.CurrentUser); + return !fl.IsPatronLimit + ? Response().Error(strs.limit_reached(fl.Quota)).SendAsync() + : Response().Pending(strs.feature_limit_reached_owner(fl.Quota, fl.Name)).SendAsync(); + }); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task ReRoList(int page = 1) + { + if (--page < 0) + return; + + var allReros = await _rero.GetReactionRolesAsync(ctx.Guild.Id); + + await Response() + .Paginated() + .Items(allReros.OrderBy(x => x.Group).ToList()) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => + { + var embed = _sender.CreateEmbed() + .WithOkColor(); + + var content = string.Empty; + foreach (var g in items + .GroupBy(x => x.MessageId) + .OrderBy(x => x.Key)) + { + var messageId = g.Key; + content += + $"[{messageId}](https://discord.com/channels/{ctx.Guild.Id}/{g.First().ChannelId}/{g.Key})\n"; + + var groupGroups = g.GroupBy(x => x.Group); + + foreach (var ggs in groupGroups) + { + content += $"`< {(g.Key == 0 ? ("Not Exclusive (Group 0)") : ($"Group {ggs.Key}"))} >`\n"; + + foreach (var rero in ggs) + { + content += + $"\t{rero.Emote} -> {(ctx.Guild.GetRole(rero.RoleId)?.Mention ?? "")}"; + if (rero.LevelReq > 0) + content += $" (lvl {rero.LevelReq}+)"; + content += '\n'; + } + } + } + + embed.WithDescription(string.IsNullOrWhiteSpace(content) + ? "There are no reaction roles on this server" + : content); + + return embed; + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task ReRoRemove(ulong messageId) + { + var succ = await _rero.RemoveReactionRoles(ctx.Guild.Id, messageId); + if (succ) + await ctx.OkAsync(); + else + await ctx.ErrorAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task ReRoDeleteAll() + { + await _rero.RemoveAllReactionRoles(ctx.Guild.Id); + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [Ratelimit(60)] + public async Task ReRoTransfer(ulong fromMessageId, ulong toMessageId) + { + var msg = await ctx.Channel.GetMessageAsync(toMessageId); + + if (msg is null) + { + await ctx.ErrorAsync(); + return; + } + + var reactions = await _rero.TransferReactionRolesAsync(ctx.Guild.Id, fromMessageId, toMessageId); + + if (reactions.Count == 0) + { + await ctx.ErrorAsync(); + } + else + { + foreach (var r in reactions) + { + await msg.AddReactionAsync(r); + } + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs b/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs new file mode 100644 index 0000000..f1216ef --- /dev/null +++ b/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs @@ -0,0 +1,408 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Modules.Patronage; +using EllieBot.Db.Models; +using OneOf.Types; +using OneOf; + +namespace EllieBot.Modules.Administration.Services; + +public sealed class ReactionRolesService : IReadyExecutor, IEService, IReactionRoleService +{ + private readonly DbService _db; + private readonly DiscordSocketClient _client; + private readonly IBotCredentials _creds; + + private ConcurrentDictionary> _cache; + private readonly object _cacheLock = new(); + private readonly SemaphoreSlim _assignementLock = new(1, 1); + private readonly IPatronageService _ps; + + private static readonly FeatureLimitKey _reroFLKey = new() + { + Key = "rero:max_count", + PrettyName = "Reaction Role" + }; + + public ReactionRolesService( + DiscordSocketClient client, + DbService db, + IBotCredentials creds, + IPatronageService ps) + { + _db = db; + _ps = ps; + _client = client; + _creds = creds; + _cache = new(); + } + + public async Task OnReadyAsync() + { + await using var uow = _db.GetDbContext(); + var reros = await uow.GetTable() + .Where( + x => Linq2DbExpressions.GuildOnShard(x.GuildId, _creds.TotalShards, _client.ShardId)) + .ToListAsyncLinqToDB(); + + foreach (var group in reros.GroupBy(x => x.MessageId)) + { + _cache[group.Key] = group.ToList(); + } + + _client.ReactionAdded += ClientOnReactionAdded; + _client.ReactionRemoved += ClientOnReactionRemoved; + } + + private async Task<(IGuildUser, IRole)> GetUserAndRoleAsync( + ulong userId, + ReactionRoleV2 rero) + { + var guild = _client.GetGuild(rero.GuildId); + var role = guild?.GetRole(rero.RoleId); + + if (role is null) + return default; + + var user = guild.GetUser(userId) as IGuildUser + ?? await _client.Rest.GetGuildUserAsync(guild.Id, userId); + + if (user is null) + return default; + + return (user, role); + } + + private Task ClientOnReactionRemoved( + Cacheable cmsg, + Cacheable ch, + SocketReaction r) + { + if (!_cache.TryGetValue(cmsg.Id, out var reros)) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + var emote = await GetFixedEmoteAsync(cmsg, r.Emote); + + var rero = reros.FirstOrDefault(x => x.Emote == emote.Name + || x.Emote == emote.ToString()); + if (rero is null) + return; + + var (user, role) = await GetUserAndRoleAsync(r.UserId, rero); + + if (user.IsBot) + return; + + await _assignementLock.WaitAsync(); + try + { + if (user.RoleIds.Contains(role.Id)) + { + await user.RemoveRoleAsync(role.Id, new RequestOptions() + { + AuditLogReason = $"Reaction role" + }); + } + } + finally + { + _assignementLock.Release(); + } + }); + + return Task.CompletedTask; + } + + + // had to add this because for some reason, reactionremoved event's reaction doesn't have IsAnimated set, + // causing the .ToString() to be wrong on animated custom emotes + private async Task GetFixedEmoteAsync( + Cacheable cmsg, + IEmote inputEmote) + { + // this should only run for emote + if (inputEmote is not Emote e) + return inputEmote; + + // try to get the message and pull + var msg = await cmsg.GetOrDownloadAsync(); + + var emote = msg.Reactions.Keys.FirstOrDefault(x => e.Equals(x)); + return emote ?? inputEmote; + } + + private Task ClientOnReactionAdded( + Cacheable msg, + Cacheable ch, + SocketReaction r) + { + if (!_cache.TryGetValue(msg.Id, out var reros)) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + var rero = reros.FirstOrDefault(x => x.Emote == r.Emote.Name || x.Emote == r.Emote.ToString()); + if (rero is null) + return; + + var (user, role) = await GetUserAndRoleAsync(r.UserId, rero); + + if (user.IsBot) + return; + + await _assignementLock.WaitAsync(); + try + { + if (!user.RoleIds.Contains(role.Id)) + { + // first check if there is a level requirement + // and if there is, make sure user satisfies it + if (rero.LevelReq > 0) + { + await using var ctx = _db.GetDbContext(); + var levelData = await ctx.GetTable() + .GetLevelDataFor(user.GuildId, user.Id); + + if (levelData.Level < rero.LevelReq) + return; + } + + // remove all other roles from the same group from the user + // execept in group 0, which is a special, non-exclusive group + if (rero.Group != 0) + { + var exclusive = reros + .Where(x => x.Group == rero.Group && x.RoleId != role.Id) + .Select(x => x.RoleId) + .Distinct() + .ToArray(); + + + if (exclusive.Any()) + { + try + { + await user.RemoveRolesAsync(exclusive, + new RequestOptions() + { + AuditLogReason = "Reaction role exclusive group" + }); + } + catch { } + } + + // remove user's previous reaction + try + { + var m = await msg.GetOrDownloadAsync(); + if (m is not null) + { + var reactToRemove = m.Reactions + .FirstOrDefault(x => x.Key.ToString() != r.Emote.ToString()) + .Key; + + if (reactToRemove is not null) + { + await m.RemoveReactionAsync(reactToRemove, user); + } + } + } + catch + { + } + } + + await user.AddRoleAsync(role.Id, new() + { + AuditLogReason = "Reaction role" + }); + } + } + finally + { + _assignementLock.Release(); + } + }); + + return Task.CompletedTask; + } + + /// + /// Adds a single reaction role + /// + /// Guild where to add a reaction role + /// Message to which to add a reaction role + /// + /// + /// + /// + /// The result of the operation + public async Task> AddReactionRole( + IGuild guild, + IMessage msg, + string emote, + IRole role, + int group = 0, + int levelReq = 0) + { + ArgumentOutOfRangeException.ThrowIfNegative(group); + + ArgumentOutOfRangeException.ThrowIfNegative(levelReq); + + await using var ctx = _db.GetDbContext(); + + await using var tran = await ctx.Database.BeginTransactionAsync(); + var activeReactionRoles = await ctx.GetTable() + .Where(x => x.GuildId == guild.Id) + .CountAsync(); + + var result = await _ps.TryGetFeatureLimitAsync(_reroFLKey, guild.OwnerId, 50); + if (result.Quota != -1 && activeReactionRoles >= result.Quota) + return result; + + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + GuildId = guild.Id, + ChannelId = msg.Channel.Id, + + MessageId = msg.Id, + Emote = emote, + + RoleId = role.Id, + Group = group, + LevelReq = levelReq + }, + (old) => new() + { + RoleId = role.Id, + Group = group, + LevelReq = levelReq + }, + () => new() + { + MessageId = msg.Id, + Emote = emote, + }); + + await tran.CommitAsync(); + + var obj = new ReactionRoleV2() + { + GuildId = guild.Id, + MessageId = msg.Id, + Emote = emote, + RoleId = role.Id, + Group = group, + LevelReq = levelReq + }; + + lock (_cacheLock) + { + _cache.AddOrUpdate(msg.Id, + _ => [obj], + (_, list) => + { + list.RemoveAll(x => x.Emote == emote); + list.Add(obj); + return list; + }); + } + + return new Success(); + } + + /// + /// Get all reaction roles on the specified server + /// + /// + /// + public async Task> GetReactionRolesAsync(ulong guildId) + { + await using var ctx = _db.GetDbContext(); + return await ctx.GetTable() + .Where(x => x.GuildId == guildId) + .ToListAsync(); + } + + /// + /// Remove reaction roles on the specified message + /// + /// + /// + /// + public async Task RemoveReactionRoles(ulong guildId, ulong messageId) + { + // guildid is used for quick index lookup + await using var ctx = _db.GetDbContext(); + var changed = await ctx.GetTable() + .Where(x => x.GuildId == guildId && x.MessageId == messageId) + .DeleteAsync(); + + _cache.TryRemove(messageId, out _); + + if (changed == 0) + return false; + + return true; + } + + /// + /// Remove all reaction roles in the specified server + /// + /// + /// + public async Task RemoveAllReactionRoles(ulong guildId) + { + await using var ctx = _db.GetDbContext(); + var output = await ctx.GetTable() + .Where(x => x.GuildId == guildId) + .DeleteWithOutputAsync(x => x.MessageId); + + lock (_cacheLock) + { + foreach (var o in output) + { + _cache.TryRemove(o, out _); + } + } + + return output.Length; + } + + public async Task> TransferReactionRolesAsync( + ulong guildId, + ulong fromMessageId, + ulong toMessageId) + { + await using var ctx = _db.GetDbContext(); + var updated = ctx.GetTable() + .Where(x => x.GuildId == guildId && x.MessageId == fromMessageId) + .UpdateWithOutput(old => new() + { + MessageId = toMessageId + }, + (old, neu) => neu); + lock (_cacheLock) + { + if (_cache.TryRemove(fromMessageId, out var data)) + { + if (_cache.TryGetValue(toMessageId, out var newData)) + { + newData.AddRange(data); + } + else + { + _cache[toMessageId] = data; + } + } + } + + return updated.Select(x => x.Emote.ToIEmote()).ToList(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Role/RoleCommands.cs b/src/EllieBot/Modules/Administration/Role/RoleCommands.cs new file mode 100644 index 0000000..7f5daea --- /dev/null +++ b/src/EllieBot/Modules/Administration/Role/RoleCommands.cs @@ -0,0 +1,209 @@ +#nullable disable +using SixLabors.ImageSharp.PixelFormats; +using Color = SixLabors.ImageSharp.Color; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + public partial class RoleCommands : EllieModule + { + public enum Exclude + { + Excl + } + + private readonly IServiceProvider _services; + private StickyRolesService _stickyRoleSvc; + + public RoleCommands(IServiceProvider services, StickyRolesService stickyRoleSvc) + { + _services = services; + _stickyRoleSvc = stickyRoleSvc; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task SetRole(IGuildUser targetUser, [Leftover] IRole roleToAdd) + { + var runnerUser = (IGuildUser)ctx.User; + var runnerMaxRolePosition = runnerUser.GetRoles().Max(x => x.Position); + if (ctx.User.Id != ctx.Guild.OwnerId && runnerMaxRolePosition <= roleToAdd.Position) + return; + try + { + await targetUser.AddRoleAsync(roleToAdd, new RequestOptions() + { + AuditLogReason = $"Added by [{ctx.User.Username}]" + }); + + await Response().Confirm(strs.setrole(Format.Bold(roleToAdd.Name), + Format.Bold(targetUser.ToString()))).SendAsync(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in setrole command"); + await Response().Error(strs.setrole_err).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task RemoveRole(IGuildUser targetUser, [Leftover] IRole roleToRemove) + { + var runnerUser = (IGuildUser)ctx.User; + if (ctx.User.Id != runnerUser.Guild.OwnerId + && runnerUser.GetRoles().Max(x => x.Position) <= roleToRemove.Position) + return; + try + { + await targetUser.RemoveRoleAsync(roleToRemove); + await Response().Confirm(strs.remrole(Format.Bold(roleToRemove.Name), + Format.Bold(targetUser.ToString()))).SendAsync(); + } + catch + { + await Response().Error(strs.remrole_err).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task RenameRole(IRole roleToEdit, [Leftover] string newname) + { + var guser = (IGuildUser)ctx.User; + if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= roleToEdit.Position) + return; + try + { + if (roleToEdit.Position > (await ctx.Guild.GetCurrentUserAsync()).GetRoles().Max(r => r.Position)) + { + await Response().Error(strs.renrole_perms).SendAsync(); + return; + } + + await roleToEdit.ModifyAsync(g => g.Name = newname); + await Response().Confirm(strs.renrole).SendAsync(); + } + catch (Exception) + { + await Response().Error(strs.renrole_err).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task RemoveAllRoles([Leftover] IGuildUser user) + { + var guser = (IGuildUser)ctx.User; + + var userRoles = user.GetRoles().Where(x => !x.IsManaged && x != x.Guild.EveryoneRole).ToList(); + + if (user.Id == ctx.Guild.OwnerId + || (ctx.User.Id != ctx.Guild.OwnerId + && guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position))) + return; + try + { + await user.RemoveRolesAsync(userRoles); + await Response().Confirm(strs.rar(Format.Bold(user.ToString()))).SendAsync(); + } + catch (Exception) + { + await Response().Error(strs.rar_err).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task CreateRole([Leftover] string roleName = null) + { + if (string.IsNullOrWhiteSpace(roleName)) + return; + + var r = await ctx.Guild.CreateRoleAsync(roleName, isMentionable: false); + await Response().Confirm(strs.cr(Format.Bold(r.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task DeleteRole([Leftover] IRole role) + { + var guser = (IGuildUser)ctx.User; + if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + return; + + await role.DeleteAsync(); + await Response().Confirm(strs.dr(Format.Bold(role.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task RoleHoist([Leftover] IRole role) + { + var newHoisted = !role.IsHoisted; + await role.ModifyAsync(r => r.Hoist = newHoisted); + if (newHoisted) + await Response().Confirm(strs.rolehoist_enabled(Format.Bold(role.Name))).SendAsync(); + else + await Response().Confirm(strs.rolehoist_disabled(Format.Bold(role.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task RoleColor([Leftover] IRole role) + => await Response().Confirm("Role Color", role.Color.RawValue.ToString("x6")).SendAsync(); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [Priority(0)] + public async Task RoleColor(Color color, [Leftover] IRole role) + { + try + { + var rgba32 = color.ToPixel(); + await role.ModifyAsync(r => r.Color = new Discord.Color(rgba32.R, rgba32.G, rgba32.B)); + await Response().Confirm(strs.rc(Format.Bold(role.Name))).SendAsync(); + } + catch (Exception) + { + await Response().Error(strs.rc_perms).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task StickyRoles() + { + var newState = await _stickyRoleSvc.ToggleStickyRoles(ctx.Guild.Id); + + if (newState) + { + await Response().Confirm(strs.sticky_roles_enabled).SendAsync(); + } + else + { + await Response().Confirm(strs.sticky_roles_disabled).SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Role/StickyRolesService.cs b/src/EllieBot/Modules/Administration/Role/StickyRolesService.cs new file mode 100644 index 0000000..1fcfc15 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Role/StickyRolesService.cs @@ -0,0 +1,139 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Db.Models; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; + +namespace EllieBot.Modules.Administration; + +public sealed class StickyRolesService : IEService, IReadyExecutor +{ + private readonly DiscordSocketClient _client; + private readonly IBotCredentials _creds; + private readonly DbService _db; + private HashSet _stickyRoles = new(); + + public StickyRolesService( + DiscordSocketClient client, + IBotCredentials creds, + DbService db) + { + _client = client; + _creds = creds; + _db = db; + } + + + public async Task OnReadyAsync() + { + await using (var ctx = _db.GetDbContext()) + { + _stickyRoles = (await ctx + .Set() + .ToLinqToDBTable() + .Where(x => Linq2DbExpressions.GuildOnShard(x.GuildId, + _creds.TotalShards, + _client.ShardId)) + .Where(x => x.StickyRoles) + .Select(x => x.GuildId) + .ToListAsync()) + .ToHashSet(); + } + + _client.UserJoined += ClientOnUserJoined; + _client.UserLeft += ClientOnUserLeft; + + // cleanup old ones every hour + // 30 days retention + if (_client.ShardId == 0) + { + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + while (await timer.WaitForNextTickAsync()) + { + await using var ctx = _db.GetDbContext(); + await ctx.GetTable() + .Where(x => x.DateAdded < DateTime.UtcNow - TimeSpan.FromDays(30)) + .DeleteAsync(); + } + } + } + + private Task ClientOnUserLeft(SocketGuild guild, SocketUser user) + { + if (user is not SocketGuildUser gu) + return Task.CompletedTask; + + if (!_stickyRoles.Contains(guild.Id)) + return Task.CompletedTask; + + _ = Task.Run(async () => await SaveRolesAsync(guild.Id, gu.Id, gu.Roles)); + + return Task.CompletedTask; + } + + private async Task SaveRolesAsync(ulong guildId, ulong userId, IReadOnlyCollection guRoles) + { + await using var ctx = _db.GetDbContext(); + await ctx.GetTable() + .InsertAsync(() => new() + { + GuildId = guildId, + UserId = userId, + RoleIds = string.Join(',', + guRoles.Where(x => !x.IsEveryone && !x.IsManaged).Select(x => x.Id.ToString())), + DateAdded = DateTime.UtcNow + }); + } + + private Task ClientOnUserJoined(SocketGuildUser user) + { + if (!_stickyRoles.Contains(user.Guild.Id)) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + var roles = await GetRolesAsync(user.Guild.Id, user.Id); + + await user.AddRolesAsync(roles); + }); + + return Task.CompletedTask; + } + + private async Task GetRolesAsync(ulong guildId, ulong userId) + { + await using var ctx = _db.GetDbContext(); + var stickyRolesEntry = await ctx + .GetTable() + .Where(x => x.GuildId == guildId && x.UserId == userId) + .DeleteWithOutputAsync(); + + if (stickyRolesEntry is { Length: > 0 }) + { + return stickyRolesEntry[0].GetRoleIds(); + } + + return []; + } + + public async Task ToggleStickyRoles(ulong guildId, bool? newState = null) + { + await using var ctx = _db.GetDbContext(); + var config = ctx.GuildConfigsForId(guildId, set => set); + + config.StickyRoles = newState ?? !config.StickyRoles; + await ctx.SaveChangesAsync(); + + if (config.StickyRoles) + { + _stickyRoles.Add(guildId); + } + else + { + _stickyRoles.Remove(guildId); + } + + return config.StickyRoles; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs b/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs new file mode 100644 index 0000000..8bcf2e1 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs @@ -0,0 +1,169 @@ +using System.Net.Http.Json; +using System.Text; +using EllieBot.Common.ModuleBehaviors; +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Administration.Self; + +public sealed class ToastielabReleaseModel +{ + [JsonPropertyName("tag_name")] + public required string TagName { get; init; } +} +public sealed class CheckForUpdatesService : IEService, IReadyExecutor +{ + private readonly BotConfigService _bcs; + private readonly IBotCredsProvider _bcp; + private readonly IHttpClientFactory _httpFactory; + private readonly DiscordSocketClient _client; + private readonly IMessageSenderService _sender; + + + private const string RELEASES_URL = "https://toastielab.dev/api/v1/repos/Emotions-stuff/Ellie/releases"; + + public CheckForUpdatesService( + BotConfigService bcs, + IBotCredsProvider bcp, + IHttpClientFactory httpFactory, + DiscordSocketClient client, + IMessageSenderService sender) + { + _bcs = bcs; + _bcp = bcp; + _httpFactory = httpFactory; + _client = client; + _sender = sender; + } + + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + while (await timer.WaitForNextTickAsync()) + { + var conf = _bcs.Data; + + if (!conf.CheckForUpdates) + continue; + + try + { + using var http = _httpFactory.CreateClient(); + var gitlabRelease = (await http.GetFromJsonAsync(RELEASES_URL)) + ?.FirstOrDefault(); + + if (gitlabRelease?.TagName is null) + continue; + + var latest = gitlabRelease.TagName; + var latestVersion = Version.Parse(latest); + var lastKnownVersion = GetLastKnownVersion(); + + if (lastKnownVersion is null) + { + UpdateLastKnownVersion(latestVersion); + continue; + } + + if (latestVersion > lastKnownVersion) + { + UpdateLastKnownVersion(latestVersion); + + // pull changelog + var changelog = await http.GetStringAsync("https://toastielab.dev/Emotions-stuff/Ellie/raw/branch/main/CHANGELOG.md"); + + var thisVersionChangelog = GetVersionChangelog(latestVersion, changelog); + + if (string.IsNullOrWhiteSpace(thisVersionChangelog)) + { + Log.Warning("New version {BotVersion} was found but changelog is unavailable", + thisVersionChangelog); + continue; + } + + var creds = _bcp.GetCreds(); + await creds.OwnerIds + .Select(async x => + { + var user = await _client.GetUserAsync(x); + if (user is null) + return; + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor($"EllieBot v{latest} Released!") + .WithTitle("Changelog") + .WithUrl("https://toastielab.dev/Emotions-stuff/Ellie/src/branch/main/CHANGELOG.md") + .WithDescription(thisVersionChangelog.TrimTo(4096)) + .WithFooter( + "You may disable these messages by typing '.conf bot checkforupdates false'"); + + await _sender.Response(user).Embed(eb).SendAsync(); + }) + .WhenAll(); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error while checking for new bot release: {ErrorMessage}", ex.Message); + } + } + } + + private string? GetVersionChangelog(Version latestVersion, string changelog) + { + var clSpan = changelog.AsSpan(); + + var sb = new StringBuilder(); + var started = false; + foreach (var line in clSpan.EnumerateLines()) + { + // if we're at the current version, keep reading lines and adding to the output + if (started) + { + // if we got to previous version, end + if (line.StartsWith("## [")) + break; + + // if we're reading a new segment, reformat it to print it better to discord + if (line.StartsWith("### ")) + { + sb.AppendLine(Format.Bold(line.ToString())); + } + else + { + sb.AppendLine(line.ToString()); + } + + continue; + } + + if (line.StartsWith($"## [{latestVersion.ToString()}]")) + { + started = true; + continue; + } + } + + return sb.ToString(); + } + + private const string LAST_KNOWN_VERSION_PATH = "data/last_known_version.txt"; + + private Version? GetLastKnownVersion() + { + if (!File.Exists(LAST_KNOWN_VERSION_PATH)) + return null; + + return Version.TryParse(File.ReadAllText(LAST_KNOWN_VERSION_PATH), out var ver) + ? ver + : null; + } + + private void UpdateLastKnownVersion(Version version) + { + File.WriteAllText("data/last_known_version.txt", version.ToString()); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Self/SelfCommands.cs b/src/EllieBot/Modules/Administration/Self/SelfCommands.cs new file mode 100644 index 0000000..d67ac93 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Self/SelfCommands.cs @@ -0,0 +1,586 @@ +#nullable disable +using Discord.Rest; +using EllieBot.Modules.Administration.Services; +using EllieBot.Db.Models; +using Ellie.Common.Marmalade; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class SelfCommands : EllieModule + { + public enum SettableUserStatus + { + Online, + Invisible, + Idle, + Dnd + } + + private readonly DiscordSocketClient _client; + private readonly IBotStrings _strings; + private readonly IMarmaladeLoaderService _marmaladeLoader; + private readonly ICoordinator _coord; + private readonly DbService _db; + + public SelfCommands( + DiscordSocketClient client, + DbService db, + IBotStrings strings, + ICoordinator coord, + IMarmaladeLoaderService marmaladeLoader) + { + _client = client; + _db = db; + _strings = strings; + _coord = coord; + _marmaladeLoader = marmaladeLoader; + } + + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public Task CacheUsers() + => CacheUsers(ctx.Guild); + + [Cmd] + [OwnerOnly] + public async Task CacheUsers(IGuild guild) + { + var downloadUsersTask = guild.DownloadUsersAsync(); + var message = await Response().Pending(strs.cache_users_pending).SendAsync(); + + await downloadUsersTask; + + var users = (await guild.GetUsersAsync(CacheMode.CacheOnly)) + .Cast() + .ToList(); + + var (added, updated) = await _service.RefreshUsersAsync(users); + + await message.ModifyAsync(x => + x.Embed = _sender.CreateEmbed() + .WithDescription(GetText(strs.cache_users_done(added, updated))) + .WithOkColor() + .Build() + ); + } + + [Cmd] + [OwnerOnly] + public async Task DoAs(IUser user, [Leftover] string message) + { + if (ctx.User is not IGuildUser { GuildPermissions.Administrator: true }) + return; + + if (ctx.Guild is SocketGuild sg + && ctx.Channel is ISocketMessageChannel ch + && ctx.Message is SocketUserMessage msg) + { + var fakeMessage = new DoAsUserMessage(msg, user, message); + + + await _cmdHandler.TryRunCommand(sg, ch, fakeMessage); + } + else + { + await Response().Error(strs.error_occured).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task StartupCommandAdd([Leftover] string cmdText) + { + if (cmdText.StartsWith(prefix + "die", StringComparison.InvariantCulture)) + return; + + var guser = (IGuildUser)ctx.User; + var cmd = new AutoCommand + { + CommandText = cmdText, + ChannelId = ctx.Channel.Id, + ChannelName = ctx.Channel.Name, + GuildId = ctx.Guild?.Id, + GuildName = ctx.Guild?.Name, + VoiceChannelId = guser.VoiceChannel?.Id, + VoiceChannelName = guser.VoiceChannel?.Name, + Interval = 0 + }; + _service.AddNewAutoCommand(cmd); + + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.scadd)) + .AddField(GetText(strs.server), + cmd.GuildId is null ? "-" : $"{cmd.GuildName}/{cmd.GuildId}", + true) + .AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true) + .AddField(GetText(strs.command_text), cmdText)) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task AutoCommandAdd(int interval, [Leftover] string cmdText) + { + if (cmdText.StartsWith(prefix + "die", StringComparison.InvariantCulture)) + return; + + if (interval < 5) + return; + + var guser = (IGuildUser)ctx.User; + var cmd = new AutoCommand + { + CommandText = cmdText, + ChannelId = ctx.Channel.Id, + ChannelName = ctx.Channel.Name, + GuildId = ctx.Guild?.Id, + GuildName = ctx.Guild?.Name, + VoiceChannelId = guser.VoiceChannel?.Id, + VoiceChannelName = guser.VoiceChannel?.Name, + Interval = interval + }; + _service.AddNewAutoCommand(cmd); + + await Response().Confirm(strs.autocmd_add(Format.Code(Format.Sanitize(cmdText)), cmd.Interval)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandsList(int page = 1) + { + if (page-- < 1) + return; + + var scmds = _service.GetStartupCommands().Skip(page * 5).Take(5).ToList(); + + if (scmds.Count == 0) + await Response().Error(strs.startcmdlist_none).SendAsync(); + else + { + var i = 0; + await Response() + .Confirm(text: string.Join("\n", + scmds.Select(x => $@"```css +#{++i + (page * 5)} +[{GetText(strs.server)}]: {(x.GuildId.HasValue ? $"{x.GuildName} #{x.GuildId}" : "-")} +[{GetText(strs.channel)}]: {x.ChannelName} #{x.ChannelId} +[{GetText(strs.command_text)}]: {x.CommandText}```")), + title: string.Empty, + footer: GetText(strs.page(page + 1))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task AutoCommandsList(int page = 1) + { + if (page-- < 1) + return; + + var scmds = _service.GetAutoCommands().Skip(page * 5).Take(5).ToList(); + if (!scmds.Any()) + await Response().Error(strs.autocmdlist_none).SendAsync(); + else + { + var i = 0; + await Response() + .Confirm(text: string.Join("\n", + scmds.Select(x => $@"```css +#{++i + (page * 5)} +[{GetText(strs.server)}]: {(x.GuildId.HasValue ? $"{x.GuildName} #{x.GuildId}" : "-")} +[{GetText(strs.channel)}]: {x.ChannelName} #{x.ChannelId} +{GetIntervalText(x.Interval)} +[{GetText(strs.command_text)}]: {x.CommandText}```")), + title: string.Empty, + footer: GetText(strs.page(page + 1))) + .SendAsync(); + } + } + + private string GetIntervalText(int interval) + => $"[{GetText(strs.interval)}]: {interval}"; + + [Cmd] + [OwnerOnly] + public async Task Wait(int miliseconds) + { + if (miliseconds <= 0) + return; + ctx.Message.DeleteAfter(0); + try + { + var msg = await Response().Confirm($"⏲ {miliseconds}ms").SendAsync(); + msg.DeleteAfter(miliseconds / 1000); + } + catch { } + + await Task.Delay(miliseconds); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task AutoCommandRemove([Leftover] int index) + { + if (!_service.RemoveAutoCommand(--index, out _)) + { + await Response().Error(strs.acrm_fail).SendAsync(); + return; + } + + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandRemove([Leftover] int index) + { + if (!_service.RemoveStartupCommand(--index, out _)) + await Response().Error(strs.scrm_fail).SendAsync(); + else + await Response().Confirm(strs.scrm).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task StartupCommandsClear() + { + _service.ClearStartupCommands(); + + await Response().Confirm(strs.startcmds_cleared).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task ForwardMessages() + { + var enabled = _service.ForwardMessages(); + + if (enabled) + await Response().Confirm(strs.fwdm_start).SendAsync(); + else + await Response().Pending(strs.fwdm_stop).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task ForwardToAll() + { + var enabled = _service.ForwardToAll(); + + if (enabled) + await Response().Confirm(strs.fwall_start).SendAsync(); + else + await Response().Pending(strs.fwall_stop).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task ForwardToChannel() + { + var enabled = _service.ForwardToChannel(ctx.Channel.Id); + + if (enabled) + await Response().Confirm(strs.fwch_start).SendAsync(); + else + await Response().Pending(strs.fwch_stop).SendAsync(); + } + + [Cmd] + public async Task ShardStats(int page = 1) + { + if (--page < 0) + return; + + var statuses = _coord.GetAllShardStatuses(); + + var status = string.Join(" : ", + statuses.Select(x => (ConnectionStateToEmoji(x), x)) + .GroupBy(x => x.Item1) + .Select(x => $"`{x.Count()} {x.Key}`") + .ToArray()); + + var allShardStrings = statuses.Select(st => + { + var timeDiff = DateTime.UtcNow - st.LastUpdate; + var stateStr = ConnectionStateToEmoji(st); + var maxGuildCountLength = + statuses.Max(x => x.GuildCount).ToString().Length; + return $"`{stateStr} " + + $"| #{st.ShardId.ToString().PadBoth(3)} " + + $"| {timeDiff:mm\\:ss} " + + $"| {st.GuildCount.ToString().PadBoth(maxGuildCountLength)} `"; + }) + .ToArray(); + await Response() + .Paginated() + .Items(allShardStrings) + .PageSize(25) + .CurrentPage(page) + .Page((items, _) => + { + var str = string.Join("\n", items); + + if (string.IsNullOrWhiteSpace(str)) + str = GetText(strs.no_shards_on_page); + + return _sender.CreateEmbed().WithOkColor().WithDescription($"{status}\n\n{str}"); + }) + .SendAsync(); + } + + private static string ConnectionStateToEmoji(ShardStatus status) + { + var timeDiff = DateTime.UtcNow - status.LastUpdate; + return status.ConnectionState switch + { + ConnectionState.Disconnected => "🔻", + _ when timeDiff > TimeSpan.FromSeconds(30) => " ❗ ", + ConnectionState.Connected => "✅", + _ => " ⏳" + }; + } + + [Cmd] + [OwnerOnly] + public async Task RestartShard(int shardId) + { + var success = _coord.RestartShard(shardId); + if (success) + await Response().Confirm(strs.shard_reconnecting(Format.Bold("#" + shardId))).SendAsync(); + else + await Response().Error(strs.no_shard_id).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public Task Leave([Leftover] string guildStr) + => _service.LeaveGuild(guildStr); + + [Cmd] + [OwnerOnly] + public async Task DeleteEmptyServers() + { + await ctx.Channel.TriggerTypingAsync(); + + var toLeave = _client.Guilds + .Where(s => s.MemberCount == 1 && s.Users.Count == 1) + .ToList(); + + foreach (var server in toLeave) + { + try + { + await server.DeleteAsync(); + Log.Information("Deleted server {ServerName} [{ServerId}]", + server.Name, + server.Id); + } + catch (Exception ex) + { + Log.Warning(ex, + "Error leaving server {ServerName} [{ServerId}]", + server.Name, + server.Id); + } + } + + await Response().Confirm(strs.deleted_x_servers(toLeave.Count)).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task Die(bool graceful = false) + { + try + { + await _client.SetStatusAsync(UserStatus.Invisible); + _ = _client.StopAsync(); + await Response().Confirm(strs.shutting_down).SendAsync(); + } + catch + { + // ignored + } + + await Task.Delay(2000); + _coord.Die(graceful); + } + + [Cmd] + [OwnerOnly] + public async Task Restart() + { + var success = _coord.RestartBot(); + if (!success) + { + await Response().Error(strs.restart_fail).SendAsync(); + return; + } + + try { await Response().Confirm(strs.restarting).SendAsync(); } + catch { } + } + + [Cmd] + [OwnerOnly] + public async Task SetName([Leftover] string newName) + { + if (string.IsNullOrWhiteSpace(newName)) + return; + + try + { + await _client.CurrentUser.ModifyAsync(u => u.Username = newName); + } + catch (RateLimitedException) + { + Log.Warning("You've been ratelimited. Wait 2 hours to change your name"); + } + + await Response().Confirm(strs.bot_name(Format.Bold(newName))).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task SetStatus([Leftover] SettableUserStatus status) + { + await _client.SetStatusAsync(SettableUserStatusToUserStatus(status)); + + await Response().Confirm(strs.bot_status(Format.Bold(status.ToString()))).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task SetAvatar([Leftover] string img = null) + { + var success = await _service.SetAvatar(img); + + if (success) + await Response().Confirm(strs.set_avatar).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task SetBanner([Leftover] string img = null) + { + var success = await _service.SetBanner(img); + + if (success) + await Response().Confirm(strs.set_banner).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task SetGame(ActivityType type, [Leftover] string game = null) + { + // var rep = new ReplacementBuilder().WithDefault(Context).Build(); + + var repCtx = new ReplacementContext(ctx); + await _service.SetGameAsync(game is null ? game : await repSvc.ReplaceAsync(game, repCtx), type); + + await Response().Confirm(strs.set_game).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task SetStream(string url, [Leftover] string name = null) + { + name ??= ""; + + await _service.SetStreamAsync(name, url); + + await Response().Confirm(strs.set_stream).SendAsync(); + } + + public enum SendWhere + { + User = 0, + U = 0, + Usr = 0, + + Channel = 1, + Ch = 1, + Chan = 1, + } + + [Cmd] + [OwnerOnly] + public async Task Send(SendWhere to, ulong id, [Leftover] SmartText text) + { + var ch = to switch + { + SendWhere.User => await ((await _client.Rest.GetUserAsync(id))?.CreateDMChannelAsync() + ?? Task.FromResult(null)), + SendWhere.Channel => await _client.Rest.GetChannelAsync(id) as IMessageChannel, + _ => null + }; + + if (ch is null) + { + await Response().Error(strs.invalid_format).SendAsync(); + return; + } + + + var repCtx = new ReplacementContext(ctx); + text = await repSvc.ReplaceAsync(text, repCtx); + await Response().Channel(ch).Text(text).SendAsync(); + + await ctx.OkAsync();; + } + + [Cmd] + [OwnerOnly] + public async Task StringsReload() + { + _strings.Reload(); + await _marmaladeLoader.ReloadStrings(); + await Response().Confirm(strs.bot_strings_reloaded).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task CoordReload() + { + await _coord.Reload(); + await ctx.OkAsync(); + } + + private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) + { + switch (sus) + { + case SettableUserStatus.Online: + return UserStatus.Online; + case SettableUserStatus.Invisible: + return UserStatus.Invisible; + case SettableUserStatus.Idle: + return UserStatus.AFK; + case SettableUserStatus.Dnd: + return UserStatus.DoNotDisturb; + } + + return UserStatus.Online; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Self/SelfService.cs b/src/EllieBot/Modules/Administration/Self/SelfService.cs new file mode 100644 index 0000000..82eb68c --- /dev/null +++ b/src/EllieBot/Modules/Administration/Self/SelfService.cs @@ -0,0 +1,485 @@ +#nullable disable +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; +using System.Collections.Immutable; +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace EllieBot.Modules.Administration.Services; + +public sealed class SelfService : IExecNoCommand, IReadyExecutor, IEService +{ + private readonly CommandHandler _cmdHandler; + private readonly DbService _db; + private readonly IBotStrings _strings; + private readonly DiscordSocketClient _client; + + private readonly IBotCredentials _creds; + + private ImmutableDictionary ownerChannels = + new Dictionary().ToImmutableDictionary(); + + private ConcurrentDictionary> autoCommands = new(); + + private readonly IHttpClientFactory _httpFactory; + private readonly BotConfigService _bss; + private readonly IPubSub _pubSub; + private readonly IMessageSenderService _sender; + + //keys + private readonly TypedKey _activitySetKey; + private readonly TypedKey _guildLeaveKey; + + public SelfService( + DiscordSocketClient client, + CommandHandler cmdHandler, + DbService db, + IBotStrings strings, + IBotCredentials creds, + IHttpClientFactory factory, + BotConfigService bss, + IPubSub pubSub, + IMessageSenderService sender) + { + _cmdHandler = cmdHandler; + _db = db; + _strings = strings; + _client = client; + _creds = creds; + _httpFactory = factory; + _bss = bss; + _pubSub = pubSub; + _sender = sender; + _activitySetKey = new("activity.set"); + _guildLeaveKey = new("guild.leave"); + + HandleStatusChanges(); + + _pubSub.Sub(_guildLeaveKey, + async input => + { + var guildStr = input.ToString().Trim().ToUpperInvariant(); + if (string.IsNullOrWhiteSpace(guildStr)) + return; + + var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr + || g.Name.Trim().ToUpperInvariant() == guildStr); + if (server is null) + return; + + if (server.OwnerId != _client.CurrentUser.Id) + { + await server.LeaveAsync(); + Log.Information("Left server {Name} [{Id}]", server.Name, server.Id); + } + else + { + await server.DeleteAsync(); + Log.Information("Deleted server {Name} [{Id}]", server.Name, server.Id); + } + }); + } + + public async Task OnReadyAsync() + { + await using var uow = _db.GetDbContext(); + + autoCommands = uow.Set().AsNoTracking() + .Where(x => x.Interval >= 5) + .AsEnumerable() + .GroupBy(x => x.GuildId) + .ToDictionary(x => x.Key, + y => y.ToDictionary(x => x.Id, TimerFromAutoCommand).ToConcurrent()) + .ToConcurrent(); + + var startupCommands = uow.Set().AsNoTracking().Where(x => x.Interval == 0); + foreach (var cmd in startupCommands) + { + try + { + await ExecuteCommand(cmd); + } + catch + { + } + } + + if (_client.ShardId == 0) + await LoadOwnerChannels(); + } + + private Timer TimerFromAutoCommand(AutoCommand x) + => new(async obj => await ExecuteCommand((AutoCommand)obj), x, x.Interval * 1000, x.Interval * 1000); + + private async Task ExecuteCommand(AutoCommand cmd) + { + try + { + if (cmd.GuildId is null) + return; + + var guildShard = (int)((cmd.GuildId.Value >> 22) % (ulong)_creds.TotalShards); + if (guildShard != _client.ShardId) + return; + var prefix = _cmdHandler.GetPrefix(cmd.GuildId); + //if someone already has .die as their startup command, ignore it + if (cmd.CommandText.StartsWith(prefix + "die", StringComparison.InvariantCulture)) + return; + await _cmdHandler.ExecuteExternal(cmd.GuildId, cmd.ChannelId, cmd.CommandText); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in SelfService ExecuteCommand"); + } + } + + public void AddNewAutoCommand(AutoCommand cmd) + { + using (var uow = _db.GetDbContext()) + { + uow.Set().Add(cmd); + uow.SaveChanges(); + } + + if (cmd.Interval >= 5) + { + var autos = autoCommands.GetOrAdd(cmd.GuildId, new ConcurrentDictionary()); + autos.AddOrUpdate(cmd.Id, + _ => TimerFromAutoCommand(cmd), + (_, old) => + { + old.Change(Timeout.Infinite, Timeout.Infinite); + return TimerFromAutoCommand(cmd); + }); + } + } + + public IEnumerable GetStartupCommands() + { + using var uow = _db.GetDbContext(); + return uow.Set().AsNoTracking().Where(x => x.Interval == 0).OrderBy(x => x.Id).ToList(); + } + + public IEnumerable GetAutoCommands() + { + using var uow = _db.GetDbContext(); + return uow.Set().AsNoTracking().Where(x => x.Interval >= 5).OrderBy(x => x.Id).ToList(); + } + + private async Task LoadOwnerChannels() + { + var channels = await _creds.OwnerIds.Select(id => + { + var user = _client.GetUser(id); + if (user is null) + return Task.FromResult(null); + + return user.CreateDMChannelAsync(); + }) + .WhenAll(); + + ownerChannels = channels.Where(x => x is not null) + .ToDictionary(x => x.Recipient.Id, x => x) + .ToImmutableDictionary(); + + if (!ownerChannels.Any()) + { + Log.Warning( + "No owner channels created! Make sure you've specified the correct OwnerId in the creds.yml file and invited the bot to a Discord server"); + } + else + { + Log.Information("Created {OwnerChannelCount} out of {TotalOwnerChannelCount} owner message channels", + ownerChannels.Count, + _creds.OwnerIds.Count); + } + } + + public Task LeaveGuild(string guildStr) + => _pubSub.Pub(_guildLeaveKey, guildStr); + + // forwards dms + public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg) + { + var bs = _bss.Data; + if (msg.Channel is IDMChannel && bs.ForwardMessages && (ownerChannels.Any() || bs.ForwardToChannel is not null)) + { + var title = _strings.GetText(strs.dm_from) + $" [{msg.Author}]({msg.Author.Id})"; + + var attachamentsTxt = _strings.GetText(strs.attachments); + + var toSend = msg.Content; + + if (msg.Attachments.Count > 0) + { + toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" + + string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl)); + } + + if (bs.ForwardToAllOwners) + { + var allOwnerChannels = ownerChannels.Values; + + foreach (var ownerCh in allOwnerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)) + { + try + { + await _sender.Response(ownerCh).Confirm(title, toSend).SendAsync(); + } + catch + { + Log.Warning("Can't contact owner with id {OwnerId}", ownerCh.Recipient.Id); + } + } + } + else if (bs.ForwardToChannel is ulong cid) + { + try + { + if (_client.GetChannel(cid) is ITextChannel ch) + await _sender.Response(ch).Confirm(title, toSend).SendAsync(); + } + catch + { + Log.Warning("Error forwarding message to the channel"); + } + } + else + { + var firstOwnerChannel = ownerChannels.Values.First(); + if (firstOwnerChannel.Recipient.Id != msg.Author.Id) + { + try + { + await _sender.Response(firstOwnerChannel).Confirm(title, toSend).SendAsync(); + } + catch + { + // ignored + } + } + } + } + } + + public bool RemoveStartupCommand(int index, out AutoCommand cmd) + { + using var uow = _db.GetDbContext(); + cmd = uow.Set().AsNoTracking().Where(x => x.Interval == 0).Skip(index).FirstOrDefault(); + + if (cmd is not null) + { + uow.Remove(cmd); + uow.SaveChanges(); + return true; + } + + return false; + } + + public bool RemoveAutoCommand(int index, out AutoCommand cmd) + { + using var uow = _db.GetDbContext(); + cmd = uow.Set().AsNoTracking().Where(x => x.Interval >= 5).Skip(index).FirstOrDefault(); + + if (cmd is not null) + { + uow.Remove(cmd); + if (autoCommands.TryGetValue(cmd.GuildId, out var autos)) + { + if (autos.TryRemove(cmd.Id, out var timer)) + timer.Change(Timeout.Infinite, Timeout.Infinite); + } + + uow.SaveChanges(); + return true; + } + + return false; + } + + public async Task SetAvatar(string img) + { + if (string.IsNullOrWhiteSpace(img)) + return false; + + if (!Uri.IsWellFormedUriString(img, UriKind.Absolute)) + return false; + + var uri = new Uri(img); + + using var http = _httpFactory.CreateClient(); + using var sr = await http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); + if (!sr.IsImage()) + return false; + + // i can't just do ReadAsStreamAsync because dicord.net's image poops itself + var imgData = await sr.Content.ReadAsByteArrayAsync(); + await using var imgStream = imgData.ToStream(); + await _client.CurrentUser.ModifyAsync(u => u.Avatar = new Image(imgStream)); + + return true; + } + + public async Task SetBanner(string img) + { + if (string.IsNullOrWhiteSpace(img)) + { + return false; + } + + if (!Uri.IsWellFormedUriString(img, UriKind.Absolute)) + { + return false; + } + + var uri = new Uri(img); + + using var http = _httpFactory.CreateClient(); + using var sr = await http.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); + + if (!sr.IsImage()) + { + return false; + } + + if (sr.GetContentLength() > 8.Megabytes()) + { + return false; + } + + await using var imageStream = await sr.Content.ReadAsStreamAsync(); + + await _client.CurrentUser.ModifyAsync(x => x.Banner = new Image(imageStream)); + return true; + } + + + public void ClearStartupCommands() + { + using var uow = _db.GetDbContext(); + var toRemove = uow.Set().AsNoTracking().Where(x => x.Interval == 0); + + uow.Set().RemoveRange(toRemove); + uow.SaveChanges(); + } + + public bool ForwardMessages() + { + var isForwarding = false; + _bss.ModifyConfig(config => { isForwarding = config.ForwardMessages = !config.ForwardMessages; }); + + return isForwarding; + } + + public bool ForwardToAll() + { + var isToAll = false; + _bss.ModifyConfig(config => { isToAll = config.ForwardToAllOwners = !config.ForwardToAllOwners; }); + return isToAll; + } + + public bool ForwardToChannel(ulong? channelId) + { + using var uow = _db.GetDbContext(); + + _bss.ModifyConfig(config => + { + config.ForwardToChannel = channelId == config.ForwardToChannel + ? null + : channelId; + }); + + return channelId is not null; + } + + private void HandleStatusChanges() + => _pubSub.Sub(_activitySetKey, + async data => + { + try + { + await _client.SetGameAsync(data.Name, data.Link, data.Type); + } + catch (Exception ex) + { + Log.Warning(ex, "Error setting activity"); + } + }); + + public Task SetGameAsync(string game, ActivityType type) + => _pubSub.Pub(_activitySetKey, + new() + { + Name = game, + Link = null, + Type = type + }); + + public Task SetStreamAsync(string name, string link) + => _pubSub.Pub(_activitySetKey, + new() + { + Name = name, + Link = link, + Type = ActivityType.Streaming + }); + + private sealed class ActivityPubData + { + public string Name { get; init; } + public string Link { get; init; } + public ActivityType Type { get; init; } + } + + + /// + /// Adds the specified to the database. If a database user with placeholder name + /// and discriminator is present in , their name and discriminator get updated accordingly. + /// + /// This database context. + /// The users to add or update in the database. + /// A tuple with the amount of new users added and old users updated. + public async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(List users) + { + await using var ctx = _db.GetDbContext(); + var presentDbUsers = await ctx.GetTable() + .Select(x => new { x.UserId, x.Username, x.Discriminator }) + .Where(x => users.Select(y => y.Id).Contains(x.UserId)) + .ToArrayAsyncEF(); + + var usersToAdd = users + .Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id)) + .Select(x => new DiscordUser() + { + UserId = x.Id, + AvatarId = x.AvatarId, + Username = x.Username, + Discriminator = x.Discriminator + }); + + var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied; + var toUpdateUserIds = presentDbUsers + .Where(x => x.Username == "Unknown" && x.Discriminator == "????") + .Select(x => x.UserId) + .ToArray(); + + foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id))) + { + await ctx.GetTable() + .Where(x => x.UserId == user.Id) + .UpdateAsync(x => new DiscordUser() + { + Username = user.Username, + Discriminator = user.Discriminator, + + // .award tends to set AvatarId and DateAdded to NULL, so account for that. + AvatarId = user.AvatarId, + DateAdded = x.DateAdded ?? DateTime.UtcNow + }); + } + + return (added, toUpdateUserIds.Length); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs b/src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs new file mode 100644 index 0000000..70581f7 --- /dev/null +++ b/src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesCommands.cs @@ -0,0 +1,239 @@ +#nullable disable +using EllieBot.Modules.Administration.Services; +using System.Text; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class SelfAssignedRolesCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [BotPerm(GuildPerm.ManageMessages)] + public async Task AdSarm() + { + var newVal = _service.ToggleAdSarm(ctx.Guild.Id); + + if (newVal) + await Response().Confirm(strs.adsarm_enable(prefix)).SendAsync(); + else + await Response().Confirm(strs.adsarm_disable(prefix)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [Priority(1)] + public Task Asar([Leftover] IRole role) + => Asar(0, role); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [Priority(0)] + public async Task Asar(int group, [Leftover] IRole role) + { + var guser = (IGuildUser)ctx.User; + if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + return; + + var succ = _service.AddNew(ctx.Guild.Id, role, group); + + if (succ) + { + await Response() + .Confirm(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString()))) + .SendAsync(); + } + else + await Response().Error(strs.role_in_list(Format.Bold(role.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [Priority(0)] + public async Task Sargn(int group, [Leftover] string name = null) + { + var set = await _service.SetNameAsync(ctx.Guild.Id, group, name); + + if (set) + { + await Response() + .Confirm(strs.group_name_added(Format.Bold(group.ToString()), Format.Bold(name))) + .SendAsync(); + } + else + await Response().Confirm(strs.group_name_removed(Format.Bold(group.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + public async Task Rsar([Leftover] IRole role) + { + var guser = (IGuildUser)ctx.User; + if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + return; + + var success = _service.RemoveSar(role.Guild.Id, role.Id); + if (!success) + await Response().Error(strs.self_assign_not).SendAsync(); + else + await Response().Confirm(strs.self_assign_rem(Format.Bold(role.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Lsar(int page = 1) + { + if (--page < 0) + return; + + var (exclusive, roles, groups) = _service.GetRoles(ctx.Guild); + + await Response() + .Paginated() + .Items(roles.OrderBy(x => x.Model.Group).ToList()) + .PageSize(20) + .CurrentPage(page) + .Page((items, _) => + { + var rolesStr = new StringBuilder(); + var roleGroups = items + .GroupBy(x => x.Model.Group) + .OrderBy(x => x.Key); + + foreach (var kvp in roleGroups) + { + string groupNameText; + if (!groups.TryGetValue(kvp.Key, out var name)) + groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key))); + else + groupNameText = Format.Bold($"{kvp.Key} - {name.TrimTo(25, true)}"); + + rolesStr.AppendLine("\t\t\t\t ⟪" + groupNameText + "⟫"); + foreach (var (model, role) in kvp.AsEnumerable()) + { + if (role is null) + { + } + else + { + // first character is invisible space + if (model.LevelRequirement == 0) + rolesStr.AppendLine("‌‌ " + role.Name); + else + rolesStr.AppendLine("‌‌ " + role.Name + $" (lvl {model.LevelRequirement}+)"); + } + } + + rolesStr.AppendLine(); + } + + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count())))) + .WithDescription(rolesStr.ToString()) + .WithFooter(exclusive + ? GetText(strs.self_assign_are_exclusive) + : GetText(strs.self_assign_are_not_exclusive)); + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task Togglexclsar() + { + var areExclusive = _service.ToggleEsar(ctx.Guild.Id); + if (areExclusive) + await Response().Confirm(strs.self_assign_excl).SendAsync(); + else + await Response().Confirm(strs.self_assign_no_excl).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task RoleLevelReq(int level, [Leftover] IRole role) + { + if (level < 0) + return; + + var succ = _service.SetLevelReq(ctx.Guild.Id, role, level); + + if (!succ) + { + await Response().Error(strs.self_assign_not).SendAsync(); + return; + } + + await Response() + .Confirm(strs.self_assign_level_req(Format.Bold(role.Name), + Format.Bold(level.ToString()))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Iam([Leftover] IRole role) + { + var guildUser = (IGuildUser)ctx.User; + + var (result, autoDelete, extra) = await _service.Assign(guildUser, role); + + IUserMessage msg; + if (result == SelfAssignedRolesService.AssignResult.ErrNotAssignable) + msg = await Response().Error(strs.self_assign_not).SendAsync(); + else if (result == SelfAssignedRolesService.AssignResult.ErrLvlReq) + msg = await Response().Error(strs.self_assign_not_level(Format.Bold(extra.ToString()))).SendAsync(); + else if (result == SelfAssignedRolesService.AssignResult.ErrAlreadyHave) + msg = await Response().Error(strs.self_assign_already(Format.Bold(role.Name))).SendAsync(); + else if (result == SelfAssignedRolesService.AssignResult.ErrNotPerms) + msg = await Response().Error(strs.self_assign_perms).SendAsync(); + else + msg = await Response().Confirm(strs.self_assign_success(Format.Bold(role.Name))).SendAsync(); + + if (autoDelete) + { + msg.DeleteAfter(3); + ctx.Message.DeleteAfter(3); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Iamnot([Leftover] IRole role) + { + var guildUser = (IGuildUser)ctx.User; + + var (result, autoDelete) = await _service.Remove(guildUser, role); + + IUserMessage msg; + if (result == SelfAssignedRolesService.RemoveResult.ErrNotAssignable) + msg = await Response().Error(strs.self_assign_not).SendAsync(); + else if (result == SelfAssignedRolesService.RemoveResult.ErrNotHave) + msg = await Response().Error(strs.self_assign_not_have(Format.Bold(role.Name))).SendAsync(); + else if (result == SelfAssignedRolesService.RemoveResult.ErrNotPerms) + msg = await Response().Error(strs.self_assign_perms).SendAsync(); + else + msg = await Response().Confirm(strs.self_assign_remove(Format.Bold(role.Name))).SendAsync(); + + if (autoDelete) + { + msg.DeleteAfter(3); + ctx.Message.DeleteAfter(3); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesService.cs b/src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesService.cs new file mode 100644 index 0000000..1305835 --- /dev/null +++ b/src/EllieBot/Modules/Administration/SelfAssignableRoles/SelfAssignedRolesService.cs @@ -0,0 +1,234 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public class SelfAssignedRolesService : IEService +{ + public enum AssignResult + { + Assigned, // successfully removed + ErrNotAssignable, // not assignable (error) + ErrAlreadyHave, // you already have that role (error) + ErrNotPerms, // bot doesn't have perms (error) + ErrLvlReq // you are not required level (error) + } + + public enum RemoveResult + { + Removed, // successfully removed + ErrNotAssignable, // not assignable (error) + ErrNotHave, // you don't have a role you want to remove (error) + ErrNotPerms // bot doesn't have perms (error) + } + + private readonly DbService _db; + + public SelfAssignedRolesService(DbService db) + => _db = db; + + public bool AddNew(ulong guildId, IRole role, int group) + { + using var uow = _db.GetDbContext(); + var roles = uow.Set().GetFromGuild(guildId); + if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id)) + return false; + + uow.Set().Add(new() + { + Group = group, + RoleId = role.Id, + GuildId = role.Guild.Id + }); + uow.SaveChanges(); + return true; + } + + public bool ToggleAdSarm(ulong guildId) + { + bool newval; + using var uow = _db.GetDbContext(); + var config = uow.GuildConfigsForId(guildId, set => set); + newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages; + uow.SaveChanges(); + return newval; + } + + public async Task<(AssignResult Result, bool AutoDelete, object extra)> Assign(IGuildUser guildUser, IRole role) + { + LevelStats userLevelData; + await using (var uow = _db.GetDbContext()) + { + var stats = uow.GetOrCreateUserXpStats(guildUser.Guild.Id, guildUser.Id); + userLevelData = new(stats.Xp + stats.AwardedXp); + } + + var (autoDelete, exclusive, roles) = GetAdAndRoles(guildUser.Guild.Id); + + var theRoleYouWant = roles.FirstOrDefault(r => r.RoleId == role.Id); + if (theRoleYouWant is null) + return (AssignResult.ErrNotAssignable, autoDelete, null); + if (theRoleYouWant.LevelRequirement > userLevelData.Level) + return (AssignResult.ErrLvlReq, autoDelete, theRoleYouWant.LevelRequirement); + if (guildUser.RoleIds.Contains(role.Id)) + return (AssignResult.ErrAlreadyHave, autoDelete, null); + + var roleIds = roles.Where(x => x.Group == theRoleYouWant.Group).Select(x => x.RoleId).ToArray(); + if (exclusive) + { + var sameRoles = guildUser.RoleIds.Where(r => roleIds.Contains(r)); + + foreach (var roleId in sameRoles) + { + var sameRole = guildUser.Guild.GetRole(roleId); + if (sameRole is not null) + { + try + { + await guildUser.RemoveRoleAsync(sameRole); + await Task.Delay(300); + } + catch + { + // ignored + } + } + } + } + + try + { + await guildUser.AddRoleAsync(role); + } + catch (Exception ex) + { + return (AssignResult.ErrNotPerms, autoDelete, ex); + } + + return (AssignResult.Assigned, autoDelete, null); + } + + public async Task SetNameAsync(ulong guildId, int group, string name) + { + var set = false; + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, y => y.Include(x => x.SelfAssignableRoleGroupNames)); + var toUpdate = gc.SelfAssignableRoleGroupNames.FirstOrDefault(x => x.Number == group); + + if (string.IsNullOrWhiteSpace(name)) + { + if (toUpdate is not null) + gc.SelfAssignableRoleGroupNames.Remove(toUpdate); + } + else if (toUpdate is null) + { + gc.SelfAssignableRoleGroupNames.Add(new() + { + Name = name, + Number = group + }); + set = true; + } + else + { + toUpdate.Name = name; + set = true; + } + + await uow.SaveChangesAsync(); + + return set; + } + + public async Task<(RemoveResult Result, bool AutoDelete)> Remove(IGuildUser guildUser, IRole role) + { + var (autoDelete, _, roles) = GetAdAndRoles(guildUser.Guild.Id); + + if (roles.FirstOrDefault(r => r.RoleId == role.Id) is null) + return (RemoveResult.ErrNotAssignable, autoDelete); + if (!guildUser.RoleIds.Contains(role.Id)) + return (RemoveResult.ErrNotHave, autoDelete); + try + { + await guildUser.RemoveRoleAsync(role); + } + catch (Exception) + { + return (RemoveResult.ErrNotPerms, autoDelete); + } + + return (RemoveResult.Removed, autoDelete); + } + + public bool RemoveSar(ulong guildId, ulong roleId) + { + bool success; + using var uow = _db.GetDbContext(); + success = uow.Set().DeleteByGuildAndRoleId(guildId, roleId); + uow.SaveChanges(); + return success; + } + + public (bool AutoDelete, bool Exclusive, IReadOnlyCollection) GetAdAndRoles(ulong guildId) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + var autoDelete = gc.AutoDeleteSelfAssignedRoleMessages; + var exclusive = gc.ExclusiveSelfAssignedRoles; + var roles = uow.Set().GetFromGuild(guildId); + + return (autoDelete, exclusive, roles); + } + + public bool SetLevelReq(ulong guildId, IRole role, int level) + { + using var uow = _db.GetDbContext(); + var roles = uow.Set().GetFromGuild(guildId); + var sar = roles.FirstOrDefault(x => x.RoleId == role.Id); + if (sar is not null) + { + sar.LevelRequirement = level; + uow.SaveChanges(); + } + else + return false; + + return true; + } + + public bool ToggleEsar(ulong guildId) + { + bool areExclusive; + using var uow = _db.GetDbContext(); + var config = uow.GuildConfigsForId(guildId, set => set); + + areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles; + uow.SaveChanges(); + return areExclusive; + } + + public (bool Exclusive, IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary + GroupNames + ) GetRoles(IGuild guild) + { + var exclusive = false; + + IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> roles; + IDictionary groupNames; + using (var uow = _db.GetDbContext()) + { + var gc = uow.GuildConfigsForId(guild.Id, set => set.Include(x => x.SelfAssignableRoleGroupNames)); + exclusive = gc.ExclusiveSelfAssignedRoles; + groupNames = gc.SelfAssignableRoleGroupNames.ToDictionary(x => x.Number, x => x.Name); + var roleModels = uow.Set().GetFromGuild(guild.Id); + roles = roleModels.Select(x => (Model: x, Role: guild.GetRole(x.RoleId))) + .ToList(); + uow.Set().RemoveRange(roles.Where(x => x.Role is null).Select(x => x.Model).ToArray()); + uow.SaveChanges(); + } + + return (exclusive, roles.Where(x => x.Role is not null).ToList(), groupNames); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/ServerLog/DummyLogCommandService.cs b/src/EllieBot/Modules/Administration/ServerLog/DummyLogCommandService.cs new file mode 100644 index 0000000..3cdd4d3 --- /dev/null +++ b/src/EllieBot/Modules/Administration/ServerLog/DummyLogCommandService.cs @@ -0,0 +1,25 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public sealed class DummyLogCommandService : ILogCommandService +#if GLOBAL_ELLIE +, INService +#endif +{ + public void AddDeleteIgnore(ulong xId) + { + } + + public Task LogServer(ulong guildId, ulong channelId, bool actionValue) + => Task.CompletedTask; + + public bool LogIgnore(ulong guildId, ulong itemId, IgnoredItemType itemType) + => false; + + public LogSetting? GetGuildLogSettings(ulong guildId) + => default; + + public bool Log(ulong guildId, ulong? channelId, LogType type) + => false; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/ServerLog/ServerLogCommandService.cs b/src/EllieBot/Modules/Administration/ServerLog/ServerLogCommandService.cs new file mode 100644 index 0000000..6ea5345 --- /dev/null +++ b/src/EllieBot/Modules/Administration/ServerLog/ServerLogCommandService.cs @@ -0,0 +1,1297 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Modules.Administration.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public sealed class LogCommandService : ILogCommandService, IReadyExecutor +#if !GLOBAL_ELLIE + , IEService // don't load this service on global ellie +#endif +{ + public ConcurrentDictionary GuildLogSettings { get; } + + private ConcurrentDictionary> PresenceUpdates { get; } = new(); + private readonly DiscordSocketClient _client; + + private readonly IBotStrings _strings; + private readonly DbService _db; + private readonly MuteService _mute; + private readonly ProtectionService _prot; + private readonly GuildTimezoneService _tz; + private readonly IMemoryCache _memoryCache; + + private readonly ConcurrentHashSet _ignoreMessageIds = []; + private readonly UserPunishService _punishService; + private readonly IMessageSenderService _sender; + + public LogCommandService( + DiscordSocketClient client, + IBotStrings strings, + DbService db, + MuteService mute, + ProtectionService prot, + GuildTimezoneService tz, + IMemoryCache memoryCache, + UserPunishService punishService, + IMessageSenderService sender) + { + _client = client; + _memoryCache = memoryCache; + _sender = sender; + _strings = strings; + _db = db; + _mute = mute; + _prot = prot; + _tz = tz; + _punishService = punishService; + + using (var uow = db.GetDbContext()) + { + var guildIds = client.Guilds.Select(x => x.Id).ToList(); + var configs = uow.Set().AsQueryable() + .AsNoTracking() + .Where(x => guildIds.Contains(x.GuildId)) + .Include(ls => ls.LogIgnores) + .ToList(); + + GuildLogSettings = configs.ToDictionary(ls => ls.GuildId).ToConcurrent(); + } + + //_client.MessageReceived += _client_MessageReceived; + _client.MessageUpdated += _client_MessageUpdated; + _client.MessageDeleted += _client_MessageDeleted; + _client.UserBanned += _client_UserBanned; + _client.UserUnbanned += _client_UserUnbanned; + _client.UserJoined += _client_UserJoined; + _client.UserLeft += _client_UserLeft; + // _client.PresenceUpdated += _client_UserPresenceUpdated; + _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; + _client.GuildMemberUpdated += _client_GuildUserUpdated; + _client.PresenceUpdated += _client_PresenceUpdated; + _client.UserUpdated += _client_UserUpdated; + _client.ChannelCreated += _client_ChannelCreated; + _client.ChannelDestroyed += _client_ChannelDestroyed; + _client.ChannelUpdated += _client_ChannelUpdated; + _client.RoleDeleted += _client_RoleDeleted; + + _client.ThreadCreated += _client_ThreadCreated; + _client.ThreadDeleted += _client_ThreadDeleted; + + _mute.UserMuted += MuteCommands_UserMuted; + _mute.UserUnmuted += MuteCommands_UserUnmuted; + + _prot.OnAntiProtectionTriggered += TriggeredAntiProtection; + + _punishService.OnUserWarned += PunishServiceOnOnUserWarned; + } + + private async Task _client_PresenceUpdated(SocketUser user, SocketPresence? before, SocketPresence? after) + { + if (user is not SocketGuildUser gu) + return; + + if (!GuildLogSettings.TryGetValue(gu.Guild.Id, out var logSetting) + || before is null + || after is null + || logSetting.LogIgnores.Any(ilc => ilc.LogItemId == gu.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + + if (!user.IsBot + && logSetting.LogUserPresenceId is not null + && (logChannel = + await TryGetLogChannel(gu.Guild, logSetting, LogType.UserPresence)) is not null) + { + if (before.Status != after.Status) + { + var str = "🎭" + + Format.Code(PrettyCurrentTime(gu.Guild)) + + GetText(logChannel.Guild, + strs.user_status_change("👤" + Format.Bold(gu.Username), + Format.Bold(after.Status.ToString()))); + PresenceUpdates.AddOrUpdate(logChannel, + [str], + (_, list) => + { + list.Add(str); + return list; + }); + } + else if (before.Activities.FirstOrDefault()?.Name != after.Activities.FirstOrDefault()?.Name) + { + var str = + $"👾`{PrettyCurrentTime(gu.Guild)}`👤__**{gu.Username}**__ is now playing **{after.Activities.FirstOrDefault()?.Name ?? "-"}**."; + PresenceUpdates.AddOrUpdate(logChannel, + [str], + (_, list) => + { + list.Add(str); + return list; + }); + } + } + } + + private Task _client_ThreadDeleted(Cacheable sch) + { + _ = Task.Run(async () => + { + try + { + if (!sch.HasValue) + return; + + var ch = sch.Value; + + if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out var logSetting) + || logSetting.ThreadDeletedId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ThreadDeleted)) is null) + return; + + var title = GetText(logChannel.Guild, strs.thread_deleted); + + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle("🗑 " + title) + .WithDescription($"{ch.Name} | {ch.Id}") + .WithFooter(CurrentTime(ch.Guild))).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_ThreadCreated(SocketThreadChannel ch) + { + _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out var logSetting) + || logSetting.ThreadCreatedId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ThreadCreated)) is null) + return; + + var title = GetText(logChannel.Guild, strs.thread_created); + + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle("🆕 " + title) + .WithDescription($"{ch.Name} | {ch.Id}") + .WithFooter(CurrentTime(ch.Guild))).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + + return Task.CompletedTask; + } + + public async Task OnReadyAsync() + => await Task.WhenAll(PresenceUpdateTask(), IgnoreMessageIdsClearTask()); + + private async Task IgnoreMessageIdsClearTask() + { + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + while (await timer.WaitForNextTickAsync()) + _ignoreMessageIds.Clear(); + } + + private async Task PresenceUpdateTask() + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(15)); + while (await timer.WaitForNextTickAsync()) + { + try + { + var keys = PresenceUpdates.Keys.ToList(); + + await keys.Select(channel => + { + if (!((SocketGuild)channel.Guild).CurrentUser.GetPermissions(channel).SendMessages) + return Task.CompletedTask; + + if (PresenceUpdates.TryRemove(channel, out var msgs)) + { + var title = GetText(channel.Guild, strs.presence_updates); + var desc = string.Join(Environment.NewLine, msgs); + return _sender.Response(channel).Confirm(title, desc.TrimTo(2048)!).SendAsync(); + } + + return Task.CompletedTask; + }) + .WhenAll(); + } + catch + { + } + } + } + + public LogSetting? GetGuildLogSettings(ulong guildId) + { + GuildLogSettings.TryGetValue(guildId, out var logSetting); + return logSetting; + } + + public void AddDeleteIgnore(ulong messageId) + => _ignoreMessageIds.Add(messageId); + + public bool LogIgnore(ulong gid, ulong itemId, IgnoredItemType itemType) + { + using var uow = _db.GetDbContext(); + var logSetting = uow.LogSettingsFor(gid); + var removed = logSetting.LogIgnores.RemoveAll(x => x.ItemType == itemType && itemId == x.LogItemId); + + if (removed == 0) + { + var toAdd = new IgnoredLogItem + { + LogItemId = itemId, + ItemType = itemType + }; + logSetting.LogIgnores.Add(toAdd); + } + + uow.SaveChanges(); + GuildLogSettings.AddOrUpdate(gid, logSetting, (_, _) => logSetting); + return removed > 0; + } + + private string GetText(IGuild guild, LocStr str) + => _strings.GetText(str, guild.Id); + + private string PrettyCurrentTime(IGuild? g) + { + var time = DateTime.UtcNow; + if (g is not null) + time = TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(g.Id)); + return $"【{time:HH:mm:ss}】"; + } + + private string CurrentTime(IGuild? g) + { + var time = DateTime.UtcNow; + if (g is not null) + time = TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(g.Id)); + + return $"{time:HH:mm:ss}"; + } + + public async Task LogServer(ulong guildId, ulong channelId, bool value) + { + await using var uow = _db.GetDbContext(); + var logSetting = uow.LogSettingsFor(guildId); + + logSetting.LogOtherId = logSetting.MessageUpdatedId = logSetting.MessageDeletedId = logSetting.UserJoinedId = + logSetting.UserLeftId = logSetting.UserBannedId = logSetting.UserUnbannedId = logSetting.UserUpdatedId = + logSetting.ChannelCreatedId = logSetting.ChannelDestroyedId = logSetting.ChannelUpdatedId = + logSetting.LogUserPresenceId = logSetting.LogVoicePresenceId = logSetting.UserMutedId = + logSetting.ThreadCreatedId = logSetting.ThreadDeletedId + = logSetting.LogWarnsId = value ? channelId : null; + await uow.SaveChangesAsync(); + GuildLogSettings.AddOrUpdate(guildId, _ => logSetting, (_, _) => logSetting); + } + + + private async Task PunishServiceOnOnUserWarned(Warning arg) + { + if (!GuildLogSettings.TryGetValue(arg.GuildId, out var logSetting) || logSetting.LogWarnsId is null) + return; + + var g = _client.GetGuild(arg.GuildId); + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserWarned)) is null) + return; + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle($"⚠️ User Warned") + .WithDescription($"<@{arg.UserId}> | {arg.UserId}") + .AddField("Mod", arg.Moderator) + .AddField("Reason", string.IsNullOrWhiteSpace(arg.Reason) ? "-" : arg.Reason, true) + .WithFooter(CurrentTime(g)); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + + private Task _client_UserUpdated(SocketUser before, SocketUser uAfter) + { + _ = Task.Run(async () => + { + try + { + if (uAfter is not SocketGuildUser after) + return; + + var g = after.Guild; + + if (!GuildLogSettings.TryGetValue(g.Id, out var logSetting) || logSetting.UserUpdatedId is null || logSetting.LogIgnores.Any(ilc => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) is null) + return; + + var embed = _sender.CreateEmbed(); + + if (before.Username != after.Username) + { + embed.WithTitle("👥 " + GetText(g, strs.username_changed)) + .WithDescription($"{before.Username} | {before.Id}") + .AddField("Old Name", $"{before.Username}", true) + .AddField("New Name", $"{after.Username}", true) + .WithFooter(CurrentTime(g)) + .WithOkColor(); + } + else if (before.AvatarId != after.AvatarId) + { + embed.WithTitle("👥" + GetText(g, strs.avatar_changed)) + .WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}") + .WithFooter(CurrentTime(g)) + .WithOkColor(); + + var bav = before.RealAvatarUrl(); + if (bav.IsAbsoluteUri) + embed.WithThumbnailUrl(bav.ToString()); + + var aav = after.RealAvatarUrl(); + if (aav.IsAbsoluteUri) + embed.WithImageUrl(aav.ToString()); + } + else + return; + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + public bool Log(ulong gid, ulong? cid, LogType type /*, string options*/) + { + ulong? channelId = null; + using (var uow = _db.GetDbContext()) + { + var logSetting = uow.LogSettingsFor(gid); + GuildLogSettings.AddOrUpdate(gid, _ => logSetting, (_, _) => logSetting); + switch (type) + { + case LogType.Other: + channelId = logSetting.LogOtherId = logSetting.LogOtherId is null ? cid : default; + break; + case LogType.MessageUpdated: + channelId = logSetting.MessageUpdatedId = logSetting.MessageUpdatedId is null ? cid : default; + break; + case LogType.MessageDeleted: + channelId = logSetting.MessageDeletedId = logSetting.MessageDeletedId is null ? cid : default; + //logSetting.DontLogBotMessageDeleted = (options == "nobot"); + break; + case LogType.UserJoined: + channelId = logSetting.UserJoinedId = logSetting.UserJoinedId is null ? cid : default; + break; + case LogType.UserLeft: + channelId = logSetting.UserLeftId = logSetting.UserLeftId is null ? cid : default; + break; + case LogType.UserBanned: + channelId = logSetting.UserBannedId = logSetting.UserBannedId is null ? cid : default; + break; + case LogType.UserUnbanned: + channelId = logSetting.UserUnbannedId = logSetting.UserUnbannedId is null ? cid : default; + break; + case LogType.UserUpdated: + channelId = logSetting.UserUpdatedId = logSetting.UserUpdatedId is null ? cid : default; + break; + case LogType.UserMuted: + channelId = logSetting.UserMutedId = logSetting.UserMutedId is null ? cid : default; + break; + case LogType.ChannelCreated: + channelId = logSetting.ChannelCreatedId = logSetting.ChannelCreatedId is null ? cid : default; + break; + case LogType.ChannelDestroyed: + channelId = logSetting.ChannelDestroyedId = logSetting.ChannelDestroyedId is null ? cid : default; + break; + case LogType.ChannelUpdated: + channelId = logSetting.ChannelUpdatedId = logSetting.ChannelUpdatedId is null ? cid : default; + break; + case LogType.UserPresence: + channelId = logSetting.LogUserPresenceId = logSetting.LogUserPresenceId is null ? cid : default; + break; + case LogType.VoicePresence: + channelId = logSetting.LogVoicePresenceId = logSetting.LogVoicePresenceId is null ? cid : default; + break; + case LogType.UserWarned: + channelId = logSetting.LogWarnsId = logSetting.LogWarnsId is null ? cid : default; + break; + case LogType.ThreadDeleted: + channelId = logSetting.ThreadDeletedId = logSetting.ThreadDeletedId is null ? cid : default; + break; + case LogType.ThreadCreated: + channelId = logSetting.ThreadCreatedId = logSetting.ThreadCreatedId is null ? cid : default; + break; + } + + uow.SaveChanges(); + } + + return channelId is not null; + } + + private void MuteCommands_UserMuted( + IGuildUser usr, + IUser mod, + MuteType muteType, + string reason) + => _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) || logSetting.UserMutedId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) is null) + return; + var mutes = string.Empty; + var mutedLocalized = GetText(logChannel.Guild, strs.muted_sn); + switch (muteType) + { + case MuteType.Voice: + mutes = "🔇 " + GetText(logChannel.Guild, strs.xmuted_voice(mutedLocalized, mod.ToString())); + break; + case MuteType.Chat: + mutes = "🔇 " + GetText(logChannel.Guild, strs.xmuted_text(mutedLocalized, mod.ToString())); + break; + case MuteType.All: + mutes = "🔇 " + + GetText(logChannel.Guild, strs.xmuted_text_and_voice(mutedLocalized, mod.ToString())); + break; + } + + var embed = _sender.CreateEmbed() + .WithAuthor(mutes) + .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}") + .WithFooter(CurrentTime(usr.Guild)) + .WithOkColor(); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + + private void MuteCommands_UserUnmuted( + IGuildUser usr, + IUser mod, + MuteType muteType, + string reason) + => _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) || logSetting.UserMutedId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) is null) + return; + + var mutes = string.Empty; + var unmutedLocalized = GetText(logChannel.Guild, strs.unmuted_sn); + switch (muteType) + { + case MuteType.Voice: + mutes = "🔊 " + GetText(logChannel.Guild, strs.xmuted_voice(unmutedLocalized, mod.ToString())); + break; + case MuteType.Chat: + mutes = "🔊 " + GetText(logChannel.Guild, strs.xmuted_text(unmutedLocalized, mod.ToString())); + break; + case MuteType.All: + mutes = "🔊 " + + GetText(logChannel.Guild, + strs.xmuted_text_and_voice(unmutedLocalized, mod.ToString())); + break; + } + + var embed = _sender.CreateEmbed() + .WithAuthor(mutes) + .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}") + .WithFooter($"{CurrentTime(usr.Guild)}") + .WithOkColor(); + + if (!string.IsNullOrWhiteSpace(reason)) + embed.WithDescription(reason); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + + public Task TriggeredAntiProtection(PunishmentAction action, ProtectionType protection, params IGuildUser[] users) + { + _ = Task.Run(async () => + { + try + { + if (users.Length == 0) + return; + + if (!GuildLogSettings.TryGetValue(users.First().Guild.Id, out var logSetting) + || logSetting.LogOtherId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(users.First().Guild, logSetting, LogType.Other)) is null) + return; + + var punishment = string.Empty; + switch (action) + { + case PunishmentAction.Mute: + punishment = "🔇 " + GetText(logChannel.Guild, strs.muted_pl).ToUpperInvariant(); + break; + case PunishmentAction.Kick: + punishment = "👢 " + GetText(logChannel.Guild, strs.kicked_pl).ToUpperInvariant(); + break; + case PunishmentAction.Softban: + punishment = "☣ " + GetText(logChannel.Guild, strs.soft_banned_pl).ToUpperInvariant(); + break; + case PunishmentAction.Ban: + punishment = "⛔️ " + GetText(logChannel.Guild, strs.banned_pl).ToUpperInvariant(); + break; + case PunishmentAction.RemoveRoles: + punishment = "⛔️ " + GetText(logChannel.Guild, strs.remove_roles_pl).ToUpperInvariant(); + break; + } + + var embed = _sender.CreateEmbed() + .WithAuthor($"🛡 Anti-{protection}") + .WithTitle(GetText(logChannel.Guild, strs.users) + " " + punishment) + .WithDescription(string.Join("\n", users.Select(u => u.ToString()))) + .WithFooter(CurrentTime(logChannel.Guild)) + .WithOkColor(); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private string GetRoleDeletedKey(ulong roleId) + => $"role_deleted_{roleId}"; + + private Task _client_RoleDeleted(SocketRole socketRole) + { + Serilog.Log.Information("Role deleted {RoleId}", socketRole.Id); + _memoryCache.Set(GetRoleDeletedKey(socketRole.Id), true, TimeSpan.FromMinutes(5)); + return Task.CompletedTask; + } + + private bool IsRoleDeleted(ulong roleId) + { + var isDeleted = _memoryCache.TryGetValue(GetRoleDeletedKey(roleId), out _); + return isDeleted; + } + + private Task _client_GuildUserUpdated(Cacheable optBefore, SocketGuildUser after) + { + _ = Task.Run(async () => + { + try + { + var before = await optBefore.GetOrDownloadAsync(); + + if (before is null) + return; + + if (!GuildLogSettings.TryGetValue(before.Guild.Id, out var logSetting) + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + if (logSetting.UserUpdatedId is not null + && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) is not null) + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithFooter(CurrentTime(before.Guild)) + .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}"); + if (before.Nickname != after.Nickname) + { + embed.WithAuthor("👥 " + GetText(logChannel.Guild, strs.nick_change)) + .AddField(GetText(logChannel.Guild, strs.old_nick), + $"{before.Nickname}#{before.Discriminator}") + .AddField(GetText(logChannel.Guild, strs.new_nick), + $"{after.Nickname}#{after.Discriminator}"); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + else if (!before.Roles.SequenceEqual(after.Roles)) + { + if (before.Roles.Count < after.Roles.Count) + { + var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => r.Name); + embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_add)) + .WithDescription(string.Join(", ", diffRoles).SanitizeMentions()); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + else if (before.Roles.Count > after.Roles.Count) + { + await Task.Delay(1000); + var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r) && !IsRoleDeleted(r.Id)) + .Select(r => r.Name) + .ToList(); + + if (diffRoles.Any()) + { + embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_rem)) + .WithDescription(string.Join(", ", diffRoles).SanitizeMentions()); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + } + } + } + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter) + { + _ = Task.Run(async () => + { + try + { + if (cbefore is not IGuildChannel before) + return; + + var after = (IGuildChannel)cafter; + + if (!GuildLogSettings.TryGetValue(before.Guild.Id, out var logSetting) + || logSetting.ChannelUpdatedId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.Channel)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) is null) + return; + + var embed = _sender.CreateEmbed().WithOkColor().WithFooter(CurrentTime(before.Guild)); + + var beforeTextChannel = cbefore as ITextChannel; + var afterTextChannel = cafter as ITextChannel; + + if (before.Name != after.Name) + { + embed.WithTitle("ℹ️ " + GetText(logChannel.Guild, strs.ch_name_change)) + .WithDescription($"{after} | {after.Id}") + .AddField(GetText(logChannel.Guild, strs.ch_old_name), before.Name); + } + else if (beforeTextChannel?.Topic != afterTextChannel?.Topic) + { + embed.WithTitle("ℹ️ " + GetText(logChannel.Guild, strs.ch_topic_change)) + .WithDescription($"{after} | {after.Id}") + .AddField(GetText(logChannel.Guild, strs.old_topic), beforeTextChannel?.Topic ?? "-") + .AddField(GetText(logChannel.Guild, strs.new_topic), afterTextChannel?.Topic ?? "-"); + } + else + return; + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_ChannelDestroyed(IChannel ich) + { + _ = Task.Run(async () => + { + try + { + if (ich is not IGuildChannel ch) + return; + + if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out var logSetting) + || logSetting.ChannelDestroyedId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == ch.Id && ilc.ItemType == IgnoredItemType.Channel)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelDestroyed)) is null) + return; + + string title; + if (ch is IVoiceChannel) + title = GetText(logChannel.Guild, strs.voice_chan_destroyed); + else + title = GetText(logChannel.Guild, strs.text_chan_destroyed); + + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle("🆕 " + title) + .WithDescription($"{ch.Name} | {ch.Id}") + .WithFooter(CurrentTime(ch.Guild))).SendAsync(); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_ChannelCreated(IChannel ich) + { + _ = Task.Run(async () => + { + try + { + if (ich is not IGuildChannel ch) + return; + + if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out var logSetting) + || logSetting.ChannelCreatedId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelCreated)) is null) + return; + string title; + if (ch is IVoiceChannel) + title = GetText(logChannel.Guild, strs.voice_chan_created); + else + title = GetText(logChannel.Guild, strs.text_chan_created); + + await _sender.Response(logChannel).Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle("🆕 " + title) + .WithDescription($"{ch.Name} | {ch.Id}") + .WithFooter(CurrentTime(ch.Guild))).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState before, SocketVoiceState after) + { + _ = Task.Run(async () => + { + try + { + if (iusr is not IGuildUser usr || usr.IsBot) + return; + + var beforeVch = before.VoiceChannel; + var afterVch = after.VoiceChannel; + + if (beforeVch == afterVch) + return; + + if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) + || logSetting.LogVoicePresenceId is null + || logSetting.LogIgnores.Any( + ilc => ilc.LogItemId == iusr.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresence)) is null) + return; + + var str = string.Empty; + if (beforeVch?.Guild == afterVch?.Guild) + { + str = "🎙" + + Format.Code(PrettyCurrentTime(usr.Guild)) + + GetText(logChannel.Guild, + strs.user_vmoved("👤" + Format.Bold(usr.Username), + Format.Bold(beforeVch?.Name ?? ""), + Format.Bold(afterVch?.Name ?? ""))); + } + else if (beforeVch is null) + { + str = "🎙" + + Format.Code(PrettyCurrentTime(usr.Guild)) + + GetText(logChannel.Guild, + strs.user_vjoined("👤" + Format.Bold(usr.Username), + Format.Bold(afterVch?.Name ?? ""))); + } + else if (afterVch is null) + { + str = "🎙" + + Format.Code(PrettyCurrentTime(usr.Guild)) + + GetText(logChannel.Guild, + strs.user_vleft("👤" + Format.Bold(usr.Username), + Format.Bold(beforeVch.Name ?? ""))); + } + + if (!string.IsNullOrWhiteSpace(str)) + { + PresenceUpdates.AddOrUpdate(logChannel, + [str], + (_, list) => + { + list.Add(str); + return list; + }); + } + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_UserLeft(SocketGuild guild, SocketUser usr) + { + _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting) + || logSetting.UserLeftId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserLeft)) is null) + return; + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left)) + .WithDescription(usr.ToString()) + .AddField("Id", usr.Id.ToString()) + .WithFooter(CurrentTime(guild)); + + if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute)) + embed.WithThumbnailUrl(usr.GetAvatarUrl()); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_UserJoined(IGuildUser usr) + { + _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting) || logSetting.UserJoinedId is null) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) is null) + return; + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("✅ " + GetText(logChannel.Guild, strs.user_joined)) + .WithDescription($"{usr.Mention} `{usr}`") + .AddField("Id", usr.Id.ToString()) + .AddField(GetText(logChannel.Guild, strs.joined_server), + $"{usr.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "?"}", + true) + .AddField(GetText(logChannel.Guild, strs.joined_discord), + $"{usr.CreatedAt:dd.MM.yyyy HH:mm}", + true) + .WithFooter(CurrentTime(usr.Guild)); + + if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute)) + embed.WithThumbnailUrl(usr.GetAvatarUrl()); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_UserUnbanned(IUser usr, IGuild guild) + { + _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting) + || logSetting.UserUnbannedId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) is null) + return; + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("♻️ " + GetText(logChannel.Guild, strs.user_unbanned)) + .WithDescription(usr.ToString()!) + .AddField("Id", usr.Id.ToString()) + .WithFooter(CurrentTime(guild)); + + if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute)) + embed.WithThumbnailUrl(usr.GetAvatarUrl()); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_UserBanned(IUser usr, IGuild guild) + { + _ = Task.Run(async () => + { + try + { + if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting) + || logSetting.UserBannedId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null) + return; + + + string? reason = null; + try + { + var ban = await guild.GetBanAsync(usr); + reason = ban?.Reason; + } + catch + { + } + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("🚫 " + GetText(logChannel.Guild, strs.user_banned)) + .WithDescription(usr.ToString()!) + .AddField("Id", usr.Id.ToString()) + .AddField("Reason", string.IsNullOrWhiteSpace(reason) ? "-" : reason) + .WithFooter(CurrentTime(guild)); + + var avatarUrl = usr.GetAvatarUrl(); + + if (Uri.IsWellFormedUriString(avatarUrl, UriKind.Absolute)) + embed.WithThumbnailUrl(usr.GetAvatarUrl()); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_MessageDeleted(Cacheable optMsg, Cacheable optCh) + { + _ = Task.Run(async () => + { + try + { + if (optMsg.Value is not IUserMessage msg || msg.IsAuthor(_client)) + return; + + if (_ignoreMessageIds.Contains(msg.Id)) + return; + + var ch = optCh.Value; + if (ch is not ITextChannel channel) + return; + + if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out var logSetting) + || logSetting.MessageDeletedId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == channel.Id && ilc.ItemType == IgnoredItemType.Channel)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageDeleted)) is null + || logChannel.Id == msg.Id) + return; + + var resolvedMessage = msg.Resolve(TagHandling.FullName); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("🗑 " + + GetText(logChannel.Guild, strs.msg_del(((ITextChannel)msg.Channel).Name))) + .WithDescription(msg.Author.ToString()!) + .AddField(GetText(logChannel.Guild, strs.content), + string.IsNullOrWhiteSpace(resolvedMessage) ? "-" : resolvedMessage) + .AddField("Id", msg.Id.ToString()) + .WithFooter(CurrentTime(channel.Guild)); + if (msg.Attachments.Any()) + { + embed.AddField(GetText(logChannel.Guild, strs.attachments), + string.Join(", ", msg.Attachments.Select(a => a.Url))); + } + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch (Exception) + { + // ignored + } + }); + return Task.CompletedTask; + } + + private Task _client_MessageUpdated( + Cacheable optmsg, + SocketMessage imsg2, + ISocketMessageChannel ch) + { + _ = Task.Run(async () => + { + try + { + if (imsg2 is not IUserMessage after || after.IsAuthor(_client)) + return; + + if ((optmsg.HasValue ? optmsg.Value : null) is not IUserMessage before) + return; + + if (ch is not ITextChannel channel) + return; + + if (before.Content == after.Content) + return; + + if (before.Author.IsBot) + return; + + if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out var logSetting) + || logSetting.MessageUpdatedId is null + || logSetting.LogIgnores.Any(ilc + => ilc.LogItemId == channel.Id && ilc.ItemType == IgnoredItemType.Channel)) + return; + + ITextChannel? logChannel; + if ((logChannel = await TryGetLogChannel(channel.Guild, logSetting, LogType.MessageUpdated)) is null + || logChannel.Id == after.Channel.Id) + return; + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("📝 " + + GetText(logChannel.Guild, + strs.msg_update(((ITextChannel)after.Channel).Name))) + .WithDescription(after.Author.ToString()!) + .AddField(GetText(logChannel.Guild, strs.old_msg), + string.IsNullOrWhiteSpace(before.Content) + ? "-" + : before.Resolve(TagHandling.FullName)) + .AddField(GetText(logChannel.Guild, strs.new_msg), + string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(TagHandling.FullName)) + .AddField("Id", after.Id.ToString()) + .WithFooter(CurrentTime(channel.Guild)); + + await _sender.Response(logChannel).Embed(embed).SendAsync(); + } + catch + { + // ignored + } + }); + return Task.CompletedTask; + } + + private async Task TryGetLogChannel(IGuild guild, LogSetting logSetting, LogType logChannelType) + { + ulong? id = null; + switch (logChannelType) + { + case LogType.Other: + id = logSetting.LogOtherId; + break; + case LogType.MessageUpdated: + id = logSetting.MessageUpdatedId; + break; + case LogType.MessageDeleted: + id = logSetting.MessageDeletedId; + break; + case LogType.UserJoined: + id = logSetting.UserJoinedId; + break; + case LogType.UserLeft: + id = logSetting.UserLeftId; + break; + case LogType.UserBanned: + id = logSetting.UserBannedId; + break; + case LogType.UserUnbanned: + id = logSetting.UserUnbannedId; + break; + case LogType.UserUpdated: + id = logSetting.UserUpdatedId; + break; + case LogType.ChannelCreated: + id = logSetting.ChannelCreatedId; + break; + case LogType.ChannelDestroyed: + id = logSetting.ChannelDestroyedId; + break; + case LogType.ChannelUpdated: + id = logSetting.ChannelUpdatedId; + break; + case LogType.UserPresence: + id = logSetting.LogUserPresenceId; + break; + case LogType.VoicePresence: + id = logSetting.LogVoicePresenceId; + break; + case LogType.UserMuted: + id = logSetting.UserMutedId; + break; + case LogType.UserWarned: + id = logSetting.LogWarnsId; + break; + case LogType.ThreadCreated: + id = logSetting.ThreadCreatedId; + break; + case LogType.ThreadDeleted: + id = logSetting.ThreadDeletedId; + break; + } + + if (id is null or 0) + { + UnsetLogSetting(guild.Id, logChannelType); + return null; + } + + var channel = await guild.GetTextChannelAsync(id.Value); + + if (channel is null) + { + UnsetLogSetting(guild.Id, logChannelType); + return null; + } + + return channel; + } + + private void UnsetLogSetting(ulong guildId, LogType logChannelType) + { + using var uow = _db.GetDbContext(); + var newLogSetting = uow.LogSettingsFor(guildId); + switch (logChannelType) + { + case LogType.Other: + newLogSetting.LogOtherId = null; + break; + case LogType.MessageUpdated: + newLogSetting.MessageUpdatedId = null; + break; + case LogType.MessageDeleted: + newLogSetting.MessageDeletedId = null; + break; + case LogType.UserJoined: + newLogSetting.UserJoinedId = null; + break; + case LogType.UserLeft: + newLogSetting.UserLeftId = null; + break; + case LogType.UserBanned: + newLogSetting.UserBannedId = null; + break; + case LogType.UserUnbanned: + newLogSetting.UserUnbannedId = null; + break; + case LogType.UserUpdated: + newLogSetting.UserUpdatedId = null; + break; + case LogType.UserMuted: + newLogSetting.UserMutedId = null; + break; + case LogType.ChannelCreated: + newLogSetting.ChannelCreatedId = null; + break; + case LogType.ChannelDestroyed: + newLogSetting.ChannelDestroyedId = null; + break; + case LogType.ChannelUpdated: + newLogSetting.ChannelUpdatedId = null; + break; + case LogType.UserPresence: + newLogSetting.LogUserPresenceId = null; + break; + case LogType.VoicePresence: + newLogSetting.LogVoicePresenceId = null; + break; + case LogType.UserWarned: + newLogSetting.LogWarnsId = null; + break; + } + + GuildLogSettings.AddOrUpdate(guildId, newLogSetting, (_, _) => newLogSetting); + uow.SaveChanges(); + } +} diff --git a/src/EllieBot/Modules/Administration/ServerLog/ServerLogCommands.cs b/src/EllieBot/Modules/Administration/ServerLog/ServerLogCommands.cs new file mode 100644 index 0000000..1632da5 --- /dev/null +++ b/src/EllieBot/Modules/Administration/ServerLog/ServerLogCommands.cs @@ -0,0 +1,175 @@ +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + [NoPublicBot] + public partial class LogCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task LogServer(PermissionAction action) + { + await _service.LogServer(ctx.Guild.Id, ctx.Channel.Id, action.Value); + if (action.Value) + await Response().Confirm(strs.log_all).SendAsync(); + else + await Response().Confirm(strs.log_disabled).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task LogIgnore() + { + var settings = _service.GetGuildLogSettings(ctx.Guild.Id); + + var chs = settings?.LogIgnores.Where(x => x.ItemType == IgnoredItemType.Channel).ToList() + ?? new List(); + var usrs = settings?.LogIgnores.Where(x => x.ItemType == IgnoredItemType.User).ToList() + ?? new List(); + + var eb = _sender.CreateEmbed() + .WithOkColor() + .AddField(GetText(strs.log_ignored_channels), + chs.Count == 0 + ? "-" + : string.Join('\n', chs.Select(x => $"{x.LogItemId} | <#{x.LogItemId}>"))) + .AddField(GetText(strs.log_ignored_users), + usrs.Count == 0 + ? "-" + : string.Join('\n', usrs.Select(x => $"{x.LogItemId} | <@{x.LogItemId}>"))); + + await Response().Embed(eb).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task LogIgnore([Leftover] ITextChannel target) + { + var removed = _service.LogIgnore(ctx.Guild.Id, target.Id, IgnoredItemType.Channel); + + if (!removed) + { + await Response() + .Confirm( + strs.log_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")"))) + .SendAsync(); + } + else + { + await Response() + .Confirm( + strs.log_not_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")"))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task LogIgnore([Leftover] IUser target) + { + var removed = _service.LogIgnore(ctx.Guild.Id, target.Id, IgnoredItemType.User); + + if (!removed) + { + await Response() + .Confirm(strs.log_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")"))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.log_not_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")"))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task LogEvents() + { + var logSetting = _service.GetGuildLogSettings(ctx.Guild.Id); + var str = string.Join("\n", + Enum.GetNames() + .Select(x => + { + var val = logSetting is null ? null : GetLogProperty(logSetting, Enum.Parse(x)); + if (val is not null) + return $"{Format.Bold(x)} <#{val}>"; + return Format.Bold(x); + })); + + await Response().Confirm(Format.Bold(GetText(strs.log_events)) + "\n" + str).SendAsync(); + } + + private static ulong? GetLogProperty(LogSetting l, LogType type) + { + switch (type) + { + case LogType.Other: + return l.LogOtherId; + case LogType.MessageUpdated: + return l.MessageUpdatedId; + case LogType.MessageDeleted: + return l.MessageDeletedId; + case LogType.UserJoined: + return l.UserJoinedId; + case LogType.UserLeft: + return l.UserLeftId; + case LogType.UserBanned: + return l.UserBannedId; + case LogType.UserUnbanned: + return l.UserUnbannedId; + case LogType.UserUpdated: + return l.UserUpdatedId; + case LogType.ChannelCreated: + return l.ChannelCreatedId; + case LogType.ChannelDestroyed: + return l.ChannelDestroyedId; + case LogType.ChannelUpdated: + return l.ChannelUpdatedId; + case LogType.UserPresence: + return l.LogUserPresenceId; + case LogType.VoicePresence: + return l.LogVoicePresenceId; + case LogType.UserMuted: + return l.UserMutedId; + case LogType.UserWarned: + return l.LogWarnsId; + case LogType.ThreadDeleted: + return l.ThreadDeletedId; + case LogType.ThreadCreated: + return l.ThreadCreatedId; + default: + return null; + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [OwnerOnly] + public async Task Log(LogType type) + { + var val = _service.Log(ctx.Guild.Id, ctx.Channel.Id, type); + + if (val) + await Response().Confirm(strs.log(Format.Bold(type.ToString()))).SendAsync(); + else + await Response().Confirm(strs.log_stop(Format.Bold(type.ToString()))).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Timezone/GuildTimezoneService.cs b/src/EllieBot/Modules/Administration/Timezone/GuildTimezoneService.cs new file mode 100644 index 0000000..e1f2fea --- /dev/null +++ b/src/EllieBot/Modules/Administration/Timezone/GuildTimezoneService.cs @@ -0,0 +1,95 @@ +#nullable disable +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Common.ModuleBehaviors; + +namespace EllieBot.Modules.Administration.Services; + +public sealed class GuildTimezoneService : ITimezoneService, IReadyExecutor, IEService +{ + private readonly ConcurrentDictionary _timezones; + private readonly DbService _db; + private readonly IReplacementPatternStore _repStore; + + public GuildTimezoneService(IBot bot, DbService db, IReplacementPatternStore repStore) + { + _timezones = bot.AllGuildConfigs.Select(GetTimzezoneTuple) + .Where(x => x.Timezone is not null) + .ToDictionary(x => x.GuildId, x => x.Timezone) + .ToConcurrent(); + + _db = db; + _repStore = repStore; + + bot.JoinedGuild += Bot_JoinedGuild; + } + + private Task Bot_JoinedGuild(GuildConfig arg) + { + var (guildId, tz) = GetTimzezoneTuple(arg); + if (tz is not null) + _timezones.TryAdd(guildId, tz); + return Task.CompletedTask; + } + + private static (ulong GuildId, TimeZoneInfo Timezone) GetTimzezoneTuple(GuildConfig x) + { + TimeZoneInfo tz; + try + { + if (x.TimeZoneId is null) + tz = null; + else + tz = TimeZoneInfo.FindSystemTimeZoneById(x.TimeZoneId); + } + catch + { + tz = null; + } + + return (x.GuildId, Timezone: tz); + } + + public TimeZoneInfo GetTimeZoneOrDefault(ulong? guildId) + { + if (guildId is ulong gid && _timezones.TryGetValue(gid, out var tz)) + return tz; + + return null; + } + + public void SetTimeZone(ulong guildId, TimeZoneInfo tz) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + + gc.TimeZoneId = tz?.Id; + uow.SaveChanges(); + + if (tz is null) + _timezones.TryRemove(guildId, out tz); + else + _timezones.AddOrUpdate(guildId, tz, (_, _) => tz); + } + + public TimeZoneInfo GetTimeZoneOrUtc(ulong? guildId) + => GetTimeZoneOrDefault(guildId) ?? TimeZoneInfo.Utc; + + public Task OnReadyAsync() + { + _repStore.Register("%server.time%", + (IGuild g) => + { + var to = TimeZoneInfo.Local; + if (g is not null) + { + to = GetTimeZoneOrDefault(g.Id) ?? TimeZoneInfo.Local; + } + + return TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Utc, to).ToString("HH:mm ") + + to.StandardName.GetInitials(); + }); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Timezone/TimeZoneCommands.cs b/src/EllieBot/Modules/Administration/Timezone/TimeZoneCommands.cs new file mode 100644 index 0000000..a05789d --- /dev/null +++ b/src/EllieBot/Modules/Administration/Timezone/TimeZoneCommands.cs @@ -0,0 +1,78 @@ +#nullable disable +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class TimeZoneCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Timezones(int page = 1) + { + page--; + + if (page is < 0 or > 20) + return; + + var timezones = TimeZoneInfo.GetSystemTimeZones().OrderBy(x => x.BaseUtcOffset).ToArray(); + var timezonesPerPage = 20; + + var curTime = DateTimeOffset.UtcNow; + + var i = 0; + var timezoneStrings = timezones.Select(x => (x, ++i % 2 == 0)) + .Select(data => + { + var (tzInfo, flip) = data; + var nameStr = $"{tzInfo.Id,-30}"; + var offset = curTime.ToOffset(tzInfo.GetUtcOffset(curTime)) + .ToString("zzz"); + if (flip) + return $"{offset} {Format.Code(nameStr)}"; + return $"{Format.Code(offset)} {nameStr}"; + }) + .ToList(); + + + await Response() + .Paginated() + .Items(timezoneStrings) + .PageSize(timezonesPerPage) + .CurrentPage(page) + .Page((items, _) => _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.timezones_available)) + .WithDescription(string.Join("\n", items))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Timezone() + => await Response().Confirm(strs.timezone_guild(_service.GetTimeZoneOrUtc(ctx.Guild.Id))).SendAsync(); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task Timezone([Leftover] string id) + { + TimeZoneInfo tz; + try { tz = TimeZoneInfo.FindSystemTimeZoneById(id); } + catch { tz = null; } + + + if (tz is null) + { + await Response().Error(strs.timezone_not_found).SendAsync(); + return; + } + + _service.SetTimeZone(ctx.Guild.Id, tz); + + await Response().Confirm(tz.ToString()).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/UserPunish/UserPunishCommands.cs b/src/EllieBot/Modules/Administration/UserPunish/UserPunishCommands.cs new file mode 100644 index 0000000..27a3f12 --- /dev/null +++ b/src/EllieBot/Modules/Administration/UserPunish/UserPunishCommands.cs @@ -0,0 +1,960 @@ +#nullable disable +using CommandLine; +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Modules.Administration.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class UserPunishCommands : EllieModule + { + public enum AddRole + { + AddRole + } + + private readonly MuteService _mute; + + public UserPunishCommands(MuteService mute) + { + _mute = mute; + } + + private async Task CheckRoleHierarchy(IGuildUser target) + { + var curUser = ((SocketGuild)ctx.Guild).CurrentUser; + var ownerId = ctx.Guild.OwnerId; + var modMaxRole = ((IGuildUser)ctx.User).GetRoles().Max(r => r.Position); + var targetMaxRole = target.GetRoles().Max(r => r.Position); + var botMaxRole = curUser.GetRoles().Max(r => r.Position); + // bot can't punish a user who is higher in the hierarchy. Discord will return 403 + // moderator can be owner, in which case role hierarchy doesn't matter + // otherwise, moderator has to have a higher role + if (botMaxRole <= targetMaxRole + || (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole) + || target.Id == ownerId) + { + await Response().Error(strs.hierarchy).SendAsync(); + return false; + } + + return true; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public Task Warn(IGuildUser user, [Leftover] string reason = null) + => Warn(1, user, reason); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public async Task Warn(int weight, IGuildUser user, [Leftover] string reason = null) + { + if (weight <= 0) + return; + + if (!await CheckRoleHierarchy(user)) + return; + + var dmFailed = false; + try + { + await _sender.Response(user) + .Embed(_sender.CreateEmbed() + .WithErrorColor() + .WithDescription(GetText(strs.warned_on(ctx.Guild.ToString()))) + .AddField(GetText(strs.moderator), ctx.User.ToString()) + .AddField(GetText(strs.reason), reason ?? "-")) + .SendAsync(); + } + catch + { + dmFailed = true; + } + + WarningPunishment punishment; + try + { + punishment = await _service.Warn(ctx.Guild, user.Id, ctx.User, weight, reason); + } + catch (Exception ex) + { + Log.Warning(ex, "Exception occured while warning a user"); + var errorEmbed = _sender.CreateEmbed().WithErrorColor() + .WithDescription(GetText(strs.cant_apply_punishment)); + + if (dmFailed) + errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(errorEmbed).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed().WithOkColor(); + if (punishment is null) + embed.WithDescription(GetText(strs.user_warned(Format.Bold(user.ToString())))); + else + { + embed.WithDescription(GetText(strs.user_warned_and_punished(Format.Bold(user.ToString()), + Format.Bold(punishment.Punishment.ToString())))); + } + + if (dmFailed) + embed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [EllieOptions] + [Priority(1)] + public async Task WarnExpire() + { + var expireDays = await _service.GetWarnExpire(ctx.Guild.Id); + + if (expireDays == 0) + await Response().Confirm(strs.warns_dont_expire).SendAsync(); + else + await Response().Error(strs.warns_expire_in(expireDays)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [EllieOptions] + [Priority(2)] + public async Task WarnExpire(int days, params string[] args) + { + if (days is < 0 or > 366) + return; + + var opts = OptionsParser.ParseFrom(args); + + await ctx.Channel.TriggerTypingAsync(); + + await _service.WarnExpireAsync(ctx.Guild.Id, days, opts.Delete); + if (days == 0) + { + await Response().Confirm(strs.warn_expire_reset).SendAsync(); + return; + } + + if (opts.Delete) + await Response().Confirm(strs.warn_expire_set_delete(Format.Bold(days.ToString()))).SendAsync(); + else + await Response().Confirm(strs.warn_expire_set_clear(Format.Bold(days.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [Priority(2)] + public Task Warnlog(int page, [Leftover] IGuildUser user = null) + { + user ??= (IGuildUser)ctx.User; + + return Warnlog(page, user.Id); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(3)] + public Task Warnlog(IGuildUser user = null) + { + user ??= (IGuildUser)ctx.User; + + return ctx.User.Id == user.Id || ((IGuildUser)ctx.User).GuildPermissions.BanMembers + ? Warnlog(user.Id) + : Task.CompletedTask; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [Priority(0)] + public Task Warnlog(int page, ulong userId) + => InternalWarnlog(userId, page - 1); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [Priority(1)] + public Task Warnlog(ulong userId) + => InternalWarnlog(userId, 0); + + private async Task InternalWarnlog(ulong userId, int inputPage) + { + if (inputPage < 0) + return; + + var allWarnings = _service.UserWarnings(ctx.Guild.Id, userId); + + await Response() + .Paginated() + .Items(allWarnings) + .PageSize(9) + .CurrentPage(inputPage) + .Page((warnings, page) => + { + var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString(); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.warnlog_for(user))); + + if (!warnings.Any()) + embed.WithDescription(GetText(strs.warnings_none)); + else + { + var descText = GetText(strs.warn_count( + Format.Bold(warnings.Where(x => !x.Forgiven).Sum(x => x.Weight).ToString()), + Format.Bold(warnings.Sum(x => x.Weight).ToString()))); + + embed.WithDescription(descText); + + var i = page * 9; + foreach (var w in warnings) + { + i++; + var name = GetText(strs.warned_on_by(w.DateAdded?.ToString("dd.MM.yyy"), + w.DateAdded?.ToString("HH:mm"), + w.Moderator)); + + if (w.Forgiven) + name = $"{Format.Strikethrough(name)} {GetText(strs.warn_cleared_by(w.ForgivenBy))}"; + + + embed.AddField($"#`{i}` " + name, + Format.Code(GetText(strs.warn_weight(w.Weight))) + '\n' + w.Reason.TrimTo(1000)); + } + } + + return embed; + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public async Task WarnlogAll(int page = 1) + { + if (--page < 0) + return; + var allWarnings = _service.WarnlogAll(ctx.Guild.Id); + + await Response() + .Paginated() + .Items(allWarnings) + .PageSize(15) + .CurrentPage(page) + .Page((warnings, _) => + { + var ws = warnings + .Select(x => + { + var all = x.Count(); + var forgiven = x.Count(y => y.Forgiven); + var total = all - forgiven; + var usr = ((SocketGuild)ctx.Guild).GetUser(x.Key); + return (usr?.ToString() ?? x.Key.ToString()) + + $" | {total} ({all} - {forgiven})"; + }); + + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.warnings_list)) + .WithDescription(string.Join("\n", ws)); + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public Task Warnclear(IGuildUser user, int index = 0) + => Warnclear(user.Id, index); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public async Task Warnclear(ulong userId, int index = 0) + { + if (index < 0) + return; + var success = await _service.WarnClearAsync(ctx.Guild.Id, userId, index, ctx.User.ToString()); + var userStr = Format.Bold((ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()); + if (index == 0) + await Response().Error(strs.warnings_cleared(userStr)).SendAsync(); + else + { + if (success) + await Response().Confirm(strs.warning_cleared(Format.Bold(index.ToString()), userStr)).SendAsync(); + else + await Response().Error(strs.warning_clear_fail).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [Priority(1)] + public async Task WarnPunish( + int number, + AddRole _, + IRole role, + StoopidTime time = null) + { + var punish = PunishmentAction.AddRole; + + if (ctx.Guild.OwnerId != ctx.User.Id + && role.Position >= ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position)) + { + await Response().Error(strs.role_too_high).SendAsync(); + return; + } + + var success = _service.WarnPunish(ctx.Guild.Id, number, punish, time, role); + + if (!success) + return; + + if (time is null) + { + await Response() + .Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()), + Format.Bold(number.ToString()))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()), + Format.Bold(number.ToString()), + Format.Bold(time.Input))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public async Task WarnPunish(int number, PunishmentAction punish, StoopidTime time = null) + { + // this should never happen. Addrole has its own method with higher priority + // also disallow warn punishment for getting warned + if (punish is PunishmentAction.AddRole or PunishmentAction.Warn) + return; + + // you must specify the time for timeout + if (punish is PunishmentAction.TimeOut && time is null) + return; + + var success = _service.WarnPunish(ctx.Guild.Id, number, punish, time); + + if (!success) + return; + + if (time is null) + { + await Response() + .Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()), + Format.Bold(number.ToString()))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()), + Format.Bold(number.ToString()), + Format.Bold(time.Input))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + public async Task WarnPunish(int number) + { + if (!_service.WarnPunishRemove(ctx.Guild.Id, number)) + return; + + await Response().Confirm(strs.warn_punish_rem(Format.Bold(number.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task WarnPunishList() + { + var ps = _service.WarnPunishList(ctx.Guild.Id); + + string list; + if (ps.Any()) + { + list = string.Join("\n", + ps.Select(x + => $"{x.Count} -> {x.Punishment} {(x.Punishment == PunishmentAction.AddRole ? $"<@&{x.RoleId}>" : "")} {(x.Time <= 0 ? "" : x.Time + "m")} ")); + } + else + list = GetText(strs.warnpl_none); + + await Response().Confirm(GetText(strs.warn_punish_list), list).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Priority(1)] + public Task Ban(StoopidTime time, IUser user, [Leftover] string msg = null) + => Ban(time, user.Id, msg); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Priority(0)] + public async Task Ban(StoopidTime time, ulong userId, [Leftover] string msg = null) + { + if (time.Time > TimeSpan.FromDays(49)) + return; + + var guildUser = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId); + + + if (guildUser is not null && !await CheckRoleHierarchy(guildUser)) + return; + + var dmFailed = false; + + if (guildUser is not null) + { + try + { + var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg)); + var smartText = + await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time); + if (smartText is not null) + await Response().User(guildUser).Text(smartText).SendAsync(); + } + catch + { + dmFailed = true; + } + } + + var user = await ctx.Client.GetUserAsync(userId); + var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; + await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune); + var toSend = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("⛔️ " + GetText(strs.banned_user)) + .AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true) + .AddField("ID", userId.ToString(), true) + .AddField(GetText(strs.duration), + time.Time.ToPrettyStringHm(), + true); + + if (dmFailed) + toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(toSend).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Priority(0)] + public async Task Ban(ulong userId, [Leftover] string msg = null) + { + var user = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId); + if (user is null) + { + var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; + await ctx.Guild.AddBanAsync(userId, banPrune, (ctx.User + " | " + msg).TrimTo(512)); + + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle("⛔️ " + GetText(strs.banned_user)) + .AddField("ID", userId.ToString(), true)) + .SendAsync(); + } + else + await Ban(user, msg); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Priority(2)] + public async Task Ban(IGuildUser user, [Leftover] string msg = null) + { + if (!await CheckRoleHierarchy(user)) + return; + + var dmFailed = false; + + try + { + var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg)); + var embed = await _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null); + if (embed is not null) + await Response().User(user).Text(embed).SendAsync(); + } + catch + { + dmFailed = true; + } + + var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; + await ctx.Guild.AddBanAsync(user, banPrune, (ctx.User + " | " + msg).TrimTo(512)); + + var toSend = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("⛔️ " + GetText(strs.banned_user)) + .AddField(GetText(strs.username), user.ToString(), true) + .AddField("ID", user.Id.ToString(), true); + + if (dmFailed) + toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(toSend).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + public async Task BanPrune(int days) + { + if (days < 0 || days > 7) + { + await Response().Error(strs.invalid_input).SendAsync(); + return; + } + + await _service.SetBanPruneAsync(ctx.Guild.Id, days); + + if (days == 0) + await Response().Confirm(strs.ban_prune_disabled).SendAsync(); + else + await Response().Confirm(strs.ban_prune(days)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + public async Task BanMessage([Leftover] string message = null) + { + if (message is null) + { + var template = _service.GetBanTemplate(ctx.Guild.Id); + if (template is null) + { + await Response().Confirm(strs.banmsg_default).SendAsync(); + return; + } + + await Response().Confirm(template).SendAsync(); + return; + } + + _service.SetBanTemplate(ctx.Guild.Id, message); + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + public async Task BanMsgReset() + { + _service.SetBanTemplate(ctx.Guild.Id, null); + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Priority(0)] + public Task BanMessageTest([Leftover] string reason = null) + => InternalBanMessageTest(reason, null); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Priority(1)] + public Task BanMessageTest(StoopidTime duration, [Leftover] string reason = null) + => InternalBanMessageTest(reason, duration.Time); + + private async Task InternalBanMessageTest(string reason, TimeSpan? duration) + { + var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason)); + var smartText = await _service.GetBanUserDmEmbed(Context, + (IGuildUser)ctx.User, + defaultMessage, + reason, + duration); + + if (smartText is null) + await Response().Confirm(strs.banmsg_disabled).SendAsync(); + else + { + try + { + await Response().User(ctx.User).Text(smartText).SendAsync(); + } + catch (Exception) + { + await Response().Error(strs.unable_to_dm_user).SendAsync(); + return; + } + + await ctx.OkAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + public async Task Unban([Leftover] string user) + { + var bans = await ctx.Guild.GetBansAsync().FlattenAsync(); + + var bun = bans.FirstOrDefault(x => x.User.ToString()!.ToLowerInvariant() == user.ToLowerInvariant()); + + if (bun is null) + { + await Response().Error(strs.user_not_found).SendAsync(); + return; + } + + await UnbanInternal(bun.User); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + public async Task Unban(ulong userId) + { + var bun = await ctx.Guild.GetBanAsync(userId); + + if (bun is null) + { + await Response().Error(strs.user_not_found).SendAsync(); + return; + } + + await UnbanInternal(bun.User); + } + + private async Task UnbanInternal(IUser user) + { + await ctx.Guild.RemoveBanAsync(user); + + await Response().Confirm(strs.unbanned_user(Format.Bold(user.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.KickMembers | GuildPerm.ManageMessages)] + [BotPerm(GuildPerm.BanMembers)] + public Task Softban(IGuildUser user, [Leftover] string msg = null) + => SoftbanInternal(user, msg); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.KickMembers | GuildPerm.ManageMessages)] + [BotPerm(GuildPerm.BanMembers)] + public async Task Softban(ulong userId, [Leftover] string msg = null) + { + var user = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId); + if (user is null) + return; + + await SoftbanInternal(user, msg); + } + + private async Task SoftbanInternal(IGuildUser user, [Leftover] string msg = null) + { + if (!await CheckRoleHierarchy(user)) + return; + + var dmFailed = false; + + try + { + await Response() + .Channel(await user.CreateDMChannelAsync()) + .Error(strs.sbdm(Format.Bold(ctx.Guild.Name), msg)) + .SendAsync(); + } + catch + { + dmFailed = true; + } + + var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; + await ctx.Guild.AddBanAsync(user, banPrune, ("Softban | " + ctx.User + " | " + msg).TrimTo(512)); + try { await ctx.Guild.RemoveBanAsync(user); } + catch { await ctx.Guild.RemoveBanAsync(user); } + + var toSend = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("☣ " + GetText(strs.sb_user)) + .AddField(GetText(strs.username), user.ToString(), true) + .AddField("ID", user.Id.ToString(), true); + + if (dmFailed) + toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(toSend).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.KickMembers)] + [BotPerm(GuildPerm.KickMembers)] + [Priority(1)] + public Task Kick(IGuildUser user, [Leftover] string msg = null) + => KickInternal(user, msg); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.KickMembers)] + [BotPerm(GuildPerm.KickMembers)] + [Priority(0)] + public async Task Kick(ulong userId, [Leftover] string msg = null) + { + var user = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId); + if (user is null) + return; + + await KickInternal(user, msg); + } + + private async Task KickInternal(IGuildUser user, string msg = null) + { + if (!await CheckRoleHierarchy(user)) + return; + + var dmFailed = false; + + try + { + await Response() + .Channel(await user.CreateDMChannelAsync()) + .Error(GetText(strs.kickdm(Format.Bold(ctx.Guild.Name), msg))) + .SendAsync(); + } + catch + { + dmFailed = true; + } + + await user.KickAsync((ctx.User + " | " + msg).TrimTo(512)); + + var toSend = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.kicked_user)) + .AddField(GetText(strs.username), user.ToString(), true) + .AddField("ID", user.Id.ToString(), true); + + if (dmFailed) + toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(toSend).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ModerateMembers)] + [BotPerm(GuildPerm.ModerateMembers)] + [Priority(2)] + public async Task Timeout(IUser globalUser, StoopidTime time, [Leftover] string msg = null) + { + var user = await ctx.Guild.GetUserAsync(globalUser.Id); + + if (user is null) + return; + + if (!await CheckRoleHierarchy(user)) + return; + + var dmFailed = false; + + try + { + var dmMessage = GetText(strs.timeoutdm(Format.Bold(ctx.Guild.Name), msg)); + await _sender.Response(user) + .Embed(_sender.CreateEmbed() + .WithPendingColor() + .WithDescription(dmMessage)) + .SendAsync(); + } + catch + { + dmFailed = true; + } + + await user.SetTimeOutAsync(time.Time); + + var toSend = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("⏳ " + GetText(strs.timedout_user)) + .AddField(GetText(strs.username), user.ToString(), true) + .AddField("ID", user.Id.ToString(), true); + + if (dmFailed) + toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); + + await Response().Embed(toSend).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [Ratelimit(30)] + public async Task MassBan(params string[] userStrings) + { + if (userStrings.Length == 0) + return; + + var missing = new List(); + var banning = new HashSet(); + + await ctx.Channel.TriggerTypingAsync(); + foreach (var userStr in userStrings) + { + if (ulong.TryParse(userStr, out var userId)) + { + IUser user = await ctx.Guild.GetUserAsync(userId) + ?? await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, + userId); + + if (user is null) + { + // if IGuildUser is null, try to get IUser + user = await ((DiscordSocketClient)Context.Client).Rest.GetUserAsync(userId); + + // only add to missing if *still* null + if (user is null) + { + missing.Add(userStr); + continue; + } + } + + //Hierachy checks only if the user is in the guild + if (user is IGuildUser gu && !await CheckRoleHierarchy(gu)) + return; + + banning.Add(user); + } + else + missing.Add(userStr); + } + + var missStr = string.Join("\n", missing); + if (string.IsNullOrWhiteSpace(missStr)) + missStr = "-"; + + var toSend = _sender.CreateEmbed() + .WithDescription(GetText(strs.mass_ban_in_progress(banning.Count))) + .AddField(GetText(strs.invalid(missing.Count)), missStr) + .WithPendingColor(); + + var banningMessage = await Response().Embed(toSend).SendAsync(); + + var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; + foreach (var toBan in banning) + { + try + { + await ctx.Guild.AddBanAsync(toBan.Id, banPrune, $"{ctx.User} | Massban"); + } + catch (Exception ex) + { + Log.Warning(ex, "Error banning {User} user in {GuildId} server", toBan.Id, ctx.Guild.Id); + } + } + + await banningMessage.ModifyAsync(x => x.Embed = _sender.CreateEmbed() + .WithDescription( + GetText(strs.mass_ban_completed(banning.Count()))) + .AddField(GetText(strs.invalid(missing.Count)), missStr) + .WithOkColor() + .Build()); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.BanMembers)] + [BotPerm(GuildPerm.BanMembers)] + [OwnerOnly] + public async Task MassKill([Leftover] string people) + { + if (string.IsNullOrWhiteSpace(people)) + return; + + var (bans, missing) = _service.MassKill((SocketGuild)ctx.Guild, people); + + var missStr = string.Join("\n", missing); + if (string.IsNullOrWhiteSpace(missStr)) + missStr = "-"; + + //send a message but don't wait for it + var banningMessageTask = Response() + .Embed(_sender.CreateEmbed() + .WithDescription( + GetText(strs.mass_kill_in_progress(bans.Count()))) + .AddField(GetText(strs.invalid(missing)), missStr) + .WithPendingColor()) + .SendAsync(); + + var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; + //do the banning + await Task.WhenAll(bans.Where(x => x.Id.HasValue) + .Select(x => ctx.Guild.AddBanAsync(x.Id.Value, + banPrune, + x.Reason, + new() + { + RetryMode = RetryMode.AlwaysRetry + }))); + + //wait for the message and edit it + var banningMessage = await banningMessageTask; + + await banningMessage.ModifyAsync(x => x.Embed = _sender.CreateEmbed() + .WithDescription( + GetText(strs.mass_kill_completed(bans.Count()))) + .AddField(GetText(strs.invalid(missing)), missStr) + .WithOkColor() + .Build()); + } + + public class WarnExpireOptions : IEllieCommandOptions + { + [Option('d', "delete", Default = false, HelpText = "Delete warnings instead of clearing them.")] + public bool Delete { get; set; } = false; + + public void NormalizeOptions() + { + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/UserPunish/UserPunishService.cs b/src/EllieBot/Modules/Administration/UserPunish/UserPunishService.cs new file mode 100644 index 0000000..cdc9900 --- /dev/null +++ b/src/EllieBot/Modules/Administration/UserPunish/UserPunishService.cs @@ -0,0 +1,597 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Db; +using EllieBot.Modules.Permissions.Services; +using EllieBot.Db.Models; +using Newtonsoft.Json; + +namespace EllieBot.Modules.Administration.Services; + +public class UserPunishService : IEService, IReadyExecutor +{ + private readonly MuteService _mute; + private readonly DbService _db; + private readonly BlacklistService _blacklistService; + private readonly BotConfigService _bcs; + private readonly DiscordSocketClient _client; + private readonly IReplacementService _repSvc; + + public event Func OnUserWarned = static delegate { return Task.CompletedTask; }; + + public UserPunishService( + MuteService mute, + DbService db, + BlacklistService blacklistService, + BotConfigService bcs, + DiscordSocketClient client, + IReplacementService repSvc) + { + _mute = mute; + _db = db; + _blacklistService = blacklistService; + _bcs = bcs; + _client = client; + _repSvc = repSvc; + } + + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + using var expiryTimer = new PeriodicTimer(TimeSpan.FromHours(12)); + do + { + try + { + await CheckAllWarnExpiresAsync(); + } + catch (Exception ex) + { + Log.Error(ex, "Unexpected error while checking for warn expiries: {ErrorMessage}", ex.Message); + } + } while (await expiryTimer.WaitForNextTickAsync()); + } + + public async Task Warn( + IGuild guild, + ulong userId, + IUser mod, + long weight, + string reason) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(weight); + + var modName = mod.ToString(); + + if (string.IsNullOrWhiteSpace(reason)) + reason = "-"; + + var guildId = guild.Id; + + var warn = new Warning + { + UserId = userId, + GuildId = guildId, + Forgiven = false, + Reason = reason, + Moderator = modName, + Weight = weight + }; + + long previousCount; + List ps; + await using (var uow = _db.GetDbContext()) + { + ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments; + + previousCount = uow.Set().ForId(guildId, userId) + .Where(w => !w.Forgiven && w.UserId == userId) + .Sum(x => x.Weight); + + uow.Set().Add(warn); + + await uow.SaveChangesAsync(); + } + + _ = OnUserWarned(warn); + + var totalCount = previousCount + weight; + + var p = ps.Where(x => x.Count > previousCount && x.Count <= totalCount) + .MaxBy(x => x.Count); + + if (p is not null) + { + var user = await guild.GetUserAsync(userId); + if (user is null) + return null; + + await ApplyPunishment(guild, user, mod, p.Punishment, p.Time, p.RoleId, "Warned too many times."); + return p; + } + + return null; + } + + public async Task ApplyPunishment( + IGuild guild, + IGuildUser user, + IUser mod, + PunishmentAction p, + int minutes, + ulong? roleId, + string reason) + { + if (!await CheckPermission(guild, p)) + return; + + int banPrune; + switch (p) + { + case PunishmentAction.Mute: + if (minutes == 0) + await _mute.MuteUser(user, mod, reason: reason); + else + await _mute.TimedMute(user, mod, TimeSpan.FromMinutes(minutes), reason: reason); + break; + case PunishmentAction.VoiceMute: + if (minutes == 0) + await _mute.MuteUser(user, mod, MuteType.Voice, reason); + else + await _mute.TimedMute(user, mod, TimeSpan.FromMinutes(minutes), MuteType.Voice, reason); + break; + case PunishmentAction.ChatMute: + if (minutes == 0) + await _mute.MuteUser(user, mod, MuteType.Chat, reason); + else + await _mute.TimedMute(user, mod, TimeSpan.FromMinutes(minutes), MuteType.Chat, reason); + break; + case PunishmentAction.Kick: + await user.KickAsync(reason); + break; + case PunishmentAction.Ban: + banPrune = await GetBanPruneAsync(user.GuildId) ?? 7; + if (minutes == 0) + await guild.AddBanAsync(user, reason: reason, pruneDays: banPrune); + else + await _mute.TimedBan(user.Guild, user.Id, TimeSpan.FromMinutes(minutes), reason, banPrune); + break; + case PunishmentAction.Softban: + banPrune = await GetBanPruneAsync(user.GuildId) ?? 7; + await guild.AddBanAsync(user, banPrune, $"Softban | {reason}"); + try + { + await guild.RemoveBanAsync(user); + } + catch + { + await guild.RemoveBanAsync(user); + } + + break; + case PunishmentAction.RemoveRoles: + await user.RemoveRolesAsync(user.GetRoles().Where(x => !x.IsManaged && x != x.Guild.EveryoneRole)); + break; + case PunishmentAction.AddRole: + if (roleId is null) + return; + var role = guild.GetRole(roleId.Value); + if (role is not null) + { + if (minutes == 0) + await user.AddRoleAsync(role); + else + await _mute.TimedRole(user, TimeSpan.FromMinutes(minutes), reason, role); + } + else + { + Log.Warning("Can't find role {RoleId} on server {GuildId} to apply punishment", + roleId.Value, + guild.Id); + } + + break; + case PunishmentAction.Warn: + await Warn(guild, user.Id, mod, 1, reason); + break; + case PunishmentAction.TimeOut: + await user.SetTimeOutAsync(TimeSpan.FromMinutes(minutes)); + break; + } + } + + /// + /// Used to prevent the bot from hitting 403's when it needs to + /// apply punishments with insufficient permissions + /// + /// Guild the punishment is applied in + /// Punishment to apply + /// Whether the bot has sufficient permissions + private async Task CheckPermission(IGuild guild, PunishmentAction punish) + { + var botUser = await guild.GetCurrentUserAsync(); + switch (punish) + { + case PunishmentAction.Mute: + return botUser.GuildPermissions.MuteMembers && botUser.GuildPermissions.ManageRoles; + case PunishmentAction.Kick: + return botUser.GuildPermissions.KickMembers; + case PunishmentAction.Ban: + return botUser.GuildPermissions.BanMembers; + case PunishmentAction.Softban: + return botUser.GuildPermissions.BanMembers; // ban + unban + case PunishmentAction.RemoveRoles: + return botUser.GuildPermissions.ManageRoles; + case PunishmentAction.ChatMute: + return botUser.GuildPermissions.ManageRoles; // adds ellie-mute role + case PunishmentAction.VoiceMute: + return botUser.GuildPermissions.MuteMembers; + case PunishmentAction.AddRole: + return botUser.GuildPermissions.ManageRoles; + case PunishmentAction.TimeOut: + return botUser.GuildPermissions.ModerateMembers; + default: + return true; + } + } + + public async Task CheckAllWarnExpiresAsync() + { + await using var uow = _db.GetDbContext(); + var cleared = await uow.Set() + .Where(x => uow.Set() + .Any(y => y.GuildId == x.GuildId + && y.WarnExpireHours > 0 + && y.WarnExpireAction == WarnExpireAction.Clear) + && x.Forgiven == false + && x.DateAdded + < DateTime.UtcNow.AddHours(-uow.Set() + .Where(y => x.GuildId == y.GuildId) + .Select(y => y.WarnExpireHours) + .First())) + .UpdateAsync(_ => new() + { + Forgiven = true, + ForgivenBy = "expiry" + }); + + var deleted = await uow.Set() + .Where(x => uow.Set() + .Any(y => y.GuildId == x.GuildId + && y.WarnExpireHours > 0 + && y.WarnExpireAction == WarnExpireAction.Delete) + && x.DateAdded + < DateTime.UtcNow.AddHours(-uow.Set() + .Where(y => x.GuildId == y.GuildId) + .Select(y => y.WarnExpireHours) + .First())) + .DeleteAsync(); + + if (cleared > 0 || deleted > 0) + { + Log.Information("Cleared {ClearedWarnings} warnings and deleted {DeletedWarnings} warnings due to expiry", + cleared, + deleted); + } + + await uow.SaveChangesAsync(); + } + + public async Task CheckWarnExpiresAsync(ulong guildId) + { + await using var uow = _db.GetDbContext(); + var config = uow.GuildConfigsForId(guildId, inc => inc); + + if (config.WarnExpireHours == 0) + return; + + if (config.WarnExpireAction == WarnExpireAction.Clear) + { + await uow.Set() + .Where(x => x.GuildId == guildId + && x.Forgiven == false + && x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours)) + .UpdateAsync(_ => new() + { + Forgiven = true, + ForgivenBy = "expiry" + }); + } + else if (config.WarnExpireAction == WarnExpireAction.Delete) + { + await uow.Set() + .Where(x => x.GuildId == guildId + && x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours)) + .DeleteAsync(); + } + + await uow.SaveChangesAsync(); + } + + public Task GetWarnExpire(ulong guildId) + { + using var uow = _db.GetDbContext(); + var config = uow.GuildConfigsForId(guildId, set => set); + return Task.FromResult(config.WarnExpireHours / 24); + } + + public async Task WarnExpireAsync(ulong guildId, int days, bool delete) + { + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(guildId, inc => inc); + + config.WarnExpireHours = days * 24; + config.WarnExpireAction = delete ? WarnExpireAction.Delete : WarnExpireAction.Clear; + await uow.SaveChangesAsync(); + + // no need to check for warn expires + if (config.WarnExpireHours == 0) + return; + } + + await CheckWarnExpiresAsync(guildId); + } + + public IGrouping[] WarnlogAll(ulong gid) + { + using var uow = _db.GetDbContext(); + return uow.Set().GetForGuild(gid).GroupBy(x => x.UserId).ToArray(); + } + + public Warning[] UserWarnings(ulong gid, ulong userId) + { + using var uow = _db.GetDbContext(); + return uow.Set().ForId(gid, userId); + } + + public async Task WarnClearAsync( + ulong guildId, + ulong userId, + int index, + string moderator) + { + var toReturn = true; + await using var uow = _db.GetDbContext(); + if (index == 0) + await uow.Set().ForgiveAll(guildId, userId, moderator); + else + toReturn = uow.Set().Forgive(guildId, userId, moderator, index - 1); + await uow.SaveChangesAsync(); + return toReturn; + } + + public bool WarnPunish( + ulong guildId, + int number, + PunishmentAction punish, + StoopidTime time, + IRole role = null) + { + // these 3 don't make sense with time + if (punish is PunishmentAction.Softban or PunishmentAction.Kick or PunishmentAction.RemoveRoles + && time is not null) + return false; + if (number <= 0 || (time is not null && time.Time > TimeSpan.FromDays(49))) + return false; + + if (punish is PunishmentAction.AddRole && role is null) + return false; + + if (punish is PunishmentAction.TimeOut && time is null) + return false; + + using var uow = _db.GetDbContext(); + var ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments; + var toDelete = ps.Where(x => x.Count == number); + + uow.RemoveRange(toDelete); + + ps.Add(new() + { + Count = number, + Punishment = punish, + Time = (int?)time?.Time.TotalMinutes ?? 0, + RoleId = punish == PunishmentAction.AddRole ? role!.Id : default(ulong?) + }); + uow.SaveChanges(); + return true; + } + + public bool WarnPunishRemove(ulong guildId, int number) + { + if (number <= 0) + return false; + + using var uow = _db.GetDbContext(); + var ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments; + var p = ps.FirstOrDefault(x => x.Count == number); + + if (p is not null) + { + uow.Remove(p); + uow.SaveChanges(); + } + + return true; + } + + public WarningPunishment[] WarnPunishList(ulong guildId) + { + using var uow = _db.GetDbContext(); + return uow.GuildConfigsForId(guildId, gc => gc.Include(x => x.WarnPunishments)) + .WarnPunishments.OrderBy(x => x.Count) + .ToArray(); + } + + public (IReadOnlyCollection<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill( + SocketGuild guild, + string people) + { + var gusers = guild.Users; + //get user objects and reasons + var bans = people.Split("\n") + .Select(x => + { + var split = x.Trim().Split(" "); + + var reason = string.Join(" ", split.Skip(1)); + + if (ulong.TryParse(split[0], out var id)) + return (Original: split[0], Id: id, Reason: reason); + + return (Original: split[0], + gusers.FirstOrDefault(u => u.ToString().ToLowerInvariant() == x)?.Id, + Reason: reason); + }) + .ToArray(); + + //if user is null, means that person couldn't be found + var missing = bans.Count(x => !x.Id.HasValue); + + //get only data for found users + var found = bans.Where(x => x.Id.HasValue).Select(x => x.Id.Value).ToList(); + + _ = _blacklistService.BlacklistUsers(found); + + return (bans, missing); + } + + public string GetBanTemplate(ulong guildId) + { + using var uow = _db.GetDbContext(); + var template = uow.Set().AsQueryable().FirstOrDefault(x => x.GuildId == guildId); + return template?.Text; + } + + public void SetBanTemplate(ulong guildId, string text) + { + using var uow = _db.GetDbContext(); + var template = uow.Set().AsQueryable().FirstOrDefault(x => x.GuildId == guildId); + + if (text is null) + { + if (template is null) + return; + + uow.Remove(template); + } + else if (template is null) + { + uow.Set().Add(new() + { + GuildId = guildId, + Text = text + }); + } + else + template.Text = text; + + uow.SaveChanges(); + } + + public async Task SetBanPruneAsync(ulong guildId, int? pruneDays) + { + await using var ctx = _db.GetDbContext(); + await ctx.Set() + .ToLinqToDBTable() + .InsertOrUpdateAsync(() => new() + { + GuildId = guildId, + Text = null, + DateAdded = DateTime.UtcNow, + PruneDays = pruneDays + }, + old => new() + { + PruneDays = pruneDays + }, + () => new() + { + GuildId = guildId + }); + } + + public async Task GetBanPruneAsync(ulong guildId) + { + await using var ctx = _db.GetDbContext(); + return await ctx.Set() + .Where(x => x.GuildId == guildId) + .Select(x => x.PruneDays) + .FirstOrDefaultAsyncLinqToDB(); + } + + public Task GetBanUserDmEmbed( + ICommandContext context, + IGuildUser target, + string defaultMessage, + string banReason, + TimeSpan? duration) + => GetBanUserDmEmbed((DiscordSocketClient)context.Client, + (SocketGuild)context.Guild, + (IGuildUser)context.User, + target, + defaultMessage, + banReason, + duration); + + public async Task GetBanUserDmEmbed( + DiscordSocketClient client, + SocketGuild guild, + IGuildUser moderator, + IGuildUser target, + string defaultMessage, + string banReason, + TimeSpan? duration) + { + var template = GetBanTemplate(guild.Id); + + banReason = string.IsNullOrWhiteSpace(banReason) ? "-" : banReason; + + var repCtx = new ReplacementContext(client, guild) + .WithOverride("%ban.mod%", () => moderator.ToString()) + .WithOverride("%ban.mod.fullname%", () => moderator.ToString()) + .WithOverride("%ban.mod.name%", () => moderator.Username) + .WithOverride("%ban.mod.discrim%", () => moderator.Discriminator) + .WithOverride("%ban.user%", () => target.ToString()) + .WithOverride("%ban.user.fullname%", () => target.ToString()) + .WithOverride("%ban.user.name%", () => target.Username) + .WithOverride("%ban.user.discrim%", () => target.Discriminator) + .WithOverride("%reason%", () => banReason) + .WithOverride("%ban.reason%", () => banReason) + .WithOverride("%ban.duration%", + () => duration?.ToString(@"d\.hh\:mm") ?? "perma"); + + + // if template isn't set, use the old message style + if (string.IsNullOrWhiteSpace(template)) + { + template = JsonConvert.SerializeObject(new + { + color = _bcs.Data.Color.Error.PackedValue >> 8, + description = defaultMessage + }); + } + // if template is set to "-" do not dm the user + else if (template == "-") + return default; + // if template is an embed, send that embed with replacements + // otherwise, treat template as a regular string with replacements + else if (SmartText.CreateFrom(template) is not { IsEmbed: true } or { IsEmbedArray: true }) + { + template = JsonConvert.SerializeObject(new + { + color = _bcs.Data.Color.Error.PackedValue >> 8, + description = template + }); + } + + var output = SmartText.CreateFrom(template); + return await _repSvc.ReplaceAsync(output, repCtx); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/VcRole/VcRoleCommands.cs b/src/EllieBot/Modules/Administration/VcRole/VcRoleCommands.cs new file mode 100644 index 0000000..a5f547a --- /dev/null +++ b/src/EllieBot/Modules/Administration/VcRole/VcRoleCommands.cs @@ -0,0 +1,77 @@ +#nullable disable +using EllieBot.Modules.Administration.Services; + +namespace EllieBot.Modules.Administration; + +public partial class Administration +{ + [Group] + public partial class VcRoleCommands : EllieModule + { + [Cmd] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [RequireContext(ContextType.Guild)] + public async Task VcRoleRm(ulong vcId) + { + if (_service.RemoveVcRole(ctx.Guild.Id, vcId)) + await Response().Confirm(strs.vcrole_removed(Format.Bold(vcId.ToString()))).SendAsync(); + else + await Response().Error(strs.vcrole_not_found).SendAsync(); + } + + [Cmd] + [UserPerm(GuildPerm.ManageRoles)] + [BotPerm(GuildPerm.ManageRoles)] + [RequireContext(ContextType.Guild)] + public async Task VcRole([Leftover] IRole role = null) + { + var user = (IGuildUser)ctx.User; + + var vc = user.VoiceChannel; + + if (vc is null || vc.GuildId != user.GuildId) + { + await Response().Error(strs.must_be_in_voice).SendAsync(); + return; + } + + if (role is null) + { + if (_service.RemoveVcRole(ctx.Guild.Id, vc.Id)) + await Response().Confirm(strs.vcrole_removed(Format.Bold(vc.Name))).SendAsync(); + } + else + { + _service.AddVcRole(ctx.Guild.Id, role, vc.Id); + await Response().Confirm(strs.vcrole_added(Format.Bold(vc.Name), Format.Bold(role.Name))).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task VcRoleList() + { + var guild = (SocketGuild)ctx.Guild; + string text; + if (_service.VcRoles.TryGetValue(ctx.Guild.Id, out var roles)) + { + if (!roles.Any()) + text = GetText(strs.no_vcroles); + else + { + text = string.Join("\n", + roles.Select(x + => $"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}")); + } + } + else + text = GetText(strs.no_vcroles); + + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.vc_role_list)) + .WithDescription(text)).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/VcRole/VcRoleService.cs b/src/EllieBot/Modules/Administration/VcRole/VcRoleService.cs new file mode 100644 index 0000000..c2dc60b --- /dev/null +++ b/src/EllieBot/Modules/Administration/VcRole/VcRoleService.cs @@ -0,0 +1,208 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Administration.Services; + +public class VcRoleService : IEService +{ + public ConcurrentDictionary> VcRoles { get; } + public ConcurrentDictionary> ToAssign { get; } + private readonly DbService _db; + private readonly DiscordSocketClient _client; + + public VcRoleService(DiscordSocketClient client, IBot bot, DbService db) + { + _db = db; + _client = client; + + _client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated; + VcRoles = new(); + ToAssign = new(); + + using (var uow = db.GetDbContext()) + { + var guildIds = client.Guilds.Select(x => x.Id).ToList(); + uow.Set() + .AsQueryable() + .Include(x => x.VcRoleInfos) + .Where(x => guildIds.Contains(x.GuildId)) + .AsEnumerable() + .Select(InitializeVcRole) + .WhenAll(); + } + + Task.Run(async () => + { + while (true) + { + Task Selector(System.Collections.Concurrent.ConcurrentQueue<(bool, IGuildUser, IRole)> queue) + { + return Task.Run(async () => + { + while (queue.TryDequeue(out var item)) + { + var (add, user, role) = item; + + try + { + if (add) + { + if (!user.RoleIds.Contains(role.Id)) + await user.AddRoleAsync(role); + } + else + { + if (user.RoleIds.Contains(role.Id)) + await user.RemoveRoleAsync(role); + } + } + catch + { + } + + await Task.Delay(250); + } + }); + } + + await ToAssign.Values.Select(Selector).Append(Task.Delay(1000)).WhenAll(); + } + }); + + _client.LeftGuild += _client_LeftGuild; + bot.JoinedGuild += Bot_JoinedGuild; + } + + private Task Bot_JoinedGuild(GuildConfig arg) + { + // includeall no longer loads vcrole + // need to load new guildconfig with vc role included + using (var uow = _db.GetDbContext()) + { + var configWithVcRole = uow.GuildConfigsForId(arg.GuildId, set => set.Include(x => x.VcRoleInfos)); + _ = InitializeVcRole(configWithVcRole); + } + + return Task.CompletedTask; + } + + private Task _client_LeftGuild(SocketGuild arg) + { + VcRoles.TryRemove(arg.Id, out _); + ToAssign.TryRemove(arg.Id, out _); + return Task.CompletedTask; + } + + private async Task InitializeVcRole(GuildConfig gconf) + { + var g = _client.GetGuild(gconf.GuildId); + if (g is null) + return; + + var infos = new ConcurrentDictionary(); + var missingRoles = new List(); + VcRoles.AddOrUpdate(gconf.GuildId, infos, delegate { return infos; }); + foreach (var ri in gconf.VcRoleInfos) + { + var role = g.GetRole(ri.RoleId); + if (role is null) + { + missingRoles.Add(ri); + continue; + } + + infos.TryAdd(ri.VoiceChannelId, role); + } + + if (missingRoles.Any()) + { + await using var uow = _db.GetDbContext(); + uow.RemoveRange(missingRoles); + await uow.SaveChangesAsync(); + + Log.Warning("Removed {MissingRoleCount} missing roles from {ServiceName}", + missingRoles.Count, + nameof(VcRoleService)); + } + } + + public void AddVcRole(ulong guildId, IRole role, ulong vcId) + { + ArgumentNullException.ThrowIfNull(role); + + var guildVcRoles = VcRoles.GetOrAdd(guildId, new ConcurrentDictionary()); + + guildVcRoles.AddOrUpdate(vcId, role, (_, _) => role); + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.VcRoleInfos)); + var toDelete = conf.VcRoleInfos.FirstOrDefault(x => x.VoiceChannelId == vcId); // remove old one + if (toDelete is not null) + uow.Remove(toDelete); + conf.VcRoleInfos.Add(new() + { + VoiceChannelId = vcId, + RoleId = role.Id + }); // add new one + uow.SaveChanges(); + } + + public bool RemoveVcRole(ulong guildId, ulong vcId) + { + if (!VcRoles.TryGetValue(guildId, out var guildVcRoles)) + return false; + + if (!guildVcRoles.TryRemove(vcId, out _)) + return false; + + using var uow = _db.GetDbContext(); + var conf = uow.GuildConfigsForId(guildId, set => set.Include(x => x.VcRoleInfos)); + var toRemove = conf.VcRoleInfos.Where(x => x.VoiceChannelId == vcId).ToList(); + uow.RemoveRange(toRemove); + uow.SaveChanges(); + + return true; + } + + private Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState) + { + if (usr is not SocketGuildUser gusr) + return Task.CompletedTask; + + var oldVc = oldState.VoiceChannel; + var newVc = newState.VoiceChannel; + _ = Task.Run(() => + { + try + { + if (oldVc != newVc) + { + ulong guildId; + guildId = newVc?.Guild.Id ?? oldVc.Guild.Id; + + if (VcRoles.TryGetValue(guildId, out var guildVcRoles)) + { + //remove old + if (oldVc is not null && guildVcRoles.TryGetValue(oldVc.Id, out var role)) + Assign(false, gusr, role); + //add new + if (newVc is not null && guildVcRoles.TryGetValue(newVc.Id, out role)) + Assign(true, gusr, role); + } + } + } + catch (Exception ex) + { + Log.Warning(ex, "Error in VcRoleService VoiceStateUpdate"); + } + }); + return Task.CompletedTask; + } + + private void Assign(bool v, SocketGuildUser gusr, IRole role) + { + var queue = ToAssign.GetOrAdd(gusr.Guild.Id, new System.Collections.Concurrent.ConcurrentQueue<(bool, IGuildUser, IRole)>()); + queue.Enqueue((v, gusr, role)); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/_common/SetServerBannerResult.cs b/src/EllieBot/Modules/Administration/_common/SetServerBannerResult.cs new file mode 100644 index 0000000..bd3eaab --- /dev/null +++ b/src/EllieBot/Modules/Administration/_common/SetServerBannerResult.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Administration._common.results; + +public enum SetServerBannerResult +{ + Success, + InvalidFileType, + Toolarge, + InvalidURL +} diff --git a/src/EllieBot/Modules/Administration/_common/SetServerIconResult.cs b/src/EllieBot/Modules/Administration/_common/SetServerIconResult.cs new file mode 100644 index 0000000..f0d0b1a --- /dev/null +++ b/src/EllieBot/Modules/Administration/_common/SetServerIconResult.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Administration._common.results; + +public enum SetServerIconResult +{ + Success, + InvalidFileType, + InvalidURL +} \ No newline at end of file From d9096a07a8cde572c615495bedbcb4181c13b0a7 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:50:22 +1200 Subject: [PATCH 47/62] Added Expressions module --- .../Expressions/EllieExpressionExtensions.cs | 91 ++ .../Modules/Expressions/EllieExpressions.cs | 447 ++++++++++ .../Expressions/EllieExpressionsService.cs | 801 ++++++++++++++++++ .../Modules/Expressions/ExportedExpr.cs | 27 + src/EllieBot/Modules/Expressions/ExprField.cs | 10 + .../TypeReaders/CommandOrExprTypeReader.cs | 33 + 6 files changed, 1409 insertions(+) create mode 100644 src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs create mode 100644 src/EllieBot/Modules/Expressions/EllieExpressions.cs create mode 100644 src/EllieBot/Modules/Expressions/EllieExpressionsService.cs create mode 100644 src/EllieBot/Modules/Expressions/ExportedExpr.cs create mode 100644 src/EllieBot/Modules/Expressions/ExprField.cs create mode 100644 src/EllieBot/Modules/Expressions/TypeReaders/CommandOrExprTypeReader.cs diff --git a/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs b/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs new file mode 100644 index 0000000..72606a7 --- /dev/null +++ b/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs @@ -0,0 +1,91 @@ +#nullable disable +using EllieBot.Db.Models; +using System.Runtime.CompilerServices; + +namespace EllieBot.Modules.EllieExpressions; + +public static class EllieExpressionExtensions +{ + private static string ResolveTriggerString(this string str, DiscordSocketClient client) + => str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal); + + public static async Task Send( + this EllieExpression cr, + IUserMessage ctx, + IReplacementService repSvc, + DiscordSocketClient client, + IMessageSenderService sender) + { + var channel = cr.DmResponse ? await ctx.Author.CreateDMChannelAsync() : ctx.Channel; + + var trigger = cr.Trigger.ResolveTriggerString(client); + var substringIndex = trigger.Length; + if (cr.ContainsAnywhere) + { + var pos = ctx.Content.AsSpan().GetWordPosition(trigger); + if (pos == WordPosition.Start) + substringIndex += 1; + else if (pos == WordPosition.End) + substringIndex = ctx.Content.Length; + else if (pos == WordPosition.Middle) + substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture); + } + + var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true; + + var repCtx = new ReplacementContext(client: client, + guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild, + channel: ctx.Channel, + users: ctx.Author + ) + .WithOverride("%target%", + () => canMentionEveryone + ? ctx.Content[substringIndex..].Trim() + : ctx.Content[substringIndex..].Trim().SanitizeMentions(true)); + + var text = SmartText.CreateFrom(cr.Response); + text = await repSvc.ReplaceAsync(text, repCtx); + + return await sender.Response(channel).Text(text).Sanitize(false).SendAsync(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WordPosition GetWordPosition(this ReadOnlySpan str, in ReadOnlySpan word) + { + var wordIndex = str.IndexOf(word, StringComparison.OrdinalIgnoreCase); + if (wordIndex == -1) + return WordPosition.None; + + if (wordIndex == 0) + { + if (word.Length < str.Length && str.IsValidWordDivider(word.Length)) + return WordPosition.Start; + } + else if (wordIndex + word.Length == str.Length) + { + if (str.IsValidWordDivider(wordIndex - 1)) + return WordPosition.End; + } + else if (str.IsValidWordDivider(wordIndex - 1) && str.IsValidWordDivider(wordIndex + word.Length)) + return WordPosition.Middle; + + return WordPosition.None; + } + + private static bool IsValidWordDivider(this in ReadOnlySpan str, int index) + { + var ch = str[index]; + if (ch is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '1' and <= '9') + return false; + + return true; + } +} + +public enum WordPosition +{ + None, + Start, + Middle, + End +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Expressions/EllieExpressions.cs b/src/EllieBot/Modules/Expressions/EllieExpressions.cs new file mode 100644 index 0000000..5def4f3 --- /dev/null +++ b/src/EllieBot/Modules/Expressions/EllieExpressions.cs @@ -0,0 +1,447 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.EllieExpressions; + +[Name("Expressions")] +public partial class EllieExpressions : EllieModule +{ + public enum All + { + All + } + + private readonly IBotCredentials _creds; + private readonly IHttpClientFactory _clientFactory; + + public EllieExpressions(IBotCredentials creds, IHttpClientFactory clientFactory) + { + _creds = creds; + _clientFactory = clientFactory; + } + + private bool AdminInGuildOrOwnerInDm() + => (ctx.Guild is null && _creds.IsOwner(ctx.User)) + || (ctx.Guild is not null && ((IGuildUser)ctx.User).GuildPermissions.Administrator); + + private async Task ExprAddInternalAsync(string key, string message) + { + if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key)) + { + return; + } + + var ex = await _service.AddAsync(ctx.Guild?.Id, key, message); + + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.expr_new)) + .WithDescription($"#{new kwum(ex.Id)}") + .AddField(GetText(strs.trigger), key) + .AddField(GetText(strs.response), + message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) + .SendAsync(); + } + + [Cmd] + [UserPerm(GuildPerm.Administrator)] + public async Task ExprToggleGlobal() + { + var result = await _service.ToggleGlobalExpressionsAsync(ctx.Guild.Id); + if (result) + await Response().Confirm(strs.expr_global_disabled).SendAsync(); + else + await Response().Confirm(strs.expr_global_enabled).SendAsync(); + } + + [Cmd] + [UserPerm(GuildPerm.Administrator)] + public async Task ExprAddServer(string key, [Leftover] string message) + { + if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key)) + { + return; + } + + await ExprAddInternalAsync(key, message); + } + + + [Cmd] + public async Task ExprAdd(string trigger, [Leftover] string response) + { + if (string.IsNullOrWhiteSpace(response) || string.IsNullOrWhiteSpace(trigger)) + { + return; + } + + if (!AdminInGuildOrOwnerInDm()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + await ExprAddInternalAsync(trigger, response); + } + + [Cmd] + public async Task ExprEdit(kwum id, [Leftover] string message) + { + var channel = ctx.Channel as ITextChannel; + if (string.IsNullOrWhiteSpace(message) || id < 0) + { + return; + } + + if (!IsValidExprEditor()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + var ex = await _service.EditAsync(ctx.Guild?.Id, id, message); + if (ex is not null) + { + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.expr_edited)) + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), ex.Trigger) + .AddField(GetText(strs.response), + message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) + .SendAsync(); + } + else + { + await Response().Error(strs.expr_no_found_id).SendAsync(); + } + } + + private bool IsValidExprEditor() + => (ctx.Guild is not null && ((IGuildUser)ctx.User).GuildPermissions.Administrator) + || (ctx.Guild is null && _creds.IsOwner(ctx.User)); + + [Cmd] + [Priority(1)] + public async Task ExprList(int page = 1) + { + if (--page < 0 || page > 999) + { + return; + } + + var allExpressions = _service.GetExpressionsFor(ctx.Guild?.Id) + .OrderBy(x => x.Trigger) + .ToArray(); + + if (!allExpressions.Any()) + { + await Response().Error(strs.expr_no_found).SendAsync(); + return; + } + + await Response() + .Paginated() + .Items(allExpressions) + .PageSize(20) + .CurrentPage(page) + .Page((exprs, _) => + { + var desc = exprs + .Select(ex => $"{(ex.ContainsAnywhere ? "🗯" : "◾")}" + + $"{(ex.DmResponse ? "✉" : "◾")}" + + $"{(ex.AutoDeleteTrigger ? "❌" : "◾")}" + + $"`{(kwum)ex.Id}` {ex.Trigger}" + + (string.IsNullOrWhiteSpace(ex.Reactions) + ? string.Empty + : " // " + string.Join(" ", ex.GetReactions()))) + .Join('\n'); + + return _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc); + }) + .SendAsync(); + } + + [Cmd] + public async Task ExprShow(kwum id) + { + var found = _service.GetExpression(ctx.Guild?.Id, id); + + if (found is null) + { + await Response().Error(strs.expr_no_found_id).SendAsync(); + return; + } + + var inter = CreateEditInteraction(id, found); + + await Response() + .Interaction(IsValidExprEditor() ? inter : null) + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024)) + .AddField(GetText(strs.response), + found.Response.TrimTo(1000).Replace("](", "]\\("))) + .SendAsync(); + } + + private EllieInteractionBase CreateEditInteraction(kwum id, EllieExpression found) + { + var modal = new ModalBuilder() + .WithCustomId("expr:edit_modal") + .WithTitle($"Edit expression {id}") + .AddTextInput(new TextInputBuilder() + .WithLabel(GetText(strs.response)) + .WithValue(found.Response) + .WithMinLength(1) + .WithCustomId("expr:edit_modal:response") + .WithStyle(TextInputStyle.Paragraph)); + + var inter = _inter.Create(ctx.User.Id, + new ButtonBuilder() + .WithEmote(Emoji.Parse("📝")) + .WithLabel("Edit") + .WithStyle(ButtonStyle.Primary) + .WithCustomId("test"), + modal, + async (sm) => + { + var msg = sm.Data.Components.FirstOrDefault()?.Value; + + await ExprEdit(id, msg); + } + ); + return inter; + } + + public async Task ExprDeleteInternalAsync(kwum id) + { + var ex = await _service.DeleteAsync(ctx.Guild?.Id, id); + + if (ex is not null) + { + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.expr_deleted)) + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024)) + .AddField(GetText(strs.response), ex.Response.TrimTo(1024))) + .SendAsync(); + } + else + { + await Response().Error(strs.expr_no_found_id).SendAsync(); + } + } + + [Cmd] + [UserPerm(GuildPerm.Administrator)] + [RequireContext(ContextType.Guild)] + public async Task ExprDeleteServer(kwum id) + => await ExprDeleteInternalAsync(id); + + [Cmd] + public async Task ExprDelete(kwum id) + { + if (!AdminInGuildOrOwnerInDm()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + await ExprDeleteInternalAsync(id); + } + + [Cmd] + public async Task ExprReact(kwum id, params string[] emojiStrs) + { + if (!AdminInGuildOrOwnerInDm()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + var ex = _service.GetExpression(ctx.Guild?.Id, id); + if (ex is null) + { + await Response().Error(strs.expr_no_found_id).SendAsync(); + return; + } + + if (emojiStrs.Length == 0) + { + await _service.ResetExprReactions(ctx.Guild?.Id, id); + await Response().Confirm(strs.expr_reset(Format.Bold(id.ToString()))).SendAsync(); + return; + } + + var succ = new List(); + foreach (var emojiStr in emojiStrs) + { + var emote = emojiStr.ToIEmote(); + + // i should try adding these emojis right away to the message, to make sure the bot can react with these emojis. If it fails, skip that emoji + try + { + await ctx.Message.AddReactionAsync(emote); + await Task.Delay(100); + succ.Add(emojiStr); + + if (succ.Count >= 3) + { + break; + } + } + catch { } + } + + if (succ.Count == 0) + { + await Response().Error(strs.invalid_emojis).SendAsync(); + return; + } + + await _service.SetExprReactions(ctx.Guild?.Id, id, succ); + + + await Response() + .Confirm(strs.expr_set(Format.Bold(id.ToString()), + succ.Select(static x => x.ToString()).Join(", "))) + .SendAsync(); + } + + [Cmd] + public Task ExprCa(kwum id) + => InternalExprEdit(id, ExprField.ContainsAnywhere); + + [Cmd] + public Task ExprDm(kwum id) + => InternalExprEdit(id, ExprField.DmResponse); + + [Cmd] + public Task ExprAd(kwum id) + => InternalExprEdit(id, ExprField.AutoDelete); + + [Cmd] + public Task ExprAt(kwum id) + => InternalExprEdit(id, ExprField.AllowTarget); + + [Cmd] + [OwnerOnly] + public async Task ExprsReload() + { + await _service.TriggerReloadExpressions(); + + await ctx.OkAsync(); + } + + private async Task InternalExprEdit(kwum id, ExprField option) + { + if (!AdminInGuildOrOwnerInDm()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + var (success, newVal) = await _service.ToggleExprOptionAsync(ctx.Guild?.Id, id, option); + if (!success) + { + await Response().Error(strs.expr_no_found_id).SendAsync(); + return; + } + + if (newVal) + { + await Response() + .Confirm(strs.option_enabled(Format.Code(option.ToString()), + Format.Code(id.ToString()))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.option_disabled(Format.Code(option.ToString()), + Format.Code(id.ToString()))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ExprClear() + { + if (await PromptUserConfirmAsync(_sender.CreateEmbed() + .WithTitle("Expression clear") + .WithDescription("This will delete all expressions on this server."))) + { + var count = _service.DeleteAllExpressions(ctx.Guild.Id); + await Response().Confirm(strs.exprs_cleared(count)).SendAsync(); + } + } + + [Cmd] + public async Task ExprsExport() + { + if (!AdminInGuildOrOwnerInDm()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var serialized = _service.ExportExpressions(ctx.Guild?.Id); + await using var stream = await serialized.ToStream(); + await ctx.Channel.SendFileAsync(stream, "exprs-export.yml"); + } + + [Cmd] +#if GLOBAL_ELLIE + [OwnerOnly] +#endif + public async Task ExprsImport([Leftover] string input = null) + { + if (!AdminInGuildOrOwnerInDm()) + { + await Response().Error(strs.expr_insuff_perms).SendAsync(); + return; + } + + input = input?.Trim(); + + _ = ctx.Channel.TriggerTypingAsync(); + + if (input is null) + { + var attachment = ctx.Message.Attachments.FirstOrDefault(); + if (attachment is null) + { + await Response().Error(strs.expr_import_no_input).SendAsync(); + return; + } + + using var client = _clientFactory.CreateClient(); + input = await client.GetStringAsync(attachment.Url); + + if (string.IsNullOrWhiteSpace(input)) + { + await Response().Error(strs.expr_import_no_input).SendAsync(); + return; + } + } + + var succ = await _service.ImportExpressionsAsync(ctx.Guild?.Id, input); + if (!succ) + { + await Response().Error(strs.expr_import_invalid_data).SendAsync(); + return; + } + + await ctx.OkAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs b/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs new file mode 100644 index 0000000..2f0b740 --- /dev/null +++ b/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs @@ -0,0 +1,801 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Common.Yml; +using EllieBot.Db; +using EllieBot.Db.Models; +using System.Runtime.CompilerServices; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Modules.Permissions.Services; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace EllieBot.Modules.EllieExpressions; + +public sealed class EllieExpressionsService : IExecOnMessage, IReadyExecutor +{ + private const string MENTION_PH = "%bot.mention%"; + + private const string PREPEND_EXPORT = + """ + # Keys are triggers, Each key has a LIST of expressions in the following format: + # - res: Response string + # id: Alphanumeric id used for commands related to the expression. (Note, when using .exprsimport, a new id will be generated.) + # react: + # - + # at: Whether expression allows targets (see .h .exprat) + # ca: Whether expression expects trigger anywhere (see .h .exprca) + # dm: Whether expression DMs the response (see .h .exprdm) + # ad: Whether expression automatically deletes triggering message (see .h .exprad) + + + """; + + private static readonly ISerializer _exportSerializer = new SerializerBuilder() + .WithEventEmitter(args + => new MultilineScalarFlowStyleEmitter(args)) + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .WithIndentedSequences() + .ConfigureDefaultValuesHandling(DefaultValuesHandling + .OmitDefaults) + .DisableAliases() + .Build(); + + public int Priority + => 0; + + private readonly object _gexprWriteLock = new(); + + private readonly TypedKey _gexprAddedKey = new("gexpr.added"); + private readonly TypedKey _gexprDeletedkey = new("gexpr.deleted"); + private readonly TypedKey _gexprEditedKey = new("gexpr.edited"); + private readonly TypedKey _exprsReloadedKey = new("exprs.reloaded"); + + // it is perfectly fine to have global expressions as an array + // 1. expressions are almost never added (compared to how many times they are being looped through) + // 2. only need write locks for this as we'll rebuild+replace the array on every edit + // 3. there's never many of them (at most a thousand, usually < 100) + private EllieExpression[] globalExpressions = Array.Empty(); + private ConcurrentDictionary newguildExpressions = new(); + + private readonly DbService _db; + + private readonly DiscordSocketClient _client; + + // private readonly PermissionService _perms; + // private readonly GlobalPermissionService _gperm; + // private readonly CmdCdService _cmdCds; + private readonly IPermissionChecker _permChecker; + private readonly ICommandHandler _cmd; + private readonly IBotStrings _strings; + private readonly IBot _bot; + private readonly IPubSub _pubSub; + private readonly IMessageSenderService _sender; + private readonly IReplacementService _repSvc; + private readonly Random _rng; + + private bool ready; + private ConcurrentHashSet _disabledGlobalExpressionGuilds; + private readonly PermissionService _pc; + + public EllieExpressionsService( + DbService db, + IBotStrings strings, + IBot bot, + DiscordSocketClient client, + ICommandHandler cmd, + IPubSub pubSub, + IMessageSenderService sender, + IReplacementService repSvc, + IPermissionChecker permChecker, + PermissionService pc) + { + _db = db; + _client = client; + _cmd = cmd; + _strings = strings; + _bot = bot; + _pubSub = pubSub; + _sender = sender; + _repSvc = repSvc; + _permChecker = permChecker; + _pc = pc; + _rng = new EllieRandom(); + + _pubSub.Sub(_exprsReloadedKey, OnExprsShouldReload); + pubSub.Sub(_gexprAddedKey, OnGexprAdded); + pubSub.Sub(_gexprDeletedkey, OnGexprDeleted); + pubSub.Sub(_gexprEditedKey, OnGexprEdited); + + bot.JoinedGuild += OnJoinedGuild; + _client.LeftGuild += OnLeftGuild; + } + + private async Task ReloadInternal(IReadOnlyList allGuildIds) + { + await using var uow = _db.GetDbContext(); + var guildItems = await uow.Set() + .AsNoTracking() + .Where(x => allGuildIds.Contains(x.GuildId.Value)) + .ToListAsync(); + + newguildExpressions = guildItems.GroupBy(k => k.GuildId!.Value) + .ToDictionary(g => g.Key, + g => g.Select(x => + { + x.Trigger = x.Trigger.Replace(MENTION_PH, + _client.CurrentUser.Mention); + return x; + }) + .ToArray()) + .ToConcurrent(); + + _disabledGlobalExpressionGuilds = new(await uow.Set() + .Where(x => x.DisableGlobalExpressions) + .Select(x => x.GuildId) + .ToListAsyncLinqToDB()); + + lock (_gexprWriteLock) + { + var globalItems = uow.Set() + .AsNoTracking() + .Where(x => x.GuildId == null || x.GuildId == 0) + .Where(x => x.Trigger != null) + .AsEnumerable() + .Select(x => + { + x.Trigger = x.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention); + return x; + }) + .ToArray(); + + globalExpressions = globalItems; + } + + ready = true; + } + + private EllieExpression TryGetExpression(IUserMessage umsg) + { + if (!ready) + return null; + + if (umsg.Channel is not SocketTextChannel channel) + return null; + + var content = umsg.Content.Trim().ToLowerInvariant(); + + if (newguildExpressions.TryGetValue(channel.Guild.Id, out var expressions) && expressions.Length > 0) + { + var expr = MatchExpressions(content, expressions); + if (expr is not null) + return expr; + } + + if (_disabledGlobalExpressionGuilds.Contains(channel.Guild.Id)) + return null; + + var localGrs = globalExpressions; + + return MatchExpressions(content, localGrs); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private EllieExpression MatchExpressions(in ReadOnlySpan content, EllieExpression[] exprs) + { + var result = new List(1); + for (var i = 0; i < exprs.Length; i++) + { + var expr = exprs[i]; + var trigger = expr.Trigger; + if (content.Length > trigger.Length) + { + // if input is greater than the trigger, it can only work if: + // it has CA enabled + if (expr.ContainsAnywhere) + { + // if ca is enabled, we have to check if it is a word within the content + var wp = content.GetWordPosition(trigger); + + // if it is, then that's valid + if (wp != WordPosition.None) + result.Add(expr); + + // if it's not, then it cant' work under any circumstance, + // because content is greater than the trigger length + // so it can't be equal, and it's not contained as a word + continue; + } + + // if CA is disabled, and expr has AllowTarget, then the + // content has to start with the trigger followed by a space + if (expr.AllowTarget + && content.StartsWith(trigger, StringComparison.OrdinalIgnoreCase) + && content[trigger.Length] == ' ') + result.Add(expr); + } + else if (content.Length < expr.Trigger.Length) + { + // if input length is less than trigger length, it means + // that the reaction can never be triggered + } + else + { + // if input length is the same as trigger length + // reaction can only trigger if the strings are equal + if (content.SequenceEqual(expr.Trigger)) + result.Add(expr); + } + } + + if (result.Count == 0) + return null; + + var cancelled = result.FirstOrDefault(x => x.Response == "-"); + if (cancelled is not null) + return cancelled; + + return result[_rng.Next(0, result.Count)]; + } + + public async Task ExecOnMessageAsync(IGuild guild, IUserMessage msg) + { + // maybe this message is an expression + var expr = TryGetExpression(msg); + + if (expr is null || expr.Response == "-") + return false; + + try + { + if (guild is SocketGuild sg) + { + var result = await _permChecker.CheckPermsAsync( + guild, + msg.Channel, + msg.Author, + "ACTUALEXPRESSIONS", + expr.Trigger + ); + + if (!result.IsAllowed) + { + var cache = _pc.GetCacheFor(guild.Id); + if (cache.Verbose) + { + if (result.TryPickT3(out var disallowed, out _)) + { + var permissionMessage = _strings.GetText(strs.perm_prevent(disallowed.PermIndex + 1, + Format.Bold(disallowed.PermText)), + sg.Id); + + try + { + await _sender.Response(msg.Channel) + .Error(permissionMessage) + .SendAsync(); + } + catch + { + } + + Log.Information("{PermissionMessage}", permissionMessage); + } + } + + return true; + } + } + + var sentMsg = await expr.Send(msg, _repSvc, _client, _sender); + + var reactions = expr.GetReactions(); + foreach (var reaction in reactions) + { + try + { + await sentMsg.AddReactionAsync(reaction.ToIEmote()); + } + catch + { + Log.Warning("Unable to add reactions to message {Message} in server {GuildId}", + sentMsg.Id, + expr.GuildId); + break; + } + + await Task.Delay(1000); + } + + if (expr.AutoDeleteTrigger) + { + try + { + await msg.DeleteAsync(); + } + catch + { + } + } + + Log.Information("s: {GuildId} c: {ChannelId} u: {UserId} | {UserName} executed expression {Expr}", + guild.Id, + msg.Channel.Id, + msg.Author.Id, + msg.Author.ToString(), + expr.Trigger); + + return true; + } + catch (Exception ex) + { + Log.Warning(ex, "Error in Expression RunBehavior: {ErrorMessage}", ex.Message); + } + + return false; + } + + public async Task ResetExprReactions(ulong? maybeGuildId, int id) + { + EllieExpression expr; + await using var uow = _db.GetDbContext(); + expr = uow.Set().GetById(id); + if (expr is null) + return; + + expr.Reactions = string.Empty; + + await uow.SaveChangesAsync(); + } + + private Task UpdateInternalAsync(ulong? maybeGuildId, EllieExpression expr) + { + if (maybeGuildId is { } guildId) + UpdateInternal(guildId, expr); + else + return _pubSub.Pub(_gexprEditedKey, expr); + + return Task.CompletedTask; + } + + private void UpdateInternal(ulong? maybeGuildId, EllieExpression expr) + { + if (maybeGuildId is { } guildId) + { + newguildExpressions.AddOrUpdate(guildId, + [expr], + (_, old) => + { + var newArray = old.ToArray(); + for (var i = 0; i < newArray.Length; i++) + { + if (newArray[i].Id == expr.Id) + newArray[i] = expr; + } + + return newArray; + }); + } + else + { + lock (_gexprWriteLock) + { + var exprs = globalExpressions; + for (var i = 0; i < exprs.Length; i++) + { + if (exprs[i].Id == expr.Id) + exprs[i] = expr; + } + } + } + } + + private Task AddInternalAsync(ulong? maybeGuildId, EllieExpression expr) + { + // only do this for perf purposes + expr.Trigger = expr.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention); + + if (maybeGuildId is { } guildId) + newguildExpressions.AddOrUpdate(guildId, [expr], (_, old) => old.With(expr)); + else + return _pubSub.Pub(_gexprAddedKey, expr); + + return Task.CompletedTask; + } + + private Task DeleteInternalAsync(ulong? maybeGuildId, int id) + { + if (maybeGuildId is { } guildId) + { + newguildExpressions.AddOrUpdate(guildId, + Array.Empty(), + (key, old) => DeleteInternal(old, id, out _)); + + return Task.CompletedTask; + } + + lock (_gexprWriteLock) + { + var expr = Array.Find(globalExpressions, item => item.Id == id); + if (expr is not null) + return _pubSub.Pub(_gexprDeletedkey, expr.Id); + } + + return Task.CompletedTask; + } + + private EllieExpression[] DeleteInternal( + IReadOnlyList exprs, + int id, + out EllieExpression deleted) + { + deleted = null; + if (exprs is null || exprs.Count == 0) + return exprs as EllieExpression[] ?? exprs?.ToArray(); + + var newExprs = new EllieExpression[exprs.Count - 1]; + for (int i = 0, k = 0; i < exprs.Count; i++, k++) + { + if (exprs[i].Id == id) + { + deleted = exprs[i]; + k--; + continue; + } + + newExprs[k] = exprs[i]; + } + + return newExprs; + } + + public async Task SetExprReactions(ulong? guildId, int id, IEnumerable emojis) + { + EllieExpression expr; + await using (var uow = _db.GetDbContext()) + { + expr = uow.Set().GetById(id); + if (expr is null) + return; + + expr.Reactions = string.Join("@@@", emojis); + + await uow.SaveChangesAsync(); + } + + await UpdateInternalAsync(guildId, expr); + } + + public async Task<(bool Sucess, bool NewValue)> ToggleExprOptionAsync(ulong? guildId, int id, ExprField field) + { + var newVal = false; + EllieExpression expr; + await using (var uow = _db.GetDbContext()) + { + expr = uow.Set().GetById(id); + + if (expr is null || expr.GuildId != guildId) + return (false, false); + if (field == ExprField.AutoDelete) + newVal = expr.AutoDeleteTrigger = !expr.AutoDeleteTrigger; + else if (field == ExprField.ContainsAnywhere) + newVal = expr.ContainsAnywhere = !expr.ContainsAnywhere; + else if (field == ExprField.DmResponse) + newVal = expr.DmResponse = !expr.DmResponse; + else if (field == ExprField.AllowTarget) + newVal = expr.AllowTarget = !expr.AllowTarget; + + await uow.SaveChangesAsync(); + } + + await UpdateInternalAsync(guildId, expr); + + return (true, newVal); + } + + public EllieExpression GetExpression(ulong? guildId, int id) + { + using var uow = _db.GetDbContext(); + var expr = uow.Set().GetById(id); + if (expr is null || expr.GuildId != guildId) + return null; + + return expr; + } + + public int DeleteAllExpressions(ulong guildId) + { + using var uow = _db.GetDbContext(); + var count = uow.Set().ClearFromGuild(guildId); + uow.SaveChanges(); + + newguildExpressions.TryRemove(guildId, out _); + + return count; + } + + public bool ExpressionExists(ulong? guildId, string input) + { + input = input.ToLowerInvariant(); + + var gexprs = globalExpressions; + foreach (var t in gexprs) + { + if (t.Trigger == input) + return true; + } + + if (guildId is ulong gid && newguildExpressions.TryGetValue(gid, out var guildExprs)) + { + foreach (var t in guildExprs) + { + if (t.Trigger == input) + return true; + } + } + + return false; + } + + public string ExportExpressions(ulong? guildId) + { + var exprs = GetExpressionsFor(guildId); + + var exprsDict = exprs.GroupBy(x => x.Trigger).ToDictionary(x => x.Key, x => x.Select(ExportedExpr.FromModel)); + + return PREPEND_EXPORT + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints(); + } + + public async Task ImportExpressionsAsync(ulong? guildId, string input) + { + Dictionary> data; + try + { + data = Yaml.Deserializer.Deserialize>>(input); + if (data.Sum(x => x.Value.Count) == 0) + return false; + } + catch + { + return false; + } + + await using var uow = _db.GetDbContext(); + foreach (var entry in data) + { + var trigger = entry.Key; + await uow.Set() + .AddRangeAsync(entry.Value + .Where(expr => !string.IsNullOrWhiteSpace(expr.Res)) + .Select(expr => new EllieExpression + { + GuildId = guildId, + Response = expr.Res, + Reactions = expr.React?.Join("@@@"), + Trigger = trigger, + AllowTarget = expr.At, + ContainsAnywhere = expr.Ca, + DmResponse = expr.Dm, + AutoDeleteTrigger = expr.Ad + })); + } + + await uow.SaveChangesAsync(); + await TriggerReloadExpressions(); + return true; + } + + #region Event Handlers + + public async Task OnReadyAsync() + => await OnExprsShouldReload(true); + + private ValueTask OnExprsShouldReload(bool _) + => new(ReloadInternal(_bot.GetCurrentGuildIds())); + + private ValueTask OnGexprAdded(EllieExpression c) + { + lock (_gexprWriteLock) + { + var newGlobalReactions = new EllieExpression[globalExpressions.Length + 1]; + Array.Copy(globalExpressions, newGlobalReactions, globalExpressions.Length); + newGlobalReactions[globalExpressions.Length] = c; + globalExpressions = newGlobalReactions; + } + + return default; + } + + private ValueTask OnGexprEdited(EllieExpression c) + { + lock (_gexprWriteLock) + { + for (var i = 0; i < globalExpressions.Length; i++) + { + if (globalExpressions[i].Id == c.Id) + { + globalExpressions[i] = c; + return default; + } + } + + // if edited expr is not found?! + // add it + OnGexprAdded(c); + } + + return default; + } + + private ValueTask OnGexprDeleted(int id) + { + lock (_gexprWriteLock) + { + var newGlobalReactions = DeleteInternal(globalExpressions, id, out _); + globalExpressions = newGlobalReactions; + } + + return default; + } + + public Task TriggerReloadExpressions() + => _pubSub.Pub(_exprsReloadedKey, true); + + #endregion + + #region Client Event Handlers + + private Task OnLeftGuild(SocketGuild arg) + { + newguildExpressions.TryRemove(arg.Id, out _); + + return Task.CompletedTask; + } + + private async Task OnJoinedGuild(GuildConfig gc) + { + await using var uow = _db.GetDbContext(); + var exprs = await uow.Set().AsNoTracking().Where(x => x.GuildId == gc.GuildId).ToArrayAsync(); + + newguildExpressions[gc.GuildId] = exprs; + } + + #endregion + + #region Basic Operations + + public async Task AddAsync( + ulong? guildId, + string key, + string message, + bool ca = false, + bool ad = false, + bool dm = false) + { + key = key.ToLowerInvariant(); + var expr = new EllieExpression + { + GuildId = guildId, + Trigger = key, + Response = message, + ContainsAnywhere = ca, + AutoDeleteTrigger = ad, + DmResponse = dm + }; + + if (expr.Response.Contains("%target%", StringComparison.OrdinalIgnoreCase)) + expr.AllowTarget = true; + + await using (var uow = _db.GetDbContext()) + { + uow.Set().Add(expr); + await uow.SaveChangesAsync(); + } + + await AddInternalAsync(guildId, expr); + + return expr; + } + + public async Task EditAsync( + ulong? guildId, + int id, + string message, + bool? ca = null, + bool? ad = null, + bool? dm = null) + { + await using var uow = _db.GetDbContext(); + var expr = uow.Set().GetById(id); + + if (expr is null || expr.GuildId != guildId) + return null; + + // disable allowtarget if message had target, but it was removed from it + if (!message.Contains("%target%", StringComparison.OrdinalIgnoreCase) + && expr.Response.Contains("%target%", StringComparison.OrdinalIgnoreCase)) + expr.AllowTarget = false; + + expr.Response = message; + + // enable allow target if message is edited to contain target + if (expr.Response.Contains("%target%", StringComparison.OrdinalIgnoreCase)) + expr.AllowTarget = true; + + expr.ContainsAnywhere = ca ?? expr.ContainsAnywhere; + expr.AutoDeleteTrigger = ad ?? expr.AutoDeleteTrigger; + expr.DmResponse = dm ?? expr.DmResponse; + + await uow.SaveChangesAsync(); + await UpdateInternalAsync(guildId, expr); + + return expr; + } + + + public async Task DeleteAsync(ulong? guildId, int id) + { + await using var uow = _db.GetDbContext(); + var toDelete = uow.Set().GetById(id); + + if (toDelete is null) + return null; + + if ((toDelete.IsGlobal() && guildId is null) || guildId == toDelete.GuildId) + { + uow.Set().Remove(toDelete); + await uow.SaveChangesAsync(); + await DeleteInternalAsync(guildId, id); + return toDelete; + } + + return null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EllieExpression[] GetExpressionsFor(ulong? maybeGuildId) + { + if (maybeGuildId is { } guildId) + return newguildExpressions.TryGetValue(guildId, out var exprs) ? exprs : Array.Empty(); + + return globalExpressions; + } + + #endregion + + public async Task ToggleGlobalExpressionsAsync(ulong guildId) + { + await using var ctx = _db.GetDbContext(); + var gc = ctx.GuildConfigsForId(guildId, set => set); + var toReturn = gc.DisableGlobalExpressions = !gc.DisableGlobalExpressions; + await ctx.SaveChangesAsync(); + + if (toReturn) + _disabledGlobalExpressionGuilds.Add(guildId); + else + _disabledGlobalExpressionGuilds.TryRemove(guildId); + + return toReturn; + } + + + public async Task<(IReadOnlyCollection Exprs, int TotalCount)> FindExpressionsAsync( + ulong guildId, + string query, + int page) + { + await using var ctx = _db.GetDbContext(); + + if (newguildExpressions.TryGetValue(guildId, out var exprs)) + { + return (exprs.Where(x => x.Trigger.Contains(query)) + .Skip(page * 9) + .Take(9) + .ToArray(), exprs.Length); + } + + return ([], 0); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Expressions/ExportedExpr.cs b/src/EllieBot/Modules/Expressions/ExportedExpr.cs new file mode 100644 index 0000000..c45fbdc --- /dev/null +++ b/src/EllieBot/Modules/Expressions/ExportedExpr.cs @@ -0,0 +1,27 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.EllieExpressions; + +public class ExportedExpr +{ + public string Res { get; set; } + public string Id { get; set; } + public bool Ad { get; set; } + public bool Dm { get; set; } + public bool At { get; set; } + public bool Ca { get; set; } + public string[] React; + + public static ExportedExpr FromModel(EllieExpression cr) + => new() + { + Res = cr.Response, + Id = ((kwum)cr.Id).ToString(), + Ad = cr.AutoDeleteTrigger, + At = cr.AllowTarget, + Ca = cr.ContainsAnywhere, + Dm = cr.DmResponse, + React = string.IsNullOrWhiteSpace(cr.Reactions) ? null : cr.GetReactions() + }; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Expressions/ExprField.cs b/src/EllieBot/Modules/Expressions/ExprField.cs new file mode 100644 index 0000000..9b9fa2f --- /dev/null +++ b/src/EllieBot/Modules/Expressions/ExprField.cs @@ -0,0 +1,10 @@ +namespace EllieBot.Modules.EllieExpressions; + +public enum ExprField +{ + AutoDelete, + DmResponse, + AllowTarget, + ContainsAnywhere, + Message +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Expressions/TypeReaders/CommandOrExprTypeReader.cs b/src/EllieBot/Modules/Expressions/TypeReaders/CommandOrExprTypeReader.cs new file mode 100644 index 0000000..716735e --- /dev/null +++ b/src/EllieBot/Modules/Expressions/TypeReaders/CommandOrExprTypeReader.cs @@ -0,0 +1,33 @@ +#nullable disable +using EllieBot.Modules.EllieExpressions; + +namespace EllieBot.Common.TypeReaders; + +public sealed class CommandOrExprTypeReader : EllieTypeReader +{ + private readonly CommandService _cmds; + private readonly ICommandHandler _commandHandler; + private readonly EllieExpressionsService _exprs; + + public CommandOrExprTypeReader(CommandService cmds, EllieExpressionsService exprs, ICommandHandler commandHandler) + { + _cmds = cmds; + _exprs = exprs; + _commandHandler = commandHandler; + } + + public override async ValueTask> ReadAsync(ICommandContext ctx, string input) + { + if (_exprs.ExpressionExists(ctx.Guild?.Id, input)) + return TypeReaderResult.FromSuccess(new CommandOrExprInfo(input, CommandOrExprInfo.Type.Custom)); + + var cmd = await new CommandTypeReader(_commandHandler, _cmds).ReadAsync(ctx, input); + if (cmd.IsSuccess) + { + return TypeReaderResult.FromSuccess(new CommandOrExprInfo(((CommandInfo)cmd.Values.First().Value).Name, + CommandOrExprInfo.Type.Normal)); + } + + return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or expression found."); + } +} \ No newline at end of file From 922f726a6e029efd1c3df66d8f21721f356b9a62 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:50:45 +1200 Subject: [PATCH 48/62] Added Gambling module --- .../Gambling/AnimalRacing/AnimalRace.cs | 153 +++ .../AnimalRacing/AnimalRaceService.cs | 9 + .../AnimalRacing/AnimalRacingCommands.cs | 197 ++++ .../Gambling/AnimalRacing/AnimalRacingUser.cs | 26 + .../Exceptions/AlreadyJoinedException.cs | 19 + .../Exceptions/AlreadyStartedException.cs | 19 + .../Exceptions/AnimalRaceFullException.cs | 19 + .../Exceptions/NotEnoughFundsException.cs | 19 + .../Gambling/AnimalRacing/RaceOptions.cs | 16 + .../Modules/Gambling/Bank/BankCommands.cs | 118 ++ .../Modules/Gambling/Bank/BankService.cs | 115 ++ .../Gambling/BlackJack/BlackJackCommands.cs | 183 +++ .../Gambling/BlackJack/BlackJackService.cs | 9 + .../Modules/Gambling/BlackJack/Blackjack.cs | 329 ++++++ .../Modules/Gambling/BlackJack/Player.cs | 57 + .../Modules/Gambling/Connect4/Connect4.cs | 409 +++++++ .../Gambling/Connect4/Connect4Commands.cs | 205 ++++ .../Modules/Gambling/CurrencyProvider.cs | 16 + .../Gambling/DiceRoll/DiceRollCommands.cs | 224 ++++ .../Modules/Gambling/Draw/DrawCommands.cs | 234 ++++ .../Modules/Gambling/EconomyResult.cs | 12 + .../Gambling/Events/CurrencyEventsCommands.cs | 60 + .../Gambling/Events/CurrencyEventsService.cs | 70 ++ .../Modules/Gambling/Events/EventOptions.cs | 39 + .../Gambling/Events/GameStatusEvent.cs | 198 ++++ .../Modules/Gambling/Events/ICurrencyEvent.cs | 9 + .../Modules/Gambling/Events/ReactionEvent.cs | 197 ++++ .../Gambling/FlipCoin/FlipCoinCommands.cs | 140 +++ .../Modules/Gambling/FlipCoin/FlipResult.cs | 7 + src/EllieBot/Modules/Gambling/Gambling.cs | 1032 +++++++++++++++++ .../Modules/Gambling/GamblingConfig.cs | 404 +++++++ .../Modules/Gambling/GamblingConfigService.cs | 194 ++++ .../Modules/Gambling/GamblingService.cs | 220 ++++ .../Gambling/GamblingTopLevelModule.cs | 68 ++ src/EllieBot/Modules/Gambling/InputRpsPick.cs | 3 + .../PlantPick/PlantAndPickCommands.cs | 114 ++ .../Gambling/PlantPick/PlantPickService.cs | 385 ++++++ .../Gambling/Raffle/CurrencyRaffleCommands.cs | 61 + .../Gambling/Raffle/CurrencyRaffleGame.cs | 69 ++ .../Gambling/Raffle/CurrencyRaffleService.cs | 81 ++ .../Modules/Gambling/Shop/IShopService.cs | 46 + .../Modules/Gambling/Shop/ShopCommands.cs | 590 ++++++++++ .../Modules/Gambling/Shop/ShopService.cs | 127 ++ .../Modules/Gambling/Slot/SlotCommands.cs | 230 ++++ .../Modules/Gambling/VoteRewardService.cs | 106 ++ .../Gambling/Waifus/WaifuClaimCommands.cs | 393 +++++++ .../Modules/Gambling/Waifus/WaifuService.cs | 582 ++++++++++ .../Gambling/Waifus/_common/AffinityTitle.cs | 16 + .../Gambling/Waifus/_common/ClaimTitle.cs | 18 + .../Gambling/Waifus/_common/DivorceResult.cs | 10 + .../Gambling/Waifus/_common/Extensions.cs | 6 + .../Waifus/_common/WaifuClaimResult.cs | 9 + .../Modules/Gambling/Waifus/db/Waifu.cs | 17 + .../Gambling/Waifus/db/WaifuExtensions.cs | 131 +++ .../Gambling/Waifus/db/WaifuInfoStats.cs | 14 + .../Modules/Gambling/Waifus/db/WaifuItem.cs | 10 + .../Gambling/Waifus/db/WaifuLbResult.cs | 16 + .../Modules/Gambling/Waifus/db/WaifuUpdate.cs | 15 + .../Gambling/Waifus/db/WaifuUpdateType.cs | 8 + .../Gambling/_common/Decks/QuadDeck.cs | 19 + .../_common/GamblingCleanupService.cs | 56 + .../_common/IGamblingCleanupService.cs | 8 + .../Gambling/_common/IGamblingService.cs | 18 + .../Gambling/_common/NewGamblingService.cs | 269 +++++ .../Modules/Gambling/_common/RollDuelGame.cs | 139 +++ .../BaseShmartInputAmountReader.cs | 95 ++ .../ShmartBankInputAmountReader.cs | 21 + .../TypeReaders/ShmartNumberTypeReader.cs | 57 + 68 files changed, 8765 insertions(+) create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRace.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRaceService.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingUser.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyJoinedException.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyStartedException.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AnimalRaceFullException.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/NotEnoughFundsException.cs create mode 100644 src/EllieBot/Modules/Gambling/AnimalRacing/RaceOptions.cs create mode 100644 src/EllieBot/Modules/Gambling/Bank/BankCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/Bank/BankService.cs create mode 100644 src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/BlackJack/BlackJackService.cs create mode 100644 src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs create mode 100644 src/EllieBot/Modules/Gambling/BlackJack/Player.cs create mode 100644 src/EllieBot/Modules/Gambling/Connect4/Connect4.cs create mode 100644 src/EllieBot/Modules/Gambling/Connect4/Connect4Commands.cs create mode 100644 src/EllieBot/Modules/Gambling/CurrencyProvider.cs create mode 100644 src/EllieBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/Draw/DrawCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/EconomyResult.cs create mode 100644 src/EllieBot/Modules/Gambling/Events/CurrencyEventsCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/Events/CurrencyEventsService.cs create mode 100644 src/EllieBot/Modules/Gambling/Events/EventOptions.cs create mode 100644 src/EllieBot/Modules/Gambling/Events/GameStatusEvent.cs create mode 100644 src/EllieBot/Modules/Gambling/Events/ICurrencyEvent.cs create mode 100644 src/EllieBot/Modules/Gambling/Events/ReactionEvent.cs create mode 100644 src/EllieBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/FlipCoin/FlipResult.cs create mode 100644 src/EllieBot/Modules/Gambling/Gambling.cs create mode 100644 src/EllieBot/Modules/Gambling/GamblingConfig.cs create mode 100644 src/EllieBot/Modules/Gambling/GamblingConfigService.cs create mode 100644 src/EllieBot/Modules/Gambling/GamblingService.cs create mode 100644 src/EllieBot/Modules/Gambling/GamblingTopLevelModule.cs create mode 100644 src/EllieBot/Modules/Gambling/InputRpsPick.cs create mode 100644 src/EllieBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/PlantPick/PlantPickService.cs create mode 100644 src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleGame.cs create mode 100644 src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleService.cs create mode 100644 src/EllieBot/Modules/Gambling/Shop/IShopService.cs create mode 100644 src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/Shop/ShopService.cs create mode 100644 src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/VoteRewardService.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/WaifuService.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/_common/AffinityTitle.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/_common/ClaimTitle.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/_common/DivorceResult.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/_common/Extensions.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/_common/WaifuClaimResult.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/WaifuInfoStats.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/WaifuLbResult.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs create mode 100644 src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdateType.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/Decks/QuadDeck.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/GamblingCleanupService.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/IGamblingCleanupService.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/IGamblingService.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/NewGamblingService.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/TypeReaders/BaseShmartInputAmountReader.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartBankInputAmountReader.cs create mode 100644 src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartNumberTypeReader.cs diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRace.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRace.cs new file mode 100644 index 0000000..84f10d4 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRace.cs @@ -0,0 +1,153 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common.AnimalRacing.Exceptions; +using EllieBot.Modules.Games.Common; + +namespace EllieBot.Modules.Gambling.Common.AnimalRacing; + +public sealed class AnimalRace : IDisposable +{ + public enum Phase + { + WaitingForPlayers, + Running, + Ended + } + + public event Func OnStarted = delegate { return Task.CompletedTask; }; + public event Func OnStartingFailed = delegate { return Task.CompletedTask; }; + public event Func OnStateUpdate = delegate { return Task.CompletedTask; }; + public event Func OnEnded = delegate { return Task.CompletedTask; }; + + public Phase CurrentPhase { get; private set; } = Phase.WaitingForPlayers; + + public IReadOnlyCollection Users + => _users.ToList(); + + public List FinishedUsers { get; } = new(); + public int MaxUsers { get; } + + private readonly SemaphoreSlim _locker = new(1, 1); + private readonly HashSet _users = new(); + private readonly ICurrencyService _currency; + private readonly RaceOptions _options; + private readonly Queue _animalsQueue; + + public AnimalRace(RaceOptions options, ICurrencyService currency, IEnumerable availableAnimals) + { + _currency = currency; + _options = options; + _animalsQueue = new(availableAnimals); + MaxUsers = _animalsQueue.Count; + + if (_animalsQueue.Count == 0) + CurrentPhase = Phase.Ended; + } + + public void Initialize() //lame name + => _ = Task.Run(async () => + { + await Task.Delay(_options.StartTime * 1000); + + await _locker.WaitAsync(); + try + { + if (CurrentPhase != Phase.WaitingForPlayers) + return; + + await Start(); + } + finally { _locker.Release(); } + }); + + public async Task JoinRace(ulong userId, string userName, long bet = 0) + { + ArgumentOutOfRangeException.ThrowIfNegative(bet); + + var user = new AnimalRacingUser(userName, userId, bet); + + await _locker.WaitAsync(); + try + { + if (_users.Count == MaxUsers) + throw new AnimalRaceFullException(); + + if (CurrentPhase != Phase.WaitingForPlayers) + throw new AlreadyStartedException(); + + if (!await _currency.RemoveAsync(userId, bet, new("animalrace", "bet"))) + throw new NotEnoughFundsException(); + + if (_users.Contains(user)) + throw new AlreadyJoinedException(); + + var animal = _animalsQueue.Dequeue(); + user.Animal = animal; + _users.Add(user); + + if (_animalsQueue.Count == 0) //start if no more spots left + await Start(); + + return user; + } + finally { _locker.Release(); } + } + + private async Task Start() + { + CurrentPhase = Phase.Running; + if (_users.Count <= 1) + { + foreach (var user in _users) + { + if (user.Bet > 0) + await _currency.AddAsync(user.UserId, user.Bet, new("animalrace", "refund")); + } + + _ = OnStartingFailed?.Invoke(this); + CurrentPhase = Phase.Ended; + return; + } + + _ = OnStarted?.Invoke(this); + _ = Task.Run(async () => + { + var rng = new EllieRandom(); + while (!_users.All(x => x.Progress >= 60)) + { + foreach (var user in _users) + { + user.Progress += rng.Next(1, 11); + if (user.Progress >= 60) + user.Progress = 60; + } + + var finished = _users.Where(x => x.Progress >= 60 && !FinishedUsers.Contains(x)).Shuffle(); + + FinishedUsers.AddRange(finished); + + _ = OnStateUpdate?.Invoke(this); + await Task.Delay(2500); + } + + if (FinishedUsers[0].Bet > 0) + { + await _currency.AddAsync(FinishedUsers[0].UserId, + FinishedUsers[0].Bet * (_users.Count - 1), + new("animalrace", "win")); + } + + _ = OnEnded?.Invoke(this); + }); + } + + public void Dispose() + { + CurrentPhase = Phase.Ended; + OnStarted = null; + OnEnded = null; + OnStartingFailed = null; + OnStateUpdate = null; + _locker.Dispose(); + _users.Clear(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRaceService.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRaceService.cs new file mode 100644 index 0000000..f4c99a8 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRaceService.cs @@ -0,0 +1,9 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common.AnimalRacing; + +namespace EllieBot.Modules.Gambling.Services; + +public class AnimalRaceService : IEService +{ + public ConcurrentDictionary AnimalRaces { get; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs new file mode 100644 index 0000000..1f23cf6 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingCommands.cs @@ -0,0 +1,197 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.AnimalRacing; +using EllieBot.Modules.Gambling.Common.AnimalRacing.Exceptions; +using EllieBot.Modules.Gambling.Services; +using EllieBot.Modules.Games.Services; + +namespace EllieBot.Modules.Gambling; + +// wth is this, needs full rewrite +public partial class Gambling +{ + [Group] + public partial class AnimalRacingCommands : GamblingSubmodule + { + private readonly ICurrencyService _cs; + private readonly DiscordSocketClient _client; + private readonly GamesConfigService _gamesConf; + + private IUserMessage raceMessage; + + public AnimalRacingCommands( + ICurrencyService cs, + DiscordSocketClient client, + GamblingConfigService gamblingConf, + GamesConfigService gamesConf) + : base(gamblingConf) + { + _cs = cs; + _client = client; + _gamesConf = gamesConf; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + public Task Race(params string[] args) + { + var (options, _) = OptionsParser.ParseFrom(new RaceOptions(), args); + + var ar = new AnimalRace(options, _cs, _gamesConf.Data.RaceAnimals.Shuffle()); + if (!_service.AnimalRaces.TryAdd(ctx.Guild.Id, ar)) + return Response() + .Error(GetText(strs.animal_race), GetText(strs.animal_race_already_started)) + .SendAsync(); + + ar.Initialize(); + + var count = 0; + + Task ClientMessageReceived(SocketMessage arg) + { + _ = Task.Run(() => + { + try + { + if (arg.Channel.Id == ctx.Channel.Id) + { + if (ar.CurrentPhase == AnimalRace.Phase.Running && ++count % 9 == 0) + raceMessage = null; + } + } + catch { } + }); + return Task.CompletedTask; + } + + Task ArOnEnded(AnimalRace race) + { + _client.MessageReceived -= ClientMessageReceived; + _service.AnimalRaces.TryRemove(ctx.Guild.Id, out _); + var winner = race.FinishedUsers[0]; + if (race.FinishedUsers[0].Bet > 0) + { + return Response() + .Confirm(GetText(strs.animal_race), + GetText(strs.animal_race_won_money(Format.Bold(winner.Username), + winner.Animal.Icon, + (race.FinishedUsers[0].Bet * (race.Users.Count - 1)) + CurrencySign))) + .SendAsync(); + } + + ar.Dispose(); + return Response() + .Confirm(GetText(strs.animal_race), + GetText(strs.animal_race_won(Format.Bold(winner.Username), winner.Animal.Icon))) + .SendAsync(); + } + + ar.OnStartingFailed += Ar_OnStartingFailed; + ar.OnStateUpdate += Ar_OnStateUpdate; + ar.OnEnded += ArOnEnded; + ar.OnStarted += Ar_OnStarted; + _client.MessageReceived += ClientMessageReceived; + + return Response() + .Confirm(GetText(strs.animal_race), + GetText(strs.animal_race_starting(options.StartTime)), + footer: GetText(strs.animal_race_join_instr(prefix))) + .SendAsync(); + } + + private Task Ar_OnStarted(AnimalRace race) + { + if (race.Users.Count == race.MaxUsers) + return Response().Confirm(GetText(strs.animal_race), GetText(strs.animal_race_full)).SendAsync(); + return Response() + .Confirm(GetText(strs.animal_race), + GetText(strs.animal_race_starting_with_x(race.Users.Count))) + .SendAsync(); + } + + private async Task Ar_OnStateUpdate(AnimalRace race) + { + var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚| +{string.Join("\n", race.Users.Select(p => +{ + var index = race.FinishedUsers.IndexOf(p); + var extra = index == -1 ? "" : $"#{index + 1} {(index == 0 ? "🏆" : "")}"; + return $"{(int)(p.Progress / 60f * 100),-2}%|{new string('‣', p.Progress) + p.Animal.Icon + extra}"; +}))} +|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|"; + + var msg = raceMessage; + + if (msg is null) + raceMessage = await Response().Confirm(text).SendAsync(); + else + { + await msg.ModifyAsync(x => x.Embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.animal_race)) + .WithDescription(text) + .WithOkColor() + .Build()); + } + } + + private Task Ar_OnStartingFailed(AnimalRace race) + { + _service.AnimalRaces.TryRemove(ctx.Guild.Id, out _); + race.Dispose(); + return Response().Error(strs.animal_race_failed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task JoinRace([OverrideTypeReader(typeof(BalanceTypeReader))] long amount = default) + { + if (!await CheckBetOptional(amount)) + return; + + if (!_service.AnimalRaces.TryGetValue(ctx.Guild.Id, out var ar)) + { + await Response().Error(strs.race_not_exist).SendAsync(); + return; + } + + try + { + var user = await ar.JoinRace(ctx.User.Id, ctx.User.ToString(), amount); + if (amount > 0) + { + await Response() + .Confirm(GetText(strs.animal_race_join_bet(ctx.User.Mention, + user.Animal.Icon, + amount + CurrencySign))) + .SendAsync(); + } + else + await Response() + .Confirm(strs.animal_race_join(ctx.User.Mention, user.Animal.Icon)) + .SendAsync(); + } + catch (ArgumentOutOfRangeException) + { + //ignore if user inputed an invalid amount + } + catch (AlreadyJoinedException) + { + // just ignore this + } + catch (AlreadyStartedException) + { + //ignore + } + catch (AnimalRaceFullException) + { + await Response().Confirm(GetText(strs.animal_race), GetText(strs.animal_race_full)).SendAsync(); + } + catch (NotEnoughFundsException) + { + await Response().Error(GetText(strs.not_enough(CurrencySign))).SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingUser.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingUser.cs new file mode 100644 index 0000000..814b475 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/AnimalRacingUser.cs @@ -0,0 +1,26 @@ +#nullable disable +using EllieBot.Modules.Games.Common; + +namespace EllieBot.Modules.Gambling.Common.AnimalRacing; + +public class AnimalRacingUser +{ + public long Bet { get; } + public string Username { get; } + public ulong UserId { get; } + public RaceAnimal Animal { get; set; } + public int Progress { get; set; } + + public AnimalRacingUser(string username, ulong userId, long bet) + { + Bet = bet; + Username = username; + UserId = userId; + } + + public override bool Equals(object obj) + => obj is AnimalRacingUser x ? x.UserId == UserId : false; + + public override int GetHashCode() + => UserId.GetHashCode(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyJoinedException.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyJoinedException.cs new file mode 100644 index 0000000..914b6a4 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyJoinedException.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.AnimalRacing.Exceptions; + +public class AlreadyJoinedException : Exception +{ + public AlreadyJoinedException() + { + } + + public AlreadyJoinedException(string message) + : base(message) + { + } + + public AlreadyJoinedException(string message, Exception innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyStartedException.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyStartedException.cs new file mode 100644 index 0000000..e662785 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AlreadyStartedException.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.AnimalRacing.Exceptions; + +public class AlreadyStartedException : Exception +{ + public AlreadyStartedException() + { + } + + public AlreadyStartedException(string message) + : base(message) + { + } + + public AlreadyStartedException(string message, Exception innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AnimalRaceFullException.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AnimalRaceFullException.cs new file mode 100644 index 0000000..9a76b5b --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/AnimalRaceFullException.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.AnimalRacing.Exceptions; + +public class AnimalRaceFullException : Exception +{ + public AnimalRaceFullException() + { + } + + public AnimalRaceFullException(string message) + : base(message) + { + } + + public AnimalRaceFullException(string message, Exception innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/NotEnoughFundsException.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/NotEnoughFundsException.cs new file mode 100644 index 0000000..b827761 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/Exceptions/NotEnoughFundsException.cs @@ -0,0 +1,19 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.AnimalRacing.Exceptions; + +public class NotEnoughFundsException : Exception +{ + public NotEnoughFundsException() + { + } + + public NotEnoughFundsException(string message) + : base(message) + { + } + + public NotEnoughFundsException(string message, Exception innerException) + : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/AnimalRacing/RaceOptions.cs b/src/EllieBot/Modules/Gambling/AnimalRacing/RaceOptions.cs new file mode 100644 index 0000000..fb0f8c9 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/AnimalRacing/RaceOptions.cs @@ -0,0 +1,16 @@ +#nullable disable +using CommandLine; + +namespace EllieBot.Modules.Gambling.Common.AnimalRacing; + +public class RaceOptions : IEllieCommandOptions +{ + [Option('s', "start-time", Default = 20, Required = false)] + public int StartTime { get; set; } = 20; + + public void NormalizeOptions() + { + if (StartTime is < 10 or > 120) + StartTime = 20; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Bank/BankCommands.cs b/src/EllieBot/Modules/Gambling/Bank/BankCommands.cs new file mode 100644 index 0000000..91388ef --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Bank/BankCommands.cs @@ -0,0 +1,118 @@ +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Bank; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Name("Bank")] + [Group("bank")] + public partial class BankCommands : GamblingModule + { + private readonly IBankService _bank; + private readonly DiscordSocketClient _client; + + public BankCommands(GamblingConfigService gcs, + IBankService bank, + DiscordSocketClient client) : base(gcs) + { + _bank = bank; + _client = client; + } + + [Cmd] + public async Task BankDeposit([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) + { + if (amount <= 0) + return; + + if (await _bank.DepositAsync(ctx.User.Id, amount)) + { + await Response().Confirm(strs.bank_deposited(N(amount))).SendAsync(); + } + else + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + } + } + + [Cmd] + public async Task BankWithdraw([OverrideTypeReader(typeof(BankBalanceTypeReader))] long amount) + { + if (amount <= 0) + return; + + if (await _bank.WithdrawAsync(ctx.User.Id, amount)) + { + await Response().Confirm(strs.bank_withdrew(N(amount))).SendAsync(); + } + else + { + await Response().Error(strs.bank_withdraw_insuff(CurrencySign)).SendAsync(); + } + } + + [Cmd] + public async Task BankBalance() + { + var bal = await _bank.GetBalanceAsync(ctx.User.Id); + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithDescription(GetText(strs.bank_balance(N(bal)))); + + try + { + await Response().User(ctx.User).Embed(eb).SendAsync(); + await ctx.OkAsync(); + } + catch + { + await Response().Error(strs.cant_dm).SendAsync(); + } + } + + private async Task BankTakeInternalAsync(long amount, ulong userId) + { + if (await _bank.TakeAsync(userId, amount)) + { + await ctx.OkAsync(); + return; + } + + await Response().Error(strs.take_fail(N(amount), + _client.GetUser(userId)?.ToString() + ?? userId.ToString(), + CurrencySign)).SendAsync(); + } + + private async Task BankAwardInternalAsync(long amount, ulong userId) + { + if (await _bank.AwardAsync(userId, amount)) + { + await ctx.OkAsync(); + return; + } + + } + + [Cmd] + [OwnerOnly] + [Priority(1)] + public async Task BankTake(long amount, [Leftover] IUser user) + => await BankTakeInternalAsync(amount, user.Id); + + [Cmd] + [OwnerOnly] + [Priority(0)] + public async Task BankTake(long amount, ulong userId) + => await BankTakeInternalAsync(amount, userId); + + [Cmd] + [OwnerOnly] + public async Task BankAward(long amount, [Leftover] IUser user) + => await BankAwardInternalAsync(amount, user.Id); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Bank/BankService.cs b/src/EllieBot/Modules/Gambling/Bank/BankService.cs new file mode 100644 index 0000000..0d75607 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Bank/BankService.cs @@ -0,0 +1,115 @@ +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling.Bank; + +public sealed class BankService : IBankService, IEService +{ + private readonly ICurrencyService _cur; + private readonly DbService _db; + + public BankService(ICurrencyService cur, DbService db) + { + _cur = cur; + _db = db; + } + + public async Task AwardAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); + + await using var ctx = _db.GetDbContext(); + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + UserId = userId, + Balance = amount + }, + (old) => new() + { + Balance = old.Balance + amount + }, + () => new() + { + UserId = userId + }); + + return true; + } + + public async Task TakeAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); + + await using var ctx = _db.GetDbContext(); + var rows = await ctx.Set() + .ToLinqToDBTable() + .Where(x => x.UserId == userId && x.Balance >= amount) + .UpdateAsync((old) => new() + { + Balance = old.Balance - amount + }); + + return rows > 0; + } + + public async Task DepositAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); + + if (!await _cur.RemoveAsync(userId, amount, new("bank", "deposit"))) + return false; + + await using var ctx = _db.GetDbContext(); + await ctx.Set() + .ToLinqToDBTable() + .InsertOrUpdateAsync(() => new() + { + UserId = userId, + Balance = amount + }, + (old) => new() + { + Balance = old.Balance + amount + }, + () => new() + { + UserId = userId + }); + + return true; + } + + public async Task WithdrawAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); + + await using var ctx = _db.GetDbContext(); + var rows = await ctx.Set() + .ToLinqToDBTable() + .Where(x => x.UserId == userId && x.Balance >= amount) + .UpdateAsync((old) => new() + { + Balance = old.Balance - amount + }); + + if (rows > 0) + { + await _cur.AddAsync(userId, amount, new("bank", "withdraw")); + return true; + } + + return false; + } + + public async Task GetBalanceAsync(ulong userId) + { + await using var ctx = _db.GetDbContext(); + return (await ctx.Set() + .ToLinqToDBTable() + .FirstOrDefaultAsync(x => x.UserId == userId)) + ?.Balance + ?? 0; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs b/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs new file mode 100644 index 0000000..772cb4f --- /dev/null +++ b/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs @@ -0,0 +1,183 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Blackjack; +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + public partial class BlackJackCommands : GamblingSubmodule + { + public enum BjAction + { + Hit = int.MinValue, + Stand, + Double + } + + private readonly ICurrencyService _cs; + private readonly DbService _db; + private IUserMessage msg; + + public BlackJackCommands(ICurrencyService cs, DbService db, GamblingConfigService gamblingConf) + : base(gamblingConf) + { + _cs = cs; + _db = db; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task BlackJack([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) + { + if (!await CheckBetMandatory(amount)) + return; + + var newBj = new Blackjack(_cs); + Blackjack bj; + if (newBj == (bj = _service.Games.GetOrAdd(ctx.Channel.Id, newBj))) + { + if (!await bj.Join(ctx.User, amount)) + { + _service.Games.TryRemove(ctx.Channel.Id, out _); + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + bj.StateUpdated += Bj_StateUpdated; + bj.GameEnded += Bj_GameEnded; + bj.Start(); + + await Response().NoReply().Confirm(strs.bj_created(ctx.User.ToString())).SendAsync(); + } + else + { + if (await bj.Join(ctx.User, amount)) + await Response().NoReply().Confirm(strs.bj_joined(ctx.User.ToString())).SendAsync(); + else + { + Log.Information("{User} can't join a blackjack game as it's in {BlackjackState} state already", + ctx.User, + bj.State); + } + } + + await ctx.Message.DeleteAsync(); + } + + private Task Bj_GameEnded(Blackjack arg) + { + _service.Games.TryRemove(ctx.Channel.Id, out _); + return Task.CompletedTask; + } + + private async Task Bj_StateUpdated(Blackjack bj) + { + try + { + if (msg is not null) + _ = msg.DeleteAsync(); + + var c = bj.Dealer.Cards.Select(x => x.GetEmojiString()) + .ToList(); + var dealerIcon = "❔ "; + if (bj.State == Blackjack.GameState.Ended) + { + if (bj.Dealer.GetHandValue() == 21) + dealerIcon = "💰 "; + else if (bj.Dealer.GetHandValue() > 21) + dealerIcon = "💥 "; + else + dealerIcon = "🏁 "; + } + + var cStr = string.Concat(c.Select(x => x[..^1] + " ")); + cStr += "\n" + string.Concat(c.Select(x => x.Last() + " ")); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("BlackJack") + .AddField($"{dealerIcon} Dealer's Hand | Value: {bj.Dealer.GetHandValue()}", cStr); + + if (bj.CurrentUser is not null) + embed.WithFooter($"Player to make a choice: {bj.CurrentUser.DiscordUser}"); + + foreach (var p in bj.Players) + { + c = p.Cards.Select(x => x.GetEmojiString()).ToList(); + cStr = "-\t" + string.Concat(c.Select(x => x[..^1] + " ")); + cStr += "\n-\t" + string.Concat(c.Select(x => x.Last() + " ")); + var full = $"{p.DiscordUser.ToString().TrimTo(20)} | Bet: {N(p.Bet)} | Value: {p.GetHandValue()}"; + if (bj.State == Blackjack.GameState.Ended) + { + if (p.State == User.UserState.Lost) + full = "❌ " + full; + else + full = "✅ " + full; + } + else if (p == bj.CurrentUser) + full = "▶ " + full; + else if (p.State == User.UserState.Stand) + full = "⏹ " + full; + else if (p.State == User.UserState.Bust) + full = "💥 " + full; + else if (p.State == User.UserState.Blackjack) + full = "💰 " + full; + + embed.AddField(full, cStr); + } + + msg = await Response().Embed(embed).SendAsync(); + } + catch + { + } + } + + private string UserToString(User x) + { + var playerName = x.State == User.UserState.Bust + ? Format.Strikethrough(x.DiscordUser.ToString().TrimTo(30)) + : x.DiscordUser.ToString(); + + // var hand = $"{string.Concat(x.Cards.Select(y => "〖" + y.GetEmojiString() + "〗"))}"; + + + return $"{playerName} | Bet: {x.Bet}\n"; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task Hit() + => InternalBlackJack(BjAction.Hit); + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task Stand() + => InternalBlackJack(BjAction.Stand); + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task Double() + => InternalBlackJack(BjAction.Double); + + private async Task InternalBlackJack(BjAction a) + { + if (!_service.Games.TryGetValue(ctx.Channel.Id, out var bj)) + return; + + if (a == BjAction.Hit) + await bj.Hit(ctx.User); + else if (a == BjAction.Stand) + await bj.Stand(ctx.User); + else if (a == BjAction.Double) + { + if (!await bj.Double(ctx.User)) + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + } + + await ctx.Message.DeleteAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/BlackJack/BlackJackService.cs b/src/EllieBot/Modules/Gambling/BlackJack/BlackJackService.cs new file mode 100644 index 0000000..3bfb87c --- /dev/null +++ b/src/EllieBot/Modules/Gambling/BlackJack/BlackJackService.cs @@ -0,0 +1,9 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common.Blackjack; + +namespace EllieBot.Modules.Gambling.Services; + +public class BlackJackService : IEService +{ + public ConcurrentDictionary Games { get; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs new file mode 100644 index 0000000..e21d2cd --- /dev/null +++ b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs @@ -0,0 +1,329 @@ +#nullable disable +using Ellie.Econ; + +namespace EllieBot.Modules.Gambling.Common.Blackjack; + +public class Blackjack +{ + public enum GameState + { + Starting, + Playing, + Ended + } + + public event Func StateUpdated; + public event Func GameEnded; + + private Deck Deck { get; } = new QuadDeck(); + public Dealer Dealer { get; set; } + + + public List Players { get; set; } = new(); + public GameState State { get; set; } = GameState.Starting; + public User CurrentUser { get; private set; } + + private TaskCompletionSource currentUserMove; + private readonly ICurrencyService _cs; + + private readonly SemaphoreSlim _locker = new(1, 1); + + public Blackjack(ICurrencyService cs) + { + _cs = cs; + Dealer = new(); + } + + public void Start() + => _ = GameLoop(); + + public async Task GameLoop() + { + try + { + //wait for players to join + await Task.Delay(20000); + await _locker.WaitAsync(); + try + { + State = GameState.Playing; + } + finally + { + _locker.Release(); + } + + await PrintState(); + //if no users joined the game, end it + if (!Players.Any()) + { + State = GameState.Ended; + _ = GameEnded?.Invoke(this); + return; + } + + //give 1 card to the dealer and 2 to each player + Dealer.Cards.Add(Deck.Draw()); + foreach (var usr in Players) + { + usr.Cards.Add(Deck.Draw()); + usr.Cards.Add(Deck.Draw()); + + if (usr.GetHandValue() == 21) + usr.State = User.UserState.Blackjack; + } + + //go through all users and ask them what they want to do + foreach (var usr in Players.Where(x => !x.Done)) + { + while (!usr.Done) + { + Log.Information("Waiting for {DiscordUser}'s move", usr.DiscordUser); + await PromptUserMove(usr); + } + } + + await PrintState(); + State = GameState.Ended; + await Task.Delay(2500); + Log.Information("Dealer moves"); + await DealerMoves(); + await PrintState(); + _ = GameEnded?.Invoke(this); + } + catch (Exception ex) + { + Log.Error(ex, "REPORT THE MESSAGE BELOW IN Ellie's Home SERVER PLEASE"); + State = GameState.Ended; + _ = GameEnded?.Invoke(this); + } + } + + private async Task PromptUserMove(User usr) + { + using var cts = new CancellationTokenSource(); + var pause = Task.Delay(20000, cts.Token); //10 seconds to decide + CurrentUser = usr; + currentUserMove = new(); + await PrintState(); + // either wait for the user to make an action and + // if he doesn't - stand + var finished = await Task.WhenAny(pause, currentUserMove.Task); + if (finished == pause) + await Stand(usr); + else + cts.Cancel(); + + CurrentUser = null; + currentUserMove = null; + } + + public async Task Join(IUser user, long bet) + { + await _locker.WaitAsync(); + try + { + if (State != GameState.Starting) + return false; + + if (Players.Count >= 5) + return false; + + if (!await _cs.RemoveAsync(user, bet, new("blackjack", "gamble"))) + return false; + + Players.Add(new(user, bet)); + _ = PrintState(); + return true; + } + finally + { + _locker.Release(); + } + } + + public async Task Stand(IUser u) + { + var cu = CurrentUser; + + if (cu is not null && cu.DiscordUser == u) + return await Stand(cu); + + return false; + } + + public async Task Stand(User u) + { + await _locker.WaitAsync(); + try + { + if (State != GameState.Playing) + return false; + + if (CurrentUser != u) + return false; + + u.State = User.UserState.Stand; + currentUserMove.TrySetResult(true); + return true; + } + finally + { + _locker.Release(); + } + } + + private async Task DealerMoves() + { + var hw = Dealer.GetHandValue(); + while (hw < 17 + || (hw == 17 + && Dealer.Cards.Count(x => x.Number == 1) > (Dealer.GetRawHandValue() - 17) / 10)) // hit on soft 17 + { + /* Dealer has + A 6 + That's 17, soft + hw == 17 => true + number of aces = 1 + 1 > 17-17 /10 => true + + AA 5 + That's 17, again soft, since one ace is worth 11, even though another one is 1 + hw == 17 => true + number of aces = 2 + 2 > 27 - 17 / 10 => true + + AA Q 5 + That's 17, but not soft, since both aces are worth 1 + hw == 17 => true + number of aces = 2 + 2 > 37 - 17 / 10 => false + * */ + Dealer.Cards.Add(Deck.Draw()); + hw = Dealer.GetHandValue(); + } + + if (hw > 21) + { + foreach (var usr in Players) + { + if (usr.State is User.UserState.Stand or User.UserState.Blackjack) + usr.State = User.UserState.Won; + else + usr.State = User.UserState.Lost; + } + } + else + { + foreach (var usr in Players) + { + if (usr.State == User.UserState.Blackjack) + usr.State = User.UserState.Won; + else if (usr.State == User.UserState.Stand) + usr.State = hw < usr.GetHandValue() ? User.UserState.Won : User.UserState.Lost; + else + usr.State = User.UserState.Lost; + } + } + + foreach (var usr in Players) + { + if (usr.State is User.UserState.Won or User.UserState.Blackjack) + await _cs.AddAsync(usr.DiscordUser.Id, usr.Bet * 2, new("blackjack", "win")); + } + } + + public async Task Double(IUser u) + { + var cu = CurrentUser; + + if (cu is not null && cu.DiscordUser == u) + return await Double(cu); + + return false; + } + + public async Task Double(User u) + { + await _locker.WaitAsync(); + try + { + if (State != GameState.Playing) + return false; + + if (CurrentUser != u) + return false; + + if (!await _cs.RemoveAsync(u.DiscordUser.Id, u.Bet, new("blackjack", "double"))) + return false; + + u.Bet *= 2; + + u.Cards.Add(Deck.Draw()); + + if (u.GetHandValue() == 21) + //blackjack + u.State = User.UserState.Blackjack; + else if (u.GetHandValue() > 21) + // user busted + u.State = User.UserState.Bust; + else + //with double you just get one card, and then you're done + u.State = User.UserState.Stand; + currentUserMove.TrySetResult(true); + + return true; + } + finally + { + _locker.Release(); + } + } + + public async Task Hit(IUser u) + { + var cu = CurrentUser; + + if (cu is not null && cu.DiscordUser == u) + return await Hit(cu); + + return false; + } + + public async Task Hit(User u) + { + await _locker.WaitAsync(); + try + { + if (State != GameState.Playing) + return false; + + if (CurrentUser != u) + return false; + + u.Cards.Add(Deck.Draw()); + + if (u.GetHandValue() == 21) + //blackjack + u.State = User.UserState.Blackjack; + else if (u.GetHandValue() > 21) + // user busted + u.State = User.UserState.Bust; + + currentUserMove.TrySetResult(true); + + return true; + } + finally + { + _locker.Release(); + } + } + + public Task PrintState() + { + if (StateUpdated is null) + return Task.CompletedTask; + return StateUpdated.Invoke(this); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/BlackJack/Player.cs b/src/EllieBot/Modules/Gambling/BlackJack/Player.cs new file mode 100644 index 0000000..fb238c1 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/BlackJack/Player.cs @@ -0,0 +1,57 @@ +#nullable disable +using Ellie.Econ; + +namespace EllieBot.Modules.Gambling.Common.Blackjack; + +public abstract class Player +{ + public List Cards { get; } = new(); + + public int GetHandValue() + { + var val = GetRawHandValue(); + + // while the hand value is greater than 21, for each ace you have in the deck + // reduce the value by 10 until it drops below 22 + // (emulating the fact that ace is either a 1 or a 11) + var i = Cards.Count(x => x.Number == 1); + while (val > 21 && i-- > 0) + val -= 10; + return val; + } + + public int GetRawHandValue() + => Cards.Sum(x => x.Number == 1 ? 11 : x.Number >= 10 ? 10 : x.Number); +} + +public class Dealer : Player +{ +} + +public class User : Player +{ + public enum UserState + { + Waiting, + Stand, + Bust, + Blackjack, + Won, + Lost + } + + public UserState State { get; set; } = UserState.Waiting; + public long Bet { get; set; } + public IUser DiscordUser { get; } + + public bool Done + => State != UserState.Waiting; + + public User(IUser user, long bet) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(bet); + + Bet = bet; + DiscordUser = user; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Connect4/Connect4.cs b/src/EllieBot/Modules/Gambling/Connect4/Connect4.cs new file mode 100644 index 0000000..45d2e89 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Connect4/Connect4.cs @@ -0,0 +1,409 @@ +#nullable disable +using CommandLine; +using System.Collections.Immutable; + +namespace EllieBot.Modules.Gambling.Common.Connect4; + +public sealed class Connect4Game : IDisposable +{ + public enum Field //temporary most likely + { + Empty, + P1, + P2 + } + + public enum Phase + { + Joining, // waiting for second player to join + P1Move, + P2Move, + Ended + } + + public enum Result + { + Draw, + CurrentPlayerWon, + OtherPlayerWon + } + + public const int NUMBER_OF_COLUMNS = 7; + public const int NUMBER_OF_ROWS = 6; + + //public event Func OnGameStarted; + public event Func OnGameStateUpdated; + public event Func OnGameFailedToStart; + public event Func OnGameEnded; + + public Phase CurrentPhase { get; private set; } = Phase.Joining; + + public ImmutableArray GameState + => _gameState.ToImmutableArray(); + + public ImmutableArray<(ulong UserId, string Username)?> Players + => _players.ToImmutableArray(); + + public (ulong UserId, string Username) CurrentPlayer + => CurrentPhase == Phase.P1Move ? _players[0].Value : _players[1].Value; + + public (ulong UserId, string Username) OtherPlayer + => CurrentPhase == Phase.P2Move ? _players[0].Value : _players[1].Value; + + //state is bottom to top, left to right + private readonly Field[] _gameState = new Field[NUMBER_OF_ROWS * NUMBER_OF_COLUMNS]; + private readonly (ulong UserId, string Username)?[] _players = new (ulong, string)?[2]; + + private readonly SemaphoreSlim _locker = new(1, 1); + private readonly Options _options; + private readonly ICurrencyService _cs; + private readonly EllieRandom _rng; + + private Timer playerTimeoutTimer; + + /* [ ][ ][ ][ ][ ][ ] + * [ ][ ][ ][ ][ ][ ] + * [ ][ ][ ][ ][ ][ ] + * [ ][ ][ ][ ][ ][ ] + * [ ][ ][ ][ ][ ][ ] + * [ ][ ][ ][ ][ ][ ] + * [ ][ ][ ][ ][ ][ ] + */ + + public Connect4Game( + ulong userId, + string userName, + Options options, + ICurrencyService cs) + { + _players[0] = (userId, userName); + _options = options; + _cs = cs; + + _rng = new(); + for (var i = 0; i < NUMBER_OF_COLUMNS * NUMBER_OF_ROWS; i++) + _gameState[i] = Field.Empty; + } + + public void Initialize() + { + if (CurrentPhase != Phase.Joining) + return; + _ = Task.Run(async () => + { + await Task.Delay(15000); + await _locker.WaitAsync(); + try + { + if (_players[1] is null) + { + _ = OnGameFailedToStart?.Invoke(this); + CurrentPhase = Phase.Ended; + await _cs.AddAsync(_players[0].Value.UserId, _options.Bet, new("connect4", "refund")); + } + } + finally { _locker.Release(); } + }); + } + + public async Task Join(ulong userId, string userName, int bet) + { + await _locker.WaitAsync(); + try + { + if (CurrentPhase != Phase.Joining) //can't join if its not a joining phase + return false; + + if (_players[0].Value.UserId == userId) // same user can't join own game + return false; + + if (bet != _options.Bet) // can't join if bet amount is not the same + return false; + + if (!await _cs.RemoveAsync(userId, bet, new("connect4", "bet"))) // user doesn't have enough money to gamble + return false; + + if (_rng.Next(0, 2) == 0) //rolling from 0-1, if number is 0, join as first player + { + _players[1] = _players[0]; + _players[0] = (userId, userName); + } + else //else join as a second player + _players[1] = (userId, userName); + + CurrentPhase = Phase.P1Move; //start the game + playerTimeoutTimer = new(async _ => + { + await _locker.WaitAsync(); + try + { + EndGame(Result.OtherPlayerWon, OtherPlayer.UserId); + } + finally { _locker.Release(); } + }, + null, + TimeSpan.FromSeconds(_options.TurnTimer), + TimeSpan.FromSeconds(_options.TurnTimer)); + _ = OnGameStateUpdated?.Invoke(this); + + return true; + } + finally { _locker.Release(); } + } + + public async Task Input(ulong userId, int inputCol) + { + await _locker.WaitAsync(); + try + { + inputCol -= 1; + if (CurrentPhase is Phase.Ended or Phase.Joining) + return false; + + if (!((_players[0].Value.UserId == userId && CurrentPhase == Phase.P1Move) + || (_players[1].Value.UserId == userId && CurrentPhase == Phase.P2Move))) + return false; + + if (inputCol is < 0 or > NUMBER_OF_COLUMNS) //invalid input + return false; + + if (IsColumnFull(inputCol)) //can't play there event? + return false; + + var start = NUMBER_OF_ROWS * inputCol; + for (var i = start; i < start + NUMBER_OF_ROWS; i++) + { + if (_gameState[i] == Field.Empty) + { + _gameState[i] = GetPlayerPiece(userId); + break; + } + } + + //check winnning condition + // ok, i'll go from [0-2] in rows (and through all columns) and check upward if 4 are connected + + for (var i = 0; i < NUMBER_OF_ROWS - 3; i++) + { + if (CurrentPhase == Phase.Ended) + break; + + for (var j = 0; j < NUMBER_OF_COLUMNS; j++) + { + if (CurrentPhase == Phase.Ended) + break; + + var first = _gameState[i + (j * NUMBER_OF_ROWS)]; + if (first != Field.Empty) + { + for (var k = 1; k < 4; k++) + { + var next = _gameState[i + k + (j * NUMBER_OF_ROWS)]; + if (next == first) + { + if (k == 3) + EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId); + else + continue; + } + else + break; + } + } + } + } + + // i'll go [0-1] in columns (and through all rows) and check to the right if 4 are connected + for (var i = 0; i < NUMBER_OF_COLUMNS - 3; i++) + { + if (CurrentPhase == Phase.Ended) + break; + + for (var j = 0; j < NUMBER_OF_ROWS; j++) + { + if (CurrentPhase == Phase.Ended) + break; + + var first = _gameState[j + (i * NUMBER_OF_ROWS)]; + if (first != Field.Empty) + { + for (var k = 1; k < 4; k++) + { + var next = _gameState[j + ((i + k) * NUMBER_OF_ROWS)]; + if (next == first) + { + if (k == 3) + EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId); + else + continue; + } + else + break; + } + } + } + } + + //need to check diagonal now + for (var col = 0; col < NUMBER_OF_COLUMNS; col++) + { + if (CurrentPhase == Phase.Ended) + break; + + for (var row = 0; row < NUMBER_OF_ROWS; row++) + { + if (CurrentPhase == Phase.Ended) + break; + + var first = _gameState[row + (col * NUMBER_OF_ROWS)]; + + if (first != Field.Empty) + { + var same = 1; + + //top left + for (var i = 1; i < 4; i++) + { + //while going top left, rows are increasing, columns are decreasing + var curRow = row + i; + var curCol = col - i; + + //check if current values are in range + if (curRow is >= NUMBER_OF_ROWS or < 0) + break; + if (curCol is < 0 or >= NUMBER_OF_COLUMNS) + break; + + var cur = _gameState[curRow + (curCol * NUMBER_OF_ROWS)]; + if (cur == first) + same++; + else + break; + } + + if (same == 4) + { + EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId); + break; + } + + same = 1; + + //top right + for (var i = 1; i < 4; i++) + { + //while going top right, rows are increasing, columns are increasing + var curRow = row + i; + var curCol = col + i; + + //check if current values are in range + if (curRow is >= NUMBER_OF_ROWS or < 0) + break; + if (curCol is < 0 or >= NUMBER_OF_COLUMNS) + break; + + var cur = _gameState[curRow + (curCol * NUMBER_OF_ROWS)]; + if (cur == first) + same++; + else + break; + } + + if (same == 4) + { + EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId); + break; + } + } + } + } + + //check draw? if it's even possible + if (_gameState.All(x => x != Field.Empty)) + EndGame(Result.Draw, null); + + if (CurrentPhase != Phase.Ended) + { + if (CurrentPhase == Phase.P1Move) + CurrentPhase = Phase.P2Move; + else + CurrentPhase = Phase.P1Move; + + ResetTimer(); + } + + _ = OnGameStateUpdated?.Invoke(this); + return true; + } + finally { _locker.Release(); } + } + + private void ResetTimer() + => playerTimeoutTimer.Change(TimeSpan.FromSeconds(_options.TurnTimer), + TimeSpan.FromSeconds(_options.TurnTimer)); + + private void EndGame(Result result, ulong? winId) + { + if (CurrentPhase == Phase.Ended) + return; + _ = OnGameEnded?.Invoke(this, result); + CurrentPhase = Phase.Ended; + + if (result == Result.Draw) + { + _cs.AddAsync(CurrentPlayer.UserId, _options.Bet, new("connect4", "draw")); + _cs.AddAsync(OtherPlayer.UserId, _options.Bet, new("connect4", "draw")); + return; + } + + if (winId is not null) + _cs.AddAsync(winId.Value, (long)(_options.Bet * 1.98), new("connect4", "win")); + } + + private Field GetPlayerPiece(ulong userId) + => _players[0].Value.UserId == userId ? Field.P1 : Field.P2; + + //column is full if there are no empty fields + private bool IsColumnFull(int column) + { + var start = NUMBER_OF_ROWS * column; + for (var i = start; i < start + NUMBER_OF_ROWS; i++) + { + if (_gameState[i] == Field.Empty) + return false; + } + + return true; + } + + public void Dispose() + { + OnGameFailedToStart = null; + OnGameStateUpdated = null; + OnGameEnded = null; + playerTimeoutTimer?.Change(Timeout.Infinite, Timeout.Infinite); + } + + + public class Options : IEllieCommandOptions + { + [Option('t', + "turn-timer", + Required = false, + Default = 15, + HelpText = "Turn time in seconds. It has to be between 5 and 60. Default 15.")] + public int TurnTimer { get; set; } = 15; + + [Option('b', "bet", Required = false, Default = 0, HelpText = "Amount you bet. Default 0.")] + public int Bet { get; set; } + + public void NormalizeOptions() + { + if (TurnTimer is < 5 or > 60) + TurnTimer = 15; + + if (Bet < 0) + Bet = 0; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Connect4/Connect4Commands.cs b/src/EllieBot/Modules/Gambling/Connect4/Connect4Commands.cs new file mode 100644 index 0000000..8210ad4 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Connect4/Connect4Commands.cs @@ -0,0 +1,205 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Connect4; +using EllieBot.Modules.Gambling.Services; +using System.Text; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class Connect4Commands : GamblingSubmodule + { + private static readonly string[] _numbers = + [ + ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:" + ]; + + private int RepostCounter + { + get => repostCounter; + set + { + if (value is < 0 or > 7) + repostCounter = 0; + else + repostCounter = value; + } + } + + private readonly DiscordSocketClient _client; + private readonly ICurrencyService _cs; + + private IUserMessage msg; + + private int repostCounter; + + public Connect4Commands(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService gamb) + : base(gamb) + { + _client = client; + _cs = cs; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + public async Task Connect4(params string[] args) + { + var (options, _) = OptionsParser.ParseFrom(new Connect4Game.Options(), args); + if (!await CheckBetOptional(options.Bet)) + return; + + var newGame = new Connect4Game(ctx.User.Id, ctx.User.ToString(), options, _cs); + Connect4Game game; + if ((game = _service.Connect4Games.GetOrAdd(ctx.Channel.Id, newGame)) != newGame) + { + if (game.CurrentPhase != Connect4Game.Phase.Joining) + return; + + newGame.Dispose(); + //means game already exists, try to join + await game.Join(ctx.User.Id, ctx.User.ToString(), options.Bet); + return; + } + + if (options.Bet > 0) + { + if (!await _cs.RemoveAsync(ctx.User.Id, options.Bet, new("connect4", "bet"))) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + _service.Connect4Games.TryRemove(ctx.Channel.Id, out _); + game.Dispose(); + return; + } + } + + game.OnGameStateUpdated += Game_OnGameStateUpdated; + game.OnGameFailedToStart += GameOnGameFailedToStart; + game.OnGameEnded += GameOnGameEnded; + _client.MessageReceived += ClientMessageReceived; + + game.Initialize(); + if (options.Bet == 0) + await Response().Confirm(strs.connect4_created).SendAsync(); + else + await Response().Error(strs.connect4_created_bet(N(options.Bet))).SendAsync(); + + Task ClientMessageReceived(SocketMessage arg) + { + if (ctx.Channel.Id != arg.Channel.Id) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + var success = false; + if (int.TryParse(arg.Content, out var col)) + success = await game.Input(arg.Author.Id, col); + + if (success) + { + try { await arg.DeleteAsync(); } + catch { } + } + else + { + if (game.CurrentPhase is Connect4Game.Phase.Joining or Connect4Game.Phase.Ended) + return; + RepostCounter++; + if (RepostCounter == 0) + { + try { msg = await Response().Embed(msg.Embeds.First().ToEmbedBuilder()).SendAsync(); } + catch { } + } + } + }); + return Task.CompletedTask; + } + + Task GameOnGameFailedToStart(Connect4Game arg) + { + if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose)) + { + _client.MessageReceived -= ClientMessageReceived; + toDispose.Dispose(); + } + + return Response().Error(strs.connect4_failed_to_start).SendAsync(); + } + + Task GameOnGameEnded(Connect4Game arg, Connect4Game.Result result) + { + if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose)) + { + _client.MessageReceived -= ClientMessageReceived; + toDispose.Dispose(); + } + + string title; + if (result == Connect4Game.Result.CurrentPlayerWon) + { + title = GetText(strs.connect4_won(Format.Bold(arg.CurrentPlayer.Username), + Format.Bold(arg.OtherPlayer.Username))); + } + else if (result == Connect4Game.Result.OtherPlayerWon) + { + title = GetText(strs.connect4_won(Format.Bold(arg.OtherPlayer.Username), + Format.Bold(arg.CurrentPlayer.Username))); + } + else + title = GetText(strs.connect4_draw); + + return msg.ModifyAsync(x => x.Embed = _sender.CreateEmbed() + .WithTitle(title) + .WithDescription(GetGameStateText(game)) + .WithOkColor() + .Build()); + } + } + + private async Task Game_OnGameStateUpdated(Connect4Game game) + { + var embed = _sender.CreateEmbed() + .WithTitle($"{game.CurrentPlayer.Username} vs {game.OtherPlayer.Username}") + .WithDescription(GetGameStateText(game)) + .WithOkColor(); + + + if (msg is null) + msg = await Response().Embed(embed).SendAsync(); + else + await msg.ModifyAsync(x => x.Embed = embed.Build()); + } + + private string GetGameStateText(Connect4Game game) + { + var sb = new StringBuilder(); + + if (game.CurrentPhase is Connect4Game.Phase.P1Move or Connect4Game.Phase.P2Move) + sb.AppendLine(GetText(strs.connect4_player_to_move(Format.Bold(game.CurrentPlayer.Username)))); + + for (var i = Connect4Game.NUMBER_OF_ROWS; i > 0; i--) + { + for (var j = 0; j < Connect4Game.NUMBER_OF_COLUMNS; j++) + { + var cur = game.GameState[i + (j * Connect4Game.NUMBER_OF_ROWS) - 1]; + + if (cur == Connect4Game.Field.Empty) + sb.Append("⚫"); //black circle + else if (cur == Connect4Game.Field.P1) + sb.Append("🔴"); //red circle + else + sb.Append("🔵"); //blue circle + } + + sb.AppendLine(); + } + + for (var i = 0; i < Connect4Game.NUMBER_OF_COLUMNS; i++) + sb.Append(_numbers[i]); + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/CurrencyProvider.cs b/src/EllieBot/Modules/Gambling/CurrencyProvider.cs new file mode 100644 index 0000000..e4f4bc1 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/CurrencyProvider.cs @@ -0,0 +1,16 @@ +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Modules.Gambling; + +public sealed class CurrencyProvider : ICurrencyProvider, IEService +{ + private readonly GamblingConfigService _cs; + + public CurrencyProvider(GamblingConfigService cs) + { + _cs = cs; + } + + public string GetCurrencySign() + => _cs.Data.Currency.Sign; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs b/src/EllieBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs new file mode 100644 index 0000000..15bf7ff --- /dev/null +++ b/src/EllieBot/Modules/Gambling/DiceRoll/DiceRollCommands.cs @@ -0,0 +1,224 @@ +#nullable disable +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System.Text.RegularExpressions; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class DiceRollCommands : EllieModule + { + private static readonly Regex _dndRegex = new(@"^(?\d+)d(?\d+)(?:\+(?\d+))?(?:\-(?\d+))?$", + RegexOptions.Compiled); + + private static readonly Regex _fudgeRegex = new(@"^(?\d+)d(?:F|f)$", RegexOptions.Compiled); + + private static readonly char[] _fateRolls = ['-', ' ', '+']; + private readonly IImageCache _images; + + public DiceRollCommands(IImageCache images) + => _images = images; + + [Cmd] + public async Task Roll() + { + var rng = new EllieRandom(); + var gen = rng.Next(1, 101); + + var num1 = gen / 10; + var num2 = gen % 10; + + using var img1 = await GetDiceAsync(num1); + using var img2 = await GetDiceAsync(num2); + using var img = new[] { img1, img2 }.Merge(out var format); + await using var ms = await img.ToStreamAsync(format); + + var fileName = $"dice.{format.FileExtensions.First()}"; + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .AddField(GetText(strs.roll2), gen) + .WithImageUrl($"attachment://{fileName}"); + + await ctx.Channel.SendFileAsync(ms, + fileName, + embed: eb.Build()); + } + + [Cmd] + [Priority(1)] + public async Task Roll(int num) + => await InternalRoll(num, true); + + + [Cmd] + [Priority(1)] + public async Task Rolluo(int num = 1) + => await InternalRoll(num, false); + + [Cmd] + [Priority(0)] + public async Task Roll(string arg) + => await InternallDndRoll(arg, true); + + [Cmd] + [Priority(0)] + public async Task Rolluo(string arg) + => await InternallDndRoll(arg, false); + + private async Task InternalRoll(int num, bool ordered) + { + if (num is < 1 or > 30) + { + await Response().Error(strs.dice_invalid_number(1, 30)).SendAsync(); + return; + } + + var rng = new EllieRandom(); + + var dice = new List>(num); + var values = new List(num); + for (var i = 0; i < num; i++) + { + var randomNumber = rng.Next(1, 7); + var toInsert = dice.Count; + if (ordered) + { + if (randomNumber == 6 || dice.Count == 0) + toInsert = 0; + else if (randomNumber != 1) + { + for (var j = 0; j < dice.Count; j++) + { + if (values[j] < randomNumber) + { + toInsert = j; + break; + } + } + } + } + else + toInsert = dice.Count; + + dice.Insert(toInsert, await GetDiceAsync(randomNumber)); + values.Insert(toInsert, randomNumber); + } + + using var bitmap = dice.Merge(out var format); + await using var ms = bitmap.ToStream(format); + foreach (var d in dice) + d.Dispose(); + + var imageName = $"dice.{format.FileExtensions.First()}"; + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .AddField(GetText(strs.rolls), values.Select(x => Format.Code(x.ToString())).Join(' '), true) + .AddField(GetText(strs.total), values.Sum(), true) + .WithDescription(GetText(strs.dice_rolled_num(Format.Bold(values.Count.ToString())))) + .WithImageUrl($"attachment://{imageName}"); + + await ctx.Channel.SendFileAsync(ms, + imageName, + embed: eb.Build()); + } + + private async Task InternallDndRoll(string arg, bool ordered) + { + Match match; + if ((match = _fudgeRegex.Match(arg)).Length != 0 + && int.TryParse(match.Groups["n1"].ToString(), out var n1) + && n1 is > 0 and < 500) + { + var rng = new EllieRandom(); + + var rolls = new List(); + + for (var i = 0; i < n1; i++) + rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .WithDescription(GetText(strs.dice_rolled_num(Format.Bold(n1.ToString())))) + .AddField(Format.Bold("Result"), + string.Join(" ", rolls.Select(c => Format.Code($"[{c}]")))); + + await Response().Embed(embed).SendAsync(); + } + else if ((match = _dndRegex.Match(arg)).Length != 0) + { + var rng = new EllieRandom(); + if (int.TryParse(match.Groups["n1"].ToString(), out n1) + && int.TryParse(match.Groups["n2"].ToString(), out var n2) + && n1 <= 50 + && n2 <= 100000 + && n1 > 0 + && n2 > 0) + { + if (!int.TryParse(match.Groups["add"].Value, out var add)) + add = 0; + if (!int.TryParse(match.Groups["sub"].Value, out var sub)) + sub = 0; + + var arr = new int[n1]; + for (var i = 0; i < n1; i++) + arr[i] = rng.Next(1, n2 + 1); + + var sum = arr.Sum(); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .WithDescription(GetText(strs.dice_rolled_num(n1 + $"`1 - {n2}`"))) + .AddField(Format.Bold(GetText(strs.rolls)), + string.Join(" ", + (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x + => Format.Code(x.ToString())))) + .AddField(Format.Bold("Sum"), + sum + " + " + add + " - " + sub + " = " + (sum + add - sub)); + await Response().Embed(embed).SendAsync(); + } + } + } + + [Cmd] + public async Task NRoll([Leftover] string range) + { + int rolled; + if (range.Contains("-")) + { + var arr = range.Split('-').Take(2).Select(int.Parse).ToArray(); + if (arr[0] > arr[1]) + { + await Response().Error(strs.second_larger_than_first).SendAsync(); + return; + } + + rolled = new EllieRandom().Next(arr[0], arr[1] + 1); + } + else + rolled = new EllieRandom().Next(0, int.Parse(range) + 1); + + await Response().Confirm(strs.dice_rolled(Format.Bold(rolled.ToString()))).SendAsync(); + } + + private async Task> GetDiceAsync(int num) + { + if (num is < 0 or > 10) + throw new ArgumentOutOfRangeException(nameof(num)); + + if (num == 10) + { + using var imgOne = Image.Load(await _images.GetDiceAsync(1)); + using var imgZero = Image.Load(await _images.GetDiceAsync(0)); + return new[] { imgOne, imgZero }.Merge(); + } + + return Image.Load(await _images.GetDiceAsync(num)); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Draw/DrawCommands.cs b/src/EllieBot/Modules/Gambling/Draw/DrawCommands.cs new file mode 100644 index 0000000..dd10cf1 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Draw/DrawCommands.cs @@ -0,0 +1,234 @@ +#nullable disable +using Ellie.Econ; +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class DrawCommands : GamblingSubmodule + { + private static readonly ConcurrentDictionary _allDecks = new(); + private readonly IImageCache _images; + + public DrawCommands(IImageCache images, GamblingConfigService gcs) : base(gcs) + => _images = images; + + private async Task InternalDraw(int count, ulong? guildId = null) + { + if (count is < 1 or > 10) + throw new ArgumentOutOfRangeException(nameof(count)); + + var cards = guildId is null ? new() : _allDecks.GetOrAdd(ctx.Guild, _ => new()); + var images = new List>(); + var cardObjects = new List(); + for (var i = 0; i < count; i++) + { + if (cards.CardPool.Count == 0 && i != 0) + { + try + { + await Response().Error(strs.no_more_cards).SendAsync(); + } + catch + { + // ignored + } + + break; + } + + var currentCard = cards.Draw(); + cardObjects.Add(currentCard); + var image = await GetCardImageAsync(currentCard); + images.Add(image); + } + + var imgName = "cards.jpg"; + using var img = images.Merge(); + foreach (var i in images) + i.Dispose(); + + var eb = _sender.CreateEmbed() + .WithOkColor(); + + var toSend = string.Empty; + if (cardObjects.Count == 5) + eb.AddField(GetText(strs.hand_value), Deck.GetHandValue(cardObjects), true); + + if (guildId is not null) + toSend += GetText(strs.cards_left(Format.Bold(cards.CardPool.Count.ToString()))); + + eb.WithDescription(toSend) + .WithAuthor(ctx.User) + .WithImageUrl($"attachment://{imgName}"); + + if (count > 1) + eb.AddField(GetText(strs.cards), count.ToString(), true); + + await using var imageStream = await img.ToStreamAsync(); + await ctx.Channel.SendFileAsync(imageStream, + imgName, + embed: eb.Build()); + } + + private async Task> GetCardImageAsync(RegularCard currentCard) + { + var cardName = currentCard.GetName().ToLowerInvariant().Replace(' ', '_'); + var cardBytes = await File.ReadAllBytesAsync($"data/images/cards/{cardName}.jpg"); + return Image.Load(cardBytes); + } + + private async Task> GetCardImageAsync(Deck.Card currentCard) + { + var cardName = currentCard.ToString().ToLowerInvariant().Replace(' ', '_'); + var cardBytes = await File.ReadAllBytesAsync($"data/images/cards/{cardName}.jpg"); + return Image.Load(cardBytes); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Draw(int num = 1) + { + if (num < 1) + return; + + if (num > 10) + num = 10; + + await InternalDraw(num, ctx.Guild.Id); + } + + [Cmd] + public async Task DrawNew(int num = 1) + { + if (num < 1) + return; + + if (num > 10) + num = 10; + + await InternalDraw(num); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task DeckShuffle() + { + //var channel = (ITextChannel)ctx.Channel; + + _allDecks.AddOrUpdate(ctx.Guild, + _ => new(), + (_, c) => + { + c.Restart(); + return c; + }); + + await Response().Confirm(strs.deck_reshuffled).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task BetDraw([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, InputValueGuess val, InputColorGuess? col = null) + => BetDrawInternal(amount, val, col); + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task BetDraw([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, InputColorGuess col, InputValueGuess? val = null) + => BetDrawInternal(amount, val, col); + + public async Task BetDrawInternal(long amount, InputValueGuess? val, InputColorGuess? col) + { + if (amount <= 0) + return; + + var res = await _service.BetDrawAsync(ctx.User.Id, + amount, + (byte?)val, + (byte?)col); + + if (!res.TryPickT0(out var result, out _)) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .WithDescription(result.Card.GetEmoji()) + .AddField(GetText(strs.guess), GetGuessInfo(val, col), true) + .AddField(GetText(strs.card), GetCardInfo(result.Card), true) + .AddField(GetText(strs.won), N((long)result.Won), false) + .WithImageUrl("attachment://card.png"); + + using var img = await GetCardImageAsync(result.Card); + await using var imgStream = await img.ToStreamAsync(); + await ctx.Channel.SendFileAsync(imgStream, "card.png", embed: eb.Build()); + } + + private string GetGuessInfo(InputValueGuess? valG, InputColorGuess? colG) + { + var val = valG switch + { + InputValueGuess.H => "Hi ⬆️", + InputValueGuess.L => "Lo ⬇️", + _ => "❓" + }; + + var col = colG switch + { + InputColorGuess.Red => "R 🔴", + InputColorGuess.Black => "B ⚫", + _ => "❓" + }; + + return $"{val} / {col}"; + } + private string GetCardInfo(RegularCard card) + { + var val = (int)card.Value switch + { + < 7 => "Lo ⬇️", + > 7 => "Hi ⬆️", + _ => "7 💀" + }; + + var col = card.Value == RegularValue.Seven + ? "7 💀" + : card.Suit switch + { + RegularSuit.Diamonds or RegularSuit.Hearts => "R 🔴", + _ => "B ⚫" + }; + + return $"{val} / {col}"; + } + + public enum InputValueGuess + { + High = 0, + H = 0, + Hi = 0, + Low = 1, + L = 1, + Lo = 1, + } + + public enum InputColorGuess + { + R = 0, + Red = 0, + B = 1, + Bl = 1, + Black = 1, + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/EconomyResult.cs b/src/EllieBot/Modules/Gambling/EconomyResult.cs new file mode 100644 index 0000000..12a00f8 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/EconomyResult.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Services; + +public sealed class EconomyResult +{ + public decimal Cash { get; init; } + public decimal Planted { get; init; } + public decimal Waifus { get; init; } + public decimal OnePercent { get; init; } + public decimal Bank { get; init; } + public long Bot { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Events/CurrencyEventsCommands.cs b/src/EllieBot/Modules/Gambling/Events/CurrencyEventsCommands.cs new file mode 100644 index 0000000..c5e836c --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Events/CurrencyEventsCommands.cs @@ -0,0 +1,60 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Events; +using EllieBot.Modules.Gambling.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class CurrencyEventsCommands : GamblingSubmodule + { + public CurrencyEventsCommands(GamblingConfigService gamblingConf) + : base(gamblingConf) + { + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + [OwnerOnly] + public async Task EventStart(CurrencyEvent.Type ev, params string[] options) + { + var (opts, _) = OptionsParser.ParseFrom(new EventOptions(), options); + if (!await _service.TryCreateEventAsync(ctx.Guild.Id, ctx.Channel.Id, ev, opts, GetEmbed)) + await Response().Error(strs.start_event_fail).SendAsync(); + } + + private EmbedBuilder GetEmbed(CurrencyEvent.Type type, EventOptions opts, long currentPot) + => type switch + { + CurrencyEvent.Type.Reaction => _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.event_title(type.ToString()))) + .WithDescription(GetReactionDescription(opts.Amount, currentPot)) + .WithFooter(GetText(strs.event_duration_footer(opts.Hours))), + CurrencyEvent.Type.GameStatus => _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.event_title(type.ToString()))) + .WithDescription(GetGameStatusDescription(opts.Amount, currentPot)) + .WithFooter(GetText(strs.event_duration_footer(opts.Hours))), + _ => throw new ArgumentOutOfRangeException(nameof(type)) + }; + + private string GetReactionDescription(long amount, long potSize) + { + var potSizeStr = Format.Bold(potSize == 0 ? "∞" + CurrencySign : N(potSize)); + + return GetText(strs.new_reaction_event(CurrencySign, Format.Bold(N(amount)), potSizeStr)); + } + + private string GetGameStatusDescription(long amount, long potSize) + { + var potSizeStr = Format.Bold(potSize == 0 ? "∞" + CurrencySign : potSize + CurrencySign); + + return GetText(strs.new_gamestatus_event(CurrencySign, Format.Bold(N(amount)), potSizeStr)); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Events/CurrencyEventsService.cs b/src/EllieBot/Modules/Gambling/Events/CurrencyEventsService.cs new file mode 100644 index 0000000..39160ff --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Events/CurrencyEventsService.cs @@ -0,0 +1,70 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Events; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling.Services; + +public class CurrencyEventsService : IEService +{ + private readonly DiscordSocketClient _client; + private readonly ICurrencyService _cs; + private readonly GamblingConfigService _configService; + + private readonly ConcurrentDictionary _events = new(); + private readonly IMessageSenderService _sender; + + public CurrencyEventsService(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService configService, + IMessageSenderService sender) + { + _client = client; + _cs = cs; + _configService = configService; + _sender = sender; + } + + public async Task TryCreateEventAsync( + ulong guildId, + ulong channelId, + CurrencyEvent.Type type, + EventOptions opts, + Func embed) + { + var g = _client.GetGuild(guildId); + if (g?.GetChannel(channelId) is not ITextChannel ch) + return false; + + ICurrencyEvent ce; + + if (type == CurrencyEvent.Type.Reaction) + ce = new ReactionEvent(_client, _cs, g, ch, opts, _configService.Data, _sender, embed); + else if (type == CurrencyEvent.Type.GameStatus) + ce = new GameStatusEvent(_client, _cs, g, ch, opts, _sender, embed); + else + return false; + + var added = _events.TryAdd(guildId, ce); + if (added) + { + try + { + ce.OnEnded += OnEventEnded; + await ce.StartEvent(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error starting event"); + _events.TryRemove(guildId, out ce); + return false; + } + } + + return added; + } + + private Task OnEventEnded(ulong gid) + { + _events.TryRemove(gid, out _); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Events/EventOptions.cs b/src/EllieBot/Modules/Gambling/Events/EventOptions.cs new file mode 100644 index 0000000..3d0eb3f --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Events/EventOptions.cs @@ -0,0 +1,39 @@ +#nullable disable +using CommandLine; + +namespace EllieBot.Modules.Gambling.Common.Events; + +public class EventOptions : IEllieCommandOptions +{ + [Option('a', "amount", Required = false, Default = 100, HelpText = "Amount of currency each user receives.")] + public long Amount { get; set; } = 100; + + [Option('p', + "pot-size", + Required = false, + Default = 0, + HelpText = "The maximum amount of currency that can be rewarded. 0 means no limit.")] + public long PotSize { get; set; } + + //[Option('t', "type", Required = false, Default = "reaction", HelpText = "Type of the event. reaction, gamestatus or joinserver.")] + //public string TypeString { get; set; } = "reaction"; + [Option('d', + "duration", + Required = false, + Default = 24, + HelpText = "Number of hours the event should run for. Default 24.")] + public int Hours { get; set; } = 24; + + + public void NormalizeOptions() + { + if (Amount < 0) + Amount = 100; + if (PotSize < 0) + PotSize = 0; + if (Hours <= 0) + Hours = 24; + if (PotSize != 0 && PotSize < Amount) + PotSize = 0; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Events/GameStatusEvent.cs b/src/EllieBot/Modules/Gambling/Events/GameStatusEvent.cs new file mode 100644 index 0000000..aeb23c0 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Events/GameStatusEvent.cs @@ -0,0 +1,198 @@ +#nullable disable +using EllieBot.Db.Models; +using System.Collections.Concurrent; + +namespace EllieBot.Modules.Gambling.Common.Events; + +public class GameStatusEvent : ICurrencyEvent +{ + public event Func OnEnded; + private long PotSize { get; set; } + public bool Stopped { get; private set; } + public bool PotEmptied { get; private set; } + private readonly DiscordSocketClient _client; + private readonly IGuild _guild; + private IUserMessage msg; + private readonly ICurrencyService _cs; + private readonly long _amount; + + private readonly Func _embedFunc; + private readonly bool _isPotLimited; + private readonly ITextChannel _channel; + private readonly ConcurrentHashSet _awardedUsers = new(); + private readonly ConcurrentQueue _toAward = new(); + private readonly Timer _t; + private readonly Timer _timeout; + private readonly EventOptions _opts; + + private readonly string _code; + + private readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10) + .Concat(Enumerable.Range(65, 26)) + .Concat(Enumerable.Range(97, 26)) + .Select(x => (char)x) + .ToArray(); + + private readonly object _stopLock = new(); + + private readonly object _potLock = new(); + private readonly IMessageSenderService _sender; + + public GameStatusEvent( + DiscordSocketClient client, + ICurrencyService cs, + SocketGuild g, + ITextChannel ch, + EventOptions opt, + IMessageSenderService sender, + Func embedFunc) + { + _client = client; + _guild = g; + _cs = cs; + _amount = opt.Amount; + PotSize = opt.PotSize; + _embedFunc = embedFunc; + _isPotLimited = PotSize > 0; + _channel = ch; + _opts = opt; + _sender = sender; + // generate code + _code = new(_sneakyGameStatusChars.Shuffle().Take(5).ToArray()); + + _t = new(OnTimerTick, null, Timeout.InfiniteTimeSpan, TimeSpan.FromSeconds(2)); + if (_opts.Hours > 0) + _timeout = new(EventTimeout, null, TimeSpan.FromHours(_opts.Hours), Timeout.InfiniteTimeSpan); + } + + private void EventTimeout(object state) + => _ = StopEvent(); + + private async void OnTimerTick(object state) + { + var potEmpty = PotEmptied; + var toAward = new List(); + while (_toAward.TryDequeue(out var x)) + toAward.Add(x); + + if (!toAward.Any()) + return; + + try + { + await _cs.AddBulkAsync(toAward, + _amount, + new("event", "gamestatus") + ); + + if (_isPotLimited) + { + await msg.ModifyAsync(m => + { + m.Embed = GetEmbed(PotSize).Build(); + }); + } + + Log.Information("Game status event awarded {Count} users {Amount} currency.{Remaining}", + toAward.Count, + _amount, + _isPotLimited ? $" {PotSize} left." : ""); + + if (potEmpty) + _ = StopEvent(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error in OnTimerTick in gamestatusevent"); + } + } + + public async Task StartEvent() + { + msg = await _sender.Response(_channel).Embed(GetEmbed(_opts.PotSize)).SendAsync(); + await _client.SetGameAsync(_code); + _client.MessageDeleted += OnMessageDeleted; + _client.MessageReceived += HandleMessage; + _t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2)); + } + + private EmbedBuilder GetEmbed(long pot) + => _embedFunc(CurrencyEvent.Type.GameStatus, _opts, pot); + + private async Task OnMessageDeleted(Cacheable message, Cacheable cacheable) + { + if (message.Id == msg.Id) + await StopEvent(); + } + + public Task StopEvent() + { + lock (_stopLock) + { + if (Stopped) + return Task.CompletedTask; + Stopped = true; + _client.MessageDeleted -= OnMessageDeleted; + _client.MessageReceived -= HandleMessage; + _t.Change(Timeout.Infinite, Timeout.Infinite); + _timeout?.Change(Timeout.Infinite, Timeout.Infinite); + _ = _client.SetGameAsync(null); + try + { + _ = msg.DeleteAsync(); + } + catch { } + + _ = OnEnded?.Invoke(_guild.Id); + } + + return Task.CompletedTask; + } + + private Task HandleMessage(SocketMessage message) + { + _ = Task.Run(async () => + { + if (message.Author is not IGuildUser gu // no unknown users, as they could be bots, or alts + || gu.IsBot // no bots + || message.Content != _code // code has to be the same + || (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5) // no recently created accounts + return; + // there has to be money left in the pot + // and the user wasn't rewarded + if (_awardedUsers.Add(message.Author.Id) && TryTakeFromPot()) + { + _toAward.Enqueue(message.Author.Id); + if (_isPotLimited && PotSize < _amount) + PotEmptied = true; + } + + try + { + await message.DeleteAsync(new() + { + RetryMode = RetryMode.AlwaysFail + }); + } + catch { } + }); + return Task.CompletedTask; + } + + private bool TryTakeFromPot() + { + if (_isPotLimited) + { + lock (_potLock) + { + if (PotSize < _amount) + return false; + + PotSize -= _amount; + return true; + } + } + + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Events/ICurrencyEvent.cs b/src/EllieBot/Modules/Gambling/Events/ICurrencyEvent.cs new file mode 100644 index 0000000..57b96d9 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Events/ICurrencyEvent.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common; + +public interface ICurrencyEvent +{ + event Func OnEnded; + Task StopEvent(); + Task StartEvent(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Events/ReactionEvent.cs b/src/EllieBot/Modules/Gambling/Events/ReactionEvent.cs new file mode 100644 index 0000000..6f02747 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Events/ReactionEvent.cs @@ -0,0 +1,197 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling.Common.Events; + +public class ReactionEvent : ICurrencyEvent +{ + public event Func OnEnded; + private long PotSize { get; set; } + public bool Stopped { get; private set; } + public bool PotEmptied { get; private set; } + private readonly DiscordSocketClient _client; + private readonly IGuild _guild; + private IUserMessage msg; + private IEmote emote; + private readonly ICurrencyService _cs; + private readonly long _amount; + + private readonly Func _embedFunc; + private readonly bool _isPotLimited; + private readonly ITextChannel _channel; + private readonly ConcurrentHashSet _awardedUsers = new(); + private readonly System.Collections.Concurrent.ConcurrentQueue _toAward = new(); + private readonly Timer _t; + private readonly Timer _timeout; + private readonly bool _noRecentlyJoinedServer; + private readonly EventOptions _opts; + private readonly GamblingConfig _config; + + private readonly object _stopLock = new(); + + private readonly object _potLock = new(); + private readonly IMessageSenderService _sender; + + public ReactionEvent( + DiscordSocketClient client, + ICurrencyService cs, + SocketGuild g, + ITextChannel ch, + EventOptions opt, + GamblingConfig config, + IMessageSenderService sender, + Func embedFunc) + { + _client = client; + _guild = g; + _cs = cs; + _amount = opt.Amount; + PotSize = opt.PotSize; + _embedFunc = embedFunc; + _isPotLimited = PotSize > 0; + _channel = ch; + _noRecentlyJoinedServer = false; + _opts = opt; + _config = config; + _sender = sender; + + _t = new(OnTimerTick, null, Timeout.InfiniteTimeSpan, TimeSpan.FromSeconds(2)); + if (_opts.Hours > 0) + _timeout = new(EventTimeout, null, TimeSpan.FromHours(_opts.Hours), Timeout.InfiniteTimeSpan); + } + + private void EventTimeout(object state) + => _ = StopEvent(); + + private async void OnTimerTick(object state) + { + var potEmpty = PotEmptied; + var toAward = new List(); + while (_toAward.TryDequeue(out var x)) + toAward.Add(x); + + if (!toAward.Any()) + return; + + try + { + await _cs.AddBulkAsync(toAward, _amount, new("event", "reaction")); + + if (_isPotLimited) + { + await msg.ModifyAsync(m => + { + m.Embed = GetEmbed(PotSize).Build(); + }); + } + + Log.Information("Reaction Event awarded {Count} users {Amount} currency.{Remaining}", + toAward.Count, + _amount, + _isPotLimited ? $" {PotSize} left." : ""); + + if (potEmpty) + _ = StopEvent(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error adding bulk currency to users"); + } + } + + public async Task StartEvent() + { + if (Emote.TryParse(_config.Currency.Sign, out var parsedEmote)) + emote = parsedEmote; + else + emote = new Emoji(_config.Currency.Sign); + msg = await _sender.Response(_channel).Embed(GetEmbed(_opts.PotSize)).SendAsync(); + await msg.AddReactionAsync(emote); + _client.MessageDeleted += OnMessageDeleted; + _client.ReactionAdded += HandleReaction; + _t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2)); + } + + private EmbedBuilder GetEmbed(long pot) + => _embedFunc(CurrencyEvent.Type.Reaction, _opts, pot); + + private async Task OnMessageDeleted(Cacheable message, Cacheable cacheable) + { + if (message.Id == msg.Id) + await StopEvent(); + } + + public Task StopEvent() + { + lock (_stopLock) + { + if (Stopped) + return Task.CompletedTask; + + Stopped = true; + _client.MessageDeleted -= OnMessageDeleted; + _client.ReactionAdded -= HandleReaction; + _t.Change(Timeout.Infinite, Timeout.Infinite); + _timeout?.Change(Timeout.Infinite, Timeout.Infinite); + try + { + _ = msg.DeleteAsync(); + } + catch { } + + _ = OnEnded?.Invoke(_guild.Id); + } + + return Task.CompletedTask; + } + + private Task HandleReaction( + Cacheable message, + Cacheable cacheable, + SocketReaction r) + { + _ = Task.Run(() => + { + if (emote.Name != r.Emote.Name) + return; + if ((r.User.IsSpecified + ? r.User.Value + : null) is not IGuildUser gu // no unknown users, as they could be bots, or alts + || message.Id != msg.Id // same message + || gu.IsBot // no bots + || (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5 // no recently created accounts + || (_noRecentlyJoinedServer + && // if specified, no users who joined the server in the last 24h + (gu.JoinedAt is null + || (DateTime.UtcNow - gu.JoinedAt.Value).TotalDays + < 1))) // and no users for who we don't know when they joined + return; + // there has to be money left in the pot + // and the user wasn't rewarded + if (_awardedUsers.Add(r.UserId) && TryTakeFromPot()) + { + _toAward.Enqueue(r.UserId); + if (_isPotLimited && PotSize < _amount) + PotEmptied = true; + } + }); + return Task.CompletedTask; + } + + private bool TryTakeFromPot() + { + if (_isPotLimited) + { + lock (_potLock) + { + if (PotSize < _amount) + return false; + + PotSize -= _amount; + return true; + } + } + + return true; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs b/src/EllieBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs new file mode 100644 index 0000000..2704495 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/FlipCoin/FlipCoinCommands.cs @@ -0,0 +1,140 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class FlipCoinCommands : GamblingSubmodule + { + public enum BetFlipGuess : byte + { + H = 0, + Head = 0, + Heads = 0, + T = 1, + Tail = 1, + Tails = 1 + } + + private static readonly EllieRandom _rng = new(); + private readonly IImageCache _images; + private readonly ICurrencyService _cs; + private readonly ImagesConfig _ic; + + public FlipCoinCommands( + IImageCache images, + ImagesConfig ic, + ICurrencyService cs, + GamblingConfigService gss) + : base(gss) + { + _ic = ic; + _images = images; + _cs = cs; + } + + [Cmd] + public async Task Flip(int count = 1) + { + if (count is > 10 or < 1) + { + await Response().Error(strs.flip_invalid(10)).SendAsync(); + return; + } + + var headCount = 0; + var tailCount = 0; + var imgs = new Image[count]; + var headsArr = await _images.GetHeadsImageAsync(); + var tailsArr = await _images.GetTailsImageAsync(); + + var result = await _service.FlipAsync(count); + + for (var i = 0; i < result.Length; i++) + { + if (result[i].Side == 0) + { + imgs[i] = Image.Load(headsArr); + headCount++; + } + else + { + imgs[i] = Image.Load(tailsArr); + tailCount++; + } + } + + using var img = imgs.Merge(out var format); + await using var stream = await img.ToStreamAsync(format); + foreach (var i in imgs) + i.Dispose(); + + var imgName = $"coins.{format.FileExtensions.First()}"; + + var msg = count != 1 + ? Format.Bold(GetText(strs.flip_results(count, headCount, tailCount))) + : GetText(strs.flipped(headCount > 0 + ? Format.Bold(GetText(strs.heads)) + : Format.Bold(GetText(strs.tails)))); + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .WithDescription(msg) + .WithImageUrl($"attachment://{imgName}"); + + await ctx.Channel.SendFileAsync(stream, + imgName, + embed: eb.Build()); + } + + [Cmd] + public async Task Betflip([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, BetFlipGuess guess) + { + if (!await CheckBetMandatory(amount) || amount == 1) + return; + + var res = await _service.BetFlipAsync(ctx.User.Id, amount, (byte)guess); + if (!res.TryPickT0(out var result, out _)) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + Uri imageToSend; + var coins = _ic.Data.Coins; + if (result.Side == 0) + { + imageToSend = coins.Heads[_rng.Next(0, coins.Heads.Length)]; + } + else + { + imageToSend = coins.Tails[_rng.Next(0, coins.Tails.Length)]; + } + + string str; + var won = (long)result.Won; + if (won > 0) + { + str = Format.Bold(GetText(strs.flip_guess(N(won)))); + } + else + { + str = Format.Bold(GetText(strs.better_luck)); + } + + await Response().Embed(_sender.CreateEmbed() + .WithAuthor(ctx.User) + .WithDescription(str) + .WithOkColor() + .WithImageUrl(imageToSend.ToString())).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/FlipCoin/FlipResult.cs b/src/EllieBot/Modules/Gambling/FlipCoin/FlipResult.cs new file mode 100644 index 0000000..6c16b9f --- /dev/null +++ b/src/EllieBot/Modules/Gambling/FlipCoin/FlipResult.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Gambling; + +public readonly struct FlipResult +{ + public long Won { get; init; } + public int Side { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Gambling.cs b/src/EllieBot/Modules/Gambling/Gambling.cs new file mode 100644 index 0000000..428f756 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Gambling.cs @@ -0,0 +1,1032 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Gambling.Bank; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; +using EllieBot.Modules.Utility.Services; +using EllieBot.Services.Currency; +using System.Collections.Immutable; +using System.Globalization; +using System.Text; +using EllieBot.Modules.Gambling.Rps; +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Patronage; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling : GamblingModule +{ + private readonly IGamblingService _gs; + private readonly DbService _db; + private readonly ICurrencyService _cs; + private readonly DiscordSocketClient _client; + private readonly NumberFormatInfo _enUsCulture; + private readonly DownloadTracker _tracker; + private readonly GamblingConfigService _configService; + private readonly IBankService _bank; + private readonly IPatronageService _ps; + private readonly IRemindService _remind; + private readonly GamblingTxTracker _gamblingTxTracker; + + private IUserMessage rdMsg; + + public Gambling( + IGamblingService gs, + DbService db, + ICurrencyService currency, + DiscordSocketClient client, + DownloadTracker tracker, + GamblingConfigService configService, + IBankService bank, + IPatronageService ps, + IRemindService remind, + GamblingTxTracker gamblingTxTracker) + : base(configService) + { + _gs = gs; + _db = db; + _cs = currency; + _client = client; + _bank = bank; + _ps = ps; + _remind = remind; + _gamblingTxTracker = gamblingTxTracker; + + _enUsCulture = new CultureInfo("en-US", false).NumberFormat; + _enUsCulture.NumberDecimalDigits = 0; + _enUsCulture.NumberGroupSeparator = " "; + _tracker = tracker; + _configService = configService; + } + + public async Task GetBalanceStringAsync(ulong userId) + { + var bal = await _cs.GetBalanceAsync(userId); + return N(bal); + } + + [Cmd] + public async Task BetStats() + { + var stats = await _gamblingTxTracker.GetAllAsync(); + + var eb = _sender.CreateEmbed() + .WithOkColor(); + + var str = "` Feature `|`   Bet  `|`Paid Out`|`  RoI  `\n"; + str += "――――――――――――――――――――\n"; + foreach (var stat in stats) + { + var perc = (stat.PaidOut / stat.Bet).ToString("P2", Culture); + str += $"`{stat.Feature.PadBoth(9)}`" + + $"|`{stat.Bet.ToString("N0").PadLeft(8, ' ')}`" + + $"|`{stat.PaidOut.ToString("N0").PadLeft(8, ' ')}`" + + $"|`{perc.PadLeft(6, ' ')}`\n"; + } + + var bet = stats.Sum(x => x.Bet); + var paidOut = stats.Sum(x => x.PaidOut); + + if (bet == 0) + bet = 1; + + var tPerc = (paidOut / bet).ToString("P2", Culture); + str += "――――――――――――――――――――\n"; + str += $"` {("TOTAL").PadBoth(7)}` " + + $"|**{N(bet).PadLeft(8, ' ')}**" + + $"|**{N(paidOut).PadLeft(8, ' ')}**" + + $"|`{tPerc.PadLeft(6, ' ')}`"; + + eb.WithDescription(str); + + await Response().Embed(eb).SendAsync(); + } + + [Cmd] + public async Task Economy() + { + var ec = await _service.GetEconomyAsync(); + decimal onePercent = 0; + + // This stops the top 1% from owning more than 100% of the money + if (ec.Cash > 0) + { + onePercent = ec.OnePercent / (ec.Cash - ec.Bot); + } + + // [21:03] Bob Page: Kinda remids me of US economy + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.economy_state)) + .AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot)) + .AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%") + .AddField(GetText(strs.currency_planted), N(ec.Planted)) + .AddField(GetText(strs.owned_waifus_total), N(ec.Waifus)) + .AddField(GetText(strs.bot_currency), N(ec.Bot)) + .AddField(GetText(strs.bank_accounts), N(ec.Bank)) + .AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank)) + .WithOkColor(); + + // ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table + await Response().Embed(embed).SendAsync(); + } + + private static readonly FeatureLimitKey _timelyKey = new FeatureLimitKey() + { + Key = "timely:extra_percent", + PrettyName = "Timely" + }; + + private async Task RemindTimelyAction(SocketMessageComponent smc, DateTime when) + { + var tt = TimestampTag.FromDateTime(when, TimestampTagStyles.Relative); + + await _remind.AddReminderAsync(ctx.User.Id, + ctx.User.Id, + ctx.Guild?.Id, + true, + when, + GetText(strs.timely_time), + ReminderType.Timely); + + await smc.RespondConfirmAsync(_sender, GetText(strs.remind_timely(tt)), ephemeral: true); + } + + private EllieInteractionBase CreateRemindMeInteraction(int period) + => _inter + .Create(ctx.User.Id, + new ButtonBuilder( + label: "Remind me", + emote: Emoji.Parse("⏰"), + customId: "timely:remind_me"), + (smc) => RemindTimelyAction(smc, DateTime.UtcNow.Add(TimeSpan.FromHours(period))) + ); + + [Cmd] + public async Task Timely() + { + var val = Config.Timely.Amount; + var period = Config.Timely.Cooldown; + if (val <= 0 || period <= 0) + { + await Response().Error(strs.timely_none).SendAsync(); + return; + } + + var inter = CreateRemindMeInteraction(period); + + if (await _service.ClaimTimelyAsync(ctx.User.Id, period) is { } rem) + { + // Removes timely button if there is a timely reminder in DB + if (_service.UserHasTimelyReminder(ctx.User.Id)) + { + inter = null; + } + + var now = DateTime.UtcNow; + var relativeTag = TimestampTag.FromDateTime(now.Add(rem), TimestampTagStyles.Relative); + await Response().Pending(strs.timely_already_claimed(relativeTag)).Interaction(inter).SendAsync(); + return; + } + + var result = await _ps.TryGetFeatureLimitAsync(_timelyKey, ctx.User.Id, 0); + + val = (int)(val * (1 + (result.Quota! * 0.01f))); + + await _cs.AddAsync(ctx.User.Id, val, new("timely", "claim")); + + await Response().Confirm(strs.timely(N(val), period)).Interaction(inter).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task TimelyReset() + { + await _service.RemoveAllTimelyClaimsAsync(); + await Response().Confirm(strs.timely_reset).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task TimelySet(int amount, int period = 24) + { + if (amount < 0 || period < 0) + { + return; + } + + _configService.ModifyConfig(gs => + { + gs.Timely.Amount = amount; + gs.Timely.Cooldown = period; + }); + + if (amount == 0) + { + await Response().Confirm(strs.timely_set_none).SendAsync(); + } + else + { + await Response() + .Confirm(strs.timely_set(Format.Bold(N(amount)), Format.Bold(period.ToString()))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Raffle([Leftover] IRole role = null) + { + role ??= ctx.Guild.EveryoneRole; + + var members = (await role.GetMembersAsync()).Where(u => u.Status != UserStatus.Offline); + var membersArray = members as IUser[] ?? members.ToArray(); + if (membersArray.Length == 0) + { + return; + } + + var usr = membersArray[new EllieRandom().Next(0, membersArray.Length)]; + await Response() + .Confirm("🎟 " + GetText(strs.raffled_user), + $"**{usr.Username}**", + footer: $"ID: {usr.Id}") + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task RaffleAny([Leftover] IRole role = null) + { + role ??= ctx.Guild.EveryoneRole; + + var members = await role.GetMembersAsync(); + var membersArray = members as IUser[] ?? members.ToArray(); + if (membersArray.Length == 0) + { + return; + } + + var usr = membersArray[new EllieRandom().Next(0, membersArray.Length)]; + await Response() + .Confirm("🎟 " + GetText(strs.raffled_user), + $"**{usr.Username}**", + footer: $"ID: {usr.Id}") + .SendAsync(); + } + + [Cmd] + [Priority(2)] + public Task CurrencyTransactions(int page = 1) + => InternalCurrencyTransactions(ctx.User.Id, page); + + [Cmd] + [OwnerOnly] + [Priority(0)] + public Task CurrencyTransactions([Leftover] IUser usr) + => InternalCurrencyTransactions(usr.Id, 1); + + [Cmd] + [OwnerOnly] + [Priority(1)] + public Task CurrencyTransactions(IUser usr, int page) + => InternalCurrencyTransactions(usr.Id, page); + + private async Task InternalCurrencyTransactions(ulong userId, int page) + { + if (--page < 0) + { + return; + } + + List trs; + await using (var uow = _db.GetDbContext()) + { + trs = await uow.Set().GetPageFor(userId, page); + } + + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString() + ?? $"{userId}"))) + .WithOkColor(); + + var sb = new StringBuilder(); + foreach (var tr in trs) + { + var change = tr.Amount >= 0 ? "🔵" : "🔴"; + var kwumId = new kwum(tr.Id).ToString(); + var date = $"#{Format.Code(kwumId)} `〖{GetFormattedCurtrDate(tr)}〗`"; + + sb.AppendLine($"\\{change} {date} {Format.Bold(N(tr.Amount))}"); + var transactionString = GetHumanReadableTransaction(tr.Type, tr.Extra, tr.OtherId); + if (transactionString is not null) + { + sb.AppendLine(transactionString); + } + + if (!string.IsNullOrWhiteSpace(tr.Note)) + { + sb.AppendLine($"\t`Note:` {tr.Note.TrimTo(50)}"); + } + } + + embed.WithDescription(sb.ToString()); + embed.WithFooter(GetText(strs.page(page + 1))); + await Response().Embed(embed).SendAsync(); + } + + private static string GetFormattedCurtrDate(CurrencyTransaction ct) + => $"{ct.DateAdded:HH:mm yyyy-MM-dd}"; + + [Cmd] + public async Task CurrencyTransaction(kwum id) + { + int intId = id; + await using var uow = _db.GetDbContext(); + + var tr = await uow.Set() + .ToLinqToDBTable() + .Where(x => x.Id == intId && x.UserId == ctx.User.Id) + .FirstOrDefaultAsync(); + + if (tr is null) + { + await Response().Error(strs.not_found).SendAsync(); + return; + } + + var eb = _sender.CreateEmbed().WithOkColor(); + + eb.WithAuthor(ctx.User); + eb.WithTitle(GetText(strs.transaction)); + eb.WithDescription(new kwum(tr.Id).ToString()); + eb.AddField("Amount", N(tr.Amount)); + eb.AddField("Type", tr.Type, true); + eb.AddField("Extra", tr.Extra, true); + + if (tr.OtherId is ulong other) + { + eb.AddField("From Id", other); + } + + if (!string.IsNullOrWhiteSpace(tr.Note)) + { + eb.AddField("Note", tr.Note); + } + + eb.WithFooter(GetFormattedCurtrDate(tr)); + + await Response().Embed(eb).SendAsync(); + } + + private string GetHumanReadableTransaction(string type, string subType, ulong? maybeUserId) + => (type, subType, maybeUserId) switch + { + ("gift", var name, ulong userId) => GetText(strs.curtr_gift(name, userId)), + ("award", var name, ulong userId) => GetText(strs.curtr_award(name, userId)), + ("take", var name, ulong userId) => GetText(strs.curtr_take(name, userId)), + ("blackjack", _, _) => $"Blackjack - {subType}", + ("wheel", _, _) => $"Lucky Ladder - {subType}", + ("lula", _, _) => $"Lucky Ladder - {subType}", + ("rps", _, _) => $"Rock Paper Scissors - {subType}", + (null, _, _) => null, + (_, null, _) => null, + (_, _, ulong userId) => $"{type} - {subType} | [{userId}]", + _ => $"{type} - {subType}" + }; + + [Cmd] + [Priority(0)] + public async Task Cash(ulong userId) + { + var cur = await GetBalanceStringAsync(userId); + await Response().Confirm(strs.has(Format.Code(userId.ToString()), cur)).SendAsync(); + } + + private async Task BankAction(SocketMessageComponent smc) + { + var balance = await _bank.GetBalanceAsync(ctx.User.Id); + + await N(balance) + .Pipe(strs.bank_balance) + .Pipe(GetText) + .Pipe(text => smc.RespondConfirmAsync(_sender, text, ephemeral: true)); + } + + private EllieInteractionBase CreateCashInteraction() + => _inter.Create(ctx.User.Id, + new ButtonBuilder( + customId: "cash:bank_show_balance", + emote: new Emoji("🏦")), + BankAction); + + [Cmd] + [Priority(1)] + public async Task Cash([Leftover] IUser user = null) + { + user ??= ctx.User; + var cur = await GetBalanceStringAsync(user.Id); + + var inter = user == ctx.User + ? CreateCashInteraction() + : null; + + await Response() + .Confirm( + user.ToString() + .Pipe(Format.Bold) + .With(cur) + .Pipe(strs.has)) + .Interaction(inter) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public async Task Give( + [OverrideTypeReader(typeof(BalanceTypeReader))] + long amount, + IGuildUser receiver, + [Leftover] string msg) + { + if (amount <= 0 || ctx.User.Id == receiver.Id || receiver.IsBot) + { + return; + } + + if (!await _cs.TransferAsync(_sender, ctx.User, receiver, amount, msg, N(amount))) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + await Response().Confirm(strs.gifted(N(amount), Format.Bold(receiver.ToString()), ctx.User)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public Task Give([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, [Leftover] IGuildUser receiver) + => Give(amount, receiver, null); + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + [Priority(0)] + public Task Award(long amount, IGuildUser usr, [Leftover] string msg) + => Award(amount, usr.Id, msg); + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + [Priority(1)] + public Task Award(long amount, [Leftover] IGuildUser usr) + => Award(amount, usr.Id); + + [Cmd] + [OwnerOnly] + [Priority(2)] + public async Task Award(long amount, ulong usrId, [Leftover] string msg = null) + { + if (amount <= 0) + { + return; + } + + var usr = await ((DiscordSocketClient)Context.Client).Rest.GetUserAsync(usrId); + + if (usr is null) + { + await Response().Error(strs.user_not_found).SendAsync(); + return; + } + + await _cs.AddAsync(usr.Id, amount, new("award", ctx.User.ToString()!, msg, ctx.User.Id)); + await Response().Confirm(strs.awarded(N(amount), $"<@{usrId}>", ctx.User)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + [Priority(3)] + public async Task Award(long amount, [Leftover] IRole role) + { + var users = (await ctx.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).ToList(); + + await _cs.AddBulkAsync(users.Select(x => x.Id).ToList(), + amount, + new("award", ctx.User.ToString()!, role.Name, ctx.User.Id)); + + await Response() + .Confirm(strs.mass_award(N(amount), + Format.Bold(users.Count.ToString()), + Format.Bold(role.Name))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + [Priority(0)] + public async Task Take(long amount, [Leftover] IRole role) + { + var users = (await role.GetMembersAsync()).ToList(); + + await _cs.RemoveBulkAsync(users.Select(x => x.Id).ToList(), + amount, + new("take", ctx.User.ToString()!, null, ctx.User.Id)); + + await Response() + .Confirm(strs.mass_take(N(amount), + Format.Bold(users.Count.ToString()), + Format.Bold(role.Name))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + [Priority(1)] + public async Task Take(long amount, [Leftover] IGuildUser user) + { + if (amount <= 0) + { + return; + } + + var extra = new TxData("take", ctx.User.ToString()!, null, ctx.User.Id); + + if (await _cs.RemoveAsync(user.Id, amount, extra)) + { + await Response().Confirm(strs.take(N(amount), Format.Bold(user.ToString()))).SendAsync(); + } + else + { + await Response().Error(strs.take_fail(N(amount), Format.Bold(user.ToString()), CurrencySign)).SendAsync(); + } + } + + [Cmd] + [OwnerOnly] + public async Task Take(long amount, [Leftover] ulong usrId) + { + if (amount <= 0) + { + return; + } + + var extra = new TxData("take", ctx.User.ToString()!, null, ctx.User.Id); + + if (await _cs.RemoveAsync(usrId, amount, extra)) + { + await Response().Confirm(strs.take(N(amount), $"<@{usrId}>")).SendAsync(); + } + else + { + await Response().Error(strs.take_fail(N(amount), Format.Code(usrId.ToString()), CurrencySign)).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task RollDuel(IUser u) + { + if (ctx.User.Id == u.Id) + { + return; + } + + //since the challenge is created by another user, we need to reverse the ids + //if it gets removed, means challenge is accepted + if (_service.Duels.TryRemove((ctx.User.Id, u.Id), out var game)) + { + await game.StartGame(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task RollDuel([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, IUser u) + { + if (ctx.User.Id == u.Id) + { + return; + } + + if (amount <= 0) + { + return; + } + + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.roll_duel)); + + var description = string.Empty; + + var game = new RollDuelGame(_cs, _client.CurrentUser.Id, ctx.User.Id, u.Id, amount); + //means challenge is just created + if (_service.Duels.TryGetValue((ctx.User.Id, u.Id), out var other)) + { + if (other.Amount != amount) + { + await Response().Error(strs.roll_duel_already_challenged).SendAsync(); + } + else + { + await RollDuel(u); + } + + return; + } + + if (_service.Duels.TryAdd((u.Id, ctx.User.Id), game)) + { + game.OnGameTick += GameOnGameTick; + game.OnEnded += GameOnEnded; + + await Response() + .Confirm(strs.roll_duel_challenge(Format.Bold(ctx.User.ToString()), + Format.Bold(u.ToString()), + Format.Bold(N(amount)))) + .SendAsync(); + } + + async Task GameOnGameTick(RollDuelGame arg) + { + var rolls = arg.Rolls.Last(); + description += $@"{Format.Bold(ctx.User.ToString())} rolled **{rolls.Item1}** +{Format.Bold(u.ToString())} rolled **{rolls.Item2}** +-- +"; + embed = embed.WithDescription(description); + + if (rdMsg is null) + { + rdMsg = await Response().Embed(embed).SendAsync(); + } + else + { + await rdMsg.ModifyAsync(x => { x.Embed = embed.Build(); }); + } + } + + async Task GameOnEnded(RollDuelGame rdGame, RollDuelGame.Reason reason) + { + try + { + if (reason == RollDuelGame.Reason.Normal) + { + var winner = rdGame.Winner == rdGame.P1 ? ctx.User : u; + description += $"\n**{winner}** Won {N((long)(rdGame.Amount * 2 * 0.98))}"; + + embed = embed.WithDescription(description); + + await rdMsg.ModifyAsync(x => x.Embed = embed.Build()); + } + else if (reason == RollDuelGame.Reason.Timeout) + { + await Response().Error(strs.roll_duel_timeout).SendAsync(); + } + else if (reason == RollDuelGame.Reason.NoFunds) + { + await Response().Error(strs.roll_duel_no_funds).SendAsync(); + } + } + finally + { + _service.Duels.TryRemove((u.Id, ctx.User.Id), out _); + } + } + } + + [Cmd] + public async Task BetRoll([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) + { + if (!await CheckBetMandatory(amount)) + { + return; + } + + var maybeResult = await _gs.BetRollAsync(ctx.User.Id, amount); + if (!maybeResult.TryPickT0(out var result, out _)) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + + var win = (long)result.Won; + string str; + if (win > 0) + { + str = GetText(strs.br_win(N(win), result.Threshold + (result.Roll == 100 ? " 👑" : ""))); + } + else + { + str = GetText(strs.better_luck); + } + + var eb = _sender.CreateEmbed() + .WithAuthor(ctx.User) + .WithDescription(Format.Bold(str)) + .AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture)) + .WithOkColor(); + + await Response().Embed(eb).SendAsync(); + } + + [Cmd] + [EllieOptions] + [Priority(0)] + public Task Leaderboard(params string[] args) + => Leaderboard(1, args); + + [Cmd] + [EllieOptions] + [Priority(1)] + public async Task Leaderboard(int page = 1, params string[] args) + { + if (--page < 0) + { + return; + } + + var (opts, _) = OptionsParser.ParseFrom(new LbOpts(), args); + + // List cleanRichest; + // it's pointless to have clean on dm context + if (ctx.Guild is null) + { + opts.Clean = false; + } + + + async Task> GetTopRichest(int curPage) + { + if (opts.Clean) + { + await ctx.Channel.TriggerTypingAsync(); + await _tracker.EnsureUsersDownloadedAsync(ctx.Guild); + + await using var uow = _db.GetDbContext(); + + var cleanRichest = await uow.Set() + .GetTopRichest(_client.CurrentUser.Id, 0, 1000); + + var sg = (SocketGuild)ctx.Guild!; + return cleanRichest.Where(x => sg.GetUser(x.UserId) is not null).ToList(); + } + else + { + await using var uow = _db.GetDbContext(); + return await uow.Set().GetTopRichest(_client.CurrentUser.Id, curPage); + } + } + + var res = Response() + .Paginated(); + + await Response() + .Paginated() + .PageItems(GetTopRichest) + .TotalElements(900) + .PageSize(9) + .CurrentPage(page) + .Page((toSend, curPage) => + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(CurrencySign + " " + GetText(strs.leaderboard)); + + if (!toSend.Any()) + { + embed.WithDescription(GetText(strs.no_user_on_this_page)); + return Task.FromResult(embed); + } + + for (var i = 0; i < toSend.Count; i++) + { + var x = toSend[i]; + var usrStr = x.ToString().TrimTo(20, true); + + var j = i; + embed.AddField("#" + ((9 * curPage) + j + 1) + " " + usrStr, N(x.CurrencyAmount), true); + } + + return Task.FromResult(embed); + }) + .SendAsync(); + } + + public enum InputRpsPick : byte + { + R = 0, + Rock = 0, + Rocket = 0, + P = 1, + Paper = 1, + Paperclip = 1, + S = 2, + Scissors = 2 + } + + [Cmd] + public async Task Rps(InputRpsPick pick, [OverrideTypeReader(typeof(BalanceTypeReader))] long amount = default) + { + static string GetRpsPick(InputRpsPick p) + { + switch (p) + { + case InputRpsPick.R: + return "🚀"; + case InputRpsPick.P: + return "📎"; + default: + return "✂️"; + } + } + + if (!await CheckBetOptional(amount) || amount == 1) + return; + + var res = await _gs.RpsAsync(ctx.User.Id, amount, (byte)pick); + + if (!res.TryPickT0(out var result, out _)) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed(); + + string msg; + if (result.Result == RpsResultType.Draw) + { + msg = GetText(strs.rps_draw(GetRpsPick(pick))); + } + else if (result.Result == RpsResultType.Win) + { + if ((long)result.Won > 0) + embed.AddField(GetText(strs.won), N((long)result.Won)); + + msg = GetText(strs.rps_win(ctx.User.Mention, + GetRpsPick(pick), + GetRpsPick((InputRpsPick)result.ComputerPick))); + } + else + { + msg = GetText(strs.rps_win(ctx.Client.CurrentUser.Mention, + GetRpsPick((InputRpsPick)result.ComputerPick), + GetRpsPick(pick))); + } + + embed + .WithOkColor() + .WithDescription(msg); + + await Response().Embed(embed).SendAsync(); + } + + private static readonly ImmutableArray _emojis = + new[] { "⬆", "↖", "⬅", "↙", "⬇", "↘", "➡", "↗" }.ToImmutableArray(); + + [Cmd] + public async Task LuckyLadder([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) + { + if (!await CheckBetMandatory(amount)) + return; + + var res = await _gs.LulaAsync(ctx.User.Id, amount); + if (!res.TryPickT0(out var result, out _)) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + var multis = result.Multipliers; + + var sb = new StringBuilder(); + foreach (var multi in multis) + { + sb.Append($"╠══╣"); + + if (multi == result.Multiplier) + sb.Append($"{Format.Bold($"x{multi:0.##}")} ⬅️"); + else + sb.Append($"||x{multi:0.##}||"); + + sb.AppendLine(); + } + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithDescription(sb.ToString()) + .AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true) + .AddField(GetText(strs.won), $"{(long)result.Won}", true) + .WithAuthor(ctx.User); + + + await Response().Embed(eb).SendAsync(); + } + + + public enum GambleTestTarget + { + Slot, + Betroll, + Betflip, + BetflipT, + BetDraw, + BetDrawHL, + BetDrawRB, + Lula, + Rps, + } + + [Cmd] + [OwnerOnly] + public async Task BetTest() + { + var values = Enum.GetValues() + .Select(x => $"`{x}`") + .Join(", "); + + await Response().Confirm(GetText(strs.available_tests), values).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task BetTest(GambleTestTarget target, int tests = 1000) + { + if (tests <= 0) + return; + + await ctx.Channel.TriggerTypingAsync(); + + var streak = 0; + var maxW = 0; + var maxL = 0; + + var dict = new Dictionary(); + for (var i = 0; i < tests; i++) + { + var multi = target switch + { + GambleTestTarget.BetDraw => (await _gs.BetDrawAsync(ctx.User.Id, 0, 1, 0)).AsT0.Multiplier, + GambleTestTarget.BetDrawRB => (await _gs.BetDrawAsync(ctx.User.Id, 0, null, 1)).AsT0.Multiplier, + GambleTestTarget.BetDrawHL => (await _gs.BetDrawAsync(ctx.User.Id, 0, 0, null)).AsT0.Multiplier, + GambleTestTarget.Slot => (await _gs.SlotAsync(ctx.User.Id, 0)).AsT0.Multiplier, + GambleTestTarget.Betflip => (await _gs.BetFlipAsync(ctx.User.Id, 0, 0)).AsT0.Multiplier, + GambleTestTarget.BetflipT => (await _gs.BetFlipAsync(ctx.User.Id, 0, 1)).AsT0.Multiplier, + GambleTestTarget.Lula => (await _gs.LulaAsync(ctx.User.Id, 0)).AsT0.Multiplier, + GambleTestTarget.Rps => (await _gs.RpsAsync(ctx.User.Id, 0, (byte)(i % 3))).AsT0.Multiplier, + GambleTestTarget.Betroll => (await _gs.BetRollAsync(ctx.User.Id, 0)).AsT0.Multiplier, + _ => throw new ArgumentOutOfRangeException(nameof(target)) + }; + + if (dict.ContainsKey(multi)) + dict[multi] += 1; + else + dict.Add(multi, 1); + + if (multi < 1) + { + if (streak <= 0) + --streak; + else + streak = -1; + + maxL = Math.Max(maxL, -streak); + } + else if (multi > 1) + { + if (streak >= 0) + ++streak; + else + streak = 1; + + maxW = Math.Max(maxW, streak); + } + } + + var sb = new StringBuilder(); + decimal payout = 0; + foreach (var key in dict.Keys.OrderByDescending(x => x)) + { + sb.AppendLine($"x**{key}** occured `{dict[key]}` times. {dict[key] * 1.0f / tests * 100}%"); + payout += key * dict[key]; + } + + sb.AppendLine(); + sb.AppendLine($"Longest win streak: `{maxW}`"); + sb.AppendLine($"Longest lose streak: `{maxL}`"); + + await Response() + .Confirm(GetText(strs.test_results_for(target)), + sb.ToString(), + footer: $"Total Bet: {tests} | Payout: {payout:F0} | {payout * 1.0M / tests * 100}%") + .SendAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/GamblingConfig.cs b/src/EllieBot/Modules/Gambling/GamblingConfig.cs new file mode 100644 index 0000000..0100c88 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/GamblingConfig.cs @@ -0,0 +1,404 @@ +#nullable disable +using Cloneable; +using EllieBot.Common.Yml; +using SixLabors.ImageSharp.PixelFormats; +using YamlDotNet.Serialization; +using Color = SixLabors.ImageSharp.Color; + +namespace EllieBot.Modules.Gambling.Common; + +[Cloneable] +public sealed partial class GamblingConfig : ICloneable +{ + [Comment("""DO NOT CHANGE""")] + public int Version { get; set; } = 2; + + [Comment("""Currency settings""")] + public CurrencyConfig Currency { get; set; } + + [Comment("""Minimum amount users can bet (>=0)""")] + public int MinBet { get; set; } = 0; + + [Comment(""" + Maximum amount users can bet + Set 0 for unlimited + """)] + public int MaxBet { get; set; } = 0; + + [Comment("""Settings for betflip command""")] + public BetFlipConfig BetFlip { get; set; } + + [Comment("""Settings for betroll command""")] + public BetRollConfig BetRoll { get; set; } + + [Comment("""Automatic currency generation settings.""")] + public GenerationConfig Generation { get; set; } + + [Comment(""" + Settings for timely command + (letting people claim X amount of currency every Y hours) + """)] + public TimelyConfig Timely { get; set; } + + [Comment("""How much will each user's owned currency decay over time.""")] + public DecayConfig Decay { get; set; } + + [Comment("""What is the bot's cut on some transactions""")] + public BotCutConfig BotCuts { get; set; } + + [Comment("""Settings for LuckyLadder command""")] + public LuckyLadderSettings LuckyLadder { get; set; } + + [Comment("""Settings related to waifus""")] + public WaifuConfig Waifu { get; set; } + + [Comment(""" + Amount of currency selfhosters will get PER pledged dollar CENT. + 1 = 100 currency per $. Used almost exclusively on public ellie. + """)] + public decimal PatreonCurrencyPerCent { get; set; } = 1; + + [Comment(""" + Currency reward per vote. + This will work only if you've set up VotesApi and correct credentials for topgg and/or discords voting + """)] + public long VoteReward { get; set; } = 100; + + [Comment("""Slot config""")] + public SlotsConfig Slots { get; set; } + + public GamblingConfig() + { + BetRoll = new(); + Waifu = new(); + Currency = new(); + BetFlip = new(); + Generation = new(); + Timely = new(); + Decay = new(); + Slots = new(); + LuckyLadder = new(); + BotCuts = new(); + } +} + +public class CurrencyConfig +{ + [Comment("""What is the emoji/character which represents the currency""")] + public string Sign { get; set; } = "💵"; + + [Comment("""What is the name of the currency""")] + public string Name { get; set; } = "Ellie Money"; + + [Comment(""" + For how long (in days) will the transactions be kept in the database (curtrs) + Set 0 to disable cleanup (keep transactions forever) + """)] + public int TransactionsLifetime { get; set; } = 0; +} + +[Cloneable] +public partial class TimelyConfig +{ + [Comment(""" + How much currency will the users get every time they run .timely command + setting to 0 or less will disable this feature + """)] + public int Amount { get; set; } = 0; + + [Comment(""" + How often (in hours) can users claim currency with .timely command + setting to 0 or less will disable this feature + """)] + public int Cooldown { get; set; } = 24; +} + +[Cloneable] +public partial class BetFlipConfig +{ + [Comment("""Bet multiplier if user guesses correctly""")] + public decimal Multiplier { get; set; } = 1.95M; +} + +[Cloneable] +public partial class BetRollConfig +{ + [Comment(""" + When betroll is played, user will roll a number 0-100. + This setting will describe which multiplier is used for when the roll is higher than the given number. + Doesn't have to be ordered. + """)] + public BetRollPair[] Pairs { get; set; } = Array.Empty(); + + public BetRollConfig() + => Pairs = + [ + new() + { + WhenAbove = 99, + MultiplyBy = 10 + }, + new() + { + WhenAbove = 90, + MultiplyBy = 4 + }, + new() + { + WhenAbove = 66, + MultiplyBy = 2 + } + ]; +} + +[Cloneable] +public partial class GenerationConfig +{ + [Comment(""" + when currency is generated, should it also have a random password + associated with it which users have to type after the .pick command + in order to get it + """)] + public bool HasPassword { get; set; } = true; + + [Comment(""" + Every message sent has a certain % chance to generate the currency + specify the percentage here (1 being 100%, 0 being 0% - for example + default is 0.02, which is 2% + """)] + public decimal Chance { get; set; } = 0.02M; + + [Comment("""How many seconds have to pass for the next message to have a chance to spawn currency""")] + public int GenCooldown { get; set; } = 10; + + [Comment("""Minimum amount of currency that can spawn""")] + public int MinAmount { get; set; } = 1; + + [Comment(""" + Maximum amount of currency that can spawn. + Set to the same value as MinAmount to always spawn the same amount + """)] + public int MaxAmount { get; set; } = 1; +} + +[Cloneable] +public partial class DecayConfig +{ + [Comment(""" + Percentage of user's current currency which will be deducted every 24h. + 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) + """)] + public decimal Percent { get; set; } = 0; + + [Comment("""Maximum amount of user's currency that can decay at each interval. 0 for unlimited.""")] + public int MaxDecay { get; set; } = 0; + + [Comment("""Only users who have more than this amount will have their currency decay.""")] + public int MinThreshold { get; set; } = 99; + + [Comment("""How often, in hours, does the decay run. Default is 24 hours""")] + public int HourInterval { get; set; } = 24; +} + +[Cloneable] +public partial class LuckyLadderSettings +{ + [Comment("""Self-Explanatory. Has to have 8 values, otherwise the command won't work.""")] + public decimal[] Multipliers { get; set; } + + public LuckyLadderSettings() + => Multipliers = [2.4M, 1.7M, 1.5M, 1.2M, 0.5M, 0.3M, 0.2M, 0.1M]; +} + +[Cloneable] +public sealed partial class WaifuConfig +{ + [Comment("""Minimum price a waifu can have""")] + public long MinPrice { get; set; } = 50; + + public MultipliersData Multipliers { get; set; } = new(); + + [Comment(""" + Settings for periodic waifu price decay. + Waifu price decays only if the waifu has no claimer. + """)] + public WaifuDecayConfig Decay { get; set; } = new(); + + [Comment(""" + List of items available for gifting. + If negative is true, gift will instead reduce waifu value. + """)] + public List Items { get; set; } = []; + + public WaifuConfig() + => Items = + [ + new("🥔", 5, "Potato"), + new("🍪", 10, "Cookie"), + new("🥖", 20, "Bread"), + new("🍭", 30, "Lollipop"), + new("🌹", 50, "Rose"), + new("🍺", 70, "Beer"), + new("🌮", 85, "Taco"), + new("💌", 100, "LoveLetter"), + new("🥛", 125, "Milk"), + new("🍕", 150, "Pizza"), + new("🍫", 200, "Chocolate"), + new("🍦", 250, "Icecream"), + new("🍣", 300, "Sushi"), + new("🍚", 400, "Rice"), + new("🍉", 500, "Watermelon"), + new("🍱", 600, "Bento"), + new("🎟", 800, "MovieTicket"), + new("🍰", 1000, "Cake"), + new("📔", 1500, "Book"), + new("🐱", 2000, "Cat"), + new("🐶", 2001, "Dog"), + new("🐼", 2500, "Panda"), + new("💄", 3000, "Lipstick"), + new("👛", 3500, "Purse"), + new("📱", 4000, "iPhone"), + new("👗", 4500, "Dress"), + new("💻", 5000, "Laptop"), + new("🎻", 7500, "Violin"), + new("🎹", 8000, "Piano"), + new("🚗", 9000, "Car"), + new("💍", 10000, "Ring"), + new("🛳", 12000, "Ship"), + new("🏠", 15000, "House"), + new("🚁", 20000, "Helicopter"), + new("🚀", 30000, "Spaceship"), + new("🌕", 50000, "Moon") + ]; + + public class WaifuDecayConfig + { + [Comment(""" + Percentage (0 - 100) of the waifu value to reduce. + Set 0 to disable + For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$) + """)] + public int Percent { get; set; } = 0; + + [Comment("""How often to decay waifu values, in hours""")] + public int HourInterval { get; set; } = 24; + + [Comment(""" + Minimum waifu price required for the decay to be applied. + For example if this value is set to 300, any waifu with the price 300 or less will not experience decay. + """)] + public long MinPrice { get; set; } = 300; + } +} + +[Cloneable] +public sealed partial class MultipliersData +{ + [Comment(""" + Multiplier for waifureset. Default 150. + Formula (at the time of writing this): + price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up + """)] + public int WaifuReset { get; set; } = 150; + + [Comment(""" + The minimum amount of currency that you have to pay + in order to buy a waifu who doesn't have a crush on you. + Default is 1.1 + Example: If a waifu is worth 100, you will have to pay at least 100 * NormalClaim currency to claim her. + (100 * 1.1 = 110) + """)] + public decimal NormalClaim { get; set; } = 1.1m; + + [Comment(""" + The minimum amount of currency that you have to pay + in order to buy a waifu that has a crush on you. + Default is 0.88 + Example: If a waifu is worth 100, you will have to pay at least 100 * CrushClaim currency to claim her. + (100 * 0.88 = 88) + """)] + public decimal CrushClaim { get; set; } = 0.88M; + + [Comment(""" + When divorcing a waifu, her new value will be her current value multiplied by this number. + Default 0.75 (meaning will lose 25% of her value) + """)] + public decimal DivorceNewValue { get; set; } = 0.75M; + + [Comment(""" + All gift prices will be multiplied by this number. + Default 1 (meaning no effect) + """)] + public decimal AllGiftPrices { get; set; } = 1.0M; + + [Comment(""" + What percentage of the value of the gift will a waifu gain when she's gifted. + Default 0.95 (meaning 95%) + Example: If a waifu is worth 1000, and she receives a gift worth 100, her new value will be 1095) + """)] + public decimal GiftEffect { get; set; } = 0.95M; + + [Comment(""" + What percentage of the value of the gift will a waifu lose when she's gifted a gift marked as 'negative'. + Default 0.5 (meaning 50%) + Example: If a waifu is worth 1000, and she receives a negative gift worth 100, her new value will be 950) + """)] + public decimal NegativeGiftEffect { get; set; } = 0.50M; +} + +public sealed class SlotsConfig +{ + [Comment("""Hex value of the color which the numbers on the slot image will have.""")] + public Rgba32 CurrencyFontColor { get; set; } = Color.Red; +} + +[Cloneable] +public sealed partial class WaifuItemModel +{ + public string ItemEmoji { get; set; } + public long Price { get; set; } + public string Name { get; set; } + + [YamlMember(DefaultValuesHandling = DefaultValuesHandling.OmitDefaults)] + public bool Negative { get; set; } + + public WaifuItemModel() + { + } + + public WaifuItemModel( + string itemEmoji, + long price, + string name, + bool negative = false) + { + ItemEmoji = itemEmoji; + Price = price; + Name = name; + Negative = negative; + } + + + public override string ToString() + => Name; +} + +[Cloneable] +public sealed partial class BetRollPair +{ + public int WhenAbove { get; set; } + public float MultiplyBy { get; set; } +} + +[Cloneable] +public sealed partial class BotCutConfig +{ + [Comment(""" + Shop sale cut percentage. + Whenever a user buys something from the shop, bot will take a cut equal to this percentage. + The rest goes to the user who posted the item/role/whatever to the shop. + This is a good way to reduce the amount of currency in circulation therefore keeping the inflation in check. + Default 0.1 (10%). + """)] + public decimal ShopSaleCut { get; set; } = 0.1m; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/GamblingConfigService.cs b/src/EllieBot/Modules/Gambling/GamblingConfigService.cs new file mode 100644 index 0000000..6fb8ff2 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/GamblingConfigService.cs @@ -0,0 +1,194 @@ +#nullable disable +using EllieBot.Common.Configs; +using EllieBot.Modules.Gambling.Common; + +namespace EllieBot.Modules.Gambling.Services; + +public sealed class GamblingConfigService : ConfigServiceBase +{ + private const string FILE_PATH = "data/gambling.yml"; + private static readonly TypedKey _changeKey = new("config.gambling.updated"); + + public override string Name + => "gambling"; + + private readonly IEnumerable _antiGiftSeed = new[] + { + new WaifuItemModel("🥀", 100, "WiltedRose", true), new WaifuItemModel("✂️", 1000, "Haircut", true), + new WaifuItemModel("🧻", 10000, "ToiletPaper", true) + }; + + public GamblingConfigService(IConfigSeria serializer, IPubSub pubSub) + : base(FILE_PATH, serializer, pubSub, _changeKey) + { + AddParsedProp("currency.name", + gs => gs.Currency.Name, + ConfigParsers.String, + ConfigPrinters.ToString); + + AddParsedProp("currency.sign", + gs => gs.Currency.Sign, + ConfigParsers.String, + ConfigPrinters.ToString); + + AddParsedProp("minbet", + gs => gs.MinBet, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("maxbet", + gs => gs.MaxBet, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("gen.min", + gs => gs.Generation.MinAmount, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 1); + + AddParsedProp("gen.max", + gs => gs.Generation.MaxAmount, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 1); + + AddParsedProp("gen.cd", + gs => gs.Generation.GenCooldown, + int.TryParse, + ConfigPrinters.ToString, + val => val > 0); + + AddParsedProp("gen.chance", + gs => gs.Generation.Chance, + decimal.TryParse, + ConfigPrinters.ToString, + val => val is >= 0 and <= 1); + + AddParsedProp("gen.has_pw", + gs => gs.Generation.HasPassword, + bool.TryParse, + ConfigPrinters.ToString); + + AddParsedProp("bf.multi", + gs => gs.BetFlip.Multiplier, + decimal.TryParse, + ConfigPrinters.ToString, + val => val >= 1); + + AddParsedProp("waifu.min_price", + gs => gs.Waifu.MinPrice, + long.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("waifu.multi.reset", + gs => gs.Waifu.Multipliers.WaifuReset, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("waifu.multi.crush_claim", + gs => gs.Waifu.Multipliers.CrushClaim, + decimal.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("waifu.multi.normal_claim", + gs => gs.Waifu.Multipliers.NormalClaim, + decimal.TryParse, + ConfigPrinters.ToString, + val => val > 0); + + AddParsedProp("waifu.multi.divorce_value", + gs => gs.Waifu.Multipliers.DivorceNewValue, + decimal.TryParse, + ConfigPrinters.ToString, + val => val > 0); + + AddParsedProp("waifu.multi.all_gifts", + gs => gs.Waifu.Multipliers.AllGiftPrices, + decimal.TryParse, + ConfigPrinters.ToString, + val => val > 0); + + AddParsedProp("waifu.multi.gift_effect", + gs => gs.Waifu.Multipliers.GiftEffect, + decimal.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("waifu.multi.negative_gift_effect", + gs => gs.Waifu.Multipliers.NegativeGiftEffect, + decimal.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("decay.percent", + gs => gs.Decay.Percent, + decimal.TryParse, + ConfigPrinters.ToString, + val => val is >= 0 and <= 1); + + AddParsedProp("decay.maxdecay", + gs => gs.Decay.MaxDecay, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + AddParsedProp("decay.threshold", + gs => gs.Decay.MinThreshold, + int.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + + Migrate(); + } + + public void Migrate() + { + if (data.Version < 2) + { + ModifyConfig(c => + { + c.Waifu.Items = c.Waifu.Items.Concat(_antiGiftSeed).ToList(); + c.Version = 2; + }); + } + + if (data.Version < 3) + { + ModifyConfig(c => + { + c.Version = 3; + c.VoteReward = 100; + }); + } + + if (data.Version < 5) + { + ModifyConfig(c => + { + c.Version = 5; + }); + } + + if (data.Version < 6) + { + ModifyConfig(c => + { + c.Version = 6; + }); + } + + if (data.Version < 7) + { + ModifyConfig(c => + { + c.Version = 7; + }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/GamblingService.cs b/src/EllieBot/Modules/Gambling/GamblingService.cs new file mode 100644 index 0000000..a324437 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/GamblingService.cs @@ -0,0 +1,220 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Connect4; + +namespace EllieBot.Modules.Gambling.Services; + +public class GamblingService : IEService, IReadyExecutor +{ + public ConcurrentDictionary<(ulong, ulong), RollDuelGame> Duels { get; } = new(); + public ConcurrentDictionary Connect4Games { get; } = new(); + private readonly DbService _db; + private readonly DiscordSocketClient _client; + private readonly IBotCache _cache; + private readonly GamblingConfigService _gss; + + private static readonly TypedKey _curDecayKey = new("currency:last_decay"); + + public GamblingService( + DbService db, + DiscordSocketClient client, + IBotCache cache, + GamblingConfigService gss) + { + _db = db; + _client = client; + _cache = cache; + _gss = gss; + } + + public Task OnReadyAsync() + => Task.WhenAll(CurrencyDecayLoopAsync(), TransactionClearLoopAsync()); + + private async Task TransactionClearLoopAsync() + { + if (_client.ShardId != 0) + return; + + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + while (await timer.WaitForNextTickAsync()) + { + try + { + var lifetime = _gss.Data.Currency.TransactionsLifetime; + if (lifetime <= 0) + continue; + + var now = DateTime.UtcNow; + var days = TimeSpan.FromDays(lifetime); + await using var uow = _db.GetDbContext(); + await uow.Set() + .DeleteAsync(ct => ct.DateAdded == null || now - ct.DateAdded < days); + } + catch (Exception ex) + { + Log.Warning(ex, + "An unexpected error occurred in transactions cleanup loop: {ErrorMessage}", + ex.Message); + } + } + } + + private async Task CurrencyDecayLoopAsync() + { + if (_client.ShardId != 0) + return; + + using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5)); + while (await timer.WaitForNextTickAsync()) + { + try + { + var config = _gss.Data; + var maxDecay = config.Decay.MaxDecay; + if (config.Decay.Percent is <= 0 or > 1 || maxDecay < 0) + continue; + + var now = DateTime.UtcNow; + + await using var uow = _db.GetDbContext(); + var result = await _cache.GetAsync(_curDecayKey); + + if (result.TryPickT0(out var bin, out _) + && (now - DateTime.FromBinary(bin) < TimeSpan.FromHours(config.Decay.HourInterval))) + { + continue; + } + + Log.Information(""" + --- Decaying users' currency --- + | decay: {ConfigDecayPercent}% + | max: {MaxDecay} + | threshold: {DecayMinTreshold} + """, + config.Decay.Percent * 100, + maxDecay, + config.Decay.MinThreshold); + + if (maxDecay == 0) + maxDecay = int.MaxValue; + + var decay = (double)config.Decay.Percent; + await uow.Set() + .Where(x => x.CurrencyAmount > config.Decay.MinThreshold && x.UserId != _client.CurrentUser.Id) + .UpdateAsync(old => new() + { + CurrencyAmount = + maxDecay > Sql.Round((old.CurrencyAmount * decay) - 0.5) + ? (long)(old.CurrencyAmount - Sql.Round((old.CurrencyAmount * decay) - 0.5)) + : old.CurrencyAmount - maxDecay + }); + + await uow.SaveChangesAsync(); + + await _cache.AddAsync(_curDecayKey, now.ToBinary()); + } + catch (Exception ex) + { + Log.Warning(ex, + "An unexpected error occurred in currency decay loop: {ErrorMessage}", + ex.Message); + } + } + } + + private static readonly TypedKey _ecoKey = new("ellie:economy"); + + public async Task GetEconomyAsync() + { + var data = await _cache.GetOrAddAsync(_ecoKey, + async () => + { + await using var uow = _db.GetDbContext(); + var cash = uow.Set().GetTotalCurrency(); + var onePercent = uow.Set().GetTopOnePercentCurrency(_client.CurrentUser.Id); + decimal planted = uow.Set().AsQueryable().Sum(x => x.Amount); + var waifus = uow.Set().GetTotalValue(); + var bot = await uow.Set().GetUserCurrencyAsync(_client.CurrentUser.Id); + decimal bank = await uow.GetTable() + .SumAsyncLinqToDB(x => x.Balance); + + var result = new EconomyResult + { + Cash = cash, + Planted = planted, + Bot = bot, + Waifus = waifus, + OnePercent = onePercent, + Bank = bank + }; + + return result; + }, + TimeSpan.FromMinutes(3)); + + return data; + } + + + private static readonly SemaphoreSlim _timelyLock = new(1, 1); + + private static TypedKey> _timelyKey + = new("timely:claims"); + + public async Task ClaimTimelyAsync(ulong userId, int period) + { + if (period == 0) + return null; + + await _timelyLock.WaitAsync(); + try + { + // get the dictionary from the cache or get a new one + var dict = (await _cache.GetOrAddAsync(_timelyKey, + () => Task.FromResult(new Dictionary())))!; + + var now = DateTime.UtcNow; + var nowB = now.ToBinary(); + + // try to get users last claim + if (!dict.TryGetValue(userId, out var lastB)) + lastB = dict[userId] = now.ToBinary(); + + var diff = now - DateTime.FromBinary(lastB); + + // if its now, or too long ago => success + if (lastB == nowB || diff > period.Hours()) + { + // update the cache + dict[userId] = nowB; + await _cache.AddAsync(_timelyKey, dict); + + return null; + } + else + { + // otherwise return the remaining time + return period.Hours() - diff; + } + } + finally + { + _timelyLock.Release(); + } + } + + public bool UserHasTimelyReminder(ulong userId) + { + var db = _db.GetDbContext(); + return db.GetTable().Any(x => x.UserId == userId + && x.Type == ReminderType.Timely); + } + + public async Task RemoveAllTimelyClaimsAsync() + => await _cache.RemoveAsync(_timelyKey); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/GamblingTopLevelModule.cs b/src/EllieBot/Modules/Gambling/GamblingTopLevelModule.cs new file mode 100644 index 0000000..25cbb73 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/GamblingTopLevelModule.cs @@ -0,0 +1,68 @@ +#nullable disable +using EllieBot.Modules.Gambling.Services; +using System.Numerics; + +namespace EllieBot.Modules.Gambling.Common; + +public abstract class GamblingModule : EllieModule +{ + protected GamblingConfig Config + => _lazyConfig.Value; + + protected string CurrencySign + => Config.Currency.Sign; + + protected string CurrencyName + => Config.Currency.Name; + + private readonly Lazy _lazyConfig; + + protected GamblingModule(GamblingConfigService gambService) + => _lazyConfig = new(() => gambService.Data); + + private async Task InternalCheckBet(long amount) + { + if (amount < 1) + return false; + + if (amount < Config.MinBet) + { + await Response().Error(strs.min_bet_limit(Format.Bold(Config.MinBet.ToString()) + CurrencySign)).SendAsync(); + return false; + } + + if (Config.MaxBet > 0 && amount > Config.MaxBet) + { + await Response().Error(strs.max_bet_limit(Format.Bold(Config.MaxBet.ToString()) + CurrencySign)).SendAsync(); + return false; + } + + return true; + } + + protected string N(T cur) + where T : INumber + => CurrencyHelper.N(cur, Culture, CurrencySign); + + protected Task CheckBetMandatory(long amount) + { + if (amount < 1) + return Task.FromResult(false); + return InternalCheckBet(amount); + } + + protected Task CheckBetOptional(long amount) + { + if (amount == 0) + return Task.FromResult(true); + return InternalCheckBet(amount); + } +} + +public abstract class GamblingSubmodule : GamblingModule +{ + protected GamblingSubmodule(GamblingConfigService gamblingConfService) + : base(gamblingConfService) + { + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/InputRpsPick.cs b/src/EllieBot/Modules/Gambling/InputRpsPick.cs new file mode 100644 index 0000000..d0c76f0 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/InputRpsPick.cs @@ -0,0 +1,3 @@ +#nullable disable +namespace EllieBot.Modules.Gambling; + diff --git a/src/EllieBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs b/src/EllieBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs new file mode 100644 index 0000000..67994c8 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/PlantPick/PlantAndPickCommands.cs @@ -0,0 +1,114 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class PlantPickCommands : GamblingSubmodule + { + private readonly ILogCommandService _logService; + + public PlantPickCommands(ILogCommandService logService, GamblingConfigService gss) + : base(gss) + => _logService = logService; + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Pick(string pass = null) + { + if (!string.IsNullOrWhiteSpace(pass) && !pass.IsAlphaNumeric()) + return; + + var picked = await _service.PickAsync(ctx.Guild.Id, (ITextChannel)ctx.Channel, ctx.User.Id, pass); + + if (picked > 0) + { + var msg = await Response().NoReply().Confirm(strs.picked(N(picked), ctx.User)).SendAsync(); + msg.DeleteAfter(10); + } + + if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages) + { + try + { + _logService.AddDeleteIgnore(ctx.Message.Id); + await ctx.Message.DeleteAsync(); + } + catch { } + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Plant([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, string pass = null) + { + if (amount < 1) + return; + + if (!string.IsNullOrWhiteSpace(pass) && !pass.IsAlphaNumeric()) + return; + + if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages) + { + _logService.AddDeleteIgnore(ctx.Message.Id); + await ctx.Message.DeleteAsync(); + } + + var success = await _service.PlantAsync(ctx.Guild.Id, + ctx.Channel, + ctx.User.Id, + ctx.User.ToString(), + amount, + pass); + + if (!success) + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] +#if GLOBAL_ELLIE + [OwnerOnly] +#endif + public async Task GenCurrency() + { + var enabled = _service.ToggleCurrencyGeneration(ctx.Guild.Id, ctx.Channel.Id); + if (enabled) + await Response().Confirm(strs.curgen_enabled).SendAsync(); + else + await Response().Confirm(strs.curgen_disabled).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [OwnerOnly] + public Task GenCurList(int page = 1) + { + if (--page < 0) + return Task.CompletedTask; + + var enabledIn = _service.GetAllGeneratingChannels(); + + return Response() + .Paginated() + .Items(enabledIn.ToList()) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + if (!items.Any()) + return _sender.CreateEmbed().WithErrorColor().WithDescription("-"); + + return items.Aggregate(_sender.CreateEmbed().WithOkColor(), + (eb, i) => eb.AddField(i.GuildId.ToString(), i.ChannelId)); + }) + .SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/PlantPick/PlantPickService.cs b/src/EllieBot/Modules/Gambling/PlantPick/PlantPickService.cs new file mode 100644 index 0000000..6b50a1e --- /dev/null +++ b/src/EllieBot/Modules/Gambling/PlantPick/PlantPickService.cs @@ -0,0 +1,385 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Db.Models; +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using Color = SixLabors.ImageSharp.Color; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Gambling.Services; + +public class PlantPickService : IEService, IExecNoCommand +{ + //channelId/last generation + public ConcurrentDictionary LastGenerations { get; } = new(); + private readonly DbService _db; + private readonly IBotStrings _strings; + private readonly IImageCache _images; + private readonly FontProvider _fonts; + private readonly ICurrencyService _cs; + private readonly CommandHandler _cmdHandler; + private readonly EllieRandom _rng; + private readonly DiscordSocketClient _client; + private readonly GamblingConfigService _gss; + + private readonly ConcurrentHashSet _generationChannels; + private readonly SemaphoreSlim _pickLock = new(1, 1); + + public PlantPickService( + DbService db, + CommandHandler cmd, + IBotStrings strings, + IImageCache images, + FontProvider fonts, + ICurrencyService cs, + CommandHandler cmdHandler, + DiscordSocketClient client, + GamblingConfigService gss) + { + _db = db; + _strings = strings; + _images = images; + _fonts = fonts; + _cs = cs; + _cmdHandler = cmdHandler; + _rng = new(); + _client = client; + _gss = gss; + + using var uow = db.GetDbContext(); + var guildIds = client.Guilds.Select(x => x.Id).ToList(); + var configs = uow.Set() + .AsQueryable() + .Include(x => x.GenerateCurrencyChannelIds) + .Where(x => guildIds.Contains(x.GuildId)) + .ToList(); + + _generationChannels = new(configs.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); + } + + public Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg) + => PotentialFlowerGeneration(msg); + + private string GetText(ulong gid, LocStr str) + => _strings.GetText(str, gid); + + public bool ToggleCurrencyGeneration(ulong gid, ulong cid) + { + bool enabled; + using var uow = _db.GetDbContext(); + var guildConfig = uow.GuildConfigsForId(gid, set => set.Include(gc => gc.GenerateCurrencyChannelIds)); + + var toAdd = new GCChannelId + { + ChannelId = cid + }; + if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd)) + { + guildConfig.GenerateCurrencyChannelIds.Add(toAdd); + _generationChannels.Add(cid); + enabled = true; + } + else + { + var toDelete = guildConfig.GenerateCurrencyChannelIds.FirstOrDefault(x => x.Equals(toAdd)); + if (toDelete is not null) + uow.Remove(toDelete); + _generationChannels.TryRemove(cid); + enabled = false; + } + + uow.SaveChanges(); + return enabled; + } + + public IEnumerable GetAllGeneratingChannels() + { + using var uow = _db.GetDbContext(); + var chs = uow.Set().GetGeneratingChannels(); + return chs; + } + + /// + /// Get a random currency image stream, with an optional password sticked onto it. + /// + /// Optional password to add to top left corner. + /// Extension of the file, defaults to png + /// Stream of the currency image + public async Task<(Stream, string)> GetRandomCurrencyImageAsync(string pass) + { + var curImg = await _images.GetCurrencyImageAsync(); + + if (string.IsNullOrWhiteSpace(pass)) + { + // determine the extension + using var load = _ = Image.Load(curImg, out var format); + + // return the image + return (curImg.ToStream(), format.FileExtensions.FirstOrDefault() ?? "png"); + } + + // get the image stream and extension + return AddPassword(curImg, pass); + } + + /// + /// Add a password to the image. + /// + /// Image to add password to. + /// Password to add to top left corner. + /// Image with the password in the top left corner. + private (Stream, string) AddPassword(byte[] curImg, string pass) + { + // draw lower, it looks better + pass = pass.TrimTo(10, true).ToLowerInvariant(); + using var img = Image.Load(curImg, out var format); + // choose font size based on the image height, so that it's visible + var font = _fonts.NotoSans.CreateFont(img.Height / 12.0f, FontStyle.Bold); + img.Mutate(x => + { + // measure the size of the text to be drawing + var size = TextMeasurer.Measure(pass, new TextOptions(font) + { + Origin = new PointF(0, 0) + }); + + // fill the background with black, add 5 pixels on each side to make it look better + x.FillPolygon(Color.ParseHex("00000080"), + new PointF(0, 0), + new PointF(size.Width + 5, 0), + new PointF(size.Width + 5, size.Height + 10), + new PointF(0, size.Height + 10)); + + // draw the password over the background + x.DrawText(pass, font, Color.White, new(0, 0)); + }); + // return image as a stream for easy sending + return (img.ToStream(format), format.FileExtensions.FirstOrDefault() ?? "png"); + } + + private Task PotentialFlowerGeneration(IUserMessage imsg) + { + if (imsg is not SocketUserMessage msg || msg.Author.IsBot) + return Task.CompletedTask; + + if (imsg.Channel is not ITextChannel channel) + return Task.CompletedTask; + + if (!_generationChannels.Contains(channel.Id)) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + try + { + var config = _gss.Data; + var lastGeneration = LastGenerations.GetOrAdd(channel.Id, DateTime.MinValue.ToBinary()); + var rng = new EllieRandom(); + + if (DateTime.UtcNow - TimeSpan.FromSeconds(config.Generation.GenCooldown) + < DateTime.FromBinary(lastGeneration)) //recently generated in this channel, don't generate again + return; + + var num = rng.Next(1, 101) + (config.Generation.Chance * 100); + if (num > 100 && LastGenerations.TryUpdate(channel.Id, DateTime.UtcNow.ToBinary(), lastGeneration)) + { + var dropAmount = config.Generation.MinAmount; + var dropAmountMax = config.Generation.MaxAmount; + + if (dropAmountMax > dropAmount) + dropAmount = new EllieRandom().Next(dropAmount, dropAmountMax + 1); + + if (dropAmount > 0) + { + var prefix = _cmdHandler.GetPrefix(channel.Guild.Id); + var toSend = dropAmount == 1 + ? GetText(channel.GuildId, strs.curgen_sn(config.Currency.Sign)) + + " " + + GetText(channel.GuildId, strs.pick_sn(prefix)) + : GetText(channel.GuildId, strs.curgen_pl(dropAmount, config.Currency.Sign)) + + " " + + GetText(channel.GuildId, strs.pick_pl(prefix)); + + var pw = config.Generation.HasPassword ? GenerateCurrencyPassword().ToUpperInvariant() : null; + + IUserMessage sent; + var (stream, ext) = await GetRandomCurrencyImageAsync(pw); + + await using (stream) + sent = await channel.SendFileAsync(stream, $"currency_image.{ext}", toSend); + + await AddPlantToDatabase(channel.GuildId, + channel.Id, + _client.CurrentUser.Id, + sent.Id, + dropAmount, + pw); + } + } + } + catch + { + } + }); + return Task.CompletedTask; + } + + /// + /// Generate a hexadecimal string from 1000 to ffff. + /// + /// A hexadecimal string from 1000 to ffff + private string GenerateCurrencyPassword() + { + // generate a number from 1000 to ffff + var num = _rng.Next(4096, 65536); + // convert it to hexadecimal + return num.ToString("x4"); + } + + public async Task PickAsync( + ulong gid, + ITextChannel ch, + ulong uid, + string pass) + { + await _pickLock.WaitAsync(); + try + { + long amount; + ulong[] ids; + await using (var uow = _db.GetDbContext()) + { + // this method will sum all plants with that password, + // remove them, and get messageids of the removed plants + + pass = pass?.Trim().TrimTo(10, true).ToUpperInvariant(); + // gets all plants in this channel with the same password + var entries = uow.Set().AsQueryable() + .Where(x => x.ChannelId == ch.Id && pass == x.Password) + .ToList(); + // sum how much currency that is, and get all of the message ids (so that i can delete them) + amount = entries.Sum(x => x.Amount); + ids = entries.Select(x => x.MessageId).ToArray(); + // remove them from the database + uow.RemoveRange(entries); + + + if (amount > 0) + // give the picked currency to the user + await _cs.AddAsync(uid, amount, new("currency", "collect")); + await uow.SaveChangesAsync(); + } + + try + { + // delete all of the plant messages which have just been picked + _ = ch.DeleteMessagesAsync(ids); + } + catch { } + + // return the amount of currency the user picked + return amount; + } + finally + { + _pickLock.Release(); + } + } + + public async Task SendPlantMessageAsync( + ulong gid, + IMessageChannel ch, + string user, + long amount, + string pass) + { + try + { + // get the text + var prefix = _cmdHandler.GetPrefix(gid); + var msgToSend = GetText(gid, strs.planted(Format.Bold(user), amount + _gss.Data.Currency.Sign)); + + if (amount > 1) + msgToSend += " " + GetText(gid, strs.pick_pl(prefix)); + else + msgToSend += " " + GetText(gid, strs.pick_sn(prefix)); + + //get the image + var (stream, ext) = await GetRandomCurrencyImageAsync(pass); + // send it + await using (stream) + { + var msg = await ch.SendFileAsync(stream, $"img.{ext}", msgToSend); + // return sent message's id (in order to be able to delete it when it's picked) + return msg.Id; + } + } + catch (Exception ex) + { + // if sending fails, return null as message id + Log.Warning(ex, "Sending plant message failed: {Message}", ex.Message); + return null; + } + } + + public async Task PlantAsync( + ulong gid, + IMessageChannel ch, + ulong uid, + string user, + long amount, + string pass) + { + // normalize it - no more than 10 chars, uppercase + pass = pass?.Trim().TrimTo(10, true).ToUpperInvariant(); + // has to be either null or alphanumeric + if (!string.IsNullOrWhiteSpace(pass) && !pass.IsAlphaNumeric()) + return false; + + // remove currency from the user who's planting + if (await _cs.RemoveAsync(uid, amount, new("put/collect", "put"))) + { + // try to send the message with the currency image + var msgId = await SendPlantMessageAsync(gid, ch, user, amount, pass); + if (msgId is null) + { + // if it fails it will return null, if it returns null, refund + await _cs.AddAsync(uid, amount, new("put/collect", "refund")); + return false; + } + + // if it doesn't fail, put the plant in the database for other people to pick + await AddPlantToDatabase(gid, ch.Id, uid, msgId.Value, amount, pass); + return true; + } + + // if user doesn't have enough currency, fail + return false; + } + + private async Task AddPlantToDatabase( + ulong gid, + ulong cid, + ulong uid, + ulong mid, + long amount, + string pass) + { + await using var uow = _db.GetDbContext(); + uow.Set().Add(new() + { + Amount = amount, + GuildId = gid, + ChannelId = cid, + Password = pass, + UserId = uid, + MessageId = mid + }); + await uow.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs b/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs new file mode 100644 index 0000000..513aa59 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleCommands.cs @@ -0,0 +1,61 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + public partial class CurrencyRaffleCommands : GamblingSubmodule + { + public enum Mixed { Mixed } + + public CurrencyRaffleCommands(GamblingConfigService gamblingConfService) + : base(gamblingConfService) + { + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public Task RaffleCur(Mixed _, [OverrideTypeReader(typeof(BalanceTypeReader))] long amount) + => RaffleCur(amount, true); + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task RaffleCur([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, bool mixed = false) + { + if (!await CheckBetMandatory(amount)) + return; + + async Task OnEnded(IUser arg, long won) + { + await Response() + .Confirm(GetText(strs.rafflecur_ended(CurrencyName, + Format.Bold(arg.ToString()), + won + CurrencySign))) + .SendAsync(); + } + + var res = await _service.JoinOrCreateGame(ctx.Channel.Id, ctx.User, amount, mixed, OnEnded); + + if (res.Item1 is not null) + { + await Response() + .Confirm(GetText(strs.rafflecur(res.Item1.GameType.ToString())), + string.Join("\n", res.Item1.Users.Select(x => $"{x.DiscordUser} ({N(x.Amount)})")), + footer: GetText(strs.rafflecur_joined(ctx.User.ToString()))) + .SendAsync(); + } + else + { + if (res.Item2 == CurrencyRaffleService.JoinErrorType.AlreadyJoinedOrInvalidAmount) + await Response().Error(strs.rafflecur_already_joined).SendAsync(); + else if (res.Item2 == CurrencyRaffleService.JoinErrorType.NotEnoughCurrency) + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleGame.cs b/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleGame.cs new file mode 100644 index 0000000..d6f5770 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleGame.cs @@ -0,0 +1,69 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common; + +public class CurrencyRaffleGame +{ + public enum Type + { + Mixed, + Normal + } + + public IEnumerable Users + => _users; + + public Type GameType { get; } + + private readonly HashSet _users = new(); + + public CurrencyRaffleGame(Type type) + => GameType = type; + + public bool AddUser(IUser usr, long amount) + { + // if game type is normal, and someone already joined the game + // (that's the user who created it) + if (GameType == Type.Normal && _users.Count > 0 && _users.First().Amount != amount) + return false; + + if (!_users.Add(new() + { + DiscordUser = usr, + Amount = amount + })) + return false; + + return true; + } + + public User GetWinner() + { + var rng = new EllieRandom(); + if (GameType == Type.Mixed) + { + var num = rng.NextLong(0L, Users.Sum(x => x.Amount)); + var sum = 0L; + foreach (var u in Users) + { + sum += u.Amount; + if (sum > num) + return u; + } + } + + var usrs = _users.ToArray(); + return usrs[rng.Next(0, usrs.Length)]; + } + + public class User + { + public IUser DiscordUser { get; set; } + public long Amount { get; set; } + + public override int GetHashCode() + => DiscordUser.GetHashCode(); + + public override bool Equals(object obj) + => obj is User u ? u.DiscordUser == DiscordUser : false; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleService.cs b/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleService.cs new file mode 100644 index 0000000..743549e --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Raffle/CurrencyRaffleService.cs @@ -0,0 +1,81 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common; + +namespace EllieBot.Modules.Gambling.Services; + +public class CurrencyRaffleService : IEService +{ + public enum JoinErrorType + { + NotEnoughCurrency, + AlreadyJoinedOrInvalidAmount + } + + public Dictionary Games { get; } = new(); + private readonly SemaphoreSlim _locker = new(1, 1); + private readonly ICurrencyService _cs; + + public CurrencyRaffleService(ICurrencyService cs) + => _cs = cs; + + public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame( + ulong channelId, + IUser user, + long amount, + bool mixed, + Func onEnded) + { + await _locker.WaitAsync(); + try + { + var newGame = false; + if (!Games.TryGetValue(channelId, out var crg)) + { + newGame = true; + crg = new(mixed ? CurrencyRaffleGame.Type.Mixed : CurrencyRaffleGame.Type.Normal); + Games.Add(channelId, crg); + } + + //remove money, and stop the game if this + // user created it and doesn't have the money + if (!await _cs.RemoveAsync(user.Id, amount, new("raffle", "join"))) + { + if (newGame) + Games.Remove(channelId); + return (null, JoinErrorType.NotEnoughCurrency); + } + + if (!crg.AddUser(user, amount)) + { + await _cs.AddAsync(user.Id, amount, new("raffle", "refund")); + return (null, JoinErrorType.AlreadyJoinedOrInvalidAmount); + } + + if (newGame) + { + _ = Task.Run(async () => + { + await Task.Delay(60000); + await _locker.WaitAsync(); + try + { + var winner = crg.GetWinner(); + var won = crg.Users.Sum(x => x.Amount); + + await _cs.AddAsync(winner.DiscordUser.Id, won, new("raffle", "win")); + Games.Remove(channelId, out _); + _ = onEnded(winner.DiscordUser, won); + } + catch { } + finally { _locker.Release(); } + }); + } + + return (crg, null); + } + finally + { + _locker.Release(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Shop/IShopService.cs b/src/EllieBot/Modules/Gambling/Shop/IShopService.cs new file mode 100644 index 0000000..f8d19f8 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Shop/IShopService.cs @@ -0,0 +1,46 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling.Services; + +public interface IShopService +{ + /// + /// Changes the price of a shop item + /// + /// Id of the guild in which the shop is + /// Index of the item + /// New item price + /// Success status + Task ChangeEntryPriceAsync(ulong guildId, int index, int newPrice); + + /// + /// Changes the name of a shop item + /// + /// Id of the guild in which the shop is + /// Index of the item + /// New item name + /// Success status + Task ChangeEntryNameAsync(ulong guildId, int index, string newName); + + /// + /// Swaps indexes of 2 items in the shop + /// + /// Id of the guild in which the shop is + /// First entry's index + /// Second entry's index + /// Whether swap was successful + Task SwapEntriesAsync(ulong guildId, int index1, int index2); + + /// + /// Swaps indexes of 2 items in the shop + /// + /// Id of the guild in which the shop is + /// Current index of the entry to move + /// Destination index of the entry + /// Whether swap was successful + Task MoveEntryAsync(ulong guildId, int fromIndex, int toIndex); + + Task SetItemRoleRequirementAsync(ulong guildId, int index, ulong? roleId); + Task AddShopCommandAsync(ulong guildId, ulong userId, int price, string command); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs b/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs new file mode 100644 index 0000000..8b5230b --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs @@ -0,0 +1,590 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; +using EllieBot.Db.Models; +using EllieBot.Modules.Administration; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class ShopCommands : GamblingSubmodule + { + public enum List + { + List + } + + public enum Role + { + Role + } + + public enum Command + { + Command, + Cmd + } + + private readonly DbService _db; + private readonly ICurrencyService _cs; + + public ShopCommands(DbService db, ICurrencyService cs, GamblingConfigService gamblingConf) + : base(gamblingConf) + { + _db = db; + _cs = cs; + } + + private Task ShopInternalAsync(int page = 0) + { + if (page < 0) + throw new ArgumentOutOfRangeException(nameof(page)); + + using var uow = _db.GetDbContext(); + var entries = uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries).ThenInclude(x => x.Items)) + .ShopEntries.ToIndexed(); + + return Response() + .Paginated() + .Items(entries.ToList()) + .PageSize(9) + .CurrentPage(page) + .Page((items, curPage) => + { + if (!items.Any()) + return _sender.CreateEmbed().WithErrorColor().WithDescription(GetText(strs.shop_none)); + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.shop)); + + for (var i = 0; i < items.Count; i++) + { + var entry = items[i]; + embed.AddField($"#{(curPage * 9) + i + 1} - {N(entry.Price)}", + EntryToString(entry), + true); + } + + return embed; + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task Shop(int page = 1) + { + if (--page < 0) + return Task.CompletedTask; + + return ShopInternalAsync(page); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Buy(int index) + { + index -= 1; + if (index < 0) + return; + ShopEntry entry; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries).ThenInclude(x => x.Items)); + var entries = new IndexedCollection(config.ShopEntries); + entry = entries.ElementAtOrDefault(index); + uow.SaveChanges(); + } + + if (entry is null) + { + await Response().Error(strs.shop_item_not_found).SendAsync(); + return; + } + + if (entry.RoleRequirement is ulong reqRoleId) + { + var role = ctx.Guild.GetRole(reqRoleId); + if (role is null) + { + await Response().Error(strs.shop_item_req_role_not_found).SendAsync(); + return; + } + + var guser = (IGuildUser)ctx.User; + if (!guser.RoleIds.Contains(reqRoleId)) + { + await Response() + .Error(strs.shop_item_req_role_unfulfilled(Format.Bold(role.ToString()))) + .SendAsync(); + return; + } + } + + if (entry.Type == ShopEntryType.Role) + { + var guser = (IGuildUser)ctx.User; + var role = ctx.Guild.GetRole(entry.RoleId); + + if (role is null) + { + await Response().Error(strs.shop_role_not_found).SendAsync(); + return; + } + + if (guser.RoleIds.Any(id => id == role.Id)) + { + await Response().Error(strs.shop_role_already_bought).SendAsync(); + return; + } + + if (await _cs.RemoveAsync(ctx.User.Id, entry.Price, new("shop", "buy", entry.Type.ToString()))) + { + try + { + await guser.AddRoleAsync(role); + } + catch (Exception ex) + { + Log.Warning(ex, "Error adding shop role"); + await _cs.AddAsync(ctx.User.Id, entry.Price, new("shop", "error-refund")); + await Response().Error(strs.shop_role_purchase_error).SendAsync(); + return; + } + + var profit = GetProfitAmount(entry.Price); + await _cs.AddAsync(entry.AuthorId, profit, new("shop", "sell", $"Shop sell item - {entry.Type}")); + await _cs.AddAsync(ctx.Client.CurrentUser.Id, entry.Price - profit, new("shop", "cut")); + await Response().Confirm(strs.shop_role_purchase(Format.Bold(role.Name))).SendAsync(); + return; + } + + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + else if (entry.Type == ShopEntryType.List) + { + if (entry.Items.Count == 0) + { + await Response().Error(strs.out_of_stock).SendAsync(); + return; + } + + var item = entry.Items.ToArray()[new EllieRandom().Next(0, entry.Items.Count)]; + + if (await _cs.RemoveAsync(ctx.User.Id, entry.Price, new("shop", "buy", entry.Type.ToString()))) + { + await using (var uow = _db.GetDbContext()) + { + uow.Set().Remove(item); + await uow.SaveChangesAsync(); + } + + try + { + await Response() + .User(ctx.User) + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name))) + .AddField(GetText(strs.item), item.Text) + .AddField(GetText(strs.price), entry.Price.ToString(), true) + .AddField(GetText(strs.name), entry.Name, true)) + .SendAsync(); + + await _cs.AddAsync(entry.AuthorId, + GetProfitAmount(entry.Price), + new("shop", "sell", entry.Name)); + } + catch + { + await _cs.AddAsync(ctx.User.Id, entry.Price, new("shop", "error-refund", entry.Name)); + await using (var uow = _db.GetDbContext()) + { + var entries = new IndexedCollection(uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries) + .ThenInclude(x => x.Items)) + .ShopEntries); + entry = entries.ElementAtOrDefault(index); + if (entry is not null) + { + if (entry.Items.Add(item)) + uow.SaveChanges(); + } + } + + await Response().Error(strs.shop_buy_error).SendAsync(); + return; + } + + await Response().Confirm(strs.shop_item_purchase).SendAsync(); + } + else + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + } + else if (entry.Type == ShopEntryType.Command) + { + var guild = ctx.Guild as SocketGuild; + var channel = ctx.Channel as ISocketMessageChannel; + var msg = ctx.Message as SocketUserMessage; + var user = await ctx.Guild.GetUserAsync(entry.AuthorId); + + if (guild is null || channel is null || msg is null || user is null) + { + await Response().Error(strs.shop_command_invalid_context).SendAsync(); + return; + } + + if (!await _cs.RemoveAsync(ctx.User.Id, entry.Price, new("shop", "buy", entry.Type.ToString()))) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + else + { + var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString()); + var eb = _sender.CreateEmbed() + .WithPendingColor() + .WithTitle("Executing shop command") + .WithDescription(cmd); + + var msgTask = Response().Embed(eb).SendAsync(); + + await _cs.AddAsync(entry.AuthorId, + GetProfitAmount(entry.Price), + new("shop", "sell", entry.Name)); + + await _cmdHandler.TryRunCommand(guild, + channel, + new DoAsUserMessage( + msg, + user, + cmd + )); + + try + { + var pendingMsg = await msgTask; + await pendingMsg.EditAsync( + SmartEmbedText.FromEmbed(eb + .WithOkColor() + .WithTitle("Shop command executed") + .Build())); + } + catch + { + } + } + } + } + + private long GetProfitAmount(int price) + => (int)Math.Ceiling((1.0m - Config.BotCuts.ShopSaleCut) * price); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task ShopAdd(Command _, int price, [Leftover] string command) + { + if (price < 1) + return; + + + var entry = await _service.AddShopCommandAsync(ctx.Guild.Id, ctx.User.Id, price, command); + + await Response().Embed(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(GuildPerm.ManageRoles)] + public async Task ShopAdd(Role _, int price, [Leftover] IRole role) + { + if (price < 1) + return; + + var entry = new ShopEntry + { + Name = "-", + Price = price, + Type = ShopEntryType.Role, + AuthorId = ctx.User.Id, + RoleId = role.Id, + RoleName = role.Name + }; + await using (var uow = _db.GetDbContext()) + { + var entries = new IndexedCollection(uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries) + .ThenInclude(x => x.Items)) + .ShopEntries) + { + entry + }; + uow.GuildConfigsForId(ctx.Guild.Id, set => set).ShopEntries = entries; + uow.SaveChanges(); + } + + await Response().Embed(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopAdd(List _, int price, [Leftover] string name) + { + if (price < 1) + return; + + var entry = new ShopEntry + { + Name = name.TrimTo(100), + Price = price, + Type = ShopEntryType.List, + AuthorId = ctx.User.Id, + Items = new() + }; + await using (var uow = _db.GetDbContext()) + { + var entries = new IndexedCollection(uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries) + .ThenInclude(x => x.Items)) + .ShopEntries) + { + entry + }; + uow.GuildConfigsForId(ctx.Guild.Id, set => set).ShopEntries = entries; + uow.SaveChanges(); + } + + await Response().Embed(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopListAdd(int index, [Leftover] string itemText) + { + index -= 1; + if (index < 0) + return; + var item = new ShopEntryItem + { + Text = itemText + }; + ShopEntry entry; + var rightType = false; + var added = false; + await using (var uow = _db.GetDbContext()) + { + var entries = new IndexedCollection(uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries) + .ThenInclude(x => x.Items)) + .ShopEntries); + entry = entries.ElementAtOrDefault(index); + if (entry is not null && (rightType = entry.Type == ShopEntryType.List)) + { + if (entry.Items.Add(item)) + { + added = true; + uow.SaveChanges(); + } + } + } + + if (entry is null) + await Response().Error(strs.shop_item_not_found).SendAsync(); + else if (!rightType) + await Response().Error(strs.shop_item_wrong_type).SendAsync(); + else if (added == false) + await Response().Error(strs.shop_list_item_not_unique).SendAsync(); + else + await Response().Confirm(strs.shop_list_item_added).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopRemove(int index) + { + index -= 1; + if (index < 0) + return; + ShopEntry removed; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(ctx.Guild.Id, + set => set.Include(x => x.ShopEntries).ThenInclude(x => x.Items)); + + var entries = new IndexedCollection(config.ShopEntries); + removed = entries.ElementAtOrDefault(index); + if (removed is not null) + { + uow.RemoveRange(removed.Items); + uow.Remove(removed); + uow.SaveChanges(); + } + } + + if (removed is null) + await Response().Error(strs.shop_item_not_found).SendAsync(); + else + await Response().Embed(EntryToEmbed(removed).WithTitle(GetText(strs.shop_item_rm))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopChangePrice(int index, int price) + { + if (--index < 0 || price <= 0) + return; + + var succ = await _service.ChangeEntryPriceAsync(ctx.Guild.Id, index, price); + if (succ) + { + await ShopInternalAsync(index / 9); + await ctx.OkAsync(); + } + else + await ctx.ErrorAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopChangeName(int index, [Leftover] string newName) + { + if (--index < 0 || string.IsNullOrWhiteSpace(newName)) + return; + + var succ = await _service.ChangeEntryNameAsync(ctx.Guild.Id, index, newName); + if (succ) + { + await ShopInternalAsync(index / 9); + await ctx.OkAsync(); + } + else + await ctx.ErrorAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopSwap(int index1, int index2) + { + if (--index1 < 0 || --index2 < 0 || index1 == index2) + return; + + var succ = await _service.SwapEntriesAsync(ctx.Guild.Id, index1, index2); + if (succ) + { + await ShopInternalAsync(index1 / 9); + await ctx.OkAsync(); + } + else + await ctx.ErrorAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopMove(int fromIndex, int toIndex) + { + if (--fromIndex < 0 || --toIndex < 0 || fromIndex == toIndex) + return; + + var succ = await _service.MoveEntryAsync(ctx.Guild.Id, fromIndex, toIndex); + if (succ) + { + await ShopInternalAsync(toIndex / 9); + await ctx.OkAsync(); + } + else + await ctx.ErrorAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ShopReq(int itemIndex, [Leftover] IRole role = null) + { + if (--itemIndex < 0) + return; + + var succ = await _service.SetItemRoleRequirementAsync(ctx.Guild.Id, itemIndex, role?.Id); + if (!succ) + { + await Response().Error(strs.shop_item_not_found).SendAsync(); + return; + } + + if (role is null) + await Response().Confirm(strs.shop_item_role_no_req(itemIndex)).SendAsync(); + else + await Response().Confirm(strs.shop_item_role_req(itemIndex + 1, role)).SendAsync(); + } + + public EmbedBuilder EntryToEmbed(ShopEntry entry) + { + var embed = _sender.CreateEmbed().WithOkColor(); + + if (entry.Type == ShopEntryType.Role) + { + return embed + .AddField(GetText(strs.name), + GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name + ?? "MISSING_ROLE"))), + true) + .AddField(GetText(strs.price), N(entry.Price), true) + .AddField(GetText(strs.type), entry.Type.ToString(), true); + } + + if (entry.Type == ShopEntryType.List) + { + return embed.AddField(GetText(strs.name), entry.Name, true) + .AddField(GetText(strs.price), N(entry.Price), true) + .AddField(GetText(strs.type), GetText(strs.random_unique_item), true); + } + + else if (entry.Type == ShopEntryType.Command) + { + return embed + .AddField(GetText(strs.name), Format.Code(entry.Command), true) + .AddField(GetText(strs.price), N(entry.Price), true) + .AddField(GetText(strs.type), entry.Type.ToString(), true); + } + + //else if (entry.Type == ShopEntryType.Infinite_List) + // return embed.AddField(GetText(strs.name), GetText(strs.shop_role(Format.Bold(entry.RoleName)), true)) + // .AddField(GetText(strs.price), entry.Price.ToString(), true) + // .AddField(GetText(strs.type), entry.Type.ToString(), true); + return null; + } + + public string EntryToString(ShopEntry entry) + { + var prepend = string.Empty; + if (entry.RoleRequirement is not null) + prepend = Format.Italics(GetText(strs.shop_item_requires_role($"<@&{entry.RoleRequirement}>"))) + + Environment.NewLine; + + if (entry.Type == ShopEntryType.Role) + return prepend + + GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE"))); + if (entry.Type == ShopEntryType.List) + return prepend + GetText(strs.unique_items_left(entry.Items.Count)) + "\n" + entry.Name; + + if (entry.Type == ShopEntryType.Command) + return prepend + Format.Code(entry.Command); + return prepend; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Shop/ShopService.cs b/src/EllieBot/Modules/Gambling/Shop/ShopService.cs new file mode 100644 index 0000000..dfe944a --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Shop/ShopService.cs @@ -0,0 +1,127 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling.Services; + +public class ShopService : IShopService, IEService +{ + private readonly DbService _db; + + public ShopService(DbService db) + => _db = db; + + private IndexedCollection GetEntriesInternal(DbContext uow, ulong guildId) + => uow.GuildConfigsForId(guildId, + set => set.Include(x => x.ShopEntries) + .ThenInclude(x => x.Items)) + .ShopEntries.ToIndexed(); + + public async Task ChangeEntryPriceAsync(ulong guildId, int index, int newPrice) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(newPrice); + + await using var uow = _db.GetDbContext(); + var entries = GetEntriesInternal(uow, guildId); + + if (index >= entries.Count) + return false; + + entries[index].Price = newPrice; + await uow.SaveChangesAsync(); + return true; + } + + public async Task ChangeEntryNameAsync(ulong guildId, int index, string newName) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + + if (string.IsNullOrWhiteSpace(newName)) + throw new ArgumentNullException(nameof(newName)); + + await using var uow = _db.GetDbContext(); + var entries = GetEntriesInternal(uow, guildId); + + if (index >= entries.Count) + return false; + + entries[index].Name = newName.TrimTo(100); + await uow.SaveChangesAsync(); + return true; + } + + public async Task SwapEntriesAsync(ulong guildId, int index1, int index2) + { + ArgumentOutOfRangeException.ThrowIfNegative(index1); + ArgumentOutOfRangeException.ThrowIfNegative(index2); + + await using var uow = _db.GetDbContext(); + var entries = GetEntriesInternal(uow, guildId); + + if (index1 >= entries.Count || index2 >= entries.Count || index1 == index2) + return false; + + entries[index1].Index = index2; + entries[index2].Index = index1; + + await uow.SaveChangesAsync(); + return true; + } + + public async Task MoveEntryAsync(ulong guildId, int fromIndex, int toIndex) + { + ArgumentOutOfRangeException.ThrowIfNegative(fromIndex); + ArgumentOutOfRangeException.ThrowIfNegative(toIndex); + + await using var uow = _db.GetDbContext(); + var entries = GetEntriesInternal(uow, guildId); + + if (fromIndex >= entries.Count || toIndex >= entries.Count || fromIndex == toIndex) + return false; + + var entry = entries[fromIndex]; + entries.RemoveAt(fromIndex); + entries.Insert(toIndex, entry); + + await uow.SaveChangesAsync(); + return true; + } + + public async Task SetItemRoleRequirementAsync(ulong guildId, int index, ulong? roleId) + { + await using var uow = _db.GetDbContext(); + var entries = GetEntriesInternal(uow, guildId); + + if (index >= entries.Count) + return false; + + var entry = entries[index]; + + entry.RoleRequirement = roleId; + + await uow.SaveChangesAsync(); + return true; + } + + public async Task AddShopCommandAsync(ulong guildId, ulong userId, int price, string command) + { + await using var uow = _db.GetDbContext(); + + var entries = GetEntriesInternal(uow, guildId); + var entry = new ShopEntry() + { + AuthorId = userId, + Command = command, + Type = ShopEntryType.Command, + Price = price, + }; + entries.Add(entry); + uow.GuildConfigsForId(guildId, set => set).ShopEntries = entries; + + await uow.SaveChangesAsync(); + + return entry; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs b/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs new file mode 100644 index 0000000..238e97e --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs @@ -0,0 +1,230 @@ +#nullable disable warnings +using EllieBot.Db.Models; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Services; +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using EllieBot.Modules.Gambling; +using EllieBot.Common.TypeReaders; +using Color = SixLabors.ImageSharp.Color; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Gambling; + +public enum GamblingError +{ + InsufficientFunds, +} + +public partial class Gambling +{ + [Group] + public partial class SlotCommands : GamblingSubmodule + { + private static decimal totalBet; + private static decimal totalPaidOut; + + private readonly IImageCache _images; + private readonly FontProvider _fonts; + private readonly DbService _db; + private object _slotStatsLock = new(); + + public SlotCommands( + IImageCache images, + FontProvider fonts, + DbService db, + GamblingConfigService gamb) + : base(gamb) + { + _images = images; + _fonts = fonts; + _db = db; + } + + public Task Test() + => Task.CompletedTask; + + [Cmd] + public async Task Slot([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) + { + if (!await CheckBetMandatory(amount)) + return; + + // var slotInteraction = CreateSlotInteractionIntenal(amount); + + await ctx.Channel.TriggerTypingAsync(); + + if (await InternalSlotAsync(amount) is not SlotResult result) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + var text = GetSlotMessageTextInternal(result); + + using var image = await GenerateSlotImageAsync(amount, result); + await using var imgStream = await image.ToStreamAsync(); + + + var eb = _sender.CreateEmbed() + .WithAuthor(ctx.User) + .WithDescription(Format.Bold(text)) + .WithImageUrl($"attachment://result.png") + .WithOkColor(); + + var bb = new ButtonBuilder(emote: Emoji.Parse("🔁"), customId: "slot:again", label: "Pull Again"); + var inter = _inter.Create(ctx.User.Id, bb, smc => + { + smc.DeferAsync(); + return Slot(amount); + }); + + var msg = await ctx.Channel.SendFileAsync(imgStream, + "result.png", + embed: eb.Build(), + components: inter.CreateComponent() + ); + await inter.RunAsync(msg); + } + + // private SlotInteraction CreateSlotInteractionIntenal(long amount) + // { + // return new SlotInteraction((DiscordSocketClient)ctx.Client, + // ctx.User.Id, + // async (smc) => + // { + // try + // { + // if (await InternalSlotAsync(amount) is not SlotResult result) + // { + // await smc.RespondErrorAsync(_eb, GetText(strs.not_enough(CurrencySign)), true); + // return; + // } + // + // var msg = GetSlotMessageInternal(result); + // + // using var image = await GenerateSlotImageAsync(amount, result); + // await using var imgStream = await image.ToStreamAsync(); + // + // var guid = Guid.NewGuid(); + // var imgName = $"result_{guid}.png"; + // + // var slotInteraction = CreateSlotInteractionIntenal(amount).GetInteraction(); + // + // await smc.Message.ModifyAsync(m => + // { + // m.Content = msg; + // m.Attachments = new[] + // { + // new FileAttachment(imgStream, imgName) + // }; + // m.Components = slotInteraction.CreateComponent(); + // }); + // + // _ = slotInteraction.RunAsync(smc.Message); + // } + // catch (Exception ex) + // { + // Log.Error(ex, "Error pulling slot again"); + // } + // // finally + // // { + // // await Task.Delay(1000); + // // _runningUsers.TryRemove(ctx.User.Id); + // // } + // }); + // } + + private string GetSlotMessageTextInternal(SlotResult result) + { + var multi = result.Multiplier.ToString("0.##"); + var msg = result.WinType switch + { + SlotWinType.SingleJoker => GetText(strs.slot_single(CurrencySign, multi)), + SlotWinType.DoubleJoker => GetText(strs.slot_two(CurrencySign, multi)), + SlotWinType.TrippleNormal => GetText(strs.slot_three(multi)), + SlotWinType.TrippleJoker => GetText(strs.slot_jackpot(multi)), + _ => GetText(strs.better_luck), + }; + return msg; + } + + private async Task InternalSlotAsync(long amount) + { + var maybeResult = await _service.SlotAsync(ctx.User.Id, amount); + + if (!maybeResult.TryPickT0(out var result, out var error)) + { + return null; + } + + lock (_slotStatsLock) + { + totalBet += amount; + totalPaidOut += result.Won; + } + + return result; + } + + private async Task> GenerateSlotImageAsync(long amount, SlotResult result) + { + long ownedAmount; + await using (var uow = _db.GetDbContext()) + { + ownedAmount = uow.Set().FirstOrDefault(x => x.UserId == ctx.User.Id)?.CurrencyAmount + ?? 0; + } + + var slotBg = await _images.GetSlotBgAsync(); + var bgImage = Image.Load(slotBg, out _); + var numbers = new int[3]; + result.Rolls.CopyTo(numbers, 0); + + Color fontColor = Config.Slots.CurrencyFontColor; + + bgImage.Mutate(x => x.DrawText(new TextOptions(_fonts.DottyFont.CreateFont(65)) + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + WrappingLength = 140, + Origin = new(298, 100) + }, + ((long)result.Won).ToString(), + fontColor)); + + var bottomFont = _fonts.DottyFont.CreateFont(50); + + bgImage.Mutate(x => x.DrawText(new TextOptions(bottomFont) + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + WrappingLength = 135, + Origin = new(196, 480) + }, + amount.ToString(), + fontColor)); + + bgImage.Mutate(x => x.DrawText(new(bottomFont) + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Origin = new(393, 480) + }, + ownedAmount.ToString(), + fontColor)); + //sw.PrintLap("drew red text"); + + for (var i = 0; i < 3; i++) + { + using var img = Image.Load(await _images.GetSlotEmojiAsync(numbers[i])); + bgImage.Mutate(x => x.DrawImage(img, new Point(148 + (105 * i), 217), 1f)); + } + + return bgImage; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/VoteRewardService.cs b/src/EllieBot/Modules/Gambling/VoteRewardService.cs new file mode 100644 index 0000000..62d861b --- /dev/null +++ b/src/EllieBot/Modules/Gambling/VoteRewardService.cs @@ -0,0 +1,106 @@ +#nullable disable +using EllieBot.Common.ModuleBehaviors; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Gambling.Services; + +public class VoteModel +{ + [JsonPropertyName("userId")] + public ulong UserId { get; set; } +} + +public class VoteRewardService : IEService, IReadyExecutor +{ + private readonly DiscordSocketClient _client; + private readonly IBotCredentials _creds; + private readonly ICurrencyService _currencyService; + private readonly GamblingConfigService _gamb; + + public VoteRewardService( + DiscordSocketClient client, + IBotCredentials creds, + ICurrencyService currencyService, + GamblingConfigService gamb) + { + _client = client; + _creds = creds; + _currencyService = currencyService; + _gamb = gamb; + } + + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + using var http = new HttpClient(new HttpClientHandler + { + AllowAutoRedirect = false, + ServerCertificateCustomValidationCallback = delegate { return true; } + }); + + while (true) + { + await Task.Delay(30000); + + var topggKey = _creds.Votes?.TopggKey; + var topggServiceUrl = _creds.Votes?.TopggServiceUrl; + + try + { + if (!string.IsNullOrWhiteSpace(topggKey) && !string.IsNullOrWhiteSpace(topggServiceUrl)) + { + http.DefaultRequestHeaders.Authorization = new(topggKey); + var uri = new Uri(new(topggServiceUrl), "topgg/new"); + var res = await http.GetStringAsync(uri); + var data = JsonSerializer.Deserialize>(res); + + if (data is { Count: > 0 }) + { + var ids = data.Select(x => x.UserId).ToList(); + + await _currencyService.AddBulkAsync(ids, + _gamb.Data.VoteReward, + new("vote", "top.gg", "top.gg vote reward")); + + Log.Information("Rewarding {Count} top.gg voters", ids.Count()); + } + } + } + catch (Exception ex) + { + Log.Error(ex, "Critical error loading top.gg vote rewards"); + } + + var discordsKey = _creds.Votes?.DiscordsKey; + var discordsServiceUrl = _creds.Votes?.DiscordsServiceUrl; + + try + { + if (!string.IsNullOrWhiteSpace(discordsKey) && !string.IsNullOrWhiteSpace(discordsServiceUrl)) + { + http.DefaultRequestHeaders.Authorization = new(discordsKey); + var res = await http.GetStringAsync(new Uri(new(discordsServiceUrl), "discords/new")); + var data = JsonSerializer.Deserialize>(res); + + if (data is { Count: > 0 }) + { + var ids = data.Select(x => x.UserId).ToList(); + + await _currencyService.AddBulkAsync(ids, + _gamb.Data.VoteReward, + new("vote", "discords", "discords.com vote reward")); + + Log.Information("Rewarding {Count} discords.com voters", ids.Count()); + } + } + } + catch (Exception ex) + { + Log.Error(ex, "Critical error loading discords.com vote rewards"); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs b/src/EllieBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs new file mode 100644 index 0000000..5f7db11 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/WaifuClaimCommands.cs @@ -0,0 +1,393 @@ +#nullable disable +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Waifu; +using EllieBot.Modules.Gambling.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling; + +public partial class Gambling +{ + [Group] + public partial class WaifuClaimCommands : GamblingSubmodule + { + public WaifuClaimCommands(GamblingConfigService gamblingConfService) + : base(gamblingConfService) + { + } + + [Cmd] + public async Task WaifuReset() + { + var price = _service.GetResetPrice(ctx.User); + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.waifu_reset_confirm)) + .WithDescription(GetText(strs.waifu_reset_price(Format.Bold(N(price))))); + + if (!await PromptUserConfirmAsync(embed)) + return; + + if (await _service.TryReset(ctx.User)) + { + await Response().Confirm(strs.waifu_reset).SendAsync(); + return; + } + + await Response().Error(strs.waifu_reset_fail).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task WaifuClaim(long amount, [Leftover] IUser target) + { + if (amount < Config.Waifu.MinPrice) + { + await Response().Error(strs.waifu_isnt_cheap(Config.Waifu.MinPrice + CurrencySign)).SendAsync(); + return; + } + + if (target.Id == ctx.User.Id) + { + await Response().Error(strs.waifu_not_yourself).SendAsync(); + return; + } + + var (w, isAffinity, result) = await _service.ClaimWaifuAsync(ctx.User, target, amount); + + if (result == WaifuClaimResult.InsufficientAmount) + { + await Response() + .Error( + strs.waifu_not_enough(N((long)Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))))) + .SendAsync(); + return; + } + + if (result == WaifuClaimResult.NotEnoughFunds) + { + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + return; + } + + var msg = GetText(strs.waifu_claimed(Format.Bold(target.ToString()), N(amount))); + if (w.Affinity?.UserId == ctx.User.Id) + msg += "\n" + GetText(strs.waifu_fulfilled(target, N(w.Price))); + else + msg = " " + msg; + await Response().Confirm(ctx.User.Mention + msg).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public async Task WaifuTransfer(ulong waifuId, IUser newOwner) + { + if (!await _service.WaifuTransfer(ctx.User, waifuId, newOwner)) + { + await Response().Error(strs.waifu_transfer_fail).SendAsync(); + return; + } + + await Response() + .Confirm(strs.waifu_transfer_success(Format.Bold(waifuId.ToString()), + Format.Bold(ctx.User.ToString()), + Format.Bold(newOwner.ToString()))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task WaifuTransfer(IUser waifu, IUser newOwner) + { + if (!await _service.WaifuTransfer(ctx.User, waifu.Id, newOwner)) + { + await Response().Error(strs.waifu_transfer_fail).SendAsync(); + return; + } + + await Response() + .Confirm(strs.waifu_transfer_success(Format.Bold(waifu.ToString()), + Format.Bold(ctx.User.ToString()), + Format.Bold(newOwner.ToString()))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(-1)] + public Task Divorce([Leftover] string target) + { + var waifuUserId = _service.GetWaifuUserId(ctx.User.Id, target); + if (waifuUserId == default) + return Response().Error(strs.waifu_not_yours).SendAsync(); + + return Divorce(waifuUserId); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public Task Divorce([Leftover] IGuildUser target) + => Divorce(target.Id); + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task Divorce([Leftover] ulong targetId) + { + if (targetId == ctx.User.Id) + return; + + var (w, result, amount, remaining) = await _service.DivorceWaifuAsync(ctx.User, targetId); + + if (result == DivorceResult.SucessWithPenalty) + { + await Response() + .Confirm(strs.waifu_divorced_like(Format.Bold(w.Waifu.ToString()), + N(amount))) + .SendAsync(); + } + else if (result == DivorceResult.Success) + await Response().Confirm(strs.waifu_divorced_notlike(N(amount))).SendAsync(); + else if (result == DivorceResult.NotYourWife) + await Response().Error(strs.waifu_not_yours).SendAsync(); + else + { + await Response() + .Error(strs.waifu_recent_divorce( + Format.Bold(((int)remaining?.TotalHours).ToString()), + Format.Bold(remaining?.Minutes.ToString()))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Affinity([Leftover] IGuildUser user = null) + { + if (user?.Id == ctx.User.Id) + { + await Response().Error(strs.waifu_egomaniac).SendAsync(); + return; + } + + var (oldAff, sucess, remaining) = await _service.ChangeAffinityAsync(ctx.User, user); + if (!sucess) + { + if (remaining is not null) + { + await Response() + .Error(strs.waifu_affinity_cooldown( + Format.Bold(((int)remaining?.TotalHours).ToString()), + Format.Bold(remaining?.Minutes.ToString()))) + .SendAsync(); + } + else + await Response().Error(strs.waifu_affinity_already).SendAsync(); + + return; + } + + if (user is null) + await Response().Confirm(strs.waifu_affinity_reset).SendAsync(); + else if (oldAff is null) + await Response().Confirm(strs.waifu_affinity_set(Format.Bold(user.ToString()))).SendAsync(); + else + { + await Response() + .Confirm(strs.waifu_affinity_changed(Format.Bold(oldAff.ToString()), + Format.Bold(user.ToString()))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task WaifuLb(int page = 1) + { + page--; + + if (page < 0) + return; + + if (page > 100) + page = 100; + + var waifus = _service.GetTopWaifusAtPage(page).ToList(); + + if (waifus.Count == 0) + { + await Response().Confirm(strs.waifus_none).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.waifus_top_waifus)).WithOkColor(); + + var i = 0; + foreach (var w in waifus) + { + var j = i++; + embed.AddField("#" + ((page * 9) + j + 1) + " - " + N(w.Price), GetLbString(w)); + } + + await Response().Embed(embed).SendAsync(); + } + + private string GetLbString(WaifuLbResult w) + { + var claimer = "no one"; + var status = string.Empty; + + var waifuUsername = w.Username.TrimTo(20); + var claimerUsername = w.Claimer?.TrimTo(20); + + if (w.Claimer is not null) + claimer = $"{claimerUsername}#{w.ClaimerDiscrim}"; + if (w.Affinity is null) + status = $"... but {waifuUsername}'s heart is empty"; + else if (w.Affinity + w.AffinityDiscrim == w.Claimer + w.ClaimerDiscrim) + status = $"... and {waifuUsername} likes {claimerUsername} too <3"; + else + status = $"... but {waifuUsername}'s heart belongs to {w.Affinity.TrimTo(20)}#{w.AffinityDiscrim}"; + return $"**{waifuUsername}#{w.Discrim}** - claimed by **{claimer}**\n\t{status}"; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public Task WaifuInfo([Leftover] IUser target = null) + { + if (target is null) + target = ctx.User; + + return InternalWaifuInfo(target.Id, target.ToString()); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public Task WaifuInfo(ulong targetId) + => InternalWaifuInfo(targetId); + + private async Task InternalWaifuInfo(ulong targetId, string name = null) + { + var wi = await _service.GetFullWaifuInfoAsync(targetId); + var affInfo = _service.GetAffinityTitle(wi.AffinityCount); + + var waifuItems = _service.GetWaifuItems().ToDictionary(x => x.ItemEmoji, x => x); + + var nobody = GetText(strs.nobody); + var itemList = await _service.GetItems(wi.WaifuId); + var itemsStr = !itemList.Any() + ? "-" + : string.Join("\n", + itemList.Where(x => waifuItems.TryGetValue(x.ItemEmoji, out _)) + .OrderByDescending(x => waifuItems[x.ItemEmoji].Price) + .GroupBy(x => x.ItemEmoji) + .Take(60) + .Select(x => $"{x.Key} x{x.Count(),-3}") + .Chunk(2) + .Select(x => string.Join(" ", x))); + + var claimsNames = (await _service.GetClaimNames(wi.WaifuId)); + var claimsStr = claimsNames + .Shuffle() + .Take(30) + .Join('\n'); + + var fansList = await _service.GetFansNames(wi.WaifuId); + var fansStr = fansList + .Shuffle() + .Take(30) + .Select((x) => claimsNames.Contains(x) ? $"{x} 💞" : x) + .Join('\n'); + + if (string.IsNullOrWhiteSpace(fansStr)) + fansStr = "-"; + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.waifu) + + " " + + (wi.FullName ?? name ?? targetId.ToString()) + + " - \"the " + + _service.GetClaimTitle(wi.ClaimCount) + + "\"") + .AddField(GetText(strs.price), N(wi.Price), true) + .AddField(GetText(strs.claimed_by), wi.ClaimerName ?? nobody, true) + .AddField(GetText(strs.likes), wi.AffinityName ?? nobody, true) + .AddField(GetText(strs.changes_of_heart), $"{wi.AffinityCount} - \"the {affInfo}\"", true) + .AddField(GetText(strs.divorces), wi.DivorceCount.ToString(), true) + .AddField("\u200B", "\u200B", true) + .AddField(GetText(strs.fans(fansList.Count)), fansStr, true) + .AddField($"Waifus ({wi.ClaimCount})", + wi.ClaimCount == 0 ? nobody : claimsStr, + true) + .AddField(GetText(strs.gifts), itemsStr, true); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task WaifuGift(int page = 1) + { + if (--page < 0 || page > (Config.Waifu.Items.Count - 1) / 9) + return; + + var waifuItems = _service.GetWaifuItems(); + await Response() + .Paginated() + .Items(waifuItems.OrderBy(x => x.Negative) + .ThenBy(x => x.Price) + .ToList()) + .PageSize(9) + .CurrentPage(page) + .Page((items, _) => + { + var embed = _sender.CreateEmbed().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor(); + + items + .ToList() + .ForEach(x => embed.AddField( + $"{(!x.Negative ? string.Empty : "\\💔")} {x.ItemEmoji} {x.Name}", + Format.Bold(N(x.Price)), + true)); + + return embed; + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public async Task WaifuGift(string itemName, [Leftover] IUser waifu) + { + if (waifu.Id == ctx.User.Id) + return; + + var allItems = _service.GetWaifuItems(); + var item = allItems.FirstOrDefault(x => x.Name.ToLowerInvariant() == itemName.ToLowerInvariant()); + if (item is null) + { + await Response().Error(strs.waifu_gift_not_exist).SendAsync(); + return; + } + + var sucess = await _service.GiftWaifuAsync(ctx.User, waifu, item); + + if (sucess) + { + await Response() + .Confirm(strs.waifu_gift(Format.Bold(item + " " + item.ItemEmoji), + Format.Bold(waifu.ToString()))) + .SendAsync(); + } + else + await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/WaifuService.cs b/src/EllieBot/Modules/Gambling/Waifus/WaifuService.cs new file mode 100644 index 0000000..dded8a9 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/WaifuService.cs @@ -0,0 +1,582 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Gambling.Common; +using EllieBot.Modules.Gambling.Common.Waifu; + +namespace EllieBot.Modules.Gambling.Services; + +public class WaifuService : IEService, IReadyExecutor +{ + private readonly DbService _db; + private readonly ICurrencyService _cs; + private readonly IBotCache _cache; + private readonly GamblingConfigService _gss; + private readonly IBotCredentials _creds; + private readonly DiscordSocketClient _client; + + public WaifuService( + DbService db, + ICurrencyService cs, + IBotCache cache, + GamblingConfigService gss, + IBotCredentials creds, + DiscordSocketClient client) + { + _db = db; + _cs = cs; + _cache = cache; + _gss = gss; + _creds = creds; + _client = client; + } + + public async Task WaifuTransfer(IUser owner, ulong waifuId, IUser newOwner) + { + if (owner.Id == newOwner.Id || waifuId == newOwner.Id) + return false; + + var settings = _gss.Data; + + await using var uow = _db.GetDbContext(); + var waifu = uow.Set().ByWaifuUserId(waifuId); + var ownerUser = uow.GetOrCreateUser(owner); + + // owner has to be the owner of the waifu + if (waifu is null || waifu.ClaimerId != ownerUser.Id) + return false; + + // if waifu likes the person, gotta pay the penalty + if (waifu.AffinityId == ownerUser.Id) + { + if (!await _cs.RemoveAsync(owner.Id, (long)(waifu.Price * 0.6), new("waifu", "affinity-penalty"))) + // unable to pay 60% penalty + return false; + + waifu.Price = (long)(waifu.Price * 0.7); // half of 60% = 30% price reduction + if (waifu.Price < settings.Waifu.MinPrice) + waifu.Price = settings.Waifu.MinPrice; + } + else // if not, pay 10% fee + { + if (!await _cs.RemoveAsync(owner.Id, waifu.Price / 10, new("waifu", "transfer"))) + return false; + + waifu.Price = (long)(waifu.Price * 0.95); // half of 10% = 5% price reduction + if (waifu.Price < settings.Waifu.MinPrice) + waifu.Price = settings.Waifu.MinPrice; + } + + //new claimerId is the id of the new owner + var newOwnerUser = uow.GetOrCreateUser(newOwner); + waifu.ClaimerId = newOwnerUser.Id; + + await uow.SaveChangesAsync(); + + return true; + } + + public long GetResetPrice(IUser user) + { + var settings = _gss.Data; + using var uow = _db.GetDbContext(); + var waifu = uow.Set().ByWaifuUserId(user.Id); + + if (waifu is null) + return settings.Waifu.MinPrice; + + var divorces = uow.Set().Count(x + => x.Old != null && x.Old.UserId == user.Id && x.UpdateType == WaifuUpdateType.Claimed && x.New == null); + var affs = uow.Set().AsQueryable() + .Where(w => w.User.UserId == user.Id + && w.UpdateType == WaifuUpdateType.AffinityChanged + && w.New != null) + .ToList() + .GroupBy(x => x.New) + .Count(); + + return (long)Math.Ceiling(waifu.Price * 1.25f) + + ((divorces + affs + 2) * settings.Waifu.Multipliers.WaifuReset); + } + + public async Task TryReset(IUser user) + { + await using var uow = _db.GetDbContext(); + var price = GetResetPrice(user); + if (!await _cs.RemoveAsync(user.Id, price, new("waifu", "reset"))) + return false; + + var affs = uow.Set().AsQueryable() + .Where(w => w.User.UserId == user.Id + && w.UpdateType == WaifuUpdateType.AffinityChanged + && w.New != null); + + var divorces = uow.Set().AsQueryable() + .Where(x => x.Old != null + && x.Old.UserId == user.Id + && x.UpdateType == WaifuUpdateType.Claimed + && x.New == null); + + //reset changes of heart to 0 + uow.Set().RemoveRange(affs); + //reset divorces to 0 + uow.Set().RemoveRange(divorces); + var waifu = uow.Set().ByWaifuUserId(user.Id); + //reset price, remove items + //remove owner, remove affinity + waifu.Price = 50; + waifu.Items.Clear(); + waifu.ClaimerId = null; + waifu.AffinityId = null; + + //wives stay though + + await uow.SaveChangesAsync(); + + return true; + } + + public async Task<(WaifuInfo, bool, WaifuClaimResult)> ClaimWaifuAsync(IUser user, IUser target, long amount) + { + var settings = _gss.Data; + WaifuClaimResult result; + WaifuInfo w; + bool isAffinity; + await using (var uow = _db.GetDbContext()) + { + w = uow.Set().ByWaifuUserId(target.Id); + isAffinity = w?.Affinity?.UserId == user.Id; + if (w is null) + { + var claimer = uow.GetOrCreateUser(user); + var waifu = uow.GetOrCreateUser(target); + if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim"))) + result = WaifuClaimResult.NotEnoughFunds; + else + { + uow.Set().Add(w = new() + { + Waifu = waifu, + Claimer = claimer, + Affinity = null, + Price = amount + }); + uow.Set().Add(new() + { + User = waifu, + Old = null, + New = claimer, + UpdateType = WaifuUpdateType.Claimed + }); + result = WaifuClaimResult.Success; + } + } + else if (isAffinity && amount > w.Price * settings.Waifu.Multipliers.CrushClaim) + { + if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim"))) + result = WaifuClaimResult.NotEnoughFunds; + else + { + var oldClaimer = w.Claimer; + w.Claimer = uow.GetOrCreateUser(user); + w.Price = amount + (amount / 4); + result = WaifuClaimResult.Success; + + uow.Set().Add(new() + { + User = w.Waifu, + Old = oldClaimer, + New = w.Claimer, + UpdateType = WaifuUpdateType.Claimed + }); + } + } + else if (amount >= w.Price * settings.Waifu.Multipliers.NormalClaim) // if no affinity + { + if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim"))) + result = WaifuClaimResult.NotEnoughFunds; + else + { + var oldClaimer = w.Claimer; + w.Claimer = uow.GetOrCreateUser(user); + w.Price = amount; + result = WaifuClaimResult.Success; + + uow.Set().Add(new() + { + User = w.Waifu, + Old = oldClaimer, + New = w.Claimer, + UpdateType = WaifuUpdateType.Claimed + }); + } + } + else + result = WaifuClaimResult.InsufficientAmount; + + + await uow.SaveChangesAsync(); + } + + return (w, isAffinity, result); + } + + public async Task<(DiscordUser, bool, TimeSpan?)> ChangeAffinityAsync(IUser user, IGuildUser target) + { + DiscordUser oldAff = null; + var success = false; + TimeSpan? remaining = null; + await using (var uow = _db.GetDbContext()) + { + var w = uow.Set().ByWaifuUserId(user.Id); + var newAff = target is null ? null : uow.GetOrCreateUser(target); + if (w?.Affinity?.UserId == target?.Id) + { + return (null, false, null); + } + + remaining = await _cache.GetRatelimitAsync(GetAffinityKey(user.Id), + 30.Minutes()); + + if (remaining is not null) + { + } + else if (w is null) + { + var thisUser = uow.GetOrCreateUser(user); + uow.Set().Add(new() + { + Affinity = newAff, + Waifu = thisUser, + Price = 1, + Claimer = null + }); + success = true; + + uow.Set().Add(new() + { + User = thisUser, + Old = null, + New = newAff, + UpdateType = WaifuUpdateType.AffinityChanged + }); + } + else + { + if (w.Affinity is not null) + oldAff = w.Affinity; + w.Affinity = newAff; + success = true; + + uow.Set().Add(new() + { + User = w.Waifu, + Old = oldAff, + New = newAff, + UpdateType = WaifuUpdateType.AffinityChanged + }); + } + + await uow.SaveChangesAsync(); + } + + return (oldAff, success, remaining); + } + + public IEnumerable GetTopWaifusAtPage(int page, int perPage = 9) + { + using var uow = _db.GetDbContext(); + return uow.Set().GetTop(perPage, page * perPage); + } + + public ulong GetWaifuUserId(ulong ownerId, string name) + { + using var uow = _db.GetDbContext(); + return uow.Set().GetWaifuUserId(ownerId, name); + } + + private static TypedKey GetDivorceKey(ulong userId) + => new($"waifu:divorce_cd:{userId}"); + + private static TypedKey GetAffinityKey(ulong userId) + => new($"waifu:affinity:{userId}"); + + public async Task<(WaifuInfo, DivorceResult, long, TimeSpan?)> DivorceWaifuAsync(IUser user, ulong targetId) + { + DivorceResult result; + TimeSpan? remaining = null; + long amount = 0; + WaifuInfo w; + await using (var uow = _db.GetDbContext()) + { + w = uow.Set().ByWaifuUserId(targetId); + if (w?.Claimer is null || w.Claimer.UserId != user.Id) + result = DivorceResult.NotYourWife; + else + { + remaining = await _cache.GetRatelimitAsync(GetDivorceKey(user.Id), 6.Hours()); + if (remaining is TimeSpan rem) + { + result = DivorceResult.Cooldown; + return (w, result, amount, rem); + } + + amount = w.Price / 2; + + if (w.Affinity?.UserId == user.Id) + { + await _cs.AddAsync(w.Waifu.UserId, amount, new("waifu", "compensation")); + w.Price = (long)Math.Floor(w.Price * _gss.Data.Waifu.Multipliers.DivorceNewValue); + result = DivorceResult.SucessWithPenalty; + } + else + { + await _cs.AddAsync(user.Id, amount, new("waifu", "refund")); + + result = DivorceResult.Success; + } + + var oldClaimer = w.Claimer; + w.Claimer = null; + + uow.Set().Add(new() + { + User = w.Waifu, + Old = oldClaimer, + New = null, + UpdateType = WaifuUpdateType.Claimed + }); + } + + await uow.SaveChangesAsync(); + } + + return (w, result, amount, remaining); + } + + public async Task GiftWaifuAsync(IUser from, IUser giftedWaifu, WaifuItemModel itemObj) + { + if (!await _cs.RemoveAsync(from, itemObj.Price, new("waifu", "item"))) + return false; + + await using var uow = _db.GetDbContext(); + var w = uow.Set().ByWaifuUserId(giftedWaifu.Id, set => set.Include(x => x.Items).Include(x => x.Claimer)); + if (w is null) + { + uow.Set().Add(w = new() + { + Affinity = null, + Claimer = null, + Price = 1, + Waifu = uow.GetOrCreateUser(giftedWaifu) + }); + } + + if (!itemObj.Negative) + { + w.Items.Add(new() + { + Name = itemObj.Name.ToLowerInvariant(), + ItemEmoji = itemObj.ItemEmoji + }); + + if (w.Claimer?.UserId == from.Id) + w.Price += (long)(itemObj.Price * _gss.Data.Waifu.Multipliers.GiftEffect); + else + w.Price += itemObj.Price / 2; + } + else + { + w.Price -= (long)(itemObj.Price * _gss.Data.Waifu.Multipliers.NegativeGiftEffect); + if (w.Price < 1) + w.Price = 1; + } + + await uow.SaveChangesAsync(); + + return true; + } + + public async Task GetFullWaifuInfoAsync(ulong targetId) + { + await using var uow = _db.GetDbContext(); + var wi = await uow.GetWaifuInfoAsync(targetId); + if (wi is null) + { + wi = new() + { + AffinityCount = 0, + AffinityName = null, + ClaimCount = 0, + ClaimerName = null, + DivorceCount = 0, + FullName = null, + Price = 1 + }; + } + + return wi; + } + + public string GetClaimTitle(int count) + { + ClaimTitle title; + if (count == 0) + title = ClaimTitle.Lonely; + else if (count == 1) + title = ClaimTitle.Devoted; + else if (count < 3) + title = ClaimTitle.Rookie; + else if (count < 6) + title = ClaimTitle.Schemer; + else if (count < 10) + title = ClaimTitle.Dilettante; + else if (count < 17) + title = ClaimTitle.Intermediate; + else if (count < 25) + title = ClaimTitle.Seducer; + else if (count < 35) + title = ClaimTitle.Expert; + else if (count < 50) + title = ClaimTitle.Veteran; + else if (count < 75) + title = ClaimTitle.Incubis; + else if (count < 100) + title = ClaimTitle.Harem_King; + else + title = ClaimTitle.Harem_God; + + return title.ToString().Replace('_', ' '); + } + + public string GetAffinityTitle(int count) + { + AffinityTitle title; + if (count < 1) + title = AffinityTitle.Pure; + else if (count < 2) + title = AffinityTitle.Faithful; + else if (count < 4) + title = AffinityTitle.Playful; + else if (count < 8) + title = AffinityTitle.Cheater; + else if (count < 11) + title = AffinityTitle.Tainted; + else if (count < 15) + title = AffinityTitle.Corrupted; + else if (count < 20) + title = AffinityTitle.Lewd; + else if (count < 25) + title = AffinityTitle.Sloot; + else if (count < 35) + title = AffinityTitle.Depraved; + else + title = AffinityTitle.Harlot; + + return title.ToString().Replace('_', ' '); + } + + public IReadOnlyList GetWaifuItems() + { + var conf = _gss.Data; + return conf.Waifu.Items.Select(x + => new WaifuItemModel(x.ItemEmoji, + (long)(x.Price * conf.Waifu.Multipliers.AllGiftPrices), + x.Name, + x.Negative)) + .ToList(); + } + + private static readonly TypedKey _waifuDecayKey = $"waifu:last_decay"; + public async Task OnReadyAsync() + { + // only decay waifu values from shard 0 + if (_client.ShardId != 0) + return; + + while (true) + { + try + { + var multi = _gss.Data.Waifu.Decay.Percent / 100f; + var minPrice = _gss.Data.Waifu.Decay.MinPrice; + var decayInterval = _gss.Data.Waifu.Decay.HourInterval; + + if (multi is < 0f or > 1f || decayInterval < 0) + continue; + + var now = DateTime.UtcNow; + var nowB = now.ToBinary(); + + var result = await _cache.GetAsync(_waifuDecayKey); + + if (result.TryGetValue(out var val)) + { + var lastDecay = DateTime.FromBinary(val); + var toWait = decayInterval.Hours() - (DateTime.UtcNow - lastDecay); + + if (toWait > 0.Hours()) + continue; + } + + await _cache.AddAsync(_waifuDecayKey, nowB); + + await using var uow = _db.GetDbContext(); + + await uow.GetTable() + .Where(x => x.Price > minPrice && x.ClaimerId == null) + .UpdateAsync(old => new() + { + Price = (long)(old.Price * multi) + }); + + } + catch (Exception ex) + { + Log.Error(ex, "Unexpected error occured in waifu decay loop: {ErrorMessage}", ex.Message); + } + finally + { + await Task.Delay(1.Hours()); + } + } + } + + public async Task> GetClaimNames(int waifuId) + { + await using var ctx = _db.GetDbContext(); + return await ctx.GetTable() + .Where(x => ctx.GetTable() + .Where(wi => wi.ClaimerId == waifuId) + .Select(wi => wi.WaifuId) + .Contains(x.Id)) + .Select(x => $"{x.Username}#{x.Discriminator}") + .ToListAsyncEF(); + } + public async Task> GetFansNames(int waifuId) + { + await using var ctx = _db.GetDbContext(); + return await ctx.GetTable() + .Where(x => ctx.GetTable() + .Where(wi => wi.AffinityId == waifuId) + .Select(wi => wi.WaifuId) + .Contains(x.Id)) + .Select(x => $"{x.Username}#{x.Discriminator}") + .ToListAsyncEF(); + } + + public async Task> GetItems(int waifuId) + { + await using var ctx = _db.GetDbContext(); + return await ctx.GetTable() + .Where(x => x.WaifuInfoId == ctx.GetTable() + .Where(x => x.WaifuId == waifuId) + .Select(x => x.Id) + .FirstOrDefault()) + .ToListAsyncEF(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/_common/AffinityTitle.cs b/src/EllieBot/Modules/Gambling/Waifus/_common/AffinityTitle.cs new file mode 100644 index 0000000..64cf443 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/_common/AffinityTitle.cs @@ -0,0 +1,16 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.Waifu; + +public enum AffinityTitle +{ + Pure, + Faithful, + Playful, + Cheater, + Tainted, + Corrupted, + Lewd, + Sloot, + Depraved, + Harlot +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/_common/ClaimTitle.cs b/src/EllieBot/Modules/Gambling/Waifus/_common/ClaimTitle.cs new file mode 100644 index 0000000..4b7628f --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/_common/ClaimTitle.cs @@ -0,0 +1,18 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.Waifu; + +public enum ClaimTitle +{ + Lonely, + Devoted, + Rookie, + Schemer, + Dilettante, + Intermediate, + Seducer, + Expert, + Veteran, + Incubis, + Harem_King, + Harem_God +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/_common/DivorceResult.cs b/src/EllieBot/Modules/Gambling/Waifus/_common/DivorceResult.cs new file mode 100644 index 0000000..650bc91 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/_common/DivorceResult.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.Waifu; + +public enum DivorceResult +{ + Success, + SucessWithPenalty, + NotYourWife, + Cooldown +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/_common/Extensions.cs b/src/EllieBot/Modules/Gambling/Waifus/_common/Extensions.cs new file mode 100644 index 0000000..44c6396 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/_common/Extensions.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Gambling.Common.Waifu; + +public class Extensions +{ + +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/_common/WaifuClaimResult.cs b/src/EllieBot/Modules/Gambling/Waifus/_common/WaifuClaimResult.cs new file mode 100644 index 0000000..d68eafb --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/_common/WaifuClaimResult.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common.Waifu; + +public enum WaifuClaimResult +{ + Success, + NotEnoughFunds, + InsufficientAmount +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs b/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs new file mode 100644 index 0000000..fa7c5d5 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs @@ -0,0 +1,17 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class WaifuInfo : DbEntity +{ + public int WaifuId { get; set; } + public DiscordUser Waifu { get; set; } + + public int? ClaimerId { get; set; } + public DiscordUser Claimer { get; set; } + + public int? AffinityId { get; set; } + public DiscordUser Affinity { get; set; } + + public long Price { get; set; } + public List Items { get; set; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs new file mode 100644 index 0000000..45f3055 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs @@ -0,0 +1,131 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class WaifuExtensions +{ + public static WaifuInfo ByWaifuUserId( + this DbSet waifus, + ulong userId, + Func, IQueryable> includes = null) + { + if (includes is null) + { + return waifus.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .Include(wi => wi.Items) + .FirstOrDefault(wi => wi.Waifu.UserId == userId); + } + + return includes(waifus).AsQueryable().FirstOrDefault(wi => wi.Waifu.UserId == userId); + } + + public static IEnumerable GetTop(this DbSet waifus, int count, int skip = 0) + { + ArgumentOutOfRangeException.ThrowIfNegative(count); + + if (count == 0) + return []; + + return waifus.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .OrderByDescending(wi => wi.Price) + .Skip(skip) + .Take(count) + .Select(x => new WaifuLbResult + { + Affinity = x.Affinity == null ? null : x.Affinity.Username, + AffinityDiscrim = x.Affinity == null ? null : x.Affinity.Discriminator, + Claimer = x.Claimer == null ? null : x.Claimer.Username, + ClaimerDiscrim = x.Claimer == null ? null : x.Claimer.Discriminator, + Username = x.Waifu.Username, + Discrim = x.Waifu.Discriminator, + Price = x.Price + }) + .ToList(); + } + + public static decimal GetTotalValue(this DbSet waifus) + => waifus.AsQueryable().Where(x => x.ClaimerId != null).Sum(x => x.Price); + + public static ulong GetWaifuUserId(this DbSet waifus, ulong ownerId, string name) + => waifus.AsQueryable() + .AsNoTracking() + .Where(x => x.Claimer.UserId == ownerId && x.Waifu.Username + "#" + x.Waifu.Discriminator == name) + .Select(x => x.Waifu.UserId) + .FirstOrDefault(); + + public static async Task GetWaifuInfoAsync(this DbContext ctx, ulong userId) + { + await ctx.Set() + .ToLinqToDBTable() + .InsertOrUpdateAsync(() => new() + { + AffinityId = null, + ClaimerId = null, + Price = 1, + WaifuId = ctx.Set().Where(x => x.UserId == userId).Select(x => x.Id).First() + }, + _ => new(), + () => new() + { + WaifuId = ctx.Set().Where(x => x.UserId == userId).Select(x => x.Id).First() + }); + + var toReturn = ctx.Set().AsQueryable() + .Where(w => w.WaifuId + == ctx.Set() + .AsQueryable() + .Where(u => u.UserId == userId) + .Select(u => u.Id) + .FirstOrDefault()) + .Select(w => new WaifuInfoStats + { + WaifuId = w.WaifuId, + FullName = + ctx.Set() + .AsQueryable() + .Where(u => u.UserId == userId) + .Select(u => u.Username + "#" + u.Discriminator) + .FirstOrDefault(), + AffinityCount = + ctx.Set() + .AsQueryable() + .Count(x => x.UserId == w.WaifuId + && x.UpdateType == WaifuUpdateType.AffinityChanged + && x.NewId != null), + AffinityName = + ctx.Set() + .AsQueryable() + .Where(u => u.Id == w.AffinityId) + .Select(u => u.Username + "#" + u.Discriminator) + .FirstOrDefault(), + ClaimCount = ctx.Set().AsQueryable().Count(x => x.ClaimerId == w.WaifuId), + ClaimerName = + ctx.Set() + .AsQueryable() + .Where(u => u.Id == w.ClaimerId) + .Select(u => u.Username + "#" + u.Discriminator) + .FirstOrDefault(), + DivorceCount = + ctx.Set() + .AsQueryable() + .Count(x => x.OldId == w.WaifuId + && x.NewId == null + && x.UpdateType == WaifuUpdateType.Claimed), + Price = w.Price, + }) + .FirstOrDefault(); + + if (toReturn is null) + return null; + + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuInfoStats.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuInfoStats.cs new file mode 100644 index 0000000..8add339 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuInfoStats.cs @@ -0,0 +1,14 @@ +#nullable disable +namespace EllieBot.Db; + +public class WaifuInfoStats +{ + public int WaifuId { get; init; } + public string FullName { get; init; } + public long Price { get; init; } + public string ClaimerName { get; init; } + public string AffinityName { get; init; } + public int AffinityCount { get; init; } + public int DivorceCount { get; init; } + public int ClaimCount { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs new file mode 100644 index 0000000..89125c8 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class WaifuItem : DbEntity +{ + public WaifuInfo WaifuInfo { get; set; } + public int? WaifuInfoId { get; set; } + public string ItemEmoji { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuLbResult.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuLbResult.cs new file mode 100644 index 0000000..f83af4f --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuLbResult.cs @@ -0,0 +1,16 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class WaifuLbResult +{ + public string Username { get; set; } + public string Discrim { get; set; } + + public string Claimer { get; set; } + public string ClaimerDiscrim { get; set; } + + public string Affinity { get; set; } + public string AffinityDiscrim { get; set; } + + public long Price { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs new file mode 100644 index 0000000..736bd0d --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class WaifuUpdate : DbEntity +{ + public int UserId { get; set; } + public DiscordUser User { get; set; } + public WaifuUpdateType UpdateType { get; set; } + + public int? OldId { get; set; } + public DiscordUser Old { get; set; } + + public int? NewId { get; set; } + public DiscordUser New { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdateType.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdateType.cs new file mode 100644 index 0000000..626bb4c --- /dev/null +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdateType.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public enum WaifuUpdateType +{ + AffinityChanged, + Claimed +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/Decks/QuadDeck.cs b/src/EllieBot/Modules/Gambling/_common/Decks/QuadDeck.cs new file mode 100644 index 0000000..04b8e76 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/Decks/QuadDeck.cs @@ -0,0 +1,19 @@ +using Ellie.Econ; + +namespace EllieBot.Modules.Gambling.Common; + +public class QuadDeck : Deck +{ + protected override void RefillPool() + { + CardPool = new(52 * 4); + for (var j = 1; j < 14; j++) + for (var i = 1; i < 5; i++) + { + CardPool.Add(new((CardSuit)i, j)); + CardPool.Add(new((CardSuit)i, j)); + CardPool.Add(new((CardSuit)i, j)); + CardPool.Add(new((CardSuit)i, j)); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/GamblingCleanupService.cs b/src/EllieBot/Modules/Gambling/_common/GamblingCleanupService.cs new file mode 100644 index 0000000..45c1c7e --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/GamblingCleanupService.cs @@ -0,0 +1,56 @@ +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Gambling; + +public class GamblingCleanupService : IGamblingCleanupService, IEService +{ + private readonly DbService _db; + + public GamblingCleanupService(DbService db) + { + _db = db; + } + + public async Task DeleteWaifus() + { + await using var ctx = _db.GetDbContext(); + await ctx.GetTable().DeleteAsync(); + await ctx.GetTable().DeleteAsync(); + await ctx.GetTable().DeleteAsync(); + } + + public async Task DeleteWaifu(ulong userId) + { + await using var ctx = _db.GetDbContext(); + await ctx.GetTable() + .Where(x => x.User.UserId == userId) + .DeleteAsync(); + await ctx.GetTable() + .Where(x => x.WaifuInfo.Waifu.UserId == userId) + .DeleteAsync(); + await ctx.GetTable() + .Where(x => x.Claimer.UserId == userId) + .UpdateAsync(old => new WaifuInfo() + { + ClaimerId = null, + }); + await ctx.GetTable() + .Where(x => x.Waifu.UserId == userId) + .DeleteAsync(); + } + + public async Task DeleteCurrency() + { + await using var ctx = _db.GetDbContext(); + await ctx.GetTable().UpdateAsync(_ => new DiscordUser() + { + CurrencyAmount = 0 + }); + + await ctx.GetTable().DeleteAsync(); + await ctx.GetTable().DeleteAsync(); + await ctx.GetTable().DeleteAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/IGamblingCleanupService.cs b/src/EllieBot/Modules/Gambling/_common/IGamblingCleanupService.cs new file mode 100644 index 0000000..8e266b4 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/IGamblingCleanupService.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Gambling; + +public interface IGamblingCleanupService +{ + Task DeleteWaifus(); + Task DeleteWaifu(ulong userId); + Task DeleteCurrency(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/IGamblingService.cs b/src/EllieBot/Modules/Gambling/_common/IGamblingService.cs new file mode 100644 index 0000000..4ed31c9 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/IGamblingService.cs @@ -0,0 +1,18 @@ +#nullable disable +using EllieBot.Modules.Gambling; +using EllieBot.Modules.Gambling.Betdraw; +using EllieBot.Modules.Gambling.Rps; +using OneOf; + +namespace EllieBot.Modules.Gambling; + +public interface IGamblingService +{ + Task> LulaAsync(ulong userId, long amount); + Task> BetRollAsync(ulong userId, long amount); + Task> BetFlipAsync(ulong userId, long amount, byte guess); + Task> SlotAsync(ulong userId, long amount); + Task FlipAsync(int count); + Task> RpsAsync(ulong userId, long amount, byte pick); + Task> BetDrawAsync(ulong userId, long amount, byte? maybeGuessValue, byte? maybeGuessColor); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/NewGamblingService.cs b/src/EllieBot/Modules/Gambling/_common/NewGamblingService.cs new file mode 100644 index 0000000..2412503 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/NewGamblingService.cs @@ -0,0 +1,269 @@ +#nullable disable +using EllieBot.Modules.Gambling; +using EllieBot.Modules.Gambling.Betdraw; +using EllieBot.Modules.Gambling.Rps; +using EllieBot.Modules.Gambling.Services; +using OneOf; + +namespace EllieBot.Modules.Gambling; + +public sealed class NewGamblingService : IGamblingService, IEService +{ + private readonly GamblingConfigService _bcs; + private readonly ICurrencyService _cs; + + public NewGamblingService(GamblingConfigService bcs, ICurrencyService cs) + { + _bcs = bcs; + _cs = cs; + } + + public async Task> LulaAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegative(amount); + + if (amount > 0) + { + var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("lula", "bet")); + + if (!isTakeSuccess) + { + return GamblingError.InsufficientFunds; + } + } + + var game = new LulaGame(_bcs.Data.LuckyLadder.Multipliers); + var result = game.Spin(amount); + + var won = (long)result.Won; + if (won > 0) + { + await _cs.AddAsync(userId, won, new("lula", "win")); + } + + return result; + } + + public async Task> BetRollAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegative(amount); + + if (amount > 0) + { + var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("betroll", "bet")); + + if (!isTakeSuccess) + { + return GamblingError.InsufficientFunds; + } + } + + var game = new BetrollGame(_bcs.Data.BetRoll.Pairs + .Select(x => (x.WhenAbove, (decimal)x.MultiplyBy)) + .ToList()); + + var result = game.Roll(amount); + + var won = (long)result.Won; + if (won > 0) + { + await _cs.AddAsync(userId, won, new("betroll", "win")); + } + + return result; + } + + public async Task> BetFlipAsync(ulong userId, long amount, byte guess) + { + ArgumentOutOfRangeException.ThrowIfNegative(amount); + + ArgumentOutOfRangeException.ThrowIfGreaterThan(guess, 1); + + if (amount > 0) + { + var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("betflip", "bet")); + + if (!isTakeSuccess) + { + return GamblingError.InsufficientFunds; + } + } + + var game = new BetflipGame(_bcs.Data.BetFlip.Multiplier); + var result = game.Flip(guess, amount); + + var won = (long)result.Won; + if (won > 0) + { + await _cs.AddAsync(userId, won, new("betflip", "win")); + } + + return result; + } + + public async Task> BetDrawAsync(ulong userId, long amount, byte? maybeGuessValue, byte? maybeGuessColor) + { + ArgumentOutOfRangeException.ThrowIfNegative(amount); + + if (maybeGuessColor is null && maybeGuessValue is null) + throw new ArgumentNullException(); + + if (maybeGuessColor > 1) + throw new ArgumentOutOfRangeException(nameof(maybeGuessColor)); + + if (maybeGuessValue > 1) + throw new ArgumentOutOfRangeException(nameof(maybeGuessValue)); + + if (amount > 0) + { + var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("betdraw", "bet")); + + if (!isTakeSuccess) + { + return GamblingError.InsufficientFunds; + } + } + + var game = new BetdrawGame(); + var result = game.Draw((BetdrawValueGuess?)maybeGuessValue, (BetdrawColorGuess?)maybeGuessColor, amount); + + var won = (long)result.Won; + if (won > 0) + { + await _cs.AddAsync(userId, won, new("betdraw", "win")); + } + + return result; + } + + public async Task> SlotAsync(ulong userId, long amount) + { + ArgumentOutOfRangeException.ThrowIfNegative(amount); + + if (amount > 0) + { + var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("slot", "bet")); + + if (!isTakeSuccess) + { + return GamblingError.InsufficientFunds; + } + } + + var game = new SlotGame(); + var result = game.Spin(amount); + + var won = (long)result.Won; + if (won > 0) + { + await _cs.AddAsync(userId, won, new("slot", "won")); + } + + return result; + } + + public Task FlipAsync(int count) + { + ArgumentOutOfRangeException.ThrowIfLessThan(count, 1); + + var game = new BetflipGame(0); + + var results = new FlipResult[count]; + for (var i = 0; i < count; i++) + { + results[i] = new() + { + Side = game.Flip(0, 0).Side + }; + } + + return Task.FromResult(results); + } + + // + // + // private readonly ConcurrentDictionary _decks = new ConcurrentDictionary(); + // + // public override Task DeckShuffle(DeckShuffleRequest request, ServerCallContext context) + // { + // _decks.AddOrUpdate(request.Id, new Deck(), (key, old) => new Deck()); + // return Task.FromResult(new DeckShuffleReply { }); + // } + // + // public override Task DeckDraw(DeckDrawRequest request, ServerCallContext context) + // { + // if (request.Count < 1 || request.Count > 10) + // throw new ArgumentOutOfRangeException(nameof(request.Id)); + // + // var deck = request.UseNew + // ? new Deck() + // : _decks.GetOrAdd(request.Id, new Deck()); + // + // var list = new List(request.Count); + // for (int i = 0; i < request.Count; i++) + // { + // var card = deck.DrawNoRestart(); + // if (card is null) + // { + // if (i == 0) + // { + // deck.Restart(); + // list.Add(deck.DrawNoRestart()); + // continue; + // } + // + // break; + // } + // + // list.Add(card); + // } + // + // var cards = list + // .Select(x => new Card + // { + // Name = x.ToString().ToLowerInvariant().Replace(' ', '_'), + // Number = x.Number, + // Suit = (CardSuit) x.Suit + // }); + // + // var toReturn = new DeckDrawReply(); + // toReturn.Cards.AddRange(cards); + // + // return Task.FromResult(toReturn); + // } + // + + public async Task> RpsAsync(ulong userId, long amount, byte pick) + { + ArgumentOutOfRangeException.ThrowIfNegative(amount); + ArgumentOutOfRangeException.ThrowIfGreaterThan(pick, 2); + + if (amount > 0) + { + var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("rps", "bet")); + + if (!isTakeSuccess) + { + return GamblingError.InsufficientFunds; + } + } + + var rps = new RpsGame(); + var result = rps.Play((RpsPick)pick, amount); + + var won = (long)result.Won; + if (won > 0) + { + var extra = result.Result switch + { + RpsResultType.Draw => "draw", + RpsResultType.Win => "win", + _ => "lose" + }; + + await _cs.AddAsync(userId, won, new("rps", extra)); + } + + return result; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs b/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs new file mode 100644 index 0000000..24b634a --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs @@ -0,0 +1,139 @@ +#nullable disable +namespace EllieBot.Modules.Gambling.Common; + +public class RollDuelGame +{ + public enum Reason + { + Normal, + NoFunds, + Timeout + } + + public enum State + { + Waiting, + Running, + Ended + } + + public event Func OnGameTick; + public event Func OnEnded; + + public ulong P1 { get; } + public ulong P2 { get; } + + public long Amount { get; } + + public List<(int, int)> Rolls { get; } = new(); + public State CurrentState { get; private set; } + public ulong Winner { get; private set; } + + private readonly ulong _botId; + + private readonly ICurrencyService _cs; + + private readonly Timer _timeoutTimer; + private readonly EllieRandom _rng = new(); + private readonly SemaphoreSlim _locker = new(1, 1); + + public RollDuelGame( + ICurrencyService cs, + ulong botId, + ulong p1, + ulong p2, + long amount) + { + P1 = p1; + P2 = p2; + _botId = botId; + Amount = amount; + _cs = cs; + + _timeoutTimer = new(async delegate + { + await _locker.WaitAsync(); + try + { + if (CurrentState != State.Waiting) + return; + CurrentState = State.Ended; + await OnEnded?.Invoke(this, Reason.Timeout); + } + catch { } + finally + { + _locker.Release(); + } + }, + null, + TimeSpan.FromSeconds(15), + TimeSpan.FromMilliseconds(-1)); + } + + public async Task StartGame() + { + await _locker.WaitAsync(); + try + { + if (CurrentState != State.Waiting) + return; + _timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite); + CurrentState = State.Running; + } + finally + { + _locker.Release(); + } + + if (!await _cs.RemoveAsync(P1, Amount, new("rollduel", "bet"))) + { + await OnEnded?.Invoke(this, Reason.NoFunds); + CurrentState = State.Ended; + return; + } + + if (!await _cs.RemoveAsync(P2, Amount, new("rollduel", "bet"))) + { + await _cs.AddAsync(P1, Amount, new("rollduel", "refund")); + await OnEnded?.Invoke(this, Reason.NoFunds); + CurrentState = State.Ended; + return; + } + + int n1, n2; + do + { + n1 = _rng.Next(0, 5); + n2 = _rng.Next(0, 5); + Rolls.Add((n1, n2)); + if (n1 != n2) + { + if (n1 > n2) + Winner = P1; + else + Winner = P2; + var won = (long)(Amount * 2 * 0.98f); + await _cs.AddAsync(Winner, won, new("rollduel", "win")); + + await _cs.AddAsync(_botId, (Amount * 2) - won, new("rollduel", "fee")); + } + + try { await OnGameTick?.Invoke(this); } + catch { } + + await Task.Delay(2500); + if (n1 != n2) + break; + } while (true); + + CurrentState = State.Ended; + await OnEnded?.Invoke(this, Reason.Normal); + } +} + +public struct RollDuelChallenge +{ + public ulong Player1 { get; set; } + public ulong Player2 { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/TypeReaders/BaseShmartInputAmountReader.cs b/src/EllieBot/Modules/Gambling/_common/TypeReaders/BaseShmartInputAmountReader.cs new file mode 100644 index 0000000..42c6f09 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/TypeReaders/BaseShmartInputAmountReader.cs @@ -0,0 +1,95 @@ +using System.Text.RegularExpressions; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Gambling.Services; +using NCalc; +using OneOf; + +namespace EllieBot.Common.TypeReaders; + +public class BaseShmartInputAmountReader +{ + private static readonly Regex _percentRegex = new(@"^((?100|\d{1,2})%)$", RegexOptions.Compiled); + protected readonly DbService _db; + protected readonly GamblingConfigService _gambling; + + public BaseShmartInputAmountReader(DbService db, GamblingConfigService gambling) + { + _db = db; + _gambling = gambling; + } + + public async ValueTask>> ReadAsync(ICommandContext context, string input) + { + var i = input.Trim().ToUpperInvariant(); + + i = i.Replace("K", "000"); + + //can't add m because it will conflict with max atm + + if (await TryHandlePercentage(context, i) is long num) + { + return num; + } + + try + { + var expr = new Expression(i, EvaluateOptions.IgnoreCase); + expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context).GetAwaiter().GetResult(); + return (long)decimal.Parse(expr.Evaluate().ToString()!); + } + catch (Exception) + { + return new OneOf.Types.Error($"Invalid input: {input}"); + } + } + + private async Task EvaluateParam(string name, ParameterArgs args, ICommandContext ctx) + { + switch (name.ToUpperInvariant()) + { + case "PI": + args.Result = Math.PI; + break; + case "E": + args.Result = Math.E; + break; + case "ALL": + case "ALLIN": + args.Result = await Cur(ctx); + break; + case "HALF": + args.Result = await Cur(ctx) / 2; + break; + case "MAX": + args.Result = await Max(ctx); + break; + } + } + + protected virtual async Task Cur(ICommandContext ctx) + { + await using var uow = _db.GetDbContext(); + return await uow.Set().GetUserCurrencyAsync(ctx.User.Id); + } + + protected virtual async Task Max(ICommandContext ctx) + { + var settings = _gambling.Data; + var max = settings.MaxBet; + return max == 0 ? await Cur(ctx) : max; + } + + private async Task TryHandlePercentage(ICommandContext ctx, string input) + { + var m = _percentRegex.Match(input); + + if (m.Captures.Count == 0) + return null; + + if (!long.TryParse(m.Groups["num"].ToString(), out var percent)) + return null; + + return (long)(await Cur(ctx) * (percent / 100.0f)); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartBankInputAmountReader.cs b/src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartBankInputAmountReader.cs new file mode 100644 index 0000000..bcb7c20 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartBankInputAmountReader.cs @@ -0,0 +1,21 @@ +using EllieBot.Modules.Gambling.Bank; +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Common.TypeReaders; + +public sealed class ShmartBankInputAmountReader : BaseShmartInputAmountReader +{ + private readonly IBankService _bank; + + public ShmartBankInputAmountReader(IBankService bank, DbService db, GamblingConfigService gambling) + : base(db, gambling) + { + _bank = bank; + } + + protected override Task Cur(ICommandContext ctx) + => _bank.GetBalanceAsync(ctx.User.Id); + + protected override Task Max(ICommandContext ctx) + => Cur(ctx); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartNumberTypeReader.cs b/src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartNumberTypeReader.cs new file mode 100644 index 0000000..cd94058 --- /dev/null +++ b/src/EllieBot/Modules/Gambling/_common/TypeReaders/ShmartNumberTypeReader.cs @@ -0,0 +1,57 @@ +#nullable disable +using EllieBot.Modules.Gambling.Bank; +using EllieBot.Modules.Gambling.Services; + +namespace EllieBot.Common.TypeReaders; + +public sealed class BalanceTypeReader : TypeReader +{ + private readonly BaseShmartInputAmountReader _tr; + + public BalanceTypeReader(DbService db, GamblingConfigService gambling) + { + _tr = new BaseShmartInputAmountReader(db, gambling); + } + + public override async Task ReadAsync( + ICommandContext context, + string input, + IServiceProvider services) + { + + var result = await _tr.ReadAsync(context, input); + + if (result.TryPickT0(out var val, out var err)) + { + return Discord.Commands.TypeReaderResult.FromSuccess(val); + } + + return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, err.Value); + } +} + +public sealed class BankBalanceTypeReader : TypeReader +{ + private readonly ShmartBankInputAmountReader _tr; + + public BankBalanceTypeReader(IBankService bank, DbService db, GamblingConfigService gambling) + { + _tr = new ShmartBankInputAmountReader(bank, db, gambling); + } + + public override async Task ReadAsync( + ICommandContext context, + string input, + IServiceProvider services) + { + + var result = await _tr.ReadAsync(context, input); + + if (result.TryPickT0(out var val, out var err)) + { + return Discord.Commands.TypeReaderResult.FromSuccess(val); + } + + return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, err.Value); + } +} \ No newline at end of file From 4261abbf722e166c1f22f83eb46db4a39fdd481f Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:51:06 +1200 Subject: [PATCH 49/62] Added Games module --- .../Modules/Games/Acrophobia/Acrophobia.cs | 200 ++++++++++++ .../Games/Acrophobia/AcrophobiaUser.cs | 22 ++ .../Games/Acrophobia/AcropobiaCommands.cs | 140 ++++++++ .../Games/ChatterBot/ChatterbotService.cs | 215 ++++++++++++ .../Games/ChatterBot/CleverBotCommands.cs | 48 +++ .../ChatterBot/_common/CleverbotResponse.cs | 8 + .../Games/ChatterBot/_common/Gpt3Response.cs | 46 +++ .../ChatterBot/_common/IChatterBotSession.cs | 7 + .../_common/OfficialCleverbotSession.cs | 38 +++ .../ChatterBot/_common/OfficialGpt3Session.cs | 105 ++++++ src/EllieBot/Modules/Games/Games.cs | 47 +++ src/EllieBot/Modules/Games/GamesConfig.cs | 174 ++++++++++ .../Modules/Games/GamesConfigService.cs | 94 ++++++ src/EllieBot/Modules/Games/GamesService.cs | 118 +++++++ src/EllieBot/Modules/Games/GirlRating.cs | 61 ++++ .../Games/Hangman/DefaultHangmanSource.cs | 64 ++++ .../Modules/Games/Hangman/HangmanCommands.cs | 76 +++++ .../Modules/Games/Hangman/HangmanGame.cs | 111 +++++++ .../Modules/Games/Hangman/HangmanService.cs | 136 ++++++++ .../Modules/Games/Hangman/HangmanTerm.cs | 8 + .../Modules/Games/Hangman/IHangmanService.cs | 10 + .../Modules/Games/Hangman/IHangmanSource.cs | 10 + src/EllieBot/Modules/Games/Nunchi/Nunchi.cs | 183 +++++++++++ .../Modules/Games/Nunchi/NunchiCommands.cs | 114 +++++++ .../Games/SpeedTyping/SpeedTypingCommands.cs | 105 ++++++ .../Games/SpeedTyping/TypingArticle.cs | 9 + .../Modules/Games/SpeedTyping/TypingGame.cs | 197 +++++++++++ .../Modules/Games/TicTacToe/TicTacToe.cs | 307 ++++++++++++++++++ .../Games/TicTacToe/TicTacToeCommands.cs | 54 +++ src/EllieBot/Modules/Games/Trivia/Games.cs | 282 ++++++++++++++++ .../QuestionPool/DefaultQuestionPool.cs | 22 ++ .../Trivia/QuestionPool/IQuestionPool.cs | 6 + .../QuestionPool/PokemonQuestionPool.cs | 32 ++ .../Modules/Games/Trivia/TriviaGame.cs | 219 +++++++++++++ .../Games/Trivia/TriviaGamesService.cs | 37 +++ .../Modules/Games/Trivia/TriviaOptions.cs | 44 +++ .../Modules/Games/Trivia/TriviaQuestion.cs | 115 +++++++ .../Modules/Games/Trivia/TriviaUser.cs | 3 + 38 files changed, 3467 insertions(+) create mode 100644 src/EllieBot/Modules/Games/Acrophobia/Acrophobia.cs create mode 100644 src/EllieBot/Modules/Games/Acrophobia/AcrophobiaUser.cs create mode 100644 src/EllieBot/Modules/Games/Acrophobia/AcropobiaCommands.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/CleverbotResponse.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs create mode 100644 src/EllieBot/Modules/Games/Games.cs create mode 100644 src/EllieBot/Modules/Games/GamesConfig.cs create mode 100644 src/EllieBot/Modules/Games/GamesConfigService.cs create mode 100644 src/EllieBot/Modules/Games/GamesService.cs create mode 100644 src/EllieBot/Modules/Games/GirlRating.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/DefaultHangmanSource.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/HangmanCommands.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/HangmanGame.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/HangmanService.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/HangmanTerm.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/IHangmanService.cs create mode 100644 src/EllieBot/Modules/Games/Hangman/IHangmanSource.cs create mode 100644 src/EllieBot/Modules/Games/Nunchi/Nunchi.cs create mode 100644 src/EllieBot/Modules/Games/Nunchi/NunchiCommands.cs create mode 100644 src/EllieBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs create mode 100644 src/EllieBot/Modules/Games/SpeedTyping/TypingArticle.cs create mode 100644 src/EllieBot/Modules/Games/SpeedTyping/TypingGame.cs create mode 100644 src/EllieBot/Modules/Games/TicTacToe/TicTacToe.cs create mode 100644 src/EllieBot/Modules/Games/TicTacToe/TicTacToeCommands.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/Games.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/QuestionPool/DefaultQuestionPool.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/QuestionPool/IQuestionPool.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/QuestionPool/PokemonQuestionPool.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/TriviaGame.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/TriviaGamesService.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/TriviaOptions.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/TriviaQuestion.cs create mode 100644 src/EllieBot/Modules/Games/Trivia/TriviaUser.cs diff --git a/src/EllieBot/Modules/Games/Acrophobia/Acrophobia.cs b/src/EllieBot/Modules/Games/Acrophobia/Acrophobia.cs new file mode 100644 index 0000000..ae8ba56 --- /dev/null +++ b/src/EllieBot/Modules/Games/Acrophobia/Acrophobia.cs @@ -0,0 +1,200 @@ +#nullable disable +using CommandLine; +using System.Collections.Immutable; + +namespace EllieBot.Modules.Games.Common.Acrophobia; + +public sealed class AcrophobiaGame : IDisposable +{ + public enum Phase + { + Submission, + Voting, + Ended + } + + public enum UserInputResult + { + Submitted, + SubmissionFailed, + Voted, + VotingFailed, + Failed + } + + public event Func OnStarted = delegate { return Task.CompletedTask; }; + + public event Func>, Task> OnVotingStarted = + delegate { return Task.CompletedTask; }; + + public event Func OnUserVoted = delegate { return Task.CompletedTask; }; + + public event Func>, Task> OnEnded = delegate + { + return Task.CompletedTask; + }; + + public Phase CurrentPhase { get; private set; } = Phase.Submission; + public ImmutableArray StartingLetters { get; private set; } + public Options Opts { get; } + + private readonly Dictionary _submissions = new(); + private readonly SemaphoreSlim _locker = new(1, 1); + private readonly EllieRandom _rng; + + private readonly HashSet _usersWhoVoted = []; + + public AcrophobiaGame(Options options) + { + Opts = options; + _rng = new(); + InitializeStartingLetters(); + } + + public async Task Run() + { + await OnStarted(this); + await Task.Delay(Opts.SubmissionTime * 1000); + await _locker.WaitAsync(); + try + { + if (_submissions.Count == 0) + { + CurrentPhase = Phase.Ended; + await OnVotingStarted(this, ImmutableArray.Create>()); + return; + } + + if (_submissions.Count == 1) + { + CurrentPhase = Phase.Ended; + await OnVotingStarted(this, _submissions.ToArray().ToImmutableArray()); + return; + } + + CurrentPhase = Phase.Voting; + + await OnVotingStarted(this, _submissions.ToArray().ToImmutableArray()); + } + finally { _locker.Release(); } + + await Task.Delay(Opts.VoteTime * 1000); + await _locker.WaitAsync(); + try + { + CurrentPhase = Phase.Ended; + await OnEnded(this, _submissions.ToArray().ToImmutableArray()); + } + finally { _locker.Release(); } + } + + private void InitializeStartingLetters() + { + var wordCount = _rng.Next(3, 6); + + var lettersArr = new char[wordCount]; + + for (var i = 0; i < wordCount; i++) + { + var randChar = (char)_rng.Next(65, 91); + lettersArr[i] = randChar == 'X' ? (char)_rng.Next(65, 88) : randChar; + } + + StartingLetters = lettersArr.ToImmutableArray(); + } + + public async Task UserInput(ulong userId, string userName, string input) + { + var user = new AcrophobiaUser(userId, userName, input.ToLowerInvariant().ToTitleCase()); + + await _locker.WaitAsync(); + try + { + switch (CurrentPhase) + { + case Phase.Submission: + if (_submissions.ContainsKey(user) || !IsValidAnswer(input)) + break; + + _submissions.Add(user, 0); + return true; + case Phase.Voting: + AcrophobiaUser toVoteFor; + if (!int.TryParse(input, out var index) + || --index < 0 + || index >= _submissions.Count + || (toVoteFor = _submissions.ToArray()[index].Key).UserId == user.UserId + || !_usersWhoVoted.Add(userId)) + break; + ++_submissions[toVoteFor]; + _ = Task.Run(() => OnUserVoted(userName)); + return true; + } + + return false; + } + finally + { + _locker.Release(); + } + } + + private bool IsValidAnswer(string input) + { + input = input.ToUpperInvariant(); + + var inputWords = input.Split(' '); + + if (inputWords.Length + != StartingLetters.Length) // number of words must be the same as the number of the starting letters + return false; + + for (var i = 0; i < StartingLetters.Length; i++) + { + var letter = StartingLetters[i]; + + if (!inputWords[i] + .StartsWith(letter.ToString(), StringComparison.InvariantCulture)) // all first letters must match + return false; + } + + return true; + } + + public void Dispose() + { + CurrentPhase = Phase.Ended; + OnStarted = null; + OnEnded = null; + OnUserVoted = null; + OnVotingStarted = null; + _usersWhoVoted.Clear(); + _submissions.Clear(); + _locker.Dispose(); + } + + public class Options : IEllieCommandOptions + { + [Option('s', + "submission-time", + Required = false, + Default = 60, + HelpText = "Time after which the submissions are closed and voting starts.")] + public int SubmissionTime { get; set; } = 60; + + [Option('v', + "vote-time", + Required = false, + Default = 60, + HelpText = "Time after which the voting is closed and the winner is declared.")] + public int VoteTime { get; set; } = 30; + + public void NormalizeOptions() + { + if (SubmissionTime is < 15 or > 300) + SubmissionTime = 60; + if (VoteTime is < 15 or > 120) + VoteTime = 30; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Acrophobia/AcrophobiaUser.cs b/src/EllieBot/Modules/Games/Acrophobia/AcrophobiaUser.cs new file mode 100644 index 0000000..2de2917 --- /dev/null +++ b/src/EllieBot/Modules/Games/Acrophobia/AcrophobiaUser.cs @@ -0,0 +1,22 @@ +#nullable disable +namespace EllieBot.Modules.Games.Common.Acrophobia; + +public class AcrophobiaUser +{ + public string UserName { get; } + public ulong UserId { get; } + public string Input { get; } + + public AcrophobiaUser(ulong userId, string userName, string input) + { + UserName = userName; + UserId = userId; + Input = input; + } + + public override int GetHashCode() + => UserId.GetHashCode(); + + public override bool Equals(object obj) + => obj is AcrophobiaUser x ? x.UserId == UserId : false; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Acrophobia/AcropobiaCommands.cs b/src/EllieBot/Modules/Games/Acrophobia/AcropobiaCommands.cs new file mode 100644 index 0000000..30defba --- /dev/null +++ b/src/EllieBot/Modules/Games/Acrophobia/AcropobiaCommands.cs @@ -0,0 +1,140 @@ +#nullable disable +using EllieBot.Modules.Games.Common.Acrophobia; +using EllieBot.Modules.Games.Services; +using System.Collections.Immutable; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class AcropobiaCommands : EllieModule + { + private readonly DiscordSocketClient _client; + + public AcropobiaCommands(DiscordSocketClient client) + => _client = client; + + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + public async Task Acrophobia(params string[] args) + { + var (options, _) = OptionsParser.ParseFrom(new AcrophobiaGame.Options(), args); + var channel = (ITextChannel)ctx.Channel; + + var game = new AcrophobiaGame(options); + if (_service.AcrophobiaGames.TryAdd(channel.Id, game)) + { + try + { + game.OnStarted += Game_OnStarted; + game.OnEnded += Game_OnEnded; + game.OnVotingStarted += Game_OnVotingStarted; + game.OnUserVoted += Game_OnUserVoted; + _client.MessageReceived += ClientMessageReceived; + await game.Run(); + } + finally + { + _client.MessageReceived -= ClientMessageReceived; + _service.AcrophobiaGames.TryRemove(channel.Id, out game); + game?.Dispose(); + } + } + else + await Response().Error(strs.acro_running).SendAsync(); + + Task ClientMessageReceived(SocketMessage msg) + { + if (msg.Channel.Id != ctx.Channel.Id) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + try + { + var success = await game.UserInput(msg.Author.Id, msg.Author.ToString(), msg.Content); + if (success) + await msg.DeleteAsync(); + } + catch { } + }); + + return Task.CompletedTask; + } + } + + private Task Game_OnStarted(AcrophobiaGame game) + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.acrophobia)) + .WithDescription( + GetText(strs.acro_started(Format.Bold(string.Join(".", game.StartingLetters))))) + .WithFooter(GetText(strs.acro_started_footer(game.Opts.SubmissionTime))); + + return Response().Embed(embed).SendAsync(); + } + + private Task Game_OnUserVoted(string user) + => Response().Confirm(GetText(strs.acrophobia), GetText(strs.acro_vote_cast(Format.Bold(user)))).SendAsync(); + + private async Task Game_OnVotingStarted( + AcrophobiaGame game, + ImmutableArray> submissions) + { + if (submissions.Length == 0) + { + await Response().Error(GetText(strs.acrophobia), GetText(strs.acro_ended_no_sub)).SendAsync(); + return; + } + + if (submissions.Length == 1) + { + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithDescription(GetText( + strs.acro_winner_only( + Format.Bold(submissions.First().Key.UserName)))) + .WithFooter(submissions.First().Key.Input)).SendAsync(); + return; + } + + + var i = 0; + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.acrophobia) + " - " + GetText(strs.submissions_closed)) + .WithDescription(GetText(strs.acro_nym_was( + Format.Bold(string.Join(".", game.StartingLetters)) + + "\n" + + $@"-- +{submissions.Aggregate("", (agg, cur) => agg + $"`{++i}.` **{cur.Key.Input}**\n")} +--"))) + .WithFooter(GetText(strs.acro_vote)); + + await Response().Embed(embed).SendAsync(); + } + + private async Task Game_OnEnded(AcrophobiaGame game, ImmutableArray> votes) + { + if (!votes.Any() || votes.All(x => x.Value == 0)) + { + await Response().Error(GetText(strs.acrophobia), GetText(strs.acro_no_votes_cast)).SendAsync(); + return; + } + + var table = votes.OrderByDescending(v => v.Value); + var winner = table.First(); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.acrophobia)) + .WithDescription(GetText(strs.acro_winner(Format.Bold(winner.Key.UserName), + Format.Bold(winner.Value.ToString())))) + .WithFooter(winner.Key.Input); + + await Response().Embed(embed).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs b/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs new file mode 100644 index 0000000..30dc17e --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs @@ -0,0 +1,215 @@ +#nullable disable +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; +using EllieBot.Modules.Games.Common; +using EllieBot.Modules.Games.Common.ChatterBot; +using EllieBot.Modules.Patronage; +using EllieBot.Modules.Permissions; + +namespace EllieBot.Modules.Games.Services; + +public class ChatterBotService : IExecOnMessage +{ + public ConcurrentDictionary> ChatterBotGuilds { get; } + + public int Priority + => 1; + + private readonly FeatureLimitKey _flKey; + + private readonly DiscordSocketClient _client; + private readonly IPermissionChecker _perms; + private readonly CommandHandler _cmd; + private readonly IBotCredentials _creds; + private readonly IHttpClientFactory _httpFactory; + private readonly IPatronageService _ps; + private readonly GamesConfigService _gcs; + private readonly IMessageSenderService _sender; + + public ChatterBotService( + DiscordSocketClient client, + IPermissionChecker perms, + IBot bot, + CommandHandler cmd, + IHttpClientFactory factory, + IBotCredentials creds, + IPatronageService ps, + GamesConfigService gcs, + IMessageSenderService sender) + { + _client = client; + _perms = perms; + _cmd = cmd; + _creds = creds; + _sender = sender; + _httpFactory = factory; + _ps = ps; + _perms = perms; + _gcs = gcs; + + _flKey = new FeatureLimitKey() + { + Key = CleverBotResponseStr.CLEVERBOT_RESPONSE, + PrettyName = "Cleverbot Replies" + }; + + ChatterBotGuilds = new(bot.AllGuildConfigs + .Where(gc => gc.CleverbotEnabled) + .ToDictionary(gc => gc.GuildId, + _ => new Lazy(() => CreateSession(), true))); + } + + public IChatterBotSession CreateSession() + { + switch (_gcs.Data.ChatBot) + { + case ChatBotImplementation.Cleverbot: + if (!string.IsNullOrWhiteSpace(_creds.CleverbotApiKey)) + return new OfficialCleverbotSession(_creds.CleverbotApiKey, _httpFactory); + + Log.Information("Cleverbot will not work as the api key is missing"); + return null; + case ChatBotImplementation.Gpt3: + if (!string.IsNullOrWhiteSpace(_creds.Gpt3ApiKey)) + return new OfficialGpt3Session(_creds.Gpt3ApiKey, + _gcs.Data.ChatGpt.ModelName, + _gcs.Data.ChatGpt.ChatHistory, + _gcs.Data.ChatGpt.MaxTokens, + _gcs.Data.ChatGpt.MinTokens, + _gcs.Data.ChatGpt.PersonalityPrompt, + _client.CurrentUser.Username, + _httpFactory); + + Log.Information("Gpt3 will not work as the api key is missing"); + return null; + default: + return null; + } + } + + public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot) + { + var channel = msg.Channel as ITextChannel; + cleverbot = null; + + if (channel is null) + return null; + + if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyCleverbot)) + return null; + + cleverbot = lazyCleverbot.Value; + + var ellieId = _client.CurrentUser.Id; + var normalMention = $"<@{ellieId}> "; + var nickMention = $"<@!{ellieId}> "; + string message; + if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture)) + message = msg.Content[normalMention.Length..].Trim(); + else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture)) + message = msg.Content[nickMention.Length..].Trim(); + else + return null; + + return message; + } + + public async Task ExecOnMessageAsync(IGuild guild, IUserMessage usrMsg) + { + if (guild is not SocketGuild sg) + return false; + + try + { + var message = PrepareMessage(usrMsg, out var cbs); + if (message is null || cbs is null) + return false; + + var res = await _perms.CheckPermsAsync(sg, + usrMsg.Channel, + usrMsg.Author, + CleverBotResponseStr.CLEVERBOT_RESPONSE, + CleverBotResponseStr.CLEVERBOT_RESPONSE); + + if (!res.IsAllowed) + return false; + + var channel = (ITextChannel)usrMsg.Channel; + var conf = _ps.GetConfig(); + if (!_creds.IsOwner(sg.OwnerId) && conf.IsEnabled) + { + var quota = await _ps.TryGetFeatureLimitAsync(_flKey, sg.OwnerId, 0); + + uint? daily = quota.Quota is int dVal and < 0 + ? (uint)-dVal + : null; + + uint? monthly = quota.Quota is int mVal and >= 0 + ? (uint)mVal + : null; + + var maybeLimit = await _ps.TryIncrementQuotaCounterAsync(sg.OwnerId, + sg.OwnerId == usrMsg.Author.Id, + FeatureType.Limit, + _flKey.Key, + null, + daily, + monthly); + + if (maybeLimit.TryPickT1(out var ql, out var counters)) + { + if (ql.Quota == 0) + { + await _sender.Response(channel) + .Error(null, + text: + "In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/elliebot) on patreon.", + footer: + "You may disable the cleverbot feature, and this message via '.cleverbot' command") + .SendAsync(); + + return true; + } + + await _sender.Response(channel) + .Error( + null!, + $"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.", + footer: "You may wait for the quota reset or .") + .SendAsync(); + + return true; + } + } + + _ = channel.TriggerTypingAsync(); + var response = await cbs.Think(message, usrMsg.Author.ToString()); + await _sender.Response(channel) + .Confirm(response) + .SendAsync(); + + Log.Information(""" + CleverBot Executed + Server: {GuildName} [{GuildId}] + Channel: {ChannelName} [{ChannelId}] + UserId: {Author} [{AuthorId}] + Message: {Content} + """, + guild.Name, + guild.Id, + usrMsg.Channel?.Name, + usrMsg.Channel?.Id, + usrMsg.Author, + usrMsg.Author.Id, + usrMsg.Content); + + return true; + } + catch (Exception ex) + { + Log.Warning(ex, "Error in cleverbot"); + } + + return false; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs b/src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs new file mode 100644 index 0000000..1a41953 --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs @@ -0,0 +1,48 @@ +#nullable disable +using EllieBot.Db; +using EllieBot.Modules.Games.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class ChatterBotCommands : EllieModule + { + private readonly DbService _db; + + public ChatterBotCommands(DbService db) + => _db = db; + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task Cleverbot() + { + var channel = (ITextChannel)ctx.Channel; + + if (_service.ChatterBotGuilds.TryRemove(channel.Guild.Id, out _)) + { + await using (var uow = _db.GetDbContext()) + { + uow.Set().SetCleverbotEnabled(ctx.Guild.Id, false); + await uow.SaveChangesAsync(); + } + + await Response().Confirm(strs.cleverbot_disabled).SendAsync(); + return; + } + + _service.ChatterBotGuilds.TryAdd(channel.Guild.Id, new(() => _service.CreateSession(), true)); + + await using (var uow = _db.GetDbContext()) + { + uow.Set().SetCleverbotEnabled(ctx.Guild.Id, true); + await uow.SaveChangesAsync(); + } + + await Response().Confirm(strs.cleverbot_enabled).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/CleverbotResponse.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/CleverbotResponse.cs new file mode 100644 index 0000000..2f83164 --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/CleverbotResponse.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Modules.Games.Common.ChatterBot; + +public class CleverbotResponse +{ + public string Cs { get; set; } + public string Output { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs new file mode 100644 index 0000000..ad8692a --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs @@ -0,0 +1,46 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Games.Common.ChatterBot; + +public class Gpt3Response +{ + [JsonPropertyName("choices")] + public Choice[] Choices { get; set; } +} + +public class Choice +{ + [JsonPropertyName("message")] + public Message Message { get; init; } +} + +public class Message { + [JsonPropertyName("content")] + public string Content { get; init; } +} + +public class Gpt3ApiRequest +{ + [JsonPropertyName("model")] + public string Model { get; init; } + + [JsonPropertyName("messages")] + public List Messages { get; init; } + + [JsonPropertyName("temperature")] + public int Temperature { get; init; } + + [JsonPropertyName("max_tokens")] + public int MaxTokens { get; init; } +} + +public class GPTMessage +{ + [JsonPropertyName("role")] + public string Role {get; init;} + [JsonPropertyName("content")] + public string Content {get; init;} + [JsonPropertyName("name")] + public string Name {get; init;} +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs new file mode 100644 index 0000000..847d661 --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace EllieBot.Modules.Games.Common.ChatterBot; + +public interface IChatterBotSession +{ + Task Think(string input, string username); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs new file mode 100644 index 0000000..83dc060 --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs @@ -0,0 +1,38 @@ +#nullable disable +using Newtonsoft.Json; + +namespace EllieBot.Modules.Games.Common.ChatterBot; + +public class OfficialCleverbotSession : IChatterBotSession +{ + private string QueryString + => $"https://www.cleverbot.com/getreply?key={_apiKey}" + "&wrapper=elliebot" + "&input={0}" + "&cs={1}"; + + private readonly string _apiKey; + private readonly IHttpClientFactory _httpFactory; + private string cs; + + public OfficialCleverbotSession(string apiKey, IHttpClientFactory factory) + { + _apiKey = apiKey; + _httpFactory = factory; + } + + public async Task Think(string input, string username) + { + using var http = _httpFactory.CreateClient(); + var dataString = await http.GetStringAsync(string.Format(QueryString, input, cs ?? "")); + try + { + var data = JsonConvert.DeserializeObject(dataString); + + cs = data?.Cs; + return data?.Output; + } + catch + { + Log.Warning("Unexpected cleverbot response received: {ResponseString}", dataString); + return null; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs new file mode 100644 index 0000000..4711fd6 --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs @@ -0,0 +1,105 @@ +#nullable disable +using Newtonsoft.Json; +using System.Net.Http.Json; +using SharpToken; + +namespace EllieBot.Modules.Games.Common.ChatterBot; + +public class OfficialGpt3Session : IChatterBotSession +{ + private string Uri + => $"https://api.openai.com/v1/chat/completions"; + + private readonly string _apiKey; + private readonly string _model; + private readonly int _maxHistory; + private readonly int _maxTokens; + private readonly int _minTokens; + private readonly string _ellieUsername; + private readonly GptEncoding _encoding; + private List messages = new(); + private readonly IHttpClientFactory _httpFactory; + + + + public OfficialGpt3Session( + string apiKey, + ChatGptModel model, + int chatHistory, + int maxTokens, + int minTokens, + string personality, + string ellieUsername, + IHttpClientFactory factory) + { + _apiKey = apiKey; + _httpFactory = factory; + switch (model) + { + case ChatGptModel.Gpt35Turbo: + _model = "gpt-3.5-turbo"; + break; + case ChatGptModel.Gpt4: + _model = "gpt-4"; + break; + case ChatGptModel.Gpt432k: + _model = "gpt-4-32k"; + break; + } + _maxHistory = chatHistory; + _maxTokens = maxTokens; + _minTokens = minTokens; + _ellieUsername = ellieUsername; + _encoding = GptEncoding.GetEncodingForModel(_model); + messages.Add(new GPTMessage(){Role = "user", Content = personality, Name = _ellieUsername}); + } + + public async Task Think(string input, string username) + { + messages.Add(new GPTMessage(){Role = "user", Content = input, Name = username}); + while(messages.Count > _maxHistory + 2){ + messages.RemoveAt(1); + } + int tokensUsed = 0; + foreach(GPTMessage message in messages){ + tokensUsed += _encoding.Encode(message.Content).Count; + } + tokensUsed *= 2; //Unsure why this is the case, but the token count chatgpt reports back is double what I calculate. + //check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why. + while(_maxTokens - tokensUsed <= _minTokens){ + if(messages.Count > 2){ + int tokens = _encoding.Encode(messages[1].Content).Count * 2; + tokensUsed -= tokens; + messages.RemoveAt(1); + } + else{ + return "Token count exceeded, please increase the number of tokens in the bot config and restart."; + } + } + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey); + var data = await http.PostAsJsonAsync(Uri, new Gpt3ApiRequest() + { + Model = _model, + Messages = messages, + MaxTokens = _maxTokens - tokensUsed, + Temperature = 1, + }); + var dataString = await data.Content.ReadAsStringAsync(); + try + { + var response = JsonConvert.DeserializeObject(dataString); + string message = response?.Choices[0]?.Message?.Content; + //Can't rely on the return to except, now that we need to add it to the messages list. + _ = message ?? throw new ArgumentNullException(nameof(message)); + messages.Add(new GPTMessage(){Role = "assistant", Content = message, Name = _ellieUsername}); + return message; + } + catch + { + Log.Warning("Unexpected GPT-3 response received: {ResponseString}", dataString); + return null; + } + } +} + diff --git a/src/EllieBot/Modules/Games/Games.cs b/src/EllieBot/Modules/Games/Games.cs new file mode 100644 index 0000000..c14d6ee --- /dev/null +++ b/src/EllieBot/Modules/Games/Games.cs @@ -0,0 +1,47 @@ +#nullable disable +using EllieBot.Modules.Games.Services; + +namespace EllieBot.Modules.Games; + +/* more games +- Shiritori +- Simple RPG adventure +*/ +public partial class Games : EllieModule +{ + private readonly IImageCache _images; + private readonly IHttpClientFactory _httpFactory; + private readonly Random _rng = new(); + + public Games(IImageCache images, IHttpClientFactory factory) + { + _images = images; + _httpFactory = factory; + } + + [Cmd] + public async Task Choose([Leftover] string list = null) + { + if (string.IsNullOrWhiteSpace(list)) + return; + var listArr = list.Split(';'); + if (listArr.Length < 2) + return; + var rng = new EllieRandom(); + await Response().Confirm("🤔", listArr[rng.Next(0, listArr.Length)]).SendAsync(); + } + + [Cmd] + public async Task EightBall([Leftover] string question = null) + { + if (string.IsNullOrWhiteSpace(question)) + return; + + var res = _service.GetEightballResponse(ctx.User.Id, question); + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithDescription(ctx.User.ToString()) + .AddField("❓ " + GetText(strs.question), question) + .AddField("🎱 " + GetText(strs._8ball), res)).SendAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/GamesConfig.cs b/src/EllieBot/Modules/Games/GamesConfig.cs new file mode 100644 index 0000000..1502c39 --- /dev/null +++ b/src/EllieBot/Modules/Games/GamesConfig.cs @@ -0,0 +1,174 @@ +#nullable disable +using Cloneable; +using EllieBot.Common.Yml; + +namespace EllieBot.Modules.Games.Common; + +[Cloneable] +public sealed partial class GamesConfig : ICloneable +{ + [Comment("DO NOT CHANGE")] + public int Version { get; set; } = 3; + + [Comment("Hangman related settings (.hangman command)")] + public HangmanConfig Hangman { get; set; } = new() + { + CurrencyReward = 0 + }; + + [Comment("Trivia related settings (.t command)")] + public TriviaConfig Trivia { get; set; } = new() + { + CurrencyReward = 0, + MinimumWinReq = 1 + }; + + [Comment("List of responses for the .8ball command. A random one will be selected every time")] + public List EightBallResponses { get; set; } = + [ + "Most definitely yes.", + "For sure.", + "Totally!", + "Of course!", + "As I see it, yes.", + "My sources say yes.", + "Yes.", + "Most likely.", + "Perhaps...", + "Maybe...", + "Hm, not sure.", + "It is uncertain.", + "Ask me again later.", + "Don't count on it.", + "Probably not.", + "Very doubtful.", + "Most likely no.", + "Nope.", + "No.", + "My sources say no.", + "Don't even think about it.", + "Definitely no.", + "NO - It may cause disease contraction!" + ]; + + [Comment("List of animals which will be used for the animal race game (.race)")] + public List RaceAnimals { get; set; } = + [ + new() + { + Icon = "🐼", + Name = "Panda" + }, + + new() + { + Icon = "🐻", + Name = "Bear" + }, + + new() + { + Icon = "🐧", + Name = "Pengu" + }, + + new() + { + Icon = "🐨", + Name = "Koala" + }, + + new() + { + Icon = "🐬", + Name = "Dolphin" + }, + + new() + { + Icon = "🐞", + Name = "Ladybird" + }, + + new() + { + Icon = "🦀", + Name = "Crab" + }, + + new() + { + Icon = "🦄", + Name = "Unicorn" + } + ]; + + [Comment(@"Which chatbot API should bot use. +'cleverbot' - bot will use Cleverbot API. +'gpt3' - bot will use GPT-3 API")] + public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt3; + + public ChatGptConfig ChatGpt { get; set; } = new(); +} + +[Cloneable] +public sealed partial class ChatGptConfig +{ + [Comment(@"Which GPT-3 Model should bot use. + gpt35turbo - cheapest + gpt4 - 30x more expensive, higher quality + gp432k - same model as above, but with a 32k token limit")] + public ChatGptModel ModelName { get; set; } = ChatGptModel.Gpt35Turbo; + + [Comment(@"How should the chat bot behave, what's its personality? (Usage of this counts towards the max tokens)")] + public string PersonalityPrompt { get; set; } = "You are a chat bot willing to have a conversation with anyone about anything."; + + [Comment(@"The maximum number of messages in a conversation that can be remembered. (This will increase the number of tokens used)")] + public int ChatHistory { get; set; } = 5; + + [Comment(@"The maximum number of tokens to use per GPT-3 API call")] + public int MaxTokens { get; set; } = 100; + + [Comment(@"The minimum number of tokens to use per GPT-3 API call, such that chat history is removed to make room.")] + public int MinTokens { get; set; } = 30; +} + +[Cloneable] +public sealed partial class HangmanConfig +{ + [Comment("The amount of currency awarded to the winner of a hangman game")] + public long CurrencyReward { get; set; } +} + +[Cloneable] +public sealed partial class TriviaConfig +{ + [Comment("The amount of currency awarded to the winner of the trivia game.")] + public long CurrencyReward { get; set; } + + [Comment(""" + Users won't be able to start trivia games which have + a smaller win requirement than the one specified by this setting. + """)] + public int MinimumWinReq { get; set; } = 1; +} + +[Cloneable] +public sealed partial class RaceAnimal +{ + public string Icon { get; set; } + public string Name { get; set; } +} + +public enum ChatBotImplementation +{ + Cleverbot, + Gpt3 +} + +public enum ChatGptModel +{ + Gpt35Turbo, + Gpt4, + Gpt432k +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/GamesConfigService.cs b/src/EllieBot/Modules/Games/GamesConfigService.cs new file mode 100644 index 0000000..6446c23 --- /dev/null +++ b/src/EllieBot/Modules/Games/GamesConfigService.cs @@ -0,0 +1,94 @@ +#nullable disable +using EllieBot.Common.Configs; +using EllieBot.Modules.Games.Common; + +namespace EllieBot.Modules.Games.Services; + +public sealed class GamesConfigService : ConfigServiceBase +{ + private const string FILE_PATH = "data/games.yml"; + private static readonly TypedKey _changeKey = new("config.games.updated"); + public override string Name { get; } = "games"; + + public GamesConfigService(IConfigSeria serializer, IPubSub pubSub) + : base(FILE_PATH, serializer, pubSub, _changeKey) + { + AddParsedProp("trivia.min_win_req", + gs => gs.Trivia.MinimumWinReq, + int.TryParse, + ConfigPrinters.ToString, + val => val > 0); + AddParsedProp("trivia.currency_reward", + gs => gs.Trivia.CurrencyReward, + long.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + AddParsedProp("hangman.currency_reward", + gs => gs.Hangman.CurrencyReward, + long.TryParse, + ConfigPrinters.ToString, + val => val >= 0); + AddParsedProp("chatbot", + gs => gs.ChatBot, + ConfigParsers.InsensitiveEnum, + ConfigPrinters.ToString); + AddParsedProp("gpt.modelName", + gs => gs.ChatGpt.ModelName, + ConfigParsers.InsensitiveEnum, + ConfigPrinters.ToString); + AddParsedProp("gpt.personality", + gs => gs.ChatGpt.PersonalityPrompt, + ConfigParsers.String, + ConfigPrinters.ToString); + AddParsedProp("gpt.chathistory", + gs => gs.ChatGpt.ChatHistory, + int.TryParse, + ConfigPrinters.ToString, + val => val > 0); + AddParsedProp("gpt.max_tokens", + gs => gs.ChatGpt.MaxTokens, + int.TryParse, + ConfigPrinters.ToString, + val => val > 0); + AddParsedProp("gpt.min_tokens", + gs => gs.ChatGpt.MinTokens, + int.TryParse, + ConfigPrinters.ToString, + val => val > 0); + + Migrate(); + } + + private void Migrate() + { + if (data.Version < 1) + { + ModifyConfig(c => + { + c.Version = 1; + c.Hangman = new() + { + CurrencyReward = 0 + }; + }); + } + + if (data.Version < 2) + { + ModifyConfig(c => + { + c.Version = 2; + c.ChatBot = ChatBotImplementation.Cleverbot; + }); + } + + if (data.Version < 3) + { + ModifyConfig(c => + { + c.Version = 3; + c.ChatGpt.ModelName = ChatGptModel.Gpt35Turbo; + }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/GamesService.cs b/src/EllieBot/Modules/Games/GamesService.cs new file mode 100644 index 0000000..9f4f61b --- /dev/null +++ b/src/EllieBot/Modules/Games/GamesService.cs @@ -0,0 +1,118 @@ +#nullable disable +using Microsoft.Extensions.Caching.Memory; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Modules.Games.Common; +using EllieBot.Modules.Games.Common.Acrophobia; +using EllieBot.Modules.Games.Common.Nunchi; +using Newtonsoft.Json; + +namespace EllieBot.Modules.Games.Services; + +public class GamesService : IEService, IReadyExecutor +{ + private const string TYPING_ARTICLES_PATH = "data/typing_articles3.json"; + + public ConcurrentDictionary GirlRatings { get; } = new(); + + public IReadOnlyList EightBallResponses + => _gamesConfig.Data.EightBallResponses; + + public List TypingArticles { get; } = new(); + + //channelId, game + public ConcurrentDictionary AcrophobiaGames { get; } = new(); + public Dictionary TicTacToeGames { get; } = new(); + public ConcurrentDictionary RunningContests { get; } = new(); + public ConcurrentDictionary NunchiGames { get; } = new(); + + public AsyncLazy Ratings { get; } + private readonly GamesConfigService _gamesConfig; + + private readonly IHttpClientFactory _httpFactory; + private readonly IMemoryCache _8BallCache; + private readonly Random _rng; + + public GamesService(GamesConfigService gamesConfig, IHttpClientFactory httpFactory) + { + _gamesConfig = gamesConfig; + _httpFactory = httpFactory; + _8BallCache = new MemoryCache(new MemoryCacheOptions + { + SizeLimit = 500_000 + }); + + Ratings = new(GetRatingTexts); + _rng = new EllieRandom(); + + try + { + TypingArticles = JsonConvert.DeserializeObject>(File.ReadAllText(TYPING_ARTICLES_PATH)); + } + catch (Exception ex) + { + Log.Warning(ex, "Error while loading typing articles: {ErrorMessage}", ex.Message); + TypingArticles = new(); + } + } + + public async Task OnReadyAsync() + { + // reset rating once a day + using var timer = new PeriodicTimer(TimeSpan.FromDays(1)); + while (await timer.WaitForNextTickAsync()) + GirlRatings.Clear(); + } + + private async Task GetRatingTexts() + { + using var http = _httpFactory.CreateClient(); + var text = await http.GetStringAsync( + "https://nadeko-pictures.nyc3.digitaloceanspaces.com/other/rategirl/rates.json"); + return JsonConvert.DeserializeObject(text); + } + + public void AddTypingArticle(IUser user, string text) + { + TypingArticles.Add(new() + { + Source = user.ToString(), + Extra = $"Text added on {DateTime.UtcNow} by {user}.", + Text = text.SanitizeMentions(true) + }); + + File.WriteAllText(TYPING_ARTICLES_PATH, JsonConvert.SerializeObject(TypingArticles)); + } + + public string GetEightballResponse(ulong userId, string question) + => _8BallCache.GetOrCreate($"8ball:{userId}:{question}", + e => + { + e.Size = question.Length; + e.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12); + return EightBallResponses[_rng.Next(0, EightBallResponses.Count)]; + }); + + public TypingArticle RemoveTypingArticle(int index) + { + var articles = TypingArticles; + if (index < 0 || index >= articles.Count) + return null; + + var removed = articles[index]; + TypingArticles.RemoveAt(index); + + File.WriteAllText(TYPING_ARTICLES_PATH, JsonConvert.SerializeObject(articles)); + return removed; + } + + public class RatingTexts + { + public string Nog { get; set; } + public string Tra { get; set; } + public string Fun { get; set; } + public string Uni { get; set; } + public string Wif { get; set; } + public string Dat { get; set; } + public string Dan { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/GirlRating.cs b/src/EllieBot/Modules/Games/GirlRating.cs new file mode 100644 index 0000000..4576216 --- /dev/null +++ b/src/EllieBot/Modules/Games/GirlRating.cs @@ -0,0 +1,61 @@ +#nullable disable +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Games.Common; + +public class GirlRating +{ + public double Crazy { get; } + public double Hot { get; } + public int Roll { get; } + public string Advice { get; } + + public AsyncLazy Stream { get; } + private readonly IImageCache _images; + + public GirlRating( + IImageCache images, + double crazy, + double hot, + int roll, + string advice) + { + _images = images; + Crazy = crazy; + Hot = hot; + Roll = roll; + Advice = advice; // convenient to have it here, even though atm there are only few different ones. + + Stream = new(async () => + { + try + { + var bgBytes = await _images.GetRategirlBgAsync(); + using var img = Image.Load(bgBytes); + const int minx = 35; + const int miny = 385; + const int length = 345; + + var pointx = (int)(minx + (length * (Hot / 10))); + var pointy = (int)(miny - (length * ((Crazy - 4) / 6))); + + var dotBytes = await _images.GetRategirlDotAsync(); + using (var pointImg = Image.Load(dotBytes)) + { + img.Mutate(x => x.DrawImage(pointImg, new(pointx - 10, pointy - 10), new GraphicsOptions())); + } + + var imgStream = new MemoryStream(); + img.SaveAsPng(imgStream); + return imgStream; + } + catch (Exception ex) + { + Log.Warning(ex, "Error getting RateGirl image"); + return null; + } + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/DefaultHangmanSource.cs b/src/EllieBot/Modules/Games/Hangman/DefaultHangmanSource.cs new file mode 100644 index 0000000..333e8f0 --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/DefaultHangmanSource.cs @@ -0,0 +1,64 @@ +using EllieBot.Common.Yml; +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Modules.Games.Hangman; + +public sealed class DefaultHangmanSource : IHangmanSource +{ + private IReadOnlyDictionary termsDict = new Dictionary(); + private readonly Random _rng; + + public DefaultHangmanSource() + { + _rng = new EllieRandom(); + Reload(); + } + + public void Reload() + { + if (!Directory.Exists("data/hangman")) + { + Log.Error("Hangman game won't work. Folder 'data/hangman' is missing"); + return; + } + + var qs = new Dictionary(); + foreach (var file in Directory.EnumerateFiles("data/hangman/", "*.yml")) + { + try + { + var data = Yaml.Deserializer.Deserialize(File.ReadAllText(file)); + qs[Path.GetFileNameWithoutExtension(file).ToLowerInvariant()] = data; + } + catch (Exception ex) + { + Log.Error(ex, "Loading {HangmanFile} failed", file); + } + } + + termsDict = qs; + + Log.Information("Loaded {HangmanCategoryCount} hangman categories", qs.Count); + } + + public IReadOnlyCollection GetCategories() + => termsDict.Keys.ToList(); + + public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term) + { + if (category is null) + { + var cats = GetCategories(); + category = cats.ElementAt(_rng.Next(0, cats.Count)); + } + + if (termsDict.TryGetValue(category, out var terms)) + { + term = terms[_rng.Next(0, terms.Length)]; + return true; + } + + term = null; + return false; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/HangmanCommands.cs b/src/EllieBot/Modules/Games/Hangman/HangmanCommands.cs new file mode 100644 index 0000000..acc0323 --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/HangmanCommands.cs @@ -0,0 +1,76 @@ +using EllieBot.Modules.Games.Hangman; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class HangmanCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Hangmanlist() + => await Response().Confirm(GetText(strs.hangman_types(prefix)), _service.GetHangmanTypes().Join('\n')).SendAsync(); + + private static string Draw(HangmanGame.State state) + => $""" + . ┌─────┐ + .┃...............┋ + .┃...............┋ + .┃{(state.Errors > 0 ? ".............😲" : "")} + .┃{(state.Errors > 1 ? "............./" : "")} {(state.Errors > 2 ? "|" : "")} {(state.Errors > 3 ? "\\" : "")} + .┃{(state.Errors > 4 ? "............../" : "")} {(state.Errors > 5 ? "\\" : "")} + /-\ + """; + + public static EmbedBuilder GetEmbed(IMessageSenderService sender, HangmanGame.State state) + { + if (state.Phase == HangmanGame.Phase.Running) + { + return sender.CreateEmbed() + .WithOkColor() + .AddField("Hangman", Draw(state)) + .AddField("Guess", Format.Code(state.Word)) + .WithFooter(state.MissedLetters.Join(' ')); + } + + if (state.Phase == HangmanGame.Phase.Ended && state.Failed) + { + return sender.CreateEmbed() + .WithErrorColor() + .AddField("Hangman", Draw(state)) + .AddField("Guess", Format.Code(state.Word)) + .WithFooter(state.MissedLetters.Join(' ')); + } + + return sender.CreateEmbed() + .WithOkColor() + .AddField("Hangman", Draw(state)) + .AddField("Guess", Format.Code(state.Word)) + .WithFooter(state.MissedLetters.Join(' ')); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Hangman([Leftover] string? type = null) + { + if (!_service.StartHangman(ctx.Channel.Id, type, out var hangman)) + { + await Response().Error(strs.hangman_running).SendAsync(); + return; + } + + var eb = GetEmbed(_sender, hangman); + eb.WithDescription(GetText(strs.hangman_game_started)); + await Response().Embed(eb).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task HangmanStop() + { + if (await _service.StopHangman(ctx.Channel.Id)) + await Response().Confirm(strs.hangman_stopped).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/HangmanGame.cs b/src/EllieBot/Modules/Games/Hangman/HangmanGame.cs new file mode 100644 index 0000000..1625b55 --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/HangmanGame.cs @@ -0,0 +1,111 @@ +#nullable disable +namespace EllieBot.Modules.Games.Hangman; + +public sealed class HangmanGame +{ + public enum GuessResult { NoAction, AlreadyTried, Incorrect, Guess, Win } + + public enum Phase { Running, Ended } + + private Phase CurrentPhase { get; set; } + + private readonly HashSet _incorrect = new(); + private readonly HashSet _correct = new(); + private readonly HashSet _remaining = new(); + + private readonly string _word; + private readonly string _imageUrl; + + public HangmanGame(HangmanTerm term) + { + _word = term.Word; + _imageUrl = term.ImageUrl; + + _remaining = _word.ToLowerInvariant().Where(x => char.IsLetter(x)).Select(char.ToLowerInvariant).ToHashSet(); + } + + public State GetState(GuessResult guessResult = GuessResult.NoAction) + => new(_incorrect.Count, + CurrentPhase, + CurrentPhase == Phase.Ended ? _word : GetScrambledWord(), + guessResult, + _incorrect.ToList(), + CurrentPhase == Phase.Ended ? _imageUrl : string.Empty); + + private string GetScrambledWord() + { + Span output = stackalloc char[_word.Length * 2]; + for (var i = 0; i < _word.Length; i++) + { + var ch = _word[i]; + if (ch == ' ') + output[i * 2] = ' '; + if (!char.IsLetter(ch) || !_remaining.Contains(char.ToLowerInvariant(ch))) + output[i * 2] = ch; + else + output[i * 2] = '_'; + + output[(i * 2) + 1] = ' '; + } + + return new(output); + } + + public State Guess(string guess) + { + if (CurrentPhase != Phase.Running) + return GetState(); + + guess = guess.Trim(); + if (guess.Length > 1) + { + if (guess.Equals(_word, StringComparison.InvariantCultureIgnoreCase)) + { + CurrentPhase = Phase.Ended; + return GetState(GuessResult.Win); + } + + return GetState(); + } + + var charGuess = guess[0]; + if (!char.IsLetter(charGuess)) + return GetState(); + + if (_incorrect.Contains(charGuess) || _correct.Contains(charGuess)) + return GetState(GuessResult.AlreadyTried); + + if (_remaining.Remove(charGuess)) + { + if (_remaining.Count == 0) + { + CurrentPhase = Phase.Ended; + return GetState(GuessResult.Win); + } + + _correct.Add(charGuess); + return GetState(GuessResult.Guess); + } + + _incorrect.Add(charGuess); + if (_incorrect.Count > 5) + { + CurrentPhase = Phase.Ended; + return GetState(GuessResult.Incorrect); + } + + return GetState(GuessResult.Incorrect); + } + + public record State( + int Errors, + Phase Phase, + string Word, + GuessResult GuessResult, + List MissedLetters, + string ImageUrl) + { + public bool Failed + => Errors > 5; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/HangmanService.cs b/src/EllieBot/Modules/Games/Hangman/HangmanService.cs new file mode 100644 index 0000000..0b5c9c0 --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/HangmanService.cs @@ -0,0 +1,136 @@ +using Microsoft.Extensions.Caching.Memory; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Modules.Games.Services; +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Modules.Games.Hangman; + +public sealed class HangmanService : IHangmanService, IExecNoCommand +{ + private readonly ConcurrentDictionary _hangmanGames = new(); + private readonly IHangmanSource _source; + private readonly IMessageSenderService _sender; + private readonly GamesConfigService _gcs; + private readonly ICurrencyService _cs; + private readonly IMemoryCache _cdCache; + private readonly object _locker = new(); + + public HangmanService( + IHangmanSource source, + IMessageSenderService sender, + GamesConfigService gcs, + ICurrencyService cs, + IMemoryCache cdCache) + { + _source = source; + _sender = sender; + _gcs = gcs; + _cs = cs; + _cdCache = cdCache; + } + + public bool StartHangman(ulong channelId, string? category, [NotNullWhen(true)] out HangmanGame.State? state) + { + state = null; + if (!_source.GetTerm(category, out var term)) + return false; + + + var game = new HangmanGame(term); + lock (_locker) + { + var hc = _hangmanGames.GetOrAdd(channelId, game); + if (hc == game) + { + state = hc.GetState(); + return true; + } + + return false; + } + } + + public ValueTask StopHangman(ulong channelId) + { + lock (_locker) + { + if (_hangmanGames.TryRemove(channelId, out _)) + return new(true); + } + + return new(false); + } + + public IReadOnlyCollection GetHangmanTypes() + => _source.GetCategories(); + + public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg) + { + if (_hangmanGames.ContainsKey(msg.Channel.Id)) + { + if (string.IsNullOrWhiteSpace(msg.Content)) + return; + + if (_cdCache.TryGetValue(msg.Author.Id, out _)) + return; + + HangmanGame.State state; + long rew = 0; + lock (_locker) + { + if (!_hangmanGames.TryGetValue(msg.Channel.Id, out var game)) + return; + + state = game.Guess(msg.Content.ToLowerInvariant()); + + if (state.GuessResult == HangmanGame.GuessResult.NoAction) + return; + + if (state.GuessResult is HangmanGame.GuessResult.Incorrect or HangmanGame.GuessResult.AlreadyTried) + { + _cdCache.Set(msg.Author.Id, + string.Empty, + new MemoryCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3) + }); + } + + if (state.Phase == HangmanGame.Phase.Ended) + { + if (_hangmanGames.TryRemove(msg.Channel.Id, out _)) + rew = _gcs.Data.Hangman.CurrencyReward; + } + } + + if (rew > 0) + await _cs.AddAsync(msg.Author, rew, new("hangman", "win")); + + await SendState((ITextChannel)msg.Channel, msg.Author, msg.Content, state); + } + } + + private Task SendState( + ITextChannel channel, + IUser user, + string content, + HangmanGame.State state) + { + var embed = Games.HangmanCommands.GetEmbed(_sender, state); + if (state.GuessResult == HangmanGame.GuessResult.Guess) + embed.WithDescription($"{user} guessed the letter {content}!").WithOkColor(); + else if (state.GuessResult == HangmanGame.GuessResult.Incorrect && state.Failed) + embed.WithDescription($"{user} Letter {content} doesn't exist! Game over!").WithErrorColor(); + else if (state.GuessResult == HangmanGame.GuessResult.Incorrect) + embed.WithDescription($"{user} Letter {content} doesn't exist!").WithErrorColor(); + else if (state.GuessResult == HangmanGame.GuessResult.AlreadyTried) + embed.WithDescription($"{user} Letter {content} has already been used.").WithPendingColor(); + else if (state.GuessResult == HangmanGame.GuessResult.Win) + embed.WithDescription($"{user} won!").WithOkColor(); + + if (!string.IsNullOrWhiteSpace(state.ImageUrl) && Uri.IsWellFormedUriString(state.ImageUrl, UriKind.Absolute)) + embed.WithImageUrl(state.ImageUrl); + + return _sender.Response(channel).Embed(embed).SendAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/HangmanTerm.cs b/src/EllieBot/Modules/Games/Hangman/HangmanTerm.cs new file mode 100644 index 0000000..22e5144 --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/HangmanTerm.cs @@ -0,0 +1,8 @@ +#nullable disable +namespace EllieBot.Modules.Games.Hangman; + +public sealed class HangmanTerm +{ + public string Word { get; set; } + public string ImageUrl { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/IHangmanService.cs b/src/EllieBot/Modules/Games/Hangman/IHangmanService.cs new file mode 100644 index 0000000..da8d027 --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/IHangmanService.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Modules.Games.Hangman; + +public interface IHangmanService +{ + bool StartHangman(ulong channelId, string? category, [NotNullWhen(true)] out HangmanGame.State? hangmanController); + ValueTask StopHangman(ulong channelId); + IReadOnlyCollection GetHangmanTypes(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Hangman/IHangmanSource.cs b/src/EllieBot/Modules/Games/Hangman/IHangmanSource.cs new file mode 100644 index 0000000..d28199b --- /dev/null +++ b/src/EllieBot/Modules/Games/Hangman/IHangmanSource.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Modules.Games.Hangman; + +public interface IHangmanSource : IEService +{ + public IReadOnlyCollection GetCategories(); + public void Reload(); + public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Nunchi/Nunchi.cs b/src/EllieBot/Modules/Games/Nunchi/Nunchi.cs new file mode 100644 index 0000000..6fa579c --- /dev/null +++ b/src/EllieBot/Modules/Games/Nunchi/Nunchi.cs @@ -0,0 +1,183 @@ +#nullable disable +using System.Collections.Immutable; + +namespace EllieBot.Modules.Games.Common.Nunchi; + +public sealed class NunchiGame : IDisposable +{ + public enum Phase + { + Joining, + Playing, + WaitingForNextRound, + Ended + } + + private const int KILL_TIMEOUT = 20 * 1000; + private const int NEXT_ROUND_TIMEOUT = 5 * 1000; + + public event Func OnGameStarted; + public event Func OnRoundStarted; + public event Func OnUserGuessed; + public event Func OnRoundEnded; // tuple of the user who failed + public event Func OnGameEnded; // name of the user who won + + public int CurrentNumber { get; private set; } = new EllieRandom().Next(0, 100); + public Phase CurrentPhase { get; private set; } = Phase.Joining; + + public ImmutableArray<(ulong Id, string Name)> Participants + => participants.ToImmutableArray(); + + public int ParticipantCount + => participants.Count; + + private readonly SemaphoreSlim _locker = new(1, 1); + + private HashSet<(ulong Id, string Name)> participants = []; + private readonly HashSet<(ulong Id, string Name)> _passed = []; + private Timer killTimer; + + public NunchiGame(ulong creatorId, string creatorName) + => participants.Add((creatorId, creatorName)); + + public async Task Join(ulong userId, string userName) + { + await _locker.WaitAsync(); + try + { + if (CurrentPhase != Phase.Joining) + return false; + + return participants.Add((userId, userName)); + } + finally { _locker.Release(); } + } + + public async Task Initialize() + { + CurrentPhase = Phase.Joining; + await Task.Delay(30000); + await _locker.WaitAsync(); + try + { + if (participants.Count < 3) + { + CurrentPhase = Phase.Ended; + return false; + } + + killTimer = new(async _ => + { + await _locker.WaitAsync(); + try + { + if (CurrentPhase != Phase.Playing) + return; + + //if some players took too long to type a number, boot them all out and start a new round + participants = new HashSet<(ulong, string)>(_passed); + EndRound(); + } + finally { _locker.Release(); } + }, + null, + KILL_TIMEOUT, + KILL_TIMEOUT); + + CurrentPhase = Phase.Playing; + _ = OnGameStarted?.Invoke(this); + _ = OnRoundStarted?.Invoke(this, CurrentNumber); + return true; + } + finally { _locker.Release(); } + } + + public async Task Input(ulong userId, string userName, int input) + { + await _locker.WaitAsync(); + try + { + if (CurrentPhase != Phase.Playing) + return; + + var userTuple = (Id: userId, Name: userName); + + // if the user is not a member of the race, + // or he already successfully typed the number + // ignore the input + if (!participants.Contains(userTuple) || !_passed.Add(userTuple)) + return; + + //if the number is correct + if (CurrentNumber == input - 1) + { + //increment current number + ++CurrentNumber; + if (_passed.Count == participants.Count - 1) + { + // if only n players are left, and n - 1 type the correct number, round is over + + // if only 2 players are left, game is over + if (participants.Count == 2) + { + killTimer.Change(Timeout.Infinite, Timeout.Infinite); + CurrentPhase = Phase.Ended; + _ = OnGameEnded?.Invoke(this, userTuple.Name); + } + else // else just start the new round without the user who was the last + { + var failure = participants.Except(_passed).First(); + + OnUserGuessed?.Invoke(this); + EndRound(failure); + return; + } + } + + OnUserGuessed?.Invoke(this); + } + else + { + //if the user failed + + EndRound(userTuple); + } + } + finally { _locker.Release(); } + } + + private void EndRound((ulong, string)? failure = null) + { + killTimer.Change(KILL_TIMEOUT, KILL_TIMEOUT); + CurrentNumber = new EllieRandom().Next(0, 100); // reset the counter + _passed.Clear(); // reset all users who passed (new round starts) + if (failure is not null) + participants.Remove(failure.Value); // remove the dude who failed from the list of players + + _ = OnRoundEnded?.Invoke(this, failure); + if (participants.Count <= 1) // means we have a winner or everyone was booted out + { + killTimer.Change(Timeout.Infinite, Timeout.Infinite); + CurrentPhase = Phase.Ended; + _ = OnGameEnded?.Invoke(this, participants.Count > 0 ? participants.First().Name : null); + return; + } + + CurrentPhase = Phase.WaitingForNextRound; + Task.Run(async () => + { + await Task.Delay(NEXT_ROUND_TIMEOUT); + CurrentPhase = Phase.Playing; + _ = OnRoundStarted?.Invoke(this, CurrentNumber); + }); + } + + public void Dispose() + { + OnGameEnded = null; + OnGameStarted = null; + OnRoundEnded = null; + OnRoundStarted = null; + OnUserGuessed = null; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Nunchi/NunchiCommands.cs b/src/EllieBot/Modules/Games/Nunchi/NunchiCommands.cs new file mode 100644 index 0000000..80e6c42 --- /dev/null +++ b/src/EllieBot/Modules/Games/Nunchi/NunchiCommands.cs @@ -0,0 +1,114 @@ +#nullable disable +using EllieBot.Modules.Games.Common.Nunchi; +using EllieBot.Modules.Games.Services; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class NunchiCommands : EllieModule + { + private readonly DiscordSocketClient _client; + + public NunchiCommands(DiscordSocketClient client) + => _client = client; + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Nunchi() + { + var newNunchi = new NunchiGame(ctx.User.Id, ctx.User.ToString()); + NunchiGame nunchi; + + //if a game was already active + if ((nunchi = _service.NunchiGames.GetOrAdd(ctx.Guild.Id, newNunchi)) != newNunchi) + { + // join it + // if you failed joining, that means game is running or just ended + if (!await nunchi.Join(ctx.User.Id, ctx.User.ToString())) + return; + + await Response().Error(strs.nunchi_joined(nunchi.ParticipantCount)).SendAsync(); + return; + } + + + try { await Response().Confirm(strs.nunchi_created).SendAsync(); } + catch { } + + nunchi.OnGameEnded += NunchiOnGameEnded; + //nunchi.OnGameStarted += Nunchi_OnGameStarted; + nunchi.OnRoundEnded += Nunchi_OnRoundEnded; + nunchi.OnUserGuessed += Nunchi_OnUserGuessed; + nunchi.OnRoundStarted += Nunchi_OnRoundStarted; + _client.MessageReceived += ClientMessageReceived; + + var success = await nunchi.Initialize(); + if (!success) + { + if (_service.NunchiGames.TryRemove(ctx.Guild.Id, out var game)) + game.Dispose(); + await Response().Confirm(strs.nunchi_failed_to_start).SendAsync(); + } + + Task ClientMessageReceived(SocketMessage arg) + { + _ = Task.Run(async () => + { + if (arg.Channel.Id != ctx.Channel.Id) + return; + + if (!int.TryParse(arg.Content, out var number)) + return; + try + { + await nunchi.Input(arg.Author.Id, arg.Author.ToString(), number); + } + catch + { + } + }); + return Task.CompletedTask; + } + + Task NunchiOnGameEnded(NunchiGame arg1, string arg2) + { + if (_service.NunchiGames.TryRemove(ctx.Guild.Id, out var game)) + { + _client.MessageReceived -= ClientMessageReceived; + game.Dispose(); + } + + if (arg2 is null) + return Response().Confirm(strs.nunchi_ended_no_winner).SendAsync(); + return Response().Confirm(strs.nunchi_ended(Format.Bold(arg2))).SendAsync(); + } + } + + private Task Nunchi_OnRoundStarted(NunchiGame arg, int cur) + => Response() + .Confirm(strs.nunchi_round_started(Format.Bold(arg.ParticipantCount.ToString()), + Format.Bold(cur.ToString()))) + .SendAsync(); + + private Task Nunchi_OnUserGuessed(NunchiGame arg) + => Response().Confirm(strs.nunchi_next_number(Format.Bold(arg.CurrentNumber.ToString()))).SendAsync(); + + private Task Nunchi_OnRoundEnded(NunchiGame arg1, (ulong Id, string Name)? arg2) + { + if (arg2.HasValue) + return Response().Confirm(strs.nunchi_round_ended(Format.Bold(arg2.Value.Name))).SendAsync(); + return Response() + .Confirm(strs.nunchi_round_ended_boot( + Format.Bold("\n" + + string.Join("\n, ", + arg1.Participants.Select(x + => x.Name))))) + .SendAsync(); // this won't work if there are too many users + } + + private Task Nunchi_OnGameStarted(NunchiGame arg) + => Response().Confirm(strs.nunchi_started(Format.Bold(arg.ParticipantCount.ToString()))).SendAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs b/src/EllieBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs new file mode 100644 index 0000000..65b8bbd --- /dev/null +++ b/src/EllieBot/Modules/Games/SpeedTyping/SpeedTypingCommands.cs @@ -0,0 +1,105 @@ +#nullable disable +using EllieBot.Modules.Games.Common; +using EllieBot.Modules.Games.Services; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class SpeedTypingCommands : EllieModule + { + private readonly GamesService _games; + private readonly DiscordSocketClient _client; + + public SpeedTypingCommands(DiscordSocketClient client, GamesService games) + { + _games = games; + _client = client; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + public async Task TypeStart(params string[] args) + { + var (options, _) = OptionsParser.ParseFrom(new TypingGame.Options(), args); + var channel = (ITextChannel)ctx.Channel; + + var game = _service.RunningContests.GetOrAdd(ctx.Guild.Id, + _ => new(_games, _client, channel, prefix, options, _sender)); + + if (game.IsActive) + await Response().Error($"Contest already running in {game.Channel.Mention} channel.").SendAsync(); + else + await game.Start(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task TypeStop() + { + if (_service.RunningContests.TryRemove(ctx.Guild.Id, out var game)) + { + await game.Stop(); + return; + } + + await Response().Error("No contest to stop on this channel.").SendAsync(); + } + + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task Typeadd([Leftover] string text) + { + if (string.IsNullOrWhiteSpace(text)) + return; + + _games.AddTypingArticle(ctx.User, text); + + await Response().Confirm("Added new article for typing game.").SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Typelist(int page = 1) + { + if (page < 1) + return; + + var articles = _games.TypingArticles.Skip((page - 1) * 15).Take(15).ToArray(); + + if (!articles.Any()) + { + await Response().Error($"{ctx.User.Mention} `No articles found on that page.`").SendAsync(); + return; + } + + var i = (page - 1) * 15; + await Response() + .Confirm("List of articles for Type Race", + string.Join("\n", articles.Select(a => $"`#{++i}` - {a.Text.TrimTo(50)}"))) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task Typedel(int index) + { + var removed = _service.RemoveTypingArticle(--index); + + if (removed is null) + return; + + var embed = _sender.CreateEmbed() + .WithTitle($"Removed typing article #{index + 1}") + .WithDescription(removed.Text.TrimTo(50)) + .WithOkColor(); + + await Response().Embed(embed).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/SpeedTyping/TypingArticle.cs b/src/EllieBot/Modules/Games/SpeedTyping/TypingArticle.cs new file mode 100644 index 0000000..cb55893 --- /dev/null +++ b/src/EllieBot/Modules/Games/SpeedTyping/TypingArticle.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Modules.Games.Common; + +public class TypingArticle +{ + public string Source { get; set; } + public string Extra { get; set; } + public string Text { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/SpeedTyping/TypingGame.cs b/src/EllieBot/Modules/Games/SpeedTyping/TypingGame.cs new file mode 100644 index 0000000..d712525 --- /dev/null +++ b/src/EllieBot/Modules/Games/SpeedTyping/TypingGame.cs @@ -0,0 +1,197 @@ +#nullable disable +using CommandLine; +using EllieBot.Modules.Games.Services; +using System.Diagnostics; + +namespace EllieBot.Modules.Games.Common; + +public class TypingGame +{ + public const float WORD_VALUE = 4.5f; + public ITextChannel Channel { get; } + public string CurrentSentence { get; private set; } + public bool IsActive { get; private set; } + private readonly Stopwatch _sw; + private readonly List _finishedUserIds; + private readonly DiscordSocketClient _client; + private readonly GamesService _games; + private readonly string _prefix; + private readonly Options _options; + private readonly IMessageSenderService _sender; + + public TypingGame( + GamesService games, + DiscordSocketClient client, + ITextChannel channel, + string prefix, + Options options, + IMessageSenderService sender) + { + _games = games; + _client = client; + _prefix = prefix; + _options = options; + _sender = sender; + + Channel = channel; + IsActive = false; + _sw = new(); + _finishedUserIds = new(); + } + + public async Task Stop() + { + if (!IsActive) + return false; + _client.MessageReceived -= AnswerReceived; + _finishedUserIds.Clear(); + IsActive = false; + _sw.Stop(); + _sw.Reset(); + try + { + await _sender.Response(Channel) + .Confirm("Typing contest stopped.") + .SendAsync(); + } + catch + { + } + + return true; + } + + public async Task Start() + { + if (IsActive) + return; // can't start running game + IsActive = true; + CurrentSentence = GetRandomSentence(); + var i = (int)(CurrentSentence.Length / WORD_VALUE * 1.7f); + try + { + await _sender.Response(Channel) + .Confirm( + $":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.") + .SendAsync(); + + + var time = _options.StartTime; + + var msg = await _sender.Response(Channel).Confirm($"Starting new typing contest in **{time}**...").SendAsync(); + + do + { + await Task.Delay(2000); + time -= 2; + try { await msg.ModifyAsync(m => m.Content = $"Starting new typing contest in **{time}**.."); } + catch { } + } while (time > 2); + + await msg.ModifyAsync(m => + { + m.Content = CurrentSentence.Replace(" ", " \x200B", StringComparison.InvariantCulture); + }); + _sw.Start(); + HandleAnswers(); + + while (i > 0) + { + await Task.Delay(1000); + i--; + if (!IsActive) + return; + } + } + catch { } + finally + { + await Stop(); + } + } + + public string GetRandomSentence() + { + if (_games.TypingArticles.Any()) + return _games.TypingArticles[new EllieRandom().Next(0, _games.TypingArticles.Count)].Text; + return $"No typing articles found. Use {_prefix}typeadd command to add a new article for typing."; + } + + private void HandleAnswers() + => _client.MessageReceived += AnswerReceived; + + private Task AnswerReceived(SocketMessage imsg) + { + _ = Task.Run(async () => + { + try + { + if (imsg.Author.IsBot) + return; + if (imsg is not SocketUserMessage msg) + return; + + if (Channel is null || Channel.Id != msg.Channel.Id) + return; + + var guess = msg.Content; + + var distance = CurrentSentence.LevenshteinDistance(guess); + var decision = Judge(distance, guess.Length); + if (decision && !_finishedUserIds.Contains(msg.Author.Id)) + { + var elapsed = _sw.Elapsed; + var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60; + _finishedUserIds.Add(msg.Author.Id); + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle($"{msg.Author} finished the race!") + .AddField("Place", $"#{_finishedUserIds.Count}", true) + .AddField("WPM", $"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*", true) + .AddField("Errors", distance.ToString(), true); + + await _sender.Response(Channel) + .Embed(embed) + .SendAsync(); + + if (_finishedUserIds.Count % 4 == 0) + { + await _sender.Response(Channel) + .Confirm( + $""" + :exclamation: A lot of people finished, here is the text for those still typing: + + **{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B", StringComparison.InvariantCulture)).SanitizeMentions(true)}** + """) + .SendAsync(); + } + } + } + catch (Exception ex) + { + Log.Warning(ex, "Error receiving typing game answer: {ErrorMessage}", ex.Message); + } + }); + return Task.CompletedTask; + } + + private static bool Judge(int errors, int textLength) + => errors <= textLength / 25; + + public class Options : IEllieCommandOptions + { + [Option('s', + "start-time", + Default = 5, + Required = false, + HelpText = "How long does it take for the race to start. Default 5.")] + public int StartTime { get; set; } = 5; + + public void NormalizeOptions() + { + if (StartTime is < 3 or > 30) + StartTime = 5; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/TicTacToe/TicTacToe.cs b/src/EllieBot/Modules/Games/TicTacToe/TicTacToe.cs new file mode 100644 index 0000000..fa8070d --- /dev/null +++ b/src/EllieBot/Modules/Games/TicTacToe/TicTacToe.cs @@ -0,0 +1,307 @@ +#nullable disable +using CommandLine; +using System.Text; + +namespace EllieBot.Modules.Games.Common; + +public class TicTacToe +{ + public event Action OnEnded; + private readonly ITextChannel _channel; + private readonly IGuildUser[] _users; + private readonly int?[,] _state; + private Phase phase; + private int curUserIndex; + private readonly SemaphoreSlim _moveLock; + + private IGuildUser winner; + + private readonly string[] _numbers = + [ + ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" + ]; + + private IUserMessage previousMessage; + private Timer timeoutTimer; + private readonly IBotStrings _strings; + private readonly DiscordSocketClient _client; + private readonly Options _options; + private readonly IMessageSenderService _sender; + + public TicTacToe( + IBotStrings strings, + DiscordSocketClient client, + ITextChannel channel, + IGuildUser firstUser, + Options options, + IMessageSenderService sender) + { + _channel = channel; + _strings = strings; + _client = client; + _options = options; + _sender = sender; + + _users = [firstUser, null]; + _state = new int?[,] { { null, null, null }, { null, null, null }, { null, null, null } }; + + phase = Phase.Starting; + _moveLock = new(1, 1); + } + + private string GetText(LocStr key) + => _strings.GetText(key, _channel.GuildId); + + public string GetState() + { + var sb = new StringBuilder(); + for (var i = 0; i < _state.GetLength(0); i++) + { + for (var j = 0; j < _state.GetLength(1); j++) + { + sb.Append(_state[i, j] is null ? _numbers[(i * 3) + j] : GetIcon(_state[i, j])); + if (j < _state.GetLength(1) - 1) + sb.Append("┃"); + } + + if (i < _state.GetLength(0) - 1) + sb.AppendLine("\n──────────"); + } + + return sb.ToString(); + } + + public EmbedBuilder GetEmbed(string title = null) + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithDescription(Environment.NewLine + GetState()) + .WithAuthor(GetText(strs.vs(_users[0], _users[1]))); + + if (!string.IsNullOrWhiteSpace(title)) + embed.WithTitle(title); + + if (winner is null) + { + if (phase == Phase.Ended) + embed.WithFooter(GetText(strs.ttt_no_moves)); + else + embed.WithFooter(GetText(strs.ttt_users_move(_users[curUserIndex]))); + } + else + embed.WithFooter(GetText(strs.ttt_has_won(winner))); + + return embed; + } + + private static string GetIcon(int? val) + { + switch (val) + { + case 0: + return "❌"; + case 1: + return "⭕"; + case 2: + return "❎"; + case 3: + return "🅾"; + default: + return "⬛"; + } + } + + public async Task Start(IGuildUser user) + { + if (phase is Phase.Started or Phase.Ended) + { + await _sender.Response(_channel).Error(user.Mention + GetText(strs.ttt_already_running)).SendAsync(); + return; + } + + if (_users[0] == user) + { + await _sender.Response(_channel).Error(user.Mention + GetText(strs.ttt_against_yourself)).SendAsync(); + return; + } + + _users[1] = user; + + phase = Phase.Started; + + timeoutTimer = new(async _ => + { + await _moveLock.WaitAsync(); + try + { + if (phase == Phase.Ended) + return; + + phase = Phase.Ended; + if (_users[1] is not null) + { + winner = _users[curUserIndex ^= 1]; + var del = previousMessage?.DeleteAsync(); + try + { + await _sender.Response(_channel).Embed(GetEmbed(GetText(strs.ttt_time_expired))).SendAsync(); + if (del is not null) + await del; + } + catch { } + } + + OnEnded?.Invoke(this); + } + catch { } + finally + { + _moveLock.Release(); + } + }, + null, + _options.TurnTimer * 1000, + Timeout.Infinite); + + _client.MessageReceived += Client_MessageReceived; + + + previousMessage = await _sender.Response(_channel).Embed(GetEmbed(GetText(strs.game_started))).SendAsync(); + } + + private bool IsDraw() + { + for (var i = 0; i < 3; i++) + for (var j = 0; j < 3; j++) + { + if (_state[i, j] is null) + return false; + } + + return true; + } + + private Task Client_MessageReceived(SocketMessage msg) + { + _ = Task.Run(async () => + { + await _moveLock.WaitAsync(); + try + { + var curUser = _users[curUserIndex]; + if (phase == Phase.Ended || msg.Author?.Id != curUser.Id) + return; + + if (int.TryParse(msg.Content, out var index) + && --index >= 0 + && index <= 9 + && _state[index / 3, index % 3] is null) + { + _state[index / 3, index % 3] = curUserIndex; + + // i'm lazy + if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2]) + { + _state[index / 3, 0] = curUserIndex + 2; + _state[index / 3, 1] = curUserIndex + 2; + _state[index / 3, 2] = curUserIndex + 2; + + phase = Phase.Ended; + } + else if (_state[0, index % 3] == _state[1, index % 3] + && _state[1, index % 3] == _state[2, index % 3]) + { + _state[0, index % 3] = curUserIndex + 2; + _state[1, index % 3] = curUserIndex + 2; + _state[2, index % 3] = curUserIndex + 2; + + phase = Phase.Ended; + } + else if (curUserIndex == _state[0, 0] + && _state[0, 0] == _state[1, 1] + && _state[1, 1] == _state[2, 2]) + { + _state[0, 0] = curUserIndex + 2; + _state[1, 1] = curUserIndex + 2; + _state[2, 2] = curUserIndex + 2; + + phase = Phase.Ended; + } + else if (curUserIndex == _state[0, 2] + && _state[0, 2] == _state[1, 1] + && _state[1, 1] == _state[2, 0]) + { + _state[0, 2] = curUserIndex + 2; + _state[1, 1] = curUserIndex + 2; + _state[2, 0] = curUserIndex + 2; + + phase = Phase.Ended; + } + + var reason = string.Empty; + + if (phase == Phase.Ended) // if user won, stop receiving moves + { + reason = GetText(strs.ttt_matched_three); + winner = _users[curUserIndex]; + _client.MessageReceived -= Client_MessageReceived; + OnEnded?.Invoke(this); + } + else if (IsDraw()) + { + reason = GetText(strs.ttt_a_draw); + phase = Phase.Ended; + _client.MessageReceived -= Client_MessageReceived; + OnEnded?.Invoke(this); + } + + _ = Task.Run(async () => + { + var del1 = msg.DeleteAsync(); + var del2 = previousMessage?.DeleteAsync(); + try { previousMessage = await _sender.Response(_channel).Embed(GetEmbed(reason)).SendAsync(); } + catch { } + + try { await del1; } + catch { } + + try + { + if (del2 is not null) + await del2; + } + catch { } + }); + curUserIndex ^= 1; + + timeoutTimer.Change(_options.TurnTimer * 1000, Timeout.Infinite); + } + } + finally + { + _moveLock.Release(); + } + }); + + return Task.CompletedTask; + } + + public class Options : IEllieCommandOptions + { + [Option('t', "turn-timer", Required = false, Default = 15, HelpText = "Turn time in seconds. Default 15.")] + public int TurnTimer { get; set; } = 15; + + public void NormalizeOptions() + { + if (TurnTimer is < 5 or > 60) + TurnTimer = 15; + } + } + + private enum Phase + { + Starting, + Started, + Ended + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/TicTacToe/TicTacToeCommands.cs b/src/EllieBot/Modules/Games/TicTacToe/TicTacToeCommands.cs new file mode 100644 index 0000000..904f8db --- /dev/null +++ b/src/EllieBot/Modules/Games/TicTacToe/TicTacToeCommands.cs @@ -0,0 +1,54 @@ +#nullable disable +using EllieBot.Modules.Games.Common; +using EllieBot.Modules.Games.Services; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class TicTacToeCommands : EllieModule + { + private readonly SemaphoreSlim _sem = new(1, 1); + private readonly DiscordSocketClient _client; + + public TicTacToeCommands(DiscordSocketClient client) + => _client = client; + + [Cmd] + [RequireContext(ContextType.Guild)] + [EllieOptions] + public async Task TicTacToe(params string[] args) + { + var (options, _) = OptionsParser.ParseFrom(new TicTacToe.Options(), args); + var channel = (ITextChannel)ctx.Channel; + + await _sem.WaitAsync(1000); + try + { + if (_service.TicTacToeGames.TryGetValue(channel.Id, out var game)) + { + _ = Task.Run(async () => + { + await game.Start((IGuildUser)ctx.User); + }); + return; + } + + game = new(Strings, _client, channel, (IGuildUser)ctx.User, options, _sender); + _service.TicTacToeGames.Add(channel.Id, game); + await Response().Confirm(strs.ttt_created(ctx.User)).SendAsync(); + + game.OnEnded += _ => + { + _service.TicTacToeGames.Remove(channel.Id); + _sem.Dispose(); + }; + } + finally + { + _sem.Release(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/Games.cs b/src/EllieBot/Modules/Games/Trivia/Games.cs new file mode 100644 index 0000000..ff7ffbd --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/Games.cs @@ -0,0 +1,282 @@ +using System.Net; +using System.Text; +using EllieBot.Modules.Games.Common.Trivia; +using EllieBot.Modules.Games.Services; + +namespace EllieBot.Modules.Games; + +public partial class Games +{ + [Group] + public partial class TriviaCommands : EllieModule + { + private readonly ILocalDataCache _cache; + private readonly ICurrencyService _cs; + private readonly GamesConfigService _gamesConfig; + private readonly DiscordSocketClient _client; + + public TriviaCommands( + DiscordSocketClient client, + ILocalDataCache cache, + ICurrencyService cs, + GamesConfigService gamesConfig) + { + _cache = cache; + _cs = cs; + _gamesConfig = gamesConfig; + _client = client; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + [EllieOptions] + public async Task Trivia(params string[] args) + { + var (opts, _) = OptionsParser.ParseFrom(new TriviaOptions(), args); + + var config = _gamesConfig.Data; + if (opts.WinRequirement != 0 + && config.Trivia.MinimumWinReq > 0 + && config.Trivia.MinimumWinReq > opts.WinRequirement) + return; + + var trivia = new TriviaGame(opts, _cache); + if (_service.RunningTrivias.TryAdd(ctx.Guild.Id, trivia)) + { + RegisterEvents(trivia); + await trivia.RunAsync(); + return; + } + + if (_service.RunningTrivias.TryGetValue(ctx.Guild.Id, out var tg)) + { + await Response().Error(strs.trivia_already_running).SendAsync(); + await tg.TriggerQuestionAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Tl() + { + if (_service.RunningTrivias.TryGetValue(ctx.Guild.Id, out var trivia)) + { + await trivia.TriggerStatsAsync(); + return; + } + + await Response().Error(strs.trivia_none).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Tq() + { + var channel = (ITextChannel)ctx.Channel; + + if (_service.RunningTrivias.TryGetValue(channel.Guild.Id, out var trivia)) + { + if (trivia.Stop()) + { + try + { + await Response() + .Confirm(GetText(strs.trivia_game), GetText(strs.trivia_stopping)) + .SendAsync(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error sending trivia stopping message"); + } + } + + return; + } + + await Response().Error(strs.trivia_none).SendAsync(); + } + + private string GetLeaderboardString(TriviaGame tg) + { + var sb = new StringBuilder(); + + foreach (var (id, pts) in tg.GetLeaderboard()) + sb.AppendLine(GetText(strs.trivia_points(Format.Bold($"<@{id}>"), pts))); + + return sb.ToString(); + } + + private EmbedBuilder? questionEmbed = null; + private IUserMessage? questionMessage = null; + private bool showHowToQuit = false; + + private void RegisterEvents(TriviaGame trivia) + { + trivia.OnQuestion += OnTriviaQuestion; + trivia.OnHint += OnTriviaHint; + trivia.OnGuess += OnTriviaGuess; + trivia.OnEnded += OnTriviaEnded; + trivia.OnStats += OnTriviaStats; + trivia.OnTimeout += OnTriviaTimeout; + } + + private void UnregisterEvents(TriviaGame trivia) + { + trivia.OnQuestion -= OnTriviaQuestion; + trivia.OnHint -= OnTriviaHint; + trivia.OnGuess -= OnTriviaGuess; + trivia.OnEnded -= OnTriviaEnded; + trivia.OnStats -= OnTriviaStats; + trivia.OnTimeout -= OnTriviaTimeout; + } + + private async Task OnTriviaHint(TriviaGame game, TriviaQuestion question) + { + try + { + if (questionMessage is null) + { + game.Stop(); + return; + } + + if (questionEmbed is not null) + await questionMessage.ModifyAsync(m + => m.Embed = questionEmbed.WithFooter(question.GetHint()).Build()); + } + catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.NotFound or HttpStatusCode.Forbidden) + { + Log.Warning("Unable to edit message to show hint. Stopping trivia"); + game.Stop(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error editing trivia message"); + } + } + + private async Task OnTriviaQuestion(TriviaGame game, TriviaQuestion question) + { + try + { + questionEmbed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.trivia_game)) + .AddField(GetText(strs.category), question.Category) + .AddField(GetText(strs.question), question.Question); + + showHowToQuit = !showHowToQuit; + if (showHowToQuit) + questionEmbed.WithFooter(GetText(strs.trivia_quit($"{prefix}tq"))); + + if (Uri.IsWellFormedUriString(question.ImageUrl, UriKind.Absolute)) + questionEmbed.WithImageUrl(question.ImageUrl); + + questionMessage = await Response().Embed(questionEmbed).SendAsync(); + } + catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.NotFound + or HttpStatusCode.Forbidden + or HttpStatusCode.BadRequest) + { + Log.Warning("Unable to send trivia questions. Stopping immediately"); + game.Stop(); + throw; + } + } + + private async Task OnTriviaTimeout(TriviaGame _, TriviaQuestion question) + { + try + { + var embed = _sender.CreateEmbed() + .WithErrorColor() + .WithTitle(GetText(strs.trivia_game)) + .WithDescription(GetText(strs.trivia_times_up(Format.Bold(question.Answer)))); + + if (Uri.IsWellFormedUriString(question.AnswerImageUrl, UriKind.Absolute)) + embed.WithImageUrl(question.AnswerImageUrl); + + await Response().Embed(embed).SendAsync(); + } + catch + { + // ignored + } + } + + private async Task OnTriviaStats(TriviaGame game) + { + try + { + await Response().Confirm(GetText(strs.leaderboard), GetLeaderboardString(game)).SendAsync(); + } + catch + { + // ignored + } + } + + private async Task OnTriviaEnded(TriviaGame game) + { + try + { + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.trivia_ended)) + .WithTitle(GetText(strs.leaderboard)) + .WithDescription(GetLeaderboardString(game))).SendAsync(); + } + catch + { + // ignored + } + finally + { + _service.RunningTrivias.TryRemove(ctx.Guild.Id, out _); + } + + UnregisterEvents(game); + } + + private async Task OnTriviaGuess( + TriviaGame _, + TriviaUser user, + TriviaQuestion question, + bool isWin) + { + try + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.trivia_game)) + .WithDescription(GetText(strs.trivia_win(user.Name, + Format.Bold(question.Answer)))); + + if (Uri.IsWellFormedUriString(question.AnswerImageUrl, UriKind.Absolute)) + embed.WithImageUrl(question.AnswerImageUrl); + + + if (isWin) + { + await Response().Embed(embed).SendAsync(); + + var reward = _gamesConfig.Data.Trivia.CurrencyReward; + if (reward > 0) + await _cs.AddAsync(user.Id, reward, new("trivia", "win")); + + return; + } + + embed.WithDescription(GetText(strs.trivia_guess(user.Name, + Format.Bold(question.Answer)))); + + await Response().Embed(embed).SendAsync(); + } + catch + { + // ignored + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/QuestionPool/DefaultQuestionPool.cs b/src/EllieBot/Modules/Games/Trivia/QuestionPool/DefaultQuestionPool.cs new file mode 100644 index 0000000..b82dd62 --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/QuestionPool/DefaultQuestionPool.cs @@ -0,0 +1,22 @@ +namespace EllieBot.Modules.Games.Common.Trivia; + +public sealed class DefaultQuestionPool : IQuestionPool +{ + private readonly ILocalDataCache _cache; + private readonly EllieRandom _rng; + + public DefaultQuestionPool(ILocalDataCache cache) + { + _cache = cache; + _rng = new EllieRandom(); + } + public async Task GetQuestionAsync() + { + var pool = await _cache.GetTriviaQuestionsAsync(); + + if(pool is null or {Length: 0}) + return default; + + return new(pool[_rng.Next(0, pool.Length)]); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/QuestionPool/IQuestionPool.cs b/src/EllieBot/Modules/Games/Trivia/QuestionPool/IQuestionPool.cs new file mode 100644 index 0000000..636ae16 --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/QuestionPool/IQuestionPool.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Games.Common.Trivia; + +public interface IQuestionPool +{ + Task GetQuestionAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/QuestionPool/PokemonQuestionPool.cs b/src/EllieBot/Modules/Games/Trivia/QuestionPool/PokemonQuestionPool.cs new file mode 100644 index 0000000..53f56cf --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/QuestionPool/PokemonQuestionPool.cs @@ -0,0 +1,32 @@ +namespace EllieBot.Modules.Games.Common.Trivia; + +public sealed class PokemonQuestionPool : IQuestionPool +{ + public int QuestionsCount => 905; // xd + private readonly EllieRandom _rng; + private readonly ILocalDataCache _cache; + + public PokemonQuestionPool(ILocalDataCache cache) + { + _cache = cache; + _rng = new EllieRandom(); + } + + public async Task GetQuestionAsync() + { + var pokes = await _cache.GetPokemonMapAsync(); + + if (pokes is null or { Count: 0 }) + return default; + + var num = _rng.Next(1, QuestionsCount + 1); + return new(new() + { + Question = "Who's That Pokémon?", + Answer = pokes[num].ToTitleCase(), + Category = "Pokemon", + ImageUrl = $@"https://nadeko.bot/images/pokemon/shadows/{num}.png", + AnswerImageUrl = $@"https://nadeko.bot/images/pokemon/real/{num}.png" + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/TriviaGame.cs b/src/EllieBot/Modules/Games/Trivia/TriviaGame.cs new file mode 100644 index 0000000..4223104 --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/TriviaGame.cs @@ -0,0 +1,219 @@ +using System.Threading.Channels; +using Exception = System.Exception; + +namespace EllieBot.Modules.Games.Common.Trivia; + +public sealed class TriviaGame +{ + private readonly TriviaOptions _opts; + + + private readonly IQuestionPool _questionPool; + + #region Events + public event Func OnQuestion = static delegate { return Task.CompletedTask; }; + public event Func OnHint = static delegate { return Task.CompletedTask; }; + public event Func OnStats = static delegate { return Task.CompletedTask; }; + public event Func OnGuess = static delegate { return Task.CompletedTask; }; + public event Func OnTimeout = static delegate { return Task.CompletedTask; }; + public event Func OnEnded = static delegate { return Task.CompletedTask; }; + #endregion + + private bool _isStopped; + + public TriviaQuestion? CurrentQuestion { get; set; } + + + private readonly ConcurrentDictionary _users = new (); + + private readonly Channel<(TriviaUser User, string Input)> _inputs + = Channel.CreateUnbounded<(TriviaUser, string)>(new UnboundedChannelOptions + { + AllowSynchronousContinuations = true, + SingleReader = true, + SingleWriter = false, + }); + + public TriviaGame(TriviaOptions options, ILocalDataCache cache) + { + _opts = options; + + _questionPool = _opts.IsPokemon + ? new PokemonQuestionPool(cache) + : new DefaultQuestionPool(cache); + + } + public async Task RunAsync() + { + await GameLoop(); + } + + private async Task GameLoop() + { + Task TimeOutFactory() => Task.Delay(_opts.QuestionTimer * 1000 / 2); + + var errorCount = 0; + var inactivity = 0; + + // loop until game is stopped + // each iteration is one round + var firstRun = true; + try + { + while (!_isStopped) + { + if (errorCount >= 5) + { + Log.Warning("Trivia errored 5 times and will quit"); + break; + } + + // wait for 3 seconds before posting the next question + if (firstRun) + { + firstRun = false; + } + else + { + await Task.Delay(3000); + } + + var maybeQuestion = await _questionPool.GetQuestionAsync(); + + if (maybeQuestion is not { } question) + { + // if question is null (ran out of question, or other bugg ) - stop + break; + } + + CurrentQuestion = question; + try + { + // clear out all of the past guesses + while (_inputs.Reader.TryRead(out _)) + ; + + await OnQuestion(this, question); + } + catch (Exception ex) + { + Log.Warning(ex, "Error executing OnQuestion: {Message}", ex.Message); + errorCount++; + continue; + } + + + // just keep looping through user inputs until someone guesses the answer + // or the timer expires + var halfGuessTimerTask = TimeOutFactory(); + var hintSent = false; + var guessed = false; + while (true) + { + using var readCancel = new CancellationTokenSource(); + var readTask = _inputs.Reader.ReadAsync(readCancel.Token).AsTask(); + + // wait for either someone to attempt to guess + // or for timeout + var task = await Task.WhenAny(readTask, halfGuessTimerTask); + + // if the task which completed is the timeout task + if (task == halfGuessTimerTask) + { + readCancel.Cancel(); + + // if hint is already sent, means time expired + // break (end the round) + if (hintSent) + break; + + // else, means half time passed, send a hint + hintSent = true; + // start a new countdown of the same length + halfGuessTimerTask = TimeOutFactory(); + if (!_opts.NoHint) + { + // send a hint out + await OnHint(this, question); + } + + continue; + } + + // otherwise, read task is successful, and we're gonna + // get the user input data + var (user, input) = await readTask; + + // check the guess + if (question.IsAnswerCorrect(input)) + { + // add 1 point to the user + var val = _users.AddOrUpdate(user.Id, 1, (_, points) => ++points); + guessed = true; + + // reset inactivity counter + inactivity = 0; + errorCount = 0; + + var isWin = false; + // if user won the game, tell the game to stop + if (_opts.WinRequirement != 0 && val >= _opts.WinRequirement) + { + _isStopped = true; + isWin = true; + } + + // call onguess + await OnGuess(this, user, question, isWin); + break; + } + } + + if (!guessed) + { + await OnTimeout(this, question); + + if (_opts.Timeout != 0 && ++inactivity >= _opts.Timeout) + { + Log.Information("Trivia game is stopping due to inactivity"); + break; + } + } + } + } + catch (Exception ex) + { + Log.Error(ex, "Fatal error in trivia game: {ErrorMessage}", ex.Message); + } + finally + { + // make sure game is set as ended + _isStopped = true; + _ = OnEnded(this); + } + } + + public IReadOnlyList<(ulong User, int points)> GetLeaderboard() + => _users.Select(x => (x.Key, x.Value)).ToArray(); + + public ValueTask InputAsync(TriviaUser user, string input) + => _inputs.Writer.WriteAsync((user, input)); + + public bool Stop() + { + var isStopped = _isStopped; + _isStopped = true; + return !isStopped; + } + + public async ValueTask TriggerStatsAsync() + { + await OnStats(this); + } + + public async Task TriggerQuestionAsync() + { + if(CurrentQuestion is TriviaQuestion q) + await OnQuestion(this, q); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/TriviaGamesService.cs b/src/EllieBot/Modules/Games/Trivia/TriviaGamesService.cs new file mode 100644 index 0000000..6fc4ab6 --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/TriviaGamesService.cs @@ -0,0 +1,37 @@ +#nullable disable +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Modules.Games.Common.Trivia; + +namespace EllieBot.Modules.Games; + +public sealed class TriviaGamesService : IReadyExecutor, IEService +{ + private readonly DiscordSocketClient _client; + public ConcurrentDictionary RunningTrivias { get; } = new(); + + public TriviaGamesService(DiscordSocketClient client) + { + _client = client; + } + + public Task OnReadyAsync() + { + _client.MessageReceived += OnMessageReceived; + + return Task.CompletedTask; + } + + private async Task OnMessageReceived(SocketMessage msg) + { + if (msg.Author.IsBot) + return; + + var umsg = msg as SocketUserMessage; + + if (umsg?.Channel is not IGuildChannel gc) + return; + + if (RunningTrivias.TryGetValue(gc.GuildId, out var tg)) + await tg.InputAsync(new(umsg.Author.Mention, umsg.Author.Id), umsg.Content); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/TriviaOptions.cs b/src/EllieBot/Modules/Games/Trivia/TriviaOptions.cs new file mode 100644 index 0000000..47bdc0b --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/TriviaOptions.cs @@ -0,0 +1,44 @@ +#nullable disable +using CommandLine; + +namespace EllieBot.Modules.Games.Common.Trivia; + +public class TriviaOptions : IEllieCommandOptions +{ + [Option('p', "pokemon", Required = false, Default = false, HelpText = "Whether it's 'Who's that pokemon?' trivia.")] + public bool IsPokemon { get; set; } = false; + + [Option("nohint", Required = false, Default = false, HelpText = "Don't show any hints.")] + public bool NoHint { get; set; } = false; + + [Option('w', + "win-req", + Required = false, + Default = 10, + HelpText = "Winning requirement. Set 0 for an infinite game. Default 10.")] + public int WinRequirement { get; set; } = 10; + + [Option('q', + "question-timer", + Required = false, + Default = 30, + HelpText = "How long until the question ends. Default 30.")] + public int QuestionTimer { get; set; } = 30; + + [Option('t', + "timeout", + Required = false, + Default = 10, + HelpText = "Number of questions of inactivity in order stop. Set 0 for never. Default 10.")] + public int Timeout { get; set; } = 10; + + public void NormalizeOptions() + { + if (WinRequirement < 0) + WinRequirement = 10; + if (QuestionTimer is < 10 or > 300) + QuestionTimer = 30; + if (Timeout is < 0 or > 20) + Timeout = 10; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/TriviaQuestion.cs b/src/EllieBot/Modules/Games/Trivia/TriviaQuestion.cs new file mode 100644 index 0000000..299c762 --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/TriviaQuestion.cs @@ -0,0 +1,115 @@ +#nullable disable +using System.Text.RegularExpressions; + +namespace EllieBot.Modules.Games.Common.Trivia; + +public class TriviaQuestion +{ + public const int MAX_STRING_LENGTH = 22; + + //represents the min size to judge levDistance with + private static readonly HashSet> _strictness = + [ + new(9, 0), + new(14, 1), + new(19, 2), + new(22, 3) + ]; + + public string Category + => _qModel.Category; + + public string Question + => _qModel.Question; + + public string ImageUrl + => _qModel.ImageUrl; + + public string AnswerImageUrl + => _qModel.AnswerImageUrl ?? ImageUrl; + + public string Answer + => _qModel.Answer; + + public string CleanAnswer + => cleanAnswer ?? (cleanAnswer = Clean(Answer)); + + private string cleanAnswer; + private readonly TriviaQuestionModel _qModel; + + public TriviaQuestion(TriviaQuestionModel qModel) + { + _qModel = qModel; + } + + public string GetHint() + => Scramble(Answer); + + public bool IsAnswerCorrect(string guess) + { + if (Answer.Equals(guess, StringComparison.InvariantCulture)) + return true; + var cleanGuess = Clean(guess); + if (CleanAnswer.Equals(cleanGuess, StringComparison.InvariantCulture)) + return true; + + var levDistanceClean = CleanAnswer.LevenshteinDistance(cleanGuess); + var levDistanceNormal = Answer.LevenshteinDistance(guess); + return JudgeGuess(CleanAnswer.Length, cleanGuess.Length, levDistanceClean) + || JudgeGuess(Answer.Length, guess.Length, levDistanceNormal); + } + + private static bool JudgeGuess(int guessLength, int answerLength, int levDistance) + { + foreach (var level in _strictness) + { + if (guessLength <= level.Item1 || answerLength <= level.Item1) + { + if (levDistance <= level.Item2) + return true; + return false; + } + } + + return false; + } + + private static string Clean(string str) + { + str = " " + str.ToLowerInvariant() + " "; + str = Regex.Replace(str, @"\s+", " "); + str = Regex.Replace(str, @"[^\w\d\s]", ""); + //Here's where custom modification can be done + str = Regex.Replace(str, @"\s(a|an|the|of|in|for|to|as|at|be)\s", " "); + //End custom mod and cleanup whitespace + str = Regex.Replace(str, @"^\s+", ""); + str = Regex.Replace(str, @"\s+$", ""); + //Trim the really long answers + str = str.Length <= MAX_STRING_LENGTH ? str : str[..MAX_STRING_LENGTH]; + return str; + } + + private static string Scramble(string word) + { + var letters = word.ToCharArray(); + var count = 0; + for (var i = 0; i < letters.Length; i++) + { + if (letters[i] == ' ') + continue; + + count++; + if (count <= letters.Length / 5) + continue; + + if (count % 3 == 0) + continue; + + if (letters[i] != ' ') + letters[i] = '_'; + } + + return string.Join(" ", + new string(letters).Replace(" ", " \u2000", StringComparison.InvariantCulture).AsEnumerable()); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/Trivia/TriviaUser.cs b/src/EllieBot/Modules/Games/Trivia/TriviaUser.cs new file mode 100644 index 0000000..b61e827 --- /dev/null +++ b/src/EllieBot/Modules/Games/Trivia/TriviaUser.cs @@ -0,0 +1,3 @@ +namespace EllieBot.Modules.Games.Common.Trivia; + +public record class TriviaUser(string Name, ulong Id); \ No newline at end of file From 79e7252f99df1c045050d6b62a14672d6712f232 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:51:19 +1200 Subject: [PATCH 50/62] Added Help module --- .../Modules/Help/CommandJsonObject.cs | 13 + src/EllieBot/Modules/Help/CommandsOptions.cs | 26 + src/EllieBot/Modules/Help/Help.cs | 593 ++++++++++++++++++ src/EllieBot/Modules/Help/HelpService.cs | 44 ++ 4 files changed, 676 insertions(+) create mode 100644 src/EllieBot/Modules/Help/CommandJsonObject.cs create mode 100644 src/EllieBot/Modules/Help/CommandsOptions.cs create mode 100644 src/EllieBot/Modules/Help/Help.cs create mode 100644 src/EllieBot/Modules/Help/HelpService.cs diff --git a/src/EllieBot/Modules/Help/CommandJsonObject.cs b/src/EllieBot/Modules/Help/CommandJsonObject.cs new file mode 100644 index 0000000..062a0b9 --- /dev/null +++ b/src/EllieBot/Modules/Help/CommandJsonObject.cs @@ -0,0 +1,13 @@ +#nullable disable +namespace EllieBot.Modules.Help; + +internal class CommandJsonObject +{ + public string[] Aliases { get; set; } + public string Description { get; set; } + public string[] Usage { get; set; } + public string Submodule { get; set; } + public string Module { get; set; } + public List Options { get; set; } + public string[] Requirements { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Help/CommandsOptions.cs b/src/EllieBot/Modules/Help/CommandsOptions.cs new file mode 100644 index 0000000..ecbb06c --- /dev/null +++ b/src/EllieBot/Modules/Help/CommandsOptions.cs @@ -0,0 +1,26 @@ +#nullable disable +using CommandLine; + +namespace EllieBot.Modules.Help.Common; + +public class CommandsOptions : IEllieCommandOptions +{ + public enum ViewType + { + Hide, + Cross, + All + } + + [Option('v', + "view", + Required = false, + Default = ViewType.Hide, + HelpText = + "Specifies how to output the list of commands. 0 - Hide commands which you can't use, 1 - Cross out commands which you can't use, 2 - Show all.")] + public ViewType View { get; set; } = ViewType.Hide; + + public void NormalizeOptions() + { + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Help/Help.cs b/src/EllieBot/Modules/Help/Help.cs new file mode 100644 index 0000000..79367b9 --- /dev/null +++ b/src/EllieBot/Modules/Help/Help.cs @@ -0,0 +1,593 @@ +#nullable disable +using EllieBot.Modules.Help.Common; +using EllieBot.Modules.Help.Services; +using Newtonsoft.Json; +using System.Text; +using Ellie.Common.Marmalade; + +namespace EllieBot.Modules.Help; + +public sealed partial class Help : EllieModule +{ + public const string PATREON_URL = "https://patreon.com/toastie_t0ast"; + public const string PAYPAL_URL = "https://paypal.me/EmotionChild"; + + private readonly ICommandsUtilityService _cus; + private readonly CommandService _cmds; + private readonly BotConfigService _bss; + private readonly IPermissionChecker _perms; + private readonly IServiceProvider _services; + private readonly DiscordSocketClient _client; + private readonly IBotStrings _strings; + + private readonly AsyncLazy _lazyClientId; + private readonly IMarmaladeLoaderService _marmalades; + + public Help( + ICommandsUtilityService _cus, + IPermissionChecker perms, + CommandService cmds, + BotConfigService bss, + IServiceProvider services, + DiscordSocketClient client, + IBotStrings strings, + IMarmaladeLoaderService marmalades) + { + this._cus = _cus; + _cmds = cmds; + _bss = bss; + _perms = perms; + _services = services; + _client = client; + _strings = strings; + _marmalades = marmalades; + + _lazyClientId = new(async () => (await _client.GetApplicationInfoAsync()).Id); + } + + public async Task GetHelpString() + { + var botSettings = _bss.Data; + if (string.IsNullOrWhiteSpace(botSettings.HelpText) || botSettings.HelpText == "-") + return default; + + var clientId = await _lazyClientId.Value; + var repCtx = new ReplacementContext(Context) + .WithOverride("{0}", () => clientId.ToString()) + .WithOverride("{1}", () => prefix) + .WithOverride("%prefix%", () => prefix) + .WithOverride("%bot.prefix%", () => prefix); + + var text = SmartText.CreateFrom(botSettings.HelpText); + return await repSvc.ReplaceAsync(text, repCtx); + } + + [Cmd] + public async Task Modules(int page = 1) + { + if (--page < 0) + return; + + var topLevelModules = new List(); + foreach (var m in _cmds.Modules.GroupBy(x => x.GetTopLevelModule()).OrderBy(x => x.Key.Name).Select(x => x.Key)) + { + var result = await _perms.CheckPermsAsync(ctx.Guild, + ctx.Channel, + ctx.User, + m.Name, + null); + +#if GLOBAL_ELLIE + if (m.Preconditions.Any(x => x is NoPublicBotAttribute)) + continue; +#endif + + if (result.IsAllowed) + topLevelModules.Add(m); + } + + var menu = new SelectMenuBuilder() + .WithPlaceholder("Select a module to see its commands") + .WithCustomId("cmds:modules_select"); + + foreach (var m in topLevelModules) + menu.AddOption(m.Name, m.Name, GetModuleEmoji(m.Name)); + + var inter = _inter.Create(ctx.User.Id, + menu, + async (smc) => + { + await smc.DeferAsync(); + var val = smc.Data.Values.FirstOrDefault(); + if (val is null) + return; + + await Commands(val); + }); + + await Response() + .Paginated() + .Items(topLevelModules) + .PageSize(12) + .CurrentPage(page) + .Interaction(inter) + .AddFooter(false) + .Page((items, _) => + { + var embed = _sender.CreateEmbed().WithOkColor().WithTitle(GetText(strs.list_of_modules)); + + if (!items.Any()) + { + embed = embed.WithOkColor().WithDescription(GetText(strs.module_page_empty)); + return embed; + } + + items + .ToList() + .ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}", + GetModuleDescription(module.Name) + + "\n" + + Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))), + true)); + + return embed; + }) + .SendAsync(); + } + + private string GetModuleDescription(string moduleName) + { + var key = GetModuleLocStr(moduleName); + + if (key.Key == strs.module_description_missing.Key) + { + var desc = _marmalades + .GetLoadedMarmalades(Culture) + .FirstOrDefault(m => m.Canaries + .Any(x => x.Name.Equals(moduleName, + StringComparison.InvariantCultureIgnoreCase))) + ?.Description; + + if (desc is not null) + return desc; + } + + return GetText(key); + } + + private LocStr GetModuleLocStr(string moduleName) + { + switch (moduleName.ToLowerInvariant()) + { + case "help": + return strs.module_description_help; + case "administration": + return strs.module_description_administration; + case "expressions": + return strs.module_description_expressions; + case "searches": + return strs.module_description_searches; + case "utility": + return strs.module_description_utility; + case "games": + return strs.module_description_games; + case "gambling": + return strs.module_description_gambling; + case "music": + return strs.module_description_music; + case "nsfw": + return strs.module_description_nsfw; + case "permissions": + return strs.module_description_permissions; + case "xp": + return strs.module_description_xp; + case "marmalade": + return strs.module_description_marmalade; + case "patronage": + return strs.module_description_patronage; + default: + return strs.module_description_missing; + } + } + + private string GetModuleEmoji(string moduleName) + { + moduleName = moduleName.ToLowerInvariant(); + switch (moduleName) + { + case "help": + return "❓"; + case "administration": + return "🛠️"; + case "expressions": + return "🗣️"; + case "searches": + return "🔍"; + case "utility": + return "🔧"; + case "games": + return "🎲"; + case "gambling": + return "💰"; + case "music": + return "🎶"; + case "nsfw": + return "😳"; + case "permissions": + return "🚓"; + case "xp": + return "📝"; + case "patronage": + return "💝"; + default: + return "📖"; + } + } + + [Cmd] + [EllieOptions] + public async Task Commands(string module = null, params string[] args) + { + if (string.IsNullOrWhiteSpace(module)) + { + await Modules(); + return; + } + + var (opts, _) = OptionsParser.ParseFrom(new CommandsOptions(), args); + + // Find commands for that module + // don't show commands which are blocked + // order by name + var allowed = new List(); + + var mdls = _cmds.Commands + .Where(c => c.Module.GetTopLevelModule() + .Name + .StartsWith(module, StringComparison.InvariantCultureIgnoreCase)) + .ToArray(); + + if (mdls.Length == 0) + { + var group = _cmds.Modules + .Where(x => x.Parent is not null) + .FirstOrDefault(x => string.Equals(x.Name.Replace("Commands", ""), + module, + StringComparison.InvariantCultureIgnoreCase)); + + if (group is not null) + { + await Group(group); + return; + } + } + + foreach (var cmd in mdls) + { + var result = await _perms.CheckPermsAsync(ctx.Guild, + ctx.Channel, + ctx.User, + cmd.Module.GetTopLevelModule().Name, + cmd.Name); + + if (result.IsAllowed) + allowed.Add(cmd); + } + + + var cmds = allowed.OrderBy(c => c.Aliases[0]) + .DistinctBy(x => x.Aliases[0]) + .ToList(); + + + // check preconditions for all commands, but only if it's not 'all' + // because all will show all commands anyway, no need to check + var succ = new HashSet(); + if (opts.View != CommandsOptions.ViewType.All) + { + succ = + [ + ..(await cmds.Select(async x => + { + var pre = await x.CheckPreconditionsAsync(Context, _services); + return (Cmd: x, Succ: pre.IsSuccess); + }) + .WhenAll()).Where(x => x.Succ) + .Select(x => x.Cmd) + ]; + + if (opts.View == CommandsOptions.ViewType.Hide) + // if hidden is specified, completely remove these commands from the list + cmds = cmds.Where(x => succ.Contains(x)).ToList(); + } + + var cmdsWithGroup = cmds.GroupBy(c => c.Module.GetGroupName()) + .OrderBy(x => x.Key == x.First().Module.Name ? int.MaxValue : x.Count()) + .ToList(); + + if (cmdsWithGroup.Count == 0) + { + if (opts.View != CommandsOptions.ViewType.Hide) + await Response().Error(strs.module_not_found).SendAsync(); + else + await Response().Error(strs.module_not_found_or_cant_exec).SendAsync(); + return; + } + + var sb = new SelectMenuBuilder() + .WithCustomId("cmds:submodule_select") + .WithPlaceholder("Select a submodule to see detailed commands"); + + var groups = cmdsWithGroup.ToArray(); + var embed = _sender.CreateEmbed().WithOkColor(); + foreach (var g in groups) + { + sb.AddOption(g.Key, g.Key); + var transformed = g + .Select(x => + { + //if cross is specified, and the command doesn't satisfy the requirements, cross it out + if (opts.View == CommandsOptions.ViewType.Cross) + { + return $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}"; + } + + + if (x.Aliases.Count == 1) + return prefix + x.Aliases[0]; + + return prefix + x.Aliases[0] + " | " + prefix + x.Aliases[1]; + }); + + embed.AddField(g.Key, "" + string.Join("\n", transformed) + "", true); + } + + embed.WithFooter(GetText(strs.commands_instr(prefix))); + + + var inter = _inter.Create(ctx.User.Id, + sb, + async (smc) => + { + var groupName = smc.Data.Values.FirstOrDefault(); + var mdl = _cmds.Modules.FirstOrDefault(x + => string.Equals(x.Name.Replace("Commands", ""), groupName, StringComparison.InvariantCultureIgnoreCase)); + await smc.DeferAsync(); + await Group(mdl); + } + ); + + await Response().Embed(embed).Interaction(inter).SendAsync(); + } + + private async Task Group(ModuleInfo group) + { + var menu = new SelectMenuBuilder() + .WithCustomId("cmds:group_select") + .WithPlaceholder("Select a command to see its details"); + + foreach (var cmd in group.Commands.DistinctBy(x => x.Aliases[0])) + { + menu.AddOption(prefix + cmd.Aliases[0], cmd.Aliases[0]); + } + + var inter = _inter.Create(ctx.User.Id, + menu, + async (smc) => + { + await smc.DeferAsync(); + + await H(smc.Data.Values.FirstOrDefault()); + }); + + await Response() + .Paginated() + .Items(group.Commands.DistinctBy(x => x.Aliases[0]).ToArray()) + .PageSize(25) + .Interaction(inter) + .Page((items, _) => + { + var eb = _sender.CreateEmbed() + .WithTitle(GetText(strs.cmd_group_commands(group.Name))) + .WithOkColor(); + + foreach (var cmd in items) + { + string cmdName; + if (cmd.Aliases.Count > 1) + cmdName = Format.Code(prefix + cmd.Aliases[0]) + " | " + Format.Code(prefix + cmd.Aliases[1]); + else + cmdName = Format.Code(prefix + cmd.Aliases.First()); + + eb.AddField(cmdName, cmd.RealSummary(_strings, _marmalades, Culture, prefix)); + } + + return eb; + }) + .SendAsync(); + } + + [Cmd] + [Priority(0)] + public async Task H([Leftover] string fail) + { + var prefixless = + _cmds.Commands.FirstOrDefault(x => x.Aliases.Any(cmdName => cmdName.ToLowerInvariant() == fail)); + if (prefixless is not null) + { + await H(prefixless); + return; + } + + if (fail.StartsWith(prefix)) + fail = fail.Substring(prefix.Length); + + var group = _cmds.Modules + .SelectMany(x => x.Submodules) + .FirstOrDefault(x => string.Equals(x.Group, + fail, + StringComparison.InvariantCultureIgnoreCase)); + + if (group is not null) + { + await Group(group); + return; + } + + await Response().Error(strs.command_not_found).SendAsync(); + } + + [Cmd] + [Priority(1)] + public async Task H([Leftover] CommandInfo com = null) + { + var channel = ctx.Channel; + if (com is null) + { + try + { + var ch = channel is ITextChannel ? await ctx.User.CreateDMChannelAsync() : channel; + var data = await GetHelpString(); + if (data == default) + return; + + await Response().Channel(ch).Text(data).SendAsync(); + try + { + await ctx.OkAsync(); + } + catch + { + } // ignore if bot can't react + } + catch (Exception) + { + await Response().Error(strs.cant_dm).SendAsync(); + } + + return; + } + + var embed = _cus.GetCommandHelp(com, ctx.Guild); + await _sender.Response(channel).Embed(embed).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task GenCmdList() + { + _ = ctx.Channel.TriggerTypingAsync(); + + // order commands by top level module name + // and make a dictionary of > + var cmdData = _cmds.Commands.GroupBy(x => x.Module.GetTopLevelModule().Name) + .OrderBy(x => x.Key) + .ToDictionary(x => x.Key, + x => x.DistinctBy(c => c.Aliases.First()) + .Select(com => + { + List optHelpStr = null; + + var opt = CommandsUtilityService.GetEllieOptionType(com.Attributes); + if (opt is not null) + optHelpStr = CommandsUtilityService.GetCommandOptionHelpList(opt); + + return new CommandJsonObject + { + Aliases = com.Aliases.Select(alias => prefix + alias).ToArray(), + Description = com.RealSummary(_strings, _marmalades, Culture, prefix), + Usage = com.RealRemarksArr(_strings, _marmalades, Culture, prefix), + Submodule = com.Module.Name, + Module = com.Module.GetTopLevelModule().Name, + Options = optHelpStr, + Requirements = CommandsUtilityService.GetCommandRequirements(com) + }; + }) + .ToList()); + + var readableData = JsonConvert.SerializeObject(cmdData, Formatting.Indented); + + // send the indented file to chat + await using var rDataStream = new MemoryStream(Encoding.ASCII.GetBytes(readableData)); + await ctx.Channel.SendFileAsync(rDataStream, "cmds.json", GetText(strs.commandlist_regen)); + } + + [Cmd] + public async Task Guide() + => await Response() + .Confirm(strs.guide("https://commands.elliebot.net", + "https://docs.elliebot.net/")) + .SendAsync(); + + + private Task SelfhostAction(SocketMessageComponent smc) + => smc.RespondConfirmAsync(_sender, + """ + - In case you don't want or cannot Donate to EllieBot project, but you + - EllieBot is a free and [open source](https://toastielab.dev/Emotions-stuff/Ellie) project which means you can run your own "selfhosted" instance on your computer. + + *Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer* + + - You can find the selfhosting guides by using the `.guide` command and clicking on the second link that pops up. + - If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/toastie_t0ast) to keep the development going :) + """, + true); + + [Cmd] + [OnlyPublicBot] + public async Task Donate() + { + var selfhostInter = _inter.Create(ctx.User.Id, + new ButtonBuilder( + emote: new Emoji("🖥️"), + customId: "donate:selfhosting", + label: "Selfhosting"), + SelfhostAction); + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("Thank you for considering to donate to the EllieBot project!"); + + eb + .WithDescription(""" + EllieBot relies on donations to keep the servers, services and APIs running. + Donating will give you access to some exclusive features. You can read about them on the [patreon page](https://patreon.com/join/toastie_t0ast) + """) + .AddField("Donation Instructions", + $""" + 🗒️ Before pledging it is recommended to open your DMs as Ellie will send you a welcome message with instructions after you pledge has been processed and confirmed. + + **Step 1:** ❤️ Pledge on Patreon ❤️ + + `1.` Go to and choose a tier. + `2.` Make sure your payment is processed and accepted. + + **Step 2** 🤝 Connect your Discord account 🤝 + + `1.` Go to your profile settings on Patreon and connect your Discord account to it. + *please make sure you're logged into the correct Discord account* + + If you do not know how to do it, you may [follow instructions here](https://support.patreon.com/hc/en-us/articles/212052266-How-do-I-connect-Discord-to-Patreon-Patron-) + + **Step 3** ⏰ Wait a short while (usually 1-3 minutes) ⏰ + + Ellie will DM you the welcome instructions, and you will receive your rewards! + 🎉 **Enjoy!** 🎉 + """); + + try + { + await Response() + .Channel(await ctx.User.CreateDMChannelAsync()) + .Embed(eb) + .Interaction(selfhostInter) + .SendAsync(); + + _ = ctx.OkAsync(); + } + catch + { + await Response().Error(strs.cant_dm).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Help/HelpService.cs b/src/EllieBot/Modules/Help/HelpService.cs new file mode 100644 index 0000000..5904c03 --- /dev/null +++ b/src/EllieBot/Modules/Help/HelpService.cs @@ -0,0 +1,44 @@ +using EllieBot.Common.ModuleBehaviors; + +namespace EllieBot.Modules.Help.Services; + +public class HelpService : IExecNoCommand, IEService +{ + private readonly BotConfigService _bss; + private readonly IReplacementService _rs; + private readonly IMessageSenderService _sender; + + public HelpService(BotConfigService bss, IReplacementService repSvc, IMessageSenderService sender) + { + _bss = bss; + _rs = repSvc; + _sender = sender; + } + + public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) + { + var settings = _bss.Data; + if (guild is null) + { + if (string.IsNullOrWhiteSpace(settings.DmHelpText) || settings.DmHelpText == "-") + return; + + // only send dm help text if it contains one of the keywords, if they're specified + // if they're not, then reply to every DM + if (settings.DmHelpTextKeywords is not null + && !settings.DmHelpTextKeywords.Any(k => msg.Content.Contains(k))) + { + return; + } + + var repCtx = new ReplacementContext(guild: guild, channel: msg.Channel, users: msg.Author) + .WithOverride("%prefix%", () => _bss.Data.Prefix) + .WithOverride("%bot.prefix%", () => _bss.Data.Prefix); + + var text = SmartText.CreateFrom(settings.DmHelpText); + text = await _rs.ReplaceAsync(text, repCtx); + + await _sender.Response(msg.Channel).Text(text).SendAsync(); + } + } +} \ No newline at end of file From 243d754d10435ffb78ffcb03570888e8d918ab92 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:51:49 +1200 Subject: [PATCH 51/62] Added Music module --- .../Marmalade/IMarmaladesRepositoryService.cs | 6 + src/EllieBot/Modules/Marmalade/Marmalade.cs | 243 ++++++++++++++++++ .../Modules/Marmalade/MarmaladeItem.cs | 8 + .../Marmalade/MarmaladesRepositoryService.cs | 67 +++++ 4 files changed, 324 insertions(+) create mode 100644 src/EllieBot/Modules/Marmalade/IMarmaladesRepositoryService.cs create mode 100644 src/EllieBot/Modules/Marmalade/Marmalade.cs create mode 100644 src/EllieBot/Modules/Marmalade/MarmaladeItem.cs create mode 100644 src/EllieBot/Modules/Marmalade/MarmaladesRepositoryService.cs diff --git a/src/EllieBot/Modules/Marmalade/IMarmaladesRepositoryService.cs b/src/EllieBot/Modules/Marmalade/IMarmaladesRepositoryService.cs new file mode 100644 index 0000000..155f56b --- /dev/null +++ b/src/EllieBot/Modules/Marmalade/IMarmaladesRepositoryService.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules; + +public interface IMarmaladesRepositoryService +{ + Task> GetModuleItemsAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Marmalade/Marmalade.cs b/src/EllieBot/Modules/Marmalade/Marmalade.cs new file mode 100644 index 0000000..530b23f --- /dev/null +++ b/src/EllieBot/Modules/Marmalade/Marmalade.cs @@ -0,0 +1,243 @@ +using Ellie.Common.Marmalade; + +namespace EllieBot.Modules; + +[OwnerOnly] +[NoPublicBot] +public partial class Marmalade : EllieModule +{ + private readonly IMarmaladesRepositoryService _repo; + + public Marmalade(IMarmaladesRepositoryService repo) + { + _repo = repo; + } + + [Cmd] + [OwnerOnly] + public async Task MarmaladeLoad(string? name = null) + { + if (string.IsNullOrWhiteSpace(name)) + { + var loaded = _service.GetLoadedMarmalades() + .Select(x => x.Name) + .ToHashSet(); + + var unloaded = _service.GetAllMarmalades() + .Where(x => !loaded.Contains(x)) + .Select(x => Format.Code(x.ToString())) + .ToArray(); + + if (unloaded.Length == 0) + { + await Response().Pending(strs.no_marmalade_available).SendAsync(); + return; + } + + await Response() + .Paginated() + .Items(unloaded) + .PageSize(10) + .Page((items, _) => + { + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.list_of_unloaded)) + .WithDescription(items.Join('\n')); + }) + .SendAsync(); + return; + } + + var res = await _service.LoadMarmaladeAsync(name); + if (res == MarmaladeLoadResult.Success) + await Response().Confirm(strs.marmalade_loaded(Format.Code(name))).SendAsync(); + else + { + var locStr = res switch + { + MarmaladeLoadResult.Empty => strs.marmalade_empty, + MarmaladeLoadResult.AlreadyLoaded => strs.marmalade_already_loaded(Format.Code(name)), + MarmaladeLoadResult.NotFound => strs.marmalade_invalid_not_found, + MarmaladeLoadResult.UnknownError => strs.error_occured, + _ => strs.error_occured + }; + + await Response().Error(locStr).SendAsync(); + } + } + + [Cmd] + [OwnerOnly] + public async Task MarmaladeUnload(string? name = null) + { + if (string.IsNullOrWhiteSpace(name)) + { + var loaded = _service.GetLoadedMarmalades(); + if (loaded.Count == 0) + { + await Response().Pending(strs.no_marmalade_loaded).SendAsync(); + return; + } + + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.loaded_marmalades)) + .WithDescription(loaded.Select(x => x.Name) + .Join("\n"))) + .SendAsync(); + + return; + } + + var res = await _service.UnloadMarmaladeAsync(name); + if (res == MarmaladeUnloadResult.Success) + await Response().Confirm(strs.marmalade_unloaded(Format.Code(name))).SendAsync(); + else + { + var locStr = res switch + { + MarmaladeUnloadResult.NotLoaded => strs.marmalade_not_loaded, + MarmaladeUnloadResult.PossiblyUnable => strs.marmalade_possibly_cant_unload, + _ => strs.error_occured + }; + + await Response().Error(locStr).SendAsync(); + } + } + + [Cmd] + [OwnerOnly] + public async Task MarmaladeList() + { + var all = _service.GetAllMarmalades(); + + if (all.Count == 0) + { + await Response().Pending(strs.no_marmalade_available).SendAsync(); + return; + } + + var loaded = _service.GetLoadedMarmalades() + .Select(x => x.Name) + .ToHashSet(); + + var output = all + .Select(m => + { + var emoji = loaded.Contains(m) ? "`✅`" : "`🔴`"; + return $"{emoji} `{m}`"; + }) + .ToArray(); + + + await Response() + .Paginated() + .Items(output) + .PageSize(10) + .Page((items, _) => _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.list_of_marmalades)) + .WithDescription(items.Join('\n'))) + .SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task MarmaladeInfo(string? name = null) + { + var marmalades = _service.GetLoadedMarmalades(); + + if (name is not null) + { + var found = marmalades.FirstOrDefault(x => string.Equals(x.Name, + name, + StringComparison.InvariantCultureIgnoreCase)); + + if (found is null) + { + await Response().Error(strs.marmalade_name_not_found).SendAsync(); + return; + } + + var cmdCount = found.Canaries.Sum(x => x.Commands.Count); + var cmdNames = found.Canaries + .SelectMany(x => Format.Code(string.IsNullOrWhiteSpace(x.Prefix) + ? x.Name + : $"{x.Prefix} {x.Name}")) + .Join("\n"); + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.marmalade_info)) + .WithTitle(found.Name) + .WithDescription(found.Description) + .AddField(GetText(strs.canaries_count(found.Canaries.Count)), + found.Canaries.Count == 0 + ? "-" + : found.Canaries.Select(x => x.Name).Join('\n'), + true) + .AddField(GetText(strs.commands_count(cmdCount)), + string.IsNullOrWhiteSpace(cmdNames) + ? "-" + : cmdNames, + true); + + await Response().Embed(eb).SendAsync(); + return; + } + + if (marmalades.Count == 0) + { + await Response().Pending(strs.no_marmalade_loaded).SendAsync(); + return; + } + + await Response() + .Paginated() + .Items(marmalades) + .PageSize(9) + .CurrentPage(0) + .Page((items, _) => + { + var eb = _sender.CreateEmbed() + .WithOkColor(); + + foreach (var marmalade in items) + { + eb.AddField(marmalade.Name, + $""" + `Canaries:` {marmalade.Canaries.Count} + `Commands:` {marmalade.Canaries.Sum(x => x.Commands.Count)} + -- + {marmalade.Description} + """); + } + + return eb; + }) + .SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task MarmaladeSearch() + { + var eb = _sender.CreateEmbed() + .WithTitle(GetText(strs.list_of_marmalades)) + .WithOkColor(); + + foreach (var item in await _repo.GetModuleItemsAsync()) + { + eb.AddField(item.Name, + $""" + {item.Description} + `{item.Command}` + """, + true); + } + + await Response().Embed(eb).SendAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Marmalade/MarmaladeItem.cs b/src/EllieBot/Modules/Marmalade/MarmaladeItem.cs new file mode 100644 index 0000000..54c2889 --- /dev/null +++ b/src/EllieBot/Modules/Marmalade/MarmaladeItem.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules; + +public sealed class ModuleItem +{ + public required string Name { get; init; } + public required string Description { get; init; } + public required string Command { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Marmalade/MarmaladesRepositoryService.cs b/src/EllieBot/Modules/Marmalade/MarmaladesRepositoryService.cs new file mode 100644 index 0000000..6cc12b5 --- /dev/null +++ b/src/EllieBot/Modules/Marmalade/MarmaladesRepositoryService.cs @@ -0,0 +1,67 @@ +namespace EllieBot.Modules; + +public class MarmaladesRepositoryService : IMarmaladesRepositoryService, IEService +{ + public async Task> GetModuleItemsAsync() + { + // Simulate retrieving data from a database or API + await Task.Delay(100); + return + [ + new() + { + Name = "RSS Reader", + Description = "Keep up to date with your favorite websites", + Command = ".mainstall rss" + }, + new() + { + Name = "Password Manager", + Description = "Safely store and manage all your passwords", + Command = ".mainstall passwordmanager" + }, + new() + { + Name = "Browser Extension", + Description = "Enhance your browsing experience with useful tools", + Command = ".mainstall browserextension" + }, + new() + { + Name = "Video Downloader", + Description = "Download videos from popular websites", + Command = ".mainstall videodownloader" + }, + new() + { + Name = "Virtual Private Network", + Description = "Securely browse the web and protect your privacy", + Command = ".mainstall vpn" + }, + new() + { + Name = "Ad Blocker", + Description = "Block annoying ads and improve page load times", + Command = ".mainstall adblocker" + }, + new() + { + Name = "Cloud Storage", + Description = "Store and share your files online", + Command = ".mainstall cloudstorage" + }, + new() + { + Name = "Social Media Manager", + Description = "Manage all your social media accounts in one place", + Command = ".mainstall socialmediamanager" + }, + new() + { + Name = "Code Editor", + Description = "Write and edit code online", + Command = ".mainstall codeeditor" + } + ]; + } +} \ No newline at end of file From 1f6858e1f3ea65ddc43806d8646b2f058dca8243 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:53:04 +1200 Subject: [PATCH 52/62] Acutally added Music module The last commit contained the Marmalade module -_- --- src/EllieBot/Modules/Music/Music.cs | 755 ++++++++++++++++++ .../Modules/Music/PlaylistCommands.cs | 246 ++++++ .../Music/Services/AyuVoiceStateService.cs | 217 +++++ .../Modules/Music/Services/IMusicService.cs | 36 + .../Modules/Music/Services/MusicService.cs | 437 ++++++++++ .../Modules/Music/Services/extractor/Misc.cs | 74 ++ .../Music/Services/extractor/YtLoader.cs | 130 +++ .../Music/_common/ICachableTrackData.cs | 12 + .../Music/_common/ILocalTrackResolver.cs | 7 + .../Modules/Music/_common/IMusicPlayer.cs | 41 + .../Modules/Music/_common/IMusicQueue.cs | 23 + .../Music/_common/IPlatformQueryResolver.cs | 6 + .../Modules/Music/_common/IQueuedTrackInfo.cs | 9 + .../Modules/Music/_common/IRadioResolver.cs | 6 + .../Modules/Music/_common/ITrackCacher.cs | 25 + .../Modules/Music/_common/ITrackInfo.cs | 12 + .../Music/_common/ITrackResolveProvider.cs | 6 + .../Modules/Music/_common/IVoiceProxy.cs | 15 + .../Modules/Music/_common/IYoutubeResolver.cs | 11 + .../Music/_common/Impl/CachableTrackData.cs | 19 + .../Music/_common/Impl/MultimediaTimer.cs | 95 +++ .../Music/_common/Impl/MusicExtensions.cs | 57 ++ .../Music/_common/Impl/MusicPlatform.cs | 9 + .../Modules/Music/_common/Impl/MusicPlayer.cs | 531 ++++++++++++ .../Modules/Music/_common/Impl/MusicQueue.cs | 345 ++++++++ .../Music/_common/Impl/RemoteTrackInfo.cs | 16 + .../Music/_common/Impl/SimpleTrackInfo.cs | 30 + .../Modules/Music/_common/Impl/TrackCacher.cs | 105 +++ .../Modules/Music/_common/Impl/VoiceProxy.cs | 102 +++ .../_common/Resolvers/LocalTrackResolver.cs | 122 +++ .../_common/Resolvers/RadioResolveStrategy.cs | 106 +++ .../_common/Resolvers/TrackResolveProvider.cs | 49 ++ .../_common/Resolvers/YtdlYoutubeResolver.cs | 315 ++++++++ .../db/MusicPlayerSettingsExtensions.cs | 27 + .../Modules/Music/_common/db/MusicPlaylist.cs | 10 + .../_common/db/MusicPlaylistExtensions.cs | 18 + .../Modules/Music/_common/db/MusicSettings.cs | 61 ++ 37 files changed, 4085 insertions(+) create mode 100644 src/EllieBot/Modules/Music/Music.cs create mode 100644 src/EllieBot/Modules/Music/PlaylistCommands.cs create mode 100644 src/EllieBot/Modules/Music/Services/AyuVoiceStateService.cs create mode 100644 src/EllieBot/Modules/Music/Services/IMusicService.cs create mode 100644 src/EllieBot/Modules/Music/Services/MusicService.cs create mode 100644 src/EllieBot/Modules/Music/Services/extractor/Misc.cs create mode 100644 src/EllieBot/Modules/Music/Services/extractor/YtLoader.cs create mode 100644 src/EllieBot/Modules/Music/_common/ICachableTrackData.cs create mode 100644 src/EllieBot/Modules/Music/_common/ILocalTrackResolver.cs create mode 100644 src/EllieBot/Modules/Music/_common/IMusicPlayer.cs create mode 100644 src/EllieBot/Modules/Music/_common/IMusicQueue.cs create mode 100644 src/EllieBot/Modules/Music/_common/IPlatformQueryResolver.cs create mode 100644 src/EllieBot/Modules/Music/_common/IQueuedTrackInfo.cs create mode 100644 src/EllieBot/Modules/Music/_common/IRadioResolver.cs create mode 100644 src/EllieBot/Modules/Music/_common/ITrackCacher.cs create mode 100644 src/EllieBot/Modules/Music/_common/ITrackInfo.cs create mode 100644 src/EllieBot/Modules/Music/_common/ITrackResolveProvider.cs create mode 100644 src/EllieBot/Modules/Music/_common/IVoiceProxy.cs create mode 100644 src/EllieBot/Modules/Music/_common/IYoutubeResolver.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/CachableTrackData.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/MultimediaTimer.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/MusicExtensions.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/MusicPlatform.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/MusicPlayer.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/MusicQueue.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/RemoteTrackInfo.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/SimpleTrackInfo.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/TrackCacher.cs create mode 100644 src/EllieBot/Modules/Music/_common/Impl/VoiceProxy.cs create mode 100644 src/EllieBot/Modules/Music/_common/Resolvers/LocalTrackResolver.cs create mode 100644 src/EllieBot/Modules/Music/_common/Resolvers/RadioResolveStrategy.cs create mode 100644 src/EllieBot/Modules/Music/_common/Resolvers/TrackResolveProvider.cs create mode 100644 src/EllieBot/Modules/Music/_common/Resolvers/YtdlYoutubeResolver.cs create mode 100644 src/EllieBot/Modules/Music/_common/db/MusicPlayerSettingsExtensions.cs create mode 100644 src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs create mode 100644 src/EllieBot/Modules/Music/_common/db/MusicPlaylistExtensions.cs create mode 100644 src/EllieBot/Modules/Music/_common/db/MusicSettings.cs diff --git a/src/EllieBot/Modules/Music/Music.cs b/src/EllieBot/Modules/Music/Music.cs new file mode 100644 index 0000000..3b1393c --- /dev/null +++ b/src/EllieBot/Modules/Music/Music.cs @@ -0,0 +1,755 @@ +#nullable disable +using EllieBot.Modules.Music.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Music; + +[NoPublicBot] +public sealed partial class Music : EllieModule +{ + public enum All { All = -1 } + + public enum InputRepeatType + { + N = 0, No = 0, None = 0, + T = 1, Track = 1, S = 1, Song = 1, + Q = 2, Queue = 2, Playlist = 2, Pl = 2 + } + + public const string MUSIC_ICON_URL = "https://i.imgur.com/nhKS3PT.png"; + + private const int LQ_ITEMS_PER_PAGE = 9; + + private static readonly SemaphoreSlim _voiceChannelLock = new(1, 1); + private readonly ILogCommandService _logService; + + public Music(ILogCommandService logService) + => _logService = logService; + + private async Task ValidateAsync() + { + var user = (IGuildUser)ctx.User; + var userVoiceChannelId = user.VoiceChannel?.Id; + + if (userVoiceChannelId is null) + { + await Response().Error(strs.must_be_in_voice).SendAsync(); + return false; + } + + var currentUser = await ctx.Guild.GetCurrentUserAsync(); + if (currentUser.VoiceChannel?.Id != userVoiceChannelId) + { + await Response().Error(strs.not_with_bot_in_voice).SendAsync(); + return false; + } + + return true; + } + + private async Task EnsureBotInVoiceChannelAsync(ulong voiceChannelId, IGuildUser botUser = null) + { + botUser ??= await ctx.Guild.GetCurrentUserAsync(); + await _voiceChannelLock.WaitAsync(); + try + { + if (botUser.VoiceChannel?.Id is null || !_service.TryGetMusicPlayer(ctx.Guild.Id, out _)) + await _service.JoinVoiceChannelAsync(ctx.Guild.Id, voiceChannelId); + } + finally + { + _voiceChannelLock.Release(); + } + } + + private async Task QueuePreconditionInternalAsync() + { + var user = (IGuildUser)ctx.User; + var voiceChannelId = user.VoiceChannel?.Id; + + if (voiceChannelId is null) + { + await Response().Error(strs.must_be_in_voice).SendAsync(); + return false; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var botUser = await ctx.Guild.GetCurrentUserAsync(); + await EnsureBotInVoiceChannelAsync(voiceChannelId!.Value, botUser); + + if (botUser.VoiceChannel?.Id != voiceChannelId) + { + await Response().Error(strs.not_with_bot_in_voice).SendAsync(); + return false; + } + + return true; + } + + private async Task QueueByQuery(string query, bool asNext = false, MusicPlatform? forcePlatform = null) + { + var succ = await QueuePreconditionInternalAsync(); + if (!succ) + return; + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + var (trackInfo, index) = await mp.TryEnqueueTrackAsync(query, ctx.User.ToString(), asNext, forcePlatform); + if (trackInfo is null) + { + await Response().Error(strs.track_not_found).SendAsync(); + return; + } + + try + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.queued_track) + " #" + (index + 1), MUSIC_ICON_URL) + .WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ") + .WithFooter(trackInfo.Platform.ToString()); + + if (!string.IsNullOrWhiteSpace(trackInfo.Thumbnail)) + embed.WithThumbnailUrl(trackInfo.Thumbnail); + + var queuedMessage = await _service.SendToOutputAsync(ctx.Guild.Id, embed); + queuedMessage?.DeleteAfter(10, _logService); + if (mp.IsStopped) + { + var msg = await Response().Pending(strs.queue_stopped(Format.Code(prefix + "play"))).SendAsync(); + msg.DeleteAfter(10, _logService); + } + } + catch + { + // ignored + } + } + + private async Task MoveToIndex(int index) + { + if (--index < 0) + return; + + var succ = await QueuePreconditionInternalAsync(); + if (!succ) + return; + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + mp.MoveTo(index); + } + + // join vc + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Join() + { + var user = (IGuildUser)ctx.User; + + var voiceChannelId = user.VoiceChannel?.Id; + + if (voiceChannelId is null) + { + await Response().Error(strs.must_be_in_voice).SendAsync(); + return; + } + + await _service.JoinVoiceChannelAsync(user.GuildId, voiceChannelId.Value); + } + + // leave vc (destroy) + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Destroy() + { + var valid = await ValidateAsync(); + if (!valid) + return; + + await _service.LeaveVoiceChannelAsync(ctx.Guild.Id); + } + + // play - no args = next + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(2)] + public Task Play() + => Next(); + + // play - index = skip to that index + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public Task Play(int index) + => MoveToIndex(index); + + // play - query = q(query) + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public Task Play([Leftover] string query) + => QueueByQuery(query); + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task Queue([Leftover] string query) + => QueueByQuery(query); + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task QueueNext([Leftover] string query) + => QueueByQuery(query, true); + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Volume(int vol) + { + if (vol is < 0 or > 100) + { + await Response().Error(strs.volume_input_invalid).SendAsync(); + return; + } + + var valid = await ValidateAsync(); + if (!valid) + return; + + await _service.SetVolumeAsync(ctx.Guild.Id, vol); + await Response().Confirm(strs.volume_set(vol)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Next() + { + var valid = await ValidateAsync(); + if (!valid) + return; + + var success = await _service.PlayAsync(ctx.Guild.Id, ((IGuildUser)ctx.User).VoiceChannel.Id); + if (!success) + await Response().Error(strs.no_player).SendAsync(); + } + + // list queue, relevant page + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ListQueue() + { + // show page with the current track + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp)) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + await ListQueue((mp.CurrentIndex / LQ_ITEMS_PER_PAGE) + 1); + } + + // list queue, specify page + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ListQueue(int page) + { + if (--page < 0) + return; + + IReadOnlyCollection tracks; + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp) || (tracks = mp.GetQueuedTracks()).Count == 0) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + EmbedBuilder PrintAction(IReadOnlyList tracks, int curPage) + { + var desc = string.Empty; + var current = mp.GetCurrentTrack(out var currentIndex); + if (current is not null) + desc = $"`🔊` {current.PrettyFullName()}\n\n" + desc; + + var repeatType = mp.Repeat; + var add = string.Empty; + if (mp.IsStopped) + add += Format.Bold(GetText(strs.queue_stopped(Format.Code(prefix + "play")))) + "\n"; + // var mps = mp.MaxPlaytimeSeconds; + // if (mps > 0) + // add += Format.Bold(GetText(strs.song_skips_after(TimeSpan.FromSeconds(mps).ToString("HH\\:mm\\:ss")))) + "\n"; + if (repeatType == PlayerRepeatType.Track) + add += "🔂 " + GetText(strs.repeating_track) + "\n"; + else + { + if (mp.AutoPlay) + add += "↪ " + GetText(strs.autoplaying) + "\n"; + // if (mp.FairPlay && !mp.Autoplay) + // add += " " + GetText(strs.fairplay) + "\n"; + if (repeatType == PlayerRepeatType.Queue) + add += "🔁 " + GetText(strs.repeating_queue) + "\n"; + } + + + desc += tracks + .Select((v, index) => + { + index += LQ_ITEMS_PER_PAGE * curPage; + if (index == currentIndex) + return $"**⇒**`{index + 1}.` {v.PrettyFullName()}"; + + return $"`{index + 1}.` {v.PrettyFullName()}"; + }) + .Join('\n'); + + if (!string.IsNullOrWhiteSpace(add)) + desc = add + "\n" + desc; + + var embed = _sender.CreateEmbed() + .WithAuthor( + GetText(strs.player_queue(curPage + 1, (tracks.Count / LQ_ITEMS_PER_PAGE) + 1)), + MUSIC_ICON_URL) + .WithDescription(desc) + .WithFooter( + $" {mp.PrettyVolume()} | 🎶 {tracks.Count} | ⌛ {mp.PrettyTotalTime()} ") + .WithOkColor(); + + return embed; + } + + await Response() + .Paginated() + .Items(tracks) + .PageSize(LQ_ITEMS_PER_PAGE) + .CurrentPage(page) + .AddFooter(false) + .Page(PrintAction) + .SendAsync(); + } + + // search + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task QueueSearch([Leftover] string query) + { + _ = ctx.Channel.TriggerTypingAsync(); + + var videos = await _service.SearchVideosAsync(query); + + if (videos.Count == 0) + { + await Response().Error(strs.track_not_found).SendAsync(); + return; + } + + + var embeds = videos.Select((x, i) => _sender.CreateEmbed() + .WithOkColor() + .WithThumbnailUrl(x.Thumbnail) + .WithDescription($"`{i + 1}.` {Format.Bold(x.Title)}\n\t{x.Url}")) + .ToList(); + + var msg = await Response() + .Text(strs.queue_search_results) + .Embeds(embeds) + .SendAsync(); + + try + { + var input = await GetUserInputAsync(ctx.User.Id, ctx.Channel.Id, str => int.TryParse(str, out _)); + if (input is null || !int.TryParse(input, out var index) || (index -= 1) < 0 || index >= videos.Count) + { + _logService.AddDeleteIgnore(msg.Id); + try + { + await msg.DeleteAsync(); + } + catch + { + } + + return; + } + + query = videos[index].Url; + + await Play(query); + } + finally + { + _logService.AddDeleteIgnore(msg.Id); + try + { + await msg.DeleteAsync(); + } + catch + { + } + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public async Task TrackRemove(int index) + { + if (index < 1) + { + await Response().Error(strs.removed_track_error).SendAsync(); + return; + } + + var valid = await ValidateAsync(); + if (!valid) + return; + + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp)) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + if (!mp.TryRemoveTrackAt(index - 1, out var track)) + { + await Response().Error(strs.removed_track_error).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed() + .WithAuthor(GetText(strs.removed_track) + " #" + index, MUSIC_ICON_URL) + .WithDescription(track.PrettyName()) + .WithFooter(track.PrettyInfo()) + .WithErrorColor(); + + await _service.SendToOutputAsync(ctx.Guild.Id, embed); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public async Task TrackRemove(All _ = All.All) + { + var valid = await ValidateAsync(); + if (!valid) + return; + + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp)) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + mp.Clear(); + await Response().Confirm(strs.queue_cleared).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Stop() + { + var valid = await ValidateAsync(); + if (!valid) + return; + + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp)) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + mp.Stop(); + } + + private PlayerRepeatType InputToDbType(InputRepeatType type) + => type switch + { + InputRepeatType.None => PlayerRepeatType.None, + InputRepeatType.Queue => PlayerRepeatType.Queue, + InputRepeatType.Track => PlayerRepeatType.Track, + _ => PlayerRepeatType.Queue + }; + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task QueueRepeat(InputRepeatType type = InputRepeatType.Queue) + { + var valid = await ValidateAsync(); + if (!valid) + return; + + await _service.SetRepeatAsync(ctx.Guild.Id, InputToDbType(type)); + + if (type == InputRepeatType.None) + await Response().Confirm(strs.repeating_none).SendAsync(); + else if (type == InputRepeatType.Queue) + await Response().Confirm(strs.repeating_queue).SendAsync(); + else + await Response().Confirm(strs.repeating_track).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Pause() + { + var valid = await ValidateAsync(); + if (!valid) + return; + + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp) || mp.GetCurrentTrack(out _) is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + mp.TogglePause(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public Task Radio(string radioLink) + => QueueByQuery(radioLink, false, MusicPlatform.Radio); + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public Task Local([Leftover] string path) + => QueueByQuery(path, false, MusicPlatform.Local); + + [Cmd] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task LocalPlaylist([Leftover] string dirPath) + { + if (string.IsNullOrWhiteSpace(dirPath)) + return; + + var user = (IGuildUser)ctx.User; + var voiceChannelId = user.VoiceChannel?.Id; + + if (voiceChannelId is null) + { + await Response().Error(strs.must_be_in_voice).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var botUser = await ctx.Guild.GetCurrentUserAsync(); + await EnsureBotInVoiceChannelAsync(voiceChannelId!.Value, botUser); + + if (botUser.VoiceChannel?.Id != voiceChannelId) + { + await Response().Error(strs.not_with_bot_in_voice).SendAsync(); + return; + } + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + await _service.EnqueueDirectoryAsync(mp, dirPath, ctx.User.ToString()); + + await Response().Confirm(strs.dir_queue_complete).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task TrackMove(int from, int to) + { + if (--from < 0 || --to < 0 || from == to) + { + await Response().Error(strs.invalid_input).SendAsync(); + return; + } + + var valid = await ValidateAsync(); + if (!valid) + return; + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + var track = mp.MoveTrack(from, to); + if (track is null) + { + await Response().Error(strs.invalid_input).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed() + .WithTitle(track.Title.TrimTo(65)) + .WithAuthor(GetText(strs.track_moved), MUSIC_ICON_URL) + .AddField(GetText(strs.from_position), $"#{from + 1}", true) + .AddField(GetText(strs.to_position), $"#{to + 1}", true) + .WithOkColor(); + + if (Uri.IsWellFormedUriString(track.Url, UriKind.Absolute)) + embed.WithUrl(track.Url); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Playlist([Leftover] string playlistQuery) + { + if (string.IsNullOrWhiteSpace(playlistQuery)) + return; + + var succ = await QueuePreconditionInternalAsync(); + if (!succ) + return; + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + + var queuedCount = await _service.EnqueueYoutubePlaylistAsync(mp, playlistQuery, ctx.User.ToString()); + if (queuedCount == 0) + { + await Response().Error(strs.no_search_results).SendAsync(); + return; + } + + await ctx.OkAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task NowPlaying() + { + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + var currentTrack = mp.GetCurrentTrack(out _); + if (currentTrack is null) + return; + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(strs.now_playing), MUSIC_ICON_URL) + .WithDescription(currentTrack.PrettyName()) + .WithThumbnailUrl(currentTrack.Thumbnail) + .WithFooter( + $"{mp.PrettyVolume()} | {mp.PrettyTotalTime()} | {currentTrack.Platform} | {currentTrack.Queuer}"); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task PlaylistShuffle() + { + var valid = await ValidateAsync(); + if (!valid) + return; + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + mp.ShuffleQueue(); + await Response().Confirm(strs.queue_shuffled).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task SetMusicChannel() + { + await _service.SetMusicChannelAsync(ctx.Guild.Id, ctx.Channel.Id); + + await Response().Confirm(strs.set_music_channel).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task UnsetMusicChannel() + { + await _service.SetMusicChannelAsync(ctx.Guild.Id, null); + + await Response().Confirm(strs.unset_music_channel).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AutoDisconnect() + { + var newState = await _service.ToggleAutoDisconnectAsync(ctx.Guild.Id); + + if (newState) + await Response().Confirm(strs.autodc_enable).SendAsync(); + else + await Response().Confirm(strs.autodc_disable).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task MusicQuality() + { + var quality = await _service.GetMusicQualityAsync(ctx.Guild.Id); + await Response().Confirm(strs.current_music_quality(Format.Bold(quality.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task MusicQuality(QualityPreset preset) + { + await _service.SetMusicQualityAsync(ctx.Guild.Id, preset); + await Response().Confirm(strs.music_quality_set(Format.Bold(preset.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task QueueAutoPlay() + { + var newValue = await _service.ToggleQueueAutoPlayAsync(ctx.Guild.Id); + if (newValue) + await Response().Confirm(strs.music_autoplay_on).SendAsync(); + else + await Response().Confirm(strs.music_autoplay_off).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task QueueFairplay() + { + var newValue = await _service.FairplayAsync(ctx.Guild.Id); + if (newValue) + await Response().Confirm(strs.music_fairplay).SendAsync(); + else + await Response().Error(strs.no_player).SendAsync(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/PlaylistCommands.cs b/src/EllieBot/Modules/Music/PlaylistCommands.cs new file mode 100644 index 0000000..259bb9e --- /dev/null +++ b/src/EllieBot/Modules/Music/PlaylistCommands.cs @@ -0,0 +1,246 @@ +#nullable disable +using LinqToDB; +using EllieBot.Db; +using EllieBot.Modules.Music.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Music; + +public sealed partial class Music +{ + [Group] + public sealed partial class PlaylistCommands : EllieModule + { + private static readonly SemaphoreSlim _playlistLock = new(1, 1); + private readonly DbService _db; + private readonly IBotCredentials _creds; + + public PlaylistCommands(DbService db, IBotCredentials creds) + { + _db = db; + _creds = creds; + } + + private async Task EnsureBotInVoiceChannelAsync(ulong voiceChannelId, IGuildUser botUser = null) + { + botUser ??= await ctx.Guild.GetCurrentUserAsync(); + await _voiceChannelLock.WaitAsync(); + try + { + if (botUser.VoiceChannel?.Id is null || !_service.TryGetMusicPlayer(ctx.Guild.Id, out _)) + await _service.JoinVoiceChannelAsync(ctx.Guild.Id, voiceChannelId); + } + finally + { + _voiceChannelLock.Release(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Playlists([Leftover] int num = 1) + { + if (num <= 0) + return; + + List playlists; + + await using (var uow = _db.GetDbContext()) + { + playlists = uow.Set().GetPlaylistsOnPage(num); + } + + var embed = _sender.CreateEmbed() + .WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL) + .WithDescription(string.Join("\n", + playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count))))) + .WithOkColor(); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task DeletePlaylist([Leftover] int id) + { + var success = false; + try + { + await using var uow = _db.GetDbContext(); + var pl = uow.Set().FirstOrDefault(x => x.Id == id); + + if (pl is not null) + { + if (_creds.IsOwner(ctx.User) || pl.AuthorId == ctx.User.Id) + { + uow.Set().Remove(pl); + await uow.SaveChangesAsync(); + success = true; + } + } + } + catch (Exception ex) + { + Log.Warning(ex, "Error deleting playlist"); + } + + if (!success) + await Response().Error(strs.playlist_delete_fail).SendAsync(); + else + await Response().Confirm(strs.playlist_deleted).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task PlaylistShow(int id, int page = 1) + { + if (page-- < 1) + return; + + MusicPlaylist mpl; + await using (var uow = _db.GetDbContext()) + { + mpl = uow.Set().GetWithSongs(id); + } + + await Response() + .Paginated() + .Items(mpl.Songs) + .PageSize(20) + .CurrentPage(page) + .Page((items, _) => + { + var i = 0; + var str = string.Join("\n", + items + .Select(x => $"`{++i}.` [{x.Title.TrimTo(45)}]({x.Query}) `{x.Provider}`")); + return _sender.CreateEmbed().WithTitle($"\"{mpl.Name}\" by {mpl.Author}") + .WithOkColor() + .WithDescription(str); + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Save([Leftover] string name) + { + if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp)) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + var songs = mp.GetQueuedTracks() + .Select(s => new PlaylistSong + { + Provider = s.Platform.ToString(), + ProviderType = (MusicType)s.Platform, + Title = s.Title, + Query = s.Platform == MusicPlatform.Local ? s.GetStreamUrl().Result!.Trim('"') : s.Url + }) + .ToList(); + + MusicPlaylist playlist; + await using (var uow = _db.GetDbContext()) + { + playlist = new() + { + Name = name, + Author = ctx.User.Username, + AuthorId = ctx.User.Id, + Songs = songs.ToList() + }; + uow.Set().Add(playlist); + await uow.SaveChangesAsync(); + } + + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.playlist_saved)) + .AddField(GetText(strs.name), name) + .AddField(GetText(strs.id), playlist.Id.ToString())) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Load([Leftover] int id) + { + // expensive action, 1 at a time + await _playlistLock.WaitAsync(); + try + { + var user = (IGuildUser)ctx.User; + var voiceChannelId = user.VoiceChannel?.Id; + + if (voiceChannelId is null) + { + await Response().Error(strs.must_be_in_voice).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var botUser = await ctx.Guild.GetCurrentUserAsync(); + await EnsureBotInVoiceChannelAsync(voiceChannelId!.Value, botUser); + + if (botUser.VoiceChannel?.Id != voiceChannelId) + { + await Response().Error(strs.not_with_bot_in_voice).SendAsync(); + return; + } + + var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel); + if (mp is null) + { + await Response().Error(strs.no_player).SendAsync(); + return; + } + + MusicPlaylist mpl; + await using (var uow = _db.GetDbContext()) + { + mpl = uow.Set().GetWithSongs(id); + } + + if (mpl is null) + { + await Response().Error(strs.playlist_id_not_found).SendAsync(); + return; + } + + IUserMessage msg = null; + try + { + msg = await Response() + .Pending(strs.attempting_to_queue(Format.Bold(mpl.Songs.Count.ToString()))) + .SendAsync(); + } + catch (Exception) + { + } + + await mp.EnqueueManyAsync(mpl.Songs.Select(x => (x.Query, (MusicPlatform)x.ProviderType)), + ctx.User.ToString()); + + if (msg is not null) + await msg.ModifyAsync(m => m.Content = GetText(strs.playlist_queue_complete)); + } + finally + { + _playlistLock.Release(); + } + } + + [Cmd] + [OwnerOnly] + public async Task DeletePlaylists() + { + await using var uow = _db.GetDbContext(); + await uow.Set().DeleteAsync(); + await uow.SaveChangesAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/Services/AyuVoiceStateService.cs b/src/EllieBot/Modules/Music/Services/AyuVoiceStateService.cs new file mode 100644 index 0000000..ff47354 --- /dev/null +++ b/src/EllieBot/Modules/Music/Services/AyuVoiceStateService.cs @@ -0,0 +1,217 @@ +#nullable disable +using EllieBot.Voice; +using System.Reflection; + +namespace EllieBot.Modules.Music.Services; + +public sealed class AyuVoiceStateService : IEService +{ + // public delegate Task VoiceProxyUpdatedDelegate(ulong guildId, IVoiceProxy proxy); + // public event VoiceProxyUpdatedDelegate OnVoiceProxyUpdate = delegate { return Task.CompletedTask; }; + + private readonly ConcurrentDictionary _voiceProxies = new(); + private readonly ConcurrentDictionary _voiceGatewayLocks = new(); + + private readonly DiscordSocketClient _client; + private readonly MethodInfo _sendVoiceStateUpdateMethodInfo; + private readonly object _dnetApiClient; + private readonly ulong _currentUserId; + + public AyuVoiceStateService(DiscordSocketClient client) + { + _client = client; + _currentUserId = _client.CurrentUser.Id; + + var prop = _client.GetType() + .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) + .First(x => x.Name == "ApiClient" && x.PropertyType.Name == "DiscordSocketApiClient"); + _dnetApiClient = prop.GetValue(_client, null); + _sendVoiceStateUpdateMethodInfo = _dnetApiClient.GetType() + .GetMethod("SendVoiceStateUpdateAsync", + [ + typeof(ulong), typeof(ulong?), typeof(bool), + typeof(bool), typeof(RequestOptions) + ]); + + _client.LeftGuild += ClientOnLeftGuild; + } + + private Task ClientOnLeftGuild(SocketGuild guild) + { + if (_voiceProxies.TryRemove(guild.Id, out var proxy)) + { + proxy.StopGateway(); + proxy.SetGateway(null); + } + + return Task.CompletedTask; + } + + private Task InvokeSendVoiceStateUpdateAsync( + ulong guildId, + ulong? channelId = null, + bool isDeafened = false, + bool isMuted = false) + // return _voiceStateUpdate(guildId, channelId, isDeafened, isMuted); + => (Task)_sendVoiceStateUpdateMethodInfo.Invoke(_dnetApiClient, + [guildId, channelId, isMuted, isDeafened, null]); + + private Task SendLeaveVoiceChannelInternalAsync(ulong guildId) + => InvokeSendVoiceStateUpdateAsync(guildId); + + private Task SendJoinVoiceChannelInternalAsync(ulong guildId, ulong channelId) + => InvokeSendVoiceStateUpdateAsync(guildId, channelId); + + private SemaphoreSlim GetVoiceGatewayLock(ulong guildId) + => _voiceGatewayLocks.GetOrAdd(guildId, new SemaphoreSlim(1, 1)); + + private async Task LeaveVoiceChannelInternalAsync(ulong guildId) + { + var complete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + Task OnUserVoiceStateUpdated(SocketUser user, SocketVoiceState oldState, SocketVoiceState newState) + { + if (user is SocketGuildUser guildUser && guildUser.Guild.Id == guildId && newState.VoiceChannel?.Id is null) + complete.TrySetResult(true); + + return Task.CompletedTask; + } + + try + { + _client.UserVoiceStateUpdated += OnUserVoiceStateUpdated; + + if (_voiceProxies.TryGetValue(guildId, out var proxy)) + { + _ = proxy.StopGateway(); + proxy.SetGateway(null); + } + + await SendLeaveVoiceChannelInternalAsync(guildId); + await Task.WhenAny(Task.Delay(1500), complete.Task); + } + finally + { + _client.UserVoiceStateUpdated -= OnUserVoiceStateUpdated; + } + } + + public async Task LeaveVoiceChannel(ulong guildId) + { + var gwLock = GetVoiceGatewayLock(guildId); + await gwLock.WaitAsync(); + try + { + await LeaveVoiceChannelInternalAsync(guildId); + } + finally + { + gwLock.Release(); + } + } + + private async Task InternalConnectToVcAsync(ulong guildId, ulong channelId) + { + var voiceStateUpdatedSource = + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var voiceServerUpdatedSource = + new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + Task OnUserVoiceStateUpdated(SocketUser user, SocketVoiceState oldState, SocketVoiceState newState) + { + if (user is SocketGuildUser guildUser && guildUser.Guild.Id == guildId) + { + if (newState.VoiceChannel?.Id == channelId) + voiceStateUpdatedSource.TrySetResult(newState.VoiceSessionId); + + voiceStateUpdatedSource.TrySetResult(null); + } + + return Task.CompletedTask; + } + + Task OnVoiceServerUpdated(SocketVoiceServer data) + { + if (data.Guild.Id == guildId) + voiceServerUpdatedSource.TrySetResult(data); + + return Task.CompletedTask; + } + + try + { + _client.VoiceServerUpdated += OnVoiceServerUpdated; + _client.UserVoiceStateUpdated += OnUserVoiceStateUpdated; + + await SendJoinVoiceChannelInternalAsync(guildId, channelId); + + // create a delay task, how much to wait for gateway response + using var cts = new CancellationTokenSource(); + var delayTask = Task.Delay(2500, cts.Token); + + // either delay or successful voiceStateUpdate + var maybeUpdateTask = Task.WhenAny(delayTask, voiceStateUpdatedSource.Task); + // either delay or successful voiceServerUpdate + var maybeServerTask = Task.WhenAny(delayTask, voiceServerUpdatedSource.Task); + + // wait for both to end (max 1s) and check if either of them is a delay task + var results = await Task.WhenAll(maybeUpdateTask, maybeServerTask); + if (results[0] == delayTask || results[1] == delayTask) + // if either is delay, return null - connection unsuccessful + return null; + else + cts.Cancel(); + + // if both are succesful, that means we can safely get + // the values from completion sources + + var session = await voiceStateUpdatedSource.Task; + + // session can be null. Means we disconnected, or connected to the wrong channel (?!) + if (session is null) + return null; + + var voiceServerData = await voiceServerUpdatedSource.Task; + + VoiceGateway CreateVoiceGatewayLocal() + { + return new(guildId, _currentUserId, session, voiceServerData.Token, voiceServerData.Endpoint); + } + + var current = _voiceProxies.AddOrUpdate(guildId, + _ => new VoiceProxy(CreateVoiceGatewayLocal()), + (gid, currentProxy) => + { + _ = currentProxy.StopGateway(); + currentProxy.SetGateway(CreateVoiceGatewayLocal()); + return currentProxy; + }); + + _ = current.StartGateway(); // don't await, this blocks until gateway is closed + return current; + } + finally + { + _client.VoiceServerUpdated -= OnVoiceServerUpdated; + _client.UserVoiceStateUpdated -= OnUserVoiceStateUpdated; + } + } + + public async Task JoinVoiceChannel(ulong guildId, ulong channelId, bool forceReconnect = true) + { + var gwLock = GetVoiceGatewayLock(guildId); + await gwLock.WaitAsync(); + try + { + await LeaveVoiceChannelInternalAsync(guildId); + return await InternalConnectToVcAsync(guildId, channelId); + } + finally + { + gwLock.Release(); + } + } + + public bool TryGetProxy(ulong guildId, out IVoiceProxy proxy) + => _voiceProxies.TryGetValue(guildId, out proxy); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/Services/IMusicService.cs b/src/EllieBot/Modules/Music/Services/IMusicService.cs new file mode 100644 index 0000000..43bad99 --- /dev/null +++ b/src/EllieBot/Modules/Music/Services/IMusicService.cs @@ -0,0 +1,36 @@ +using EllieBot.Db.Models; +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Modules.Music.Services; + +public interface IMusicService +{ + /// + /// Leave voice channel in the specified guild if it's connected to one + /// + /// Id of the guild + public Task LeaveVoiceChannelAsync(ulong guildId); + + /// + /// Joins the voice channel with the specified id + /// + /// Id of the guild where the voice channel is + /// Id of the voice channel + public Task JoinVoiceChannelAsync(ulong guildId, ulong voiceChannelId); + + Task GetOrCreateMusicPlayerAsync(ITextChannel contextChannel); + bool TryGetMusicPlayer(ulong guildId, [MaybeNullWhen(false)] out IMusicPlayer musicPlayer); + Task EnqueueYoutubePlaylistAsync(IMusicPlayer mp, string playlistId, string queuer); + Task EnqueueDirectoryAsync(IMusicPlayer mp, string dirPath, string queuer); + Task SendToOutputAsync(ulong guildId, EmbedBuilder embed); + Task PlayAsync(ulong guildId, ulong voiceChannelId); + Task> SearchVideosAsync(string query); + Task SetMusicChannelAsync(ulong guildId, ulong? channelId); + Task SetRepeatAsync(ulong guildId, PlayerRepeatType repeatType); + Task SetVolumeAsync(ulong guildId, int value); + Task ToggleAutoDisconnectAsync(ulong guildId); + Task GetMusicQualityAsync(ulong guildId); + Task SetMusicQualityAsync(ulong guildId, QualityPreset preset); + Task ToggleQueueAutoPlayAsync(ulong guildId); + Task FairplayAsync(ulong guildId); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/Services/MusicService.cs b/src/EllieBot/Modules/Music/Services/MusicService.cs new file mode 100644 index 0000000..b2b3da3 --- /dev/null +++ b/src/EllieBot/Modules/Music/Services/MusicService.cs @@ -0,0 +1,437 @@ +using EllieBot.Db; +using EllieBot.Db.Models; +using System.Diagnostics.CodeAnalysis; + +namespace EllieBot.Modules.Music.Services; + +public sealed class MusicService : IMusicService, IPlaceholderProvider +{ + private readonly AyuVoiceStateService _voiceStateService; + private readonly ITrackResolveProvider _trackResolveProvider; + private readonly DbService _db; + private readonly IYoutubeResolver _ytResolver; + private readonly ILocalTrackResolver _localResolver; + private readonly DiscordSocketClient _client; + private readonly IBotStrings _strings; + private readonly IGoogleApiService _googleApiService; + private readonly YtLoader _ytLoader; + private readonly IMessageSenderService _sender; + + private readonly ConcurrentDictionary _players; + private readonly ConcurrentDictionary _outputChannels; + private readonly ConcurrentDictionary _settings; + + public MusicService( + AyuVoiceStateService voiceStateService, + ITrackResolveProvider trackResolveProvider, + DbService db, + IYoutubeResolver ytResolver, + ILocalTrackResolver localResolver, + DiscordSocketClient client, + IBotStrings strings, + IGoogleApiService googleApiService, + YtLoader ytLoader, + IMessageSenderService sender) + { + _voiceStateService = voiceStateService; + _trackResolveProvider = trackResolveProvider; + _db = db; + _ytResolver = ytResolver; + _localResolver = localResolver; + _client = client; + _strings = strings; + _googleApiService = googleApiService; + _ytLoader = ytLoader; + _sender = sender; + + _players = new(); + _outputChannels = new ConcurrentDictionary(); + _settings = new(); + + _client.LeftGuild += ClientOnLeftGuild; + } + + private void DisposeMusicPlayer(IMusicPlayer musicPlayer) + { + musicPlayer.Kill(); + _ = Task.Delay(10_000).ContinueWith(_ => musicPlayer.Dispose()); + } + + private void RemoveMusicPlayer(ulong guildId) + { + _outputChannels.TryRemove(guildId, out _); + if (_players.TryRemove(guildId, out var mp)) + DisposeMusicPlayer(mp); + } + + private Task ClientOnLeftGuild(SocketGuild guild) + { + RemoveMusicPlayer(guild.Id); + return Task.CompletedTask; + } + + public async Task LeaveVoiceChannelAsync(ulong guildId) + { + RemoveMusicPlayer(guildId); + await _voiceStateService.LeaveVoiceChannel(guildId); + } + + public Task JoinVoiceChannelAsync(ulong guildId, ulong voiceChannelId) + => _voiceStateService.JoinVoiceChannel(guildId, voiceChannelId); + + public async Task GetOrCreateMusicPlayerAsync(ITextChannel contextChannel) + { + var newPLayer = await CreateMusicPlayerInternalAsync(contextChannel.GuildId, contextChannel); + if (newPLayer is null) + return null; + + return _players.GetOrAdd(contextChannel.GuildId, newPLayer); + } + + public bool TryGetMusicPlayer(ulong guildId, [MaybeNullWhen(false)] out IMusicPlayer musicPlayer) + => _players.TryGetValue(guildId, out musicPlayer); + + public async Task EnqueueYoutubePlaylistAsync(IMusicPlayer mp, string query, string queuer) + { + var count = 0; + await foreach (var track in _ytResolver.ResolveTracksFromPlaylistAsync(query)) + { + if (mp.IsKilled) + break; + + mp.EnqueueTrack(track, queuer); + ++count; + } + + return count; + } + + public async Task EnqueueDirectoryAsync(IMusicPlayer mp, string dirPath, string queuer) + { + await foreach (var track in _localResolver.ResolveDirectoryAsync(dirPath)) + { + if (mp.IsKilled) + break; + + mp.EnqueueTrack(track, queuer); + } + } + + private async Task CreateMusicPlayerInternalAsync(ulong guildId, ITextChannel defaultChannel) + { + var queue = new MusicQueue(); + var resolver = _trackResolveProvider; + + if (!_voiceStateService.TryGetProxy(guildId, out var proxy)) + return null; + + var settings = await GetSettingsInternalAsync(guildId); + + ITextChannel? overrideChannel = null; + if (settings.MusicChannelId is { } channelId) + { + overrideChannel = _client.GetGuild(guildId)?.GetTextChannel(channelId); + + if (overrideChannel is null) + Log.Warning("Saved music output channel doesn't exist, falling back to current channel"); + } + + _outputChannels[guildId] = (defaultChannel, overrideChannel); + + var mp = new MusicPlayer(queue, + resolver, + proxy, + _googleApiService, + settings.QualityPreset, + settings.AutoPlay); + + mp.SetRepeat(settings.PlayerRepeat); + + if (settings.Volume is >= 0 and <= 100) + mp.SetVolume(settings.Volume); + else + Log.Error("Saved Volume is outside of valid range >= 0 && <=100 ({Volume})", settings.Volume); + + mp.OnCompleted += OnTrackCompleted(guildId); + mp.OnStarted += OnTrackStarted(guildId); + mp.OnQueueStopped += OnQueueStopped(guildId); + + return mp; + } + + public async Task SendToOutputAsync(ulong guildId, EmbedBuilder embed) + { + if (_outputChannels.TryGetValue(guildId, out var chan)) + { + var msg = await _sender.Response(chan.Override ?? chan.Default) + .Embed(embed) + .SendAsync(); + return msg; + } + + return null; + } + + private Func OnTrackCompleted(ulong guildId) + { + IUserMessage? lastFinishedMessage = null; + return async (mp, trackInfo) => + { + _ = lastFinishedMessage?.DeleteAsync(); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(guildId, strs.finished_track), Music.MUSIC_ICON_URL) + .WithDescription(trackInfo.PrettyName()) + .WithFooter(trackInfo.PrettyTotalTime()); + + lastFinishedMessage = await SendToOutputAsync(guildId, embed); + }; + } + + private Func OnTrackStarted(ulong guildId) + { + IUserMessage? lastPlayingMessage = null; + return async (mp, trackInfo, index) => + { + _ = lastPlayingMessage?.DeleteAsync(); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(GetText(guildId, strs.playing_track(index + 1)), Music.MUSIC_ICON_URL) + .WithDescription(trackInfo.PrettyName()) + .WithFooter($"{mp.PrettyVolume()} | {trackInfo.PrettyInfo()}"); + + lastPlayingMessage = await SendToOutputAsync(guildId, embed); + }; + } + + private Func OnQueueStopped(ulong guildId) + => _ => + { + if (_settings.TryGetValue(guildId, out var settings)) + { + if (settings.AutoDisconnect) + return LeaveVoiceChannelAsync(guildId); + } + + return Task.CompletedTask; + }; + + // this has to be done because dragging bot to another vc isn't supported yet + public async Task PlayAsync(ulong guildId, ulong voiceChannelId) + { + if (!TryGetMusicPlayer(guildId, out var mp)) + return false; + + if (mp.IsStopped) + { + if (!_voiceStateService.TryGetProxy(guildId, out var proxy) + || proxy.State == VoiceProxy.VoiceProxyState.Stopped) + await JoinVoiceChannelAsync(guildId, voiceChannelId); + } + + mp.Next(); + return true; + } + + private async Task> SearchYtLoaderVideosAsync(string query) + { + var result = await _ytLoader.LoadResultsAsync(query); + return result.Select(x => (x.Title, x.Url, x.Thumb)).ToList(); + } + + private async Task> SearchGoogleApiVideosAsync(string query) + { + var result = await _googleApiService.GetVideoInfosByKeywordAsync(query, 5); + return result.Select(x => (x.Name, x.Url, x.Thumbnail)).ToList(); + } + + public async Task> SearchVideosAsync(string query) + { + try + { + IList<(string, string, string)> videos = await SearchYtLoaderVideosAsync(query); + if (videos.Count > 0) + return videos; + } + catch (Exception ex) + { + Log.Warning("Failed geting videos with YtLoader: {ErrorMessage}", ex.Message); + } + + try + { + return await SearchGoogleApiVideosAsync(query); + } + catch (Exception ex) + { + Log.Warning("Failed getting video results with Google Api. " + + "Probably google api key missing: {ErrorMessage}", + ex.Message); + } + + return Array.Empty<(string, string, string)>(); + } + + private string GetText(ulong guildId, LocStr str) + => _strings.GetText(str, guildId); + + public IEnumerable<(string Name, Func Func)> GetPlaceholders() + { + // random track that's playing + yield return ("%music.playing%", () => + { + var randomPlayingTrack = _players.Select(x => x.Value.GetCurrentTrack(out _)) + .Where(x => x is not null) + .Shuffle() + .FirstOrDefault(); + + if (randomPlayingTrack is null) + return "-"; + + return randomPlayingTrack.Title; + }); + + // number of servers currently listening to music + yield return ("%music.servers%", () => + { + var count = _players.Select(x => x.Value.GetCurrentTrack(out _)).Count(x => x is not null); + + return count.ToString(); + }); + + yield return ("%music.queued%", () => + { + var count = _players.Sum(x => x.Value.GetQueuedTracks().Count); + + return count.ToString(); + }); + } + + #region Settings + + private async Task GetSettingsInternalAsync(ulong guildId) + { + if (_settings.TryGetValue(guildId, out var settings)) + return settings; + + await using var uow = _db.GetDbContext(); + var toReturn = _settings[guildId] = await uow.Set().ForGuildAsync(guildId); + await uow.SaveChangesAsync(); + + return toReturn; + } + + private async Task ModifySettingsInternalAsync( + ulong guildId, + Action action, + TState state) + { + await using var uow = _db.GetDbContext(); + var ms = await uow.Set().ForGuildAsync(guildId); + action(ms, state); + await uow.SaveChangesAsync(); + _settings[guildId] = ms; + } + + public async Task SetMusicChannelAsync(ulong guildId, ulong? channelId) + { + if (channelId is null) + { + await UnsetMusicChannelAsync(guildId); + return true; + } + + var channel = _client.GetGuild(guildId)?.GetTextChannel(channelId.Value); + if (channel is null) + return false; + + await ModifySettingsInternalAsync(guildId, + (settings, chId) => { settings.MusicChannelId = chId; }, + channelId); + + _outputChannels.AddOrUpdate(guildId, (channel, channel), (_, old) => (old.Default, channel)); + + return true; + } + + public async Task UnsetMusicChannelAsync(ulong guildId) + { + await ModifySettingsInternalAsync(guildId, + (settings, _) => { settings.MusicChannelId = null; }, + (ulong?)null); + + if (_outputChannels.TryGetValue(guildId, out var old)) + _outputChannels[guildId] = (old.Default, null); + } + + public async Task SetRepeatAsync(ulong guildId, PlayerRepeatType repeatType) + { + await ModifySettingsInternalAsync(guildId, + (settings, type) => { settings.PlayerRepeat = type; }, + repeatType); + + if (TryGetMusicPlayer(guildId, out var mp)) + mp.SetRepeat(repeatType); + } + + public async Task SetVolumeAsync(ulong guildId, int value) + { + if (value is < 0 or > 100) + throw new ArgumentOutOfRangeException(nameof(value)); + + await ModifySettingsInternalAsync(guildId, + (settings, newValue) => { settings.Volume = newValue; }, + value); + + if (TryGetMusicPlayer(guildId, out var mp)) + mp.SetVolume(value); + } + + public async Task ToggleAutoDisconnectAsync(ulong guildId) + { + var newState = false; + await ModifySettingsInternalAsync(guildId, + (settings, _) => { newState = settings.AutoDisconnect = !settings.AutoDisconnect; }, + default(object)); + + return newState; + } + + public async Task GetMusicQualityAsync(ulong guildId) + { + await using var uow = _db.GetDbContext(); + var settings = await uow.Set().ForGuildAsync(guildId); + return settings.QualityPreset; + } + + public Task SetMusicQualityAsync(ulong guildId, QualityPreset preset) + => ModifySettingsInternalAsync(guildId, + (settings, _) => { settings.QualityPreset = preset; }, + preset); + + public async Task ToggleQueueAutoPlayAsync(ulong guildId) + { + var newValue = false; + await ModifySettingsInternalAsync(guildId, + (settings, _) => newValue = settings.AutoPlay = !settings.AutoPlay, + false); + + if (TryGetMusicPlayer(guildId, out var mp)) + mp.AutoPlay = newValue; + + return newValue; + } + + public Task FairplayAsync(ulong guildId) + { + if (TryGetMusicPlayer(guildId, out var mp)) + { + mp.SetFairplay(); + return Task.FromResult(true); + } + + return Task.FromResult(false); + } + + #endregion +} diff --git a/src/EllieBot/Modules/Music/Services/extractor/Misc.cs b/src/EllieBot/Modules/Music/Services/extractor/Misc.cs new file mode 100644 index 0000000..68c1fca --- /dev/null +++ b/src/EllieBot/Modules/Music/Services/extractor/Misc.cs @@ -0,0 +1,74 @@ +#nullable disable +namespace EllieBot.Modules.Music.Services; + +public sealed partial class YtLoader +{ + public class InitRange + { + public string Start { get; set; } + public string End { get; set; } + } + + public class IndexRange + { + public string Start { get; set; } + public string End { get; set; } + } + + public class ColorInfo + { + public string Primaries { get; set; } + public string TransferCharacteristics { get; set; } + public string MatrixCoefficients { get; set; } + } + + public class YtAdaptiveFormat + { + public int Itag { get; set; } + public string MimeType { get; set; } + public int Bitrate { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public InitRange InitRange { get; set; } + public IndexRange IndexRange { get; set; } + public string LastModified { get; set; } + public string ContentLength { get; set; } + public string Quality { get; set; } + public int Fps { get; set; } + public string QualityLabel { get; set; } + public string ProjectionType { get; set; } + public int AverageBitrate { get; set; } + public ColorInfo ColorInfo { get; set; } + public string ApproxDurationMs { get; set; } + public string SignatureCipher { get; set; } + } + + public abstract class TrackInfo + { + public abstract string Url { get; } + public abstract string Title { get; } + public abstract string Thumb { get; } + public abstract TimeSpan Duration { get; } + } + + public sealed class YtTrackInfo : TrackInfo + { + private const string BASE_YOUTUBE_URL = "https://youtube.com/watch?v="; + public override string Url { get; } + public override string Title { get; } + public override string Thumb { get; } + public override TimeSpan Duration { get; } + + private readonly string _videoId; + + public YtTrackInfo(string title, string videoId, string thumb, TimeSpan duration) + { + Title = title; + Thumb = thumb; + Url = BASE_YOUTUBE_URL + videoId; + Duration = duration; + + _videoId = videoId; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/Services/extractor/YtLoader.cs b/src/EllieBot/Modules/Music/Services/extractor/YtLoader.cs new file mode 100644 index 0000000..a91dd11 --- /dev/null +++ b/src/EllieBot/Modules/Music/Services/extractor/YtLoader.cs @@ -0,0 +1,130 @@ +#nullable disable +using System.Globalization; +using System.Text; +using System.Text.Json; + +namespace EllieBot.Modules.Music.Services; + +public sealed partial class YtLoader : IEService +{ + private static readonly byte[] _ytResultInitialData = Encoding.UTF8.GetBytes("var ytInitialData = "); + private static readonly byte[] _ytResultJsonEnd = Encoding.UTF8.GetBytes(";<"); + + private static readonly string[] _durationFormats = + [ + @"m\:ss", @"mm\:ss", @"h\:mm\:ss", @"hh\:mm\:ss", @"hhh\:mm\:ss" + ]; + + private readonly IHttpClientFactory _httpFactory; + + public YtLoader(IHttpClientFactory httpFactory) + => _httpFactory = httpFactory; + + // public async Task LoadTrackByIdAsync(string videoId) + // { + // using var http = new HttpClient(); + // http.DefaultRequestHeaders.Add("X-YouTube-Client-Name", "1"); + // http.DefaultRequestHeaders.Add("X-YouTube-Client-Version", "2.20210520.09.00"); + // http.DefaultRequestHeaders.Add("Cookie", "CONSENT=YES+cb.20210530-19-p0.en+FX+071;"); + // + // var responseString = await http.GetStringAsync($"https://youtube.com?" + + // $"pbj=1" + + // $"&hl=en" + + // $"&v=" + videoId); + // + // var jsonDoc = JsonDocument.Parse(responseString).RootElement; + // var elem = jsonDoc.EnumerateArray() + // .FirstOrDefault(x => x.TryGetProperty("page", out var elem) && elem.GetString() == "watch"); + // + // var formatsJsonArray = elem.GetProperty("streamingdata") + // .GetProperty("formats") + // .GetRawText(); + // + // var formats = JsonSerializer.Deserialize>(formatsJsonArray); + // var result = formats + // .Where(x => x.MimeType.StartsWith("audio/")) + // .OrderByDescending(x => x.Bitrate) + // .FirstOrDefault(); + // + // if (result is null) + // return null; + // + // return new YtTrackInfo("1", "2", TimeSpan.Zero); + // } + + public async Task> LoadResultsAsync(string query) + { + query = Uri.EscapeDataString(query); + + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Add("Cookie", "CONSENT=YES+cb.20210530-19-p0.en+FX+071;"); + + byte[] response; + try + { + response = await http.GetByteArrayAsync($"https://youtube.com/results?hl=en&search_query={query}"); + } + catch (HttpRequestException ex) + { + Log.Warning("Unable to retrieve data with YtLoader: {ErrorMessage}", ex.Message); + return null; + } + + // there is a lot of useless html above the script tag, however if html gets significantly reduced + // this will result in the json being cut off + + var mem = GetScriptResponseSpan(response); + var root = JsonDocument.Parse(mem).RootElement; + + using var tracksJsonItems = root + .GetProperty("contents") + .GetProperty("twoColumnSearchResultsRenderer") + .GetProperty("primaryContents") + .GetProperty("sectionListRenderer") + .GetProperty("contents")[0] + .GetProperty("itemSectionRenderer") + .GetProperty("contents") + .EnumerateArray(); + + var tracks = new List(); + foreach (var track in tracksJsonItems) + { + if (!track.TryGetProperty("videoRenderer", out var elem)) + continue; + + var videoId = elem.GetProperty("videoId").GetString(); + var thumb = elem.GetProperty("thumbnail").GetProperty("thumbnails")[0].GetProperty("url").GetString(); + var title = elem.GetProperty("title").GetProperty("runs")[0].GetProperty("text").GetString(); + var durationString = elem.GetProperty("lengthText").GetProperty("simpleText").GetString(); + + if (!TimeSpan.TryParseExact(durationString, + _durationFormats, + CultureInfo.InvariantCulture, + out var duration)) + { + Log.Warning("Cannot parse duration: {DurationString}", durationString); + continue; + } + + tracks.Add(new YtTrackInfo(title, videoId, thumb, duration)); + if (tracks.Count >= 5) + break; + } + + return tracks; + } + + private Memory GetScriptResponseSpan(byte[] response) + { + var responseSpan = response.AsSpan()[140_000..]; + var startIndex = responseSpan.IndexOf(_ytResultInitialData); + if (startIndex == -1) + return null; // FUTURE try selecting html + startIndex += _ytResultInitialData.Length; + + var endIndex = + 140_000 + startIndex + responseSpan[(startIndex + 20_000)..].IndexOf(_ytResultJsonEnd) + 20_000; + startIndex += 140_000; + return response.AsMemory(startIndex, endIndex - startIndex); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/ICachableTrackData.cs b/src/EllieBot/Modules/Music/_common/ICachableTrackData.cs new file mode 100644 index 0000000..020e074 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/ICachableTrackData.cs @@ -0,0 +1,12 @@ +#nullable disable +namespace EllieBot.Modules.Music; + +public interface ICachableTrackData +{ + string Id { get; set; } + string Url { get; set; } + string Thumbnail { get; set; } + public TimeSpan Duration { get; } + MusicPlatform Platform { get; set; } + string Title { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/ILocalTrackResolver.cs b/src/EllieBot/Modules/Music/_common/ILocalTrackResolver.cs new file mode 100644 index 0000000..f4ea2bf --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/ILocalTrackResolver.cs @@ -0,0 +1,7 @@ +#nullable disable +namespace EllieBot.Modules.Music; + +public interface ILocalTrackResolver : IPlatformQueryResolver +{ + IAsyncEnumerable ResolveDirectoryAsync(string dirPath); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IMusicPlayer.cs b/src/EllieBot/Modules/Music/_common/IMusicPlayer.cs new file mode 100644 index 0000000..a593a57 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IMusicPlayer.cs @@ -0,0 +1,41 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Music; + +public interface IMusicPlayer : IDisposable +{ + float Volume { get; } + bool IsPaused { get; } + bool IsStopped { get; } + bool IsKilled { get; } + int CurrentIndex { get; } + public PlayerRepeatType Repeat { get; } + bool AutoPlay { get; set; } + + void Stop(); + void Clear(); + IReadOnlyCollection GetQueuedTracks(); + IQueuedTrackInfo? GetCurrentTrack(out int index); + void Next(); + bool MoveTo(int index); + void SetVolume(int newVolume); + + void Kill(); + bool TryRemoveTrackAt(int index, out IQueuedTrackInfo? trackInfo); + + + Task<(IQueuedTrackInfo? QueuedTrack, int Index)> TryEnqueueTrackAsync( + string query, + string queuer, + bool asNext, + MusicPlatform? forcePlatform = null); + + Task EnqueueManyAsync(IEnumerable<(string Query, MusicPlatform Platform)> queries, string queuer); + bool TogglePause(); + IQueuedTrackInfo? MoveTrack(int from, int to); + void EnqueueTrack(ITrackInfo track, string queuer); + void EnqueueTracks(IEnumerable tracks, string queuer); + void SetRepeat(PlayerRepeatType type); + void ShuffleQueue(); + void SetFairplay(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IMusicQueue.cs b/src/EllieBot/Modules/Music/_common/IMusicQueue.cs new file mode 100644 index 0000000..5d4d24b --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IMusicQueue.cs @@ -0,0 +1,23 @@ +namespace EllieBot.Modules.Music; + +public interface IMusicQueue +{ + int Index { get; } + int Count { get; } + IQueuedTrackInfo Enqueue(ITrackInfo trackInfo, string queuer, out int index); + IQueuedTrackInfo EnqueueNext(ITrackInfo song, string queuer, out int index); + + void EnqueueMany(IEnumerable tracks, string queuer); + + public IReadOnlyCollection List(); + IQueuedTrackInfo? GetCurrent(out int index); + void Advance(); + void Clear(); + bool SetIndex(int index); + bool TryRemoveAt(int index, out IQueuedTrackInfo? trackInfo, out bool isCurrent); + void RemoveCurrent(); + IQueuedTrackInfo? MoveTrack(int from, int to); + void Shuffle(Random rng); + bool IsLast(); + void ReorderFairly(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IPlatformQueryResolver.cs b/src/EllieBot/Modules/Music/_common/IPlatformQueryResolver.cs new file mode 100644 index 0000000..fa282ed --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IPlatformQueryResolver.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Music; + +public interface IPlatformQueryResolver +{ + Task ResolveByQueryAsync(string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IQueuedTrackInfo.cs b/src/EllieBot/Modules/Music/_common/IQueuedTrackInfo.cs new file mode 100644 index 0000000..5093cd9 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IQueuedTrackInfo.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Modules.Music; + +public interface IQueuedTrackInfo : ITrackInfo +{ + public ITrackInfo TrackInfo { get; } + + public string Queuer { get; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IRadioResolver.cs b/src/EllieBot/Modules/Music/_common/IRadioResolver.cs new file mode 100644 index 0000000..86a6ba5 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IRadioResolver.cs @@ -0,0 +1,6 @@ +#nullable disable +namespace EllieBot.Modules.Music; + +public interface IRadioResolver : IPlatformQueryResolver +{ +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/ITrackCacher.cs b/src/EllieBot/Modules/Music/_common/ITrackCacher.cs new file mode 100644 index 0000000..d55cd65 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/ITrackCacher.cs @@ -0,0 +1,25 @@ +namespace EllieBot.Modules.Music; + +public interface ITrackCacher +{ + Task GetOrCreateStreamLink( + string id, + MusicPlatform platform, + Func> streamUrlFactory); + + Task CacheTrackDataAsync(ICachableTrackData data); + Task GetCachedDataByIdAsync(string id, MusicPlatform platform); + Task GetCachedDataByQueryAsync(string query, MusicPlatform platform); + Task CacheTrackDataByQueryAsync(string query, ICachableTrackData data); + + Task CacheStreamUrlAsync( + string id, + MusicPlatform platform, + string url, + TimeSpan expiry); + + Task> GetPlaylistTrackIdsAsync(string playlistId, MusicPlatform platform); + Task CachePlaylistTrackIdsAsync(string playlistId, MusicPlatform platform, IEnumerable ids); + Task CachePlaylistIdByQueryAsync(string query, MusicPlatform platform, string playlistId); + Task GetPlaylistIdByQueryAsync(string query, MusicPlatform platform); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/ITrackInfo.cs b/src/EllieBot/Modules/Music/_common/ITrackInfo.cs new file mode 100644 index 0000000..347e8fa --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/ITrackInfo.cs @@ -0,0 +1,12 @@ +namespace EllieBot.Modules.Music; + +public interface ITrackInfo +{ + public string Id => string.Empty; + public string Title { get; } + public string Url { get; } + public string Thumbnail { get; } + public TimeSpan Duration { get; } + public MusicPlatform Platform { get; } + public ValueTask GetStreamUrl(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/ITrackResolveProvider.cs b/src/EllieBot/Modules/Music/_common/ITrackResolveProvider.cs new file mode 100644 index 0000000..ae3d1e6 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/ITrackResolveProvider.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Music; + +public interface ITrackResolveProvider +{ + Task QuerySongAsync(string query, MusicPlatform? forcePlatform); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IVoiceProxy.cs b/src/EllieBot/Modules/Music/_common/IVoiceProxy.cs new file mode 100644 index 0000000..d88e51c --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IVoiceProxy.cs @@ -0,0 +1,15 @@ +#nullable disable +using EllieBot.Voice; + +namespace EllieBot.Modules.Music; + +public interface IVoiceProxy +{ + VoiceProxy.VoiceProxyState State { get; } + public bool SendPcmFrame(VoiceClient vc, Span data, int length); + public void SetGateway(VoiceGateway gateway); + Task StartSpeakingAsync(); + Task StopSpeakingAsync(); + public Task StartGateway(); + Task StopGateway(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/IYoutubeResolver.cs b/src/EllieBot/Modules/Music/_common/IYoutubeResolver.cs new file mode 100644 index 0000000..433012d --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/IYoutubeResolver.cs @@ -0,0 +1,11 @@ +using System.Text.RegularExpressions; + +namespace EllieBot.Modules.Music; + +public interface IYoutubeResolver : IPlatformQueryResolver +{ + public Regex YtVideoIdRegex { get; } + public Task ResolveByIdAsync(string id); + IAsyncEnumerable ResolveTracksFromPlaylistAsync(string query); + Task ResolveByQueryAsync(string query, bool tryExtractingId); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/CachableTrackData.cs b/src/EllieBot/Modules/Music/_common/Impl/CachableTrackData.cs new file mode 100644 index 0000000..4e663ad --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/CachableTrackData.cs @@ -0,0 +1,19 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Music; + +public sealed class CachableTrackData : ICachableTrackData +{ + public string Title { get; set; } = string.Empty; + public string Id { get; set; } = string.Empty; + public string Url { get; set; } = string.Empty; + public string Thumbnail { get; set; } = string.Empty; + public double TotalDurationMs { get; set; } + + [JsonIgnore] + public TimeSpan Duration + => TimeSpan.FromMilliseconds(TotalDurationMs); + + public MusicPlatform Platform { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/MultimediaTimer.cs b/src/EllieBot/Modules/Music/_common/Impl/MultimediaTimer.cs new file mode 100644 index 0000000..9c8a9a3 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/MultimediaTimer.cs @@ -0,0 +1,95 @@ +#nullable disable +using System.Runtime.InteropServices; + +namespace EllieBot.Modules.Music.Common; + +public sealed class MultimediaTimer : IDisposable +{ + private LpTimeProcDelegate lpTimeProc; + private readonly uint _eventId; + private readonly Action _callback; + private readonly object _state; + + public MultimediaTimer(Action callback, object state, int period) + { + if (period <= 0) + throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than 0"); + + _callback = callback; + _state = state; + + lpTimeProc = CallbackInternal; + _eventId = timeSetEvent((uint)period, 1, lpTimeProc, 0, TimerMode.Periodic); + } + + /// + /// The timeSetEvent function starts a specified timer event. The multimedia timer runs in its own thread. + /// After the event is activated, it calls the specified callback function or sets or pulses the specified + /// event object. + /// + /// + /// Event delay, in milliseconds. If this value is not in the range of the minimum and + /// maximum event delays supported by the timer, the function returns an error. + /// + /// + /// Resolution of the timer event, in milliseconds. The resolution increases with + /// smaller values; a resolution of 0 indicates periodic events should occur with the greatest possible accuracy. + /// To reduce system overhead, however, you should use the maximum value appropriate for your application. + /// + /// + /// Pointer to a callback function that is called once upon expiration of a single event or periodically upon + /// expiration of periodic events. If fuEvent specifies the TIME_CALLBACK_EVENT_SET or TIME_CALLBACK_EVENT_PULSE + /// flag, then the lpTimeProc parameter is interpreted as a handle to an event object. The event will be set or + /// pulsed upon completion of a single event or periodically upon completion of periodic events. + /// For any other value of fuEvent, the lpTimeProc parameter is a pointer to a callback function of type + /// LPTIMECALLBACK. + /// + /// User-supplied callback data. + /// + /// Timer event type. This parameter may include one of the following values. + [DllImport("Winmm.dll")] + private static extern uint timeSetEvent( + uint uDelay, + uint uResolution, + LpTimeProcDelegate lpTimeProc, + int dwUser, + TimerMode fuEvent); + + /// + /// The timeKillEvent function cancels a specified timer event. + /// + /// + /// Identifier of the timer event to cancel. + /// This identifier was returned by the timeSetEvent function when the timer event was set up. + /// + /// Returns TIMERR_NOERROR if successful or MMSYSERR_INVALPARAM if the specified timer event does not exist. + [DllImport("Winmm.dll")] + private static extern int timeKillEvent(uint uTimerId); + + private void CallbackInternal( + uint uTimerId, + uint uMsg, + int dwUser, + int dw1, + int dw2) + => _callback(_state); + + public void Dispose() + { + lpTimeProc = default; + timeKillEvent(_eventId); + } + + private delegate void LpTimeProcDelegate( + uint uTimerId, + uint uMsg, + int dwUser, + int dw1, + int dw2); + + private enum TimerMode + { + OneShot, + Periodic + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/MusicExtensions.cs b/src/EllieBot/Modules/Music/_common/Impl/MusicExtensions.cs new file mode 100644 index 0000000..cab883b --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/MusicExtensions.cs @@ -0,0 +1,57 @@ +#nullable disable +namespace EllieBot.Modules.Music; + +public static class MusicExtensions +{ + public static string PrettyTotalTime(this IMusicPlayer mp) + { + long sum = 0; + foreach (var track in mp.GetQueuedTracks()) + { + if (track.Duration == TimeSpan.MaxValue) + return "∞"; + + sum += track.Duration.Ticks; + } + + var total = new TimeSpan(sum); + + return total.ToString(@"hh\:mm\:ss"); + } + + public static string PrettyVolume(this IMusicPlayer mp) + => $"🔉 {(int)(mp.Volume * 100)}%"; + + public static string PrettyName(this ITrackInfo trackInfo) + => $"**[{trackInfo.Title.TrimTo(60).Replace("[", "\\[").Replace("]", "\\]")}]({trackInfo.Url.TrimTo(50, true)})**"; + + public static string PrettyInfo(this IQueuedTrackInfo trackInfo) + => $"{trackInfo.PrettyTotalTime()} | {trackInfo.Platform} | {trackInfo.Queuer}"; + + public static string PrettyFullName(this IQueuedTrackInfo trackInfo) + => $@"{trackInfo.PrettyName()} + `{trackInfo.PrettyTotalTime()} | {trackInfo.Platform} | {Format.Sanitize(trackInfo.Queuer.TrimTo(15))}`"; + + public static string PrettyTotalTime(this ITrackInfo trackInfo) + { + if (trackInfo.Duration == TimeSpan.Zero) + return "(?)"; + if (trackInfo.Duration == TimeSpan.MaxValue) + return "∞"; + if (trackInfo.Duration.TotalHours >= 1) + return trackInfo.Duration.ToString("""hh\:mm\:ss"""); + + return trackInfo.Duration.ToString("""mm\:ss"""); + } + + public static ICachableTrackData ToCachedData(this ITrackInfo trackInfo, string id) + => new CachableTrackData + { + TotalDurationMs = trackInfo.Duration.TotalMilliseconds, + Id = id, + Thumbnail = trackInfo.Thumbnail, + Url = trackInfo.Url, + Platform = trackInfo.Platform, + Title = trackInfo.Title + }; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/MusicPlatform.cs b/src/EllieBot/Modules/Music/_common/Impl/MusicPlatform.cs new file mode 100644 index 0000000..0d6c149 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/MusicPlatform.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Modules.Music; + +public enum MusicPlatform +{ + Radio, + Youtube, + Local, +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/MusicPlayer.cs b/src/EllieBot/Modules/Music/_common/Impl/MusicPlayer.cs new file mode 100644 index 0000000..6819d4e --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/MusicPlayer.cs @@ -0,0 +1,531 @@ +using EllieBot.Voice; +using EllieBot.Db.Models; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace EllieBot.Modules.Music; + +public sealed class MusicPlayer : IMusicPlayer +{ + public event Func? OnCompleted; + public event Func? OnStarted; + public event Func? OnQueueStopped; + public bool IsKilled { get; private set; } + public bool IsStopped { get; private set; } + public bool IsPaused { get; private set; } + public PlayerRepeatType Repeat { get; private set; } + + public int CurrentIndex + => _queue.Index; + + public float Volume { get; private set; } = 1.0f; + + private readonly AdjustVolumeDelegate _adjustVolume; + private readonly VoiceClient _vc; + + private readonly IMusicQueue _queue; + private readonly ITrackResolveProvider _trackResolveProvider; + private readonly IVoiceProxy _proxy; + private readonly IGoogleApiService _googleApiService; + private readonly ISongBuffer _songBuffer; + + private bool skipped; + private int? forceIndex; + private readonly Thread _thread; + private readonly Random _rng; + + public bool AutoPlay { get; set; } + + public MusicPlayer( + IMusicQueue queue, + ITrackResolveProvider trackResolveProvider, + IVoiceProxy proxy, + IGoogleApiService googleApiService, + QualityPreset qualityPreset, + bool autoPlay) + { + _queue = queue; + _trackResolveProvider = trackResolveProvider; + _proxy = proxy; + _googleApiService = googleApiService; + AutoPlay = autoPlay; + _rng = new EllieRandom(); + + _vc = GetVoiceClient(qualityPreset); + if (_vc.BitDepth == 16) + _adjustVolume = AdjustVolumeInt16; + else + _adjustVolume = AdjustVolumeFloat32; + + _songBuffer = new PoopyBufferImmortalized(_vc.InputLength); + + _thread = new(async () => { await PlayLoop(); }); + _thread.Start(); + } + + private static VoiceClient GetVoiceClient(QualityPreset qualityPreset) + => qualityPreset switch + { + QualityPreset.Highest => new(), + QualityPreset.High => new(SampleRate._48k, Bitrate._128k, Channels.Two, FrameDelay.Delay40), + QualityPreset.Medium => new(SampleRate._48k, + Bitrate._96k, + Channels.Two, + FrameDelay.Delay40, + BitDepthEnum.UInt16), + QualityPreset.Low => new(SampleRate._48k, + Bitrate._64k, + Channels.Two, + FrameDelay.Delay40, + BitDepthEnum.UInt16), + _ => throw new ArgumentOutOfRangeException(nameof(qualityPreset), qualityPreset, null) + }; + + private async Task PlayLoop() + { + var sw = new Stopwatch(); + + while (!IsKilled) + { + // wait until a song is available in the queue + // or until the queue is resumed + var track = _queue.GetCurrent(out var index); + + if (track is null || IsStopped) + { + await Task.Delay(500); + continue; + } + + if (skipped) + { + skipped = false; + _queue.Advance(); + continue; + } + + using var cancellationTokenSource = new CancellationTokenSource(); + var token = cancellationTokenSource.Token; + try + { + // light up green in vc + _ = _proxy.StartSpeakingAsync(); + + _ = OnStarted?.Invoke(this, track, index); + + // make sure song buffer is ready to be (re)used + _songBuffer.Reset(); + + var streamUrl = await track.GetStreamUrl(); + // start up the data source + using var source = FfmpegTrackDataSource.CreateAsync( + _vc.BitDepth, + streamUrl, + track.Platform == MusicPlatform.Local); + + // start moving data from the source into the buffer + // this method will return once the sufficient prebuffering is done + await _songBuffer.BufferAsync(source, token); + + // // Implemenation with multimedia timer. Works but a hassle because no support for switching + // // vcs, as any error in copying will cancel the song. Also no idea how to use this as an option + // // for selfhosters. + // if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // { + // var cancelSource = new CancellationTokenSource(); + // var cancelToken = cancelSource.Token; + // using var timer = new MultimediaTimer(_ => + // { + // if (IsStopped || IsKilled) + // { + // cancelSource.Cancel(); + // return; + // } + // + // if (_skipped) + // { + // _skipped = false; + // cancelSource.Cancel(); + // return; + // } + // + // if (IsPaused) + // return; + // + // try + // { + // // this should tolerate certain number of errors + // var result = CopyChunkToOutput(_songBuffer, _vc); + // if (!result) + // cancelSource.Cancel(); + // + // } + // catch (Exception ex) + // { + // Log.Warning(ex, "Something went wrong sending voice data: {ErrorMessage}", ex.Message); + // cancelSource.Cancel(); + // } + // + // }, null, 20); + // + // while(true) + // await Task.Delay(1000, cancelToken); + // } + + // start sending data + var ticksPerMs = 1000f / Stopwatch.Frequency; + sw.Start(); + Thread.Sleep(2); + + var delay = sw.ElapsedTicks * ticksPerMs > 3f ? _vc.Delay - 16 : _vc.Delay - 3; + + var errorCount = 0; + while (!IsStopped && !IsKilled) + { + // doing the skip this way instead of in the condition + // ensures that a song will for sure be skipped + if (skipped) + { + skipped = false; + break; + } + + if (IsPaused) + { + await Task.Delay(200); + continue; + } + + sw.Restart(); + var ticks = sw.ElapsedTicks; + try + { + var result = CopyChunkToOutput(_songBuffer, _vc); + + // if song is finished + if (result is null) + break; + + if (result is true) + { + if (errorCount > 0) + { + _ = _proxy.StartSpeakingAsync(); + errorCount = 0; + } + + // FUTURE windows multimedia api + + // wait for slightly less than the latency + Thread.Sleep(delay); + + // and then spin out the rest + while ((sw.ElapsedTicks - ticks) * ticksPerMs <= _vc.Delay - 0.1f) + Thread.SpinWait(100); + } + else + { + // result is false is either when the gateway is being swapped + // or if the bot is reconnecting, or just disconnected for whatever reason + + // tolerate up to 15x200ms of failures (3 seconds) + if (++errorCount <= 15) + { + await Task.Delay(200); + continue; + } + + Log.Warning("Can't send data to voice channel"); + + IsStopped = true; + // if errors are happening for more than 3 seconds + // Stop the player + break; + } + } + catch (Exception ex) + { + Log.Warning(ex, "Something went wrong sending voice data: {ErrorMessage}", ex.Message); + } + } + } + catch (Win32Exception) + { + IsStopped = true; + Log.Error("Please install ffmpeg and make sure it's added to your " + + "PATH environment variable before trying again"); + } + catch (OperationCanceledException) + { + Log.Information("Song skipped"); + } + catch (Exception ex) + { + Log.Error(ex, "Unknown error in music loop: {ErrorMessage}", ex.Message); + } + finally + { + cancellationTokenSource.Cancel(); + // turn off green in vc + + _ = OnCompleted?.Invoke(this, track); + + if (AutoPlay && track.Platform == MusicPlatform.Youtube) + { + try + { + var relatedSongs = await _googleApiService.GetRelatedVideosAsync(track.TrackInfo.Id, 5); + var related = relatedSongs.Shuffle().FirstOrDefault(); + if (related is not null) + { + var relatedTrack = + await _trackResolveProvider.QuerySongAsync(related, MusicPlatform.Youtube); + if (relatedTrack is not null) + EnqueueTrack(relatedTrack, "Autoplay"); + } + } + catch (Exception ex) + { + Log.Warning(ex, "Failed queueing a related song via autoplay"); + } + } + + + HandleQueuePostTrack(); + skipped = false; + + _ = _proxy.StopSpeakingAsync(); + + await Task.Delay(100); + } + } + } + + private bool? CopyChunkToOutput(ISongBuffer sb, VoiceClient vc) + { + var data = sb.Read(vc.InputLength, out var length); + + // if nothing is read from the buffer, song is finished + if (data.Length == 0) + return null; + + _adjustVolume(data, Volume); + return _proxy.SendPcmFrame(vc, data, length); + } + + private void HandleQueuePostTrack() + { + if (forceIndex is { } index) + { + _queue.SetIndex(index); + forceIndex = null; + return; + } + + var (repeat, isStopped) = (Repeat, IsStopped); + + if (repeat == PlayerRepeatType.Track || isStopped) + return; + + // if queue is being repeated, advance no matter what + if (repeat == PlayerRepeatType.None) + { + // if this is the last song, + // stop the queue + if (_queue.IsLast()) + { + IsStopped = true; + OnQueueStopped?.Invoke(this); + return; + } + + _queue.Advance(); + return; + } + + _queue.Advance(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AdjustVolumeInt16(Span audioSamples, float volume) + { + if (Math.Abs(volume - 1f) < 0.0001f) + return; + + var samples = MemoryMarshal.Cast(audioSamples); + + for (var i = 0; i < samples.Length; i++) + { + ref var sample = ref samples[i]; + sample = (short)(sample * volume); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AdjustVolumeFloat32(Span audioSamples, float volume) + { + if (Math.Abs(volume - 1f) < 0.0001f) + return; + + var samples = MemoryMarshal.Cast(audioSamples); + + for (var i = 0; i < samples.Length; i++) + { + ref var sample = ref samples[i]; + sample *= volume; + } + } + + public async Task<(IQueuedTrackInfo? QueuedTrack, int Index)> TryEnqueueTrackAsync( + string query, + string queuer, + bool asNext, + MusicPlatform? forcePlatform = null) + { + var song = await _trackResolveProvider.QuerySongAsync(query, forcePlatform); + if (song is null) + return default; + + int index; + + if (asNext) + return (_queue.EnqueueNext(song, queuer, out index), index); + + return (_queue.Enqueue(song, queuer, out index), index); + } + + public async Task EnqueueManyAsync(IEnumerable<(string Query, MusicPlatform Platform)> queries, string queuer) + { + var errorCount = 0; + foreach (var chunk in queries.Chunk(5)) + { + if (IsKilled) + break; + + await chunk.Select(async data => + { + var (query, platform) = data; + try + { + await TryEnqueueTrackAsync(query, queuer, false, platform); + errorCount = 0; + } + catch (Exception ex) + { + Log.Warning(ex, "Error resolving {MusicPlatform} Track {TrackQuery}", platform, query); + ++errorCount; + } + }) + .WhenAll(); + + await Task.Delay(1000); + + // > 10 errors in a row = kill + if (errorCount > 10) + break; + } + } + + public void EnqueueTrack(ITrackInfo track, string queuer) + => _queue.Enqueue(track, queuer, out _); + + public void EnqueueTracks(IEnumerable tracks, string queuer) + => _queue.EnqueueMany(tracks, queuer); + + public void SetRepeat(PlayerRepeatType type) + => Repeat = type; + + public void ShuffleQueue() + => _queue.Shuffle(_rng); + + public void Stop() + => IsStopped = true; + + public void Clear() + { + _queue.Clear(); + skipped = true; + } + + public IReadOnlyCollection GetQueuedTracks() + => _queue.List(); + + public IQueuedTrackInfo? GetCurrentTrack(out int index) + => _queue.GetCurrent(out index); + + public void Next() + { + skipped = true; + IsStopped = false; + IsPaused = false; + } + + public bool MoveTo(int index) + { + if (_queue.SetIndex(index)) + { + forceIndex = index; + skipped = true; + IsStopped = false; + IsPaused = false; + return true; + } + + return false; + } + + public void SetVolume(int newVolume) + { + var normalizedVolume = newVolume / 100f; + if (normalizedVolume is < 0f or > 1f) + throw new ArgumentOutOfRangeException(nameof(newVolume), "Volume must be in range 0-100"); + + Volume = normalizedVolume; + } + + public void Kill() + { + IsKilled = true; + IsStopped = true; + IsPaused = false; + skipped = true; + } + + public bool TryRemoveTrackAt(int index, out IQueuedTrackInfo? trackInfo) + { + if (!_queue.TryRemoveAt(index, out trackInfo, out var isCurrent)) + return false; + + if (isCurrent) + skipped = true; + + return true; + } + + public bool TogglePause() + => IsPaused = !IsPaused; + + public IQueuedTrackInfo? MoveTrack(int from, int to) + => _queue.MoveTrack(from, to); + + public void Dispose() + { + IsKilled = true; + OnCompleted = null; + OnStarted = null; + OnQueueStopped = null; + _queue.Clear(); + _songBuffer.Dispose(); + _vc.Dispose(); + } + + private delegate void AdjustVolumeDelegate(Span data, float volume); + + public void SetFairplay() + { + _queue.ReorderFairly(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/MusicQueue.cs b/src/EllieBot/Modules/Music/_common/Impl/MusicQueue.cs new file mode 100644 index 0000000..1b1ce9c --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/MusicQueue.cs @@ -0,0 +1,345 @@ +namespace EllieBot.Modules.Music; + +public sealed partial class MusicQueue +{ + private sealed class QueuedTrackInfo : IQueuedTrackInfo + { + public ITrackInfo TrackInfo { get; } + public string Queuer { get; } + + public string Title + => TrackInfo.Title; + + public string Url + => TrackInfo.Url; + + public string Thumbnail + => TrackInfo.Thumbnail; + + public TimeSpan Duration + => TrackInfo.Duration; + + public MusicPlatform Platform + => TrackInfo.Platform; + + + public QueuedTrackInfo(ITrackInfo trackInfo, string queuer) + { + TrackInfo = trackInfo; + Queuer = queuer; + } + + public ValueTask GetStreamUrl() + => TrackInfo.GetStreamUrl(); + } +} + +public sealed partial class MusicQueue : IMusicQueue +{ + public int Index + { + get + { + // just make sure the internal logic runs first + // to make sure that some potential intermediate value is not returned + lock (_locker) + { + return index; + } + } + } + + public int Count + { + get + { + lock (_locker) + { + return tracks.Count; + } + } + } + + private LinkedList tracks; + + private int index; + + private readonly object _locker = new(); + + public MusicQueue() + { + index = 0; + tracks = new(); + } + + public IQueuedTrackInfo Enqueue(ITrackInfo trackInfo, string queuer, out int enqueuedAt) + { + lock (_locker) + { + var added = new QueuedTrackInfo(trackInfo, queuer); + enqueuedAt = tracks.Count; + tracks.AddLast(added); + + return added; + } + } + + + public IQueuedTrackInfo EnqueueNext(ITrackInfo trackInfo, string queuer, out int trackIndex) + { + lock (_locker) + { + if (tracks.Count == 0) + return Enqueue(trackInfo, queuer, out trackIndex); + + var currentNode = tracks.First!; + int i; + for (i = 1; i <= index; i++) + currentNode = currentNode.Next!; // can't be null because index is always in range of the count + + var added = new QueuedTrackInfo(trackInfo, queuer); + trackIndex = i; + + tracks.AddAfter(currentNode, added); + + return added; + } + } + + public void EnqueueMany(IEnumerable toEnqueue, string queuer) + { + lock (_locker) + { + foreach (var track in toEnqueue) + { + var added = new QueuedTrackInfo(track, queuer); + tracks.AddLast(added); + } + } + } + + public IReadOnlyCollection List() + { + lock (_locker) + { + return tracks.ToList(); + } + } + + public IQueuedTrackInfo? GetCurrent(out int currentIndex) + { + lock (_locker) + { + currentIndex = index; + return tracks.ElementAtOrDefault(index); + } + } + + public void Advance() + { + lock (_locker) + { + if (++index >= tracks.Count) + index = 0; + } + } + + public void Clear() + { + lock (_locker) + { + tracks.Clear(); + } + } + + public bool SetIndex(int newIndex) + { + lock (_locker) + { + if (newIndex < 0 || newIndex >= tracks.Count) + return false; + + index = newIndex; + return true; + } + } + + private void RemoveAtInternal(int remoteAtIndex, out IQueuedTrackInfo trackInfo) + { + var removedNode = tracks.First!; + int i; + for (i = 0; i < remoteAtIndex; i++) + removedNode = removedNode.Next!; + + trackInfo = removedNode.Value; + tracks.Remove(removedNode); + + if (i <= index) + --index; + + if (index < 0) + index = Count; + + // if it was the last song in the queue + // // wrap back to start + // if (_index == Count) + // _index = 0; + // else if (i <= _index) + // if (_index == 0) + // _index = Count; + // else --_index; + } + + public void RemoveCurrent() + { + lock (_locker) + { + if (index < tracks.Count) + RemoveAtInternal(index, out _); + } + } + + public IQueuedTrackInfo? MoveTrack(int from, int to) + { + ArgumentOutOfRangeException.ThrowIfNegative(from); + ArgumentOutOfRangeException.ThrowIfNegative(to); + ArgumentOutOfRangeException.ThrowIfEqual(to, from); + + lock (_locker) + { + if (from >= Count || to >= Count) + return null; + + // update current track index + if (from == index) + { + // if the song being moved is the current track + // it means that it will for sure end up on the destination + index = to; + } + else + { + // moving a track from below the current track means + // means it will drop down + if (from < index) + index--; + + // moving a track to below the current track + // means it will rise up + if (to <= index) + index++; + + + // if both from and to are below _index - net change is + 1 - 1 = 0 + // if from is below and to is above - net change is -1 (as the track is taken and put above) + // if from is above and to is below - net change is 1 (as the track is inserted under) + // if from is above and to is above - net change is 0 + } + + // get the node which needs to be moved + var fromNode = tracks.First!; + for (var i = 0; i < from; i++) + fromNode = fromNode.Next!; + + // remove it from the queue + tracks.Remove(fromNode); + + // if it needs to be added as a first node, + // add it directly and return + if (to == 0) + { + tracks.AddFirst(fromNode); + return fromNode.Value; + } + + // else find the node at the index before the specified target + var addAfterNode = tracks.First!; + for (var i = 1; i < to; i++) + addAfterNode = addAfterNode.Next!; + + // and add after it + tracks.AddAfter(addAfterNode, fromNode); + return fromNode.Value; + } + } + + public void Shuffle(Random rng) + { + lock (_locker) + { + var list = tracks.ToArray(); + rng.Shuffle(list); + tracks = new(list); + } + } + + public bool IsLast() + { + lock (_locker) + { + return index == tracks.Count // if there are no tracks + || index == tracks.Count - 1; + } + } + + public void ReorderFairly() + { + lock (_locker) + { + var groups = new Dictionary(); + var queuers = new List>(); + + foreach (var track in tracks.Skip(index).Concat(tracks.Take(index))) + { + if (!groups.TryGetValue(track.Queuer, out var qIndex)) + { + queuers.Add(new Queue()); + qIndex = queuers.Count - 1; + groups.Add(track.Queuer, qIndex); + } + + queuers[qIndex].Enqueue(track); + } + + tracks = new LinkedList(); + index = 0; + + while (true) + { + for (var i = 0; i < queuers.Count; i++) + { + var queue = queuers[i]; + tracks.AddLast(queue.Dequeue()); + + if (queue.Count == 0) + { + queuers.RemoveAt(i); + i--; + } + } + + if (queuers.Count == 0) + break; + } + } + } + + public bool TryRemoveAt(int remoteAt, out IQueuedTrackInfo? trackInfo, out bool isCurrent) + { + lock (_locker) + { + isCurrent = false; + trackInfo = null; + + if (remoteAt < 0 || remoteAt >= tracks.Count) + return false; + + if (remoteAt == index) + isCurrent = true; + + RemoveAtInternal(remoteAt, out trackInfo); + + return true; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/RemoteTrackInfo.cs b/src/EllieBot/Modules/Music/_common/Impl/RemoteTrackInfo.cs new file mode 100644 index 0000000..b002779 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/RemoteTrackInfo.cs @@ -0,0 +1,16 @@ +namespace EllieBot.Modules.Music; + +public sealed record RemoteTrackInfo( + string Id, + string Title, + string Url, + string Thumbnail, + TimeSpan Duration, + MusicPlatform Platform, + Func> _streamFactory) : ITrackInfo +{ + private readonly Func> _streamFactory = _streamFactory; + + public async ValueTask GetStreamUrl() + => await _streamFactory(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/SimpleTrackInfo.cs b/src/EllieBot/Modules/Music/_common/Impl/SimpleTrackInfo.cs new file mode 100644 index 0000000..9ae1c30 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/SimpleTrackInfo.cs @@ -0,0 +1,30 @@ +namespace EllieBot.Modules.Music; + +public sealed class SimpleTrackInfo : ITrackInfo +{ + public string Title { get; } + public string Url { get; } + public string Thumbnail { get; } + public TimeSpan Duration { get; } + public MusicPlatform Platform { get; } + public string? StreamUrl { get; } + + public SimpleTrackInfo( + string title, + string url, + string thumbnail, + TimeSpan duration, + MusicPlatform platform, + string streamUrl) + { + Title = title; + Url = url; + Thumbnail = thumbnail; + Duration = duration; + Platform = platform; + StreamUrl = streamUrl; + } + + public ValueTask GetStreamUrl() + => new(StreamUrl); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/TrackCacher.cs b/src/EllieBot/Modules/Music/_common/Impl/TrackCacher.cs new file mode 100644 index 0000000..2dcffcc --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/TrackCacher.cs @@ -0,0 +1,105 @@ +namespace EllieBot.Modules.Music; + +public sealed class TrackCacher : ITrackCacher +{ + private readonly IBotCache _cache; + + public TrackCacher(IBotCache cache) + => _cache = cache; + + + private TypedKey GetStreamLinkKey(MusicPlatform platform, string id) + => new($"music:stream:{platform}:{id}"); + + public async Task GetOrCreateStreamLink( + string id, + MusicPlatform platform, + Func> streamUrlFactory) + { + var key = GetStreamLinkKey(platform, id); + + var streamUrl = await _cache.GetOrDefaultAsync(key); + await _cache.RemoveAsync(key); + + if (streamUrl == default) + { + (streamUrl, _) = await streamUrlFactory(); + } + + // make a new one for later use + _ = Task.Run(async () => + { + (streamUrl, var expiry) = await streamUrlFactory(); + await CacheStreamUrlAsync(id, platform, streamUrl, expiry); + }); + + return streamUrl; + } + + public async Task CacheStreamUrlAsync( + string id, + MusicPlatform platform, + string url, + TimeSpan expiry) + => await _cache.AddAsync(GetStreamLinkKey(platform, id), url, expiry); + + // track data by id + private TypedKey GetTrackDataKey(MusicPlatform platform, string id) + => new($"music:track:{platform}:{id}"); + public async Task CacheTrackDataAsync(ICachableTrackData data) + => await _cache.AddAsync(GetTrackDataKey(data.Platform, data.Id), ToCachableTrackData(data)); + + private CachableTrackData ToCachableTrackData(ICachableTrackData data) + => new CachableTrackData() + { + Id = data.Id, + Platform = data.Platform, + Thumbnail = data.Thumbnail, + Title = data.Title, + Url = data.Url, + }; + + public async Task GetCachedDataByIdAsync(string id, MusicPlatform platform) + => await _cache.GetOrDefaultAsync(GetTrackDataKey(platform, id)); + + + // track data by query + private TypedKey GetTrackDataQueryKey(MusicPlatform platform, string query) + => new($"music:track:{platform}:q:{query}"); + + public async Task CacheTrackDataByQueryAsync(string query, ICachableTrackData data) + => await Task.WhenAll( + _cache.AddAsync(GetTrackDataQueryKey(data.Platform, query), ToCachableTrackData(data)).AsTask(), + _cache.AddAsync(GetTrackDataKey(data.Platform, data.Id), ToCachableTrackData(data)).AsTask()); + + public async Task GetCachedDataByQueryAsync(string query, MusicPlatform platform) + => await _cache.GetOrDefaultAsync(GetTrackDataQueryKey(platform, query)); + + + // playlist track ids by playlist id + private TypedKey> GetPlaylistTracksCacheKey(string playlist, MusicPlatform platform) + => new($"music:playlist_tracks:{platform}:{playlist}"); + + public async Task CachePlaylistTrackIdsAsync(string playlistId, MusicPlatform platform, IEnumerable ids) + => await _cache.AddAsync(GetPlaylistTracksCacheKey(playlistId, platform), ids.ToList()); + + public async Task> GetPlaylistTrackIdsAsync(string playlistId, MusicPlatform platform) + { + var result = await _cache.GetAsync(GetPlaylistTracksCacheKey(playlistId, platform)); + if (result.TryGetValue(out var val)) + return val; + + return Array.Empty(); + } + + + // playlist id by query + private TypedKey GetPlaylistCacheKey(string query, MusicPlatform platform) + => new($"music:playlist_id:{platform}:{query}"); + + public async Task CachePlaylistIdByQueryAsync(string query, MusicPlatform platform, string playlistId) + => await _cache.AddAsync(GetPlaylistCacheKey(query, platform), playlistId); + + public async Task GetPlaylistIdByQueryAsync(string query, MusicPlatform platform) + => await _cache.GetOrDefaultAsync(GetPlaylistCacheKey(query, platform)); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Impl/VoiceProxy.cs b/src/EllieBot/Modules/Music/_common/Impl/VoiceProxy.cs new file mode 100644 index 0000000..08bb8b8 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Impl/VoiceProxy.cs @@ -0,0 +1,102 @@ +#nullable disable +using EllieBot.Voice; +using EllieBot.Voice.Models; + +namespace EllieBot.Modules.Music; + +public sealed class VoiceProxy : IVoiceProxy +{ + public enum VoiceProxyState + { + Created, + Started, + Stopped + } + + private const int MAX_ERROR_COUNT = 20; + private const int DELAY_ON_ERROR_MILISECONDS = 200; + + public VoiceProxyState State + => gateway switch + { + { Started: true, Stopped: false } => VoiceProxyState.Started, + { Stopped: false } => VoiceProxyState.Created, + _ => VoiceProxyState.Stopped + }; + + + private VoiceGateway gateway; + + public VoiceProxy(VoiceGateway initial) + => gateway = initial; + + public bool SendPcmFrame(VoiceClient vc, Span data, int length) + { + try + { + var gw = gateway; + if (gw is null || gw.Stopped || !gw.Started) + return false; + + vc.SendPcmFrame(gw, data, 0, length); + return true; + } + catch (Exception) + { + return false; + } + } + + public async Task RunGatewayAction(Func action) + { + var errorCount = 0; + do + { + if (State == VoiceProxyState.Stopped) + break; + + try + { + var gw = gateway; + if (gw is null || !gw.ConnectingFinished.Task.IsCompleted) + { + ++errorCount; + await Task.Delay(DELAY_ON_ERROR_MILISECONDS); + Log.Debug("Gateway is not ready"); + continue; + } + + await action(gw); + errorCount = 0; + } + catch (Exception ex) + { + ++errorCount; + await Task.Delay(DELAY_ON_ERROR_MILISECONDS); + Log.Debug(ex, "Error performing proxy gateway action"); + } + } while (errorCount is > 0 and <= MAX_ERROR_COUNT); + + return State != VoiceProxyState.Stopped && errorCount <= MAX_ERROR_COUNT; + } + + public void SetGateway(VoiceGateway newGateway) + => gateway = newGateway; + + public Task StartSpeakingAsync() + => RunGatewayAction(gw => gw.SendSpeakingAsync(VoiceSpeaking.State.Microphone)); + + public Task StopSpeakingAsync() + => RunGatewayAction(gw => gw.SendSpeakingAsync(VoiceSpeaking.State.None)); + + public async Task StartGateway() + => await gateway.Start(); + + public Task StopGateway() + { + if (gateway is { } gw) + return gw.StopAsync(); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Resolvers/LocalTrackResolver.cs b/src/EllieBot/Modules/Music/_common/Resolvers/LocalTrackResolver.cs new file mode 100644 index 0000000..d728ce7 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Resolvers/LocalTrackResolver.cs @@ -0,0 +1,122 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Text; + +namespace EllieBot.Modules.Music.Resolvers; + +public sealed class LocalTrackResolver : ILocalTrackResolver +{ + private static readonly HashSet _musicExtensions = new[] + { + ".MP4", ".MP3", ".FLAC", ".OGG", ".WAV", ".WMA", ".WMV", ".AAC", ".MKV", ".WEBM", ".M4A", ".AA", ".AAX", + ".ALAC", ".AIFF", ".MOV", ".FLV", ".OGG", ".M4V" + }.ToHashSet(); + + public async Task ResolveByQueryAsync(string query) + { + if (!File.Exists(query)) + return null; + + var trackDuration = await Ffprobe.GetTrackDurationAsync(query); + return new SimpleTrackInfo(Path.GetFileNameWithoutExtension(query), + $"https://google.com?q={Uri.EscapeDataString(Path.GetFileNameWithoutExtension(query))}", + "https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png", + trackDuration, + MusicPlatform.Local, + $"\"{Path.GetFullPath(query)}\""); + } + + public async IAsyncEnumerable ResolveDirectoryAsync(string dirPath) + { + DirectoryInfo dir; + try + { + dir = new(dirPath); + } + catch (Exception ex) + { + Log.Error(ex, "Specified directory {DirectoryPath} could not be opened", dirPath); + yield break; + } + + var files = dir.EnumerateFiles() + .Where(x => + { + if (!x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System) + && _musicExtensions.Contains(x.Extension.ToUpperInvariant())) + return true; + return false; + }) + .ToList(); + + var firstFile = files.FirstOrDefault()?.FullName; + if (firstFile is null) + yield break; + + var firstData = await ResolveByQueryAsync(firstFile); + if (firstData is not null) + yield return firstData; + + var fileChunks = files.Skip(1).Chunk(10); + foreach (var chunk in fileChunks) + { + var part = await chunk.Select(x => ResolveByQueryAsync(x.FullName)).WhenAll(); + + // nullable reference types being annoying + foreach (var p in part) + { + if (p is null) + continue; + + yield return p; + } + } + } +} + +public static class Ffprobe +{ + public static async Task GetTrackDurationAsync(string query) + { + query = query.Replace("\"", ""); + + try + { + using var p = Process.Start(new ProcessStartInfo + { + FileName = "ffprobe", + Arguments = + $"-v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -- \"{query}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + CreateNoWindow = true + }); + + if (p is null) + return TimeSpan.Zero; + + var data = await p.StandardOutput.ReadToEndAsync(); + if (double.TryParse(data, out var seconds)) + return TimeSpan.FromSeconds(seconds); + + var errorData = await p.StandardError.ReadToEndAsync(); + if (!string.IsNullOrWhiteSpace(errorData)) + Log.Warning("Ffprobe warning for file {FileName}: {ErrorMessage}", query, errorData); + + return TimeSpan.Zero; + } + catch (Win32Exception) + { + Log.Warning("Ffprobe was likely not installed. Local song durations will show as (?)"); + } + catch (Exception ex) + { + Log.Error(ex, "Unknown exception running ffprobe; {ErrorMessage}", ex.Message); + } + + return TimeSpan.Zero; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Resolvers/RadioResolveStrategy.cs b/src/EllieBot/Modules/Music/_common/Resolvers/RadioResolveStrategy.cs new file mode 100644 index 0000000..c3733a4 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Resolvers/RadioResolveStrategy.cs @@ -0,0 +1,106 @@ +#nullable disable +using System.Text.RegularExpressions; + +namespace EllieBot.Modules.Music.Resolvers; + +public class RadioResolver : IRadioResolver +{ + private readonly Regex _plsRegex = new(@"File1=(?.*?)\n", RegexOptions.Compiled); + private readonly Regex _m3URegex = new(@"(?^[^#].*)", RegexOptions.Compiled | RegexOptions.Multiline); + private readonly Regex _asxRegex = new(@".*?)""", RegexOptions.Compiled); + private readonly Regex _xspfRegex = new(@"(?.*?)", RegexOptions.Compiled); + + public async Task ResolveByQueryAsync(string query) + { + if (IsRadioLink(query)) + query = await HandleStreamContainers(query); + + return new SimpleTrackInfo(query.TrimTo(50), + query, + "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png", + TimeSpan.MaxValue, + MusicPlatform.Radio, + query); + } + + public static bool IsRadioLink(string query) + => (query.StartsWith("http", StringComparison.InvariantCulture) + || query.StartsWith("ww", StringComparison.InvariantCulture)) + && (query.Contains(".pls") || query.Contains(".m3u") || query.Contains(".asx") || query.Contains(".xspf")); + + private async Task HandleStreamContainers(string query) + { + string file = null; + try + { + using var http = new HttpClient(); + file = await http.GetStringAsync(query); + } + catch + { + return query; + } + + if (query.Contains(".pls")) + { + try + { + var m = _plsRegex.Match(file); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Log.Warning("Failed reading .pls:\n{PlsFile}", file); + return null; + } + } + + if (query.Contains(".m3u")) + { + try + { + var m = _m3URegex.Match(file); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Log.Warning("Failed reading .m3u:\n{M3uFile}", file); + return null; + } + } + + if (query.Contains(".asx")) + { + try + { + var m = _asxRegex.Match(file); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Log.Warning("Failed reading .asx:\n{AsxFile}", file); + return null; + } + } + + if (query.Contains(".xspf")) + { + try + { + var m = _xspfRegex.Match(file); + var res = m.Groups["url"]?.ToString(); + return res?.Trim(); + } + catch + { + Log.Warning("Failed reading .xspf:\n{XspfFile}", file); + return null; + } + } + + return query; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Resolvers/TrackResolveProvider.cs b/src/EllieBot/Modules/Music/_common/Resolvers/TrackResolveProvider.cs new file mode 100644 index 0000000..642edf1 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Resolvers/TrackResolveProvider.cs @@ -0,0 +1,49 @@ +namespace EllieBot.Modules.Music; + +public sealed class TrackResolveProvider : ITrackResolveProvider +{ + private readonly IYoutubeResolver _ytResolver; + private readonly ILocalTrackResolver _localResolver; + private readonly IRadioResolver _radioResolver; + + public TrackResolveProvider( + IYoutubeResolver ytResolver, + ILocalTrackResolver localResolver, + IRadioResolver radioResolver) + { + _ytResolver = ytResolver; + _localResolver = localResolver; + _radioResolver = radioResolver; + } + + public Task QuerySongAsync(string query, MusicPlatform? forcePlatform) + { + switch (forcePlatform) + { + case MusicPlatform.Radio: + return _radioResolver.ResolveByQueryAsync(query); + case MusicPlatform.Youtube: + return _ytResolver.ResolveByQueryAsync(query); + case MusicPlatform.Local: + return _localResolver.ResolveByQueryAsync(query); + case null: + var match = _ytResolver.YtVideoIdRegex.Match(query); + if (match.Success) + return _ytResolver.ResolveByIdAsync(match.Groups["id"].Value); + else if (Uri.TryCreate(query, UriKind.Absolute, out var uri) && uri.IsFile) + return _localResolver.ResolveByQueryAsync(uri.AbsolutePath); + else if (IsRadioLink(query)) + return _radioResolver.ResolveByQueryAsync(query); + else + return _ytResolver.ResolveByQueryAsync(query, false); + default: + Log.Error("Unsupported platform: {MusicPlatform}", forcePlatform); + return Task.FromResult(null); + } + } + + public static bool IsRadioLink(string query) + => (query.StartsWith("http", StringComparison.InvariantCulture) + || query.StartsWith("ww", StringComparison.InvariantCulture)) + && (query.Contains(".pls") || query.Contains(".m3u") || query.Contains(".asx") || query.Contains(".xspf")); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/Resolvers/YtdlYoutubeResolver.cs b/src/EllieBot/Modules/Music/_common/Resolvers/YtdlYoutubeResolver.cs new file mode 100644 index 0000000..70479d0 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/Resolvers/YtdlYoutubeResolver.cs @@ -0,0 +1,315 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using EllieBot.Modules.Searches; + +namespace EllieBot.Modules.Music; + +public sealed class YtdlYoutubeResolver : IYoutubeResolver +{ + private static readonly string[] _durationFormats = + [ + "ss", "m\\:ss", "mm\\:ss", "h\\:mm\\:ss", "hh\\:mm\\:ss", "hhh\\:mm\\:ss" + ]; + + private static readonly Regex _expiryRegex = new(@"(?:[\?\&]expire\=(?\d+))"); + + + private static readonly Regex _simplePlaylistRegex = new(@"&list=(?[\w\-]{12,})", RegexOptions.Compiled); + + public Regex YtVideoIdRegex { get; } = + new(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?[a-zA-Z0-9_-]{6,11})", + RegexOptions.Compiled); + + private readonly ITrackCacher _trackCacher; + + private readonly YtdlOperation _ytdlPlaylistOperation; + private readonly YtdlOperation _ytdlIdOperation; + private readonly YtdlOperation _ytdlSearchOperation; + + private readonly IGoogleApiService _google; + + public YtdlYoutubeResolver(ITrackCacher trackCacher, IGoogleApiService google, SearchesConfigService scs) + { + _trackCacher = trackCacher; + _google = google; + + + _ytdlPlaylistOperation = new("-4 " + + "--geo-bypass " + + "--encoding UTF8 " + + "-f bestaudio " + + "-e " + + "--get-url " + + "--get-id " + + "--get-thumbnail " + + "--get-duration " + + "--no-check-certificate " + + "-i " + + "--yes-playlist " + + "-- \"{0}\"", scs.Data.YtProvider != YoutubeSearcher.Ytdl); + + _ytdlIdOperation = new("-4 " + + "--geo-bypass " + + "--encoding UTF8 " + + "-f bestaudio " + + "-e " + + "--get-url " + + "--get-id " + + "--get-thumbnail " + + "--get-duration " + + "--no-check-certificate " + + "-- \"{0}\"", scs.Data.YtProvider != YoutubeSearcher.Ytdl); + + _ytdlSearchOperation = new("-4 " + + "--geo-bypass " + + "--encoding UTF8 " + + "-f bestaudio " + + "-e " + + "--get-url " + + "--get-id " + + "--get-thumbnail " + + "--get-duration " + + "--no-check-certificate " + + "--default-search " + + "\"ytsearch:\" -- \"{0}\"", scs.Data.YtProvider != YoutubeSearcher.Ytdl); + } + + private YtTrackData ResolveYtdlData(string ytdlOutputString) + { + if (string.IsNullOrWhiteSpace(ytdlOutputString)) + return default; + + var dataArray = ytdlOutputString.Trim().Split('\n'); + + if (dataArray.Length < 5) + { + Log.Information("Not enough data received: {YtdlData}", ytdlOutputString); + return default; + } + + if (!TimeSpan.TryParseExact(dataArray[4], _durationFormats, CultureInfo.InvariantCulture, out var time)) + time = TimeSpan.Zero; + + var thumbnail = Uri.IsWellFormedUriString(dataArray[3], UriKind.Absolute) ? dataArray[3].Trim() : string.Empty; + + return new(dataArray[0], dataArray[1], thumbnail, dataArray[2], time); + } + + private ITrackInfo DataToInfo(in YtTrackData trackData) + => new RemoteTrackInfo( + trackData.Id, + trackData.Title, + $"https://youtube.com/watch?v={trackData.Id}", + trackData.Thumbnail, + trackData.Duration, + MusicPlatform.Youtube, + CreateCacherFactory(trackData.Id)); + + private Func> CreateCacherFactory(string id) + => () => _trackCacher.GetOrCreateStreamLink(id, + MusicPlatform.Youtube, + async () => await ExtractNewStreamUrlAsync(id)); + + private static TimeSpan GetExpiry(string streamUrl) + { + var match = _expiryRegex.Match(streamUrl); + if (match.Success && double.TryParse(match.Groups["timestamp"].ToString(), out var timestamp)) + { + var realExpiry = timestamp.ToUnixTimestamp() - DateTime.UtcNow; + if (realExpiry > TimeSpan.FromMinutes(60)) + return realExpiry.Subtract(TimeSpan.FromMinutes(30)); + + return realExpiry; + } + + return TimeSpan.FromHours(1); + } + + private async Task<(string StreamUrl, TimeSpan Expiry)> ExtractNewStreamUrlAsync(string id) + { + var data = await _ytdlIdOperation.GetDataAsync(id); + var trackInfo = ResolveYtdlData(data); + if (string.IsNullOrWhiteSpace(trackInfo.StreamUrl)) + return default; + + return (trackInfo.StreamUrl!, GetExpiry(trackInfo.StreamUrl!)); + } + + public async Task ResolveByIdAsync(string id) + { + id = id.Trim(); + + var cachedData = await _trackCacher.GetCachedDataByIdAsync(id, MusicPlatform.Youtube); + if (cachedData is null) + { + Log.Information("Resolving youtube track by Id: {YoutubeId}", id); + + var data = await _ytdlIdOperation.GetDataAsync(id); + + var trackInfo = ResolveYtdlData(data); + if (string.IsNullOrWhiteSpace(trackInfo.Title)) + return default; + + var toReturn = DataToInfo(in trackInfo); + + await Task.WhenAll(_trackCacher.CacheTrackDataAsync(toReturn.ToCachedData(id)), + CacheStreamUrlAsync(trackInfo)); + + return toReturn; + } + + return DataToInfo(new(cachedData.Title, cachedData.Id, cachedData.Thumbnail, null, cachedData.Duration)); + } + + private Task CacheStreamUrlAsync(YtTrackData trackInfo) + => _trackCacher.CacheStreamUrlAsync(trackInfo.Id, + MusicPlatform.Youtube, + trackInfo.StreamUrl!, + GetExpiry(trackInfo.StreamUrl!)); + + public async IAsyncEnumerable ResolveTracksByPlaylistIdAsync(string playlistId) + { + Log.Information("Resolving youtube tracks from playlist: {PlaylistId}", playlistId); + var count = 0; + + var ids = await _trackCacher.GetPlaylistTrackIdsAsync(playlistId, MusicPlatform.Youtube); + if (ids.Count > 0) + { + foreach (var id in ids) + { + var trackInfo = await ResolveByIdAsync(id); + if (trackInfo is null) + continue; + + yield return trackInfo; + } + + yield break; + } + + var data = string.Empty; + var trackIds = new List(); + await foreach (var line in _ytdlPlaylistOperation.EnumerateDataAsync(playlistId)) + { + data += line; + + if (++count == 5) + { + var trackData = ResolveYtdlData(data); + data = string.Empty; + count = 0; + if (string.IsNullOrWhiteSpace(trackData.Id)) + continue; + + var info = DataToInfo(in trackData); + await Task.WhenAll(_trackCacher.CacheTrackDataAsync(info.ToCachedData(trackData.Id)), + CacheStreamUrlAsync(trackData)); + + trackIds.Add(trackData.Id); + yield return info; + } + else + data += Environment.NewLine; + } + + await _trackCacher.CachePlaylistTrackIdsAsync(playlistId, MusicPlatform.Youtube, trackIds); + } + + public async IAsyncEnumerable ResolveTracksFromPlaylistAsync(string query) + { + string? playlistId; + // try to match playlist id inside the query, if a playlist url has been queried + var match = _simplePlaylistRegex.Match(query); + if (match.Success) + { + // if it's a success, just return from that playlist using the id + playlistId = match.Groups["id"].ToString(); + await foreach (var track in ResolveTracksByPlaylistIdAsync(playlistId)) + yield return track; + + yield break; + } + + // if a query is a search term, try the cache + playlistId = await _trackCacher.GetPlaylistIdByQueryAsync(query, MusicPlatform.Youtube); + if (playlistId is null) + { + // if it's not in the cache + // find playlist id by keyword using google api + try + { + var playlistIds = await _google.GetPlaylistIdsByKeywordsAsync(query); + playlistId = playlistIds.FirstOrDefault(); + } + catch (Exception ex) + { + Log.Warning(ex, "Error Getting playlist id via GoogleApi"); + } + + // if query is not a playlist url + // and query result is not in the cache + // and api returns no values + // it means invalid input has been used, + // or google api key is not provided + if (playlistId is null) + yield break; + } + + // cache the query -> playlist id for fast future lookup + await _trackCacher.CachePlaylistIdByQueryAsync(query, MusicPlatform.Youtube, playlistId); + await foreach (var track in ResolveTracksByPlaylistIdAsync(playlistId)) + yield return track; + } + + public Task ResolveByQueryAsync(string query) + => ResolveByQueryAsync(query, true); + + public async Task ResolveByQueryAsync(string query, bool tryResolving) + { + if (tryResolving) + { + var match = YtVideoIdRegex.Match(query); + if (match.Success) + return await ResolveByIdAsync(match.Groups["id"].Value); + } + + Log.Information("Resolving youtube song by search term: {YoutubeQuery}", query); + + var cachedData = await _trackCacher.GetCachedDataByQueryAsync(query, MusicPlatform.Youtube); + if (cachedData is null || string.IsNullOrWhiteSpace(cachedData.Title)) + { + var stringData = await _ytdlSearchOperation.GetDataAsync(query); + var trackData = ResolveYtdlData(stringData); + + var trackInfo = DataToInfo(trackData); + await Task.WhenAll(_trackCacher.CacheTrackDataByQueryAsync(query, trackInfo.ToCachedData(trackData.Id)), + CacheStreamUrlAsync(trackData)); + return trackInfo; + } + + return DataToInfo(new(cachedData.Title, cachedData.Id, cachedData.Thumbnail, null, cachedData.Duration)); + } + + private readonly struct YtTrackData + { + public readonly string Title; + public readonly string Id; + public readonly string Thumbnail; + public readonly string? StreamUrl; + public readonly TimeSpan Duration; + + public YtTrackData( + string title, + string id, + string thumbnail, + string? streamUrl, + TimeSpan duration) + { + Title = title.Trim(); + Id = id.Trim(); + Thumbnail = thumbnail; + StreamUrl = streamUrl; + Duration = duration; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/db/MusicPlayerSettingsExtensions.cs b/src/EllieBot/Modules/Music/_common/db/MusicPlayerSettingsExtensions.cs new file mode 100644 index 0000000..d8f81b5 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/db/MusicPlayerSettingsExtensions.cs @@ -0,0 +1,27 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class MusicPlayerSettingsExtensions +{ + public static async Task ForGuildAsync(this DbSet settings, ulong guildId) + { + var toReturn = await settings.AsQueryable().FirstOrDefaultAsync(x => x.GuildId == guildId); + + if (toReturn is null) + { + var newSettings = new MusicPlayerSettings + { + GuildId = guildId, + PlayerRepeat = PlayerRepeatType.Queue + }; + + await settings.AddAsync(newSettings); + return newSettings; + } + + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs b/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs new file mode 100644 index 0000000..16a755b --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class MusicPlaylist : DbEntity +{ + public string Name { get; set; } + public string Author { get; set; } + public ulong AuthorId { get; set; } + public List Songs { get; set; } = new(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/db/MusicPlaylistExtensions.cs b/src/EllieBot/Modules/Music/_common/db/MusicPlaylistExtensions.cs new file mode 100644 index 0000000..0e3e603 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/db/MusicPlaylistExtensions.cs @@ -0,0 +1,18 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Db; + +public static class MusicPlaylistExtensions +{ + public static List GetPlaylistsOnPage(this DbSet playlists, int num) + { + ArgumentOutOfRangeException.ThrowIfLessThan(num, 1); + + return playlists.AsQueryable().Skip((num - 1) * 20).Take(20).Include(pl => pl.Songs).ToList(); + } + + public static MusicPlaylist GetWithSongs(this DbSet playlists, int id) + => playlists.Include(mpl => mpl.Songs).FirstOrDefault(mpl => mpl.Id == id); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Music/_common/db/MusicSettings.cs b/src/EllieBot/Modules/Music/_common/db/MusicSettings.cs new file mode 100644 index 0000000..40f8397 --- /dev/null +++ b/src/EllieBot/Modules/Music/_common/db/MusicSettings.cs @@ -0,0 +1,61 @@ +#nullable disable +namespace EllieBot.Db.Models; + +public class MusicPlayerSettings +{ + /// + /// Auto generated Id + /// + public int Id { get; set; } + + /// + /// Id of the guild + /// + public ulong GuildId { get; set; } + + /// + /// Queue repeat type + /// + public PlayerRepeatType PlayerRepeat { get; set; } = PlayerRepeatType.Queue; + + /// + /// Channel id the bot will always try to send track related messages to + /// + public ulong? MusicChannelId { get; set; } + + /// + /// Default volume player will be created with + /// + public int Volume { get; set; } = 100; + + /// + /// Whether the bot should auto disconnect from the voice channel once the queue is done + /// This only has effect if + /// + public bool AutoDisconnect { get; set; } + + /// + /// Selected quality preset for the music player + /// + public QualityPreset QualityPreset { get; set; } + + /// + /// Whether the bot will automatically queue related songs + /// + public bool AutoPlay { get; set; } +} + +public enum QualityPreset +{ + Highest, + High, + Medium, + Low +} + +public enum PlayerRepeatType +{ + None, + Track, + Queue +} \ No newline at end of file From 7c965e5d10b224d884a30b82f9718f0d67fc86bd Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:54:32 +1200 Subject: [PATCH 53/62] Added Patronage module --- .../Patronage/Config/PatronageConfig.cs | 35 + .../Patronage/CurrencyRewardService.cs | 195 ++++ .../Modules/Patronage/InsufficientTier.cs | 11 + .../Patronage/Patreon/PatreonClient.cs | 150 ++++ .../Patronage/Patreon/PatreonCredentials.cs | 10 + .../Modules/Patronage/Patreon/PatreonData.cs | 134 +++ .../Patronage/Patreon/PatreonMemberData.cs | 33 + .../Patronage/Patreon/PatreonRefreshData.cs | 22 + .../Patreon/PatreonSubscriptionHandler.cs | 79 ++ .../Modules/Patronage/PatronageCommands.cs | 156 ++++ .../Modules/Patronage/PatronageService.cs | 843 ++++++++++++++++++ 11 files changed, 1668 insertions(+) create mode 100644 src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs create mode 100644 src/EllieBot/Modules/Patronage/CurrencyRewardService.cs create mode 100644 src/EllieBot/Modules/Patronage/InsufficientTier.cs create mode 100644 src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs create mode 100644 src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs create mode 100644 src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs create mode 100644 src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs create mode 100644 src/EllieBot/Modules/Patronage/Patreon/PatreonRefreshData.cs create mode 100644 src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs create mode 100644 src/EllieBot/Modules/Patronage/PatronageCommands.cs create mode 100644 src/EllieBot/Modules/Patronage/PatronageService.cs diff --git a/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs b/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs new file mode 100644 index 0000000..56f166f --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs @@ -0,0 +1,35 @@ +using EllieBot.Common.Configs; + +namespace EllieBot.Modules.Patronage; + +public class PatronageConfig : ConfigServiceBase +{ + public override string Name + => "patron"; + + private static readonly TypedKey _changeKey; + + private const string FILE_PATH = "data/patron.yml"; + + public PatronageConfig(IConfigSeria serializer, IPubSub pubSub) : base(FILE_PATH, serializer, pubSub, _changeKey) + { + AddParsedProp("enabled", + x => x.IsEnabled, + bool.TryParse, + ConfigPrinters.ToString); + + Migrate(); + } + + private void Migrate() + { + ModifyConfig(c => + { + if (c.Version == 1) + { + c.Version = 2; + c.IsEnabled = false; + } + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs b/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs new file mode 100644 index 0000000..336fe9c --- /dev/null +++ b/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs @@ -0,0 +1,195 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Modules.Gambling.Services; +using EllieBot.Modules.Patronage; +using EllieBot.Services.Currency; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Utility; + +public sealed class CurrencyRewardService : IEService, IDisposable +{ + private readonly ICurrencyService _cs; + private readonly IPatronageService _ps; + private readonly DbService _db; + private readonly IMessageSenderService _sender; + private readonly GamblingConfigService _config; + private readonly DiscordSocketClient _client; + + public CurrencyRewardService( + ICurrencyService cs, + IPatronageService ps, + DbService db, + IMessageSenderService sender, + GamblingConfigService config, + DiscordSocketClient client) + { + _cs = cs; + _ps = ps; + _db = db; + _sender = sender; + _config = config; + _client = client; + + _ps.OnNewPatronPayment += OnNewPayment; + _ps.OnPatronRefunded += OnPatronRefund; + _ps.OnPatronUpdated += OnPatronUpdate; + } + + public void Dispose() + { + _ps.OnNewPatronPayment -= OnNewPayment; + _ps.OnPatronRefunded -= OnPatronRefund; + _ps.OnPatronUpdated -= OnPatronUpdate; + } + + private async Task OnPatronUpdate(Patron oldPatron, Patron newPatron) + { + // if pledge was increased + if (oldPatron.Amount < newPatron.Amount) + { + var conf = _config.Data; + var newAmount = (long)(newPatron.Amount * conf.PatreonCurrencyPerCent); + + RewardedUser old; + await using (var ctx = _db.GetDbContext()) + { + old = await ctx.GetTable() + .Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId) + .FirstOrDefaultAsync(); + + if (old is null) + { + await OnNewPayment(newPatron); + return; + } + + // no action as the amount is the same or lower + if (old.AmountRewardedThisMonth >= newAmount) + return; + + var count = await ctx.GetTable() + .Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId) + .UpdateAsync(_ => new() + { + PlatformUserId = newPatron.UniquePlatformUserId, + UserId = newPatron.UserId, + // amount before bonuses + AmountRewardedThisMonth = newAmount, + LastReward = newPatron.PaidAt + }); + + // shouldn't ever happen + if (count == 0) + return; + } + + var oldAmount = old.AmountRewardedThisMonth; + + var realNewAmount = GetRealCurrencyReward( + (int)(newAmount / conf.PatreonCurrencyPerCent), + newAmount, + out var percentBonus); + + var realOldAmount = GetRealCurrencyReward( + (int)(oldAmount / conf.PatreonCurrencyPerCent), + oldAmount, + out _); + + var diff = realNewAmount - realOldAmount; + if (diff <= 0) + return; // no action if new is lower + + // if the user pledges 5$ or more, they will get X % more flowers where X is amount in dollars, + // up to 100% + + await _cs.AddAsync(newPatron.UserId, diff, new TxData("patron", "update")); + + _ = SendMessageToUser(newPatron.UserId, + $"You've received an additional **{diff}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!"); + } + } + + private long GetRealCurrencyReward(int pledgeCents, long modifiedAmount, out int percentBonus) + { + // needs at least 5$ to be eligible for a bonus + if (pledgeCents < 500) + { + percentBonus = 0; + return modifiedAmount; + } + + var dollarValue = pledgeCents / 100; + percentBonus = dollarValue switch + { + >= 100 => 100, + >= 50 => 50, + >= 20 => 20, + >= 10 => 10, + >= 5 => 5, + _ => 0 + }; + return (long)(modifiedAmount * (1 + (percentBonus / 100.0f))); + } + + // on a new payment, always give the full amount. + private async Task OnNewPayment(Patron patron) + { + var amount = (long)(patron.Amount * _config.Data.PatreonCurrencyPerCent); + await using var ctx = _db.GetDbContext(); + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + PlatformUserId = patron.UniquePlatformUserId, + UserId = patron.UserId, + AmountRewardedThisMonth = amount, + LastReward = patron.PaidAt, + }, + old => new() + { + AmountRewardedThisMonth = amount, + UserId = patron.UserId, + LastReward = patron.PaidAt + }, + () => new() + { + PlatformUserId = patron.UniquePlatformUserId + }); + + var realAmount = GetRealCurrencyReward(patron.Amount, amount, out var percentBonus); + await _cs.AddAsync(patron.UserId, realAmount, new("patron", "new")); + _ = SendMessageToUser(patron.UserId, + $"You've received **{realAmount}**{_config.Data.Currency.Sign} as a currency reward (**+{percentBonus}%**)!"); + } + + private async Task SendMessageToUser(ulong userId, string message) + { + try + { + var user = (IUser)_client.GetUser(userId) ?? await _client.Rest.GetUserAsync(userId); + if (user is null) + return; + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithDescription(message); + + await _sender.Response(user).Embed(eb).SendAsync(); + } + catch + { + Log.Warning("Unable to send a \"Currency Reward\" message to the patron {UserId}", userId); + } + } + + private async Task OnPatronRefund(Patron patron) + { + await using var ctx = _db.GetDbContext(); + _ = await ctx.GetTable() + .UpdateAsync(old => new() + { + AmountRewardedThisMonth = old.AmountRewardedThisMonth * 2 + }); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/InsufficientTier.cs b/src/EllieBot/Modules/Patronage/InsufficientTier.cs new file mode 100644 index 0000000..26a0675 --- /dev/null +++ b/src/EllieBot/Modules/Patronage/InsufficientTier.cs @@ -0,0 +1,11 @@ +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Patronage; + +public readonly struct InsufficientTier +{ + public FeatureType FeatureType { get; init; } + public string Feature { get; init; } + public PatronTier RequiredTier { get; init; } + public PatronTier UserTier { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs new file mode 100644 index 0000000..ad65448 --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs @@ -0,0 +1,150 @@ +#nullable disable +using OneOf; +using OneOf.Types; +using System.Net.Http.Json; +using System.Text.Json; + +namespace EllieBot.Modules.Patronage; + +public class PatreonClient : IDisposable +{ + private readonly string _clientId; + private readonly string _clientSecret; + private string refreshToken; + + + private string accessToken = string.Empty; + private readonly HttpClient _http; + + private DateTime refreshAt = DateTime.UtcNow; + + public PatreonClient(string clientId, string clientSecret, string refreshToken) + { + _clientId = clientId; + _clientSecret = clientSecret; + this.refreshToken = refreshToken; + + _http = new(); + } + + public void Dispose() + => _http.Dispose(); + + public PatreonCredentials GetCredentials() + => new PatreonCredentials() + { + AccessToken = accessToken, + ClientId = _clientId, + ClientSecret = _clientSecret, + RefreshToken = refreshToken, + }; + + public async Task>> RefreshTokenAsync(bool force) + { + if (!force && IsTokenValid()) + return new Success(); + + var res = await _http.PostAsync("https://www.patreon.com/api/oauth2/token" + + "?grant_type=refresh_token" + + $"&refresh_token={refreshToken}" + + $"&client_id={_clientId}" + + $"&client_secret={_clientSecret}", + null); + + if (!res.IsSuccessStatusCode) + return new Error($"Request did not return a sucess status code. Status code: {res.StatusCode}"); + + try + { + var data = await res.Content.ReadFromJsonAsync(); + + if (data is null) + return new Error($"Invalid data retrieved from Patreon."); + + refreshToken = data.RefreshToken; + accessToken = data.AccessToken; + + refreshAt = DateTime.UtcNow.AddSeconds(data.ExpiresIn - 5.Minutes().TotalSeconds); + return new Success(); + } + catch (Exception ex) + { + return new Error($"Error during deserialization: {ex.Message}"); + } + } + + private async ValueTask EnsureTokenValidAsync() + { + if (!IsTokenValid()) + { + var res = await RefreshTokenAsync(true); + return res.Match( + static _ => true, + static err => + { + Log.Warning("Error getting token: {ErrorMessage}", err.Value); + return false; + }); + } + + return true; + } + + private bool IsTokenValid() + => refreshAt > DateTime.UtcNow && !string.IsNullOrWhiteSpace(accessToken); + + public async Task>, Error>> GetMembersAsync(string campaignId) + { + if (!await EnsureTokenValidAsync()) + return new Error("Unable to get patreon token"); + + return OneOf>, Error>.FromT0( + GetMembersInternalAsync(campaignId)); + } + + private async IAsyncEnumerable> GetMembersInternalAsync(string campaignId) + { + _http.DefaultRequestHeaders.Clear(); + _http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", + $"Bearer {accessToken}"); + + var page = + $"https://www.patreon.com/api/oauth2/v2/campaigns/{campaignId}/members" + + $"?fields%5Bmember%5D=full_name,currently_entitled_amount_cents,last_charge_date,last_charge_status" + + $"&fields%5Buser%5D=social_connections" + + $"&include=user" + + $"&sort=-last_charge_date"; + PatreonMembersResponse data; + + do + { + var res = await _http.GetStreamAsync(page); + data = await JsonSerializer.DeserializeAsync(res); + + if (data is null) + break; + + var userData = data.Data + .Join(data.Included, + static m => m.Relationships.User.Data.Id, + static u => u.Id, + static (m, u) => new PatreonMemberData() + { + PatreonUserId = m.Relationships.User.Data.Id, + UserId = ulong.TryParse( + u.Attributes?.SocialConnections?.Discord?.UserId ?? string.Empty, + out var userId) + ? userId + : 0, + EntitledToCents = m.Attributes.CurrentlyEntitledAmountCents, + LastChargeDate = m.Attributes.LastChargeDate, + LastChargeStatus = m.Attributes.LastChargeStatus + }) + .Where(x => x.UserId == 140788173885276160) + .ToArray(); + + yield return userData; + + } while (!string.IsNullOrWhiteSpace(page = data.Links?.Next)); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs new file mode 100644 index 0000000..5eb6f1f --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Modules.Patronage; + +public readonly struct PatreonCredentials +{ + public string ClientId { get; init; } + public string ClientSecret { get; init; } + public string AccessToken { get; init; } + public string RefreshToken { get; init; } +} diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs new file mode 100644 index 0000000..f5d120e --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs @@ -0,0 +1,134 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Patronage; + +public sealed class Attributes +{ + [JsonPropertyName("full_name")] + public string FullName { get; set; } + + [JsonPropertyName("is_follower")] + public bool IsFollower { get; set; } + + [JsonPropertyName("last_charge_date")] + public DateTime? LastChargeDate { get; set; } + + [JsonPropertyName("last_charge_status")] + public string LastChargeStatus { get; set; } + + [JsonPropertyName("lifetime_support_cents")] + public int LifetimeSupportCents { get; set; } + + [JsonPropertyName("currently_entitled_amount_cents")] + public int CurrentlyEntitledAmountCents { get; set; } + + [JsonPropertyName("patron_status")] + public string PatronStatus { get; set; } +} + +public sealed class Data +{ + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("type")] + public string Type { get; set; } +} + +public sealed class Address +{ + [JsonPropertyName("data")] + public Data Data { get; set; } +} + +// public sealed class CurrentlyEntitledTiers +// { +// [JsonPropertyName("data")] +// public List Data { get; set; } +// } + +// public sealed class Relationships +// { +// [JsonPropertyName("address")] +// public Address Address { get; set; } +// +// // [JsonPropertyName("currently_entitled_tiers")] +// // public CurrentlyEntitledTiers CurrentlyEntitledTiers { get; set; } +// } + +public sealed class PatreonMembersResponse +{ + [JsonPropertyName("data")] + public List Data { get; set; } + + [JsonPropertyName("included")] + public List Included { get; set; } + + [JsonPropertyName("links")] + public PatreonLinks Links { get; set; } +} + +public sealed class PatreonLinks +{ + [JsonPropertyName("next")] + public string Next { get; set; } +} + +public sealed class PatreonUser +{ + [JsonPropertyName("attributes")] + public PatreonUserAttributes Attributes { get; set; } + + [JsonPropertyName("id")] + public string Id { get; set; } + // public string Type { get; set; } +} + +public sealed class PatreonUserAttributes +{ + [JsonPropertyName("social_connections")] + public PatreonSocials SocialConnections { get; set; } +} + +public sealed class PatreonSocials +{ + [JsonPropertyName("discord")] + public DiscordSocial Discord { get; set; } +} + +public sealed class DiscordSocial +{ + [JsonPropertyName("user_id")] + public string UserId { get; set; } +} + +public sealed class PatreonMember +{ + [JsonPropertyName("attributes")] + public Attributes Attributes { get; set; } + + [JsonPropertyName("relationships")] + public Relationships Relationships { get; set; } + + [JsonPropertyName("type")] + public string Type { get; set; } +} + +public sealed class Relationships +{ + [JsonPropertyName("user")] + public PatreonRelationshipUser User { get; set; } +} + +public sealed class PatreonRelationshipUser +{ + [JsonPropertyName("data")] + public PatreonUserData Data { get; set; } +} + +public sealed class PatreonUserData +{ + [JsonPropertyName("id")] + public string Id { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs new file mode 100644 index 0000000..58656b9 --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs @@ -0,0 +1,33 @@ +#nullable disable +namespace EllieBot.Modules.Patronage; + +public sealed class PatreonMemberData : ISubscriberData +{ + public string PatreonUserId { get; init; } + public ulong UserId { get; init; } + public DateTime? LastChargeDate { get; init; } + public string LastChargeStatus { get; init; } + public int EntitledToCents { get; init; } + + public string UniquePlatformUserId + => PatreonUserId; + ulong ISubscriberData.UserId + => UserId; + public int Cents + => EntitledToCents; + public DateTime? LastCharge + => LastChargeDate; + public SubscriptionChargeStatus ChargeStatus + => LastChargeStatus switch + { + "Paid" => SubscriptionChargeStatus.Paid, + "Fraud" or "Refunded" => SubscriptionChargeStatus.Refunded, + "Declined" or "Pending" => SubscriptionChargeStatus.Unpaid, + _ => SubscriptionChargeStatus.Other, + }; +} + +public sealed class PatreonPledgeData +{ + +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonRefreshData.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonRefreshData.cs new file mode 100644 index 0000000..2b6d154 --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonRefreshData.cs @@ -0,0 +1,22 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Patronage; + +public sealed class PatreonRefreshData +{ + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } + + [JsonPropertyName("refresh_token")] + public string RefreshToken { get; set; } + + [JsonPropertyName("expires_in")] + public long ExpiresIn { get; set; } + + [JsonPropertyName("scope")] + public string Scope { get; set; } + + [JsonPropertyName("token_type")] + public string TokenType { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs new file mode 100644 index 0000000..1fd170e --- /dev/null +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs @@ -0,0 +1,79 @@ +#nullable disable +namespace EllieBot.Modules.Patronage; + +/// +/// Service tasked with handling pledges on patreon +/// +public sealed class PatreonSubscriptionHandler : ISubscriptionHandler, IEService +{ + private readonly IBotCredsProvider _credsProvider; + private readonly PatreonClient _patreonClient; + + public PatreonSubscriptionHandler(IBotCredsProvider credsProvider) + { + _credsProvider = credsProvider; + var botCreds = credsProvider.GetCreds(); + _patreonClient = new PatreonClient(botCreds.Patreon.ClientId, botCreds.Patreon.ClientSecret, botCreds.Patreon.RefreshToken); + } + + public async IAsyncEnumerable> GetPatronsAsync() + { + var botCreds = _credsProvider.GetCreds(); + + if (string.IsNullOrWhiteSpace(botCreds.Patreon.CampaignId) + || string.IsNullOrWhiteSpace(botCreds.Patreon.ClientId) + || string.IsNullOrWhiteSpace(botCreds.Patreon.ClientSecret) + || string.IsNullOrWhiteSpace(botCreds.Patreon.RefreshToken)) + yield break; + + var result = await _patreonClient.RefreshTokenAsync(false); + if (!result.TryPickT0(out _, out var error)) + { + Log.Warning("Unable to refresh patreon token: {ErrorMessage}", error.Value); + yield break; + } + + var patreonCreds = _patreonClient.GetCredentials(); + + _credsProvider.ModifyCredsFile(c => + { + c.Patreon.AccessToken = patreonCreds.AccessToken; + c.Patreon.RefreshToken = patreonCreds.RefreshToken; + }); + + IAsyncEnumerable> data; + try + { + var maybeUserData = await _patreonClient.GetMembersAsync(botCreds.Patreon.CampaignId); + data = maybeUserData.Match( + static userData => userData, + static err => + { + Log.Warning("Error while getting patreon members: {ErrorMessage}", err.Value); + return AsyncEnumerable.Empty>(); + }); + } + catch (Exception ex) + { + Log.Warning(ex, + "Unexpected error while refreshing patreon members: {ErroMessage}", + ex.Message); + + yield break; + } + + var now = DateTime.UtcNow; + var firstOfThisMonth = new DateOnly(now.Year, now.Month, 1); + await foreach (var batch in data) + { + // send only active patrons + var toReturn = batch.Where(x => x.Cents > 0 + && x.LastCharge is { } lc + && lc.ToUniversalTime().ToDateOnly() >= firstOfThisMonth) + .ToArray(); + + if (toReturn.Length > 0) + yield return toReturn; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/PatronageCommands.cs b/src/EllieBot/Modules/Patronage/PatronageCommands.cs new file mode 100644 index 0000000..8d0a38a --- /dev/null +++ b/src/EllieBot/Modules/Patronage/PatronageCommands.cs @@ -0,0 +1,156 @@ +using EllieBot.Modules.Patronage; + +namespace EllieBot.Modules.Help; + +public partial class Help +{ + [OnlyPublicBot] + public partial class Patronage : EllieModule + { + private readonly PatronageService _service; + private readonly PatronageConfig _pConf; + + public Patronage(PatronageService service, PatronageConfig pConf) + { + _service = service; + _pConf = pConf; + } + + [Cmd] + [Priority(2)] + public Task Patron() + => InternalPatron(ctx.User); + + [Cmd] + [Priority(0)] + [OwnerOnly] + public Task Patron(IUser user) + => InternalPatron(user); + + [Cmd] + [Priority(0)] + [OwnerOnly] + public async Task PatronMessage(PatronTier tierAndHigher, string message) + { + _ = ctx.Channel.TriggerTypingAsync(); + var result = await _service.SendMessageToPatronsAsync(tierAndHigher, message); + + await Response() + .Confirm(strs.patron_msg_sent( + Format.Code(tierAndHigher.ToString()), + Format.Bold(result.Success.ToString()), + Format.Bold(result.Failed.ToString()))) + .SendAsync(); + } + + // [OwnerOnly] + // public async Task PatronGift(IUser user, int amount) + // { + // // i can't figure out a good way to gift more than one month at the moment. + // + // if (amount < 1) + // return; + // + // var patron = _service.GiftPatronAsync(user, amount); + // + // var eb = _sender.CreateEmbed(); + // + // await Response().Embed(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!") + // .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) + // .AddField("Amount", $"**{patron.Amount / 100.0f:N1}$**", true) + // .AddField("Until", TimestampTag.FromDateTime(patron.ValidThru.AddDays(1)))).SendAsync(); + // + // + // } + + private async Task InternalPatron(IUser user) + { + if (!_pConf.Data.IsEnabled) + { + await Response().Error(strs.patron_not_enabled).SendAsync(); + return; + } + + var patron = await _service.GetPatronAsync(user.Id); + var quotaStats = await _service.GetUserQuotaStatistic(user.Id); + + var eb = _sender.CreateEmbed() + .WithAuthor(user) + .WithTitle(GetText(strs.patron_info)) + .WithOkColor(); + + if (quotaStats.Commands.Count == 0 + && quotaStats.Groups.Count == 0 + && quotaStats.Modules.Count == 0) + { + eb.WithDescription(GetText(strs.no_quota_found)); + } + else + { + eb.AddField(GetText(strs.tier), Format.Bold(patron.Tier.ToFullName()), true) + .AddField(GetText(strs.pledge), $"**{patron.Amount / 100.0f:N1}$**", true); + + if (patron.Tier != PatronTier.None) + eb.AddField(GetText(strs.expires), + patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), + true); + + eb.AddField(GetText(strs.quotas), "⁣", false); + + if (quotaStats.Commands.Count > 0) + { + var text = GetQuotaList(quotaStats.Commands); + if (!string.IsNullOrWhiteSpace(text)) + eb.AddField(GetText(strs.commands), text, true); + } + + if (quotaStats.Groups.Count > 0) + { + var text = GetQuotaList(quotaStats.Groups); + if (!string.IsNullOrWhiteSpace(text)) + eb.AddField(GetText(strs.groups), text, true); + } + + if (quotaStats.Modules.Count > 0) + { + var text = GetQuotaList(quotaStats.Modules); + if (!string.IsNullOrWhiteSpace(text)) + eb.AddField(GetText(strs.modules), text, true); + } + } + + + try + { + await Response().User(ctx.User).Embed(eb).SendAsync(); + _ = ctx.OkAsync(); + } + catch + { + await Response().Error(strs.cant_dm).SendAsync(); + } + } + + private string GetQuotaList(IReadOnlyDictionary featureQuotaStats) + { + var text = string.Empty; + foreach (var (key, q) in featureQuotaStats) + { + text += $"\n⁣\t`{key}`\n"; + if (q.Hourly != default) + text += $"⁣ ⁣ {GetEmoji(q.Hourly)} {q.Hourly.Cur}/{q.Hourly.Max} per hour\n"; + if (q.Daily != default) + text += $"⁣ ⁣ {GetEmoji(q.Daily)} {q.Daily.Cur}/{q.Daily.Max} per day\n"; + if (q.Monthly != default) + text += $"⁣ ⁣ {GetEmoji(q.Monthly)} {q.Monthly.Cur}/{q.Monthly.Max} per month\n"; + } + + return text; + } + + private string GetEmoji((uint Cur, uint Max) limit) + => limit.Cur < limit.Max + ? "✅" + : "⚠️"; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/PatronageService.cs b/src/EllieBot/Modules/Patronage/PatronageService.cs new file mode 100644 index 0000000..3d5f62c --- /dev/null +++ b/src/EllieBot/Modules/Patronage/PatronageService.cs @@ -0,0 +1,843 @@ +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; +using OneOf; +using OneOf.Types; +using CommandInfo = Discord.Commands.CommandInfo; + +namespace EllieBot.Modules.Patronage; + +/// +public sealed class PatronageService + : IPatronageService, + IReadyExecutor, + IExecPreCommand, + IEService +{ + public event Func OnNewPatronPayment = static delegate { return Task.CompletedTask; }; + public event Func OnPatronUpdated = static delegate { return Task.CompletedTask; }; + public event Func OnPatronRefunded = static delegate { return Task.CompletedTask; }; + + // this has to run right before the command + public int Priority + => int.MinValue; + + private static readonly PatronTier[] _tiers = Enum.GetValues(); + + private readonly PatronageConfig _pConf; + private readonly DbService _db; + private readonly DiscordSocketClient _client; + private readonly ISubscriptionHandler _subsHandler; + + private static readonly TypedKey _quotaKey + = new($"quota:last_hourly_reset"); + + private readonly IBotCache _cache; + private readonly IBotCredsProvider _creds; + private readonly IMessageSenderService _sender; + + public PatronageService( + PatronageConfig pConf, + DbService db, + DiscordSocketClient client, + ISubscriptionHandler subsHandler, + IBotCache cache, + IBotCredsProvider creds, + IMessageSenderService sender) + { + _pConf = pConf; + _db = db; + _client = client; + _subsHandler = subsHandler; + _sender = sender; + _cache = cache; + _creds = creds; + } + + public Task OnReadyAsync() + { + if (_client.ShardId != 0) + return Task.CompletedTask; + + return Task.WhenAll(ResetLoopAsync(), LoadSubscribersLoopAsync()); + } + + private async Task LoadSubscribersLoopAsync() + { + var timer = new PeriodicTimer(TimeSpan.FromSeconds(60)); + while (await timer.WaitForNextTickAsync()) + { + try + { + if (!_pConf.Data.IsEnabled) + continue; + + await foreach (var batch in _subsHandler.GetPatronsAsync()) + { + await ProcesssPatronsAsync(batch); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error processing patrons"); + } + } + } + + public async Task ResetLoopAsync() + { + await Task.Delay(1.Minutes()); + while (true) + { + try + { + if (!_pConf.Data.IsEnabled) + { + await Task.Delay(1.Minutes()); + continue; + } + + var now = DateTime.UtcNow; + var lastRun = DateTime.MinValue; + + var result = await _cache.GetAsync(_quotaKey); + if (result.TryGetValue(out var lastVal) && lastVal != default) + { + lastRun = DateTime.FromBinary(lastVal); + } + + var nowDate = now.ToDateOnly(); + var lastDate = lastRun.ToDateOnly(); + + await using var ctx = _db.GetDbContext(); + + if ((lastDate.Day == 1 || (lastDate.Month != nowDate.Month)) && nowDate.Day > 1) + { + // assumes bot won't be offline for a year + await ctx.GetTable() + .TruncateAsync(); + } + else if (nowDate.DayNumber != lastDate.DayNumber) + { + // day is different, means hour is different. + // reset both hourly and daily quota counts. + await ctx.GetTable() + .UpdateAsync((old) => new() + { + HourlyCount = 0, + DailyCount = 0, + }); + } + else if (now.Hour != lastRun.Hour) // if it's not, just reset hourly quotas + { + await ctx.GetTable() + .UpdateAsync((old) => new() + { + HourlyCount = 0 + }); + } + + // assumes that the code above runs in less than an hour + await _cache.AddAsync(_quotaKey, now.ToBinary()); + } + catch (Exception ex) + { + Log.Error(ex, "Error in quota reset loop. Message: {ErrorMessage}", ex.Message); + } + + await Task.Delay(TimeSpan.FromHours(1).Add(TimeSpan.FromMinutes(1))); + } + } + + private async Task ProcesssPatronsAsync(IReadOnlyCollection subscribersEnum) + { + // process only users who have discord accounts connected + var subscribers = subscribersEnum.Where(x => x.UserId != 0).ToArray(); + + if (subscribers.Length == 0) + return; + + var todayDate = DateTime.UtcNow.Date; + await using var ctx = _db.GetDbContext(); + + // handle paid users + foreach (var subscriber in subscribers.Where(x => x.ChargeStatus == SubscriptionChargeStatus.Paid)) + { + if (subscriber.LastCharge is null) + continue; + + var lastChargeUtc = subscriber.LastCharge.Value.ToUniversalTime(); + var dateInOneMonth = lastChargeUtc.Date.AddMonths(1); + try + { + var dbPatron = await ctx.GetTable() + .FirstOrDefaultAsync(x + => x.UniquePlatformUserId == subscriber.UniquePlatformUserId); + + if (dbPatron is null) + { + // if the user is not in the database alrady + dbPatron = await ctx.GetTable() + .InsertWithOutputAsync(() => new() + { + UniquePlatformUserId = subscriber.UniquePlatformUserId, + UserId = subscriber.UserId, + AmountCents = subscriber.Cents, + LastCharge = lastChargeUtc, + ValidThru = dateInOneMonth, + }); + + // await tran.CommitAsync(); + + var newPatron = PatronUserToPatron(dbPatron); + _ = SendWelcomeMessage(newPatron); + await OnNewPatronPayment(newPatron); + } + else + { + if (dbPatron.LastCharge.Month < lastChargeUtc.Month + || dbPatron.LastCharge.Year < lastChargeUtc.Year) + { + // user is charged again for this month + // if his sub would end in teh future, extend it by one month. + // if it's not, just add 1 month to the last charge date + var count = await ctx.GetTable() + .Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId) + .UpdateAsync(old => new() + { + UserId = subscriber.UserId, + AmountCents = subscriber.Cents, + LastCharge = lastChargeUtc, + ValidThru = old.ValidThru >= todayDate + // ? Sql.DateAdd(Sql.DateParts.Month, 1, old.ValidThru).Value + ? old.ValidThru.AddMonths(1) + : dateInOneMonth, + }); + + // this should never happen + if (count == 0) + { + // await tran.RollbackAsync(); + continue; + } + + // await tran.CommitAsync(); + + await OnNewPatronPayment(PatronUserToPatron(dbPatron)); + } + else if (dbPatron.AmountCents != subscriber.Cents // if user changed the amount + || dbPatron.UserId != subscriber.UserId) // if user updated user id) + { + var cents = subscriber.Cents; + // the user updated the pledge or changed the connected discord account + await ctx.GetTable() + .Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId) + .UpdateAsync(old => new() + { + UserId = subscriber.UserId, + AmountCents = cents, + LastCharge = lastChargeUtc, + ValidThru = old.ValidThru, + }); + + var newPatron = dbPatron.Clone(); + newPatron.AmountCents = cents; + newPatron.UserId = subscriber.UserId; + + // idk what's going on but UpdateWithOutputAsync doesn't work properly here + // nor does firstordefault after update. I'm not seeing something obvious + await OnPatronUpdated( + PatronUserToPatron(dbPatron), + PatronUserToPatron(newPatron)); + } + } + } + catch (Exception ex) + { + Log.Error(ex, + "Unexpected error occured while processing rewards for patron {UserId}", + subscriber.UserId); + } + } + + var expiredDate = DateTime.MinValue; + foreach (var patron in subscribers.Where(x => x.ChargeStatus == SubscriptionChargeStatus.Refunded)) + { + // if the subscription is refunded, Disable user's valid thru + var changedCount = await ctx.GetTable() + .Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId + && x.ValidThru != expiredDate) + .UpdateAsync(old => new() + { + ValidThru = expiredDate + }); + + if (changedCount == 0) + continue; + + var updated = await ctx.GetTable() + .Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId) + .FirstAsync(); + + await OnPatronRefunded(PatronUserToPatron(updated)); + } + } + + public async Task ExecPreCommandAsync( + ICommandContext ctx, + string moduleName, + CommandInfo command) + { + var ownerId = ctx.Guild?.OwnerId ?? 0; + + var result = await AttemptRunCommand( + ctx.User.Id, + ownerId: ownerId, + command.Aliases.First().ToLowerInvariant(), + command.Module.Parent == null ? string.Empty : command.Module.GetGroupName().ToLowerInvariant(), + moduleName.ToLowerInvariant() + ); + + return result.Match( + _ => false, + ins => + { + var eb = _sender.CreateEmbed() + .WithPendingColor() + .WithTitle("Insufficient Patron Tier") + .AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true) + .AddField("Required Tier", + $"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/elliebot)", + true); + + if (ctx.Guild is null || ctx.Guild?.OwnerId == ctx.User.Id) + eb.WithDescription("You don't have the sufficent Patron Tier to run this command.") + .WithFooter("You can use '.patron' and '.donate' commands for more info"); + else + eb.WithDescription( + "Neither you nor the server owner have the sufficent Patron Tier to run this command.") + .WithFooter("You can use '.patron' and '.donate' commands for more info"); + + _ = ctx.WarningAsync(); + + if (ctx.Guild?.OwnerId == ctx.User.Id) + _ = _sender.Response(ctx) + .Context(ctx) + .Embed(eb) + .SendAsync(); + else + _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync(); + + return true; + }, + quota => + { + var eb = _sender.CreateEmbed() + .WithPendingColor() + .WithTitle("Quota Limit Reached"); + + if (quota.IsOwnQuota || ctx.User.Id == ownerId) + { + eb.WithDescription($"You've reached your quota of `{quota.Quota} {quota.QuotaPeriod.ToFullName()}`") + .WithFooter("You may want to check your quota by using the '.patron' command."); + } + else + { + eb.WithDescription( + $"This server reached the quota of {quota.Quota} `{quota.QuotaPeriod.ToFullName()}`") + .WithFooter("You may contact the server owner about this issue.\n" + + "Alternatively, you can become patron yourself by using the '.donate' command.\n" + + "If you're already a patron, it means you've reached your quota.\n" + + "You can use '.patron' command to check your quota status."); + } + + eb.AddField("For", $"{quota.FeatureType}: `{quota.Feature}`", true) + .AddField("Resets At", quota.ResetsAt.ToShortAndRelativeTimestampTag(), true); + + _ = ctx.WarningAsync(); + + // send the message in the server in case it's the owner + if (ctx.Guild?.OwnerId == ctx.User.Id) + _ = _sender.Response(ctx) + .Embed(eb) + .SendAsync(); + else + _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync(); + + return true; + }); + } + + private async ValueTask> AttemptRunCommand( + ulong userId, + ulong ownerId, + string commandName, + string groupName, + string moduleName) + { + // try to run as a user + var res = await AttemptRunCommand(userId, commandName, groupName, moduleName, true); + + // if it fails, try to run as an owner + // but only if the command is ran in a server + // and if the owner is not the user + if (!res.IsT0 && ownerId != 0 && ownerId != userId) + res = await AttemptRunCommand(ownerId, commandName, groupName, moduleName, false); + + return res; + } + + /// + /// Returns either the current usage counter if limit wasn't reached, or QuotaLimit if it is. + /// + public async ValueTask> TryIncrementQuotaCounterAsync( + ulong userId, + bool isSelf, + FeatureType featureType, + string featureName, + uint? maybeHourly, + uint? maybeDaily, + uint? maybeMonthly) + { + await using var ctx = _db.GetDbContext(); + + var now = DateTime.UtcNow; + await using var tran = await ctx.Database.BeginTransactionAsync(); + + var userQuotaData = await ctx.GetTable() + .FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId + && x.Feature == featureName) + ?? new PatronQuota(); + + // if hourly exists, if daily exists, etc... + if (maybeHourly is uint hourly && userQuotaData.HourlyCount >= hourly) + { + return new QuotaLimit() + { + QuotaPeriod = QuotaPer.PerHour, + Quota = hourly, + // quite a neat trick. https://stackoverflow.com/a/5733560 + ResetsAt = now.Date.AddHours(now.Hour + 1), + Feature = featureName, + FeatureType = featureType, + IsOwnQuota = isSelf + }; + } + + if (maybeDaily is uint daily + && userQuotaData.DailyCount >= daily) + { + return new QuotaLimit() + { + QuotaPeriod = QuotaPer.PerDay, + Quota = daily, + ResetsAt = now.Date.AddDays(1), + Feature = featureName, + FeatureType = featureType, + IsOwnQuota = isSelf + }; + } + + if (maybeMonthly is uint monthly && userQuotaData.MonthlyCount >= monthly) + { + return new QuotaLimit() + { + QuotaPeriod = QuotaPer.PerMonth, + Quota = monthly, + ResetsAt = now.Date.SecondOfNextMonth(), + Feature = featureName, + FeatureType = featureType, + IsOwnQuota = isSelf + }; + } + + await ctx.GetTable() + .InsertOrUpdateAsync(() => new() + { + UserId = userId, + FeatureType = featureType, + Feature = featureName, + DailyCount = 1, + MonthlyCount = 1, + HourlyCount = 1, + }, + (old) => new() + { + HourlyCount = old.HourlyCount + 1, + DailyCount = old.DailyCount + 1, + MonthlyCount = old.MonthlyCount + 1, + }, + () => new() + { + UserId = userId, + FeatureType = featureType, + Feature = featureName, + }); + + await tran.CommitAsync(); + + return (userQuotaData.HourlyCount + 1, userQuotaData.DailyCount + 1, userQuotaData.MonthlyCount + 1); + } + + /// + /// Attempts to add 1 to user's quota for the command, group and module. + /// Input MUST BE lowercase + /// + /// Id of the user who is attempting to run the command + /// Name of the command the user is trying to run + /// Name of the command's group + /// Name of the command's top level module + /// Whether this is check is for the user himself. False if it's someone else's id (owner) + /// Either a succcess (user can run the command) or one of the error values. + private async ValueTask> AttemptRunCommand( + ulong userId, + string commandName, + string groupName, + string moduleName, + bool isSelf) + { + var confData = _pConf.Data; + + if (!confData.IsEnabled) + return default; + + if (_creds.GetCreds().IsOwner(userId)) + return default; + + // get user tier + var patron = await GetPatronAsync(userId); + FeatureType quotaForFeatureType; + + if (confData.Quotas.Commands.TryGetValue(commandName, out var quotaData)) + { + quotaForFeatureType = FeatureType.Command; + } + else if (confData.Quotas.Groups.TryGetValue(groupName, out quotaData)) + { + quotaForFeatureType = FeatureType.Group; + } + else if (confData.Quotas.Modules.TryGetValue(moduleName, out quotaData)) + { + quotaForFeatureType = FeatureType.Module; + } + else + { + return default; + } + + var featureName = quotaForFeatureType switch + { + FeatureType.Command => commandName, + FeatureType.Group => groupName, + FeatureType.Module => moduleName, + _ => throw new ArgumentOutOfRangeException(nameof(quotaForFeatureType)) + }; + + if (!TryGetTierDataOrLower(quotaData, patron.Tier, out var data)) + { + return new InsufficientTier() + { + Feature = featureName, + FeatureType = quotaForFeatureType, + RequiredTier = quotaData.Count == 0 + ? PatronTier.ComingSoon + : quotaData.Keys.First(), + UserTier = patron.Tier, + }; + } + + // no quota limits for this tier + if (data is null) + return default; + + var quotaCheckResult = await TryIncrementQuotaCounterAsync(userId, + isSelf, + quotaForFeatureType, + featureName, + data.TryGetValue(QuotaPer.PerHour, out var hourly) ? hourly : null, + data.TryGetValue(QuotaPer.PerDay, out var daily) ? daily : null, + data.TryGetValue(QuotaPer.PerMonth, out var monthly) ? monthly : null + ); + + return quotaCheckResult.Match>( + _ => new Success(), + x => x); + } + + private bool TryGetTierDataOrLower( + IReadOnlyDictionary data, + PatronTier tier, + out T? o) + { + // check for quotas on this tier + if (data.TryGetValue(tier, out o)) + return true; + + // if there are none, get the quota first tier below this one + // which has quotas specified + for (var i = _tiers.Length - 1; i >= 0; i--) + { + var lowerTier = _tiers[i]; + if (lowerTier < tier && data.TryGetValue(lowerTier, out o)) + return true; + } + + // if there are none, that means the feature is intended + // to be patron-only but the quotas haven't been specified yet + // so it will be marked as "Coming Soon" + o = default; + return false; + } + + public async Task GetPatronAsync(ulong userId) + { + await using var ctx = _db.GetDbContext(); + + // this can potentially return multiple users if the user + // is subscribed on multiple platforms + // or if there are multiple users on the same platform who connected the same discord account?! + var users = await ctx.GetTable() + .Where(x => x.UserId == userId) + .ToListAsync(); + + // first find all active subscriptions + // and return the one with the highest amount + var maxActive = users.Where(x => !x.ValidThru.IsBeforeToday()).MaxBy(x => x.AmountCents); + if (maxActive is not null) + return PatronUserToPatron(maxActive); + + // if there are no active subs, return the one with the highest amount + + var max = users.MaxBy(x => x.AmountCents); + if (max is null) + return default; // no patron with that name + + return PatronUserToPatron(max); + } + + public async Task GetUserQuotaStatistic(ulong userId) + { + var pConfData = _pConf.Data; + + if (!pConfData.IsEnabled) + return new(); + + var patron = await GetPatronAsync(userId); + + await using var ctx = _db.GetDbContext(); + var allPatronQuotas = await ctx.GetTable() + .Where(x => x.UserId == userId) + .ToListAsync(); + + var allQuotasDict = allPatronQuotas + .GroupBy(static x => x.FeatureType) + .ToDictionary(static x => x.Key, static x => x.ToDictionary(static y => y.Feature)); + + allQuotasDict.TryGetValue(FeatureType.Command, out var data); + var userCommandQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Commands); + + allQuotasDict.TryGetValue(FeatureType.Group, out data); + var userGroupQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Groups); + + allQuotasDict.TryGetValue(FeatureType.Module, out data); + var userModuleQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Modules); + + return new UserQuotaStats() + { + Tier = patron.Tier, + Commands = userCommandQuotaStats, + Groups = userGroupQuotaStats, + Modules = userModuleQuotaStats, + }; + } + + private IReadOnlyDictionary GetFeatureQuotaStats( + PatronTier patronTier, + IReadOnlyDictionary? allQuotasDict, + Dictionary?>> commands) + { + var userCommandQuotaStats = new Dictionary(); + foreach (var (key, quotaData) in commands) + { + if (TryGetTierDataOrLower(quotaData, patronTier, out var data)) + { + // if data is null that means the quota for the user's tier is unlimited + // no point in returning it? + + if (data is null) + continue; + + var (daily, hourly, monthly) = default((uint, uint, uint)); + // try to get users stats for this feature + // if it fails just leave them at 0 + if (allQuotasDict?.TryGetValue(key, out var quota) ?? false) + (daily, hourly, monthly) = (quota.DailyCount, quota.HourlyCount, quota.MonthlyCount); + + userCommandQuotaStats[key] = new FeatureQuotaStats() + { + Hourly = data.TryGetValue(QuotaPer.PerHour, out var hourD) + ? (hourly, hourD) + : default, + Daily = data.TryGetValue(QuotaPer.PerDay, out var maxD) + ? (daily, maxD) + : default, + Monthly = data.TryGetValue(QuotaPer.PerMonth, out var maxM) + ? (monthly, maxM) + : default, + }; + } + } + + return userCommandQuotaStats; + } + + public async Task TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue) + { + var conf = _pConf.Data; + + // if patron system is disabled, the quota is just default + if (!conf.IsEnabled) + return new() + { + Name = key.PrettyName, + Quota = defaultValue, + IsPatronLimit = false + }; + + + if (!conf.Quotas.Features.TryGetValue(key.Key, out var data)) + return new() + { + Name = key.PrettyName, + Quota = defaultValue, + IsPatronLimit = false, + }; + + var patron = await GetPatronAsync(userId); + if (!TryGetTierDataOrLower(data, patron.Tier, out var limit)) + return new() + { + Name = key.PrettyName, + Quota = 0, + IsPatronLimit = true, + }; + + return new() + { + Name = key.PrettyName, + Quota = limit, + IsPatronLimit = true + }; + } + + // public async Task GiftPatronAsync(IUser user, int amount) + // { + // if (amount < 1) + // throw new ArgumentOutOfRangeException(nameof(amount)); + // + // + // } + + private Patron PatronUserToPatron(PatronUser user) + => new Patron() + { + UniquePlatformUserId = user.UniquePlatformUserId, + UserId = user.UserId, + Amount = user.AmountCents, + Tier = CalculateTier(user), + PaidAt = user.LastCharge, + ValidThru = user.ValidThru, + }; + + private PatronTier CalculateTier(PatronUser user) + { + if (user.ValidThru.IsBeforeToday()) + return PatronTier.None; + + return user.AmountCents switch + { + >= 10_000 => PatronTier.C, + >= 5000 => PatronTier.L, + >= 2000 => PatronTier.XX, + >= 1000 => PatronTier.X, + >= 500 => PatronTier.V, + >= 100 => PatronTier.I, + _ => PatronTier.None + }; + } + + private async Task SendWelcomeMessage(Patron patron) + { + try + { + var user = (IUser)_client.GetUser(patron.UserId) ?? await _client.Rest.GetUserAsync(patron.UserId); + if (user is null) + return; + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("❤️ Thank you for supporting EllieBot! ❤️") + .WithDescription( + "Your donation has been processed and you will receive the rewards shortly.\n" + + "You can visit to see rewards for your tier. 🎉") + .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) + .AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true) + .AddField("Expires", + patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), + true) + .AddField("Instructions", + """ + *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.* + *- You can check your benefits on * + *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands* + *- **ALL** of the servers that you **own** will enjoy your Patron benefits.* + *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)* + *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Ellie's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* + *- Permission guide can be found here if you're not familiar with it: * + """, + inline: false) + .WithFooter($"platform id: {patron.UniquePlatformUserId}"); + + await _sender.Response(user).Embed(eb).SendAsync(); + } + catch + { + Log.Warning("Unable to send a \"Welcome\" message to the patron {UserId}", patron.UserId); + } + } + + public async Task<(int Success, int Failed)> SendMessageToPatronsAsync(PatronTier tierAndHigher, string message) + { + await using var ctx = _db.GetDbContext(); + + var patrons = await ctx.GetTable() + .Where(x => x.ValidThru > DateTime.UtcNow) + .ToArrayAsync(); + + var text = SmartText.CreateFrom(message); + + var succ = 0; + var fail = 0; + foreach (var patron in patrons) + { + try + { + var user = await _client.GetUserAsync(patron.UserId); + await _sender.Response(user).Text(text).SendAsync(); + ++succ; + } + catch + { + ++fail; + } + + await Task.Delay(1000); + } + + return (succ, fail); + } + + public PatronConfigData GetConfig() + => _pConf.Data; +} \ No newline at end of file From 78c78353468ff3ccfbd45f73652f4730865e7a8b Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:54:52 +1200 Subject: [PATCH 54/62] Added Permissions module --- .../Blacklist/BlacklistCommands.cs | 154 +++++ .../CleverbotResponseCmdCdTypeReader.cs | 15 + .../CommandCooldown/CmdCdService.cs | 142 +++++ .../CommandCooldown/CmdCdsCommands.cs | 107 ++++ .../Permissions/Filter/FilterCommands.cs | 327 +++++++++++ .../Permissions/Filter/FilterService.cs | 250 ++++++++ .../Filter/ServerFilterSettings.cs | 10 + .../GlobalPermissionCommands.cs | 77 +++ .../GlobalPermissionService.cs | 92 +++ .../Modules/Permissions/PermissionCache.cs | 11 + .../Permissions/PermissionExtensions.cs | 132 +++++ .../Modules/Permissions/Permissions.cs | 544 ++++++++++++++++++ .../Permissions/PermissionsCollection.cs | 74 +++ .../Modules/Permissions/PermissionsService.cs | 187 ++++++ .../Permissions/ResetPermissionsCommands.cs | 37 ++ 15 files changed, 2159 insertions(+) create mode 100644 src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs create mode 100644 src/EllieBot/Modules/Permissions/CommandCooldown/CleverbotResponseCmdCdTypeReader.cs create mode 100644 src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs create mode 100644 src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs create mode 100644 src/EllieBot/Modules/Permissions/Filter/FilterCommands.cs create mode 100644 src/EllieBot/Modules/Permissions/Filter/FilterService.cs create mode 100644 src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs create mode 100644 src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs create mode 100644 src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs create mode 100644 src/EllieBot/Modules/Permissions/PermissionCache.cs create mode 100644 src/EllieBot/Modules/Permissions/PermissionExtensions.cs create mode 100644 src/EllieBot/Modules/Permissions/Permissions.cs create mode 100644 src/EllieBot/Modules/Permissions/PermissionsCollection.cs create mode 100644 src/EllieBot/Modules/Permissions/PermissionsService.cs create mode 100644 src/EllieBot/Modules/Permissions/ResetPermissionsCommands.cs diff --git a/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs b/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs new file mode 100644 index 0000000..9db46fb --- /dev/null +++ b/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs @@ -0,0 +1,154 @@ +#nullable disable +using EllieBot.Modules.Permissions.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions; + +public partial class Permissions +{ + [Group] + public partial class BlacklistCommands : EllieModule + { + private readonly DiscordSocketClient _client; + + public BlacklistCommands(DiscordSocketClient client) + => _client = client; + + private async Task ListBlacklistInternal(string title, BlacklistType type, int page = 0) + { + ArgumentOutOfRangeException.ThrowIfNegative(page); + + var list = _service.GetBlacklist(); + var allItems = await list.Where(x => x.Type == type) + .Select(i => + { + try + { + return Task.FromResult(i.Type switch + { + BlacklistType.Channel => Format.Code(i.ItemId.ToString()) + + " " + + (_client.GetChannel(i.ItemId)?.ToString() + ?? ""), + BlacklistType.User => Format.Code(i.ItemId.ToString()) + + " " + + ((_client.GetUser(i.ItemId)) + ?.ToString() + ?? ""), + BlacklistType.Server => Format.Code(i.ItemId.ToString()) + + " " + + (_client.GetGuild(i.ItemId)?.ToString() ?? ""), + _ => Format.Code(i.ItemId.ToString()) + }); + } + catch + { + Log.Warning("Can't get {BlacklistType} [{BlacklistItemId}]", + i.Type, + i.ItemId); + + return Task.FromResult(Format.Code(i.ItemId.ToString())); + } + }) + .WhenAll(); + + await Response() + .Paginated() + .Items(allItems) + .PageSize(10) + .CurrentPage(page) + .Page((pageItems, _) => + { + if (pageItems.Count == 0) + return _sender.CreateEmbed() + .WithOkColor() + .WithTitle(title) + .WithDescription(GetText(strs.empty_page)); + + return _sender.CreateEmbed() + .WithTitle(title) + .WithDescription(allItems.Join('\n')) + .WithOkColor(); + }) + .SendAsync(); + } + + [Cmd] + [OwnerOnly] + public Task UserBlacklist(int page = 1) + { + if (--page < 0) + return Task.CompletedTask; + + return ListBlacklistInternal(GetText(strs.blacklisted_users), BlacklistType.User, page); + } + + [Cmd] + [OwnerOnly] + public Task ChannelBlacklist(int page = 1) + { + if (--page < 0) + return Task.CompletedTask; + + return ListBlacklistInternal(GetText(strs.blacklisted_channels), BlacklistType.Channel, page); + } + + [Cmd] + [OwnerOnly] + public Task ServerBlacklist(int page = 1) + { + if (--page < 0) + return Task.CompletedTask; + + return ListBlacklistInternal(GetText(strs.blacklisted_servers), BlacklistType.Server, page); + } + + [Cmd] + [OwnerOnly] + public Task UserBlacklist(AddRemove action, ulong id) + => Blacklist(action, id, BlacklistType.User); + + [Cmd] + [OwnerOnly] + public Task UserBlacklist(AddRemove action, IUser usr) + => Blacklist(action, usr.Id, BlacklistType.User); + + [Cmd] + [OwnerOnly] + public Task ChannelBlacklist(AddRemove action, ulong id) + => Blacklist(action, id, BlacklistType.Channel); + + [Cmd] + [OwnerOnly] + public Task ServerBlacklist(AddRemove action, ulong id) + => Blacklist(action, id, BlacklistType.Server); + + [Cmd] + [OwnerOnly] + public Task ServerBlacklist(AddRemove action, IGuild guild) + => Blacklist(action, guild.Id, BlacklistType.Server); + + private async Task Blacklist(AddRemove action, ulong id, BlacklistType type) + { + if (action == AddRemove.Add) + await _service.Blacklist(type, id); + else + await _service.UnBlacklist(type, id); + + if (action == AddRemove.Add) + { + await Response() + .Confirm(strs.blacklisted(Format.Code(type.ToString()), + Format.Code(id.ToString()))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.unblacklisted(Format.Code(type.ToString()), + Format.Code(id.ToString()))) + .SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/CommandCooldown/CleverbotResponseCmdCdTypeReader.cs b/src/EllieBot/Modules/Permissions/CommandCooldown/CleverbotResponseCmdCdTypeReader.cs new file mode 100644 index 0000000..618ec59 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/CommandCooldown/CleverbotResponseCmdCdTypeReader.cs @@ -0,0 +1,15 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using static EllieBot.Common.TypeReaders.TypeReaderResult; + +namespace EllieBot.Modules.Permissions; + +public class CleverbotResponseCmdCdTypeReader : EllieTypeReader +{ + public override ValueTask> ReadAsync( + ICommandContext ctx, + string input) + => input.ToLowerInvariant() == CleverBotResponseStr.CLEVERBOT_RESPONSE + ? new(FromSuccess(new CleverBotResponseStr())) + : new(FromError(CommandError.ParseFailed, "Not a valid cleverbot")); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs b/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs new file mode 100644 index 0000000..f4ea9e8 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs @@ -0,0 +1,142 @@ +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; + +namespace EllieBot.Modules.Permissions.Services; + +public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, IEService +{ + private readonly DbService _db; + private readonly ConcurrentDictionary> _settings = new(); + + private readonly ConcurrentDictionary<(ulong, string), ConcurrentDictionary> _activeCooldowns = + new(); + + public int Priority => 0; + + public CmdCdService(IBot bot, DbService db) + { + _db = db; + _settings = bot + .AllGuildConfigs + .ToDictionary(x => x.GuildId, x => x.CommandCooldowns + .DistinctBy(x => x.CommandName.ToLowerInvariant()) + .ToDictionary(c => c.CommandName, c => c.Seconds) + .ToConcurrent()) + .ToConcurrent(); + } + + public Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command) + => TryBlock(context.Guild, context.User, command.Name.ToLowerInvariant()); + + public Task TryBlock(IGuild? guild, IUser user, string commandName) + { + if (guild is null) + return Task.FromResult(false); + + if (!_settings.TryGetValue(guild.Id, out var cooldownSettings)) + return Task.FromResult(false); + + if (!cooldownSettings.TryGetValue(commandName, out var cdSeconds)) + return Task.FromResult(false); + + var cooldowns = _activeCooldowns.GetOrAdd( + (guild.Id, commandName), + static _ => new()); + + // if user is not already on cooldown, add + if (cooldowns.TryAdd(user.Id, DateTime.UtcNow)) + { + return Task.FromResult(false); + } + + // if there is an entry, maybe it expired. Try to check if it expired and don't fail if it did + // - just update + if (cooldowns.TryGetValue(user.Id, out var oldValue)) + { + var diff = DateTime.UtcNow - oldValue; + if (diff.TotalSeconds > cdSeconds) + { + if (cooldowns.TryUpdate(user.Id, DateTime.UtcNow, oldValue)) + return Task.FromResult(false); + } + } + + return Task.FromResult(true); + } + + public async Task OnReadyAsync() + { + using var timer = new PeriodicTimer(TimeSpan.FromHours(1)); + + while (await timer.WaitForNextTickAsync()) + { + // once per hour delete expired entries + foreach (var ((guildId, commandName), dict) in _activeCooldowns) + { + // if this pair no longer has associated config, that means it has been removed. + // remove all cooldowns + if (!_settings.TryGetValue(guildId, out var inner) + || !inner.TryGetValue(commandName, out var cdSeconds)) + { + _activeCooldowns.Remove((guildId, commandName), out _); + continue; + } + + Cleanup(dict, cdSeconds); + } + } + } + + private void Cleanup(ConcurrentDictionary dict, int cdSeconds) + { + var now = DateTime.UtcNow; + foreach (var (key, _) in dict.Where(x => (now - x.Value).TotalSeconds > cdSeconds).ToArray()) + { + dict.TryRemove(key, out _); + } + } + + public void ClearCooldowns(ulong guildId, string cmdName) + { + if (_settings.TryGetValue(guildId, out var dict)) + dict.TryRemove(cmdName, out _); + + _activeCooldowns.TryRemove((guildId, cmdName), out _); + + using var ctx = _db.GetDbContext(); + var gc = ctx.GuildConfigsForId(guildId, x => x.Include(x => x.CommandCooldowns)); + gc.CommandCooldowns.RemoveWhere(x => x.CommandName == cmdName); + ctx.SaveChanges(); + } + + public void AddCooldown(ulong guildId, string name, int secs) + { + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(secs); + + var sett = _settings.GetOrAdd(guildId, static _ => new()); + sett[name] = secs; + + // force cleanup + if (_activeCooldowns.TryGetValue((guildId, name), out var dict)) + Cleanup(dict, secs); + + using var ctx = _db.GetDbContext(); + var gc = ctx.GuildConfigsForId(guildId, x => x.Include(x => x.CommandCooldowns)); + gc.CommandCooldowns.RemoveWhere(x => x.CommandName == name); + gc.CommandCooldowns.Add(new() + { + Seconds = secs, + CommandName = name + }); + ctx.SaveChanges(); + } + + public IReadOnlyCollection<(string CommandName, int Seconds)> GetCommandCooldowns(ulong guildId) + { + if (!_settings.TryGetValue(guildId, out var dict)) + return Array.Empty<(string, int)>(); + + return dict.Select(x => (x.Key, x.Value)).ToArray(); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs b/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs new file mode 100644 index 0000000..e2c1427 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdsCommands.cs @@ -0,0 +1,107 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.TypeReaders; +using EllieBot.Db; +using EllieBot.Modules.Permissions.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions; + +public partial class Permissions +{ + [Group] + public partial class CmdCdsCommands : EllieModule + { + private readonly DbService _db; + private readonly CmdCdService _service; + + public CmdCdsCommands(CmdCdService service, DbService db) + { + _service = service; + _db = db; + } + + private async Task CmdCooldownInternal(string cmdName, int secs) + { + var channel = (ITextChannel)ctx.Channel; + if (secs is < 0 or > 3600) + { + await Response().Error(strs.invalid_second_param_between(0, 3600)).SendAsync(); + return; + } + + var name = cmdName.ToLowerInvariant(); + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns)); + + var toDelete = config.CommandCooldowns.FirstOrDefault(cc => cc.CommandName == name); + if (toDelete is not null) + uow.Set().Remove(toDelete); + if (secs != 0) + { + var cc = new CommandCooldown + { + CommandName = name, + Seconds = secs + }; + config.CommandCooldowns.Add(cc); + _service.AddCooldown(channel.Guild.Id, name, secs); + } + + await uow.SaveChangesAsync(); + } + + if (secs == 0) + { + _service.ClearCooldowns(ctx.Guild.Id, cmdName); + await Response().Confirm(strs.cmdcd_cleared(Format.Bold(name))).SendAsync(); + } + else + await Response().Confirm(strs.cmdcd_add(Format.Bold(name), Format.Bold(secs.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(0)] + public Task CmdCooldown(CleverBotResponseStr command, int secs) + => CmdCooldownInternal(CleverBotResponseStr.CLEVERBOT_RESPONSE, secs); + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public Task CmdCooldown(CommandOrExprInfo command, int secs) + => CmdCooldownInternal(command.Name, secs); + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AllCmdCooldowns(int page = 1) + { + if (--page < 0) + return; + + var localSet = _service.GetCommandCooldowns(ctx.Guild.Id); + + if (!localSet.Any()) + await Response().Confirm(strs.cmdcd_none).SendAsync(); + else + { + await Response() + .Paginated() + .Items(localSet) + .PageSize(15) + .CurrentPage(page) + .Page((items, _) => + { + var output = items.Select(x => + $"{Format.Code(x.CommandName)}: {x.Seconds}s"); + + return _sender.CreateEmbed() + .WithOkColor() + .WithDescription(output.Join("\n")); + }) + .SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/Filter/FilterCommands.cs b/src/EllieBot/Modules/Permissions/Filter/FilterCommands.cs new file mode 100644 index 0000000..cdd3cad --- /dev/null +++ b/src/EllieBot/Modules/Permissions/Filter/FilterCommands.cs @@ -0,0 +1,327 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Modules.Permissions.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions; + +public partial class Permissions +{ + [Group] + public partial class FilterCommands : EllieModule + { + private readonly DbService _db; + + public FilterCommands(DbService db) + => _db = db; + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task FwClear() + { + _service.ClearFilteredWords(ctx.Guild.Id); + await Response().Confirm(strs.fw_cleared).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task FilterList() + { + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle("Server filter settings"); + + var config = await _service.GetFilterSettings(ctx.Guild.Id); + + string GetEnabledEmoji(bool value) + => value ? "\\🟢" : "\\🔴"; + + async Task GetChannelListAsync(IReadOnlyCollection channels) + { + var toReturn = (await channels + .Select(async cid => + { + var ch = await ctx.Guild.GetChannelAsync(cid); + return ch is null + ? $"{cid} *missing*" + : $"<#{cid}>"; + }) + .WhenAll()) + .Join('\n'); + + if (string.IsNullOrWhiteSpace(toReturn)) + return GetText(strs.no_channel_found); + + return toReturn; + } + + embed.AddField($"{GetEnabledEmoji(config.FilterLinksEnabled)} Filter Links", + await GetChannelListAsync(config.FilterLinksChannels)); + + embed.AddField($"{GetEnabledEmoji(config.FilterInvitesEnabled)} Filter Invites", + await GetChannelListAsync(config.FilterInvitesChannels)); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task SrvrFilterInv() + { + var channel = (ITextChannel)ctx.Channel; + + bool enabled; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(channel.Guild.Id, set => set); + enabled = config.FilterInvites = !config.FilterInvites; + await uow.SaveChangesAsync(); + } + + if (enabled) + { + _service.InviteFilteringServers.Add(channel.Guild.Id); + await Response().Confirm(strs.invite_filter_server_on).SendAsync(); + } + else + { + _service.InviteFilteringServers.TryRemove(channel.Guild.Id); + await Response().Confirm(strs.invite_filter_server_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ChnlFilterInv() + { + var channel = (ITextChannel)ctx.Channel; + + FilterChannelId removed; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(channel.Guild.Id, + set => set.Include(gc => gc.FilterInvitesChannelIds)); + var match = new FilterChannelId + { + ChannelId = channel.Id + }; + removed = config.FilterInvitesChannelIds.FirstOrDefault(fc => fc.Equals(match)); + + if (removed is null) + config.FilterInvitesChannelIds.Add(match); + else + uow.Remove(removed); + await uow.SaveChangesAsync(); + } + + if (removed is null) + { + _service.InviteFilteringChannels.Add(channel.Id); + await Response().Confirm(strs.invite_filter_channel_on).SendAsync(); + } + else + { + _service.InviteFilteringChannels.TryRemove(channel.Id); + await Response().Confirm(strs.invite_filter_channel_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task SrvrFilterLin() + { + var channel = (ITextChannel)ctx.Channel; + + bool enabled; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(channel.Guild.Id, set => set); + enabled = config.FilterLinks = !config.FilterLinks; + await uow.SaveChangesAsync(); + } + + if (enabled) + { + _service.LinkFilteringServers.Add(channel.Guild.Id); + await Response().Confirm(strs.link_filter_server_on).SendAsync(); + } + else + { + _service.LinkFilteringServers.TryRemove(channel.Guild.Id); + await Response().Confirm(strs.link_filter_server_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ChnlFilterLin() + { + var channel = (ITextChannel)ctx.Channel; + + FilterLinksChannelId removed; + await using (var uow = _db.GetDbContext()) + { + var config = + uow.GuildConfigsForId(channel.Guild.Id, set => set.Include(gc => gc.FilterLinksChannelIds)); + var match = new FilterLinksChannelId + { + ChannelId = channel.Id + }; + removed = config.FilterLinksChannelIds.FirstOrDefault(fc => fc.Equals(match)); + + if (removed is null) + config.FilterLinksChannelIds.Add(match); + else + uow.Remove(removed); + await uow.SaveChangesAsync(); + } + + if (removed is null) + { + _service.LinkFilteringChannels.Add(channel.Id); + await Response().Confirm(strs.link_filter_channel_on).SendAsync(); + } + else + { + _service.LinkFilteringChannels.TryRemove(channel.Id); + await Response().Confirm(strs.link_filter_channel_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task SrvrFilterWords() + { + var channel = (ITextChannel)ctx.Channel; + + bool enabled; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(channel.Guild.Id, set => set); + enabled = config.FilterWords = !config.FilterWords; + await uow.SaveChangesAsync(); + } + + if (enabled) + { + _service.WordFilteringServers.Add(channel.Guild.Id); + await Response().Confirm(strs.word_filter_server_on).SendAsync(); + } + else + { + _service.WordFilteringServers.TryRemove(channel.Guild.Id); + await Response().Confirm(strs.word_filter_server_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ChnlFilterWords() + { + var channel = (ITextChannel)ctx.Channel; + + FilterWordsChannelId removed; + await using (var uow = _db.GetDbContext()) + { + var config = + uow.GuildConfigsForId(channel.Guild.Id, set => set.Include(gc => gc.FilterWordsChannelIds)); + + var match = new FilterWordsChannelId + { + ChannelId = channel.Id + }; + removed = config.FilterWordsChannelIds.FirstOrDefault(fc => fc.Equals(match)); + if (removed is null) + config.FilterWordsChannelIds.Add(match); + else + uow.Remove(removed); + await uow.SaveChangesAsync(); + } + + if (removed is null) + { + _service.WordFilteringChannels.Add(channel.Id); + await Response().Confirm(strs.word_filter_channel_on).SendAsync(); + } + else + { + _service.WordFilteringChannels.TryRemove(channel.Id); + await Response().Confirm(strs.word_filter_channel_off).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task FilterWord([Leftover] string word) + { + var channel = (ITextChannel)ctx.Channel; + + word = word?.Trim().ToLowerInvariant(); + + if (string.IsNullOrWhiteSpace(word)) + return; + + FilteredWord removed; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(channel.Guild.Id, set => set.Include(gc => gc.FilteredWords)); + + removed = config.FilteredWords.FirstOrDefault(fw => fw.Word.Trim().ToLowerInvariant() == word); + + if (removed is null) + { + config.FilteredWords.Add(new() + { + Word = word + }); + } + else + uow.Remove(removed); + + await uow.SaveChangesAsync(); + } + + var filteredWords = + _service.ServerFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); + + if (removed is null) + { + filteredWords.Add(word); + await Response().Confirm(strs.filter_word_add(Format.Code(word))).SendAsync(); + } + else + { + filteredWords.TryRemove(word); + await Response().Confirm(strs.filter_word_remove(Format.Code(word))).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task LstFilterWords(int page = 1) + { + page--; + if (page < 0) + return; + + var channel = (ITextChannel)ctx.Channel; + + _service.ServerFilteredWords.TryGetValue(channel.Guild.Id, out var fwHash); + + var fws = fwHash.ToArray(); + + await Response() + .Paginated() + .Items(fws) + .PageSize(10) + .CurrentPage(page) + .Page((items, _) => _sender.CreateEmbed() + .WithTitle(GetText(strs.filter_word_list)) + .WithDescription(string.Join("\n", items)) + .WithOkColor()) + .SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/Filter/FilterService.cs b/src/EllieBot/Modules/Permissions/Filter/FilterService.cs new file mode 100644 index 0000000..9dfe01e --- /dev/null +++ b/src/EllieBot/Modules/Permissions/Filter/FilterService.cs @@ -0,0 +1,250 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions.Services; + +public sealed class FilterService : IExecOnMessage +{ + public ConcurrentHashSet InviteFilteringChannels { get; } + public ConcurrentHashSet InviteFilteringServers { get; } + + //serverid, filteredwords + public ConcurrentDictionary> ServerFilteredWords { get; } + + public ConcurrentHashSet WordFilteringChannels { get; } + public ConcurrentHashSet WordFilteringServers { get; } + + public ConcurrentHashSet LinkFilteringChannels { get; } + public ConcurrentHashSet LinkFilteringServers { get; } + + public int Priority + => int.MaxValue - 1; + + private readonly DbService _db; + + public FilterService(DiscordSocketClient client, DbService db) + { + _db = db; + + using (var uow = db.GetDbContext()) + { + var ids = client.GetGuildIds(); + var configs = uow.Set() + .AsQueryable() + .Include(x => x.FilteredWords) + .Include(x => x.FilterLinksChannelIds) + .Include(x => x.FilterWordsChannelIds) + .Include(x => x.FilterInvitesChannelIds) + .Where(gc => ids.Contains(gc.GuildId)) + .ToList(); + + InviteFilteringServers = new(configs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId)); + InviteFilteringChannels = + new(configs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId))); + + LinkFilteringServers = new(configs.Where(gc => gc.FilterLinks).Select(gc => gc.GuildId)); + LinkFilteringChannels = + new(configs.SelectMany(gc => gc.FilterLinksChannelIds.Select(fci => fci.ChannelId))); + + var dict = configs.ToDictionary(gc => gc.GuildId, + gc => new ConcurrentHashSet(gc.FilteredWords.Select(fw => fw.Word).Distinct())); + + ServerFilteredWords = new(dict); + + var serverFiltering = configs.Where(gc => gc.FilterWords); + WordFilteringServers = new(serverFiltering.Select(gc => gc.GuildId)); + WordFilteringChannels = + new(configs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId))); + } + + client.MessageUpdated += (oldData, newMsg, channel) => + { + _ = Task.Run(() => + { + var guild = (channel as ITextChannel)?.Guild; + + if (guild is null || newMsg is not IUserMessage usrMsg) + return Task.CompletedTask; + + return ExecOnMessageAsync(guild, usrMsg); + }); + return Task.CompletedTask; + }; + } + + public ConcurrentHashSet FilteredWordsForChannel(ulong channelId, ulong guildId) + { + var words = new ConcurrentHashSet(); + if (WordFilteringChannels.Contains(channelId)) + ServerFilteredWords.TryGetValue(guildId, out words); + return words; + } + + public void ClearFilteredWords(ulong guildId) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, + set => set.Include(x => x.FilteredWords).Include(x => x.FilterWordsChannelIds)); + + WordFilteringServers.TryRemove(guildId); + ServerFilteredWords.TryRemove(guildId, out _); + + foreach (var c in gc.FilterWordsChannelIds) + WordFilteringChannels.TryRemove(c.ChannelId); + + gc.FilterWords = false; + gc.FilteredWords.Clear(); + gc.FilterWordsChannelIds.Clear(); + + uow.SaveChanges(); + } + + public ConcurrentHashSet FilteredWordsForServer(ulong guildId) + { + var words = new ConcurrentHashSet(); + if (WordFilteringServers.Contains(guildId)) + ServerFilteredWords.TryGetValue(guildId, out words); + return words; + } + + public async Task ExecOnMessageAsync(IGuild guild, IUserMessage msg) + { + if (msg.Author is not IGuildUser gu || gu.GuildPermissions.Administrator) + return false; + + var results = await Task.WhenAll(FilterInvites(guild, msg), FilterWords(guild, msg), FilterLinks(guild, msg)); + + return results.Any(x => x); + } + + private async Task FilterWords(IGuild guild, IUserMessage usrMsg) + { + if (guild is null) + return false; + if (usrMsg is null) + return false; + + var filteredChannelWords = + FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet(); + var filteredServerWords = FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet(); + var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' '); + if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0) + { + foreach (var word in wordsInMessage) + { + if (filteredChannelWords.Contains(word) || filteredServerWords.Contains(word)) + { + Log.Information("User {UserName} [{UserId}] used a filtered word in {ChannelId} channel", + usrMsg.Author.ToString(), + usrMsg.Author.Id, + usrMsg.Channel.Id); + + try + { + await usrMsg.DeleteAsync(); + } + catch (HttpException ex) + { + Log.Warning(ex, + "I do not have permission to filter words in channel with id {Id}", + usrMsg.Channel.Id); + } + + return true; + } + } + } + + return false; + } + + private async Task FilterInvites(IGuild guild, IUserMessage usrMsg) + { + if (guild is null) + return false; + if (usrMsg is null) + return false; + + // if user has manage messages perm, don't filter + if (usrMsg.Channel is ITextChannel ch && usrMsg.Author is IGuildUser gu && gu.GetPermissions(ch).ManageMessages) + return false; + + if ((InviteFilteringChannels.Contains(usrMsg.Channel.Id) || InviteFilteringServers.Contains(guild.Id)) + && usrMsg.Content.IsDiscordInvite()) + { + Log.Information("User {UserName} [{UserId}] sent a filtered invite to {ChannelId} channel", + usrMsg.Author.ToString(), + usrMsg.Author.Id, + usrMsg.Channel.Id); + + try + { + await usrMsg.DeleteAsync(); + return true; + } + catch (HttpException ex) + { + Log.Warning(ex, + "I do not have permission to filter invites in channel with id {Id}", + usrMsg.Channel.Id); + return true; + } + } + + return false; + } + + private async Task FilterLinks(IGuild guild, IUserMessage usrMsg) + { + if (guild is null) + return false; + if (usrMsg is null) + return false; + + // if user has manage messages perm, don't filter + if (usrMsg.Channel is ITextChannel ch && usrMsg.Author is IGuildUser gu && gu.GetPermissions(ch).ManageMessages) + return false; + + if ((LinkFilteringChannels.Contains(usrMsg.Channel.Id) || LinkFilteringServers.Contains(guild.Id)) + && usrMsg.Content.TryGetUrlPath(out _)) + { + Log.Information("User {UserName} [{UserId}] sent a filtered link to {ChannelId} channel", + usrMsg.Author.ToString(), + usrMsg.Author.Id, + usrMsg.Channel.Id); + + try + { + await usrMsg.DeleteAsync(); + return true; + } + catch (HttpException ex) + { + Log.Warning(ex, "I do not have permission to filter links in channel with id {Id}", usrMsg.Channel.Id); + return true; + } + } + + return false; + } + + public async Task GetFilterSettings(ulong guildId) + { + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, + set => set + .Include(x => x.FilterInvitesChannelIds) + .Include(x => x.FilterLinksChannelIds)); + + return new() + { + FilterInvitesChannels = gc.FilterInvitesChannelIds.Map(x => x.ChannelId), + FilterLinksChannels = gc.FilterLinksChannelIds.Map(x => x.ChannelId), + FilterInvitesEnabled = gc.FilterInvites, + FilterLinksEnabled = gc.FilterLinks, + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs b/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs new file mode 100644 index 0000000..bf8454b --- /dev/null +++ b/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs @@ -0,0 +1,10 @@ +#nullable disable +namespace EllieBot.Modules.Permissions.Services; + +public readonly struct ServerFilterSettings +{ + public bool FilterInvitesEnabled { get; init; } + public bool FilterLinksEnabled { get; init; } + public IReadOnlyCollection FilterInvitesChannels { get; init; } + public IReadOnlyCollection FilterLinksChannels { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs b/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs new file mode 100644 index 0000000..d3abefd --- /dev/null +++ b/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionCommands.cs @@ -0,0 +1,77 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Permissions.Services; + +namespace EllieBot.Modules.Permissions; + +public partial class Permissions +{ + [Group] + public partial class GlobalPermissionCommands : EllieModule + { + private readonly GlobalPermissionService _service; + private readonly DbService _db; + + public GlobalPermissionCommands(GlobalPermissionService service, DbService db) + { + _service = service; + _db = db; + } + + [Cmd] + [OwnerOnly] + public async Task GlobalPermList() + { + var blockedModule = _service.BlockedModules; + var blockedCommands = _service.BlockedCommands; + if (!blockedModule.Any() && !blockedCommands.Any()) + { + await Response().Error(strs.lgp_none).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed().WithOkColor(); + + if (blockedModule.Any()) + embed.AddField(GetText(strs.blocked_modules), string.Join("\n", _service.BlockedModules)); + + if (blockedCommands.Any()) + embed.AddField(GetText(strs.blocked_commands), string.Join("\n", _service.BlockedCommands)); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task GlobalModule(ModuleOrExpr module) + { + var moduleName = module.Name.ToLowerInvariant(); + + var added = _service.ToggleModule(moduleName); + + if (added) + { + await Response().Confirm(strs.gmod_add(Format.Bold(module.Name))).SendAsync(); + return; + } + + await Response().Confirm(strs.gmod_remove(Format.Bold(module.Name))).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task GlobalCommand(CommandOrExprInfo cmd) + { + var commandName = cmd.Name.ToLowerInvariant(); + var added = _service.ToggleCommand(commandName); + + if (added) + { + await Response().Confirm(strs.gcmd_add(Format.Bold(cmd.Name))).SendAsync(); + return; + } + + await Response().Confirm(strs.gcmd_remove(Format.Bold(cmd.Name))).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs b/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs new file mode 100644 index 0000000..00dfd78 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs @@ -0,0 +1,92 @@ +#nullable disable +using EllieBot.Common.ModuleBehaviors; + +namespace EllieBot.Modules.Permissions.Services; + +public class GlobalPermissionService : IExecPreCommand, IEService +{ + public int Priority { get; } = 0; + + public HashSet BlockedCommands + => _bss.Data.Blocked.Commands; + + public HashSet BlockedModules + => _bss.Data.Blocked.Modules; + + private readonly BotConfigService _bss; + + public GlobalPermissionService(BotConfigService bss) + => _bss = bss; + + + public Task ExecPreCommandAsync(ICommandContext ctx, string moduleName, CommandInfo command) + { + var settings = _bss.Data; + var commandName = command.Name.ToLowerInvariant(); + + if (commandName != "resetglobalperms" + && (settings.Blocked.Commands.Contains(commandName) + || settings.Blocked.Modules.Contains(moduleName.ToLowerInvariant()))) + return Task.FromResult(true); + + return Task.FromResult(false); + } + + /// + /// Toggles module blacklist + /// + /// Lowercase module name + /// Whether the module is added + public bool ToggleModule(string moduleName) + { + var added = false; + _bss.ModifyConfig(bs => + { + if (bs.Blocked.Modules.Add(moduleName)) + added = true; + else + { + bs.Blocked.Modules.Remove(moduleName); + added = false; + } + }); + + return added; + } + + /// + /// Toggles command blacklist + /// + /// Lowercase command name + /// Whether the command is added + public bool ToggleCommand(string commandName) + { + var added = false; + _bss.ModifyConfig(bs => + { + if (bs.Blocked.Commands.Add(commandName)) + added = true; + else + { + bs.Blocked.Commands.Remove(commandName); + added = false; + } + }); + + return added; + } + + /// + /// Resets all global permissions + /// + public Task Reset() + { + _bss.ModifyConfig(bs => + { + bs.Blocked.Commands.Clear(); + bs.Blocked.Modules.Clear(); + }); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/PermissionCache.cs b/src/EllieBot/Modules/Permissions/PermissionCache.cs new file mode 100644 index 0000000..47b5983 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/PermissionCache.cs @@ -0,0 +1,11 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions.Common; + +public class PermissionCache +{ + public string PermRole { get; set; } + public bool Verbose { get; set; } = true; + public PermissionsCollection Permissions { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/PermissionExtensions.cs b/src/EllieBot/Modules/Permissions/PermissionExtensions.cs new file mode 100644 index 0000000..04eee4e --- /dev/null +++ b/src/EllieBot/Modules/Permissions/PermissionExtensions.cs @@ -0,0 +1,132 @@ +#nullable disable +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions.Common; + +public static class PermissionExtensions +{ + public static bool CheckPermissions( + this IEnumerable permsEnumerable, + IUser user, + IMessageChannel message, + string commandName, + string moduleName, + out int permIndex) + { + var perms = permsEnumerable as List ?? permsEnumerable.ToList(); + + for (var i = perms.Count - 1; i >= 0; i--) + { + var perm = perms[i]; + + var result = perm.CheckPermission(user, message, commandName, moduleName); + + if (result is null) + continue; + permIndex = i; + return result.Value; + } + + permIndex = -1; //defaut behaviour + return true; + } + + //null = not applicable + //true = applicable, allowed + //false = applicable, not allowed + public static bool? CheckPermission( + this Permissionv2 perm, + IUser user, + IMessageChannel channel, + string commandName, + string moduleName) + { + if (!((perm.SecondaryTarget == SecondaryPermissionType.Command + && string.Equals(perm.SecondaryTargetName, commandName, StringComparison.InvariantCultureIgnoreCase)) + || (perm.SecondaryTarget == SecondaryPermissionType.Module + && string.Equals(perm.SecondaryTargetName, moduleName, StringComparison.InvariantCultureIgnoreCase)) + || perm.SecondaryTarget == SecondaryPermissionType.AllModules)) + return null; + + var guildUser = user as IGuildUser; + + switch (perm.PrimaryTarget) + { + case PrimaryPermissionType.User: + if (perm.PrimaryTargetId == user.Id) + return perm.State; + break; + case PrimaryPermissionType.Channel: + if (perm.PrimaryTargetId == channel.Id) + return perm.State; + break; + case PrimaryPermissionType.Role: + if (guildUser is null) + break; + if (guildUser.RoleIds.Contains(perm.PrimaryTargetId)) + return perm.State; + break; + case PrimaryPermissionType.Server: + if (guildUser is null) + break; + return perm.State; + } + + return null; + } + + public static string GetCommand(this Permissionv2 perm, string prefix, SocketGuild guild = null) + { + var com = string.Empty; + switch (perm.PrimaryTarget) + { + case PrimaryPermissionType.User: + com += "u"; + break; + case PrimaryPermissionType.Channel: + com += "c"; + break; + case PrimaryPermissionType.Role: + com += "r"; + break; + case PrimaryPermissionType.Server: + com += "s"; + break; + } + + switch (perm.SecondaryTarget) + { + case SecondaryPermissionType.Module: + com += "m"; + break; + case SecondaryPermissionType.Command: + com += "c"; + break; + case SecondaryPermissionType.AllModules: + com = "a" + com + "m"; + break; + } + + var secName = perm.SecondaryTarget == SecondaryPermissionType.Command && !perm.IsCustomCommand + ? prefix + perm.SecondaryTargetName + : perm.SecondaryTargetName; + com += " " + (perm.SecondaryTargetName != "*" ? secName + " " : "") + (perm.State ? "enable" : "disable") + " "; + + switch (perm.PrimaryTarget) + { + case PrimaryPermissionType.User: + com += guild?.GetUser(perm.PrimaryTargetId)?.ToString() ?? $"<@{perm.PrimaryTargetId}>"; + break; + case PrimaryPermissionType.Channel: + com += $"<#{perm.PrimaryTargetId}>"; + break; + case PrimaryPermissionType.Role: + com += guild?.GetRole(perm.PrimaryTargetId)?.ToString() ?? $"<@&{perm.PrimaryTargetId}>"; + break; + case PrimaryPermissionType.Server: + break; + } + + return prefix + com; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/Permissions.cs b/src/EllieBot/Modules/Permissions/Permissions.cs new file mode 100644 index 0000000..90de56b --- /dev/null +++ b/src/EllieBot/Modules/Permissions/Permissions.cs @@ -0,0 +1,544 @@ +#nullable disable +using EllieBot.Common.TypeReaders; +using EllieBot.Common.TypeReaders.Models; +using EllieBot.Db; +using EllieBot.Modules.Permissions.Common; +using EllieBot.Modules.Permissions.Services; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions; + +public partial class Permissions : EllieModule +{ + public enum Reset { Reset } + + private readonly DbService _db; + + public Permissions(DbService db) + => _db = db; + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Verbose(PermissionAction action = null) + { + await using (var uow = _db.GetDbContext()) + { + var config = uow.GcWithPermissionsFor(ctx.Guild.Id); + if (action is null) + action = new(!config.VerbosePermissions); // New behaviour, can toggle. + config.VerbosePermissions = action.Value; + await uow.SaveChangesAsync(); + _service.UpdateCache(config); + } + + if (action.Value) + await Response().Confirm(strs.verbose_true).SendAsync(); + else + await Response().Confirm(strs.verbose_false).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(0)] + public async Task PermRole([Leftover] IRole role = null) + { + if (role is not null && role == role.Guild.EveryoneRole) + return; + + if (role is null) + { + var cache = _service.GetCacheFor(ctx.Guild.Id); + if (!ulong.TryParse(cache.PermRole, out var roleId) + || (role = ((SocketGuild)ctx.Guild).GetRole(roleId)) is null) + await Response().Confirm(strs.permrole_not_set).SendAsync(); + else + await Response().Confirm(strs.permrole(Format.Bold(role.ToString()))).SendAsync(); + return; + } + + await using (var uow = _db.GetDbContext()) + { + var config = uow.GcWithPermissionsFor(ctx.Guild.Id); + config.PermissionRole = role.Id.ToString(); + uow.SaveChanges(); + _service.UpdateCache(config); + } + + await Response().Confirm(strs.permrole_changed(Format.Bold(role.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [Priority(1)] + public async Task PermRole(Reset _) + { + await using (var uow = _db.GetDbContext()) + { + var config = uow.GcWithPermissionsFor(ctx.Guild.Id); + config.PermissionRole = null; + await uow.SaveChangesAsync(); + _service.UpdateCache(config); + } + + await Response().Confirm(strs.permrole_reset).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ListPerms(int page = 1) + { + if (page < 1) + return; + + IList perms; + + if (_service.Cache.TryGetValue(ctx.Guild.Id, out var permCache)) + perms = permCache.Permissions.Source.ToList(); + else + perms = Permissionv2.GetDefaultPermlist; + + var startPos = 20 * (page - 1); + var toSend = Format.Bold(GetText(strs.page(page))) + + "\n\n" + + string.Join("\n", + perms.Reverse() + .Skip(startPos) + .Take(20) + .Select(p => + { + var str = + $"`{p.Index + 1}.` {Format.Bold(p.GetCommand(prefix, (SocketGuild)ctx.Guild))}"; + if (p.Index == 0) + str += $" [{GetText(strs.uneditable)}]"; + return str; + })); + + await Response().Confirm(toSend).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task RemovePerm(int index) + { + index -= 1; + if (index < 0) + return; + try + { + Permissionv2 p; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GcWithPermissionsFor(ctx.Guild.Id); + var permsCol = new PermissionsCollection(config.Permissions); + p = permsCol[index]; + permsCol.RemoveAt(index); + uow.Remove(p); + await uow.SaveChangesAsync(); + _service.UpdateCache(config); + } + + await Response() + .Confirm(strs.removed(index + 1, + Format.Code(p.GetCommand(prefix, (SocketGuild)ctx.Guild)))) + .SendAsync(); + } + catch (IndexOutOfRangeException) + { + await Response().Error(strs.perm_out_of_range).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task MovePerm(int from, int to) + { + from -= 1; + to -= 1; + if (!(from == to || from < 0 || to < 0)) + { + try + { + Permissionv2 fromPerm; + await using (var uow = _db.GetDbContext()) + { + var config = uow.GcWithPermissionsFor(ctx.Guild.Id); + var permsCol = new PermissionsCollection(config.Permissions); + + var fromFound = from < permsCol.Count; + var toFound = to < permsCol.Count; + + if (!fromFound) + { + await Response().Error(strs.perm_not_found(++from)).SendAsync(); + return; + } + + if (!toFound) + { + await Response().Error(strs.perm_not_found(++to)).SendAsync(); + return; + } + + fromPerm = permsCol[from]; + + permsCol.RemoveAt(from); + permsCol.Insert(to, fromPerm); + await uow.SaveChangesAsync(); + _service.UpdateCache(config); + } + + await Response() + .Confirm(strs.moved_permission( + Format.Code(fromPerm.GetCommand(prefix, (SocketGuild)ctx.Guild)), + ++from, + ++to)) + .SendAsync(); + + return; + } + catch (Exception e) when (e is ArgumentOutOfRangeException or IndexOutOfRangeException) + { + } + } + + await Response().Confirm(strs.perm_out_of_range).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task SrvrCmd(CommandOrExprInfo command, PermissionAction action) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Server, + PrimaryTargetId = 0, + SecondaryTarget = SecondaryPermissionType.Command, + SecondaryTargetName = command.Name.ToLowerInvariant(), + State = action.Value, + IsCustomCommand = command.IsCustom + }); + + if (action.Value) + await Response().Confirm(strs.sx_enable(Format.Code(command.Name), GetText(strs.of_command))).SendAsync(); + else + await Response().Confirm(strs.sx_disable(Format.Code(command.Name), GetText(strs.of_command))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task SrvrMdl(ModuleOrExpr module, PermissionAction action) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Server, + PrimaryTargetId = 0, + SecondaryTarget = SecondaryPermissionType.Module, + SecondaryTargetName = module.Name.ToLowerInvariant(), + State = action.Value + }); + + if (action.Value) + await Response().Confirm(strs.sx_enable(Format.Code(module.Name), GetText(strs.of_module))).SendAsync(); + else + await Response().Confirm(strs.sx_disable(Format.Code(module.Name), GetText(strs.of_module))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task UsrCmd(CommandOrExprInfo command, PermissionAction action, [Leftover] IGuildUser user) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.User, + PrimaryTargetId = user.Id, + SecondaryTarget = SecondaryPermissionType.Command, + SecondaryTargetName = command.Name.ToLowerInvariant(), + State = action.Value, + IsCustomCommand = command.IsCustom + }); + + if (action.Value) + { + await Response() + .Confirm(strs.ux_enable(Format.Code(command.Name), + GetText(strs.of_command), + Format.Code(user.ToString()))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.ux_disable(Format.Code(command.Name), + GetText(strs.of_command), + Format.Code(user.ToString()))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task UsrMdl(ModuleOrExpr module, PermissionAction action, [Leftover] IGuildUser user) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.User, + PrimaryTargetId = user.Id, + SecondaryTarget = SecondaryPermissionType.Module, + SecondaryTargetName = module.Name.ToLowerInvariant(), + State = action.Value + }); + + if (action.Value) + { + await Response() + .Confirm(strs.ux_enable(Format.Code(module.Name), + GetText(strs.of_module), + Format.Code(user.ToString()))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.ux_disable(Format.Code(module.Name), + GetText(strs.of_module), + Format.Code(user.ToString()))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task RoleCmd(CommandOrExprInfo command, PermissionAction action, [Leftover] IRole role) + { + if (role == role.Guild.EveryoneRole) + return; + + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Role, + PrimaryTargetId = role.Id, + SecondaryTarget = SecondaryPermissionType.Command, + SecondaryTargetName = command.Name.ToLowerInvariant(), + State = action.Value, + IsCustomCommand = command.IsCustom + }); + + if (action.Value) + { + await Response() + .Confirm(strs.rx_enable(Format.Code(command.Name), + GetText(strs.of_command), + Format.Code(role.Name))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.rx_disable(Format.Code(command.Name), + GetText(strs.of_command), + Format.Code(role.Name))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task RoleMdl(ModuleOrExpr module, PermissionAction action, [Leftover] IRole role) + { + if (role == role.Guild.EveryoneRole) + return; + + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Role, + PrimaryTargetId = role.Id, + SecondaryTarget = SecondaryPermissionType.Module, + SecondaryTargetName = module.Name.ToLowerInvariant(), + State = action.Value + }); + + + if (action.Value) + { + await Response() + .Confirm(strs.rx_enable(Format.Code(module.Name), + GetText(strs.of_module), + Format.Code(role.Name))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.rx_disable(Format.Code(module.Name), + GetText(strs.of_module), + Format.Code(role.Name))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ChnlCmd(CommandOrExprInfo command, PermissionAction action, [Leftover] ITextChannel chnl) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Channel, + PrimaryTargetId = chnl.Id, + SecondaryTarget = SecondaryPermissionType.Command, + SecondaryTargetName = command.Name.ToLowerInvariant(), + State = action.Value, + IsCustomCommand = command.IsCustom + }); + + if (action.Value) + { + await Response() + .Confirm(strs.cx_enable(Format.Code(command.Name), + GetText(strs.of_command), + Format.Code(chnl.Name))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.cx_disable(Format.Code(command.Name), + GetText(strs.of_command), + Format.Code(chnl.Name))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task ChnlMdl(ModuleOrExpr module, PermissionAction action, [Leftover] ITextChannel chnl) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Channel, + PrimaryTargetId = chnl.Id, + SecondaryTarget = SecondaryPermissionType.Module, + SecondaryTargetName = module.Name.ToLowerInvariant(), + State = action.Value + }); + + if (action.Value) + { + await Response() + .Confirm(strs.cx_enable(Format.Code(module.Name), + GetText(strs.of_module), + Format.Code(chnl.Name))) + .SendAsync(); + } + else + { + await Response() + .Confirm(strs.cx_disable(Format.Code(module.Name), + GetText(strs.of_module), + Format.Code(chnl.Name))) + .SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AllChnlMdls(PermissionAction action, [Leftover] ITextChannel chnl) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Channel, + PrimaryTargetId = chnl.Id, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = action.Value + }); + + if (action.Value) + await Response().Confirm(strs.acm_enable(Format.Code(chnl.Name))).SendAsync(); + else + await Response().Confirm(strs.acm_disable(Format.Code(chnl.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AllRoleMdls(PermissionAction action, [Leftover] IRole role) + { + if (role == role.Guild.EveryoneRole) + return; + + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Role, + PrimaryTargetId = role.Id, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = action.Value + }); + + if (action.Value) + await Response().Confirm(strs.arm_enable(Format.Code(role.Name))).SendAsync(); + else + await Response().Confirm(strs.arm_disable(Format.Code(role.Name))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AllUsrMdls(PermissionAction action, [Leftover] IUser user) + { + await _service.AddPermissions(ctx.Guild.Id, + new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.User, + PrimaryTargetId = user.Id, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = action.Value + }); + + if (action.Value) + await Response().Confirm(strs.aum_enable(Format.Code(user.ToString()))).SendAsync(); + else + await Response().Confirm(strs.aum_disable(Format.Code(user.ToString()))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AllSrvrMdls(PermissionAction action) + { + var newPerm = new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.Server, + PrimaryTargetId = 0, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = action.Value + }; + + var allowUser = new Permissionv2 + { + PrimaryTarget = PrimaryPermissionType.User, + PrimaryTargetId = ctx.User.Id, + SecondaryTarget = SecondaryPermissionType.AllModules, + SecondaryTargetName = "*", + State = true + }; + + await _service.AddPermissions(ctx.Guild.Id, newPerm, allowUser); + + if (action.Value) + await Response().Confirm(strs.asm_enable).SendAsync(); + else + await Response().Confirm(strs.asm_disable).SendAsync(); + } +} diff --git a/src/EllieBot/Modules/Permissions/PermissionsCollection.cs b/src/EllieBot/Modules/Permissions/PermissionsCollection.cs new file mode 100644 index 0000000..c2526ea --- /dev/null +++ b/src/EllieBot/Modules/Permissions/PermissionsCollection.cs @@ -0,0 +1,74 @@ +#nullable disable +namespace EllieBot.Modules.Permissions.Common; + +public class PermissionsCollection : IndexedCollection + where T : class, IIndexed +{ + public override T this[int index] + { + get => Source[index]; + set + { + lock (_localLocker) + { + if (index == 0) // can't set first element. It's always allow all + throw new IndexOutOfRangeException(nameof(index)); + base[index] = value; + } + } + } + + private readonly object _localLocker = new(); + + public PermissionsCollection(IEnumerable source) + : base(source) + { + } + + public static implicit operator List(PermissionsCollection x) + => x.Source; + + public override void Clear() + { + lock (_localLocker) + { + var first = Source[0]; + base.Clear(); + Source[0] = first; + } + } + + public override bool Remove(T item) + { + bool removed; + lock (_localLocker) + { + if (Source.IndexOf(item) == 0) + throw new ArgumentException("You can't remove first permsission (allow all)"); + removed = base.Remove(item); + } + + return removed; + } + + public override void Insert(int index, T item) + { + lock (_localLocker) + { + if (index == 0) // can't insert on first place. Last item is always allow all. + throw new IndexOutOfRangeException(nameof(index)); + base.Insert(index, item); + } + } + + public override void RemoveAt(int index) + { + lock (_localLocker) + { + if (index == 0) // you can't remove first permission (allow all) + throw new IndexOutOfRangeException(nameof(index)); + + base.RemoveAt(index); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/PermissionsService.cs b/src/EllieBot/Modules/Permissions/PermissionsService.cs new file mode 100644 index 0000000..7bca184 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/PermissionsService.cs @@ -0,0 +1,187 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Modules.Permissions.Common; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Permissions.Services; + +public class PermissionService : IExecPreCommand, IEService +{ + public int Priority { get; } = 0; + + //guildid, root permission + public ConcurrentDictionary Cache { get; } = new(); + + private readonly DbService _db; + private readonly CommandHandler _cmd; + private readonly IBotStrings _strings; + private readonly IMessageSenderService _sender; + + public PermissionService( + DiscordSocketClient client, + DbService db, + CommandHandler cmd, + IBotStrings strings, + IMessageSenderService sender) + { + _db = db; + _cmd = cmd; + _strings = strings; + _sender = sender; + + using var uow = _db.GetDbContext(); + foreach (var x in uow.Set().PermissionsForAll(client.Guilds.ToArray().Select(x => x.Id).ToList())) + { + Cache.TryAdd(x.GuildId, + new() + { + Verbose = x.VerbosePermissions, + PermRole = x.PermissionRole, + Permissions = new(x.Permissions) + }); + } + } + + public PermissionCache GetCacheFor(ulong guildId) + { + if (!Cache.TryGetValue(guildId, out var pc)) + { + using (var uow = _db.GetDbContext()) + { + var config = uow.GuildConfigsForId(guildId, set => set.Include(x => x.Permissions)); + UpdateCache(config); + } + + Cache.TryGetValue(guildId, out pc); + if (pc is null) + throw new("Cache is null."); + } + + return pc; + } + + public async Task AddPermissions(ulong guildId, params Permissionv2[] perms) + { + await using var uow = _db.GetDbContext(); + var config = uow.GcWithPermissionsFor(guildId); + //var orderedPerms = new PermissionsCollection(config.Permissions); + var max = config.Permissions.Max(x => x.Index); //have to set its index to be the highest + foreach (var perm in perms) + { + perm.Index = ++max; + config.Permissions.Add(perm); + } + + await uow.SaveChangesAsync(); + UpdateCache(config); + } + + public void UpdateCache(GuildConfig config) + => Cache.AddOrUpdate(config.GuildId, + new PermissionCache + { + Permissions = new(config.Permissions), + PermRole = config.PermissionRole, + Verbose = config.VerbosePermissions + }, + (_, old) => + { + old.Permissions = new(config.Permissions); + old.PermRole = config.PermissionRole; + old.Verbose = config.VerbosePermissions; + return old; + }); + + public async Task ExecPreCommandAsync(ICommandContext ctx, string moduleName, CommandInfo command) + { + var guild = ctx.Guild; + var msg = ctx.Message; + var user = ctx.User; + var channel = ctx.Channel; + var commandName = command.Name.ToLowerInvariant(); + + if (guild is null) + return false; + + var resetCommand = commandName == "resetperms"; + + var pc = GetCacheFor(guild.Id); + if (!resetCommand + && !pc.Permissions.CheckPermissions(msg.Author, msg.Channel, commandName, moduleName, out var index)) + { + if (pc.Verbose) + { + try + { + await _sender.Response(channel) + .Error(_strings.GetText(strs.perm_prevent(index + 1, + Format.Bold(pc.Permissions[index] + .GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild))), + guild.Id)) + .SendAsync(); + } + catch + { + } + } + + return true; + } + + + if (moduleName == nameof(Permissions)) + { + if (user is not IGuildUser guildUser) + return true; + + if (guildUser.GuildPermissions.Administrator) + return false; + + var permRole = pc.PermRole; + if (!ulong.TryParse(permRole, out var rid)) + rid = 0; + string returnMsg; + IRole role; + if (string.IsNullOrWhiteSpace(permRole) || (role = guild.GetRole(rid)) is null) + { + returnMsg = "You need Admin permissions in order to use permission commands."; + if (pc.Verbose) + { + try + { await _sender.Response(channel).Error(returnMsg).SendAsync(); } + catch { } + } + + return true; + } + + if (!guildUser.RoleIds.Contains(rid)) + { + returnMsg = $"You need the {Format.Bold(role.Name)} role in order to use permission commands."; + if (pc.Verbose) + { + try + { await _sender.Response(channel).Error(returnMsg).SendAsync(); } + catch { } + } + + return true; + } + + return false; + } + + return false; + } + + public async Task Reset(ulong guildId) + { + await using var uow = _db.GetDbContext(); + var config = uow.GcWithPermissionsFor(guildId); + config.Permissions = Permissionv2.GetDefaultPermlist; + await uow.SaveChangesAsync(); + UpdateCache(config); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/ResetPermissionsCommands.cs b/src/EllieBot/Modules/Permissions/ResetPermissionsCommands.cs new file mode 100644 index 0000000..4193337 --- /dev/null +++ b/src/EllieBot/Modules/Permissions/ResetPermissionsCommands.cs @@ -0,0 +1,37 @@ +#nullable disable +using EllieBot.Modules.Permissions.Services; + +namespace EllieBot.Modules.Permissions; + +public partial class Permissions +{ + [Group] + public partial class ResetPermissionsCommands : EllieModule + { + private readonly GlobalPermissionService _gps; + private readonly PermissionService _perms; + + public ResetPermissionsCommands(GlobalPermissionService gps, PermissionService perms) + { + _gps = gps; + _perms = perms; + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task ResetPerms() + { + await _perms.Reset(ctx.Guild.Id); + await Response().Confirm(strs.perms_reset).SendAsync(); + } + + [Cmd] + [OwnerOnly] + public async Task ResetGlobalPerms() + { + await _gps.Reset(); + await Response().Confirm(strs.global_perms_reset).SendAsync(); + } + } +} \ No newline at end of file From e124621f90642dc0323f416598ac71757ab997a4 Mon Sep 17 00:00:00 2001 From: Toastie Date: Tue, 18 Jun 2024 23:55:36 +1200 Subject: [PATCH 55/62] Added Searches module --- .../Modules/Searches/Anime/AnimeResult.cs | 41 ++ .../Searches/Anime/AnimeSearchCommands.cs | 204 ++++++ .../Searches/Anime/AnimeSearchService.cs | 79 +++ .../Modules/Searches/Anime/MangaResult.cs | 40 ++ .../Modules/Searches/Crypto/CryptoCommands.cs | 196 ++++++ .../Modules/Searches/Crypto/CryptoService.cs | 215 ++++++ .../Crypto/DefaultStockDataService.cs | 126 ++++ .../Crypto/Drawing/CandleDrawingData.cs | 12 + .../Drawing/IStockChartDrawingService.cs | 8 + .../ImagesharpStockChartDrawingService.cs | 200 ++++++ .../Searches/Crypto/IStockDataService.cs | 8 + .../Searches/Crypto/_common/CandleData.cs | 8 + .../Searches/Crypto/_common/ImageData.cs | 7 + .../Searches/Crypto/_common/QuoteResponse.cs | 43 ++ .../Searches/Crypto/_common/StockData.cs | 15 + .../Searches/Crypto/_common/SymbolData.cs | 3 + .../Crypto/_common/YahooFinanceCandleData.cs | 12 + .../_common/YahooFinanceSearchResponse.cs | 19 + .../_common/YahooFinanceSearchResponseItem.cs | 25 + .../Crypto/_common/YahooQueryModel.cs | 9 + .../Modules/Searches/Feeds/FeedCommands.cs | 146 ++++ .../Modules/Searches/Feeds/FeedsService.cs | 294 ++++++++ src/EllieBot/Modules/Searches/JokeCommands.cs | 53 ++ .../Modules/Searches/MemegenCommands.cs | 99 +++ src/EllieBot/Modules/Searches/OsuCommands.cs | 297 ++++++++ .../Modules/Searches/PathOfExileCommands.cs | 312 +++++++++ .../Modules/Searches/PokemonSearchCommands.cs | 74 ++ .../Search/DefaultSearchServiceFactory.cs | 65 ++ .../Search/Google/GoogleCustomSearchResult.cs | 22 + .../Searches/Search/Google/GoogleImageData.cs | 12 + .../Search/Google/GoogleImageResult.cs | 19 + .../Search/Google/GoogleImageResultEntry.cs | 13 + .../Google/GoogleSearchResultInformation.cs | 13 + .../Search/Google/GoogleSearchService.cs | 66 ++ .../Google/OfficialGoogleSearchResultEntry.cs | 19 + .../GoogleScrape/GoogleScrapeService.cs | 121 ++++ .../PlainGoogleScrapeSearchResult.cs | 8 + .../GoogleScrape/PlainSearchResultEntry.cs | 9 + .../GoogleScrape/PlainSearchResultInfo.cs | 7 + .../Searches/Search/IImageSearchResult.cs | 13 + .../Modules/Searches/Search/ISearchResult.cs | 8 + .../Searches/Search/ISearchResultEntry.cs | 9 + .../Search/ISearchResultInformation.cs | 7 + .../Modules/Searches/Search/ISearchService.cs | 9 + .../Searches/Search/ISearchServiceFactory.cs | 10 + .../Modules/Searches/Search/SearchCommands.cs | 202 ++++++ .../Searches/Search/SearchServiceBase.cs | 9 + .../Search/Searx/SearxImageSearchResult.cs | 28 + .../Searx/SearxImageSearchResultEntry.cs | 14 + .../Searches/Search/Searx/SearxInfobox.cs | 30 + .../Search/Searx/SearxSearchAttribute.cs | 15 + .../Search/Searx/SearxSearchResult.cs | 47 ++ .../Search/Searx/SearxSearchResultEntry.cs | 51 ++ .../Searx/SearxSearchResultInformation.cs | 7 + .../Search/Searx/SearxSearchService.cs | 76 ++ .../Searches/Search/Searx/SearxUrlData.cs | 15 + .../Search/Youtube/IYoutubeSearchService.cs | 6 + .../Search/Youtube/InvidiousSearchResponse.cs | 9 + .../Youtube/InvidiousYtSearchService.cs | 46 ++ .../Searches/Search/Youtube/VideoInfo.cs | 9 + .../Youtube/YoutubeDataApiSearchService.cs | 26 + .../Youtube/YtdlYoutubeSearchService.cs | 7 + .../Youtube/YtdlpYoutubeSearchService.cs | 7 + .../Search/Youtube/YtdlxServiceBase.cs | 34 + src/EllieBot/Modules/Searches/Searches.cs | 600 ++++++++++++++++ .../Modules/Searches/SearchesService.cs | 457 ++++++++++++ .../StreamNotificationCommands.cs | 211 ++++++ .../StreamNotificationService.cs | 651 ++++++++++++++++++ .../StreamOnlineMessageDeleterService.cs | 99 +++ .../Searches/Translate/ITranslateService.cs | 17 + .../Searches/Translate/TranslateService.cs | 224 ++++++ .../Searches/Translate/TranslatorCommands.cs | 95 +++ src/EllieBot/Modules/Searches/XkcdCommands.cs | 97 +++ .../Searches/YoutubeTrack/YtTrackService.cs | 134 ++++ .../Searches/YoutubeTrack/YtUploadCommands.cs | 54 ++ .../Modules/Searches/_common/AtlExtensions.cs | 12 + .../Modules/Searches/_common/BibleVerses.cs | 20 + .../_common/Config/ImgSearchEngine.cs | 7 + .../Searches/_common/Config/SearchesConfig.cs | 86 +++ .../_common/Config/SearchesConfigService.cs | 58 ++ .../_common/Config/WebSearchEngine.cs | 9 + .../Modules/Searches/_common/CryptoData.cs | 66 ++ .../Modules/Searches/_common/DefineModel.cs | 43 ++ .../Modules/Searches/_common/E621Object.cs | 24 + .../Exceptions/StreamNotFoundException.cs | 19 + .../Modules/Searches/_common/Extensions.cs | 9 + .../Modules/Searches/_common/Gallery.cs | 44 ++ .../Searches/_common/GatariUserResponse.cs | 52 ++ .../_common/GatariUserStatsResponse.cs | 76 ++ .../Searches/_common/GoogleSearchResult.cs | 16 + .../Searches/_common/HearthstoneCardData.cs | 13 + .../Searches/_common/LowerCaseNamingPolicy.cs | 12 + .../Modules/Searches/_common/MagicItem.cs | 8 + .../Modules/Searches/_common/MtgData.cs | 26 + .../Modules/Searches/_common/NovelData.cs | 14 + .../Modules/Searches/_common/OmdbMovie.cs | 13 + .../Modules/Searches/_common/OsuMapData.cs | 9 + .../Modules/Searches/_common/OsuUserBets.cs | 58 ++ .../Modules/Searches/_common/OsuUserData.cs | 70 ++ .../Searches/_common/PathOfExileModels.cs | 40 ++ .../Modules/Searches/_common/SteamGameId.cs | 35 + .../Models/HelixStreamsResponse.cs | 64 ++ .../Models/HelixUsersResponse.cs | 46 ++ .../Models/PicartoChannelResponse.cs | 157 +++++ .../StreamNotifications/Models/StreamData.cs | 21 + .../Models/StreamDataKey.cs | 16 + .../Models/TrovoGetUsersResponse.cs | 61 ++ .../Models/TrovoRequestData.cs | 10 + .../Models/TrovoSocialLink.cs | 13 + .../Models/TwitchResponseV5.cs | 114 +++ .../Models/TwitchUsersResponseV5.cs | 37 + .../StreamNotifications/NotifChecker.cs | 215 ++++++ .../Providers/PicartoProvider.cs | 100 +++ .../StreamNotifications/Providers/Provider.cs | 63 ++ .../Providers/TrovoProvider.cs | 126 ++++ .../Providers/TwitchHelixProvider.cs | 194 ++++++ .../Modules/Searches/_common/TimeData.cs | 9 + .../Modules/Searches/_common/TimeModels.cs | 22 + .../Modules/Searches/_common/UrbanDef.cs | 14 + .../Modules/Searches/_common/WeatherModels.cs | 67 ++ .../Searches/_common/WikipediaApiModel.cs | 18 + .../Modules/Searches/_common/WoWJoke.cs | 11 + 122 files changed, 8469 insertions(+) create mode 100644 src/EllieBot/Modules/Searches/Anime/AnimeResult.cs create mode 100644 src/EllieBot/Modules/Searches/Anime/AnimeSearchCommands.cs create mode 100644 src/EllieBot/Modules/Searches/Anime/AnimeSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Anime/MangaResult.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/CryptoCommands.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/CryptoService.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/Drawing/CandleDrawingData.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/Drawing/IStockChartDrawingService.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/Drawing/ImagesharpStockChartDrawingService.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/IStockDataService.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/CandleData.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/ImageData.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/QuoteResponse.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/StockData.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/SymbolData.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceCandleData.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponse.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponseItem.cs create mode 100644 src/EllieBot/Modules/Searches/Crypto/_common/YahooQueryModel.cs create mode 100644 src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs create mode 100644 src/EllieBot/Modules/Searches/Feeds/FeedsService.cs create mode 100644 src/EllieBot/Modules/Searches/JokeCommands.cs create mode 100644 src/EllieBot/Modules/Searches/MemegenCommands.cs create mode 100644 src/EllieBot/Modules/Searches/OsuCommands.cs create mode 100644 src/EllieBot/Modules/Searches/PathOfExileCommands.cs create mode 100644 src/EllieBot/Modules/Searches/PokemonSearchCommands.cs create mode 100644 src/EllieBot/Modules/Searches/Search/DefaultSearchServiceFactory.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/GoogleCustomSearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/GoogleImageData.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/GoogleImageResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/GoogleImageResultEntry.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/GoogleSearchResultInformation.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/GoogleSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Google/OfficialGoogleSearchResultEntry.cs create mode 100644 src/EllieBot/Modules/Searches/Search/GoogleScrape/GoogleScrapeService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainGoogleScrapeSearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultEntry.cs create mode 100644 src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultInfo.cs create mode 100644 src/EllieBot/Modules/Searches/Search/IImageSearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/ISearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/ISearchResultEntry.cs create mode 100644 src/EllieBot/Modules/Searches/Search/ISearchResultInformation.cs create mode 100644 src/EllieBot/Modules/Searches/Search/ISearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/ISearchServiceFactory.cs create mode 100644 src/EllieBot/Modules/Searches/Search/SearchCommands.cs create mode 100644 src/EllieBot/Modules/Searches/Search/SearchServiceBase.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResultEntry.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxInfobox.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxSearchAttribute.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultEntry.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultInformation.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Searx/SearxUrlData.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/IYoutubeSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/InvidiousSearchResponse.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/InvidiousYtSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/VideoInfo.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/YoutubeDataApiSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/YtdlYoutubeSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/YtdlpYoutubeSearchService.cs create mode 100644 src/EllieBot/Modules/Searches/Search/Youtube/YtdlxServiceBase.cs create mode 100644 src/EllieBot/Modules/Searches/Searches.cs create mode 100644 src/EllieBot/Modules/Searches/SearchesService.cs create mode 100644 src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs create mode 100644 src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationService.cs create mode 100644 src/EllieBot/Modules/Searches/StreamNotification/StreamOnlineMessageDeleterService.cs create mode 100644 src/EllieBot/Modules/Searches/Translate/ITranslateService.cs create mode 100644 src/EllieBot/Modules/Searches/Translate/TranslateService.cs create mode 100644 src/EllieBot/Modules/Searches/Translate/TranslatorCommands.cs create mode 100644 src/EllieBot/Modules/Searches/XkcdCommands.cs create mode 100644 src/EllieBot/Modules/Searches/YoutubeTrack/YtTrackService.cs create mode 100644 src/EllieBot/Modules/Searches/YoutubeTrack/YtUploadCommands.cs create mode 100644 src/EllieBot/Modules/Searches/_common/AtlExtensions.cs create mode 100644 src/EllieBot/Modules/Searches/_common/BibleVerses.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Config/ImgSearchEngine.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Config/SearchesConfigService.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Config/WebSearchEngine.cs create mode 100644 src/EllieBot/Modules/Searches/_common/CryptoData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/DefineModel.cs create mode 100644 src/EllieBot/Modules/Searches/_common/E621Object.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Exceptions/StreamNotFoundException.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Extensions.cs create mode 100644 src/EllieBot/Modules/Searches/_common/Gallery.cs create mode 100644 src/EllieBot/Modules/Searches/_common/GatariUserResponse.cs create mode 100644 src/EllieBot/Modules/Searches/_common/GatariUserStatsResponse.cs create mode 100644 src/EllieBot/Modules/Searches/_common/GoogleSearchResult.cs create mode 100644 src/EllieBot/Modules/Searches/_common/HearthstoneCardData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/LowerCaseNamingPolicy.cs create mode 100644 src/EllieBot/Modules/Searches/_common/MagicItem.cs create mode 100644 src/EllieBot/Modules/Searches/_common/MtgData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/NovelData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/OmdbMovie.cs create mode 100644 src/EllieBot/Modules/Searches/_common/OsuMapData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/OsuUserBets.cs create mode 100644 src/EllieBot/Modules/Searches/_common/OsuUserData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/PathOfExileModels.cs create mode 100644 src/EllieBot/Modules/Searches/_common/SteamGameId.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/HelixStreamsResponse.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/HelixUsersResponse.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/PicartoChannelResponse.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/StreamData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/StreamDataKey.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/TrovoGetUsersResponse.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/TrovoRequestData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/TrovoSocialLink.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/TwitchResponseV5.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Models/TwitchUsersResponseV5.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/NotifChecker.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Providers/PicartoProvider.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Providers/Provider.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Providers/TrovoProvider.cs create mode 100644 src/EllieBot/Modules/Searches/_common/StreamNotifications/Providers/TwitchHelixProvider.cs create mode 100644 src/EllieBot/Modules/Searches/_common/TimeData.cs create mode 100644 src/EllieBot/Modules/Searches/_common/TimeModels.cs create mode 100644 src/EllieBot/Modules/Searches/_common/UrbanDef.cs create mode 100644 src/EllieBot/Modules/Searches/_common/WeatherModels.cs create mode 100644 src/EllieBot/Modules/Searches/_common/WikipediaApiModel.cs create mode 100644 src/EllieBot/Modules/Searches/_common/WoWJoke.cs diff --git a/src/EllieBot/Modules/Searches/Anime/AnimeResult.cs b/src/EllieBot/Modules/Searches/Anime/AnimeResult.cs new file mode 100644 index 0000000..c47eed7 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Anime/AnimeResult.cs @@ -0,0 +1,41 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches.Common; + +public class AnimeResult +{ + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("airing_status")] + public string AiringStatusParsed { get; set; } + + [JsonPropertyName("title_english")] + public string TitleEnglish { get; set; } + + [JsonPropertyName("total_episodes")] + public int TotalEpisodes { get; set; } + + [JsonPropertyName("description")] + public string Description { get; set; } + + [JsonPropertyName("image_url_lge")] + public string ImageUrlLarge { get; set; } + + [JsonPropertyName("genres")] + public string[] Genres { get; set; } + + [JsonPropertyName("average_score")] + public float AverageScore { get; set; } + + + public string AiringStatus + => AiringStatusParsed.ToTitleCase(); + + public string Link + => "http://anilist.co/anime/" + Id; + + public string Synopsis + => Description?[..(Description.Length > 500 ? 500 : Description.Length)] + "..."; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Anime/AnimeSearchCommands.cs b/src/EllieBot/Modules/Searches/Anime/AnimeSearchCommands.cs new file mode 100644 index 0000000..8acae72 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Anime/AnimeSearchCommands.cs @@ -0,0 +1,204 @@ +#nullable disable +using AngleSharp; +using AngleSharp.Html.Dom; +using EllieBot.Modules.Searches.Services; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class AnimeSearchCommands : EllieModule + { + // [EllieCommand, Aliases] + // public async Task Novel([Leftover] string query) + // { + // if (string.IsNullOrWhiteSpace(query)) + // return; + // + // var novelData = await _service.GetNovelData(query); + // + // if (novelData is null) + // { + // await Response().Error(strs.failed_finding_novel).SendAsync(); + // return; + // } + // + // var embed = _sender.CreateEmbed() + // .WithOkColor() + // .WithDescription(novelData.Description.Replace("
", Environment.NewLine, StringComparison.InvariantCulture)) + // .WithTitle(novelData.Title) + // .WithUrl(novelData.Link) + // .WithImageUrl(novelData.ImageUrl) + // .AddField(GetText(strs.authors), string.Join("\n", novelData.Authors), true) + // .AddField(GetText(strs.status), novelData.Status, true) + // .AddField(GetText(strs.genres), string.Join(" ", novelData.Genres.Any() ? novelData.Genres : new[] { "none" }), true) + // .WithFooter($"{GetText(strs.score)} {novelData.Score}"); + // + // await Response().Embed(embed).SendAsync(); + // } + + [Cmd] + [Priority(0)] + public async Task Mal([Leftover] string name) + { + if (string.IsNullOrWhiteSpace(name)) + return; + + var fullQueryLink = "https://myanimelist.net/profile/" + name; + + var config = Configuration.Default.WithDefaultLoader(); + using var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + var imageElem = + document.QuerySelector( + "body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-left > div.user-profile > div.user-image > img"); + var imageUrl = ((IHtmlImageElement)imageElem)?.Source + ?? "http://icecream.me/uploads/870b03f36b59cc16ebfe314ef2dde781.png"; + + var stats = document + .QuerySelectorAll( + "body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-right > div#statistics > div.user-statistics-stats > div.stats > div.clearfix > ul.stats-status > li > span") + .Select(x => x.InnerHtml) + .ToList(); + + var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc"); + + var favAnime = GetText(strs.anime_no_fav); + if (favorites.Length > 0 && favorites[0].QuerySelector("p") is null) + { + favAnime = string.Join("\n", + favorites[0] + .QuerySelectorAll("ul > li > div.di-tc.va-t > a") + .Shuffle() + .Take(3) + .Select(x => + { + var elem = (IHtmlAnchorElement)x; + return $"[{elem.InnerHtml}]({elem.Href})"; + })); + } + + var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li.clearfix") + .Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml)) + .ToList(); + + var daysAndMean = document.QuerySelectorAll("div.anime:nth-child(1) > div:nth-child(2) > div") + .Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray()) + .ToArray(); + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.mal_profile(name))) + .AddField("💚 " + GetText(strs.watching), stats[0], true) + .AddField("💙 " + GetText(strs.completed), stats[1], true); + if (info.Count < 3) + embed.AddField("💛 " + GetText(strs.on_hold), stats[2], true); + embed.AddField("💔 " + GetText(strs.dropped), stats[3], true) + .AddField("⚪ " + GetText(strs.plan_to_watch), stats[4], true) + .AddField("🕐 " + daysAndMean[0][0], daysAndMean[0][1], true) + .AddField("📊 " + daysAndMean[1][0], daysAndMean[1][1], true) + .AddField(MalInfoToEmoji(info[0].Item1) + " " + info[0].Item1, info[0].Item2.TrimTo(20), true) + .AddField(MalInfoToEmoji(info[1].Item1) + " " + info[1].Item1, info[1].Item2.TrimTo(20), true); + if (info.Count > 2) + embed.AddField(MalInfoToEmoji(info[2].Item1) + " " + info[2].Item1, info[2].Item2.TrimTo(20), true); + + embed.WithDescription($@" +** https://myanimelist.net/animelist/{name} ** + +**{GetText(strs.top_3_fav_anime)}** +{favAnime}") + .WithUrl(fullQueryLink) + .WithImageUrl(imageUrl); + + await Response().Embed(embed).SendAsync(); + } + + private static string MalInfoToEmoji(string info) + { + info = info.Trim().ToLowerInvariant(); + switch (info) + { + case "gender": + return "🚁"; + case "location": + return "🗺"; + case "last online": + return "👥"; + case "birthday": + return "📆"; + default: + return "❔"; + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [Priority(1)] + public Task Mal(IGuildUser usr) + => Mal(usr.Username); + + [Cmd] + public async Task Anime([Leftover] string query) + { + if (string.IsNullOrWhiteSpace(query)) + return; + + var animeData = await _service.GetAnimeData(query); + + if (animeData is null) + { + await Response().Error(strs.failed_finding_anime).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithDescription(animeData.Synopsis.Replace("
", + Environment.NewLine, + StringComparison.InvariantCulture)) + .WithTitle(animeData.TitleEnglish) + .WithUrl(animeData.Link) + .WithImageUrl(animeData.ImageUrlLarge) + .AddField(GetText(strs.episodes), animeData.TotalEpisodes.ToString(), true) + .AddField(GetText(strs.status), animeData.AiringStatus, true) + .AddField(GetText(strs.genres), + string.Join(",\n", animeData.Genres.Any() ? animeData.Genres : ["none"]), + true) + .WithFooter($"{GetText(strs.score)} {animeData.AverageScore} / 100"); + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Manga([Leftover] string query) + { + if (string.IsNullOrWhiteSpace(query)) + return; + + var mangaData = await _service.GetMangaData(query); + + if (mangaData is null) + { + await Response().Error(strs.failed_finding_manga).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithDescription(mangaData.Synopsis.Replace("
", + Environment.NewLine, + StringComparison.InvariantCulture)) + .WithTitle(mangaData.TitleEnglish) + .WithUrl(mangaData.Link) + .WithImageUrl(mangaData.ImageUrlLge) + .AddField(GetText(strs.chapters), mangaData.TotalChapters.ToString(), true) + .AddField(GetText(strs.status), mangaData.PublishingStatus, true) + .AddField(GetText(strs.genres), + string.Join(",\n", mangaData.Genres.Any() ? mangaData.Genres : ["none"]), + true) + .WithFooter($"{GetText(strs.score)} {mangaData.AverageScore} / 100"); + + await Response().Embed(embed).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Anime/AnimeSearchService.cs b/src/EllieBot/Modules/Searches/Anime/AnimeSearchService.cs new file mode 100644 index 0000000..4cf1b01 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Anime/AnimeSearchService.cs @@ -0,0 +1,79 @@ +#nullable disable +using EllieBot.Modules.Searches.Common; +using System.Net.Http.Json; + +namespace EllieBot.Modules.Searches.Services; + +public class AnimeSearchService : IEService +{ + private readonly IBotCache _cache; + private readonly IHttpClientFactory _httpFactory; + + public AnimeSearchService(IBotCache cache, IHttpClientFactory httpFactory) + { + _cache = cache; + _httpFactory = httpFactory; + } + + public async Task GetAnimeData(string query) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + + TypedKey GetKey(string link) + => new TypedKey($"anime2:{link}"); + + try + { + var suffix = Uri.EscapeDataString(query.Replace("/", " ", StringComparison.InvariantCulture)); + var link = $"https://aniapi.nadeko.bot/anime/{suffix}"; + link = link.ToLowerInvariant(); + var result = await _cache.GetAsync(GetKey(link)); + if (!result.TryPickT0(out var data, out _)) + { + using var http = _httpFactory.CreateClient(); + data = await http.GetFromJsonAsync(link); + + await _cache.AddAsync(GetKey(link), data, expiry: TimeSpan.FromHours(12)); + } + + return data; + } + catch + { + return null; + } + } + + public async Task GetMangaData(string query) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + + TypedKey GetKey(string link) + => new TypedKey($"manga2:{link}"); + + try + { + var link = "https://aniapi.nadeko.bot/manga/" + + Uri.EscapeDataString(query.Replace("/", " ", StringComparison.InvariantCulture)); + link = link.ToLowerInvariant(); + + var result = await _cache.GetAsync(GetKey(link)); + if (!result.TryPickT0(out var data, out _)) + { + using var http = _httpFactory.CreateClient(); + data = await http.GetFromJsonAsync(link); + + await _cache.AddAsync(GetKey(link), data, expiry: TimeSpan.FromHours(3)); + } + + + return data; + } + catch + { + return null; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Anime/MangaResult.cs b/src/EllieBot/Modules/Searches/Anime/MangaResult.cs new file mode 100644 index 0000000..9a32703 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Anime/MangaResult.cs @@ -0,0 +1,40 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches.Common; + +public class MangaResult +{ + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("publishing_status")] + public string PublishingStatus { get; set; } + + [JsonPropertyName("image_url_lge")] + public string ImageUrlLge { get; set; } + + [JsonPropertyName("title_english")] + public string TitleEnglish { get; set; } + + [JsonPropertyName("total_chapters")] + public int TotalChapters { get; set; } + + [JsonPropertyName("total_volumes")] + public int TotalVolumes { get; set; } + + [JsonPropertyName("description")] + public string Description { get; set; } + + [JsonPropertyName("genres")] + public string[] Genres { get; set; } + + [JsonPropertyName("average_score")] + public float AverageScore { get; set; } + + public string Link + => "http://anilist.co/manga/" + Id; + + public string Synopsis + => Description?[..(Description.Length > 500 ? 500 : Description.Length)] + "..."; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/CryptoCommands.cs b/src/EllieBot/Modules/Searches/Crypto/CryptoCommands.cs new file mode 100644 index 0000000..37353b1 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/CryptoCommands.cs @@ -0,0 +1,196 @@ +#nullable disable +using EllieBot.Modules.Searches.Services; +using System.Globalization; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + public partial class FinanceCommands : EllieModule + { + private readonly IStockDataService _stocksService; + private readonly IStockChartDrawingService _stockDrawingService; + + public FinanceCommands(IStockDataService stocksService, IStockChartDrawingService stockDrawingService) + { + _stocksService = stocksService; + _stockDrawingService = stockDrawingService; + } + + [Cmd] + public async Task Stock([Leftover]string query) + { + using var typing = ctx.Channel.EnterTypingState(); + + var stock = await _stocksService.GetStockDataAsync(query); + + if (stock is null) + { + var symbols = await _stocksService.SearchSymbolAsync(query); + + if (symbols.Count == 0) + { + await Response().Error(strs.not_found).SendAsync(); + return; + } + + var symbol = symbols.First(); + var promptEmbed = _sender.CreateEmbed() + .WithDescription(symbol.Description) + .WithTitle(GetText(strs.did_you_mean(symbol.Symbol))); + + if (!await PromptUserConfirmAsync(promptEmbed)) + return; + + query = symbol.Symbol; + stock = await _stocksService.GetStockDataAsync(query); + + if (stock is null) + { + await Response().Error(strs.not_found).SendAsync(); + return; + } + } + + var candles = await _stocksService.GetCandleDataAsync(query); + var stockImageTask = _stockDrawingService.GenerateCombinedChartAsync(candles); + + var localCulture = (CultureInfo)Culture.Clone(); + localCulture.NumberFormat.CurrencySymbol = "$"; + + var sign = stock.Price >= stock.Close + ? "\\🔼" + : "\\🔻"; + + var change = (stock.Price - stock.Close).ToString("N2", Culture); + var changePercent = (1 - (stock.Close / stock.Price)).ToString("P1", Culture); + + var sign50 = stock.Change50d >= 0 + ? "\\🔼" + : "\\🔻"; + + var change50 = (stock.Change50d).ToString("P1", Culture); + + var sign200 = stock.Change200d >= 0 + ? "\\🔼" + : "\\🔻"; + + var change200 = (stock.Change200d).ToString("P1", Culture); + + var price = stock.Price.ToString("C2", localCulture); + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(stock.Symbol) + .WithUrl($"https://www.tradingview.com/chart/?symbol={stock.Symbol}") + .WithTitle(stock.Name) + .AddField(GetText(strs.price), $"{sign} **{price}**", true) + .AddField(GetText(strs.market_cap), stock.MarketCap, true) + .AddField(GetText(strs.volume_24h), stock.DailyVolume.ToString("C0", localCulture), true) + .AddField("Change", $"{change} ({changePercent})", true) + // .AddField("Change 50d", $"{sign50}{change50}", true) + // .AddField("Change 200d", $"{sign200}{change200}", true) + .WithFooter(stock.Exchange); + + var message = await Response().Embed(eb).SendAsync(); + await using var imageData = await stockImageTask; + if (imageData is null) + return; + + var fileName = $"{query}-sparkline.{imageData.Extension}"; + using var attachment = new FileAttachment( + imageData.FileData, + fileName + ); + await message.ModifyAsync(mp => + { + mp.Attachments = + new(new[] + { + attachment + }); + + mp.Embed = eb.WithImageUrl($"attachment://{fileName}").Build(); + }); + } + + + [Cmd] + public async Task Crypto(string name) + { + name = name?.ToUpperInvariant(); + + if (string.IsNullOrWhiteSpace(name)) + return; + + var (crypto, nearest) = await _service.GetCryptoData(name); + + if (nearest is not null) + { + var embed = _sender.CreateEmbed() + .WithTitle(GetText(strs.crypto_not_found)) + .WithDescription( + GetText(strs.did_you_mean(Format.Bold($"{nearest.Name} ({nearest.Symbol})")))); + + if (await PromptUserConfirmAsync(embed)) + crypto = nearest; + } + + if (crypto is null) + { + await Response().Error(strs.crypto_not_found).SendAsync(); + return; + } + + var usd = crypto.Quote["USD"]; + + var localCulture = (CultureInfo)Culture.Clone(); + localCulture.NumberFormat.CurrencySymbol = "$"; + + var sevenDay = (usd.PercentChange7d / 100).ToString("P2", localCulture); + var lastDay = (usd.PercentChange24h / 100).ToString("P2", localCulture); + var price = usd.Price < 0.01 + ? usd.Price.ToString(localCulture) + : usd.Price.ToString("C2", localCulture); + + var volume = usd.Volume24h.ToString("C0", localCulture); + var marketCap = usd.MarketCap.ToString("C0", localCulture); + var dominance = (usd.MarketCapDominance / 100).ToString("P2", localCulture); + + await using var sparkline = await _service.GetSparklineAsync(crypto.Id, usd.PercentChange7d >= 0); + var fileName = $"{crypto.Slug}_7d.png"; + + var toSend = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor($"#{crypto.CmcRank}") + .WithTitle($"{crypto.Name} ({crypto.Symbol})") + .WithUrl($"https://coinmarketcap.com/currencies/{crypto.Slug}/") + .WithThumbnailUrl($"https://s3.coinmarketcap.com/static/img/coins/128x128/{crypto.Id}.png") + .AddField(GetText(strs.market_cap), marketCap, true) + .AddField(GetText(strs.price), price, true) + .AddField(GetText(strs.volume_24h), volume, true) + .AddField(GetText(strs.change_7d_24h), $"{sevenDay} / {lastDay}", true) + .AddField(GetText(strs.market_cap_dominance), dominance, true) + .WithImageUrl($"attachment://{fileName}"); + + if (crypto.CirculatingSupply is double cs) + { + var csStr = cs.ToString("N0", localCulture); + + if (crypto.MaxSupply is double ms) + { + var perc = (cs / ms).ToString("P1", localCulture); + + toSend.AddField(GetText(strs.circulating_supply), $"{csStr} ({perc})", true); + } + else + { + toSend.AddField(GetText(strs.circulating_supply), csStr, true); + } + } + + + await ctx.Channel.SendFileAsync(sparkline, fileName, embed: toSend.Build()); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs b/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs new file mode 100644 index 0000000..146dac3 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs @@ -0,0 +1,215 @@ +#nullable enable +using EllieBot.Modules.Searches.Common; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System.Globalization; +using System.Net.Http.Json; +using System.Xml; +using Color = SixLabors.ImageSharp.Color; +using StringExtensions = EllieBot.Extensions.StringExtensions; + +namespace EllieBot.Modules.Searches.Services; + +public class CryptoService : IEService +{ + private readonly IBotCache _cache; + private readonly IHttpClientFactory _httpFactory; + private readonly IBotCredentials _creds; + + private readonly SemaphoreSlim _getCryptoLock = new(1, 1); + + public CryptoService(IBotCache cache, IHttpClientFactory httpFactory, IBotCredentials creds) + { + _cache = cache; + _httpFactory = httpFactory; + _creds = creds; + } + + private PointF[] GetSparklinePointsFromSvgText(string svgText) + { + var xml = new XmlDocument(); + xml.LoadXml(svgText); + + var gElement = xml["svg"]?["g"]; + if (gElement is null) + return Array.Empty(); + + Span points = new PointF[gElement.ChildNodes.Count]; + var cnt = 0; + + bool GetValuesFromAttributes( + XmlAttributeCollection attrs, + out float x1, + out float y1, + out float x2, + out float y2) + { + (x1, y1, x2, y2) = (0, 0, 0, 0); + return attrs["x1"]?.Value is string x1Str + && float.TryParse(x1Str, NumberStyles.Any, CultureInfo.InvariantCulture, out x1) + && attrs["y1"]?.Value is string y1Str + && float.TryParse(y1Str, NumberStyles.Any, CultureInfo.InvariantCulture, out y1) + && attrs["x2"]?.Value is string x2Str + && float.TryParse(x2Str, NumberStyles.Any, CultureInfo.InvariantCulture, out x2) + && attrs["y2"]?.Value is string y2Str + && float.TryParse(y2Str, NumberStyles.Any, CultureInfo.InvariantCulture, out y2); + } + + foreach (XmlElement x in gElement.ChildNodes) + { + if (x.Name != "line") + continue; + + if (GetValuesFromAttributes(x.Attributes, out var x1, out var y1, out var x2, out var y2)) + { + points[cnt++] = new(x1, y1); + // this point will be set twice to the same value + // on all points except the last one + if (cnt + 1 < points.Length) + points[cnt + 1] = new(x2, y2); + } + } + + if (cnt == 0) + return Array.Empty(); + + return points.Slice(0, cnt).ToArray(); + } + + private SixLabors.ImageSharp.Image GenerateSparklineChart(PointF[] points, bool up) + { + const int width = 164; + const int height = 48; + + var img = new Image(width, height, Color.Transparent); + var color = up + ? Color.Green + : Color.FromRgb(220, 0, 0); + + img.Mutate(x => + { + x.DrawLines(color, 2, points); + }); + + return img; + } + + public async Task<(CmcResponseData? Data, CmcResponseData? Nearest)> GetCryptoData(string name) + { + if (string.IsNullOrWhiteSpace(name)) + return (null, null); + + name = name.ToUpperInvariant(); + var cryptos = await GetCryptoDataInternal(); + + if (cryptos is null or { Count: 0 }) + return (null, null); + + var crypto = cryptos.FirstOrDefault(x + => x.Slug.ToUpperInvariant() == name + || x.Name.ToUpperInvariant() == name + || x.Symbol.ToUpperInvariant() == name); + + if (crypto is not null) + return (crypto, null); + + + var nearest = cryptos + .Select(elem => (Elem: elem, + Distance: elem.Name.ToUpperInvariant().LevenshteinDistance(name))) + .OrderBy(x => x.Distance) + .FirstOrDefault(x => x.Distance <= 2); + + return (null, nearest.Elem); + } + + public async Task?> GetCryptoDataInternal() + { + await _getCryptoLock.WaitAsync(); + try + { + var data = await _cache.GetOrAddAsync(new("ellie:crypto_data"), + async () => + { + try + { + using var http = _httpFactory.CreateClient(); + var data = await http.GetFromJsonAsync( + "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?" + + $"CMC_PRO_API_KEY={_creds.CoinmarketcapApiKey}" + + "&start=1" + + "&limit=5000" + + "&convert=USD"); + + return data; + } + catch (Exception ex) + { + Log.Error(ex, "Error getting crypto data: {Message}", ex.Message); + return default; + } + }, + TimeSpan.FromHours(2)); + + if (data is null) + return default; + + return data.Data; + } + catch (Exception ex) + { + Log.Error(ex, "Error retreiving crypto data: {Message}", ex.Message); + return default; + } + finally + { + _getCryptoLock.Release(); + } + } + + private TypedKey GetSparklineKey(int id) + => new($"crypto:sparkline:{id}"); + + public async Task GetSparklineAsync(int id, bool up) + { + try + { + var bytes = await _cache.GetOrAddAsync(GetSparklineKey(id), + async () => + { + // if it fails, generate a new one + var points = await DownloadSparklinePointsAsync(id); + var sparkline = GenerateSparklineChart(points, up); + + using var stream = await sparkline.ToStreamAsync(); + return stream.ToArray(); + }, + TimeSpan.FromHours(1)); + + if (bytes is { Length: > 0 }) + { + return bytes.ToStream(); + } + + return default; + } + catch (Exception ex) + { + Log.Warning(ex, + "Exception occurred while downloading sparkline points: {ErrorMessage}", + ex.Message); + return default; + } + } + + private async Task DownloadSparklinePointsAsync(int id) + { + using var http = _httpFactory.CreateClient(); + var str = await http.GetStringAsync( + $"https://s3.coinmarketcap.com/generated/sparklines/web/7d/usd/{id}.svg"); + var points = GetSparklinePointsFromSvgText(str); + return points; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs b/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs new file mode 100644 index 0000000..5b5bf40 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs @@ -0,0 +1,126 @@ +using AngleSharp; +using CsvHelper; +using CsvHelper.Configuration; +using System.Globalization; +using System.Text.Json; + +namespace EllieBot.Modules.Searches; + +public sealed class DefaultStockDataService : IStockDataService, IEService +{ + private readonly IHttpClientFactory _httpClientFactory; + + public DefaultStockDataService(IHttpClientFactory httpClientFactory) + => _httpClientFactory = httpClientFactory; + + public async Task GetStockDataAsync(string query) + { + try + { + if (!query.IsAlphaNumeric()) + return default; + + using var http = _httpClientFactory.CreateClient(); + + + + var quoteHtmlPage = $"https://finance.yahoo.com/quote/{query.ToUpperInvariant()}"; + + var config = Configuration.Default.WithDefaultLoader(); + using var document = await BrowsingContext.New(config).OpenAsync(quoteHtmlPage); + var divElem = + document.QuerySelector( + "#quote-header-info > div:nth-child(2) > div > div > h1"); + var tickerName = (divElem)?.TextContent; + + var marketcap = document + .QuerySelectorAll("table") + .Skip(1) + .First() + .QuerySelector("tbody > tr > td:nth-child(2)") + ?.TextContent; + + + var volume = document.QuerySelector("td[data-test='AVERAGE_VOLUME_3MONTH-value']") + ?.TextContent; + + var close= document.QuerySelector("td[data-test='PREV_CLOSE-value']") + ?.TextContent ?? "0"; + + var price = document + .QuerySelector("#quote-header-info") + ?.QuerySelector("fin-streamer[data-field='regularMarketPrice']") + ?.TextContent ?? close; + + // var data = await http.GetFromJsonAsync( + // $"https://query1.finance.yahoo.com/v7/finance/quote?symbols={query}"); + // + // if (data is null) + // return default; + + // var symbol = data.QuoteResponse.Result.FirstOrDefault(); + + // if (symbol is null) + // return default; + + return new() + { + Name = tickerName, + Symbol = query, + Price = double.Parse(price, NumberStyles.Any, CultureInfo.InvariantCulture), + Close = double.Parse(close, NumberStyles.Any, CultureInfo.InvariantCulture), + MarketCap = marketcap, + DailyVolume = (long)double.Parse(volume ?? "0", NumberStyles.Any, CultureInfo.InvariantCulture), + }; + } + catch (Exception ex) + { + Log.Warning(ex, "Error getting stock data: {ErrorMessage}", ex.ToString()); + return default; + } + } + + public async Task> SearchSymbolAsync(string query) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + + query = Uri.EscapeDataString(query); + + using var http = _httpClientFactory.CreateClient(); + + var res = await http.GetStringAsync( + "https://finance.yahoo.com/_finance_doubledown/api/resource/searchassist" + + $";searchTerm={query}" + + "?device=console"); + + var data = JsonSerializer.Deserialize(res); + + if (data is null or { Items: null }) + return Array.Empty(); + + return data.Items + .Where(x => x.Type == "S") + .Select(x => new SymbolData(x.Symbol, x.Name)) + .ToList(); + } + + private static CsvConfiguration _csvConfig = new(CultureInfo.InvariantCulture); + + public async Task> GetCandleDataAsync(string query) + { + using var http = _httpClientFactory.CreateClient(); + await using var resStream = await http.GetStreamAsync( + $"https://query1.finance.yahoo.com/v7/finance/download/{query}" + + $"?period1={DateTime.UtcNow.Subtract(30.Days()).ToTimestamp()}" + + $"&period2={DateTime.UtcNow.ToTimestamp()}" + + "&interval=1d"); + + using var textReader = new StreamReader(resStream); + using var csv = new CsvReader(textReader, _csvConfig); + var records = csv.GetRecords().ToArray(); + + return records + .Map(static x => new CandleData(x.Open, x.Close, x.High, x.Low, x.Volume)); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/Drawing/CandleDrawingData.cs b/src/EllieBot/Modules/Searches/Crypto/Drawing/CandleDrawingData.cs new file mode 100644 index 0000000..97da2da --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/Drawing/CandleDrawingData.cs @@ -0,0 +1,12 @@ +using SixLabors.ImageSharp; + +namespace EllieBot.Modules.Searches; + +/// +/// All data required to draw a candle +/// +/// Whether the candle is green +/// Rectangle for the body +/// High line point +/// Low line point +public record CandleDrawingData(bool IsGreen, RectangleF BodyRect, PointF High, PointF Low); \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/Drawing/IStockChartDrawingService.cs b/src/EllieBot/Modules/Searches/Crypto/Drawing/IStockChartDrawingService.cs new file mode 100644 index 0000000..9676e88 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/Drawing/IStockChartDrawingService.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Searches; + +public interface IStockChartDrawingService +{ + Task GenerateSparklineAsync(IReadOnlyCollection series); + Task GenerateCombinedChartAsync(IReadOnlyCollection series); + Task GenerateCandleChartAsync(IReadOnlyCollection series); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/Drawing/ImagesharpStockChartDrawingService.cs b/src/EllieBot/Modules/Searches/Crypto/Drawing/ImagesharpStockChartDrawingService.cs new file mode 100644 index 0000000..731fc78 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/Drawing/ImagesharpStockChartDrawingService.cs @@ -0,0 +1,200 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System.Runtime.CompilerServices; +using Color = SixLabors.ImageSharp.Color; + +namespace EllieBot.Modules.Searches; + +public sealed class ImagesharpStockChartDrawingService : IStockChartDrawingService, IEService +{ + private const int WIDTH = 300; + private const int HEIGHT = 100; + private const decimal MAX_HEIGHT = HEIGHT * 0.8m; + + private static readonly Rgba32 _backgroundColor = Rgba32.ParseHex("17181E"); + private static readonly Rgba32 _lineGuideColor = Rgba32.ParseHex("212125"); + private static readonly Rgba32 _sparklineColor = Rgba32.ParseHex("2961FC"); + private static readonly Rgba32 _greenBrush = Rgba32.ParseHex("26A69A"); + private static readonly Rgba32 _redBrush = Rgba32.ParseHex("EF5350"); + + private static float GetNormalizedPoint(decimal max, decimal point, decimal range) + => (float)((MAX_HEIGHT * ((max - point) / range)) + HeightOffset()); + + private PointF[] GetSparklinePointsInternal(IReadOnlyCollection series) + { + var candleStep = WIDTH / (series.Count + 1); + var max = series.Max(static x => x.High); + var min = series.Min(static x => x.Low); + + var range = max - min; + + var points = new PointF[series.Count]; + + var i = 0; + foreach (var candle in series) + { + var x = candleStep * (i + 1); + + var y = GetNormalizedPoint(max, candle.Close, range); + points[i++] = new(x, y); + } + + return points; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static decimal HeightOffset() + => (HEIGHT - MAX_HEIGHT) / 2m; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Image CreateCanvasInternal() + => new Image(WIDTH, HEIGHT, _backgroundColor); + + private CandleDrawingData[] GetChartDrawingDataInternal(IReadOnlyCollection series) + { + var candleMargin = 2; + var candleStep = (WIDTH - (candleMargin * series.Count)) / (series.Count + 1); + var max = series.Max(static x => x.High); + var min = series.Min(static x => x.Low); + + var range = max - min; + + var drawData = new CandleDrawingData[series.Count]; + + var candleWidth = candleStep; + + var i = 0; + foreach (var candle in series) + { + var offsetX = (i - 1) * candleMargin; + var x = (candleStep * (i + 1)) + offsetX; + var yOpen = GetNormalizedPoint(max, candle.Open, range); + var yClose = GetNormalizedPoint(max, candle.Close, range); + var y = candle.Open > candle.Close + ? yOpen + : yClose; + + var sizeH = Math.Abs(yOpen - yClose); + + var high = GetNormalizedPoint(max, candle.High, range); + var low = GetNormalizedPoint(max, candle.Low, range); + drawData[i] = new(candle.Open < candle.Close, + new(x, y, candleWidth, sizeH), + new(x + (candleStep / 2), high), + new(x + (candleStep / 2), low)); + ++i; + } + + return drawData; + } + + private void DrawChartData(Image image, CandleDrawingData[] drawData) + => image.Mutate(ctx => + { + foreach (var data in drawData) + ctx.DrawLines(data.IsGreen + ? _greenBrush + : _redBrush, + 1, + data.High, + data.Low); + + + foreach (var data in drawData) + ctx.Fill(data.IsGreen + ? _greenBrush + : _redBrush, + data.BodyRect); + }); + + private void DrawLineGuides(Image image, IReadOnlyCollection series) + { + var max = series.Max(x => x.High); + var min = series.Min(x => x.Low); + + var step = (max - min) / 5; + + var lines = new float[6]; + + for (var i = 0; i < 6; i++) + { + var y = GetNormalizedPoint(max, min + (step * i), max - min); + lines[i] = y; + } + + image.Mutate(ctx => + { + // draw guides + foreach (var y in lines) + ctx.DrawLines(_lineGuideColor, 1, new PointF(0, y), new PointF(WIDTH, y)); + + // // draw min and max price on the chart + // ctx.DrawText(min.ToString(CultureInfo.InvariantCulture), + // SystemFonts.CreateFont("Arial", 5), + // Color.White, + // new PointF(0, (float)HeightOffset() - 5) + // ); + // + // ctx.DrawText(max.ToString("N1", CultureInfo.InvariantCulture), + // SystemFonts.CreateFont("Arial", 5), + // Color.White, + // new PointF(0, HEIGHT - (float)HeightOffset()) + // ); + }); + } + + public Task GenerateSparklineAsync(IReadOnlyCollection series) + { + if (series.Count == 0) + return Task.FromResult(default); + + using var image = CreateCanvasInternal(); + + var points = GetSparklinePointsInternal(series); + + image.Mutate(ctx => + { + ctx.DrawLines(_sparklineColor, 2, points); + }); + + return Task.FromResult(new("png", image.ToStream())); + } + + public Task GenerateCombinedChartAsync(IReadOnlyCollection series) + { + if (series.Count == 0) + return Task.FromResult(default); + + using var image = CreateCanvasInternal(); + + DrawLineGuides(image, series); + + var chartData = GetChartDrawingDataInternal(series); + DrawChartData(image, chartData); + + var points = GetSparklinePointsInternal(series); + image.Mutate(ctx => + { + ctx.DrawLines(Color.ParseHex("00FFFFAA"), 1, points); + }); + + return Task.FromResult(new("png", image.ToStream())); + } + + public Task GenerateCandleChartAsync(IReadOnlyCollection series) + { + if (series.Count == 0) + return Task.FromResult(default); + + using var image = CreateCanvasInternal(); + + DrawLineGuides(image, series); + + var drawData = GetChartDrawingDataInternal(series); + DrawChartData(image, drawData); + + return Task.FromResult(new("png", image.ToStream())); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/IStockDataService.cs b/src/EllieBot/Modules/Searches/Crypto/IStockDataService.cs new file mode 100644 index 0000000..5f778e8 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/IStockDataService.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Searches; + +public interface IStockDataService +{ + public Task GetStockDataAsync(string symbol); + Task> SearchSymbolAsync(string query); + Task> GetCandleDataAsync(string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/CandleData.cs b/src/EllieBot/Modules/Searches/Crypto/_common/CandleData.cs new file mode 100644 index 0000000..97d1a17 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/CandleData.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Searches; + +public record CandleData( + decimal Open, + decimal Close, + decimal High, + decimal Low, + long Volume); \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/ImageData.cs b/src/EllieBot/Modules/Searches/Crypto/_common/ImageData.cs new file mode 100644 index 0000000..d49d1ba --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/ImageData.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches; + +public record ImageData(string Extension, Stream FileData) : IAsyncDisposable +{ + public ValueTask DisposeAsync() + => FileData.DisposeAsync(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/QuoteResponse.cs b/src/EllieBot/Modules/Searches/Crypto/_common/QuoteResponse.cs new file mode 100644 index 0000000..13ea277 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/QuoteResponse.cs @@ -0,0 +1,43 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public class QuoteResponse +{ + public class ResultModel + { + [JsonPropertyName("longName")] + public string LongName { get; set; } + + [JsonPropertyName("regularMarketPrice")] + public double RegularMarketPrice { get; set; } + + [JsonPropertyName("regularMarketPreviousClose")] + public double RegularMarketPreviousClose { get; set; } + + [JsonPropertyName("fullExchangeName")] + public string FullExchangeName { get; set; } + + [JsonPropertyName("averageDailyVolume10Day")] + public int AverageDailyVolume10Day { get; set; } + + [JsonPropertyName("fiftyDayAverageChangePercent")] + public double FiftyDayAverageChangePercent { get; set; } + + [JsonPropertyName("twoHundredDayAverageChangePercent")] + public double TwoHundredDayAverageChangePercent { get; set; } + + [JsonPropertyName("marketCap")] + public long MarketCap { get; set; } + + [JsonPropertyName("symbol")] + public string Symbol { get; set; } + } + + [JsonPropertyName("result")] + public List Result { get; set; } + + [JsonPropertyName("error")] + public object Error { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/StockData.cs b/src/EllieBot/Modules/Searches/Crypto/_common/StockData.cs new file mode 100644 index 0000000..dfb99c7 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/StockData.cs @@ -0,0 +1,15 @@ +#nullable disable +namespace EllieBot.Modules.Searches; + +public class StockData +{ + public string Name { get; set; } + public string Symbol { get; set; } + public double Price { get; set; } + public string MarketCap { get; set; } + public double Close { get; set; } + public double Change50d { get; set; } + public double Change200d { get; set; } + public long DailyVolume { get; set; } + public string Exchange { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/SymbolData.cs b/src/EllieBot/Modules/Searches/Crypto/_common/SymbolData.cs new file mode 100644 index 0000000..01ef65d --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/SymbolData.cs @@ -0,0 +1,3 @@ +namespace EllieBot.Modules.Searches; + +public record SymbolData(string Symbol, string Description); \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceCandleData.cs b/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceCandleData.cs new file mode 100644 index 0000000..619bdc3 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceCandleData.cs @@ -0,0 +1,12 @@ +namespace EllieBot.Modules.Searches; + +public class YahooFinanceCandleData +{ + public DateTime Date { get; set; } + public decimal Open { get; set; } + public decimal High { get; set; } + public decimal Low { get; set; } + public decimal Close { get; set; } + public decimal AdjClose { get; set; } + public long Volume { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponse.cs b/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponse.cs new file mode 100644 index 0000000..168dd82 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponse.cs @@ -0,0 +1,19 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public class YahooFinanceSearchResponse +{ + [JsonPropertyName("suggestionTitleAccessor")] + public string SuggestionTitleAccessor { get; set; } + + [JsonPropertyName("suggestionMeta")] + public List SuggestionMeta { get; set; } + + [JsonPropertyName("hiConf")] + public bool HiConf { get; set; } + + [JsonPropertyName("items")] + public List Items { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponseItem.cs b/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponseItem.cs new file mode 100644 index 0000000..e8eaa9f --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/YahooFinanceSearchResponseItem.cs @@ -0,0 +1,25 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public class YahooFinanceSearchResponseItem +{ + [JsonPropertyName("symbol")] + public string Symbol { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("exch")] + public string Exch { get; set; } + + [JsonPropertyName("type")] + public string Type { get; set; } + + [JsonPropertyName("exchDisp")] + public string ExchDisp { get; set; } + + [JsonPropertyName("typeDisp")] + public string TypeDisp { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Crypto/_common/YahooQueryModel.cs b/src/EllieBot/Modules/Searches/Crypto/_common/YahooQueryModel.cs new file mode 100644 index 0000000..4efc94f --- /dev/null +++ b/src/EllieBot/Modules/Searches/Crypto/_common/YahooQueryModel.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public class YahooQueryModel +{ + [JsonPropertyName("quoteResponse")] + public QuoteResponse QuoteResponse { get; set; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs b/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs new file mode 100644 index 0000000..37376f0 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs @@ -0,0 +1,146 @@ +#nullable disable +using CodeHollow.FeedReader; +using EllieBot.Modules.Searches.Services; +using System.Text.RegularExpressions; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class FeedCommands : EllieModule + { + private static readonly Regex _ytChannelRegex = + new(@"youtube\.com\/(?:c\/|channel\/|user\/)?(?[a-zA-Z0-9\-_]{1,})"); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [Priority(1)] + public Task YtUploadNotif(string url, [Leftover] string message = null) + => YtUploadNotif(url, null, message); + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [Priority(2)] + public Task YtUploadNotif(string url, ITextChannel channel = null, [Leftover] string message = null) + { + var m = _ytChannelRegex.Match(url); + if (!m.Success) + return Response().Error(strs.invalid_input).SendAsync(); + + if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone) + message = message?.SanitizeAllMentions(); + + var channelId = m.Groups["channelid"].Value; + + return Feed($"https://www.youtube.com/feeds/videos.xml?channel_id={channelId}", channel, message); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [Priority(0)] + public Task Feed(string url, [Leftover] string message = null) + => Feed(url, null, message); + + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [Priority(1)] + public async Task Feed(string url, ITextChannel channel = null, [Leftover] string message = null) + { + if (!Uri.TryCreate(url, UriKind.Absolute, out var uri) + || (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)) + { + await Response().Error(strs.feed_invalid_url).SendAsync(); + return; + } + + if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone) + message = message?.SanitizeAllMentions(); + + channel ??= (ITextChannel)ctx.Channel; + try + { + await FeedReader.ReadAsync(url); + } + catch (Exception ex) + { + Log.Information(ex, "Unable to get feeds from that url"); + await Response().Error(strs.feed_cant_parse).SendAsync(); + return; + } + + if (ctx.User is not IGuildUser gu || !gu.GuildPermissions.Administrator) + message = message?.SanitizeMentions(true); + + var result = _service.AddFeed(ctx.Guild.Id, channel.Id, url, message); + if (result == FeedAddResult.Success) + { + await Response().Confirm(strs.feed_added).SendAsync(); + return; + } + + if (result == FeedAddResult.Duplicate) + { + await Response().Error(strs.feed_duplicate).SendAsync(); + return; + } + + if (result == FeedAddResult.LimitReached) + { + await Response().Error(strs.feed_limit_reached).SendAsync(); + return; + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task FeedRemove(int index) + { + if (_service.RemoveFeed(ctx.Guild.Id, --index)) + await Response().Confirm(strs.feed_removed).SendAsync(); + else + await Response().Error(strs.feed_out_of_range).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task FeedList(int page = 1) + { + if (--page < 0) + return; + + var feeds = _service.GetFeeds(ctx.Guild.Id); + + if (!feeds.Any()) + { + await Response() + .Embed(_sender.CreateEmbed().WithOkColor().WithDescription(GetText(strs.feed_no_feed))) + .SendAsync(); + return; + } + + await Response() + .Paginated() + .Items(feeds) + .PageSize(10) + .CurrentPage(page) + .Page((items, cur) => + { + var embed = _sender.CreateEmbed().WithOkColor(); + var i = 0; + var fs = string.Join("\n", + items.Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}")); + + return embed.WithDescription(fs); + }) + .SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs b/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs new file mode 100644 index 0000000..d19195c --- /dev/null +++ b/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs @@ -0,0 +1,294 @@ +#nullable disable +using CodeHollow.FeedReader; +using CodeHollow.FeedReader.Feeds; +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Searches.Services; + +public class FeedsService : IEService +{ + private readonly DbService _db; + private readonly ConcurrentDictionary> _subs; + private readonly DiscordSocketClient _client; + private readonly IMessageSenderService _sender; + + private readonly ConcurrentDictionary _lastPosts = new(); + private readonly Dictionary _errorCounters = new(); + + public FeedsService( + IBot bot, + DbService db, + DiscordSocketClient client, + IMessageSenderService sender) + { + _db = db; + + using (var uow = db.GetDbContext()) + { + var guildConfigIds = bot.AllGuildConfigs.Select(x => x.Id).ToList(); + _subs = uow.Set() + .AsQueryable() + .Where(x => guildConfigIds.Contains(x.Id)) + .Include(x => x.FeedSubs) + .ToList() + .SelectMany(x => x.FeedSubs) + .GroupBy(x => x.Url.ToLower()) + .ToDictionary(x => x.Key, x => x.ToList()) + .ToConcurrent(); + } + + _client = client; + _sender = sender; + + _ = Task.Run(TrackFeeds); + } + + private void ClearErrors(string url) + => _errorCounters.Remove(url); + + private async Task AddError(string url, List ids) + { + try + { + var newValue = _errorCounters[url] = _errorCounters.GetValueOrDefault(url) + 1; + + if (newValue >= 100) + { + // remove from db + await using var ctx = _db.GetDbContext(); + await ctx.GetTable() + .DeleteAsync(x => ids.Contains(x.Id)); + + // remove from the local cache + _subs.TryRemove(url, out _); + + // reset the error counter + ClearErrors(url); + } + + return newValue; + } + catch (Exception ex) + { + Log.Error(ex, "Error adding rss errors..."); + return 0; + } + } + + public async Task TrackFeeds() + { + while (true) + { + var allSendTasks = new List(_subs.Count); + foreach (var kvp in _subs) + { + if (kvp.Value.Count == 0) + continue; + + var rssUrl = kvp.Value.First().Url; + try + { + var feed = await FeedReader.ReadAsync(rssUrl); + + var items = feed + .Items.Select(item => (Item: item, + LastUpdate: item.PublishingDate?.ToUniversalTime() + ?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime())) + .Where(data => data.LastUpdate is not null) + .Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate)) + .OrderByDescending(data => data.LastUpdate) + .Reverse() // start from the oldest + .ToList(); + + if (!_lastPosts.TryGetValue(kvp.Key, out var lastFeedUpdate)) + { + lastFeedUpdate = _lastPosts[kvp.Key] = + items.Any() ? items[items.Count - 1].LastUpdate : DateTime.UtcNow; + } + + foreach (var (feedItem, itemUpdateDate) in items) + { + if (itemUpdateDate <= lastFeedUpdate) + continue; + + var embed = _sender.CreateEmbed().WithFooter(rssUrl); + + _lastPosts[kvp.Key] = itemUpdateDate; + + var link = feedItem.SpecificItem.Link; + if (!string.IsNullOrWhiteSpace(link) && Uri.IsWellFormedUriString(link, UriKind.Absolute)) + embed.WithUrl(link); + + var title = string.IsNullOrWhiteSpace(feedItem.Title) ? "-" : feedItem.Title; + + var gotImage = false; + if (feedItem.SpecificItem is MediaRssFeedItem mrfi + && (mrfi.Enclosure?.MediaType?.StartsWith("image/") ?? false)) + { + var imgUrl = mrfi.Enclosure.Url; + if (!string.IsNullOrWhiteSpace(imgUrl) + && Uri.IsWellFormedUriString(imgUrl, UriKind.Absolute)) + { + embed.WithImageUrl(imgUrl); + gotImage = true; + } + } + + if (!gotImage && feedItem.SpecificItem is AtomFeedItem afi) + { + var previewElement = afi.Element.Elements() + .FirstOrDefault(x => x.Name.LocalName == "preview"); + + if (previewElement is null) + { + previewElement = afi.Element.Elements() + .FirstOrDefault(x => x.Name.LocalName == "thumbnail"); + } + + if (previewElement is not null) + { + var urlAttribute = previewElement.Attribute("url"); + if (urlAttribute is not null + && !string.IsNullOrWhiteSpace(urlAttribute.Value) + && Uri.IsWellFormedUriString(urlAttribute.Value, UriKind.Absolute)) + { + embed.WithImageUrl(urlAttribute.Value); + gotImage = true; + } + } + } + + embed.WithTitle(title.TrimTo(256)); + + var desc = feedItem.Description?.StripHtml(); + if (!string.IsNullOrWhiteSpace(feedItem.Description)) + embed.WithDescription(desc.TrimTo(2048)); + + //send the created embed to all subscribed channels + var feedSendTasks = kvp.Value + .Where(x => x.GuildConfig is not null) + .Select(x => + { + var ch = _client.GetGuild(x.GuildConfig.GuildId) + ?.GetTextChannel(x.ChannelId); + + if (ch is null) + return null; + + return _sender.Response(ch) + .Embed(embed) + .Text(string.IsNullOrWhiteSpace(x.Message) + ? string.Empty + : x.Message) + .SendAsync(); + }) + .Where(x => x is not null); + + allSendTasks.Add(feedSendTasks.WhenAll()); + + // as data retrieval was successful, reset error counter + ClearErrors(rssUrl); + } + } + catch (Exception ex) + { + var errorCount = await AddError(rssUrl, kvp.Value.Select(x => x.Id).ToList()); + + Log.Warning("An error occured while getting rss stream ({ErrorCount} / 100) {RssFeed}" + + "\n {Message}", + errorCount, + rssUrl, + $"[{ex.GetType().Name}]: {ex.Message}"); + } + } + + await Task.WhenAll(Task.WhenAll(allSendTasks), Task.Delay(30000)); + } + } + + public List GetFeeds(ulong guildId) + { + using var uow = _db.GetDbContext(); + return uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs)) + .FeedSubs.OrderBy(x => x.Id) + .ToList(); + } + + public FeedAddResult AddFeed( + ulong guildId, + ulong channelId, + string rssFeed, + string message) + { + ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed)); + + var fs = new FeedSub + { + ChannelId = channelId, + Url = rssFeed.Trim(), + Message = message + }; + + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs)); + + if (gc.FeedSubs.Any(x => x.Url.ToLower() == fs.Url.ToLower())) + return FeedAddResult.Duplicate; + if (gc.FeedSubs.Count >= 10) + return FeedAddResult.LimitReached; + + gc.FeedSubs.Add(fs); + uow.SaveChanges(); + //adding all, in case bot wasn't on this guild when it started + foreach (var feed in gc.FeedSubs) + { + _subs.AddOrUpdate(feed.Url.ToLower(), + [feed], + (_, old) => + { + old.Add(feed); + return old; + }); + } + + return FeedAddResult.Success; + } + + public bool RemoveFeed(ulong guildId, int index) + { + if (index < 0) + return false; + + using var uow = _db.GetDbContext(); + var items = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs)) + .FeedSubs.OrderBy(x => x.Id) + .ToList(); + + if (items.Count <= index) + return false; + var toRemove = items[index]; + _subs.AddOrUpdate(toRemove.Url.ToLower(), + [], + (_, old) => + { + old.Remove(toRemove); + return old; + }); + uow.Remove(toRemove); + uow.SaveChanges(); + + return true; + } +} + +public enum FeedAddResult +{ + Success, + LimitReached, + Invalid, + Duplicate, +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/JokeCommands.cs b/src/EllieBot/Modules/Searches/JokeCommands.cs new file mode 100644 index 0000000..d41c50a --- /dev/null +++ b/src/EllieBot/Modules/Searches/JokeCommands.cs @@ -0,0 +1,53 @@ +#nullable disable +using EllieBot.Modules.Searches.Services; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class JokeCommands : EllieModule + { + [Cmd] + public async Task Yomama() + => await Response().Confirm(await _service.GetYomamaJoke()).SendAsync(); + + [Cmd] + public async Task Randjoke() + { + var (setup, punchline) = await _service.GetRandomJoke(); + await Response().Confirm(setup, punchline).SendAsync(); + } + + [Cmd] + public async Task ChuckNorris() + => await Response().Confirm(await _service.GetChuckNorrisJoke()).SendAsync(); + + [Cmd] + public async Task WowJoke() + { + if (!_service.WowJokes.Any()) + { + await Response().Error(strs.jokes_not_loaded).SendAsync(); + return; + } + + var joke = _service.WowJokes[new EllieRandom().Next(0, _service.WowJokes.Count)]; + await Response().Confirm(joke.Question, joke.Answer).SendAsync(); + } + + [Cmd] + public async Task MagicItem() + { + if (!_service.MagicItems.Any()) + { + await Response().Error(strs.magicitems_not_loaded).SendAsync(); + return; + } + + var item = _service.MagicItems[new EllieRandom().Next(0, _service.MagicItems.Count)]; + + await Response().Confirm("✨" + item.Name, item.Description).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/MemegenCommands.cs b/src/EllieBot/Modules/Searches/MemegenCommands.cs new file mode 100644 index 0000000..dbe2679 --- /dev/null +++ b/src/EllieBot/Modules/Searches/MemegenCommands.cs @@ -0,0 +1,99 @@ +#nullable disable +using Newtonsoft.Json; +using System.Collections.Immutable; +using System.Text; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class MemegenCommands : EllieModule + { + private static readonly ImmutableDictionary _map = new Dictionary + { + { '?', "~q" }, + { '%', "~p" }, + { '#', "~h" }, + { '/', "~s" }, + { ' ', "-" }, + { '-', "--" }, + { '_', "__" }, + { '"', "''" } + }.ToImmutableDictionary(); + + private readonly IHttpClientFactory _httpFactory; + + public MemegenCommands(IHttpClientFactory factory) + => _httpFactory = factory; + + [Cmd] + public async Task Memelist(int page = 1) + { + if (--page < 0) + return; + + using var http = _httpFactory.CreateClient("memelist"); + using var res = await http.GetAsync("https://api.memegen.link/templates/"); + + var rawJson = await res.Content.ReadAsStringAsync(); + + var data = JsonConvert.DeserializeObject>(rawJson)!; + + await Response() + .Paginated() + .Items(data) + .PageSize(15) + .CurrentPage(page) + .Page((items, curPage) => + { + var templates = string.Empty; + foreach (var template in items) + templates += $"**{template.Name}:**\n key: `{template.Id}`\n"; + var embed = _sender.CreateEmbed().WithOkColor().WithDescription(templates); + + return embed; + }) + .SendAsync(); + } + + [Cmd] + public async Task Memegen(string meme, [Leftover] string memeText = null) + { + var memeUrl = $"http://api.memegen.link/{meme}"; + if (!string.IsNullOrWhiteSpace(memeText)) + { + var memeTextArray = memeText.Split(';'); + foreach (var text in memeTextArray) + { + var newText = Replace(text); + memeUrl += $"/{newText}"; + } + } + + memeUrl += ".png"; + await Response().Text(memeUrl).SendAsync(); + } + + private static string Replace(string input) + { + var sb = new StringBuilder(); + + foreach (var c in input) + { + if (_map.TryGetValue(c, out var tmp)) + sb.Append(tmp); + else + sb.Append(c); + } + + return sb.ToString(); + } + + private class MemegenTemplate + { + public string Name { get; set; } + public string Id { get; set; } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/OsuCommands.cs b/src/EllieBot/Modules/Searches/OsuCommands.cs new file mode 100644 index 0000000..599df2d --- /dev/null +++ b/src/EllieBot/Modules/Searches/OsuCommands.cs @@ -0,0 +1,297 @@ +#nullable disable +using EllieBot.Modules.Searches.Common; +using Newtonsoft.Json; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class OsuCommands : EllieModule + { + private readonly IBotCredentials _creds; + private readonly IHttpClientFactory _httpFactory; + + public OsuCommands(IBotCredentials creds, IHttpClientFactory factory) + { + _creds = creds; + _httpFactory = factory; + } + + [Cmd] + public async Task Osu(string user, [Leftover] string mode = null) + { + if (string.IsNullOrWhiteSpace(user)) + return; + + using var http = _httpFactory.CreateClient(); + var modeNumber = string.IsNullOrWhiteSpace(mode) ? 0 : ResolveGameMode(mode); + + try + { + if (string.IsNullOrWhiteSpace(_creds.OsuApiKey)) + { + await Response().Error(strs.osu_api_key).SendAsync(); + return; + } + + var smode = ResolveGameMode(modeNumber); + var userReq = $"https://osu.ppy.sh/api/get_user?k={_creds.OsuApiKey}&u={user}&m={modeNumber}"; + var userResString = await http.GetStringAsync(userReq); + var objs = JsonConvert.DeserializeObject>(userResString); + + if (objs.Count == 0) + { + await Response().Error(strs.osu_user_not_found).SendAsync(); + return; + } + + var obj = objs[0]; + var userId = obj.UserId; + + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle($"osu! {smode} profile for {user}") + .WithThumbnailUrl($"https://a.ppy.sh/{userId}") + .WithDescription($"https://osu.ppy.sh/u/{userId}") + .AddField("Official Rank", $"#{obj.PpRank}", true) + .AddField("Country Rank", + $"#{obj.PpCountryRank} :flag_{obj.Country.ToLower()}:", + true) + .AddField("Total PP", Math.Round(obj.PpRaw, 2), true) + .AddField("Accuracy", Math.Round(obj.Accuracy, 2) + "%", true) + .AddField("Playcount", obj.Playcount, true) + .AddField("Level", Math.Round(obj.Level), true)).SendAsync(); + } + catch (ArgumentOutOfRangeException) + { + await Response().Error(strs.osu_user_not_found).SendAsync(); + } + catch (Exception ex) + { + await Response().Error(strs.osu_failed).SendAsync(); + Log.Warning(ex, "Osu command failed"); + } + } + + [Cmd] + public async Task Gatari(string user, [Leftover] string mode = null) + { + using var http = _httpFactory.CreateClient(); + var modeNumber = string.IsNullOrWhiteSpace(mode) ? 0 : ResolveGameMode(mode); + + var modeStr = ResolveGameMode(modeNumber); + var resString = await http.GetStringAsync($"https://api.gatari.pw/user/stats?u={user}&mode={modeNumber}"); + + var statsResponse = JsonConvert.DeserializeObject(resString); + if (statsResponse.Code != 200 || statsResponse.Stats.Id == 0) + { + await Response().Error(strs.osu_user_not_found).SendAsync(); + return; + } + + var usrResString = await http.GetStringAsync($"https://api.gatari.pw/users/get?u={user}"); + + var userData = JsonConvert.DeserializeObject(usrResString).Users[0]; + var userStats = statsResponse.Stats; + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle($"osu!Gatari {modeStr} profile for {user}") + .WithThumbnailUrl($"https://a.gatari.pw/{userStats.Id}") + .WithDescription($"https://osu.gatari.pw/u/{userStats.Id}") + .AddField("Official Rank", $"#{userStats.Rank}", true) + .AddField("Country Rank", + $"#{userStats.CountryRank} :flag_{userData.Country.ToLower()}:", + true) + .AddField("Total PP", userStats.Pp, true) + .AddField("Accuracy", $"{Math.Round(userStats.AvgAccuracy, 2)}%", true) + .AddField("Playcount", userStats.Playcount, true) + .AddField("Level", userStats.Level, true); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + public async Task Osu5(string user, [Leftover] string mode = null) + { + if (string.IsNullOrWhiteSpace(_creds.OsuApiKey)) + { + await Response().Error("An osu! API key is required.").SendAsync(); + return; + } + + if (string.IsNullOrWhiteSpace(user)) + { + await Response().Error("Please provide a username.").SendAsync(); + return; + } + + using var http = _httpFactory.CreateClient(); + var m = 0; + if (!string.IsNullOrWhiteSpace(mode)) + m = ResolveGameMode(mode); + + var reqString = "https://osu.ppy.sh/api/get_user_best" + + $"?k={_creds.OsuApiKey}" + + $"&u={Uri.EscapeDataString(user)}" + + "&type=string" + + "&limit=5" + + $"&m={m}"; + + var resString = await http.GetStringAsync(reqString); + var obj = JsonConvert.DeserializeObject>(resString); + + var mapTasks = obj.Select(async item => + { + var mapReqString = "https://osu.ppy.sh/api/get_beatmaps" + + $"?k={_creds.OsuApiKey}" + + $"&b={item.BeatmapId}"; + + var mapResString = await http.GetStringAsync(mapReqString); + var map = JsonConvert.DeserializeObject>(mapResString).FirstOrDefault(); + if (map is null) + return default; + var pp = Math.Round(item.Pp, 2); + var acc = CalculateAcc(item, m); + var mods = ResolveMods(item.EnabledMods); + + var title = $"{map.Artist}-{map.Title} ({map.Version})"; + var desc = $@"[/b/{item.BeatmapId}](https://osu.ppy.sh/b/{item.BeatmapId}) +{pp + "pp",-7} | {acc + "%",-7} +"; + if (mods != "+") + desc += Format.Bold(mods); + + return (title, desc); + }); + + var eb = _sender.CreateEmbed().WithOkColor().WithTitle($"Top 5 plays for {user}"); + + var mapData = await mapTasks.WhenAll(); + foreach (var (title, desc) in mapData.Where(x => x != default)) + eb.AddField(title, desc); + + await Response().Embed(eb).SendAsync(); + } + + //https://osu.ppy.sh/wiki/Accuracy + private static double CalculateAcc(OsuUserBests play, int mode) + { + double hitPoints; + double totalHits; + if (mode == 0) + { + hitPoints = (play.Count50 * 50) + (play.Count100 * 100) + (play.Count300 * 300); + totalHits = play.Count50 + play.Count100 + play.Count300 + play.Countmiss; + totalHits *= 300; + } + else if (mode == 1) + { + hitPoints = (play.Countmiss * 0) + (play.Count100 * 0.5) + play.Count300; + totalHits = (play.Countmiss + play.Count100 + play.Count300) * 300; + hitPoints *= 300; + } + else if (mode == 2) + { + hitPoints = play.Count50 + play.Count100 + play.Count300; + totalHits = play.Countmiss + play.Count50 + play.Count100 + play.Count300 + play.Countkatu; + } + else + { + hitPoints = (play.Count50 * 50) + + (play.Count100 * 100) + + (play.Countkatu * 200) + + ((play.Count300 + play.Countgeki) * 300); + + totalHits = (play.Countmiss + + play.Count50 + + play.Count100 + + play.Countkatu + + play.Count300 + + play.Countgeki) + * 300; + } + + + return Math.Round(hitPoints / totalHits * 100, 2); + } + + private static int ResolveGameMode(string mode) + { + switch (mode.ToUpperInvariant()) + { + case "STD": + case "STANDARD": + return 0; + case "TAIKO": + return 1; + case "CTB": + case "CATCHTHEBEAT": + return 2; + case "MANIA": + case "OSU!MANIA": + return 3; + default: + return 0; + } + } + + private static string ResolveGameMode(int mode) + { + switch (mode) + { + case 0: + return "Standard"; + case 1: + return "Taiko"; + case 2: + return "Catch"; + case 3: + return "Mania"; + default: + return "Standard"; + } + } + + //https://github.com/ppy/osu-api/wiki#mods + private static string ResolveMods(int mods) + { + var modString = "+"; + + if (IsBitSet(mods, 0)) + modString += "NF"; + if (IsBitSet(mods, 1)) + modString += "EZ"; + if (IsBitSet(mods, 8)) + modString += "HT"; + + if (IsBitSet(mods, 3)) + modString += "HD"; + if (IsBitSet(mods, 4)) + modString += "HR"; + if (IsBitSet(mods, 6) && !IsBitSet(mods, 9)) + modString += "DT"; + if (IsBitSet(mods, 9)) + modString += "NC"; + if (IsBitSet(mods, 10)) + modString += "FL"; + + if (IsBitSet(mods, 5)) + modString += "SD"; + if (IsBitSet(mods, 14)) + modString += "PF"; + + if (IsBitSet(mods, 7)) + modString += "RX"; + if (IsBitSet(mods, 11)) + modString += "AT"; + if (IsBitSet(mods, 12)) + modString += "SO"; + return modString; + } + + private static bool IsBitSet(int mods, int pos) + => (mods & (1 << pos)) != 0; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/PathOfExileCommands.cs b/src/EllieBot/Modules/Searches/PathOfExileCommands.cs new file mode 100644 index 0000000..a966a5b --- /dev/null +++ b/src/EllieBot/Modules/Searches/PathOfExileCommands.cs @@ -0,0 +1,312 @@ +#nullable disable +using EllieBot.Modules.Searches.Common; +using EllieBot.Modules.Searches.Services; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Globalization; +using System.Text; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class PathOfExileCommands : EllieModule + { + private const string POE_URL = "https://www.pathofexile.com/character-window/get-characters?accountName="; + private const string PON_URL = "http://poe.ninja/api/Data/GetCurrencyOverview?league="; + private const string POGS_URL = "http://pathofexile.gamepedia.com/api.php?action=opensearch&search="; + + private const string POG_URL = + "https://pathofexile.gamepedia.com/api.php?action=browsebysubject&format=json&subject="; + + private const string POGI_URL = + "https://pathofexile.gamepedia.com/api.php?action=query&prop=imageinfo&iiprop=url&format=json&titles=File:"; + + private const string PROFILE_URL = "https://www.pathofexile.com/account/view-profile/"; + + private readonly IHttpClientFactory _httpFactory; + + private Dictionary currencyDictionary = new(StringComparer.OrdinalIgnoreCase) + { + { "Chaos Orb", "Chaos Orb" }, + { "Orb of Alchemy", "Orb of Alchemy" }, + { "Jeweller's Orb", "Jeweller's Orb" }, + { "Exalted Orb", "Exalted Orb" }, + { "Mirror of Kalandra", "Mirror of Kalandra" }, + { "Vaal Orb", "Vaal Orb" }, + { "Orb of Alteration", "Orb of Alteration" }, + { "Orb of Scouring", "Orb of Scouring" }, + { "Divine Orb", "Divine Orb" }, + { "Orb of Annulment", "Orb of Annulment" }, + { "Master Cartographer's Sextant", "Master Cartographer's Sextant" }, + { "Journeyman Cartographer's Sextant", "Journeyman Cartographer's Sextant" }, + { "Apprentice Cartographer's Sextant", "Apprentice Cartographer's Sextant" }, + { "Blessed Orb", "Blessed Orb" }, + { "Orb of Regret", "Orb of Regret" }, + { "Gemcutter's Prism", "Gemcutter's Prism" }, + { "Glassblower's Bauble", "Glassblower's Bauble" }, + { "Orb of Fusing", "Orb of Fusing" }, + { "Cartographer's Chisel", "Cartographer's Chisel" }, + { "Chromatic Orb", "Chromatic Orb" }, + { "Orb of Augmentation", "Orb of Augmentation" }, + { "Blacksmith's Whetstone", "Blacksmith's Whetstone" }, + { "Orb of Transmutation", "Orb of Transmutation" }, + { "Armourer's Scrap", "Armourer's Scrap" }, + { "Scroll of Wisdom", "Scroll of Wisdom" }, + { "Regal Orb", "Regal Orb" }, + { "Chaos", "Chaos Orb" }, + { "Alch", "Orb of Alchemy" }, + { "Alchs", "Orb of Alchemy" }, + { "Jews", "Jeweller's Orb" }, + { "Jeweller", "Jeweller's Orb" }, + { "Jewellers", "Jeweller's Orb" }, + { "Jeweller's", "Jeweller's Orb" }, + { "X", "Exalted Orb" }, + { "Ex", "Exalted Orb" }, + { "Exalt", "Exalted Orb" }, + { "Exalts", "Exalted Orb" }, + { "Mirror", "Mirror of Kalandra" }, + { "Mirrors", "Mirror of Kalandra" }, + { "Vaal", "Vaal Orb" }, + { "Alt", "Orb of Alteration" }, + { "Alts", "Orb of Alteration" }, + { "Scour", "Orb of Scouring" }, + { "Scours", "Orb of Scouring" }, + { "Divine", "Divine Orb" }, + { "Annul", "Orb of Annulment" }, + { "Annulment", "Orb of Annulment" }, + { "Master Sextant", "Master Cartographer's Sextant" }, + { "Journeyman Sextant", "Journeyman Cartographer's Sextant" }, + { "Apprentice Sextant", "Apprentice Cartographer's Sextant" }, + { "Blessed", "Blessed Orb" }, + { "Regret", "Orb of Regret" }, + { "Regrets", "Orb of Regret" }, + { "Gcp", "Gemcutter's Prism" }, + { "Glassblowers", "Glassblower's Bauble" }, + { "Glassblower's", "Glassblower's Bauble" }, + { "Fusing", "Orb of Fusing" }, + { "Fuses", "Orb of Fusing" }, + { "Fuse", "Orb of Fusing" }, + { "Chisel", "Cartographer's Chisel" }, + { "Chisels", "Cartographer's Chisel" }, + { "Chance", "Orb of Chance" }, + { "Chances", "Orb of Chance" }, + { "Chrome", "Chromatic Orb" }, + { "Chromes", "Chromatic Orb" }, + { "Aug", "Orb of Augmentation" }, + { "Augmentation", "Orb of Augmentation" }, + { "Augment", "Orb of Augmentation" }, + { "Augments", "Orb of Augmentation" }, + { "Whetstone", "Blacksmith's Whetstone" }, + { "Whetstones", "Blacksmith's Whetstone" }, + { "Transmute", "Orb of Transmutation" }, + { "Transmutes", "Orb of Transmutation" }, + { "Armourers", "Armourer's Scrap" }, + { "Armourer's", "Armourer's Scrap" }, + { "Wisdom Scroll", "Scroll of Wisdom" }, + { "Wisdom Scrolls", "Scroll of Wisdom" }, + { "Regal", "Regal Orb" }, + { "Regals", "Regal Orb" } + }; + + public PathOfExileCommands(IHttpClientFactory httpFactory) + => _httpFactory = httpFactory; + + [Cmd] + public async Task PathOfExile(string usr, string league = "", int page = 1) + { + if (--page < 0) + return; + + if (string.IsNullOrWhiteSpace(usr)) + { + await Response().Error("Please provide an account name.").SendAsync(); + return; + } + + var characters = new List(); + + try + { + using var http = _httpFactory.CreateClient(); + var res = await http.GetStringAsync($"{POE_URL}{usr}"); + characters = JsonConvert.DeserializeObject>(res); + } + catch + { + var embed = _sender.CreateEmbed().WithDescription(GetText(strs.account_not_found)).WithErrorColor(); + + await Response().Embed(embed).SendAsync(); + return; + } + + if (!string.IsNullOrWhiteSpace(league)) + characters.RemoveAll(c => c.League != league); + + await Response() + .Paginated() + .Items(characters) + .PageSize(9) + .CurrentPage(page) + .Page((items, curPage) => + { + var embed = _sender.CreateEmbed() + .WithAuthor($"Characters on {usr}'s account", + "https://web.poecdn.com/image/favicon/ogimage.png", + $"{PROFILE_URL}{usr}") + .WithOkColor(); + + if (characters.Count == 0) + return embed.WithDescription("This account has no characters."); + + var sb = new StringBuilder(); + sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}"); + for (var i = 0; i < items.Count; i++) + { + var character = items[i]; + + sb.AppendLine( + $"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}"); + } + + sb.AppendLine("```"); + embed.WithDescription(sb.ToString()); + + return embed; + }) + .SendAsync(); + } + + [Cmd] + public async Task PathOfExileLeagues() + { + var leagues = new List(); + + try + { + using var http = _httpFactory.CreateClient(); + var res = await http.GetStringAsync("http://api.pathofexile.com/leagues?type=main&compact=1"); + leagues = JsonConvert.DeserializeObject>(res); + } + catch + { + var eembed = _sender.CreateEmbed().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor(); + + await Response().Embed(eembed).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed() + .WithAuthor("Path of Exile Leagues", + "https://web.poecdn.com/image/favicon/ogimage.png", + "https://www.pathofexile.com") + .WithOkColor(); + + var sb = new StringBuilder(); + sb.AppendLine($"```{"#",-5}{"League Name",-23}"); + for (var i = 0; i < leagues.Count; i++) + { + var league = leagues[i]; + + sb.AppendLine($"#{i + 1,-4}{league.Id,-23}"); + } + + sb.AppendLine("```"); + + embed.WithDescription(sb.ToString()); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + public async Task PathOfExileCurrency( + string leagueName, + string currencyName, + string convertName = "Chaos Orb") + { + if (string.IsNullOrWhiteSpace(leagueName)) + { + await Response().Error("Please provide league name.").SendAsync(); + return; + } + + if (string.IsNullOrWhiteSpace(currencyName)) + { + await Response().Error("Please provide currency name.").SendAsync(); + return; + } + + var cleanCurrency = ShortCurrencyName(currencyName); + var cleanConvert = ShortCurrencyName(convertName); + + try + { + var res = $"{PON_URL}{leagueName}"; + using var http = _httpFactory.CreateClient(); + var obj = JObject.Parse(await http.GetStringAsync(res)); + + var chaosEquivalent = 0.0F; + var conversionEquivalent = 0.0F; + + // poe.ninja API does not include a "chaosEquivalent" property for Chaos Orbs. + if (cleanCurrency == "Chaos Orb") + chaosEquivalent = 1.0F; + else + { + var currencyInput = obj["lines"] + .Values() + .Where(i => i["currencyTypeName"].Value() == cleanCurrency) + .FirstOrDefault(); + chaosEquivalent = float.Parse(currencyInput["chaosEquivalent"].ToString(), + CultureInfo.InvariantCulture); + } + + if (cleanConvert == "Chaos Orb") + conversionEquivalent = 1.0F; + else + { + var currencyOutput = obj["lines"] + .Values() + .Where(i => i["currencyTypeName"].Value() == cleanConvert) + .FirstOrDefault(); + conversionEquivalent = float.Parse(currencyOutput["chaosEquivalent"].ToString(), + CultureInfo.InvariantCulture); + } + + var embed = _sender.CreateEmbed() + .WithAuthor($"{leagueName} Currency Exchange", + "https://web.poecdn.com/image/favicon/ogimage.png", + "http://poe.ninja") + .AddField("Currency Type", cleanCurrency, true) + .AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true) + .WithOkColor(); + + await Response().Embed(embed).SendAsync(); + } + catch + { + var embed = _sender.CreateEmbed().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor(); + + await Response().Embed(embed).SendAsync(); + } + } + + private string ShortCurrencyName(string str) + { + if (currencyDictionary.ContainsValue(str)) + return str; + + var currency = currencyDictionary[str]; + + return currency; + } + + private static string ShortLeagueName(string str) + { + var league = str.Replace("Hardcore", "HC", StringComparison.InvariantCultureIgnoreCase); + + return league; + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/PokemonSearchCommands.cs b/src/EllieBot/Modules/Searches/PokemonSearchCommands.cs new file mode 100644 index 0000000..6250e87 --- /dev/null +++ b/src/EllieBot/Modules/Searches/PokemonSearchCommands.cs @@ -0,0 +1,74 @@ +#nullable disable +using EllieBot.Modules.Searches.Services; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class PokemonSearchCommands : EllieModule + { + private readonly ILocalDataCache _cache; + + public PokemonSearchCommands(ILocalDataCache cache) + => _cache = cache; + + [Cmd] + public async Task Pokemon([Leftover] string pokemon = null) + { + pokemon = pokemon?.Trim().ToUpperInvariant(); + if (string.IsNullOrWhiteSpace(pokemon)) + return; + + foreach (var kvp in await _cache.GetPokemonsAsync()) + { + if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant()) + { + var p = kvp.Value; + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(kvp.Key.ToTitleCase()) + .WithDescription(p.BaseStats.ToString()) + .WithThumbnailUrl( + $"https://assets.pokemon.com/assets/cms2/img/pokedex/detail/{p.Id.ToString("000")}.png") + .AddField(GetText(strs.types), string.Join("\n", p.Types), true) + .AddField(GetText(strs.height_weight), + GetText(strs.height_weight_val(p.HeightM, p.WeightKg)), + true) + .AddField(GetText(strs.abilities), + string.Join("\n", p.Abilities.Select(a => a.Value)), + true)).SendAsync(); + return; + } + } + + await Response().Error(strs.pokemon_none).SendAsync(); + } + + [Cmd] + public async Task PokemonAbility([Leftover] string ability = null) + { + ability = ability?.Trim().ToUpperInvariant().Replace(" ", "", StringComparison.InvariantCulture); + if (string.IsNullOrWhiteSpace(ability)) + return; + foreach (var kvp in await _cache.GetPokemonAbilitiesAsync()) + { + if (kvp.Key.ToUpperInvariant() == ability) + { + await Response().Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(kvp.Value.Name) + .WithDescription(string.IsNullOrWhiteSpace(kvp.Value.Desc) + ? kvp.Value.ShortDesc + : kvp.Value.Desc) + .AddField(GetText(strs.rating), + kvp.Value.Rating.ToString(Culture), + true)).SendAsync(); + return; + } + } + + await Response().Error(strs.pokemon_ability_none).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/DefaultSearchServiceFactory.cs b/src/EllieBot/Modules/Searches/Search/DefaultSearchServiceFactory.cs new file mode 100644 index 0000000..fa3c634 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/DefaultSearchServiceFactory.cs @@ -0,0 +1,65 @@ +using EllieBot.Modules.Searches.GoogleScrape; +using EllieBot.Modules.Searches.Youtube; + +namespace EllieBot.Modules.Searches; + +public sealed class DefaultSearchServiceFactory : ISearchServiceFactory, IEService +{ + private readonly SearchesConfigService _scs; + private readonly SearxSearchService _sss; + private readonly GoogleSearchService _gss; + + private readonly YtdlpYoutubeSearchService _ytdlp; + private readonly YtdlYoutubeSearchService _ytdl; + private readonly YoutubeDataApiSearchService _ytdata; + private readonly InvidiousYtSearchService _iYtSs; + private readonly GoogleScrapeService _gscs; + + public DefaultSearchServiceFactory( + SearchesConfigService scs, + GoogleSearchService gss, + GoogleScrapeService gscs, + SearxSearchService sss, + YtdlpYoutubeSearchService ytdlp, + YtdlYoutubeSearchService ytdl, + YoutubeDataApiSearchService ytdata, + InvidiousYtSearchService iYtSs) + { + _scs = scs; + _sss = sss; + _gss = gss; + _gscs = gscs; + _iYtSs = iYtSs; + + _ytdlp = ytdlp; + _ytdl = ytdl; + _ytdata = ytdata; + } + + public ISearchService GetSearchService(string? hint = null) + => _scs.Data.WebSearchEngine switch + { + WebSearchEngine.Google => _gss, + WebSearchEngine.Google_Scrape => _gscs, + WebSearchEngine.Searx => _sss, + _ => _gss + }; + + public ISearchService GetImageSearchService(string? hint = null) + => _scs.Data.ImgSearchEngine switch + { + ImgSearchEngine.Google => _gss, + ImgSearchEngine.Searx => _sss, + _ => _gss + }; + + public IYoutubeSearchService GetYoutubeSearchService(string? hint = null) + => _scs.Data.YtProvider switch + { + YoutubeSearcher.YtDataApiv3 => _ytdata, + YoutubeSearcher.Ytdlp => _ytdlp, + YoutubeSearcher.Ytdl => _ytdl, + YoutubeSearcher.Invidious => _iYtSs, + _ => _ytdl + }; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/GoogleCustomSearchResult.cs b/src/EllieBot/Modules/Searches/Search/Google/GoogleCustomSearchResult.cs new file mode 100644 index 0000000..74fd3c0 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/GoogleCustomSearchResult.cs @@ -0,0 +1,22 @@ +using EllieBot.Modules.Searches; +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class GoogleCustomSearchResult : ISearchResult +{ + ISearchResultInformation ISearchResult.Info + => Info; + + public string? Answer + => null; + + IReadOnlyCollection ISearchResult.Entries + => Entries ?? Array.Empty(); + + [JsonPropertyName("searchInformation")] + public GoogleSearchResultInformation Info { get; init; } = null!; + + [JsonPropertyName("items")] + public IReadOnlyCollection? Entries { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/GoogleImageData.cs b/src/EllieBot/Modules/Searches/Search/Google/GoogleImageData.cs new file mode 100644 index 0000000..503a1cc --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/GoogleImageData.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class GoogleImageData +{ + [JsonPropertyName("contextLink")] + public string ContextLink { get; init; } = null!; + + [JsonPropertyName("thumbnailLink")] + public string ThumbnailLink { get; init; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/GoogleImageResult.cs b/src/EllieBot/Modules/Searches/Search/Google/GoogleImageResult.cs new file mode 100644 index 0000000..9cf406b --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/GoogleImageResult.cs @@ -0,0 +1,19 @@ +using EllieBot.Modules.Searches; +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class GoogleImageResult : IImageSearchResult +{ + ISearchResultInformation IImageSearchResult.Info + => Info; + + IReadOnlyCollection IImageSearchResult.Entries + => Entries ?? Array.Empty(); + + [JsonPropertyName("searchInformation")] + public GoogleSearchResultInformation Info { get; init; } = null!; + + [JsonPropertyName("items")] + public IReadOnlyCollection? Entries { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/GoogleImageResultEntry.cs b/src/EllieBot/Modules/Searches/Search/Google/GoogleImageResultEntry.cs new file mode 100644 index 0000000..cd06fae --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/GoogleImageResultEntry.cs @@ -0,0 +1,13 @@ +using EllieBot.Modules.Searches; +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class GoogleImageResultEntry : IImageSearchResultEntry +{ + [JsonPropertyName("link")] + public string Link { get; init; } = null!; + + [JsonPropertyName("image")] + public GoogleImageData Image { get; init; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/GoogleSearchResultInformation.cs b/src/EllieBot/Modules/Searches/Search/Google/GoogleSearchResultInformation.cs new file mode 100644 index 0000000..0106c0a --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/GoogleSearchResultInformation.cs @@ -0,0 +1,13 @@ +using EllieBot.Modules.Searches; +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class GoogleSearchResultInformation : ISearchResultInformation +{ + [JsonPropertyName("formattedTotalResults")] + public string TotalResults { get; init; } = null!; + + [JsonPropertyName("formattedSearchTime")] + public string SearchTime { get; init; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/GoogleSearchService.cs b/src/EllieBot/Modules/Searches/Search/Google/GoogleSearchService.cs new file mode 100644 index 0000000..c74d746 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/GoogleSearchService.cs @@ -0,0 +1,66 @@ +using MorseCode.ITask; + +namespace EllieBot.Modules.Searches; + +public sealed class GoogleSearchService : SearchServiceBase, IEService +{ + private readonly IBotCredsProvider _creds; + private readonly IHttpClientFactory _httpFactory; + + public GoogleSearchService(IBotCredsProvider creds, IHttpClientFactory httpFactory) + { + _creds = creds; + _httpFactory = httpFactory; + } + + public override async ITask SearchImagesAsync(string query) + { + ArgumentNullException.ThrowIfNull(query); + + var creds = _creds.GetCreds(); + var key = creds.Google.ImageSearchId; + var cx = string.IsNullOrWhiteSpace(key) + ? "c3f56de3be2034c07" + : key; + + using var http = _httpFactory.CreateClient("google:search"); + http.DefaultRequestHeaders.Add("Accept-Encoding", "gzip"); + await using var stream = await http.GetStreamAsync( + $"https://customsearch.googleapis.com/customsearch/v1" + + $"?cx={cx}" + + $"&q={Uri.EscapeDataString(query)}" + + $"&fields=items(image(contextLink%2CthumbnailLink)%2Clink)%2CsearchInformation" + + $"&key={creds.GoogleApiKey}" + + $"&searchType=image" + + $"&safe=active"); + + var result = await System.Text.Json.JsonSerializer.DeserializeAsync(stream); + + return result; + } + + public override async ITask SearchAsync(string? query) + { + ArgumentNullException.ThrowIfNull(query); + + var creds = _creds.GetCreds(); + var key = creds.Google.SearchId; + var cx = string.IsNullOrWhiteSpace(key) + ? "c7f1dac95987d4571" + : key; + + using var http = _httpFactory.CreateClient("google:search"); + http.DefaultRequestHeaders.Add("Accept-Encoding", "gzip"); + await using var stream = await http.GetStreamAsync( + $"https://customsearch.googleapis.com/customsearch/v1" + + $"?cx={cx}" + + $"&q={Uri.EscapeDataString(query)}" + + $"&fields=items(title%2Clink%2CdisplayLink%2Csnippet)%2CsearchInformation" + + $"&key={creds.GoogleApiKey}" + + $"&safe=active"); + + var result = await System.Text.Json.JsonSerializer.DeserializeAsync(stream); + + return result; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Google/OfficialGoogleSearchResultEntry.cs b/src/EllieBot/Modules/Searches/Search/Google/OfficialGoogleSearchResultEntry.cs new file mode 100644 index 0000000..bf23180 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Google/OfficialGoogleSearchResultEntry.cs @@ -0,0 +1,19 @@ +using EllieBot.Modules.Searches; +using System.Text.Json.Serialization; + +namespace EllieBot.Services; + +public sealed class OfficialGoogleSearchResultEntry : ISearchResultEntry +{ + [JsonPropertyName("title")] + public string Title { get; init; } = null!; + + [JsonPropertyName("link")] + public string Url { get; init; } = null!; + + [JsonPropertyName("displayLink")] + public string DisplayUrl { get; init; } = null!; + + [JsonPropertyName("snippet")] + public string Description { get; init; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/GoogleScrape/GoogleScrapeService.cs b/src/EllieBot/Modules/Searches/Search/GoogleScrape/GoogleScrapeService.cs new file mode 100644 index 0000000..8c20767 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/GoogleScrape/GoogleScrapeService.cs @@ -0,0 +1,121 @@ +using AngleSharp.Html.Dom; +using AngleSharp.Html.Parser; +using MorseCode.ITask; + +namespace EllieBot.Modules.Searches.GoogleScrape; + +public sealed class GoogleScrapeService : SearchServiceBase, IEService +{ + private static readonly HtmlParser _googleParser = new(new() + { + IsScripting = false, + IsEmbedded = false, + IsSupportingProcessingInstructions = false, + IsKeepingSourceReferences = false, + IsNotSupportingFrames = true + }); + + + private readonly IHttpClientFactory _httpFactory; + + public GoogleScrapeService(IHttpClientFactory httpClientFactory) + => _httpFactory = httpClientFactory; + + public override async ITask SearchAsync(string? query) + { + ArgumentNullException.ThrowIfNull(query); + + query = Uri.EscapeDataString(query)?.Replace(' ', '+'); + + var fullQueryLink = $"https://www.google.ca/search?q={query}&safe=on&lr=lang_eng&hl=en&ie=utf-8&oe=utf-8"; + + using var msg = new HttpRequestMessage(HttpMethod.Get, fullQueryLink); + msg.Headers.Add("User-Agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"); + msg.Headers.Add("Cookie", "CONSENT=YES+shp.gws-20210601-0-RC2.en+FX+423;"); + + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Clear(); + + using var response = await http.SendAsync(msg); + await using var content = await response.Content.ReadAsStreamAsync(); + + using var document = await _googleParser.ParseDocumentAsync(content); + var elems = document.QuerySelectorAll("div.g, div.mnr-c > div > div"); + + var resultsElem = document.QuerySelector("#result-stats"); + var resultsArr = resultsElem?.TextContent.Split("results"); + var totalResults = resultsArr?.Length is null or 0 + ? null + : resultsArr[0]; + + var time = resultsArr is null or {Length: < 2} + ? null + : resultsArr[1] + .Replace("(", string.Empty) + .Replace("seconds)", string.Empty); + + //var time = resultsElem.Children.FirstOrDefault()?.TextContent + //^ this doesn't work for some reason, is completely missing in parsed collection + if (!elems.Any()) + return default; + + var results = elems.Select(elem => + { + var aTag = elem.QuerySelector("a"); + + if (aTag is null) + return null; + + var url = ((IHtmlAnchorElement)aTag).Href; + var title = aTag.QuerySelector("h3")?.TextContent; + + var txt = aTag.ParentElement + ?.NextElementSibling + ?.QuerySelector("span") + ?.TextContent + .StripHtml() + ?? elem + ?.QuerySelectorAll("span") + .Skip(3) + .FirstOrDefault() + ?.TextContent + .StripHtml(); + // .Select(x => x.TextContent.StripHtml()) + // .Join("\n"); + + if (string.IsNullOrWhiteSpace(url) + || string.IsNullOrWhiteSpace(title) + || string.IsNullOrWhiteSpace(txt)) + return null; + + return new PlainSearchResultEntry + { + Title = title, + Url = url, + DisplayUrl = url, + Description = txt + }; + }) + .Where(x => x is not null) + .ToList(); + + // return new GoogleSearchResult(results.AsReadOnly(), fullQueryLink, totalResults); + + return new PlainGoogleScrapeSearchResult() + { + Answer = null, + Entries = results!, + Info = new PlainSearchResultInfo() + { + SearchTime = time ?? "?", + TotalResults = totalResults ?? "?" + } + }; + } + + + // someone can mr this + public override ITask SearchImagesAsync(string query) + => throw new NotSupportedException(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainGoogleScrapeSearchResult.cs b/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainGoogleScrapeSearchResult.cs new file mode 100644 index 0000000..9abc999 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainGoogleScrapeSearchResult.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Searches.GoogleScrape; + +public class PlainGoogleScrapeSearchResult : ISearchResult +{ + public required string? Answer { get; init; } + public required IReadOnlyCollection Entries { get; init; } + public required ISearchResultInformation Info { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultEntry.cs b/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultEntry.cs new file mode 100644 index 0000000..99fad02 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultEntry.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Searches.GoogleScrape; + +public sealed class PlainSearchResultEntry : ISearchResultEntry +{ + public string Title { get; init; } = null!; + public string Url { get; init; } = null!; + public string DisplayUrl { get; init; } = null!; + public string? Description { get; init; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultInfo.cs b/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultInfo.cs new file mode 100644 index 0000000..92ba006 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/GoogleScrape/PlainSearchResultInfo.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches.GoogleScrape; + +public sealed class PlainSearchResultInfo : ISearchResultInformation +{ + public string TotalResults { get; init; } = null!; + public string SearchTime { get; init; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/IImageSearchResult.cs b/src/EllieBot/Modules/Searches/Search/IImageSearchResult.cs new file mode 100644 index 0000000..d470613 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/IImageSearchResult.cs @@ -0,0 +1,13 @@ +namespace EllieBot.Modules.Searches; + +public interface IImageSearchResult +{ + ISearchResultInformation Info { get; } + + IReadOnlyCollection Entries { get; } +} + +public interface IImageSearchResultEntry +{ + string Link { get; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/ISearchResult.cs b/src/EllieBot/Modules/Searches/Search/ISearchResult.cs new file mode 100644 index 0000000..d910819 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/ISearchResult.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Searches; + +public interface ISearchResult +{ + string? Answer { get; } + IReadOnlyCollection Entries { get; } + ISearchResultInformation Info { get; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/ISearchResultEntry.cs b/src/EllieBot/Modules/Searches/Search/ISearchResultEntry.cs new file mode 100644 index 0000000..e4dfc44 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/ISearchResultEntry.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Searches; + +public interface ISearchResultEntry +{ + string Title { get; } + string Url { get; } + string DisplayUrl { get; } + string? Description { get; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/ISearchResultInformation.cs b/src/EllieBot/Modules/Searches/Search/ISearchResultInformation.cs new file mode 100644 index 0000000..dfd9a53 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/ISearchResultInformation.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches; + +public interface ISearchResultInformation +{ + string TotalResults { get; } + string SearchTime { get; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/ISearchService.cs b/src/EllieBot/Modules/Searches/Search/ISearchService.cs new file mode 100644 index 0000000..7454a60 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/ISearchService.cs @@ -0,0 +1,9 @@ +using MorseCode.ITask; + +namespace EllieBot.Modules.Searches; + +public interface ISearchService +{ + ITask SearchAsync(string? query); + ITask SearchImagesAsync(string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/ISearchServiceFactory.cs b/src/EllieBot/Modules/Searches/Search/ISearchServiceFactory.cs new file mode 100644 index 0000000..bb46b09 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/ISearchServiceFactory.cs @@ -0,0 +1,10 @@ +using EllieBot.Modules.Searches.Youtube; + +namespace EllieBot.Modules.Searches; + +public interface ISearchServiceFactory +{ + public ISearchService GetSearchService(string? hint = null); + public ISearchService GetImageSearchService(string? hint = null); + public IYoutubeSearchService GetYoutubeSearchService(string? hint = null); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/SearchCommands.cs b/src/EllieBot/Modules/Searches/Search/SearchCommands.cs new file mode 100644 index 0000000..6a98eac --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/SearchCommands.cs @@ -0,0 +1,202 @@ +using EllieBot.Modules.Searches.Youtube; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + public partial class SearchCommands : EllieModule + { + private readonly ISearchServiceFactory _searchFactory; + private readonly IBotCache _cache; + + public SearchCommands( + ISearchServiceFactory searchFactory, + IBotCache cache) + { + _searchFactory = searchFactory; + _cache = cache; + } + + [Cmd] + public async Task Google([Leftover] string? query = null) + { + query = query?.Trim(); + + if (string.IsNullOrWhiteSpace(query)) + { + await Response().Error(strs.specify_search_params).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var search = _searchFactory.GetSearchService(); + var data = await search.SearchAsync(query); + + if (data is null or { Entries: null or { Count: 0 } }) + { + await Response().Error(strs.no_results).SendAsync(); + return; + } + + // 3 with an answer + // 4 without an answer + // 5 is ideal but it lookes horrible on mobile + + var takeCount = string.IsNullOrWhiteSpace(data.Answer) + ? 4 + : 3; + + var descStr = data.Entries + .Take(takeCount) + .Select(static res => $@"**[{Format.Sanitize(res.Title)}]({res.Url})** +*{Format.EscapeUrl(res.DisplayUrl)}* +{Format.Sanitize(res.Description ?? "-")}") + .Join("\n\n"); + + if (!string.IsNullOrWhiteSpace(data.Answer)) + descStr = Format.Code(data.Answer) + "\n\n" + descStr; + + descStr = descStr.TrimTo(4096); + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .WithTitle(query.TrimTo(64)!) + .WithDescription(descStr) + .WithFooter( + GetText(strs.results_in(data.Info.TotalResults, data.Info.SearchTime)), + "https://i.imgur.com/G46fm8J.png"); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + public async Task Image([Leftover] string? query = null) + { + query = query?.Trim(); + + if (string.IsNullOrWhiteSpace(query)) + { + await Response().Error(strs.specify_search_params).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var search = _searchFactory.GetImageSearchService(); + var data = await search.SearchImagesAsync(query); + + if (data is null or { Entries: null or { Count: 0 } }) + { + await Response().Error(strs.no_search_results).SendAsync(); + return; + } + + var embeds = new List(4); + + + EmbedBuilder CreateEmbed(IImageSearchResultEntry entry) + { + return _sender.CreateEmbed() + .WithOkColor() + .WithAuthor(ctx.User) + .WithTitle(query) + .WithUrl("https://google.com") + .WithImageUrl(entry.Link); + } + + embeds.Add(CreateEmbed(data.Entries.First()) + .WithFooter( + GetText(strs.results_in(data.Info.TotalResults, data.Info.SearchTime)), + "https://i.imgur.com/G46fm8J.png")); + + var random = data.Entries.Skip(1) + .Shuffle() + .Take(3) + .ToArray(); + + foreach (var entry in random) + { + embeds.Add(CreateEmbed(entry)); + } + + await Response().Embeds(embeds).SendAsync(); + } + + private TypedKey GetYtCacheKey(string query) + => new($"search:youtube:{query}"); + + private async Task AddYoutubeUrlToCacheAsync(string query, string url) + => await _cache.AddAsync(GetYtCacheKey(query), url, expiry: 1.Hours()); + + private async Task GetYoutubeUrlFromCacheAsync(string query) + { + var result = await _cache.GetAsync(GetYtCacheKey(query)); + + if (!result.TryGetValue(out var url) || string.IsNullOrWhiteSpace(url)) + return null; + + return new VideoInfo() + { + Url = url + }; + } + + [Cmd] + public async Task Youtube([Leftover] string? query = null) + { + query = query?.Trim(); + + if (string.IsNullOrWhiteSpace(query)) + { + await Response().Error(strs.specify_search_params).SendAsync(); + return; + } + + _ = ctx.Channel.TriggerTypingAsync(); + + var maybeResult = await GetYoutubeUrlFromCacheAsync(query) + ?? await _searchFactory.GetYoutubeSearchService().SearchAsync(query); + if (maybeResult is not {} result || result is {Url: null}) + { + await Response().Error(strs.no_results).SendAsync(); + return; + } + + await AddYoutubeUrlToCacheAsync(query, result.Url); + await Response().Text(result.Url).SendAsync(); + } + +// [Cmd] +// public async Task DuckDuckGo([Leftover] string query = null) +// { +// query = query?.Trim(); +// if (!await ValidateQuery(query)) +// return; +// +// _ = ctx.Channel.TriggerTypingAsync(); +// +// var data = await _service.DuckDuckGoSearchAsync(query); +// if (data is null) +// { +// await Response().Error(strs.no_results).SendAsync(); +// return; +// } +// +// var desc = data.Results.Take(5) +// .Select(res => $@"[**{res.Title}**]({res.Link}) +// {res.Text.TrimTo(380 - res.Title.Length - res.Link.Length)}"); +// +// var descStr = string.Join("\n\n", desc); +// +// var embed = _sender.CreateEmbed() +// .WithAuthor(ctx.User.ToString(), +// "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png") +// .WithDescription($"{GetText(strs.search_for)} **{query}**\n\n" + descStr) +// .WithOkColor(); +// +// await Response().Embed(embed).SendAsync(); +// } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/SearchServiceBase.cs b/src/EllieBot/Modules/Searches/Search/SearchServiceBase.cs new file mode 100644 index 0000000..c346306 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/SearchServiceBase.cs @@ -0,0 +1,9 @@ +using MorseCode.ITask; + +namespace EllieBot.Modules.Searches; + +public abstract class SearchServiceBase : ISearchService +{ + public abstract ITask SearchAsync(string? query); + public abstract ITask SearchImagesAsync(string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResult.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResult.cs new file mode 100644 index 0000000..54fdcdd --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResult.cs @@ -0,0 +1,28 @@ +using System.Globalization; +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxImageSearchResult : IImageSearchResult +{ + public string SearchTime { get; set; } = null!; + + public ISearchResultInformation Info + => new SearxSearchResultInformation() + { + SearchTime = SearchTime, + TotalResults = NumberOfResults.ToString("N", CultureInfo.InvariantCulture) + }; + + public IReadOnlyCollection Entries + => Results; + + [JsonPropertyName("results")] + public List Results { get; set; } = new List(); + + [JsonPropertyName("query")] + public string Query { get; set; } = null!; + + [JsonPropertyName("number_of_results")] + public double NumberOfResults { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResultEntry.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResultEntry.cs new file mode 100644 index 0000000..888a2ce --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxImageSearchResultEntry.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxImageSearchResultEntry : IImageSearchResultEntry +{ + public string Link + => ImageSource.StartsWith("//") + ? "https:" + ImageSource + : ImageSource; + + [JsonPropertyName("img_src")] + public string ImageSource { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxInfobox.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxInfobox.cs new file mode 100644 index 0000000..1fd9ee2 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxInfobox.cs @@ -0,0 +1,30 @@ +// using System.Text.Json.Serialization; +// +// namespace EllieBot.Modules.Searches; +// +// public sealed class SearxInfobox +// { +// [JsonPropertyName("infobox")] +// public string Infobox { get; set; } +// +// [JsonPropertyName("id")] +// public string Id { get; set; } +// +// [JsonPropertyName("content")] +// public string Content { get; set; } +// +// [JsonPropertyName("img_src")] +// public string ImgSrc { get; set; } +// +// [JsonPropertyName("urls")] +// public List Urls { get; } = new List(); +// +// [JsonPropertyName("engine")] +// public string Engine { get; set; } +// +// [JsonPropertyName("engines")] +// public List Engines { get; } = new List(); +// +// [JsonPropertyName("attributes")] +// public List Attributes { get; } = new List(); +// } \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchAttribute.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchAttribute.cs new file mode 100644 index 0000000..7071ea7 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchAttribute.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxSearchAttribute +{ + [JsonPropertyName("label")] + public string? Label { get; set; } + + [JsonPropertyName("value")] + public string? Value { get; set; } + + [JsonPropertyName("entity")] + public string? Entity { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResult.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResult.cs new file mode 100644 index 0000000..3483548 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResult.cs @@ -0,0 +1,47 @@ +using System.Globalization; +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxSearchResult : ISearchResult +{ + [JsonPropertyName("query")] + public string Query { get; set; } = null!; + + [JsonPropertyName("number_of_results")] + public double NumberOfResults { get; set; } + + [JsonPropertyName("results")] + public List Results { get; set; } = new List(); + + [JsonPropertyName("answers")] + public List Answers { get; set; } = new List(); + // + // [JsonPropertyName("corrections")] + // public List Corrections { get; } = new List(); + + // [JsonPropertyName("infoboxes")] + // public List Infoboxes { get; } = new List(); + // + // [JsonPropertyName("suggestions")] + // public List Suggestions { get; } = new List(); + + // [JsonPropertyName("unresponsive_engines")] + // public List UnresponsiveEngines { get; } = new List(); + + + public string SearchTime { get; set; } = null!; + + public IReadOnlyCollection Entries + => Results; + + public ISearchResultInformation Info + => new SearxSearchResultInformation() + { + SearchTime = SearchTime, + TotalResults = NumberOfResults.ToString("N", CultureInfo.InvariantCulture) + }; + + public string? Answer + => Answers.FirstOrDefault(); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultEntry.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultEntry.cs new file mode 100644 index 0000000..9670a17 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultEntry.cs @@ -0,0 +1,51 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxSearchResultEntry : ISearchResultEntry +{ + public string DisplayUrl + => Url; + + public string Description + => Content.TrimTo(768)!; + + [JsonPropertyName("url")] + public string Url { get; set; } = null!; + + [JsonPropertyName("title")] + public string Title { get; set; } = null!; + + [JsonPropertyName("content")] + public string? Content { get; set; } + + // [JsonPropertyName("engine")] + // public string Engine { get; set; } + // + // [JsonPropertyName("parsed_url")] + // public List ParsedUrl { get; } = new List(); + // + // [JsonPropertyName("template")] + // public string Template { get; set; } + // + // [JsonPropertyName("engines")] + // public List Engines { get; } = new List(); + // + // [JsonPropertyName("positions")] + // public List Positions { get; } = new List(); + // + // [JsonPropertyName("score")] + // public double Score { get; set; } + // + // [JsonPropertyName("category")] + // public string Category { get; set; } + // + // [JsonPropertyName("pretty_url")] + // public string PrettyUrl { get; set; } + // + // [JsonPropertyName("open_group")] + // public bool OpenGroup { get; set; } + // + // [JsonPropertyName("close_group")] + // public bool? CloseGroup { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultInformation.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultInformation.cs new file mode 100644 index 0000000..33b8077 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchResultInformation.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches; + +public sealed class SearxSearchResultInformation : ISearchResultInformation +{ + public string TotalResults { get; init; } = string.Empty; + public string SearchTime { get; init; } = string.Empty; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchService.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchService.cs new file mode 100644 index 0000000..87e4103 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxSearchService.cs @@ -0,0 +1,76 @@ +using MorseCode.ITask; +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxSearchService : SearchServiceBase, IEService +{ + private readonly IHttpClientFactory _http; + private readonly SearchesConfigService _scs; + + private static readonly Random _rng = new EllieRandom(); + + public SearxSearchService(IHttpClientFactory http, SearchesConfigService scs) + => (_http, _scs) = (http, scs); + + private string GetRandomInstance() + { + var instances = _scs.Data.SearxInstances; + + if (instances is null or { Count: 0 }) + throw new InvalidOperationException("No searx instances specified in searches.yml"); + + return instances[_rng.Next(0, instances.Count)]; + } + + public override async ITask SearchAsync(string? query) + { + ArgumentNullException.ThrowIfNull(query); + + var instanceUrl = GetRandomInstance(); + + Log.Information("Using {Instance} instance for web search...", instanceUrl); + var sw = Stopwatch.StartNew(); + using var http = _http.CreateClient(); + await using var res = await http.GetStreamAsync($"{instanceUrl}" + + $"?q={Uri.EscapeDataString(query)}" + + $"&format=json" + + $"&strict=2"); + + sw.Stop(); + var dat = await JsonSerializer.DeserializeAsync(res); + + if (dat is null) + return new SearxSearchResult(); + + dat.SearchTime = sw.Elapsed.TotalSeconds.ToString("N2", CultureInfo.InvariantCulture); + return dat; + } + + public override async ITask SearchImagesAsync(string query) + { + ArgumentNullException.ThrowIfNull(query); + + var instanceUrl = GetRandomInstance(); + + Log.Information("Using {Instance} instance for img search...", instanceUrl); + var sw = Stopwatch.StartNew(); + using var http = _http.CreateClient(); + await using var res = await http.GetStreamAsync($"{instanceUrl}" + + $"?q={Uri.EscapeDataString(query)}" + + $"&format=json" + + $"&category_images=on" + + $"&strict=2"); + + sw.Stop(); + var dat = await JsonSerializer.DeserializeAsync(res); + + if (dat is null) + return new SearxImageSearchResult(); + + dat.SearchTime = sw.Elapsed.TotalSeconds.ToString("N2", CultureInfo.InvariantCulture); + return dat; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Searx/SearxUrlData.cs b/src/EllieBot/Modules/Searches/Search/Searx/SearxUrlData.cs new file mode 100644 index 0000000..07f8591 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Searx/SearxUrlData.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class SearxUrlData +{ + [JsonPropertyName("title")] + public string Title { get; set; } = null!; + + [JsonPropertyName("url")] + public string Url { get; set; } = null!; + + [JsonPropertyName("official")] + public bool? Official { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/IYoutubeSearchService.cs b/src/EllieBot/Modules/Searches/Search/Youtube/IYoutubeSearchService.cs new file mode 100644 index 0000000..5b9bfab --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/IYoutubeSearchService.cs @@ -0,0 +1,6 @@ +namespace EllieBot.Modules.Searches.Youtube; + +public interface IYoutubeSearchService +{ + Task SearchAsync(string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/InvidiousSearchResponse.cs b/src/EllieBot/Modules/Searches/Search/Youtube/InvidiousSearchResponse.cs new file mode 100644 index 0000000..9951db8 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/InvidiousSearchResponse.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches; + +public sealed class InvidiousSearchResponse +{ + [JsonPropertyName("videoId")] + public string VideoId { get; set; } = null!; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/InvidiousYtSearchService.cs b/src/EllieBot/Modules/Searches/Search/Youtube/InvidiousYtSearchService.cs new file mode 100644 index 0000000..6fc8bac --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/InvidiousYtSearchService.cs @@ -0,0 +1,46 @@ +using EllieBot.Modules.Searches.Youtube; +using System.Net.Http.Json; + +namespace EllieBot.Modules.Searches; + +public sealed class InvidiousYtSearchService : IYoutubeSearchService, IEService +{ + private readonly IHttpClientFactory _http; + private readonly SearchesConfigService _scs; + private readonly EllieRandom _rng; + + public InvidiousYtSearchService( + IHttpClientFactory http, + SearchesConfigService scs) + { + _http = http; + _scs = scs; + _rng = new(); + } + + public async Task SearchAsync(string query) + { + ArgumentNullException.ThrowIfNull(query); + + var instances = _scs.Data.InvidiousInstances; + if (instances is null or { Count: 0 }) + { + Log.Warning("Attempted to use Invidious as the .youtube provider but there are no 'invidiousInstances' " + + "specified in `data/searches.yml`"); + return null; + } + + var instance = instances[_rng.Next(0, instances.Count)]; + + using var http = _http.CreateClient(); + var res = await http.GetFromJsonAsync>( + $"{instance}/api/v1/search" + + $"?q={query}" + + $"&type=video"); + + if (res is null or {Count: 0}) + return null; + + return new VideoInfo(res[0].VideoId); + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/VideoInfo.cs b/src/EllieBot/Modules/Searches/Search/Youtube/VideoInfo.cs new file mode 100644 index 0000000..5f53b9b --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/VideoInfo.cs @@ -0,0 +1,9 @@ +namespace EllieBot.Modules.Searches.Youtube; + +public readonly struct VideoInfo +{ + public VideoInfo(string videoId) + => Url = $"https://youtube.com/watch?v={videoId}"; + + public string Url { get; init; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/YoutubeDataApiSearchService.cs b/src/EllieBot/Modules/Searches/Search/Youtube/YoutubeDataApiSearchService.cs new file mode 100644 index 0000000..e8bfcd2 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/YoutubeDataApiSearchService.cs @@ -0,0 +1,26 @@ +namespace EllieBot.Modules.Searches.Youtube; + +public sealed class YoutubeDataApiSearchService : IYoutubeSearchService, IEService +{ + private readonly IGoogleApiService _gapi; + + public YoutubeDataApiSearchService(IGoogleApiService gapi) + { + _gapi = gapi; + } + + public async Task SearchAsync(string query) + { + ArgumentNullException.ThrowIfNull(query); + + var results = await _gapi.GetVideoLinksByKeywordAsync(query); + var first = results.FirstOrDefault(); + if (first is null) + return null; + + return new() + { + Url = first + }; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/YtdlYoutubeSearchService.cs b/src/EllieBot/Modules/Searches/Search/Youtube/YtdlYoutubeSearchService.cs new file mode 100644 index 0000000..3ac59f8 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/YtdlYoutubeSearchService.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches.Youtube; + +public sealed class YtdlYoutubeSearchService : YoutubedlxServiceBase, IEService +{ + public override async Task SearchAsync(string query) + => await InternalGetInfoAsync(query, false); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/YtdlpYoutubeSearchService.cs b/src/EllieBot/Modules/Searches/Search/Youtube/YtdlpYoutubeSearchService.cs new file mode 100644 index 0000000..d7e66fa --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/YtdlpYoutubeSearchService.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches.Youtube; + +public sealed class YtdlpYoutubeSearchService : YoutubedlxServiceBase, IEService +{ + public override async Task SearchAsync(string query) + => await InternalGetInfoAsync(query, true); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Search/Youtube/YtdlxServiceBase.cs b/src/EllieBot/Modules/Searches/Search/Youtube/YtdlxServiceBase.cs new file mode 100644 index 0000000..6239bdd --- /dev/null +++ b/src/EllieBot/Modules/Searches/Search/Youtube/YtdlxServiceBase.cs @@ -0,0 +1,34 @@ +namespace EllieBot.Modules.Searches.Youtube; + +public abstract class YoutubedlxServiceBase : IYoutubeSearchService +{ + private YtdlOperation CreateYtdlOp(bool isYtDlp) + => new YtdlOperation("-4 " + + "--geo-bypass " + + "--encoding UTF8 " + + "--get-id " + + "--no-check-certificate " + + "--default-search " + + "\"ytsearch:\" -- \"{0}\"", + isYtDlp: isYtDlp); + + protected async Task InternalGetInfoAsync(string query, bool isYtDlp) + { + var op = CreateYtdlOp(isYtDlp); + var data = await op.GetDataAsync(query); + var items = data?.Split('\n'); + if (items is null or { Length: 0 }) + return null; + + var id = items.FirstOrDefault(x => x.Length is > 5 and < 15); + if (id is null) + return null; + + return new VideoInfo() + { + Url = $"https://youtube.com/watch?v={id}" + }; + } + + public abstract Task SearchAsync(string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Searches.cs b/src/EllieBot/Modules/Searches/Searches.cs new file mode 100644 index 0000000..04050e6 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Searches.cs @@ -0,0 +1,600 @@ +#nullable disable +using Microsoft.Extensions.Caching.Memory; +using EllieBot.Modules.Searches.Common; +using EllieBot.Modules.Searches.Services; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System.Diagnostics.CodeAnalysis; +using System.Net; +using System.Net.Http.Json; +using Color = SixLabors.ImageSharp.Color; + +namespace EllieBot.Modules.Searches; + +public partial class Searches : EllieModule +{ + private static readonly ConcurrentDictionary _cachedShortenedLinks = new(); + private readonly IBotCredentials _creds; + private readonly IGoogleApiService _google; + private readonly IHttpClientFactory _httpFactory; + private readonly IMemoryCache _cache; + private readonly ITimezoneService _tzSvc; + + public Searches( + IBotCredentials creds, + IGoogleApiService google, + IHttpClientFactory factory, + IMemoryCache cache, + ITimezoneService tzSvc) + { + _creds = creds; + _google = google; + _httpFactory = factory; + _cache = cache; + _tzSvc = tzSvc; + } + + [Cmd] + public async Task Rip([Leftover] IGuildUser usr) + { + var av = usr.RealAvatarUrl(); + await using var picStream = await _service.GetRipPictureAsync(usr.Nickname ?? usr.Username, av); + await ctx.Channel.SendFileAsync(picStream, + "rip.png", + $"Rip {Format.Bold(usr.ToString())} \n\t- " + Format.Italics(ctx.User.ToString())); + } + + [Cmd] + public async Task Weather([Leftover] string query) + { + if (!await ValidateQuery(query)) + return; + + var embed = _sender.CreateEmbed(); + var data = await _service.GetWeatherDataAsync(query); + + if (data is null) + embed.WithDescription(GetText(strs.city_not_found)).WithErrorColor(); + else + { + var f = StandardConversions.CelsiusToFahrenheit; + + var tz = _tzSvc.GetTimeZoneOrUtc(ctx.Guild?.Id); + var sunrise = data.Sys.Sunrise.ToUnixTimestamp(); + var sunset = data.Sys.Sunset.ToUnixTimestamp(); + sunrise = sunrise.ToOffset(tz.GetUtcOffset(sunrise)); + sunset = sunset.ToOffset(tz.GetUtcOffset(sunset)); + var timezone = $"UTC{sunrise:zzz}"; + + embed + .AddField("🌍 " + Format.Bold(GetText(strs.location)), + $"[{data.Name + ", " + data.Sys.Country}](https://openweathermap.org/city/{data.Id})", + true) + .AddField("📏 " + Format.Bold(GetText(strs.latlong)), $"{data.Coord.Lat}, {data.Coord.Lon}", true) + .AddField("☁ " + Format.Bold(GetText(strs.condition)), + string.Join(", ", data.Weather.Select(w => w.Main)), + true) + .AddField("😓 " + Format.Bold(GetText(strs.humidity)), $"{data.Main.Humidity}%", true) + .AddField("💨 " + Format.Bold(GetText(strs.wind_speed)), data.Wind.Speed + " m/s", true) + .AddField("🌡 " + Format.Bold(GetText(strs.temperature)), + $"{data.Main.Temp:F1}°C / {f(data.Main.Temp):F1}°F", + true) + .AddField("🔆 " + Format.Bold(GetText(strs.min_max)), + $"{data.Main.TempMin:F1}°C - {data.Main.TempMax:F1}°C\n{f(data.Main.TempMin):F1}°F - {f(data.Main.TempMax):F1}°F", + true) + .AddField("🌄 " + Format.Bold(GetText(strs.sunrise)), $"{sunrise:HH:mm} {timezone}", true) + .AddField("🌇 " + Format.Bold(GetText(strs.sunset)), $"{sunset:HH:mm} {timezone}", true) + .WithOkColor() + .WithFooter("Powered by openweathermap.org", + $"https://openweathermap.org/img/w/{data.Weather[0].Icon}.png"); + } + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + public async Task Time([Leftover] string query) + { + if (!await ValidateQuery(query)) + return; + + await ctx.Channel.TriggerTypingAsync(); + + var (data, err) = await _service.GetTimeDataAsync(query); + if (err is not null) + { + LocStr errorKey; + switch (err) + { + case TimeErrors.ApiKeyMissing: + errorKey = strs.api_key_missing; + break; + case TimeErrors.InvalidInput: + errorKey = strs.invalid_input; + break; + case TimeErrors.NotFound: + errorKey = strs.not_found; + break; + default: + errorKey = strs.error_occured; + break; + } + + await Response().Error(errorKey).SendAsync(); + return; + } + + if (string.IsNullOrWhiteSpace(data.TimeZoneName)) + { + await Response().Error(strs.timezone_db_api_key).SendAsync(); + return; + } + + var eb = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.time_new)) + .WithDescription(Format.Code(data.Time.ToString(Culture))) + .AddField(GetText(strs.location), string.Join('\n', data.Address.Split(", ")), true) + .AddField(GetText(strs.timezone), data.TimeZoneName, true); + + await Response().Embed(eb).SendAsync(); + } + + [Cmd] + public async Task Movie([Leftover] string query = null) + { + if (!await ValidateQuery(query)) + return; + + await ctx.Channel.TriggerTypingAsync(); + + var movie = await _service.GetMovieDataAsync(query); + if (movie is null) + { + await Response().Error(strs.imdb_fail).SendAsync(); + return; + } + + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(movie.Title) + .WithUrl($"https://www.imdb.com/title/{movie.ImdbId}/") + .WithDescription(movie.Plot.TrimTo(1000)) + .AddField("Rating", movie.ImdbRating, true) + .AddField("Genre", movie.Genre, true) + .AddField("Year", movie.Year, true) + .WithImageUrl(movie.Poster)) + .SendAsync(); + } + + [Cmd] + public Task RandomCat() + => InternalRandomImage(SearchesService.ImageTag.Cats); + + [Cmd] + public Task RandomDog() + => InternalRandomImage(SearchesService.ImageTag.Dogs); + + [Cmd] + public Task RandomFood() + => InternalRandomImage(SearchesService.ImageTag.Food); + + [Cmd] + public Task RandomBird() + => InternalRandomImage(SearchesService.ImageTag.Birds); + + private Task InternalRandomImage(SearchesService.ImageTag tag) + { + var url = _service.GetRandomImageUrl(tag); + return Response().Embed(_sender.CreateEmbed().WithOkColor().WithImageUrl(url)).SendAsync(); + } + + [Cmd] + public async Task Lmgtfy([Leftover] string ffs = null) + { + if (!await ValidateQuery(ffs)) + return; + + var shortenedUrl = await _google.ShortenUrl($"https://letmegooglethat.com/?q={Uri.EscapeDataString(ffs)}"); + await Response().Confirm($"<{shortenedUrl}>").SendAsync(); + } + + [Cmd] + public async Task Shorten([Leftover] string query) + { + if (!await ValidateQuery(query)) + return; + + query = query.Trim(); + if (!_cachedShortenedLinks.TryGetValue(query, out var shortLink)) + { + try + { + using var http = _httpFactory.CreateClient(); + using var req = new HttpRequestMessage(HttpMethod.Post, "https://goolnk.com/api/v1/shorten"); + var formData = new MultipartFormDataContent + { + { new StringContent(query), "url" } + }; + req.Content = formData; + + using var res = await http.SendAsync(req); + var content = await res.Content.ReadAsStringAsync(); + var data = JsonConvert.DeserializeObject(content); + + if (!string.IsNullOrWhiteSpace(data?.ResultUrl)) + _cachedShortenedLinks.TryAdd(query, data.ResultUrl); + else + return; + + shortLink = data.ResultUrl; + } + catch (Exception ex) + { + Log.Error(ex, "Error shortening a link: {Message}", ex.Message); + return; + } + } + + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .AddField(GetText(strs.original_url), $"<{query}>") + .AddField(GetText(strs.short_url), $"<{shortLink}>")) + .SendAsync(); + } + + [Cmd] + public async Task MagicTheGathering([Leftover] string search) + { + if (!await ValidateQuery(search)) + return; + + await ctx.Channel.TriggerTypingAsync(); + var card = await _service.GetMtgCardAsync(search); + + if (card is null) + { + await Response().Error(strs.card_not_found).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithTitle(card.Name) + .WithDescription(card.Description) + .WithImageUrl(card.ImageUrl) + .AddField(GetText(strs.store_url), card.StoreUrl, true) + .AddField(GetText(strs.cost), card.ManaCost, true) + .AddField(GetText(strs.types), card.Types, true); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + public async Task Hearthstone([Leftover] string name) + { + if (!await ValidateQuery(name)) + return; + + if (string.IsNullOrWhiteSpace(_creds.RapidApiKey)) + { + await Response().Error(strs.mashape_api_missing).SendAsync(); + return; + } + + await ctx.Channel.TriggerTypingAsync(); + var card = await _service.GetHearthstoneCardDataAsync(name); + + if (card is null) + { + await Response().Error(strs.card_not_found).SendAsync(); + return; + } + + var embed = _sender.CreateEmbed().WithOkColor().WithImageUrl(card.Img); + + if (!string.IsNullOrWhiteSpace(card.Flavor)) + embed.WithDescription(card.Flavor); + + await Response().Embed(embed).SendAsync(); + } + + [Cmd] + public async Task UrbanDict([Leftover] string query = null) + { + if (!await ValidateQuery(query)) + return; + + await ctx.Channel.TriggerTypingAsync(); + using (var http = _httpFactory.CreateClient()) + { + var res = await http.GetStringAsync( + $"https://api.urbandictionary.com/v0/define?term={Uri.EscapeDataString(query)}"); + try + { + var allItems = JsonConvert.DeserializeObject(res).List; + if (allItems.Any()) + { + await Response() + .Paginated() + .Items(allItems) + .PageSize(1) + .CurrentPage(0) + .Page((items, _) => + { + var item = items[0]; + return _sender.CreateEmbed() + .WithOkColor() + .WithUrl(item.Permalink) + .WithTitle(item.Word) + .WithDescription(item.Definition); + }) + .SendAsync(); + return; + } + } + catch + { + } + } + + await Response().Error(strs.ud_error).SendAsync(); + } + + [Cmd] + public async Task Define([Leftover] string word) + { + if (!await ValidateQuery(word)) + return; + + using var http = _httpFactory.CreateClient(); + string res; + try + { + res = await _cache.GetOrCreateAsync($"define_{word}", + e => + { + e.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12); + return http.GetStringAsync("https://api.pearson.com/v2/dictionaries/entries?headword=" + + WebUtility.UrlEncode(word)); + }); + + var responseModel = JsonConvert.DeserializeObject(res); + + var data = responseModel.Results + .Where(x => x.Senses is not null + && x.Senses.Count > 0 + && x.Senses[0].Definition is not null) + .Select(x => (Sense: x.Senses[0], x.PartOfSpeech)) + .ToList(); + + if (!data.Any()) + { + Log.Warning("Definition not found: {Word}", word); + await Response().Error(strs.define_unknown).SendAsync(); + } + + + var col = data.Select(x => ( + Definition: x.Sense.Definition is string + ? x.Sense.Definition.ToString() + : ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(), + Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0 + ? string.Empty + : x.Sense.Examples[0].Text, Word: word, + WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech)) + .ToList(); + + Log.Information("Sending {Count} definition for: {Word}", col.Count, word); + + await Response() + .Paginated() + .Items(col) + .PageSize(1) + .Page((items, _) => + { + var model = items.First(); + var embed = _sender.CreateEmbed() + .WithDescription(ctx.User.Mention) + .AddField(GetText(strs.word), model.Word, true) + .AddField(GetText(strs._class), model.WordType, true) + .AddField(GetText(strs.definition), model.Definition) + .WithOkColor(); + + if (!string.IsNullOrWhiteSpace(model.Example)) + embed.AddField(GetText(strs.example), model.Example); + + return embed; + }) + .SendAsync(); + } + catch (Exception ex) + { + Log.Error(ex, "Error retrieving definition data for: {Word}", word); + } + } + + [Cmd] + public async Task Catfact() + { + using var http = _httpFactory.CreateClient(); + var response = await http.GetStringAsync("https://catfact.ninja/fact"); + + var fact = JObject.Parse(response)["fact"].ToString(); + await Response().Confirm("🐈" + GetText(strs.catfact), fact).SendAsync(); + } + + [Cmd] + public async Task Wiki([Leftover] string query = null) + { + query = query?.Trim(); + + if (!await ValidateQuery(query)) + return; + + using var http = _httpFactory.CreateClient(); + var result = await http.GetStringAsync( + "https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + + Uri.EscapeDataString(query)); + var data = JsonConvert.DeserializeObject(result); + if (data.Query.Pages[0].Missing || string.IsNullOrWhiteSpace(data.Query.Pages[0].FullUrl)) + await Response().Error(strs.wiki_page_not_found).SendAsync(); + else + await Response().Text(data.Query.Pages[0].FullUrl).SendAsync(); + } + + [Cmd] + public async Task Color(params Color[] colors) + { + if (!colors.Any()) + return; + + var colorObjects = colors.Take(10).ToArray(); + + using var img = new Image(colorObjects.Length * 50, 50); + for (var i = 0; i < colorObjects.Length; i++) + { + var x = i * 50; + img.Mutate(m => m.FillPolygon(colorObjects[i], new(x, 0), new(x + 50, 0), new(x + 50, 50), new(x, 50))); + } + + await using var ms = img.ToStream(); + await ctx.Channel.SendFileAsync(ms, "colors.png"); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Avatar([Leftover] IGuildUser usr = null) + { + if (usr is null) + usr = (IGuildUser)ctx.User; + + var avatarUrl = usr.RealAvatarUrl(2048); + + await Response() + .Embed( + _sender.CreateEmbed() + .WithOkColor() + .AddField("Username", usr.ToString()) + .AddField("Avatar Url", avatarUrl) + .WithThumbnailUrl(avatarUrl.ToString())) + .SendAsync(); + } + + [Cmd] + public async Task Wikia(string target, [Leftover] string query) + { + if (string.IsNullOrWhiteSpace(target) || string.IsNullOrWhiteSpace(query)) + { + await Response().Error(strs.wikia_input_error).SendAsync(); + return; + } + + await ctx.Channel.TriggerTypingAsync(); + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Clear(); + try + { + var res = await http.GetStringAsync($"https://{Uri.EscapeDataString(target)}.fandom.com/api.php" + + "?action=query" + + "&format=json" + + "&list=search" + + $"&srsearch={Uri.EscapeDataString(query)}" + + "&srlimit=1"); + var items = JObject.Parse(res); + var title = items["query"]?["search"]?.FirstOrDefault()?["title"]?.ToString(); + + if (string.IsNullOrWhiteSpace(title)) + { + await Response().Error(strs.wikia_error).SendAsync(); + return; + } + + var url = Uri.EscapeDataString($"https://{target}.fandom.com/wiki/{title}"); + var response = $@"`{GetText(strs.title)}` {title.SanitizeMentions()} +`{GetText(strs.url)}:` {url}"; + await Response().Text(response).SendAsync(); + } + catch + { + await Response().Error(strs.wikia_error).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Bible(string book, string chapterAndVerse) + { + var obj = new BibleVerses(); + try + { + using var http = _httpFactory.CreateClient(); + obj = await http.GetFromJsonAsync($"https://bible-api.com/{book} {chapterAndVerse}"); + } + catch + { + } + + if (obj.Error is not null || obj.Verses is null || obj.Verses.Length == 0) + await Response().Error(obj.Error ?? "No verse found.").SendAsync(); + else + { + var v = obj.Verses[0]; + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}") + .WithDescription(v.Text)) + .SendAsync(); + } + } + + [Cmd] + public async Task Steam([Leftover] string query) + { + if (string.IsNullOrWhiteSpace(query)) + return; + + await ctx.Channel.TriggerTypingAsync(); + + var appId = await _service.GetSteamAppIdByName(query); + if (appId == -1) + { + await Response().Error(strs.not_found).SendAsync(); + return; + } + + //var embed = _sender.CreateEmbed() + // .WithOkColor() + // .WithDescription(gameData.ShortDescription) + // .WithTitle(gameData.Name) + // .WithUrl(gameData.Link) + // .WithImageUrl(gameData.HeaderImage) + // .AddField(GetText(strs.genres), gameData.TotalEpisodes.ToString(), true) + // .AddField(GetText(strs.price), gameData.IsFree ? GetText(strs.FREE) : game, true) + // .AddField(GetText(strs.links), gameData.GetGenresString(), true) + // .WithFooter(GetText(strs.recommendations(gameData.TotalRecommendations))); + await Response().Text($"https://store.steampowered.com/app/{appId}").SendAsync(); + } + + private async Task ValidateQuery([MaybeNullWhen(false)] string query) + { + if (!string.IsNullOrWhiteSpace(query)) + return true; + + await Response().Error(strs.specify_search_params).SendAsync(); + return false; + } + + public class ShortenData + { + [JsonProperty("result_url")] + public string ResultUrl { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/SearchesService.cs b/src/EllieBot/Modules/Searches/SearchesService.cs new file mode 100644 index 0000000..f5e3be4 --- /dev/null +++ b/src/EllieBot/Modules/Searches/SearchesService.cs @@ -0,0 +1,457 @@ +#nullable disable +using EllieBot.Modules.Searches.Common; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using Color = SixLabors.ImageSharp.Color; +using Image = SixLabors.ImageSharp.Image; + +namespace EllieBot.Modules.Searches.Services; + +public class SearchesService : IEService +{ + public enum ImageTag + { + Food, + Dogs, + Cats, + Birds + } + + public List WowJokes { get; } = []; + public List MagicItems { get; } = []; + private readonly IHttpClientFactory _httpFactory; + private readonly IGoogleApiService _google; + private readonly IImageCache _imgs; + private readonly IBotCache _c; + private readonly FontProvider _fonts; + private readonly IBotCredsProvider _creds; + private readonly EllieRandom _rng; + private readonly List _yomamaJokes; + + private readonly object _yomamaLock = new(); + private int yomamaJokeIndex; + + public SearchesService( + IGoogleApiService google, + IImageCache images, + IBotCache c, + IHttpClientFactory factory, + FontProvider fonts, + IBotCredsProvider creds) + { + _httpFactory = factory; + _google = google; + _imgs = images; + _c = c; + _fonts = fonts; + _creds = creds; + _rng = new(); + + //joke commands + if (File.Exists("data/wowjokes.json")) + WowJokes = JsonConvert.DeserializeObject>(File.ReadAllText("data/wowjokes.json")); + else + Log.Warning("data/wowjokes.json is missing. WOW Jokes are not loaded"); + + if (File.Exists("data/magicitems.json")) + MagicItems = JsonConvert.DeserializeObject>(File.ReadAllText("data/magicitems.json")); + else + Log.Warning("data/magicitems.json is missing. Magic items are not loaded"); + + if (File.Exists("data/yomama.txt")) + _yomamaJokes = File.ReadAllLines("data/yomama.txt").Shuffle().ToList(); + else + { + _yomamaJokes = []; + Log.Warning("data/yomama.txt is missing. .yomama command won't work"); + } + } + + public async Task GetRipPictureAsync(string text, Uri imgUrl) + => (await GetRipPictureFactory(text, imgUrl)).ToStream(); + + private void DrawAvatar(Image bg, Image avatarImage) + => bg.Mutate(x => x.Grayscale().DrawImage(avatarImage, new(83, 139), new GraphicsOptions())); + + public async Task GetRipPictureFactory(string text, Uri avatarUrl) + { + using var bg = Image.Load(await _imgs.GetRipBgAsync()); + var result = await _c.GetImageDataAsync(avatarUrl); + if (!result.TryPickT0(out var data, out _)) + { + using var http = _httpFactory.CreateClient(); + data = await http.GetByteArrayAsync(avatarUrl); + using (var avatarImg = Image.Load(data)) + { + avatarImg.Mutate(x => x.Resize(85, 85).ApplyRoundedCorners(42)); + await using var avStream = await avatarImg.ToStreamAsync(); + data = avStream.ToArray(); + DrawAvatar(bg, avatarImg); + } + + await _c.SetImageDataAsync(avatarUrl, data); + } + else + { + using var avatarImg = Image.Load(data); + DrawAvatar(bg, avatarImg); + } + + bg.Mutate(x => x.DrawText( + new TextOptions(_fonts.RipFont) + { + HorizontalAlignment = HorizontalAlignment.Center, + FallbackFontFamilies = _fonts.FallBackFonts, + Origin = new(bg.Width / 2, 225), + }, + text, + Color.Black)); + + //flowa + using (var flowers = Image.Load(await _imgs.GetRipOverlayAsync())) + { + bg.Mutate(x => x.DrawImage(flowers, new(0, 0), new GraphicsOptions())); + } + + await using var stream = bg.ToStream(); + return stream.ToArray(); + } + + public async Task GetWeatherDataAsync(string query) + { + query = query.Trim().ToLowerInvariant(); + + return await _c.GetOrAddAsync(new($"ellie_weather_{query}"), + async () => await GetWeatherDataFactory(query), + TimeSpan.FromHours(3)); + } + + private async Task GetWeatherDataFactory(string query) + { + using var http = _httpFactory.CreateClient(); + try + { + var data = await http.GetStringAsync("https://api.openweathermap.org/data/2.5/weather?" + + $"q={query}&" + + "appid=42cd627dd60debf25a5739e50a217d74&" + + "units=metric"); + + if (string.IsNullOrWhiteSpace(data)) + return null; + + return JsonConvert.DeserializeObject(data); + } + catch (Exception ex) + { + Log.Warning(ex, "Error getting weather data"); + return null; + } + } + + public Task<((string Address, DateTime Time, string TimeZoneName), TimeErrors?)> GetTimeDataAsync(string arg) + => GetTimeDataFactory(arg); + + //return _cache.GetOrAddCachedDataAsync($"ellie_time_{arg}", + // GetTimeDataFactory, + // arg, + // TimeSpan.FromMinutes(1)); + private async Task<((string Address, DateTime Time, string TimeZoneName), TimeErrors?)> GetTimeDataFactory( + string query) + { + query = query.Trim(); + + if (string.IsNullOrEmpty(query)) + return (default, TimeErrors.InvalidInput); + + + var locIqKey = _creds.GetCreds().LocationIqApiKey; + var tzDbKey = _creds.GetCreds().TimezoneDbApiKey; + if (string.IsNullOrWhiteSpace(locIqKey) || string.IsNullOrWhiteSpace(tzDbKey)) + return (default, TimeErrors.ApiKeyMissing); + + try + { + using var http = _httpFactory.CreateClient(); + var res = await _c.GetOrAddAsync(new($"searches:geo:{query}"), + async () => + { + var url = "https://eu1.locationiq.com/v1/search.php?" + + (string.IsNullOrWhiteSpace(locIqKey) + ? "key=" + : $"key={locIqKey}&") + + $"q={Uri.EscapeDataString(query)}&" + + "format=json"; + + var res = await http.GetStringAsync(url); + return res; + }, + TimeSpan.FromHours(1)); + + var responses = JsonConvert.DeserializeObject(res); + if (responses is null || responses.Length == 0) + { + Log.Warning("Geocode lookup failed for: {Query}", query); + return (default, TimeErrors.NotFound); + } + + var geoData = responses[0]; + + using var req = new HttpRequestMessage(HttpMethod.Get, + "http://api.timezonedb.com/v2.1/get-time-zone?" + + $"key={tzDbKey}" + + $"&format=json" + + $"&by=position" + + $"&lat={geoData.Lat}" + + $"&lng={geoData.Lon}"); + + using var geoRes = await http.SendAsync(req); + var resString = await geoRes.Content.ReadAsStringAsync(); + var timeObj = JsonConvert.DeserializeObject(resString); + + var time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timeObj.Timestamp); + + return ((Address: responses[0].DisplayName, Time: time, TimeZoneName: timeObj.TimezoneName), default); + } + catch (Exception ex) + { + Log.Error(ex, "Weather error: {Message}", ex.Message); + return (default, TimeErrors.NotFound); + } + } + + public string GetRandomImageUrl(ImageTag tag) + { + var subpath = tag.ToString().ToLowerInvariant(); + + var max = tag switch + { + ImageTag.Food => 773, + ImageTag.Dogs => 750, + ImageTag.Cats => 773, + ImageTag.Birds => 578, + _ => 100, + }; + + + return $"https://nadeko-pictures.nyc3.digitaloceanspaces.com/{subpath}/" + + _rng.Next(1, max).ToString("000") + + ".png"; + } + + public Task GetYomamaJoke() + { + string joke; + lock (_yomamaLock) + { + if (yomamaJokeIndex >= _yomamaJokes.Count) + { + yomamaJokeIndex = 0; + var newList = _yomamaJokes.ToList(); + _yomamaJokes.Clear(); + _yomamaJokes.AddRange(newList.Shuffle()); + } + + joke = _yomamaJokes[yomamaJokeIndex++]; + } + + return Task.FromResult(joke); + + // using (var http = _httpFactory.CreateClient()) + // { + // var response = await http.GetStringAsync(new Uri("http://api.yomomma.info/")); + // return JObject.Parse(response)["joke"].ToString() + " 😆"; + // } + } + + public async Task<(string Setup, string Punchline)> GetRandomJoke() + { + using var http = _httpFactory.CreateClient(); + var res = await http.GetStringAsync("https://official-joke-api.appspot.com/random_joke"); + var resObj = JsonConvert.DeserializeAnonymousType(res, + new + { + setup = "", + punchline = "" + }); + return (resObj.setup, resObj.punchline); + } + + public async Task GetChuckNorrisJoke() + { + using var http = _httpFactory.CreateClient(); + var response = await http.GetStringAsync(new Uri("https://api.chucknorris.io/jokes/random")); + return JObject.Parse(response)["value"] + " 😆"; + } + + public async Task GetMtgCardAsync(string search) + { + search = search.Trim().ToLowerInvariant(); + var data = await _c.GetOrAddAsync(new($"mtg:{search}"), + async () => await GetMtgCardFactory(search), + TimeSpan.FromDays(1)); + + if (data is null || data.Length == 0) + return null; + + return data[_rng.Next(0, data.Length)]; + } + + private async Task GetMtgCardFactory(string search) + { + async Task GetMtgDataAsync(MtgResponse.Data card) + { + string storeUrl; + try + { + storeUrl = await _google.ShortenUrl("https://shop.tcgplayer.com/productcatalog/product/show?" + + "newSearch=false&" + + "ProductType=All&" + + "IsProductNameExact=false&" + + $"ProductName={Uri.EscapeDataString(card.Name)}"); + } + catch { storeUrl = ""; } + + return new() + { + Description = card.Text, + Name = card.Name, + ImageUrl = card.ImageUrl, + StoreUrl = storeUrl, + Types = string.Join(",\n", card.Types), + ManaCost = card.ManaCost + }; + } + + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Clear(); + var response = + await http.GetStringAsync($"https://api.magicthegathering.io/v1/cards?name={Uri.EscapeDataString(search)}"); + + var responseObject = JsonConvert.DeserializeObject(response); + if (responseObject is null) + return Array.Empty(); + + var cards = responseObject.Cards.Take(5).ToArray(); + if (cards.Length == 0) + return Array.Empty(); + + return await cards.Select(GetMtgDataAsync).WhenAll(); + } + + public async Task GetHearthstoneCardDataAsync(string name) + { + name = name.ToLowerInvariant(); + return await _c.GetOrAddAsync($"hearthstone:{name}", + () => HearthstoneCardDataFactory(name), + TimeSpan.FromDays(1)); + } + + private async Task HearthstoneCardDataFactory(string name) + { + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Clear(); + http.DefaultRequestHeaders.Add("x-rapidapi-key", _creds.GetCreds().RapidApiKey); + try + { + var response = await http.GetStringAsync("https://omgvamp-hearthstone-v1.p.rapidapi.com/" + + $"cards/search/{Uri.EscapeDataString(name)}"); + var objs = JsonConvert.DeserializeObject(response); + if (objs is null || objs.Length == 0) + return null; + var data = objs.FirstOrDefault(x => x.Collectible) + ?? objs.FirstOrDefault(x => !string.IsNullOrEmpty(x.PlayerClass)) ?? objs.FirstOrDefault(); + if (data is null) + return null; + if (!string.IsNullOrWhiteSpace(data.Img)) + data.Img = await _google.ShortenUrl(data.Img); + // if (!string.IsNullOrWhiteSpace(data.Text)) + // { + // var converter = new Converter(); + // data.Text = converter.Convert(data.Text); + // } + + return data; + } + catch (Exception ex) + { + Log.Error(ex, "Error getting Hearthstone Card: {ErrorMessage}", ex.Message); + return null; + } + } + + public async Task GetMovieDataAsync(string name) + { + name = name.Trim().ToLowerInvariant(); + return await _c.GetOrAddAsync(new($"movie:{name}"), + () => GetMovieDataFactory(name), + TimeSpan.FromDays(1)); + } + + private async Task GetMovieDataFactory(string name) + { + using var http = _httpFactory.CreateClient(); + var res = await http.GetStringAsync(string.Format("https://omdbapi.nadeko.bot/" + + "?t={0}" + + "&y=" + + "&plot=full" + + "&r=json", + name.Trim().Replace(' ', '+'))); + var movie = JsonConvert.DeserializeObject(res); + if (movie?.Title is null) + return null; + movie.Poster = await _google.ShortenUrl(movie.Poster); + return movie; + } + + public async Task GetSteamAppIdByName(string query) + { + const string steamGameIdsKey = "steam_names_to_appid"; + + var gamesMap = await _c.GetOrAddAsync(new(steamGameIdsKey), + async () => + { + using var http = _httpFactory.CreateClient(); + + // https://api.steampowered.com/ISteamApps/GetAppList/v2/ + var gamesStr = await http.GetStringAsync("https://api.steampowered.com/ISteamApps/GetAppList/v2/"); + var apps = JsonConvert + .DeserializeAnonymousType(gamesStr, + new + { + applist = new + { + apps = new List() + } + })! + .applist.apps; + + return apps.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(x => x.Name) + .ToDictionary(x => x.Key, x => x.First().AppId); + }, + TimeSpan.FromHours(24)); + + if (gamesMap is null) + return -1; + + query = query.Trim(); + + var keyList = gamesMap.Keys.ToList(); + + var key = keyList.FirstOrDefault(x => x.Equals(query, StringComparison.OrdinalIgnoreCase)); + + if (key == default) + { + key = keyList.FirstOrDefault(x => x.StartsWith(query, StringComparison.OrdinalIgnoreCase)); + if (key == default) + return -1; + } + + return gamesMap[key]; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs b/src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs new file mode 100644 index 0000000..46f9ed6 --- /dev/null +++ b/src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationCommands.cs @@ -0,0 +1,211 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Searches.Services; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class StreamNotificationCommands : EllieModule + { + private readonly DbService _db; + + public StreamNotificationCommands(DbService db) + => _db = db; + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task StreamAdd(string link) + { + var data = await _service.FollowStream(ctx.Guild.Id, ctx.Channel.Id, link); + if (data is null) + { + await Response().Error(strs.stream_not_added).SendAsync(); + return; + } + + var embed = _service.GetEmbed(ctx.Guild.Id, data); + await Response() + .Embed(embed) + .Text(strs.stream_tracked) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + [Priority(1)] + public async Task StreamRemove(int index) + { + if (--index < 0) + return; + + var fs = await _service.UnfollowStreamAsync(ctx.Guild.Id, index); + if (fs is null) + { + await Response().Error(strs.stream_no).SendAsync(); + return; + } + + await Response().Confirm(strs.stream_removed(Format.Bold(fs.Username), fs.Type)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + public async Task StreamsClear() + { + await _service.ClearAllStreams(ctx.Guild.Id); + await Response().Confirm(strs.streams_cleared).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task StreamList(int page = 1) + { + if (page-- < 1) + return; + + var allStreams = new List(); + await using (var uow = _db.GetDbContext()) + { + var all = uow.GuildConfigsForId(ctx.Guild.Id, set => set.Include(gc => gc.FollowedStreams)) + .FollowedStreams.OrderBy(x => x.Id) + .ToList(); + + for (var index = all.Count - 1; index >= 0; index--) + { + var fs = all[index]; + if (((SocketGuild)ctx.Guild).GetTextChannel(fs.ChannelId) is null) + await _service.UnfollowStreamAsync(fs.GuildId, index); + else + allStreams.Insert(0, fs); + } + } + + await Response() + .Paginated() + .Items(allStreams) + .PageSize(12) + .CurrentPage(page) + .Page((elements, cur) => + { + if (elements.Count == 0) + return _sender.CreateEmbed().WithDescription(GetText(strs.streams_none)).WithErrorColor(); + + var eb = _sender.CreateEmbed().WithTitle(GetText(strs.streams_follow_title)).WithOkColor(); + for (var index = 0; index < elements.Count; index++) + { + var elem = elements[index]; + eb.AddField($"**#{index + 1 + (12 * cur)}** {elem.Username.ToLower()}", + $"【{elem.Type}】\n<#{elem.ChannelId}>\n{elem.Message?.TrimTo(50)}", + true); + } + + return eb; + }) + .SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task StreamOffline() + { + var newValue = _service.ToggleStreamOffline(ctx.Guild.Id); + if (newValue) + await Response().Confirm(strs.stream_off_enabled).SendAsync(); + else + await Response().Confirm(strs.stream_off_disabled).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task StreamOnlineDelete() + { + var newValue = _service.ToggleStreamOnlineDelete(ctx.Guild.Id); + if (newValue) + await Response().Confirm(strs.stream_online_delete_enabled).SendAsync(); + else + await Response().Confirm(strs.stream_online_delete_disabled).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task StreamMessage(int index, [Leftover] string message) + { + if (--index < 0) + return; + + var canMentionEveryone = (ctx.User as IGuildUser)?.GuildPermissions.MentionEveryone ?? true; + if (!canMentionEveryone) + message = message?.SanitizeAllMentions(); + + if (!_service.SetStreamMessage(ctx.Guild.Id, index, message, out var fs)) + { + await Response().Confirm(strs.stream_not_following).SendAsync(); + return; + } + + if (string.IsNullOrWhiteSpace(message)) + await Response().Confirm(strs.stream_message_reset(Format.Bold(fs.Username))).SendAsync(); + else + await Response().Confirm(strs.stream_message_set(Format.Bold(fs.Username))).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.ManageMessages)] + public async Task StreamMessageAll([Leftover] string message) + { + var canMentionEveryone = (ctx.User as IGuildUser)?.GuildPermissions.MentionEveryone ?? true; + if (!canMentionEveryone) + message = message?.SanitizeAllMentions(); + + var count = _service.SetStreamMessageForAll(ctx.Guild.Id, message); + + if (count == 0) + { + await Response().Confirm(strs.stream_not_following_any).SendAsync(); + return; + } + + await Response().Confirm(strs.stream_message_set_all(count)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task StreamCheck(string url) + { + try + { + var data = await _service.GetStreamDataAsync(url); + if (data is null) + { + await Response().Error(strs.no_channel_found).SendAsync(); + return; + } + + if (data.IsLive) + { + await Response() + .Confirm(strs.streamer_online(Format.Bold(data.Name), + Format.Bold(data.Viewers.ToString()))) + .SendAsync(); + } + else + await Response().Confirm(strs.streamer_offline(data.Name)).SendAsync(); + } + catch + { + await Response().Error(strs.no_channel_found).SendAsync(); + } + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationService.cs b/src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationService.cs new file mode 100644 index 0000000..c003366 --- /dev/null +++ b/src/EllieBot/Modules/Searches/StreamNotification/StreamNotificationService.cs @@ -0,0 +1,651 @@ +#nullable disable +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Db.Models; +using EllieBot.Modules.Searches.Common; +using EllieBot.Modules.Searches.Common.StreamNotifications; + +namespace EllieBot.Modules.Searches.Services; + +public sealed class StreamNotificationService : IEService, IReadyExecutor +{ + private readonly DbService _db; + private readonly IBotStrings _strings; + private readonly Random _rng = new EllieRandom(); + private readonly DiscordSocketClient _client; + private readonly NotifChecker _streamTracker; + + private readonly object _shardLock = new(); + + private readonly Dictionary> _trackCounter = new(); + + private readonly Dictionary>> _shardTrackedStreams; + private readonly ConcurrentHashSet _offlineNotificationServers; + private readonly ConcurrentHashSet _deleteOnOfflineServers; + + private readonly IPubSub _pubSub; + private readonly IMessageSenderService _sender; + private readonly SearchesConfigService _config; + private readonly IReplacementService _repSvc; + + public TypedKey> StreamsOnlineKey { get; } + public TypedKey> StreamsOfflineKey { get; } + + private readonly TypedKey _streamFollowKey; + private readonly TypedKey _streamUnfollowKey; + + public event Func< + FollowedStream.FType, + string, + IReadOnlyCollection<(ulong, ulong)>, + Task> OnlineMessagesSent = static delegate { return Task.CompletedTask; }; + + public StreamNotificationService( + DbService db, + DiscordSocketClient client, + IBotStrings strings, + IBotCredsProvider creds, + IHttpClientFactory httpFactory, + IBot bot, + IPubSub pubSub, + IMessageSenderService sender, + SearchesConfigService config, + IReplacementService repSvc) + { + _db = db; + _client = client; + _strings = strings; + _pubSub = pubSub; + _sender = sender; + _config = config; + _repSvc = repSvc; + + _streamTracker = new(httpFactory, creds); + + StreamsOnlineKey = new("streams.online"); + StreamsOfflineKey = new("streams.offline"); + + _streamFollowKey = new("stream.follow"); + _streamUnfollowKey = new("stream.unfollow"); + + using (var uow = db.GetDbContext()) + { + var ids = client.GetGuildIds(); + var guildConfigs = uow.Set() + .AsQueryable() + .Include(x => x.FollowedStreams) + .Where(x => ids.Contains(x.GuildId)) + .ToList(); + + _offlineNotificationServers = new(guildConfigs + .Where(gc => gc.NotifyStreamOffline) + .Select(x => x.GuildId) + .ToList()); + + _deleteOnOfflineServers = new(guildConfigs + .Where(gc => gc.DeleteStreamOnlineMessage) + .Select(x => x.GuildId) + .ToList()); + + var followedStreams = guildConfigs.SelectMany(x => x.FollowedStreams).ToList(); + + _shardTrackedStreams = followedStreams.GroupBy(x => new + { + x.Type, + Name = x.Username.ToLower() + }) + .ToList() + .ToDictionary( + x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()), + x => x.GroupBy(y => y.GuildId) + .ToDictionary(y => y.Key, + y => y.AsEnumerable().ToHashSet())); + + // shard 0 will keep track of when there are no more guilds which track a stream + if (client.ShardId == 0) + { + var allFollowedStreams = uow.Set().AsQueryable().ToList(); + + foreach (var fs in allFollowedStreams) + _streamTracker.AddLastData(fs.CreateKey(), null, false); + + _trackCounter = allFollowedStreams.GroupBy(x => new + { + x.Type, + Name = x.Username.ToLower() + }) + .ToDictionary(x => new StreamDataKey(x.Key.Type, x.Key.Name), + x => x.Select(fs => fs.GuildId).ToHashSet()); + } + } + + _pubSub.Sub(StreamsOfflineKey, HandleStreamsOffline); + _pubSub.Sub(StreamsOnlineKey, HandleStreamsOnline); + + if (client.ShardId == 0) + { + // only shard 0 will run the tracker, + // and then publish updates with redis to other shards + _streamTracker.OnStreamsOffline += OnStreamsOffline; + _streamTracker.OnStreamsOnline += OnStreamsOnline; + _ = _streamTracker.RunAsync(); + + _pubSub.Sub(_streamFollowKey, HandleFollowStream); + _pubSub.Sub(_streamUnfollowKey, HandleUnfollowStream); + } + + bot.JoinedGuild += ClientOnJoinedGuild; + client.LeftGuild += ClientOnLeftGuild; + } + + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + using var timer = new PeriodicTimer(TimeSpan.FromMinutes(30)); + while (await timer.WaitForNextTickAsync()) + { + try + { + var errorLimit = TimeSpan.FromHours(12); + var failingStreams = _streamTracker.GetFailingStreams(errorLimit, true).ToList(); + + if (!failingStreams.Any()) + continue; + + var deleteGroups = failingStreams.GroupBy(x => x.Type) + .ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList()); + + await using var uow = _db.GetDbContext(); + foreach (var kvp in deleteGroups) + { + Log.Information( + "Deleting {StreamCount} {Platform} streams because they've been erroring for more than {ErrorLimit}: {RemovedList}", + kvp.Value.Count, + kvp.Key, + errorLimit, + string.Join(", ", kvp.Value)); + + var toDelete = uow.Set() + .AsQueryable() + .Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username)) + .ToList(); + + uow.RemoveRange(toDelete); + await uow.SaveChangesAsync(); + + foreach (var loginToDelete in kvp.Value) + _streamTracker.UntrackStreamByKey(new(kvp.Key, loginToDelete)); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error cleaning up FollowedStreams"); + } + } + } + + /// + /// Handles follow stream pubs to keep the counter up to date. + /// When counter reaches 0, stream is removed from tracking because + /// that means no guilds are subscribed to that stream anymore + /// + private ValueTask HandleFollowStream(FollowStreamPubData info) + { + _streamTracker.AddLastData(info.Key, null, false); + lock (_shardLock) + { + var key = info.Key; + if (_trackCounter.ContainsKey(key)) + _trackCounter[key].Add(info.GuildId); + else + { + _trackCounter[key] = [info.GuildId]; + } + } + + return default; + } + + /// + /// Handles unfollow pubs to keep the counter up to date. + /// When counter reaches 0, stream is removed from tracking because + /// that means no guilds are subscribed to that stream anymore + /// + private ValueTask HandleUnfollowStream(FollowStreamPubData info) + { + lock (_shardLock) + { + var key = info.Key; + if (!_trackCounter.TryGetValue(key, out var set)) + { + // it should've been removed already? + _streamTracker.UntrackStreamByKey(in key); + return default; + } + + set.Remove(info.GuildId); + if (set.Count != 0) + return default; + + _trackCounter.Remove(key); + // if no other guilds are following this stream + // untrack the stream + _streamTracker.UntrackStreamByKey(in key); + } + + return default; + } + + private async ValueTask HandleStreamsOffline(List offlineStreams) + { + foreach (var stream in offlineStreams) + { + var key = stream.CreateKey(); + if (_shardTrackedStreams.TryGetValue(key, out var fss)) + { + await fss + // send offline stream notifications only to guilds which enable it with .stoff + .SelectMany(x => x.Value) + .Where(x => _offlineNotificationServers.Contains(x.GuildId)) + .Select(fs => + { + var ch = _client.GetGuild(fs.GuildId) + ?.GetTextChannel(fs.ChannelId); + + if (ch is null) + return Task.CompletedTask; + + return _sender.Response(ch).Embed(GetEmbed(fs.GuildId, stream)).SendAsync(); + }) + .WhenAll(); + } + } + } + + + private async ValueTask HandleStreamsOnline(List onlineStreams) + { + foreach (var stream in onlineStreams) + { + var key = stream.CreateKey(); + if (_shardTrackedStreams.TryGetValue(key, out var fss)) + { + var messages = await fss.SelectMany(x => x.Value) + .Select(async fs => + { + var textChannel = _client.GetGuild(fs.GuildId) + ?.GetTextChannel(fs.ChannelId); + + if (textChannel is null) + return default; + + var repCtx = new ReplacementContext(guild: textChannel.Guild, + client: _client) + .WithOverride("%platform%", () => fs.Type.ToString()); + + + var message = string.IsNullOrWhiteSpace(fs.Message) + ? "" + : await _repSvc.ReplaceAsync(fs.Message, repCtx); + + var msg = await _sender.Response(textChannel) + .Embed(GetEmbed(fs.GuildId, stream, false)) + .Text(message) + .Sanitize(false) + .SendAsync(); + + // only cache the ids of channel/message pairs + if (_deleteOnOfflineServers.Contains(fs.GuildId)) + return (textChannel.Id, msg.Id); + else + return default; + }) + .WhenAll(); + + + // push online stream messages to redis + // when streams go offline, any server which + // has the online stream message deletion feature + // enabled will have the online messages deleted + try + { + var pairs = messages + .Where(x => x != default) + .Select(x => (x.Item1, x.Item2)) + .ToList(); + + if (pairs.Count > 0) + await OnlineMessagesSent(key.Type, key.Name, pairs); + } + catch + { + } + } + } + } + + private Task OnStreamsOnline(List data) + => _pubSub.Pub(StreamsOnlineKey, data); + + private Task OnStreamsOffline(List data) + => _pubSub.Pub(StreamsOfflineKey, data); + + private Task ClientOnJoinedGuild(GuildConfig guildConfig) + { + using (var uow = _db.GetDbContext()) + { + var gc = uow.Set() + .AsQueryable() + .Include(x => x.FollowedStreams) + .FirstOrDefault(x => x.GuildId == guildConfig.GuildId); + + if (gc is null) + return Task.CompletedTask; + + if (gc.NotifyStreamOffline) + _offlineNotificationServers.Add(gc.GuildId); + + foreach (var followedStream in gc.FollowedStreams) + { + var key = followedStream.CreateKey(); + var streams = GetLocalGuildStreams(key, gc.GuildId); + streams.Add(followedStream); + PublishFollowStream(followedStream); + } + } + + return Task.CompletedTask; + } + + private Task ClientOnLeftGuild(SocketGuild guild) + { + using (var uow = _db.GetDbContext()) + { + var gc = uow.GuildConfigsForId(guild.Id, set => set.Include(x => x.FollowedStreams)); + + _offlineNotificationServers.TryRemove(gc.GuildId); + + foreach (var followedStream in gc.FollowedStreams) + { + var streams = GetLocalGuildStreams(followedStream.CreateKey(), guild.Id); + streams.Remove(followedStream); + + PublishUnfollowStream(followedStream); + } + } + + return Task.CompletedTask; + } + + public async Task ClearAllStreams(ulong guildId) + { + await using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FollowedStreams)); + uow.RemoveRange(gc.FollowedStreams); + + foreach (var s in gc.FollowedStreams) + await PublishUnfollowStream(s); + + uow.SaveChanges(); + + return gc.FollowedStreams.Count; + } + + public async Task UnfollowStreamAsync(ulong guildId, int index) + { + FollowedStream fs; + await using (var uow = _db.GetDbContext()) + { + var fss = uow.Set() + .AsQueryable() + .Where(x => x.GuildId == guildId) + .OrderBy(x => x.Id) + .ToList(); + + // out of range + if (fss.Count <= index) + return null; + + fs = fss[index]; + uow.Remove(fs); + + await uow.SaveChangesAsync(); + + // remove from local cache + lock (_shardLock) + { + var key = fs.CreateKey(); + var streams = GetLocalGuildStreams(key, guildId); + streams.Remove(fs); + } + } + + await PublishUnfollowStream(fs); + + return fs; + } + + private void PublishFollowStream(FollowedStream fs) + => _pubSub.Pub(_streamFollowKey, + new() + { + Key = fs.CreateKey(), + GuildId = fs.GuildId + }); + + private Task PublishUnfollowStream(FollowedStream fs) + => _pubSub.Pub(_streamUnfollowKey, + new() + { + Key = fs.CreateKey(), + GuildId = fs.GuildId + }); + + public async Task FollowStream(ulong guildId, ulong channelId, string url) + { + // this will + var data = await _streamTracker.GetStreamDataByUrlAsync(url); + + if (data is null) + return null; + + FollowedStream fs; + await using (var uow = _db.GetDbContext()) + { + var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FollowedStreams)); + + // add it to the database + fs = new() + { + Type = data.StreamType, + Username = data.UniqueName, + ChannelId = channelId, + GuildId = guildId + }; + + var config = _config.Data; + if (config.FollowedStreams.MaxCount is not -1 + && gc.FollowedStreams.Count >= config.FollowedStreams.MaxCount) + return null; + + gc.FollowedStreams.Add(fs); + await uow.SaveChangesAsync(); + + // add it to the local cache of tracked streams + // this way this shard will know it needs to post a message to discord + // when shard 0 publishes stream status changes for this stream + lock (_shardLock) + { + var key = data.CreateKey(); + var streams = GetLocalGuildStreams(key, guildId); + streams.Add(fs); + } + } + + PublishFollowStream(fs); + + return data; + } + + public EmbedBuilder GetEmbed(ulong guildId, StreamData status, bool showViewers = true) + { + var embed = _sender.CreateEmbed() + .WithTitle(status.Name) + .WithUrl(status.StreamUrl) + .WithDescription(status.StreamUrl) + .AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true); + + if (showViewers) + { + embed.AddField(GetText(guildId, strs.viewers), + status.Viewers == 0 && !status.IsLive + ? "-" + : status.Viewers, + true); + } + + if (status.IsLive) + embed = embed.WithOkColor(); + else + embed = embed.WithErrorColor(); + + if (!string.IsNullOrWhiteSpace(status.Title)) + embed.WithAuthor(status.Title); + + if (!string.IsNullOrWhiteSpace(status.Game)) + embed.AddField(GetText(guildId, strs.streaming), status.Game, true); + + if (!string.IsNullOrWhiteSpace(status.AvatarUrl)) + embed.WithThumbnailUrl(status.AvatarUrl); + + if (!string.IsNullOrWhiteSpace(status.Preview)) + embed.WithImageUrl(status.Preview + "?dv=" + _rng.Next()); + + return embed; + } + + private string GetText(ulong guildId, LocStr str) + => _strings.GetText(str, guildId); + + public bool ToggleStreamOffline(ulong guildId) + { + bool newValue; + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + newValue = gc.NotifyStreamOffline = !gc.NotifyStreamOffline; + uow.SaveChanges(); + + if (newValue) + _offlineNotificationServers.Add(guildId); + else + _offlineNotificationServers.TryRemove(guildId); + + return newValue; + } + + public bool ToggleStreamOnlineDelete(ulong guildId) + { + using var uow = _db.GetDbContext(); + var gc = uow.GuildConfigsForId(guildId, set => set); + var newValue = gc.DeleteStreamOnlineMessage = !gc.DeleteStreamOnlineMessage; + uow.SaveChanges(); + + if (newValue) + _deleteOnOfflineServers.Add(guildId); + else + _deleteOnOfflineServers.TryRemove(guildId); + + return newValue; + } + + public Task GetStreamDataAsync(string url) + => _streamTracker.GetStreamDataByUrlAsync(url); + + private HashSet GetLocalGuildStreams(in StreamDataKey key, ulong guildId) + { + if (_shardTrackedStreams.TryGetValue(key, out var map)) + { + if (map.TryGetValue(guildId, out var set)) + return set; + return map[guildId] = []; + } + + _shardTrackedStreams[key] = new() + { + { guildId, [] } + }; + return _shardTrackedStreams[key][guildId]; + } + + public bool SetStreamMessage( + ulong guildId, + int index, + string message, + out FollowedStream fs) + { + using var uow = _db.GetDbContext(); + var fss = uow.Set().AsQueryable().Where(x => x.GuildId == guildId).OrderBy(x => x.Id).ToList(); + + if (fss.Count <= index) + { + fs = null; + return false; + } + + fs = fss[index]; + fs.Message = message; + lock (_shardLock) + { + var streams = GetLocalGuildStreams(fs.CreateKey(), guildId); + + // message doesn't participate in equality checking + // removing and adding = update + streams.Remove(fs); + streams.Add(fs); + } + + uow.SaveChanges(); + + return true; + } + + public int SetStreamMessageForAll(ulong guildId, string message) + { + using var uow = _db.GetDbContext(); + + var all = uow.Set() + .Where(x => x.GuildId == guildId) + .ToList(); + + if (all.Count == 0) + return 0; + + all.ForEach(x => x.Message = message); + + uow.SaveChanges(); + + lock (_shardLock) + { + foreach (var fs in all) + { + var streams = GetLocalGuildStreams(fs.CreateKey(), guildId); + + // message doesn't participate in equality checking + // removing and adding = update + streams.Remove(fs); + streams.Add(fs); + } + } + + return all.Count; + } + + public sealed class FollowStreamPubData + { + public StreamDataKey Key { get; init; } + public ulong GuildId { get; init; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/StreamNotification/StreamOnlineMessageDeleterService.cs b/src/EllieBot/Modules/Searches/StreamNotification/StreamOnlineMessageDeleterService.cs new file mode 100644 index 0000000..ae51752 --- /dev/null +++ b/src/EllieBot/Modules/Searches/StreamNotification/StreamOnlineMessageDeleterService.cs @@ -0,0 +1,99 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; +using EllieBot.Modules.Searches.Common; + +namespace EllieBot.Modules.Searches.Services; + +public sealed class StreamOnlineMessageDeleterService : IEService, IReadyExecutor +{ + private readonly StreamNotificationService _notifService; + private readonly DbService _db; + private readonly DiscordSocketClient _client; + private readonly IPubSub _pubSub; + + public StreamOnlineMessageDeleterService( + StreamNotificationService notifService, + DbService db, + IPubSub pubSub, + DiscordSocketClient client) + { + _notifService = notifService; + _db = db; + _client = client; + _pubSub = pubSub; + } + + public async Task OnReadyAsync() + { + _notifService.OnlineMessagesSent += OnOnlineMessagesSent; + + if (_client.ShardId == 0) + await _pubSub.Sub(_notifService.StreamsOfflineKey, OnStreamsOffline); + } + + private async Task OnOnlineMessagesSent( + FollowedStream.FType type, + string name, + IReadOnlyCollection<(ulong, ulong)> pairs) + { + await using var ctx = _db.GetDbContext(); + foreach (var (channelId, messageId) in pairs) + { + await ctx.GetTable() + .InsertAsync(() => new() + { + Name = name, + Type = type, + MessageId = messageId, + ChannelId = channelId, + DateAdded = DateTime.UtcNow, + }); + } + } + + private async ValueTask OnStreamsOffline(List streamDatas) + { + if (_client.ShardId != 0) + return; + + var pairs = await GetMessagesToDelete(streamDatas); + + foreach (var (channelId, messageId) in pairs) + { + try + { + var textChannel = await _client.GetChannelAsync(channelId) as ITextChannel; + if (textChannel is null) + continue; + + await textChannel.DeleteMessageAsync(messageId); + } + catch + { + continue; + } + } + } + + private async Task> GetMessagesToDelete(List streamDatas) + { + await using var ctx = _db.GetDbContext(); + + var toReturn = new List<(ulong, ulong)>(); + foreach (var sd in streamDatas) + { + var key = sd.CreateKey(); + var toDelete = await ctx.GetTable() + .Where(x => (x.Type == key.Type && x.Name == key.Name) + || Sql.DateDiff(Sql.DateParts.Day, x.DateAdded, DateTime.UtcNow) > 1) + .DeleteWithOutputAsync(); + + toReturn.AddRange(toDelete.Select(x => (x.ChannelId, x.MessageId))); + } + + return toReturn; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Translate/ITranslateService.cs b/src/EllieBot/Modules/Searches/Translate/ITranslateService.cs new file mode 100644 index 0000000..6766b6f --- /dev/null +++ b/src/EllieBot/Modules/Searches/Translate/ITranslateService.cs @@ -0,0 +1,17 @@ +#nullable disable +namespace EllieBot.Modules.Searches; + +public interface ITranslateService +{ + public Task Translate(string source, string target, string text = null); + Task ToggleAtl(ulong guildId, ulong channelId, bool autoDelete); + IEnumerable GetLanguages(); + + Task RegisterUserAsync( + ulong userId, + ulong channelId, + string from, + string to); + + Task UnregisterUser(ulong channelId, ulong userId); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Translate/TranslateService.cs b/src/EllieBot/Modules/Searches/Translate/TranslateService.cs new file mode 100644 index 0000000..9f50615 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Translate/TranslateService.cs @@ -0,0 +1,224 @@ +#nullable disable +using LinqToDB; +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db.Models; +using System.Net; + +namespace EllieBot.Modules.Searches; + +public sealed class TranslateService : ITranslateService, IExecNoCommand, IReadyExecutor, IEService +{ + private readonly IGoogleApiService _google; + private readonly DbService _db; + private readonly IMessageSenderService _sender; + private readonly IBot _bot; + + private readonly ConcurrentDictionary _atcs = new(); + private readonly ConcurrentDictionary> _users = new(); + + public TranslateService( + IGoogleApiService google, + DbService db, + IMessageSenderService sender, + IBot bot) + { + _google = google; + _db = db; + _sender = sender; + _bot = bot; + } + + public async Task OnReadyAsync() + { + List cs; + await using (var ctx = _db.GetDbContext()) + { + var guilds = _bot.AllGuildConfigs.Select(x => x.GuildId).ToList(); + cs = await ctx.Set().Include(x => x.Users) + .Where(x => guilds.Contains(x.GuildId)) + .ToListAsyncEF(); + } + + foreach (var c in cs) + { + _atcs[c.ChannelId] = c.AutoDelete; + _users[c.ChannelId] = + new(c.Users.ToDictionary(x => x.UserId, x => (x.Source.ToLower(), x.Target.ToLower()))); + } + } + + + public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg) + { + if (string.IsNullOrWhiteSpace(msg.Content)) + return; + + if (msg is { Channel: ITextChannel tch } um) + { + if (!_atcs.TryGetValue(tch.Id, out var autoDelete)) + return; + + if (!_users.TryGetValue(tch.Id, out var users) || !users.TryGetValue(um.Author.Id, out var langs)) + return; + + var output = await _google.Translate(msg.Content, langs.From, langs.To); + + if (string.IsNullOrWhiteSpace(output) + || msg.Content.Equals(output, StringComparison.InvariantCultureIgnoreCase)) + return; + + var embed = _sender.CreateEmbed().WithOkColor(); + + if (autoDelete) + { + embed.WithAuthor(um.Author.ToString(), um.Author.GetAvatarUrl()) + .AddField(langs.From, um.Content) + .AddField(langs.To, output); + + await _sender.Response(tch).Embed(embed).SendAsync(); + + try + { + await um.DeleteAsync(); + } + catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden) + { + _atcs.TryUpdate(tch.Id, false, true); + } + + return; + } + + await um.ReplyAsync(embed: embed.AddField(langs.To, output).Build(), allowedMentions: AllowedMentions.None); + } + } + + public async Task Translate(string source, string target, string text = null) + { + if (string.IsNullOrWhiteSpace(text)) + throw new ArgumentException("Text is empty or null", nameof(text)); + + var res = await _google.Translate(text, source.ToLowerInvariant(), target.ToLowerInvariant()); + return res.SanitizeMentions(true); + } + + public async Task ToggleAtl(ulong guildId, ulong channelId, bool autoDelete) + { + await using var ctx = _db.GetDbContext(); + + var old = await ctx.Set().ToLinqToDBTable() + .FirstOrDefaultAsyncLinqToDB(x => x.ChannelId == channelId); + + if (old is null) + { + ctx.Set().Add(new() + { + GuildId = guildId, + ChannelId = channelId, + AutoDelete = autoDelete + }); + + await ctx.SaveChangesAsync(); + + _atcs[channelId] = autoDelete; + _users[channelId] = new(); + + return true; + } + + // if autodelete value is different, update the autodelete value + // instead of disabling + if (old.AutoDelete != autoDelete) + { + old.AutoDelete = autoDelete; + await ctx.SaveChangesAsync(); + _atcs[channelId] = autoDelete; + return true; + } + + await ctx.Set().ToLinqToDBTable().DeleteAsync(x => x.ChannelId == channelId); + + await ctx.SaveChangesAsync(); + _atcs.TryRemove(channelId, out _); + _users.TryRemove(channelId, out _); + + return false; + } + + + private void UpdateUser( + ulong channelId, + ulong userId, + string from, + string to) + { + var dict = _users.GetOrAdd(channelId, new ConcurrentDictionary()); + dict[userId] = (from, to); + } + + public async Task RegisterUserAsync( + ulong userId, + ulong channelId, + string from, + string to) + { + if (!_google.Languages.ContainsKey(from) || !_google.Languages.ContainsKey(to)) + return null; + + await using var ctx = _db.GetDbContext(); + var ch = await ctx.Set().GetByChannelId(channelId); + + if (ch is null) + return null; + + var user = ch.Users.FirstOrDefault(x => x.UserId == userId); + + if (user is null) + { + ch.Users.Add(user = new() + { + Source = from, + Target = to, + UserId = userId + }); + + await ctx.SaveChangesAsync(); + + UpdateUser(channelId, userId, from, to); + + return true; + } + + // if it's different from old settings, update + if (user.Source != from || user.Target != to) + { + user.Source = from; + user.Target = to; + + await ctx.SaveChangesAsync(); + + UpdateUser(channelId, userId, from, to); + + return true; + } + + return await UnregisterUser(channelId, userId); + } + + public async Task UnregisterUser(ulong channelId, ulong userId) + { + await using var ctx = _db.GetDbContext(); + var rows = await ctx.Set().ToLinqToDBTable() + .DeleteAsync(x => x.UserId == userId && x.Channel.ChannelId == channelId); + + if (_users.TryGetValue(channelId, out var inner)) + inner.TryRemove(userId, out _); + + return rows > 0; + } + + public IEnumerable GetLanguages() + => _google.Languages.GroupBy(x => x.Value).Select(x => $"{x.AsEnumerable().Select(y => y.Key).Join(", ")}"); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Translate/TranslatorCommands.cs b/src/EllieBot/Modules/Searches/Translate/TranslatorCommands.cs new file mode 100644 index 0000000..348ca61 --- /dev/null +++ b/src/EllieBot/Modules/Searches/Translate/TranslatorCommands.cs @@ -0,0 +1,95 @@ +#nullable disable +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class TranslateCommands : EllieModule + { + public enum AutoDeleteAutoTranslate + { + Del, + Nodel + } + + [Cmd] + public async Task Translate(string fromLang, string toLang, [Leftover] string text = null) + { + try + { + await ctx.Channel.TriggerTypingAsync(); + var translation = await _service.Translate(fromLang, toLang, text); + + var embed = _sender.CreateEmbed().WithOkColor().AddField(fromLang, text).AddField(toLang, translation); + + await Response().Embed(embed).SendAsync(); + } + catch + { + await Response().Error(strs.bad_input_format).SendAsync(); + } + } + + [Cmd] + [RequireContext(ContextType.Guild)] + [UserPerm(GuildPerm.Administrator)] + [BotPerm(ChannelPerm.ManageMessages)] + [OwnerOnly] + public async Task AutoTranslate(AutoDeleteAutoTranslate autoDelete = AutoDeleteAutoTranslate.Nodel) + { + var toggle = + await _service.ToggleAtl(ctx.Guild.Id, ctx.Channel.Id, autoDelete == AutoDeleteAutoTranslate.Del); + if (toggle) + await Response().Confirm(strs.atl_started).SendAsync(); + else + await Response().Confirm(strs.atl_stopped).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AutoTransLang() + { + if (await _service.UnregisterUser(ctx.Channel.Id, ctx.User.Id)) + await Response().Confirm(strs.atl_removed).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task AutoTransLang(string fromLang, string toLang) + { + var succ = await _service.RegisterUserAsync(ctx.User.Id, ctx.Channel.Id, fromLang.ToLower(), toLang.ToLower()); + + if (succ is null) + { + await Response().Error(strs.atl_not_enabled).SendAsync(); + return; + } + + if (succ is false) + { + await Response().Error(strs.invalid_lang).SendAsync(); + return; + } + + await Response().Confirm(strs.atl_set(fromLang, toLang)).SendAsync(); + } + + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Translangs() + { + var langs = _service.GetLanguages().ToList(); + + var eb = _sender.CreateEmbed() + .WithTitle(GetText(strs.supported_languages)) + .WithOkColor(); + + foreach (var chunk in langs.Chunk(15)) + { + eb.AddField("󠀁", chunk.Join("\n"), inline: true); + } + + await Response().Embed(eb).SendAsync(); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/XkcdCommands.cs b/src/EllieBot/Modules/Searches/XkcdCommands.cs new file mode 100644 index 0000000..d913a87 --- /dev/null +++ b/src/EllieBot/Modules/Searches/XkcdCommands.cs @@ -0,0 +1,97 @@ +#nullable disable +using Newtonsoft.Json; + +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + [Group] + public partial class XkcdCommands : EllieModule + { + private const string XKCD_URL = "https://xkcd.com"; + private readonly IHttpClientFactory _httpFactory; + + public XkcdCommands(IHttpClientFactory factory) + => _httpFactory = factory; + + [Cmd] + [Priority(0)] + public async Task Xkcd(string arg = null) + { + if (arg?.ToLowerInvariant().Trim() == "latest") + { + try + { + using var http = _httpFactory.CreateClient(); + var res = await http.GetStringAsync($"{XKCD_URL}/info.0.json"); + var comic = JsonConvert.DeserializeObject(res); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithImageUrl(comic.ImageLink) + .WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{comic.Num}") + .AddField(GetText(strs.comic_number), comic.Num.ToString(), true) + .AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true); + var sent = await Response().Embed(embed).SendAsync(); + + await Task.Delay(10000); + + await sent.ModifyAsync(m => m.Embed = embed.AddField("Alt", comic.Alt).Build()); + } + catch (HttpRequestException) + { + await Response().Error(strs.comic_not_found).SendAsync(); + } + + return; + } + + await Xkcd(new EllieRandom().Next(1, 1750)); + } + + [Cmd] + [Priority(1)] + public async Task Xkcd(int num) + { + if (num < 1) + return; + try + { + using var http = _httpFactory.CreateClient(); + var res = await http.GetStringAsync($"{XKCD_URL}/{num}/info.0.json"); + + var comic = JsonConvert.DeserializeObject(res); + var embed = _sender.CreateEmbed() + .WithOkColor() + .WithImageUrl(comic.ImageLink) + .WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{num}") + .AddField(GetText(strs.comic_number), comic.Num.ToString(), true) + .AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true); + + var sent = await Response().Embed(embed).SendAsync(); + + await Task.Delay(10000); + + await sent.ModifyAsync(m => m.Embed = embed.AddField("Alt", comic.Alt).Build()); + } + catch (HttpRequestException) + { + await Response().Error(strs.comic_not_found).SendAsync(); + } + } + } + + public class XkcdComic + { + public int Num { get; set; } + public string Month { get; set; } + public string Year { get; set; } + + [JsonProperty("safe_title")] + public string Title { get; set; } + + [JsonProperty("img")] + public string ImageLink { get; set; } + + public string Alt { get; set; } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/YoutubeTrack/YtTrackService.cs b/src/EllieBot/Modules/Searches/YoutubeTrack/YtTrackService.cs new file mode 100644 index 0000000..6cbe065 --- /dev/null +++ b/src/EllieBot/Modules/Searches/YoutubeTrack/YtTrackService.cs @@ -0,0 +1,134 @@ +#nullable disable + +// public class YtTrackService : IEService +// { +// private readonly IGoogleApiService _google; +// private readonly IHttpClientFactory httpClientFactory; +// private readonly DiscordSocketClient _client; +// private readonly DbService _db; +// private readonly ConcurrentDictionary>> followedChannels; +// private readonly ConcurrentDictionary _latestPublishes = new ConcurrentDictionary(); +// +// public YtTrackService(IGoogleApiService google, IHttpClientFactory httpClientFactory, DiscordSocketClient client, +// DbService db) +// { +// this._google = google; +// this.httpClientFactory = httpClientFactory; +// this._client = client; +// this._db = db; +// +// if (_client.ShardId == 0) +// { +// _ = CheckLoop(); +// } +// } +// +// public async Task CheckLoop() +// { +// while (true) +// { +// await Task.Delay(10000); +// using (var http = httpClientFactory.CreateClient()) +// { +// await followedChannels.Select(kvp => CheckChannel(kvp.Key, kvp.Value.SelectMany(x => x.Value).ToList())).WhenAll(); +// } +// } +// } +// +// /// +// /// Checks the specified youtube channel, and sends a message to all provided +// /// +// /// Id of the youtube channel +// /// Where to post updates if there is a new update +// private async Task CheckChannel(string youtubeChannelId, List followedChannels) +// { +// var latestVid = (await _google.GetLatestChannelVideosAsync(youtubeChannelId, 1)) +// .FirstOrDefault(); +// if (latestVid is null) +// { +// return; +// } +// +// if (_latestPublishes.TryGetValue(youtubeChannelId, out var latestPub) && latestPub >= latestVid.PublishedAt) +// { +// return; +// } +// _latestPublishes[youtubeChannelId] = latestVid.PublishedAt; +// +// foreach (var chObj in followedChannels) +// { +// var gCh = _client.GetChannel(chObj.ChannelId); +// if (gCh is ITextChannel ch) +// { +// var msg = latestVid.GetVideoUrl(); +// if (!string.IsNullOrWhiteSpace(chObj.UploadMessage)) +// msg = chObj.UploadMessage + Environment.NewLine + msg; +// +// await ch.SendMessageAsync(msg); +// } +// } +// } +// +// /// +// /// Starts posting updates on the specified discord channel when a new video is posted on the specified YouTube channel. +// /// +// /// Id of the discord guild +// /// Id of the discord channel +// /// Id of the youtube channel +// /// Message to post when a new video is uploaded, along with video URL +// /// Whether adding was successful +// public async Task ToggleChannelFollowAsync(ulong guildId, ulong channelId, string ytChannelId, string uploadMessage) +// { +// // to to see if we can get a video from that channel +// var vids = await _google.GetLatestChannelVideosAsync(ytChannelId, 1); +// if (vids.Count == 0) +// return false; +// +// using(var uow = _db.GetDbContext()) +// { +// var gc = uow.GuildConfigsForId(guildId, set => set.Include(x => x.YtFollowedChannels)); +// +// // see if this yt channel was already followed on this discord channel +// var oldObj = gc.YtFollowedChannels +// .FirstOrDefault(x => x.ChannelId == channelId && x.YtChannelId == ytChannelId); +// +// if(oldObj is not null) +// { +// return false; +// } +// +// // can only add up to 10 tracked channels per server +// if (gc.YtFollowedChannels.Count >= 10) +// { +// return false; +// } +// +// var obj = new YtFollowedChannel +// { +// ChannelId = channelId, +// YtChannelId = ytChannelId, +// UploadMessage = uploadMessage +// }; +// +// // add to database +// gc.YtFollowedChannels.Add(obj); +// +// // add to the local cache: +// +// // get follows on all guilds +// var allGuildFollows = followedChannels.GetOrAdd(ytChannelId, new ConcurrentDictionary>()); +// // add to this guild's follows +// allGuildFollows.AddOrUpdate(guildId, +// new List(), +// (key, old) => +// { +// old.Add(obj); +// return old; +// }); +// +// await uow.SaveChangesAsync(); +// } +// +// return true; +// } +// } \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/YoutubeTrack/YtUploadCommands.cs b/src/EllieBot/Modules/Searches/YoutubeTrack/YtUploadCommands.cs new file mode 100644 index 0000000..2439ad4 --- /dev/null +++ b/src/EllieBot/Modules/Searches/YoutubeTrack/YtUploadCommands.cs @@ -0,0 +1,54 @@ +#nullable disable +namespace EllieBot.Modules.Searches; + +public partial class Searches +{ + // [Group] + // public partial class YtTrackCommands : EllieModule + // { + // ; + // [RequireContext(ContextType.Guild)] + // public async Task YtFollow(string ytChannelId, [Leftover] string uploadMessage = null) + // { + // var succ = await _service.ToggleChannelFollowAsync(ctx.Guild.Id, ctx.Channel.Id, ytChannelId, uploadMessage); + // if(succ) + // { + // await Response().Confirm(strs.yt_follow_added).SendAsync(); + // } + // else + // { + // await Response().Confirm(strs.yt_follow_fail).SendAsync(); + // } + // } + // + // [EllieCommand, Usage, Description, Aliases] + // [RequireContext(ContextType.Guild)] + // public async Task YtTrackRm(int index) + // { + // //var succ = await _service.ToggleChannelTrackingAsync(ctx.Guild.Id, ctx.Channel.Id, ytChannelId, uploadMessage); + // //if (succ) + // //{ + // // await Response().Confirm(strs.yt_track_added).SendAsync(); + // //} + // //else + // //{ + // // await Response().Confirm(strs.yt_track_fail).SendAsync(); + // //} + // } + // + // [EllieCommand, Usage, Description, Aliases] + // [RequireContext(ContextType.Guild)] + // public async Task YtTrackList() + // { + // //var succ = await _service.ToggleChannelTrackingAsync(ctx.Guild.Id, ctx.Channel.Id, ytChannelId, uploadMessage); + // //if (succ) + // //{ + // // await Response().Confirm(strs.yt_track_added).SendAsync(); + // //} + // //else + // //{ + // // await Response().Confirm(strs.yt_track_fail).SendAsync(); + // //} + // } + // } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/AtlExtensions.cs b/src/EllieBot/Modules/Searches/_common/AtlExtensions.cs new file mode 100644 index 0000000..e8ab960 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/AtlExtensions.cs @@ -0,0 +1,12 @@ +#nullable disable +using LinqToDB.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using EllieBot.Db.Models; + +namespace EllieBot.Modules.Searches; + +public static class AtlExtensions +{ + public static Task GetByChannelId(this IQueryable set, ulong channelId) + => set.Include(x => x.Users).FirstOrDefaultAsyncEF(x => x.ChannelId == channelId); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/BibleVerses.cs b/src/EllieBot/Modules/Searches/_common/BibleVerses.cs new file mode 100644 index 0000000..30dd045 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/BibleVerses.cs @@ -0,0 +1,20 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches.Common; + +public class BibleVerses +{ + public string Error { get; set; } + public BibleVerse[] Verses { get; set; } +} + +public class BibleVerse +{ + [JsonPropertyName("book_name")] + public string BookName { get; set; } + + public int Chapter { get; set; } + public int Verse { get; set; } + public string Text { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/Config/ImgSearchEngine.cs b/src/EllieBot/Modules/Searches/_common/Config/ImgSearchEngine.cs new file mode 100644 index 0000000..b34fb36 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/Config/ImgSearchEngine.cs @@ -0,0 +1,7 @@ +namespace EllieBot.Modules.Searches; + +public enum ImgSearchEngine +{ + Google, + Searx, +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs new file mode 100644 index 0000000..fb64849 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs @@ -0,0 +1,86 @@ +using Cloneable; +using EllieBot.Common.Yml; + +namespace EllieBot.Modules.Searches; + +[Cloneable] +public partial class SearchesConfig : ICloneable +{ + [Comment("DO NOT CHANGE")] + public int Version { get; set; } = 0; + + [Comment(""" + Which engine should .search command + 'google_scrape' - default. Scrapes the webpage for results. May break. Requires no api keys. + 'google' - official google api. Requires googleApiKey and google.searchId set in creds.yml + 'searx' - requires at least one searx instance specified in the 'searxInstances' property below + """)] + public WebSearchEngine WebSearchEngine { get; set; } = WebSearchEngine.Google_Scrape; + + [Comment(""" + Which engine should .image command use + 'google'- official google api. googleApiKey and google.imageSearchId set in creds.yml + 'searx' requires at least one searx instance specified in the 'searxInstances' property below + """)] + public ImgSearchEngine ImgSearchEngine { get; set; } = ImgSearchEngine.Google; + + + [Comment(""" + Which search provider will be used for the `.youtube` command. + + - `ytDataApiv3` - uses google's official youtube data api. Requires `GoogleApiKey` set in creds and youtube data api enabled in developers console + + - `ytdl` - default, uses youtube-dl. Requires `youtube-dl` to be installed and it's path added to env variables. Slow. + + - `ytdlp` - recommended easy, uses `yt-dlp`. Requires `yt-dlp` to be installed and it's path added to env variables + + - `invidious` - recommended advanced, uses invidious api. Requires at least one invidious instance specified in the `invidiousInstances` property + """)] + public YoutubeSearcher YtProvider { get; set; } = YoutubeSearcher.Ytdlp; + + [Comment(""" + Set the searx instance urls in case you want to use 'searx' for either img or web search. + Ellie will use a random one for each request. + Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com` + Instances specified must support 'format=json' query parameter. + - In case you're running your own searx instance, set + + search: + formats: + - json + + in 'searxng/settings.yml' on your server + + - If you're using a public instance, make sure that the instance you're using supports it (they usually don't) + """)] + public List SearxInstances { get; set; } = new List(); + + [Comment(""" + Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search + Ellie will use a random one for each request. + These instances may be used for music queue functionality in the future. + Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com + + Instances specified must have api available. + You check that by opening an api endpoint in your browser. For example: https://my-invidious-instance.mydomain.com/api/v1/trending + """)] + public List InvidiousInstances { get; set; } = new List(); + + [Comment("Maximum number of followed streams per server")] + public FollowedStreamConfig FollowedStreams { get; set; } = new FollowedStreamConfig(); +} + +public sealed class FollowedStreamConfig +{ + [Comment("Maximum number of streams that each server can follow. -1 for infinite")] + public int MaxCount { get; set; } = 10; +} + +public enum YoutubeSearcher +{ + YtDataApiv3, + Ytdl, + Ytdlp, + Invid, + Invidious = 3 +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/Config/SearchesConfigService.cs b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfigService.cs new file mode 100644 index 0000000..f656a5b --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfigService.cs @@ -0,0 +1,58 @@ +using EllieBot.Common.Configs; + +namespace EllieBot.Modules.Searches; + +public class SearchesConfigService : ConfigServiceBase +{ + private static string FILE_PATH = "data/searches.yml"; + private static readonly TypedKey _changeKey = new("config.searches.updated"); + + public override string Name + => "searches"; + + public SearchesConfigService(IConfigSeria serializer, IPubSub pubSub) + : base(FILE_PATH, serializer, pubSub, _changeKey) + { + AddParsedProp("webEngine", + sc => sc.WebSearchEngine, + ConfigParsers.InsensitiveEnum, + ConfigPrinters.ToString); + + AddParsedProp("imgEngine", + sc => sc.ImgSearchEngine, + ConfigParsers.InsensitiveEnum, + ConfigPrinters.ToString); + + AddParsedProp("ytProvider", + sc => sc.YtProvider, + ConfigParsers.InsensitiveEnum, + ConfigPrinters.ToString); + + AddParsedProp("followedStreams.maxCount", + sc => sc.FollowedStreams.MaxCount, + int.TryParse, + ConfigPrinters.ToString); + + Migrate(); + } + + private void Migrate() + { + if (data.Version < 1) + { + ModifyConfig(c => + { + c.Version = 1; + c.WebSearchEngine = WebSearchEngine.Google_Scrape; + }); + } + + if (data.Version < 2) + { + ModifyConfig(c => + { + c.Version = 2; + }); + } + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/Config/WebSearchEngine.cs b/src/EllieBot/Modules/Searches/_common/Config/WebSearchEngine.cs new file mode 100644 index 0000000..e924f03 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/Config/WebSearchEngine.cs @@ -0,0 +1,9 @@ +// ReSharper disable InconsistentNaming +namespace EllieBot.Modules.Searches; + +public enum WebSearchEngine +{ + Google, + Google_Scrape, + Searx, +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/CryptoData.cs b/src/EllieBot/Modules/Searches/_common/CryptoData.cs new file mode 100644 index 0000000..6600b59 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/CryptoData.cs @@ -0,0 +1,66 @@ +#nullable disable +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Searches.Common; + +public class CryptoResponse +{ + public List Data { get; set; } +} + +public class CmcQuote +{ + [JsonPropertyName("price")] + public double Price { get; set; } + + [JsonPropertyName("volume_24h")] + public double Volume24h { get; set; } + + // [JsonPropertyName("volume_change_24h")] + // public double VolumeChange24h { get; set; } + // + // [JsonPropertyName("percent_change_1h")] + // public double PercentChange1h { get; set; } + + [JsonPropertyName("percent_change_24h")] + public double PercentChange24h { get; set; } + + [JsonPropertyName("percent_change_7d")] + public double PercentChange7d { get; set; } + + [JsonPropertyName("market_cap")] + public double MarketCap { get; set; } + + [JsonPropertyName("market_cap_dominance")] + public double MarketCapDominance { get; set; } +} + +public class CmcResponseData +{ + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("symbol")] + public string Symbol { get; set; } + + [JsonPropertyName("slug")] + public string Slug { get; set; } + + [JsonPropertyName("cmc_rank")] + public int CmcRank { get; set; } + + [JsonPropertyName("circulating_supply")] + public double? CirculatingSupply { get; set; } + + [JsonPropertyName("total_supply")] + public double? TotalSupply { get; set; } + + [JsonPropertyName("max_supply")] + public double? MaxSupply { get; set; } + + [JsonPropertyName("quote")] + public Dictionary Quote { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/_common/DefineModel.cs b/src/EllieBot/Modules/Searches/_common/DefineModel.cs new file mode 100644 index 0000000..a0e2018 --- /dev/null +++ b/src/EllieBot/Modules/Searches/_common/DefineModel.cs @@ -0,0 +1,43 @@ +#nullable disable +using Newtonsoft.Json; + +namespace EllieBot.Modules.Searches.Common; + +public class Audio +{ + public string Url { get; set; } +} + +public class Example +{ + public List

Q1+_maa()G2}A636W~R9#Dqq1$5Q>`D8`YcYoX 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 gx{x!${Kiifp3*99Uy(c|X*CdW=%CDC zq7ep|+kKC9uXp0)W@eHMpZVv`&7Co$GkKXrGhOr(5NJRJ6{Qs)hlh46Q5t;o{r=WI zr>dF;G&l44-2ean`FuEa&VH=D*4k^Wz1G_MoX&s#&R9Gai&gV~Y%CVLk6-<3w(IdP zHIrholh63|$+4fExbeOBP0DS2@0AM{-c;AVWbxOQeC5Wvwy*rjpDez)?yJ|;Em`^} zbqoKbE_3M>bvG`)_PURrbkfvh2zrYD&KED(yX=AJ|3!bf?}3YX{)eC5a(~)>zjc4J z{oZ!}MfQ8^{aJp0IP<3ue1_i(_TKWqpYi)IKfU$-l>IKd|9t!Xj}N%tZ`$+a3)>cG zjAK#M+7gRh`xhs~{_2nZ>guS?NbG%e@2EOC7Mngf7MlvO{2P21_qBGr+)8v`6^or< zMdjaEJ0)T&|Egm1Y3e#fKNFu_N$Zx$vG<=Fi!FP{39&Wm+rh zpAehRZR^h_$F7XZj`Dji^>s%zmZvENX6zY$-^p*qzh=bfqpn$O%`__N;7JX?hbOe_`e?grXf#4=YzFPB zBCc}Jzh=Q(a?_GF?u{q#2IeyE(b`?NXfX}vQyqg>)^65>cIT`5|Ih!t&MzisUG1&h z-X+53{IE>+a&Qs1(=>*kYM z{4TGMOV$NTYA468Pb|JUSx3t=u1_?@KECU{lVd!@uTKn*P_>Eweb*<>&2&%Fbwe%X z1C%|Yr)_jTH*??=o{QHfZhEwa%P5!Om-s(O>E7!TOJ1hql7|7l_z9|?n8xL`>gyBx z9;0M8|GTLkc@H-mxcMFJhKIO$X*M@cQTh<=chdf*!}J{9Mu|GErO64+e+Es$-u2#bkS; zUL0N7(|S$!gV8@Y?TOQkiMh8X>oSSCnPe^3X~~?w?pG%viH!KEU)I6OOk#1>*!k1^ z^TBoT*<)Ru=T95!;`T$)&HJL8)1sT{(aqH8rV21kv3?%2g=YBO6g#NPurAN*vP+lk zx@^{^|N3-dag)a0e0_^%hr50*!;rd|uEVeJOYhp=oEJ3p3QT6OK3SWR{zDj(RKiOjgCTQ`x?xqs6|BN4HU+A@jViMf9{sP27%&D?tU8YKGG!Kginx&Jss zRi!|nzxAHK7H#zkm(_ayK=9ZbV`GxmY;CrXu1j3q^=qfb!vl#kni;TZXN?rVTe)}A z(wAu1^hD&?ms9|cj*zrziRX?xFWGHu^au2HiUJ;E-1P5R5%eECZe4T4zX zbuLQQdYw0iD~oz82U6=jW|Iw@;c>ZB;_N|8?a|Q|u*BS- zCA)ZFc&66f+>yMKo0k){F~7Oy<-{p42$=J-g%&M-cO{oo+n-5(5p1*&Q;nhww+P1f zlkE=1kCOAbkv`diV#|cnr`1FB%Oq;2dWGsYxW(tVz2#0XF~Abm6hpXMmS0q;-l!T1 z6LarR-YZDx>^cVcS+dzZots%#tHL6M_a_^p!Xg+A4*;YC%!)AP_FNKUDCdO6tatKN zxDzhtX10J~rMsfCmvCz2#=LFMMGi~JeL1S?@xJUJeFY$_dPEgrl zYuMYq`kjUogU@eTYs?v4`#Yf?c1r>nmIrAJ(NPPk$|na&G2zsmmyZ z1PIZT^r&K^Rrjg-kZPDiYbVd1S~Tk1%+6EF&?rC%Xh?6l?d=aj(YcvESDqMtkfOB| z4NJgX#4#w~+x6J5rbRt6@9i7a3@sYo$PB=fQYB^Wo2aC)k?KvA6`HD>9#gym2n$@K z5yL=UJiv6Aq--IISgZ+C1hZsBit*?)E^iQ2?4$Kfuj^)r|9faixFKSe98fRNx4_0i z6N_gQnrJ8sWu)7WOSesbmkd@>Ss^=-K_F6VZk8;_j4|D=k@>T2^qgX)6kv6>u8tjF+ce6 zOTby#T}$UBn*k&y=KX_xndCLG?8@hsCsqx|BPm4SjwXeyFHFo)#W0vMP7J${xm$*~ zTqZG`%l~gkl$v5r_M99__L^dEXs%7GO^BQXZjw4U(L%<~%{*}m;Ej!op9A-EGri)) zaF_Zr9p`5H?KuP!)i{x^6ha!BkZw|;1k%I`J0-D-L=kX9HvW*nm&K5%$|OzUtK@8) z7*f{0xh#gnZK3c|Arx=gDKP|u6T|(YuM7G49Rg>ajeF$dgT!ly;bD8aInFR_z1PG%`h) ziEtjZn8ERz9%mk14n)?EnO(e(|1u|LKuYGsEQxG~vm`?_IKW)*qcsM`D|9YLe~)KX zT!utgMpgx5QZg+^PMqaQlrRb1j4n54Ov*Tm5@1p0zfNrAED5o?bE>#;E*CdHGM_Gg z-oeDm{{fEa2ZZUxg>%lyH|)>)4|)e5m8;oUkx#&p`{=)^Rrb98B`0S6F|Xl}*YIZQ zae4k;`hHoaT*Gsv{DW7rSM+=z_G-yQdo{Yh!d|&F&dL{;dxh$=G)MsgG;=wk2*Rgp zlOB^mcE>BU+=<98U7quQAZJkqaIxn*^VxFtR^}IhY)N(H8Z_7c_h-O}w64F?D_nJF zHa?gyWXG~&UFpOxs!vUyot|`dRc7j7R(ZrHTUKqo`Ca02UEc3cZ4H`VuZ|HH?)fgO zj>5IN`?!e_9(*ys`qjj$gYv_ffz$u~q{&2ymyG57ZQ0_UDfxznvi?I^xgpK5arvfe zldai8zE--}5+iR0r1X6*CSSZL+3HFxm3Fg*Az!rnTTAyg-HK0C!2{8B_)vLI#g&99 ziZHgR+NOKAUH94bfL&j+7V@#0VsbcjMN?!&(9_|7|0Db#RiP;o>WwKV$uF`t$tz@Q z75C5~%$d=JOc{NYO>>zwZe4l}HV2cIS|aZULvRuqJzq=X<@4$Egv{O+o-S(F6Bc4P zP=h)>;p+~M=&4apukkdhr)G`tgz2^x+w)uP*~l2+8DFF62^NWA%dsV=E3vU?daZtL zo?fS)Tc!I%FnHlGU2CC#5^8Pt2aTb;)yi|A65C=Tw(0mm)?CmJ4LLi9*|Y z7re@*b-5-kVDKXv8KjX?Ch0Gwzj)0TzSP}(MLGGfz%*d;!Z!)K zm4IJWO7>0A#my}c4pJF}f%sIeUb##iN;zDWAsH-3>MTjla>@T*Y|HYMduSyHI` zca$<^zkB{D%p>1KzJ}zU5;j+Rq-zG{a>>}+7$t4c_{E?4e9dImCK8bM4Urp4fM-tW z8xKd^BX8EE6}CR-Z&8+~F?U{|q|QgDxTKDxzLeCdb;zwsj!+7gcO-|nDJOMW)^xV~ zSlbN!Eq5~t4#MJ=HPUW1{!yqw5V@RQ74~gnKF9L@%Ha%oVM0fiB6iSAC=D~nLjD5q z1(n>VfMMx3@$`LDL7vXdY%=rTN8#O;gR;UtP{Ow2k1Xv1Ide1FdkQl-ugY6eCgd^{%BlZDGdk=qR#FYYTZ~|N^xAH88J%@JxydHz4=0;hAEr&M=r@0F08`^Y2S4Tc^lmXmfu163G(H{4DZqL04y2Jq8xX$fh+adH#I zT|=O0NuS}TqP)&-iG@YV&$^V(M_6BSq;%>f9T>jr?o~$TlC-6C@(l;?B%gDJ%jaNL z&mNc0$#>x#-5Wf%s~jC|0mkC%?#=mHD*P+8Zs4%@wcHc)Tkc-jRn^&Ywx2ABbF1!P~ zFO_evD&OYIw=HYX3X%}?W&9|mq%=~LYIxQfJYm;|?YdD@0M6#xW5&(BA5!5CT?TbI zhJQ~mAg`Vac1rHPJbU%h*0`?D!Dr8qt;9aCSllrr7I3o*y^Yi9iKlcSeaP?>Z>RWz zS{1R3m^Xhxot{|7%+tT1QE;Ci>c@MhX|p|QmUX6K@deJ+U#I6mJnF^`>nGza%@y>Zl0}iV%!-Ul;FNpHplmrZfkTShB~`AwSAd5A z&rt0Y63oaNC|LR8Y{o{T!bHvx4@%@9kEJG8&TggJvU^kmg2&;F7U|5MZ*k9TfG+;j z);GnQ(9Ec1DOCq}m*&BCEhhgayJ*=u%MmXbm#%Xe<0wJr54?0x)P|669|kQ-(#S|Q{kRAlAMN!ZPT^{fYn=X;zPoZ|J{F<4H&`1y8aN&0qFb95+*e;GmnF1ZKA#pE88EBP|X z62;F~Z~~_;cy?2D%-<3Gke@TVIn_}|YQp~Ar*o#^y$bGANL}&#fADx~O^ZuMd;aAnT;rSJnv!kW)F^gY~pb-=|}} zUg!7i*n}W83Q2?XkJRUsouf;Z_J32+{_dl+|0eZ31wFv8df6Z*;lG{I>zP6loeC* zjXaa3#gr){EvBMowNaW(50-3-4mVk{X?a*frVf8Q_@EwFzZ#u%`WCseKMqei-ONd+ zl@$pymoF;|kINEGp1ijtJj+F4Nn#KaXWa5Sq~#=rOjAyWgErYT-eKouoZMV;mYb_) z!LYfy`=2W0M#aH5w;f$>{*so*lba>fOWvILZj`ja=6ao4i{>rsZw|fy3aX35>%6xB z`)=ylIB?j$_>bcxYxCA>#2~-=g_~=#{VisrBooFVWTNgN%jt=Q6|xXn9%q04@3AjW zKVK4&w`pI#e@y%GM;|-VzO4G66>=hT6kNVVa&mvAed+i7ZNb-Rne+R-!pwUQRL8Oh zci7aWR}LkDORcJGT0R{;&s=?E(6srNX_fw!k_xNzok5{r zwo2RnZK73LOq+35Df5)GN~cv=rAWAg^hb|0N`Gf8`hM~_Mk$oPW7(stUiyEhJzDx~ zN!Xk{`dPSw*|H^P%j}Vpu*e>5)?rpw0ht+Rk2ZbyNP9Hre^khs*`vMq46=6>>sYVk ztcsRq;AVO-X`Gxr{|}X>2s4N&;*2b&D4Hx;qW{X^m6qsV=w;6{4~`rG@Vit+(s(p! z`_qd0qphi*rM_gu=JHS>h*P2OI7aLXn~!V6#>-C~n__I!9L9zA{Fj0=V6<1bx?Yck zOX`D!dv0~lty+Ruu5M-l!y~(9&j`zumbXb>XPPxK%`%mq#s9hre~kM6Nq}MDJ8GLF z?5XWkr9bO0sm7!6zgfdkV*m5gJb!IE-d>%KFRMw%=S|D_pRdjMm(R%f7tLyk&#P^T zx6WvZd$ThB`Ez_P8P6v(@s>IM<#q9^>ik%|1#wuEoR#kU(`q4Km+t&_jpsAJ>CP_$ zn)AWw&J$WXzg*kW`PmsQotMmN>HN%`bmwPjcu6w-iMjt)o0yS zlR4{4wVAW7nvppxKPz)q%bc^Wsyi#66oK`fjt5QhvnSHS+(qZPBmRGWhX2i3{*pQV z*Xtmu8csvdk$+&&@E_b>1?|c-i@lImX=1g>}a5&PkchbakdPTa)R$Y+9!C zbG4byZ%p8(_z4$nk2LaOR_^z_!bQyg+F!TO3*EH~6iqc$e3?D*0mya_pM^Cj&A{`_r?<=O^cEFLWt|?;jhx9W5L13e~G= z%O=|QxFXDOG+TUaw&LCT;09XeZ`gKfzVO$o1I$;-S;L!guxPllDJ+T5;&KTtQe@Wf}&v#nICu|1w`Fs5BpcK1-i; z!-lxyS*Ei#=MQ#z)!71JnBc7SierM)Fp}wuB zqB$*{Uu9#m$2+EbW%}j(ZHeNn94=wqRbF9H@_(|8+6Cek={!bg{;^<$S2sD2@-ZHE z1-sqDE_--{2g3PX*nNA}*%Nzqtv?p5wjjs4{xbNnYyC@Lx$a+cwR-qv@SmvtZ8anN zPbSXLc(kMVCXGkBW$6ncU={BQK3v)LQri6HM0I^FdS9y4KV|)g$M^qbu-{CsjWH!i z(B|LtQfN8;ra!yq`6 zzvuZ|j?(#zMQW`5?`4W7nz9`hV;faz(U* zM|82apNEw_^NzH?N7}y?`*(niz;HmCg@balQ>^T*4s_>K%lbj%^W+UjF_*M$F7Vol zGS>=@vu#}}n&q{v)o*LItvlEDc(&~^JuS<&6?1LvL@n%k8eqw{6OS-5RUB->nO6$)wkoV?!-O4x%i0Z_h%FLfWfWFbL_E?$D)?KWjtm{M$8b_ zy6vu;J7FqFeRkg(ww}e4V}T0VGRbLx>XGqVmTS9NFI(!E(uC*t|r$)Ghqcd2OwZI?zVsaT3eQsH+3j58s zezUBfqi2C?imwskT+3TTZPzA0spa@yahtIlOKABU={gYcFh0Pz#=baZ5kBpn%6r5| zyX&RPS`Yd2c=T4R1!$G6G_>f_I;diL*YS*~eBVh1W$?n-lDLQ0?Tm_ex7UWWdT}Of zV=lhKxEx|6*}2aUzBO5$b;~$a>{z}w+eUDdw#y@MDE8%$J?Rkx_vPeOnxxD!tb1~8 zKQc_H?6(r8!G!^o6a|qfuHnANphG?Pz2Utir_YPS05IKb@=%>LM8gSIKkfN;31iWJ zzk8WZ!nHt>(HhNt;+|_+Lc^i+a3DSqF)5OVI?A&60_t2JVj$UY@(>oxqdE zgM{j2E?&&Xhw_EL0Fz1L$Z~Elyf`GYX=Y?fl9`$>CadX`L(xr12{0UPZ2_j zg-C}RoGBX+H3-#&dC|S74?BF4cH)8)4wux-VGL_r8K8L$Nd;04@O74?&Wj_! z$o43c={2nNAl_1(lgx6hm$*2r3F-gNKu7@Oq{~~j0VIWGxr3Mt1uO$r33X1VMW8lw zWD>F~x&Tn6S*y0Tb><5@#yZ62(QKSBNy;PXpPyqHn}yKjBy^CDLFH9_*F&ovKq+FW z<7SI)&Y|&3kr|ejwp|I&+1J7b)S3;b=gMI_;AU489d;~)^oIv5rr9_z7hj2K)mS-< zrB#FpbtYM!KII~v4tIsqV{MzQ%=MFymVl=CyjE4v$@5mPRm-PFbVrO+q+@y zsUBxzu6k1JJ> zKKPgm&mZ+;>4Q56$`9^PQsCfYTEc4&J{lzkNENumK+SOy17`HQj~}nBfewpTUdA^c z3!1ACsKQlaJZukA?qRzwzfrsro`1GB+k#dbt|4v;e#48TPmDWFuH=_RAgHO8tYV*P18rn>Z zS3YQU7gY8aVJhApy#6~Q%#GplPa(q7twZSlM+1%p8(aqp==~yOPKZ|=tZh`4;-jeh z_TY~4cpnVzq0Pj2#o_y%%Kl}1bLIZqgT-p&CSiN0brAAnf#NL7 za9+ix(x%|$1DbP}$T)VOGBIDWV!s*Dwr|cL6hO?056F(4KdtcLPZKWG6z0Sb{yMMi z>|EP7=UiBrp$MP`-hQSq=SDC<`&shve=~)1{;2bgWQ?lx4Vyn8_q~~($r~=OJJq@B z^%oQ{;^wut%4>H=ryH~K)~k~@^nak`hT;cuZCmxa{``E~Hhg!i)H<*2%c>Tj*{;!Lp}`5)Qrxyd2X55uht3}2Uv2cSLxA)i)!vn&VCw1&Yx2-DD7 z`OKR!7rUnfUrr}%WtFik(WG2_l=Wb?R&21=8ilb|tfXL!H3JUFhi}fsw^D~I@d!V> zgke=~7$^iHXyK%+%@_U~9VcbA@WcmmouLbWo8@u8TtMZJi!&??_>YBOQ&y!FU3`~> zz#Gt&LG~g_ZsxURxx9&cUJxZ(;Gj#cpYX-;FgMDxC+M@~6<^0;C1!=emYnPXpgb(^ zVL`s|a~nI(#Jx!zv00*5n~iS>d*btq2!mM$x1Q?;{=dO!p$jAjQl5)uIUhP*w3qv) zPani_k_`m_$tTL{4Hc(e@-M=cP8C7yK_xdOpOJSIg&r9gp&_#IfqY?wP&Otgac|?9N$p1=1>#SYb^&ER|*jJ z6j{|Z&F#_=Th0$?Rc~o{vEj9rhAr8`U6Rw1&%siU+u_9n&*dXaZbw5PuR}Wro%PzK z(VY-!GUr2e%PEQHlFQN!{hckAmmE5+Gf(Q?@uy*+b17N-RpwnfhoduJD~Cfun`wAD z)7dg3(|KJo(|O~p&fDf>Ifp8B*+Ng)NnZ?ObJ& ziwR{4MUR=zl6f6xLdk~Tkql^aVPRS_-}aJ1e9xI%c#yeal~sNq-}ZREZEJ;%Wj@wn zVDoJ#%Hz4V^)i;NvTJqT_egSkohVb{o`YsSJ&UHyUlumG&U2Eo?cO9rLSlgqwY`c& z%FNC}^pHzje9SO4mh)CTh#8d?=_iRIbBkEC@p=-%XdUP&zgm_Tky)pW`x+TmuM_y+ zqhGH~`h4Ye+yviczoF5^He^Yy=x`ZL(Gwom0vAKYox(f}A;!l=-Rv(ssz(dU5&o@8 zHprd`G7uxnVF0k&V7>qlR~r6AOcl0Os|bFrb%gG0m{5>WA(a3qGk|n4+uDZko^x?z z=^a;lv|j+V?KI6L>php>mywt85}Qc#3n|*jo+_v>*&kKI!WtXK#ixpUjsNrVh2%w9 ze}fi=+aL)+PS4l6GZR^w6e?NGw}?UD%UhvsK%%r}5&#hc7IFmZdBFfc6SJ6)#4Z zhz;Uty^$aBw4pT3wo!EwB zMe;VQc&}EbRa#*3h_*HCbA+Xf�VjmrTRKbmxuJS~{1`$rq|GPb=9_xRdUaS{fdU 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 z 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%0A)}`3W7Ngvp`=F#vx5 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%0AiOxr0XV6GmwxbxGTOJ5H=xMID!Hb5L)zd?_ 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 literal 0 HcmV?d00001 diff --git a/src/EllieBot/libsodium.so b/src/EllieBot/libsodium.so new file mode 100644 index 0000000000000000000000000000000000000000..548285a61c55ea0c71a6a17b75601d6addf31fd4 GIT binary patch literal 1999216 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