Is you hair in the early stages of hair loss?
Make your hair look more natural?
Run, and don't walk to the phone, and call Hair Center International, located in Astoria, Queens, NY in New York City, NYC, New York. We are minutes away from Manhattan, Long Island, Westchester, NJ, CT, Philadelphia, and are a women's thinning hair solutions salon. We have many different female thinning hair options, in our posh, NYC, NY salon.
We offer affordable thinning hair options that are usually more than half what our competition in NJ, Manhattan, Westchester, and Long Island charge, and yet we have 5-10 times more solutions that anyone else. Plus, our hair quality is 100% Natural Remy Human Premium Hair, the best found on the market! Other salons will try to slap a net on your hair, and say that is fine for all women. We don't! We won't! We offer those types of solutions also, but, many, many, more options from women suffering for thinning hair. As a matter of fact, most of our 100+ different hair extension and hair replacement types can be used for thinning hair, so come to the New York, NY leader in fine woman's thinning hair options.
Thinning hair can be caused by many reasons. Some of them can be temporary, such as thinning hair due to stress, medication, thyroid issues, menopause, pregnancy, etc. These issues are reversible, and your hair will grow back in time. We have many solutions for women until your hair grows back, until your hair becomes the way it use to. We will cover your female hair loss until your hair grows back. Hair Center International Hair Loss Treatment salon for woman with thinning hair and want thicker, fuller looking hair located in New York, NY, NYC, minutes from Long Island, NJ, CT, and Westchester.
Many ladies have permanent thinning hair, hair that will not grow back. The thinning hair will get worse, until, the hair is gone. All of the various forms of Alopecia can develop, and take hold, so you will need a long term solution, and will be a long term customer. We can help you get the long, thicker, fuller hair that you desire. The best thing to do is visit us, and we can tell you what is going to be your best thinning hair options, hair loss options.
We have many options. Come in for a FREE hair analysis and consultation. We pride ourselves in offering many solutions for women's hair loss, female hair loss, thinning hair loss. You have nothing to loss. That is why we are the leaders in the New York, NY, NYC, Manhattan, NJ, CT, Long Island, Philadelphia, areas! We serve all ethnic types, and are experts with Caucasian thinning hair, black thinning hair, European thinning hair, Latin American thinning hair! We have all hair types, such as Yaki Hair, Brazilian Hair, Virgin Hair, European Hair, Russian Hair, Indian Hair, etc. We have private rooms, and will go through what is going to be the best in options for you!


Green Lanes, London, N4 1HE.
Fastech Net is an internet caf� which serves food and drinks to customers using the computers. Fastech Net is based in Green Lanes, London - see map for location of Green Lanes.
Share your experience of Fastech Net with thousands of people each day.
Fastech Net is in Green Lanes, London. You can view a list of neighbouring businesses by going to the Green Lanes page.
This map shows the approximate location of Fastech Net in Green Lanes.
Note: the pin is positioned at the postcode centre, and may not correspond with the precise location of Green Lanes.


text:
using Discord;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DColor = System.Drawing.Color;

namespace DisBot {
    public static class DisBotCore {

        public static string NL;

        public static readonly Lazy<Version> Version = new Lazy<Version>(() => Assembly.GetExecutingAssembly().GetName().Version);
        public static readonly Lazy<string> PublicIP = new Lazy<string>(delegate () {
            using (WebClient wc = new WebClient()) {
                return wc.DownloadString("http://ipinfo.io/ip").Trim();
            }
        });
        public static readonly Lazy<string> Hostname = new Lazy<string>(delegate () {
            string hostname = Dns.GetHostName();
            if (hostname != "localhost") {
                return hostname;
            }
            return Environment.MachineName;
        });
        public static readonly Lazy<string> OS = new Lazy<string>(delegate () {
            if (Environment.OSVersion.Platform != PlatformID.Unix) {
                return Environment.OSVersion.ToString();
            }

            StringBuilder data = new StringBuilder();
            Process p;

            p = new Process();
            p.StartInfo.FileName = "which";
            p.StartInfo.Arguments = "lsb_release";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.UseShellExecute = false;
            p.EnableRaisingEvents = true;

            p.OutputDataReceived += new DataReceivedEventHandler(
                delegate (object sender, DataReceivedEventArgs e) {
                    data.AppendLine(e.Data);
                }
            );
            p.Start();
            p.BeginOutputReadLine();
            p.StandardInput.WriteLine();
            p.WaitForExit();
            p.CancelOutputRead();
            if (data.Length == 0) {
                return Environment.OSVersion.ToString();
            }

            p = new Process();
            p.StartInfo.FileName = "lsb_release";
            p.StartInfo.Arguments = "-a";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.UseShellExecute = false;
            p.EnableRaisingEvents = true;
            data.Clear();
            p.OutputDataReceived += new DataReceivedEventHandler(
                delegate (object sender, DataReceivedEventArgs e) {
                    data.AppendLine(e.Data);
                }
            );
            p.Start();
            p.BeginOutputReadLine();
            p.StandardInput.WriteLine();
            p.WaitForExit();
            p.CancelOutputRead();

            string desc = data.ToString();
            desc = desc.Substring(desc.IndexOf("Description")).Trim();
            desc = desc.Substring(desc.IndexOf(':') + 1).Trim();
            desc = desc.Substring(0, desc.IndexOf('\n')).Trim();

            data.Clear();
            data.Append(desc);
            data.Append(" (Linux ").Append(Environment.OSVersion.Version).Append(")");

            return data.ToString();
        });

        private static DiscordClient Client;

        public readonly static string RootDir = "disbot";

        public readonly static string GlobalLogFile = "globallog.txt";
        public readonly static string TokenFile = "token.txt";

        public static Random RNG;

        public static Dictionary<ulong, DisBotServerConfig> Servers = new Dictionary<ulong, DisBotServerConfig>();

        public static List<DisBotCommand> Commands = new List<DisBotCommand>();
        public static List<DisBotParser> Parsers = new List<DisBotParser>();

        public static Bitmap SharedBitmap;
        public static Graphics SharedGraphics;

        public readonly static bool IsMono = Type.GetType("Mono.Runtime") != null;

        public static ulong OverlordID = 93713629047697408UL;

        public static Regex PathVerifyRegex = new Regex("[" + Regex.Escape(new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars())) + "]");

        static DisBotCore() {
            try {
                CheckGDI();

                SharedBitmap = new Bitmap(1, 1);
                SharedGraphics = Graphics.FromImage(SharedBitmap);
            } catch (Exception) { /* GDI unsupported. */ }
        }

        public static void Main(string[] args) {
            if (args.Length == 1 && args[0] == "ouya") {
                ServicePointManager.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
                    if (sslPolicyErrors != SslPolicyErrors.None) {
                        for (int i = 0; i < chain.ChainStatus.Length; i++) {
                            if (chain.ChainStatus[i].Status != X509ChainStatusFlags.RevocationStatusUnknown) {
                                chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
                                chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                                chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
                                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
                                if (!chain.Build((X509Certificate2) certificate)) {
                                    return false;
                                }
                            }
                        }
                    }
                    return true;
                };
            }

            AppDomain.CurrentDomain.UnhandledException += delegate (object sender, UnhandledExceptionEventArgs eargs) {
                Exception e = (Exception) eargs.ExceptionObject;

                if (string.IsNullOrEmpty(GlobalLogFile)) return;
                string log = Path.Combine(RootDir, GlobalLogFile);
                // TODO better.
                lock (GlobalLogFile)
                try {
                    File.AppendAllText(log, "----------------\nCRITICAL! CRITICAL!----------------\n" + e.ToString() + "\n----------------\n\n");
                } catch (IOException) { /* Disk IO. */ }
            };

            Init();
            Run();
        }

        public static void Init() {
            if (Client != null) return;
            NL = "\n";
            if (Environment.OSVersion.Platform != PlatformID.Unix && Environment.OSVersion.Platform != PlatformID.MacOSX) {
                NL = "\r\n";
            }

            RNG = new Random();

            Client = new DiscordClient(new DiscordConfigBuilder() {
                MessageCacheSize = 10,
                ConnectionTimeout = 180000
            });

            Client.MessageReceived += MessageReceived;
            Client.JoinedServer += (object s, ServerEventArgs e) => GetServer(e.Server, true);
            Client.ServerAvailable += (object s, ServerEventArgs e) => GetServer(e.Server, true);
            Client.LeftServer += (object s, ServerEventArgs e) => RemoveServer(e.Server);

            Commands.Add(new DisBotDCommand() {
                Name = "help",
                Info = "Yet another help command.",
                Help = "<command to get help for>",
                OnRun = delegate (DisBotDCommand cmd_, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    StringBuilder builder = new StringBuilder();

                    if (args.Length == 0) {
                        builder.Append("**disbot ").Append(Version.Value.ToString()).AppendLine("**");
                        builder.Append("This server has got **").Append(server.Commands.Count).Append(" commands** and **").Append(server.Parsers.Count).AppendLine(" parsers.**");
                        builder.AppendLine();

                        builder.AppendLine("**Commands:**");
                        for (int i = 0; i < server.Commands.Count; i++) {
                            DisBotCommand cmd = server.Commands[i];
                            builder.Append(server.Prefix).Append(cmd.Name).AppendLine(": ");
                            builder.Append(" ").Append(cmd.Info).AppendLine();
                        }
                        builder.AppendLine($"*(Use a command with {server.Prefix}{server.Prefix} to make your message vanish!)*");
                        builder.AppendLine();

                        builder.AppendLine("**Parsers:**");
                        for (int i = 0; i < server.Parsers.Count; i++) {
                            DisBotParser parser = server.Parsers[i];
                            builder.Append(parser.Name).AppendLine(": ");
                            builder.Append(" ").Append(parser.Info).AppendLine();
                        }
                        builder.AppendLine();

                    } else {
                        for (int i = 0; i < args.Length; i++) {
                            string cmdName = args[i];
                            if (cmdName.StartsWithInvariant(server.Prefix)) {
                                cmdName = cmdName.Substring(server.Prefix.Length);
                            }

                            DisBotCommand cmd = server.GetCommand(cmdName);
                            if (cmd == null) {
                                builder.Append("Command not found: `").Append(cmdName).AppendLine("`");
                                builder.AppendLine();
                                continue;
                            }

                            builder.Append(cmd.Name).AppendLine(": ");
                            builder.Append(" ").Append(cmd.Info).AppendLine();
                            builder.Append(" `").Append(server.Prefix).Append(cmd.Name).Append(" ").AppendLine(cmd.Help).AppendLine("`");
                            builder.AppendLine();
                        }
                    }

                    server.Send(msg.Channel, builder.ToString());
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "bot",
                Info = "Info about the current disbot instance.",
                Help = "",
                OnRun = delegate (DisBotDCommand cmd, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    StringBuilder builder = new StringBuilder();
                    builder.Append("**disbot ").Append(Version.Value.ToString()).AppendLine("** by 0x0ade.");
                    builder
                        .Append("Running on *").Append(OS.Value)
                        .Append("* @ `").Append(Hostname.Value)
                        .Append(" (").Append(PublicIP.Value).AppendLine(")`");

                    if (IsMono) {
                        builder.AppendLine("Using *Mono.*");
                    } else {
                        builder.AppendLine("Using *.NET Framework.*");
                    }

                    builder.AppendLine();
                    builder.Append("disbot is being used on **").Append(Servers.Count).AppendLine("** servers!");

                    if (server.Server == null) {
                        server.Send(msg.Channel, builder.ToString());
                        return;
                    }

                    builder.AppendLine();
                    builder.AppendLine("Info for this server:");
                    builder.Append("**").Append(server.Commands.Count).AppendLine("** commands.");
                    builder.Append("**").Append(server.Aliases.Count).AppendLine("** aliases.");
                    builder.Append("**").Append(server.Parsers.Count).AppendLine("** parsers.");
                    builder.Append("**").Append(server.Images.Count).AppendLine("** images.");

                    server.Send(msg.Channel, builder.ToString());
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "conf",
                Info = "Configuration management command.",
                Help = "export | import [data] | get [prop] | set [prop] [value]",
                OnRun = delegate (DisBotDCommand cmd_, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    if (server.Server == null) {
                        return;
                    }

                    if (args.Length == 1 && args[0] == "export") {
                        server.Save();
                        server.Send(msg.Channel, $"```\n{File.ReadAllText(Path.Combine(RootDir, server.Dir, server.ConfigFile))}\n```");
                        return;
                    }

                    if (args.Length == 2 && args[0] == "get") {
                        Func<string> getter;
                        if (!server.OnSave.TryGetValue(args[1], out getter)) {
                            server.Send(msg.Channel, $"Property `{args[1]}` not found! Property names are case-sensitive!");
                            return;
                        }
                        server.Send(msg.Channel, $"```\n{getter()}\n```");
                        return;
                    }

                    if (!server.IsBotCommander(msg.User, msg)) {
                        return;
                    }

                    if (args.Length >= 2 && args[0] == "import") {
                        string data = msg.Text.Substring(msg.Text.IndexOf(' ') + 6 + 1);
                        data = data.Trim('`', ' ', '\n').Trim();
                        File.WriteAllText(Path.Combine(RootDir, server.Dir, server.ConfigFile), data);
                        server.Load();
                        server.Save();
                        server.Send(msg.Channel, "Data imported.");
                        return;
                    }

                    if (args.Length >= 2 && args[0] == "name") {
                        if (!server.IsBotOverlord(msg.User, msg)) {
                            return;
                        }

                        Task.Run(async delegate () {
                            try {
                                string data = msg.Text.Substring(msg.Text.IndexOf(' ') + 4 + 1);
                                data = data.Trim();
                                await Client.CurrentUser.Edit(username: data);
                                server.Send(msg.Channel, "Name changed.");
                            } catch (Exception e) {
                                server.Send(msg.Channel, $"Could not change name! Consult `{server.Prefix}log internal`");
                                server.Log("internal", e.ToString());
                            }
                        });
                        return;
                    }

                    if (args.Length >= 2 && args[0] == "avatar") {
                        if (!server.IsBotOverlord(msg.User, msg)) {
                            return;
                        }

                        Task.Run(async delegate () {
                            try {
                                string data = msg.Text.Substring(msg.Text.IndexOf(' ') + 6 + 1);
                                data = data.Trim();
                                using (MemoryStream ms = new MemoryStream()) {
                                    using (WebClient wc = new WebClient())
                                    using (Stream s = wc.OpenRead(data)) {
                                        s.CopyTo(ms);
                                    }

                                    ms.Position = 0;
                                    await Client.CurrentUser.Edit(avatar: ms);
                                }
                                server.Send(msg.Channel, "Avatar changed.");
                            } catch (Exception e) {
                                server.Send(msg.Channel, $"Could not change avatar! Consult `{server.Prefix}log internal`");
                                server.Log("internal", e.ToString());
                            }
                        });
                        return;
                    }

                    if (args.Length >= 2 && args[0] == "game") {
                        if (!server.IsBotOverlord(msg.User, msg)) {
                            return;
                        }

                        string data = msg.Text.Substring(msg.Text.IndexOf(' ') + 4 + 1);
                        data = data.Trim();
                        Client.SetGame(data);
                        server.Send(msg.Channel, "Game changed.");
                        return;
                    }

                    if (args.Length >= 3 && args[0] == "set") {
                        Action<string> setter;
                        if (!server.OnLoad.TryGetValue(args[1], out setter)) {
                            server.Send(msg.Channel, $"Property `{args[1]}` not found! Property names are case-sensitive!");
                            return;
                        }
                        string data = msg.Text.Substring(msg.Text.IndexOf(' ') + 3 + 1 + args[1].String.Length + 1);
                        data = data.Trim('`', ' ', '\n').Trim();
                        setter(data);
                        server.Save();
                        server.Send(msg.Channel, $"Property `{args[1]}` updated.");
                        return;
                    }

                    Task.Run(() => server.GetCommand("help").Run(server, msg, new DisBotCommandArg(cmd_.Name)));
                    return;
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "alias",
                Info = "Alias management command.",
                Help = "+ [alias] [cmd] <args> | - [alias] | [alias]",
                OnRun = delegate (DisBotDCommand cmd_, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    if (server.Server == null) {
                        return;
                    }

                    if (args.Length == 2 && args[0] == "-") {
                        Tuple<string, string> alias = server.GetAliasTuple(args[1]);
                        if (alias == null) {
                            server.Send(msg.Channel, $"Alias `{args[1]}` not found! Add a new one via `{server.Prefix}{cmd_.Name} + {args[1]} [cmd] <args>`");
                            return;
                        }

                        server.Aliases.Remove(alias);
                        server.Save();
                        server.Send(msg.Channel, $"Alias `{args[1]}` removed!");
                        return;
                    }

                    if (args.Length >= 3 && (args[0] == "+" || args[0] == "add")) {
                        DisBotCommand cmd = server.GetCommand(args[1]);
                        if (cmd != null) {
                            server.Send(msg.Channel, $"Command `{args[1]}` already existing!");
                            return;
                        }

                        string aliasName = args[1].String;
                        if (aliasName.StartsWithInvariant(server.Prefix)) {
                            aliasName = aliasName.Substring(server.Prefix.Length);
                        }

                        Tuple<string, string> alias = server.GetAliasTuple(aliasName);
                        if (alias != null) {
                            server.Send(msg.Channel, $"Alias `{aliasName}` already existing!");
                            return;
                        }

                        string aliasCmd = msg.Text.Substring(
                            msg.Text.IndexOf(' ') +
                            args[0].String.Length + 1 +
                            args[1].String.Length + 1
                        ).Trim();
                        if (aliasCmd.StartsWithInvariant(server.Prefix)) {
                            aliasCmd = aliasCmd.Substring(server.Prefix.Length);
                        }

                        server.Aliases.Add(Tuple.Create(aliasName, aliasCmd));
                        server.Save();
                        server.Send(msg.Channel, $"Alias `{aliasName}` added!");
                        return;
                    }

                    StringBuilder builder = new StringBuilder();

                    if (args.Length == 0) {
                        builder.Append("This server has got **").Append(server.Commands.Count).Append(" aliases.**");
                        builder.AppendLine();

                        for (int i = 0; i < server.Aliases.Count; i++) {
                            Tuple<string, string> alias = server.Aliases[i];
                            builder.Append("Alias `").Append(alias.Item1).AppendLine("`:");
                            builder.AppendLine("```");
                            builder.Append(server.Prefix).AppendLine(alias.Item2);
                            builder.AppendLine("```");
                        }
                        builder.AppendLine();
                    } else {
                        for (int i = 0; i < args.Length; i++) {
                            string aliasName = args[i];
                            if (aliasName.StartsWithInvariant(server.Prefix)) {
                                aliasName = aliasName.Substring(server.Prefix.Length);
                            }
                            string aliasCmd = server.GetAlias(aliasName);
                            if (aliasCmd == null) {
                                server.Send(msg.Channel, $"Alias `{aliasName}` not found! Add a new one via `{server.Prefix}{cmd_.Name} + {aliasName} [cmd] <args>`");
                                continue;
                            }

                            builder.Append("Alias `").Append(aliasName).AppendLine("`:");
                            builder.AppendLine("```");
                            builder.Append(server.Prefix).AppendLine(aliasCmd);
                            builder.AppendLine("```");
                        }
                    }

                    server.Send(msg.Channel, builder.ToString());
                    return;
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "log",
                Info = "Gives you a look at what happened in this server.",
                Help = "<tag (default: all) / list> <range (n, -n, a-b, a+n)>",
                OnRun = delegate (DisBotDCommand cmd, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    if (server.Server == null) {
                        return;
                    }

                    StringBuilder builder = new StringBuilder();

                    CircularBuffer<string> buffer = args.Length == 0 ? server.LogBuffer : server.GetLogBuffer(args[0]);

                    if (buffer == null) {
                        if (args[0] == "list") {
                            builder.AppendLine("Available tags:");
                            goto ListTags;
                        }
                    }

                    if (buffer == null) {
                        builder.AppendLine($"Log with tag `{args[0]}` not found! Available tags:");
                        goto ListTags;
                    }

                    int offset = 0;
                    int size = int.MaxValue;
                    if (args.Length != 0) {
                        buffer = buffer ?? server.LogBuffer;
                        string sizeStr = args[args.Length - 1];
                        string[] sizeStrSplit;
                        if (int.TryParse(sizeStr, out size)) { if (size < 0) { offset = buffer.CurrentSize + size; size = -size; } } else if ((sizeStrSplit = sizeStr.Split('+')).Length == 2 && int.TryParse(sizeStrSplit[0], out offset) && int.TryParse(sizeStrSplit[1], out size)) { } else if ((sizeStrSplit = sizeStr.Split('-')).Length == 2 && int.TryParse(sizeStrSplit[0], out offset) && int.TryParse(sizeStrSplit[1], out size)) { size -= offset; } else { size = int.MaxValue; }
                    }

                    if (buffer != null) {
                        builder.AppendLine("```");
                        offset = Math.Max(0, offset);
                        size = Math.Min(buffer.CurrentSize - offset, size);
                        for (int i = offset; i < offset + size; i++) {
                            builder.AppendLine(buffer[i].Replace("```", "---"));
                        }
                        builder.AppendLine("```");
                    }

                    if (builder.Length > DiscordConfig.MaxMessageSize) {
                        server.Send(msg.Channel, "The log is quite big. Sending it to you via PM.");

                        Task.Run(async delegate () {
                            Task<Channel> channelT = msg.User.CreatePMChannel();
                            List<string> texts = new List<string>();
                            string text = builder.ToString();
                            while (text.Length > DiscordConfig.MaxMessageSize) {
                                int lastnl = text.LastIndexOf("\n", DiscordConfig.MaxMessageSize, DiscordConfig.MaxMessageSize);
                                if (lastnl < 0) lastnl = DiscordConfig.MaxMessageSize;
                                texts.Add(text.Substring(0, lastnl));
                                text = text.Substring(lastnl);
                            }
                            texts.Add(text);
                            Channel channel = await channelT;
                            for (int i = 0; i < texts.Count; i++) {
                                text = texts[i];
                                if (i != 0) text = "```\n" + text;
                                if (i != texts.Count - 1) text = text + "\n```";
                                server.Send(channel, text);
                            }
                        });
                        return;
                    }
                    server.Send(msg.Channel, builder.ToString());
                    return;

                    ListTags:
                    builder.AppendLine($" `all`");
                    foreach (string tag in server.LogTags) {
                        builder.AppendLine($" `{tag}`");
                    }
                    server.Send(msg.Channel, builder.ToString());
                    return;
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "echo",
                Info = "Repeats what you said.",
                Help = "[anything]",
                OnRun = (cmd, server, msg, args) => server.Send(msg.Channel, msg.Text.Substring(Math.Max(0, msg.Text.IndexOf(' '))).Trim())
            });

            Commands.Add(new DisBotDCommand() {
                Name = "mute",
                Info = "Mutes someone. Except it doesn't.",
                Help = "[anything]",
                OnRun = (cmd, server, msg, args) => server.Send(msg.Channel, msg.Text.Substring(msg.Text.IndexOf(' ')).Trim() + " muted.")
            });

            Commands.Add(new DisBotDCommand() {
                Name = "img",
                Info = "Your friendly image vault.",
                Help = "[any search query] | + [url] | + [attached image] | - [name] <number> | ~ <oldname> [newname]",
                OnRun = delegate (DisBotDCommand cmd, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    if (server.Server == null) {
                        return;
                    }

                    string url, imguri;

                    if (args.Length == 2) {
                        if (args[0] == "++") {
                            if (!server.IsBotCommander(msg.User, msg)) {
                                return;
                            }
                            if (!server.ImageBlacklist.Contains(args[1])) {
                                server.Send(msg.Channel, $"`{args[1]}` not in blacklist.");
                                return;
                            }

                            server.ImageBlacklist.Remove(args[1]);
                            server.Save();
                            server.Send(msg.Channel, $"Removed `{args[1]}` from blacklist.");
                            return;
                        }
                        if (args[0] == "--") {
                            if (!server.IsBotCommander(msg.User, msg)) {
                                return;
                            }
                            if (server.ImageBlacklist.Contains(args[1])) {
                                server.Send(msg.Channel, $"`{args[1]}` already in blacklist.");
                                return;
                            }

                            server.ImageBlacklist.Add(args[1]);
                            server.Save();
                            server.Send(msg.Channel, $"Added `{args[1]}` to blacklist.");
                            return;
                        }
                    }

                    if (((1 <= args.Length && args.Length <= 2) && args[0].String.StartsWithInvariant("+")) || (args.Length == 2 && args[0] == "add")) {
                        if (msg.Attachments.Length == 0 && args.Length == 1 && args[0].String.Length == 1) {
                            server.Send(msg.Channel, "You didn't attach any image to your message!");
                            return;
                        }

                        if (args[0].String.Length == 1 && args.Length == 1) {
                            if (msg.Attachments[0].Width == null) {
                                server.Send(msg.Channel, "Not an image, you dirty liar!");
                                return;
                            }
                            url = msg.Attachments[0].Url;
                        } else {
                            if (args.Length == 2) url = args[1];
                            else url = args[0].String.Substring(1);
                            string urll = url.ToLowerInvariant();
                            if (
                                !urll.EndsWith(".png") &&
                                !urll.EndsWith(".jpg") &&
                                !urll.EndsWith(".jpeg") &&
                                !urll.EndsWith(".gif")
                            ) {
                                server.Send(msg.Channel, "Not an image, you dirty liar!");
                                return;
                            }
                        }

                        imguri = Path.Combine(RootDir, server.Dir, server.ImageDir, url.Substring(url.LastIndexOf("/") + 1).Replace(' ', '_').Replace("%20", "_"));

                        if (File.Exists(imguri)) {
                            server.Send(msg.Channel, "Image already exists!");
                            return;
                        }

                        if (GetWebStreamLength(url) > 3L * 1024L * 1024L) {
                            server.Send(msg.Channel, "Image too large!");
                            return;
                        }

                        if (server.IsImageBlacklisted(url)) {
                            server.Send(msg.Channel, "Image blacklisted!");
                            return;
                        }

                        Task.Run(async delegate () {
                            server.Log("bot", $"Downloading {url} to {imguri}");
                            Task<Message> replyT = msg.Channel.SendMessage("Downloading image...");
                            Message reply;

                            try {
                                using (WebClient wc = new WebClient()) {
                                    wc.DownloadFile(url, imguri);
                                }
                            } catch (Exception e) {
                                reply = await replyT;
                                server.Log("bot", "Download failed.");
                                server.Log("internal", msg.Server.Name, msg.Channel.Name, e.ToString());
                                await reply.Edit($"Something went wrong! Consult `{server.Prefix}log internal`");
                                return;
                            }

                            server.RefreshImageCache();
                            server.LastImage = imguri;

                            reply = await replyT;
                            await reply.Edit("Stored your image successfully!");
                        });
                        return;
                    }

                    if (args.Length == 1 && args[0] == "-") {
                        if (server.LastImage == null) {
                            server.Send(msg.Channel, "disbot no remembering image!");
                            return;
                        }

                        File.Delete(server.LastImage);
                        server.RefreshImageCache();
                        server.Send(msg.Channel, $"Image {Path.GetFileName(server.LastImage)} removed!");
                        server.LastImage = null;
                        return;
                    }

                    if (args.Length == 2 && args[0] == "-") {
                        List<string> matches = server.GetImages(args[1]);
                        if (matches.Count == 0) {
                            server.Send(msg.Channel, "Image does not exist!");
                            return;
                        }

                        if (matches.Count > 1) {
                            StringBuilder builder = new StringBuilder();
                            builder.AppendLine("Found following matches:");

                            for (int i = 0; i < matches.Count; i++) {
                                builder.Append(i).Append(": ").AppendLine(Path.GetFileName(matches[i]));
                            }

                            builder.AppendLine();
                            builder.AppendLine($"Use `{server.Prefix}img - {args[1]} NUMBER`, where number is one of the above.");

                            server.Send(msg.Channel, builder.ToString());
                            return;
                        }

                        File.Delete(matches[0]);
                        server.RefreshImageCache();
                        if (server.LastImage == matches[0]) server.LastImage = null;
                        server.Send(msg.Channel, "Image removed!");
                        return;
                    }

                    if (args.Length == 3 && args[0] == "-") {
                        List<string> matches = server.GetImages(args[1]);
                        if (matches.Count == 0) {
                            server.Send(msg.Channel, "Image does not exist!");
                            return;
                        }

                        if (matches.Count == 1) {
                            server.Send(msg.Channel, "Wrong syntax! Only use the number when multiple images exist for a given query!");
                            return;
                        }

                        int id;
                        if (!int.TryParse(args[2], out id)) {
                            server.Send(msg.Channel, $"`{args[2]}` not a valid number!");
                            return;
                        }
                        File.Delete(matches[id]);
                        server.RefreshImageCache();
                        if (server.LastImage == matches[id]) server.LastImage = null;
                        server.Send(msg.Channel, "Image removed!");
                        return;
                    }

                    if (args.Length == 2 && args[0] == "~") {
                        if (server.LastImage == null) {
                            server.Send(msg.Channel, "disbot no remembering image!");
                            return;
                        }

                        // Relative file name copy because extension shouldn't change when moving
                        string toR = Path.ChangeExtension(args[1], Path.GetExtension(server.LastImage));
                        string to = Path.Combine(RootDir, server.Dir, server.ImageDir, toR);
                        if (File.Exists(to)) {
                            server.Send(msg.Channel, "Destination image already existing!");
                            return;
                        }

                        if (server.IsImageBlacklisted(to)) {
                            server.Send(msg.Channel, "Image blacklisted!");
                            File.Delete(server.LastImage);
                            server.RefreshImageCache();
                            return;
                        }

                        File.Move(server.LastImage, to);
                        server.RefreshImageCache();
                        server.LastImage = to;
                        server.Send(msg.Channel, $"Image now known as {toR}!");
                        return;
                    }

                    if (args.Length == 3 && args[0] == "~") {
                        string from = Path.Combine(RootDir, server.Dir, server.ImageDir, args[1]);
                        if (!File.Exists(from)) {
                            List<string> matches = server.GetImages(args[1]);
                            if (matches.Count == 0) {
                                server.Send(msg.Channel, "Image does not exist!");
                                return;
                            }

                            if (matches.Count > 1) {
                                StringBuilder builder = new StringBuilder();
                                builder.AppendLine("Found following matches:");

                                for (int i = 0; i < matches.Count; i++) {
                                    builder.Append(" ").AppendLine(Path.GetFileName(matches[i]));
                                }

                                builder.AppendLine();
                                builder.AppendLine($"Use `{server.Prefix}img ~ FULLNAME {args[2]}`, where FULLNAME is one of the above.");

                                server.Send(msg.Channel, builder.ToString());
                                return;
                            }

                            from = matches[0];
                        }
                        // Relative file name copy because extension shouldn't change when moving
                        string toR = Path.ChangeExtension(args[2], Path.GetExtension(from));
                        string to = Path.Combine(RootDir, server.Dir, server.ImageDir, toR);
                        if (File.Exists(to)) {
                            server.Send(msg.Channel, "Destination image already existing!");
                            return;
                        }

                        if (server.IsImageBlacklisted(to)) {
                            server.Send(msg.Channel, "Image blacklisted!");
                            File.Delete(from);
                            server.RefreshImageCache();
                            return;
                        }

                        File.Move(from, to);
                        server.RefreshImageCache();
                        server.LastImage = to;
                        server.Send(msg.Channel, $"Image now known as {toR}!");
                        return;
                    }

                    if (args.Length == 1 && (args[0] == "list" || args[0] == "all")) {
                        StringBuilder builder = new StringBuilder();
                        builder.AppendLine("Found following images for this server:");

                        for (int i = 0; i < server.Images.Count; i++) {
                            builder.Append(" ").AppendLine(Path.GetFileName(server.Images[i]).Replace('_', ' '));
                        }

                        builder.AppendLine();
                        builder.AppendLine($"Use `{server.Prefix}img` for a random image or `{server.Prefix}img QUERY` to search for a specific image.");

                        if (server.Images.Count > 20) {
                            server.Send(msg.Channel, "The image list is quite big. Sending it to you via PM.");

                            Task.Run(async delegate () {
                                server.Send(await msg.User.CreatePMChannel(), builder.ToString());
                            });
                            return;
                        }
                        server.Send(msg.Channel, builder.ToString());
                        return;
                    }

                    if (args.Length == 1 && args[0] == "blacklist") {
                        StringBuilder builder = new StringBuilder();
                        builder.AppendLine("Following images blacklisted for this server:");

                        for (int i = 0; i < server.ImageBlacklist.Count; i++) {
                            builder.Append(" ").AppendLine(server.ImageBlacklist[i].Replace('_', ' '));
                        }

                        builder.AppendLine();
                        builder.AppendLine($"Use `{server.Prefix}img -- [img]` to blacklist and `{server.Prefix}img ++ [img]` to unblock an image.");

                        server.Send(msg.Channel, builder.ToString());
                        return;
                    }

                    if (args.Length == 1 && (args[0] == "info" || args[0] == "last")) {
                        if (server.LastImage == null) {
                            server.Send(msg.Channel, "No image was used. Or at least, that's what my memory says.");
                            return;
                        }

                        server.Send(msg.Channel, $"The last image used was: {Path.GetFileName(server.LastImage)}");
                        return;
                    }

                    if (args.Length >= 1) {
                        List<string> matches = server.GetImages(msg.Text.Substring(msg.Text.IndexOf(' ')).Trim());
                        if (matches.Count == 0) {
                            server.Send(msg.Channel, "Image does not exist!");
                            return;
                        }
                        imguri = matches[RNG.Next(matches.Count)];

                    } else {
                        if (server.Images.Count == 0) {
                            server.Send(msg.Channel, $"No images found! Try submitting an image by sending an image with `{server.Prefix}img +` or via `{server.Prefix}img +[URL]`.");
                            return;
                        }
                        imguri = server.Images[RNG.Next(server.Images.Count)];
                    }

                    server.LastImage = imguri;
                    server.SendImage(msg.Channel, imguri);
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "emoji",
                Info = "Idea stolen from Zatherz. Sorry!",
                Help = "[anything]",
                OnRun = delegate (DisBotDCommand cmd, DisBotServerConfig server, Message msg, DisBotCommandArg[] args) {
                    if (args.Length == 0) {
                        return;
                    }
                    string text = msg.Text.Substring(msg.Text.IndexOf(' ')).Trim();
                    string textLower = text.ToLowerInvariant();

                    StringBuilder emoji = new StringBuilder();
                    for (int i = 0; i < textLower.Length; i++) {
                        char c = textLower[i];

                        if (c == ' ' || c == '\v') emoji.Append("        ");
                        else if ('a' <= c && c <= 'z') emoji.Append($":regional_indicator_{c}: ");
                        else if (c == '0') emoji.Append(":zero: ");
                        else if (c == '1') emoji.Append(":one: ");
                        else if (c == '2') emoji.Append(":two: ");
                        else if (c == '3') emoji.Append(":three: ");
                        else if (c == '4') emoji.Append(":four: ");
                        else if (c == '5') emoji.Append(":five: ");
                        else if (c == '6') emoji.Append(":six: ");
                        else if (c == '7') emoji.Append(":seven: ");
                        else if (c == '8') emoji.Append(":eight: ");
                        else if (c == '9') emoji.Append(":nine: ");
                        else if (c == ',') emoji.Append(":black_small_square: ");
                        else if (c == '.') emoji.Append(":black_circle: ");
                        else if (c == '+') emoji.Append(":heavy_plus_sign: ");
                        else if (c == '-') emoji.Append(":heavy_minus_sign: ");
                        else if (c == '\u2715') emoji.Append(":heavy_multiplication_x: ");
                        else if (c == '\u00f7') emoji.Append(":heavy_division_sign: ");
                        else if (c == '!') emoji.Append(":exclamation: ");
                        else if (c == '?') emoji.Append(":question: ");
                        else if (c == '\'') emoji.Append(":arrow_down_small: ");
                        else if (c == '*') emoji.Append(":asterisk: ");
                        else if (c == '#') emoji.Append(":hash: ");

                        else emoji.Append(text[i]);
                    }

                    server.Send(msg.Channel, emoji.ToString());
                }
            });

            Commands.Add(new DisBotDCommand() {
                Name = "pasta",
                Info = "Stolen from Zatherz, too. Sorry!",
                Help = "",
                OnRun = (cmd_, server, msg, args) => server.Send(msg.Channel,
@"Hey Zath. I'm now quitting Discord.
I want you to know that the Enter the Gungeon server was the first big modding job that I've done, and while I did do some bad, I'm not letting your power whoring stopping me from doing anything I deem fun.The fact that you took the community I helped run, put yourself in charge, and not put me back on staff is the best proof I can think of for the fact that you have always wanted to abuse power much more than I ever have.You could have simply taught me a lesson and put me back on staff, but you didn't.
Like I said, I genuinely enjoyed running the community, and I didn't do the best all the time. I actually wanted to be friends with you. Most of the time, at least, while you were arguing with me about how I ran the server, I actually tried to be at least a little bit understanding on your end. Other times I said some rude things, and I take those mean words back. Anger feeding into anger doesn't get anyone anywhere, and that's exactly what I did. So I apologize for that. But you wouldn't.
See, this is what separates me from you -I'm willing to admit my flaws. I messed up, and I admitted it. You have done wrong in the past (not what we deem wrong, but things that are generally considered wrong across the board. For example, you made fun of autism, a certain member of the community complained about the fact that he had it himself, and you continued to do it), but you won't admit your flaws.It takes guts to admit that someone does something wrong, and that's exactly what I did. Meanwhile, while we aren't arguing and I'm away, you're constantly putting yourself up on a pedestal saying that the coup went "+"\"so well\""+@", that your plan to sabotage us was practically the best thing you've ever done. If your life amounts to bringing down a small group of people just because they did some wrong for a small internet community, then you seriously need to rethink your life.
This account will never be used again, and I genuinely don't care what you do to the community any more.  I don't care what you think about me.I don't even care if you ban me. All I know is that the community is now more toxic for the drama you helped spread (on the server and on the subreddit too) and you singlehandedly ruined it for not wanting to move on. I don't think the future is bright for the community right now, but all I can say is that I hope for the best, even with you leading it. Goodbye."
                    )
            });

            Parsers.Add(new DisBotDParser() {
                Name = "tableunflip",
                Info = "Your friendly tableunflipper bot.",
                OnParse = (parser, server, msg) => msg.Text.Contains("(╯°□°)╯︵ ┻━┻") || msg.Text.StartsWithInvariant("/tableflip"),
                OnRun = (parser, server, msg) => server.Send(msg.Channel, "┬──┬◡ノ(° -°ノ)")
            });

            Parsers.Add(new DisBotDParser() {
                Name = "hohono",
                Info = "hoho no.",
                OnParse = delegate (DisBotDParser parser, DisBotServerConfig server, Message msg) {
                    string text = msg.Text.ToLowerInvariant();
                    return
                        (text.Contains("haha") && text.Contains("yes")) ||
                        (text.Contains("fun") && text.Contains("central"));
                },
                OnRun = delegate (DisBotDParser parser, DisBotServerConfig server, Message msg) {
                    if (RNG.Next(6) > 1) return;
                    server.Send(msg.Channel, RNG.Next(4) <= 1 ? "hoho **NO.**" : RNG.Next(4) <= 1 ? "haha yes" : "hoho no");
                }
            });

            Parsers.Add(new DisBotDParser() {
                Name = "prefix",
                Info = "Set the disbot prefix (not a command): @disbot prefix [prefix]",
                OnParse = delegate (DisBotDParser parser, DisBotServerConfig server, Message msg) {
                    string[] split = msg.Text.Split(' ');
                    return msg.IsMentioningMe() && split.Length == 3 && split[1] == "prefix";
                },
                OnRun = delegate (DisBotDParser parser, DisBotServerConfig server, Message msg) {
                    if (server.Server == null) {
                        return;
                    }
                    if (!server.IsBotCommander(msg.User, msg)) {
                        return;
                    }
                    string[] split = msg.Text.Split(' ');
                    string prefix = split[2].Trim();
                    server.Prefix = prefix;
                    server.Save();
                    server.Send(msg.Channel, $"Prefix set to `{prefix}`.");
                }
            });

            // TODO
            new DisBotQImgModule().Init();
        }

        public static Task Start() {
            return Client.Connect(File.ReadAllText(Path.Combine(RootDir, TokenFile)).Trim(), TokenType.Bot);
        }

        public static void Run() {
            Client.ExecuteAndWait(
                async () => await Client.Connect(File.ReadAllText(Path.Combine(RootDir, TokenFile)).Trim(), TokenType.Bot)
            );
        }

        public static async void MessageReceived(object sender, MessageEventArgs e) {
            await Task.Run(() => GetServer(e.Server, true).MessageReceived(sender, e));
        }

        private static Dictionary<string, Image> _avatarCache = new Dictionary<string, Image>();
        private readonly static DColor _roundAvatarBG = DColor.FromArgb(unchecked((int) 0xFF36393E));
        public static async Task<Image> GetAvatarRound(User user, int size = 40) {
            Bitmap img = new Bitmap(size, size);
            Rectangle bounds = new Rectangle(0, 0, size, size);

            using (Graphics g = Graphics.FromImage(img)) {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                Image avatar = await GetAvatar(user);
                g.DrawImage(avatar, bounds, 0, 0, avatar.Width, avatar.Height, GraphicsUnit.Pixel);
            }

            using (Bitmap mask = new Bitmap(size, size)) {
                using (Graphics g = Graphics.FromImage(mask))
                using (SolidBrush brush = new SolidBrush(DColor.White))
                using (GraphicsPath ellipse = new GraphicsPath()) {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    ellipse.AddEllipse(0, 0, size - 1, size - 1);
                    g.FillPath(brush, ellipse);
                }

                img.ApplyMask(mask);
            }

            return img;
        }
        public static async Task<Image> GetAvatar(User user) {
            return await Task.Run(delegate () {
                Image img;
                if (!_avatarCache.TryGetValue(user.AvatarId, out img)) {
                    using (WebClient wc = new WebClient())
                    using (Stream s = wc.OpenRead(user.AvatarUrl)) {
                        img = Image.FromStream(s);
                    }
                    _avatarCache[user.AvatarId] = img;
                }
                return img;
            });
        }

        public static void ApplyMask(this Bitmap img, Bitmap mask) {
            Rectangle bounds = new Rectangle(0, 0, img.Width, img.Height);

            if (!IsMono) {
                BitmapData imgData = img.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                BitmapData maskData = mask.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                unsafe
                {
                    byte* imgP = (byte*) imgData.Scan0.ToPointer();
                    byte* maskP = (byte*) maskData.Scan0.ToPointer();
                    imgP += 3; // a
                    maskP += 3; // a
                    for (int i = bounds.Width * bounds.Height; i > 0; i--) {
                        *imgP = *maskP;
                        imgP += 4;
                        maskP += 4;
                    }
                }
                img.UnlockBits(imgData);
                mask.UnlockBits(maskData);

            } else {
                for (int y = bounds.Height - 1; y >= 0; y--) {
                    for (int x = bounds.Width - 1; x >= 0; x--) {
                        byte a = mask.GetPixel(x, y).A;
                        float f = a / 255f;
                        float ff = 1f - f;

                        if (f < 0.007f) {
                            img.SetPixel(x, y, _roundAvatarBG);
                            continue;
                        }

                        DColor cA = img.GetPixel(x, y);
                        DColor cB = _roundAvatarBG;
                        float r = cA.R * f + cB.R * ff;
                        float g = cA.G * f + cB.G * ff;
                        float b = cA.B * f + cB.B * ff;

                        img.SetPixel(x, y, DColor.FromArgb((byte) r, (byte) g, (byte) b));
                    }
                }
            }
        }

        public static string DateString(this DateTime time) {
            if (time == default(DateTime)) time = DateTime.UtcNow;
            return time.ToString("yyyy-MM-dd HH:mm:ss");
        }

        public static DisBotServerConfig GetServer(Server server, bool create = false) {
            DisBotServerConfig config;
            ulong id = server?.Id ?? 0UL;
            if (!Servers.TryGetValue(id, out config) && create) {
                Servers[id] = config = new DisBotServerConfig(server);
                config.Init();
            }
            return config;
        }
        public static void RemoveServer(Server server) {
            if (Servers.ContainsKey(server.Id)) {
                Servers.Remove(server.Id);
            }
        }

        public static long GetWebStreamLength(string url) {
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
            request.UserAgent = "disbot";
            request.Method = "HEAD";

            using (HttpWebResponse response = (HttpWebResponse) request.GetResponse()) {
                return response.ContentLength;
            }
        }

        public static bool StartsWithInvariant(this string a, string b) {
            return a.StartsWith(b, StringComparison.InvariantCulture);
        }

        public static Stream ToStream(this Image img, ImageFormat format = null) {
            format = format ?? ImageFormat.Png;
            MemoryStream ms = new MemoryStream();
            img.Save(ms, format);
            ms.Position = 0;
            return ms;
        }

        public static void CheckGDI() {
            // throw new Exception("GDI not supported.");
        }

        private readonly static object[] a_object_0 = new object[0];

        private readonly static MethodInfo m_Message_Clone =
            typeof(Message).GetMethod("Clone", BindingFlags.NonPublic | BindingFlags.Instance);
        private readonly static MethodInfo m_Message_set_Text =
            typeof(Message).GetProperty("Text", BindingFlags.Public | BindingFlags.Instance).GetSetMethod(true);
        public static Message Clone(this Message msg, string text = null) {
            Message clone = (Message) m_Message_Clone.Invoke(msg, a_object_0);
            if (text != null) {
                m_Message_set_Text.Invoke(clone, new object[] { text });
            }
            return clone;
        }

    }
}

redpajama_set_name: RedPajamaGithub


text:
Our Fragrant Past
Lisa Tant
The Roses of Heliogabalus by Alma-Tadema (1888)
Portrait of Louis XIV, 1701 (copy by Hyacinthe Rigaud studio)
Vintage perfume bottle
Estée Lauder. Photo courtesy of Estée Lauder
Coco Chanel by Boris Lipnitzki, 1936
A symbol of seduction.
The hallmark of wealth.
A holy grail.
A toxic murder weapon.
Flowers are at the heart of all perfumes, and an ongoing obsession for Fleurs de Villes. We'll bring you the latest news and fascinating fragrant facts but first, a brief history of perfume …
"Per fumum" the Latin phrase meaning "through smoke".
The Ancient Egyptians treasured perfumes believing them to be the sweat of the gods. Legend has it that Cleopatra coated the sails of her ship with fragrant oils as a sign of her seductive powers. The Ancient Greeks named their scents after Greek goddesses, while affluent Ancient Romans luxuriated in scented baths. The world's first recorded "nose" (perfume creator) was a Babylonian woman named Tapputi. Her wizardry using solvents to extract scents from resins and woods laid the foundation for a history of perfume. All around the globe, ancient cultures dabbled in scent making with perfumes reserved for royalty or religious figures.
Perfumes were blended from flower petals but also fruit (oranges, lime, vanilla), resins (myrrh and incense), roots (vetiver and verbena), spices (cinnamon), woods, and even animal fats (musk and ambergris). They were refined over the centuries as different cultures and personalities – royalty, conquerors and later celebrities – added their twists. In the 11th century, crusaders brought perfume made from musk, amber, jasmine and roses to Europe from their voyages across the Arab World and Far East. Venice, the travel hub for Marco Polo, flourished as the fragrance capital of Europe.
A fusion of scented lavender and rosemary oils in an alcohol solution, the first modern perfume was made in 1370 by the decree of Queen Elizabeth of Hungary. It became known as Hungary Water, and was further refined in Italy and France where the latter became the European centre for perfume production. Flash forward a few hundred years and perfume was used by the wealthy and royalty to mask body odour. A common belief that disease spread in water, made perfume more popular than soap. It was dabbed everywhere, including furniture, and perfumed gloves became a major industry. (Fragrance also hid the scent of the leather.) Crafty chemists also mixed formulas with poisons to become an unfortunately popular way to murder a troublesome member of court. These toxic scents were rubbed into gloves or fabric that was then absorbed by the skin.
The overwhelming heady fragranced world hit its peak in Louis XIV's French court which became known as "la cour parfumee" (the perfumed court). The King demanded a different fragrance every day for his apartments. Members of his court also had their own personalized blends.
In the late 19th century, the introduction of synthetic ingredients revolutionized the concept of perfume. Instead of a regal luxury, the mixes of flowers, spices and herbs became a mass produced delight that was quickly incorporated into daily beauty routines. Many of the world's best known perfume brands including Guerlain, Roger and Gallet, and Coty took root in France. Cultivation of flowers for their essence was centered in the warm sunny south in Grasse which is known today as the capital of perfume. Miles of fields of roses, lavender and jasmine are cultivated here and then blended into new scents by professional "noses" based in the French Riviera.
In the early 1900s, the first fragrance to associate with designer fashion was created by Paul Poiret. His inspiration for his scents was echoed in his exotic kimono style coats, harem pants and turbans. The bottles housing the "juice" became as intricate, quickly gaining collectors status. There was no turning back.
1920 saw the stylish rise of one of the most savvy female business women of modern times. Sleek, petite and impossibly chic, Coco Chanel launched her style revolution with a millinery boutique in 1921. Soon after, her direction for a bold fresh new scent resulted in the use of aldehydes, a fizzy family of chemicals. The synthetic notes propelled the blend of jasmine, rose, vanilla and sandalwood, Chanel No5 - still one of the world's leading scents, celebrating their 100th anniversary in 2021 - was born.
Thirty years later, another wildly innovative savvy business woman, Estée Lauder, created Youth Dew in New York. Named after one of her successful skin creams, Youth Dew was formulated as a bath oil to start a craze for wearing scents as an everyday pleasure.
The 21st century introduced a new scent for every Tom, Dick and Jane celebrity. Boy bands launched one. Pop stars, opera singers, Hollywood actors (both legends and newbies) sold millions of bottles, introducing a new juice every year. Fashion houses relied upon lucrative scents to fund their apparel business. Fragrances mirror the times as scents focus less on gender and more on lifestyle. From its roots with ancient civilizations, perfume is the original natural sustainable luxury.
According to a report by Grand View Research, the global fragrance market is projected to be worth more than $91 billion by 2025.

redpajama_set_name: RedPajamaCommonCrawl


text:
	<title>Laurie Kilmartin's panel show appearances</title>

	<link rel="stylesheet" media="all" href="../style.css" type="text/css"/>

Laurie Kilmartin's panel show appearances

Laurie Kilmartin has appeared in 1 episodes between 2021-2021. Note that these appearances may be for more than one person if multiple people have the same name.

2021

2021-04-02 / The Blame Game


text:
Q: Show image out of WAR application I am working in a Struts application and I need to show an image in the JSP that is contained out of the WAR content.
The application is running from:
/servicios/was7/watt/instalado/app.WAR

And the image is placed in:
/servicios/was7/watt/compartido/plantillas_prmifid/T_ES_MIFID_26052008.jpg

I don't know how to access by the attribute src of the <img> tag to the required path.  How to form the path for the image?

A: JSR 315: You can load resources from /META-INF/resources from the Context of your Webapplication.
This does only works on web-xml from version 3.0.
You see: no need to place resources out of the war.

redpajama_set_name: RedPajamaStackExchange


text:
Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat
Kazuya Idemitsu, Syeda Afsarun Nessa, Shigeru Yamazaki, Hirotomo Ikeuchi, Yaohiro Inagaki, Tatsumi Arima
Quantum Sciences of Materials
Carbon steel overpack is corroded by consuming oxygen introduced by repository construction after closure of the repository and then maintains the reducing environment in the vicinity of the repository. The migration of iron corrosion products through the buffer material will affect the migration of redox-sensitive radionuclides. Therefore, it is important to study the migration of iron corrosion products through the buffer material because it may affect the corrosion rate of overpack, and migration of redox-sensitive radionuclides. Electromigration experiments have been conducted with the source of iron ions supplied by anode corrosion of the iron coupon in compacted bentonite. The carbon steel coupon was connected as the working electrode to the potentiostat and was held at a constant supplied potential between - 650 to +300 mV vs. Ag/AgCl electrode for up to 168 hours. The amount of iron penetrated into a bentonite specimen was in good agreement with the calculated value from the corrosion current under the assumption that iron is dissolved as ferrous ions. A model using dispersion and electromigration could explain the measured iron profiles in the bentonite specimens. The fitted value of electromigration velocity depended on the potential supplied. On the other hand the fitted value of the dispersion coefficient did not depend on the potential supplied but a constant. This constant dispersion coefficient could be due to the much larger diffusion coefficient of ferrous ion in bentonite compared with the effect of mechanical dispersion. The experimental configurations used in this study are applicable to the examination of the migration behaviour of cations with the source of iron ions under a reducing condition controlled with a potentiostat.
Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI
31st International Symposium on the Scientific Basis for Nuclear Waste Management - Sheffield, United Kingdom
Duration: Sep 16 2007 → Sep 21 2007
31st International Symposium on the Scientific Basis for Nuclear Waste Management
Electromigration
carbon steels
Idemitsu, K., Nessa, S. A., Yamazaki, S., Ikeuchi, H., Inagaki, Y., & Arima, T. (2008). Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat. In Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI (Vol. 1107, pp. 501-508)
Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat. / Idemitsu, Kazuya; Nessa, Syeda Afsarun; Yamazaki, Shigeru; Ikeuchi, Hirotomo; Inagaki, Yaohiro; Arima, Tatsumi.
Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI. Vol. 1107 2008. p. 501-508.
Idemitsu, K, Nessa, SA, Yamazaki, S, Ikeuchi, H, Inagaki, Y & Arima, T 2008, Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat. in Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI. vol. 1107, pp. 501-508, 31st International Symposium on the Scientific Basis for Nuclear Waste Management, Sheffield, United Kingdom, 9/16/07.
Idemitsu K, Nessa SA, Yamazaki S, Ikeuchi H, Inagaki Y, Arima T. Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat. In Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI. Vol. 1107. 2008. p. 501-508
Idemitsu, Kazuya ; Nessa, Syeda Afsarun ; Yamazaki, Shigeru ; Ikeuchi, Hirotomo ; Inagaki, Yaohiro ; Arima, Tatsumi. / Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat. Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI. Vol. 1107 2008. pp. 501-508
@inproceedings{dd6c3aa78a2647c58b7e4a6ab3d52b1c,
title = "Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat",
abstract = "Carbon steel overpack is corroded by consuming oxygen introduced by repository construction after closure of the repository and then maintains the reducing environment in the vicinity of the repository. The migration of iron corrosion products through the buffer material will affect the migration of redox-sensitive radionuclides. Therefore, it is important to study the migration of iron corrosion products through the buffer material because it may affect the corrosion rate of overpack, and migration of redox-sensitive radionuclides. Electromigration experiments have been conducted with the source of iron ions supplied by anode corrosion of the iron coupon in compacted bentonite. The carbon steel coupon was connected as the working electrode to the potentiostat and was held at a constant supplied potential between - 650 to +300 mV vs. Ag/AgCl electrode for up to 168 hours. The amount of iron penetrated into a bentonite specimen was in good agreement with the calculated value from the corrosion current under the assumption that iron is dissolved as ferrous ions. A model using dispersion and electromigration could explain the measured iron profiles in the bentonite specimens. The fitted value of electromigration velocity depended on the potential supplied. On the other hand the fitted value of the dispersion coefficient did not depend on the potential supplied but a constant. This constant dispersion coefficient could be due to the much larger diffusion coefficient of ferrous ion in bentonite compared with the effect of mechanical dispersion. The experimental configurations used in this study are applicable to the examination of the migration behaviour of cations with the source of iron ions under a reducing condition controlled with a potentiostat.",
author = "Kazuya Idemitsu and Nessa, {Syeda Afsarun} and Shigeru Yamazaki and Hirotomo Ikeuchi and Yaohiro Inagaki and Tatsumi Arima",
booktitle = "Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI",
T1 - Migration behaviour of ferrous ion in compacted bentonite under reducing conditions controlled with potentiostat
AU - Idemitsu, Kazuya
AU - Nessa, Syeda Afsarun
AU - Yamazaki, Shigeru
AU - Ikeuchi, Hirotomo
AU - Inagaki, Yaohiro
AU - Arima, Tatsumi
N2 - Carbon steel overpack is corroded by consuming oxygen introduced by repository construction after closure of the repository and then maintains the reducing environment in the vicinity of the repository. The migration of iron corrosion products through the buffer material will affect the migration of redox-sensitive radionuclides. Therefore, it is important to study the migration of iron corrosion products through the buffer material because it may affect the corrosion rate of overpack, and migration of redox-sensitive radionuclides. Electromigration experiments have been conducted with the source of iron ions supplied by anode corrosion of the iron coupon in compacted bentonite. The carbon steel coupon was connected as the working electrode to the potentiostat and was held at a constant supplied potential between - 650 to +300 mV vs. Ag/AgCl electrode for up to 168 hours. The amount of iron penetrated into a bentonite specimen was in good agreement with the calculated value from the corrosion current under the assumption that iron is dissolved as ferrous ions. A model using dispersion and electromigration could explain the measured iron profiles in the bentonite specimens. The fitted value of electromigration velocity depended on the potential supplied. On the other hand the fitted value of the dispersion coefficient did not depend on the potential supplied but a constant. This constant dispersion coefficient could be due to the much larger diffusion coefficient of ferrous ion in bentonite compared with the effect of mechanical dispersion. The experimental configurations used in this study are applicable to the examination of the migration behaviour of cations with the source of iron ions under a reducing condition controlled with a potentiostat.
AB - Carbon steel overpack is corroded by consuming oxygen introduced by repository construction after closure of the repository and then maintains the reducing environment in the vicinity of the repository. The migration of iron corrosion products through the buffer material will affect the migration of redox-sensitive radionuclides. Therefore, it is important to study the migration of iron corrosion products through the buffer material because it may affect the corrosion rate of overpack, and migration of redox-sensitive radionuclides. Electromigration experiments have been conducted with the source of iron ions supplied by anode corrosion of the iron coupon in compacted bentonite. The carbon steel coupon was connected as the working electrode to the potentiostat and was held at a constant supplied potential between - 650 to +300 mV vs. Ag/AgCl electrode for up to 168 hours. The amount of iron penetrated into a bentonite specimen was in good agreement with the calculated value from the corrosion current under the assumption that iron is dissolved as ferrous ions. A model using dispersion and electromigration could explain the measured iron profiles in the bentonite specimens. The fitted value of electromigration velocity depended on the potential supplied. On the other hand the fitted value of the dispersion coefficient did not depend on the potential supplied but a constant. This constant dispersion coefficient could be due to the much larger diffusion coefficient of ferrous ion in bentonite compared with the effect of mechanical dispersion. The experimental configurations used in this study are applicable to the examination of the migration behaviour of cations with the source of iron ions under a reducing condition controlled with a potentiostat.
BT - Materials Research Society Symposium Proceedings - Scientific Basis for Nuclear Waste Management XXXI


text:
Review: Jane Eyre
It's time for my review of Jane Eyre.
My Mum was really eager to see Jane Eyre, as it was a book she has studied at school and had really enjoyed. I knew little about both the show and the original book, but had high hopes from what had been described to me. Luckily, this was indeed an excellent choice. It's a really unique and quirky production and its creativity is something which is quite rare. Part of this quirkiness is that Jane Eyre relies heavily on physical theatre, something which I'm not always a fan of, but it worked well here. The story follows an orphan, who despite facing horrific cruelty by her adopted family and by her teachers at school, overcomes what everyone thought of her and becomes a governess. The show follows a large portion of Jane Eyre's life and by the end of the show you feel like you have been on a journey. It's a very inspiring tale and one I found to be extremely moving. The cast are extraordinary and cannot be faulted in anyway. With the exclusion of two cast members, they all played multiple roles. Multi-roleing can become difficult, but I thought they did a terrific job at differentiating characters. Each and every cast members showed good characterisations and a large variety of talent. Jane Eyre features music, which I thought was a really nice addition. It was especially good that the decision was made to have a live band onstage, as opposed to just using pre-recorded music. In addition to this, the shows singer Melanie Marshall had an absolutely phenomenal voice! Lighting, costume and sound design were all brilliant, I have no complaints in any of those aspects. The set design didn't particularly wow me, but it was still able to serve its purpose well. My only criticism for the show is that it is slightly too long (three hours). Without a doubt, this production could have easily been shortened by at least half an hour. Due to the length of the show my concentration wavered a little, which was a shame. There are some who like long plays, but I personally feel they should be kept to a maximum of 2 and a half hours (I'm fine with musicals being a bit longer).
The featured star of Jane Eyre is, drum roll please... NADIA CLIFFORD!
Nadia gives an absolutely outstanding performance as Jane Eyre! I'm not 100% sure if this correct, but I can't actually remember Nadia leaving the stage at any point throughout the entire show. It's incredible that she would have the stamina to do this demanding role for three hours (especially as this was a two show day).
Now for my final verdict on Jane Eyre. I give Jane Eyre...
This rating was easy for me to give. It's not quite a 5 star, but it's miles above a 3 star!
-The Reviewer
Posted by The Basic Theatre Reviewer at 13:22 No comments:
Review: An Octoroon
It's time for my review of An Octoroon.
Having not been to the Orange Tree Theatre in a long time and having a free Saturday afternoon, An Octoroon seemed like the perfect show to go and see at the weekend. It was also a lot better than having to venture into London (which takes around 45 minutes). Sadly though, An Octoroon was not the show for me. Honestly, it seemed that the show lacked consistency. There were certain parts of the show that were a little all over the place. An Octoroon left me somewhat baffled and even four days after seeing it, I am struggling to understand certain parts of it. It took me over half an hour to realise what was going on onstage. It's described as being a 'play, within a play, within a play', which is an interesting concept but not one that I felt worked particularly well. The playwright of the adaption has merged himself and his life, the original playwright of Octoroon's life and the play itself. From what I could gather, the original play itself didn't really did much editing, and therefore I am not really sure as to why so many different elements were added in. As the old saying goes, "if it ain't broke, don't fix it". Luckily, that's all I have to say about the negatives of the show, let's move onto positives! The best thing about An Octoroon was its phenomenal cast. They all delivered extremely good performances in what were very demanding roles. They all showed a vast variety of talents; including some amazing American accents (I seriously believed they were all actually American). The majority of the technical aspects were good, with lighting, costume and sound design all being impressive. The storyline (the original storyline, that is, not the added parts) was actually really interesting and was able to educate me further on the issues of slavery in America. The use of white face and black face makeup was extremely unique; it's something I've never seen done before. If the parts that were added in (the two playwright's) were taken out, I would definitely see this production again. This production ticks a lot of the right boxes, but sadly it still manages to miss the mark.
The featured star of An Octoroon is, drum roll please... VIVIAN OPARAH!
It took me ages to make this decision, so in the end I decided to go through each cast member and give them a rating out of ten. The actors with the highest ratings (9/10) were Ken Nwosu, Vivian Oparah and Celeste Dodwell. From there, I just had to go with gut instinct. Vivan Oparah gave a phenomenal performance. She was immensely funny, and yet was also very good at the more serious parts of her role. It's amazing to think this is her theatre debut!
Now for my final verdict on An Octoroon. I give An Octoroon...
An Octoroon was far from the best show I have ever seen, but I cannot deny that it does have a fair amount of redeeming qualities, which is why I award An Octoroon three stars.
Review: Don Juan in Soho
It's time for my review of Don Juan in Soho.
We had originally booked to see this back in Easter, but had to exchange tickets due to my America trip during that week, so I ended up seeing it last weekend. I had heard very mixed opinions about it and from what I had heard it seemed like it was a 'love it or hate it' type show. Fortunately, I was one of those that loved it and the show really appealed to my sense of humour. The aspect of the show that makes it really special is David Tennant's performance of Don Juan. To say he is amazing would be an understatement; this is the role he was born to play. As much as I love him onscreen, I actually thought it was better to see him live. He absolutely nailed everything about the part. He was great at the comedic parts, he was great at the more serious parts and adding to that, he had hilarious facial expressions. David Tennant's performance is worth the ticket price alone! I don't think I would have enjoyed the show as much, if it didn't have him in. At David's side was Adrian Scarborough as Stan, Don Juan's trusted servant. Adrian also gave a remarkable performance and holds his own alongside David Tennant. He had very good comic timing and was perfectly cast. The remainder of the cast cannot be faulted either. The writing is extremely clever and witty; I was laughing throughout! I had seen another play which had been written by Patrick Marber called Three Days in the Country, and as good as that was, I really think the writer is truly in his element here. All the production aspects cannot be faulted, with the lighting, costume, set and sound design all being excellent. To my surprise, Don Juan in Soho features several modern dance numbers, which added to the craziness of the show and fitted in nicely. It's a really well made production and has been carefully thought out. Now for my criticisms (luckily, there's only a few). A lot of crazy and exciting things happened in act one, but act two felt a little flat. I was really excited in the intermission as to what would happen next, but act two just appeared as being non-eventful and rushed. The ending happened extremely quickly. I think it would have been a good idea to stretch out the ending a little more. My only other critique is that, during the play the character of Stan speaks to the audience and I wasn't sure that this was carried out too well. It was a nice idea, but if I had been directing it, I would have organised for the light to purely be on Stan during his asides. That's a nitpick though, and doesn't really affect the show as a whole.
The featured star of Don Juan in Soho is, drum roll please... DAVID TENANT!
I don't see how there could be any way to fault this performance. David Tenant's portrayal of Don Juan is perfect in every way! I would love to see David Tennant onstage again, as he is pure magic when seen live.
Now for my final verdict on Don Juan in Soho. I give Don Juan in Soho...
Don Juan in Soho is only playing for another 5 days, but luckily there are tickets that are still available, so if you think this would be your kind of show, don't delay in getting tickets!
Review: Woyzeck
It's time for my review of Woyzeck.
Due it being a very busy week for me with revising for my Summer exams, I had done little to no research on Woyzeck before seeing it, which is somewhat rare for me. Being the huge Star Wars geek I am, I was really keen to see this due to its lead star, John Boyega (John played a lead role in the most recent Star Wars film: The Force Awakens). Woyzeck was extremely unique and quite different. It was not what I was expecting, but it was good nevertheless. Woyzeck deals with the dehumanising effects of doctors and the military on a young man's life. It's a very important issue, which was heartbreaking and moving to witness. It is excellently written and well structured. All cast members were remarkable, with the stand-outs being John Boyega as Woyzeck, Sarah Greene as Marie and Ben Batt as Andrews. What struck me the most with John Boyega's performance was that he showed a wide diversity of acting abilities throughout the play. Woyzeck begins as a funny, loving and caring boyfriend and father, but by the end of the play he becomes a psychotic, disturbed and controlling individual. Sarah Greene was definitely on a par with John and she also gave an absolutely phenomenal performance. She was perfectly cast. Adding to this, Ben Batt also gave an exceptional performance, especially in his final scene where his character unexpectedly turns violent. The lighting and sound design have an extremely large impact on the show; I actually don't think it would have had the same effect without these two elements. They were both very powerful and extremely well designed. A warning to those that have an interest in seeing this play is that it has some heavy nudity, sex and vulgar language. I wasn't expecting it, so it came as a little bit of a shock. I feel perhaps the nudity, sex and vulgar language were overdone a little bit, but it didn't affect my enjoyment of the show. The set design was a bit of an odd one and it left me wondering as to what was the point of it. Considering the light and sound design were both phenomenal, I definitely think that more effort could have gone into the set.
The featured star of Woyzeck is, drum roll please... JOHN BOYEGA!
The role of Woyzeck is extremely demanding and it's amazing to think that John pulls it off 18 times a week. The role seems absolutely perfect for him and he nailed it! I hope he considers doing more theatre in the future.
Now for my final verdict on Woyzeck. I give Woyzeck...
As I mentioned, this is a really unique production; I don't think I've ever seen anything quite like it. It's one I would most likely recommend; however the themes may be a little off-putting for some.
Review: The Girls
It's time for my review of The Girls.
Before seeing The Girls, I had heard a lot of buzz about the show. It had received extremely good reviews plus a few Olivier Award nominations. Another factor for me was that The Girls had been composed by Gary Barlow. I don't know a lot about Take That, but I adore Barlow's other musical 'Finding Neverland'. This show had a lot to live up to! I am very pleased to say that The Girls lived up to my expectations and I thoroughly enjoyed it. It was a really sweet and heartwarming show, with a nice feel-good factor. Adding to this, it also delivers a really powerful message of hope, acceptance and not always judging a book by its cover. The story follows a group of middle-aged women in Yorkshire who decided to make a nude calendar to raise money for a settee at the local hospital. It seemed like a wild idea, but they had hope and did not give up, despite how daunting it seemed. It's an inspiring tale that tells its audience to try new things and not give up, no matter how scary or unsettling it may be. After all, you only live once! The book of the show (written by Gary Barlow and Tim Firth) is fantastically written and is one of the best musical books I have seen since Groundhog Day. It's hilariously written and had the audience in stitches! At the performance I attended, a total of 6 understudies were performing (I wonder what the record is?). There was absolutely nothing to fear though; every single cast member was remarkable and very well cast. Cast members who stood out were Jenny Gayner who was understudying as Annie, Claire Moore as Chris, Claire Machin as Cora, Sophie-Louise Dann as Celia, Judith Street who was understudying as Jessie, Debbie Chazen as Ruth, James Gaddas as John, Josh Benson as Tommo and Ben Hunter as Danny. Each cast member seemed absolutely perfect for their role. They all gelled with each other extremely well. The set design consists of several mini wardrobes stacked on top of each other, which represent hills. If I'm honest, I didn't quite see the point of the set design. I feel as if it may have symbolised something, but I'm not quite sure. Having said that, it still did a good job and serviced the show well. Now for my one critique (it's not even really much of a critique, more an aberration)... I wasn't that stunned with the music. The music was not bad by any means, but it didn't leave any impact on me. There's only one song from The Girls which has stuck in my mind. The music isn't really a big deal though, as the book of the show makes up for it.
The featured star of The Girls is, drum roll please... CLAIRE MOORE!
As phenomenal as the cast are, this was a decision that came quite easy to me. I thought Claire was both hilarious and moving in the role of Chris. I personally felt that she had a large command of the stage. There was certainly never a dull moment during any of her scenes!
Now for my final verdict on The Girls. I give The Girls...
This rating was one that I struggled with, as it's very close to a 5 star, but went with four in the end. Sadly, The Girls closes on the 15th of July, so I highly recommend this one before it closes. If you see this show, there's a high chance you will leave feeling happy and inspired!


Thanks to Mike for the suggestion to add the create/insert statements.
but I can't work out how to use the dense_rank() trick with other window functions to get the right result.
Subtracting a date from another date yields an integer. Since you are looking for consecutive days, every next row would be greater by one. If we subtract row_number() from that, the whole streak ends up in the same group (grp) per pid. Then it's simple to deal out number per group.
One multiplication, one subtraction. String concatenation and casting is more expensive. Test with EXPLAIN ANALYZE.
Don't forget to partition by pid additionally in both steps, or you'll inadvertently mix groups that should be separated.
Using a subquery, since that is typically faster than a CTE. There is nothing here that a plain subquery couldn't do.
And since you mentioned it: dense_rank() is obviously not necessary here. Basic row_number() does the job.
You'll get more attention if you include CREATE TABLE statements and INSERT statements in your question.
The principle is simple. A streak of distinct, consecutive dates minus row_number() is a constant. You can group by the constant, and take the dense_rank() over that result.
Not the answer you're looking for? Browse other questions tagged sql postgresql window-functions date-arithmetic gaps-and-islands or ask your own question.
How can I rank items in a RDD to build a streak?
How to return the latest row written for the day?


Answer a few questions and view jobs at Hotchkis & Wiley Global Value Fund that match your preferences.
Do You Work At Hotchkis & Wiley Global Value Fund?
How Would You Rate The Company Culture Of Hotchkis & Wiley Global Value Fund?
Have you worked at Hotchkis & Wiley Global Value Fund? Help other job seekers by rating Hotchkis & Wiley Global Value Fund.
You can find out what it is like to work at Hotchkis & Wiley Global Value Fund, also known as Hotchkis & Wiley Capital Mgmt and Hotchkis & Wiley Global Value Fund.
Zippia gives an in-depth look into the details of Hotchkis & Wiley Global Value Fund, including salaries, political affiliations, employee data, and more, in order to inform job seekers about Hotchkis & Wiley Global Value Fund. The employee data is based on information from people who have self-reported their past or current employments at Hotchkis & Wiley Global Value Fund. While we have made attempts to ensure that the information displayed are correct, Zippia is not responsible for any errors or omissions, or for the results obtained from the use of this information. The data presented on this page does not represent the view of Hotchkis & Wiley Global Value Fund and its employees or that of Zippia.