text:
using System;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ServiceStack.Text.Common;
using ServiceStack.Text.Json;
using ServiceStack.Text.Pools;

namespace ServiceStack.Text
{
    public sealed class DefaultMemory : MemoryProvider
    {
        private static DefaultMemory provider;
        public static DefaultMemory Provider => provider ?? (provider = new DefaultMemory());
        private DefaultMemory() { }

        public static void Configure() => Instance = Provider;

        public override bool ParseBoolean(ReadOnlySpan<char> value)
        {
            if (!value.TryParseBoolean(out bool result))
                throw new FormatException(BadFormat);

            return result;
        }

        public override bool TryParseBoolean(ReadOnlySpan<char> value, out bool result)
        {
            result = false;

            if (value.CompareIgnoreCase(bool.TrueString.AsSpan()))
            {
                result = true;
                return true;
            }

            return value.CompareIgnoreCase(bool.FalseString.AsSpan());
        }

        public override bool TryParseDecimal(ReadOnlySpan<char> value, out decimal result) =>
            TryParseDecimal(value, allowThousands: true, out result);

        public override decimal ParseDecimal(ReadOnlySpan<char> value) => ParseDecimal(value, allowThousands: true);

        public override decimal ParseDecimal(ReadOnlySpan<char> value, bool allowThousands)
        {
            if (!TryParseDecimal(value, allowThousands, out var result))
                throw new FormatException(BadFormat);

            return result;
        }

        public override bool TryParseFloat(ReadOnlySpan<char> value, out float result) => float.TryParse(
            value.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture,
            out result);

        public override float ParseFloat(ReadOnlySpan<char> value) => float.Parse(value.ToString(),
            NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture);

        public override bool TryParseDouble(ReadOnlySpan<char> value, out double result) => double.TryParse(
            value.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture,
            out result);

        public override double ParseDouble(ReadOnlySpan<char> value) => double.Parse(value.ToString(),
            NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture);

        public override sbyte ParseSByte(ReadOnlySpan<char> value) => SignedInteger<sbyte>.ParseSByte(value);

        public override byte ParseByte(ReadOnlySpan<char> value) => UnsignedInteger<byte>.ParseByte(value);

        public override short ParseInt16(ReadOnlySpan<char> value) => SignedInteger<short>.ParseInt16(value);

        public override ushort ParseUInt16(ReadOnlySpan<char> value) => UnsignedInteger<ushort>.ParseUInt16(value);

        public override int ParseInt32(ReadOnlySpan<char> value) => SignedInteger<int>.ParseInt32(value);

        public override uint ParseUInt32(ReadOnlySpan<char> value) => UnsignedInteger<uint>.ParseUInt32(value);

        public override uint ParseUInt32(ReadOnlySpan<char> value, NumberStyles style) =>
            uint.Parse(value.ToString(), style);

        public override long ParseInt64(ReadOnlySpan<char> value) => SignedInteger<int>.ParseInt64(value);

        public override ulong ParseUInt64(ReadOnlySpan<char> value) => UnsignedInteger<ulong>.ParseUInt64(value);

        internal static Exception CreateOverflowException(long maxValue) =>
            new OverflowException(string.Format(OverflowMessage, SignedMaxValueToIntType(maxValue)));

        internal static Exception CreateOverflowException(ulong maxValue) =>
            new OverflowException(string.Format(OverflowMessage, UnsignedMaxValueToIntType(maxValue)));

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static string SignedMaxValueToIntType(long maxValue)
        {
            switch (maxValue)
            {
                case sbyte.MaxValue:
                    return nameof(SByte);
                case short.MaxValue:
                    return nameof(Int16);
                case int.MaxValue:
                    return nameof(Int32);
                case long.MaxValue:
                    return nameof(Int64);
                default:
                    return "Unknown";
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static string UnsignedMaxValueToIntType(ulong maxValue)
        {
            switch (maxValue)
            {
                case byte.MaxValue:
                    return nameof(Byte);
                case ushort.MaxValue:
                    return nameof(UInt16);
                case uint.MaxValue:
                    return nameof(UInt32);
                case ulong.MaxValue:
                    return nameof(UInt64);
                default:
                    return "Unknown";
            }
        }

        public static bool TryParseDecimal(ReadOnlySpan<char> value, bool allowThousands, out decimal result)
        {
            result = 0;

            if (value.Length == 0)
                return false;

            ulong preResult = 0;
            bool isLargeNumber = false;
            int i = 0;
            int end = value.Length;
            var state = ParseState.LeadingWhite;
            bool negative = false;
            bool noIntegerPart = false;
            sbyte scale = 0;

            while (i < end)
            {
                var c = value[i++];

                switch (state)
                {
                    case ParseState.LeadingWhite:
                        if (JsonUtils.IsWhiteSpace(c))
                            break;

                        if (c == '-')
                        {
                            negative = true;
                            state = ParseState.Sign;
                        }
                        else if (c == '.')
                        {
                            noIntegerPart = true;
                            state = ParseState.FractionNumber;

                            if (i == end)
                                return false;
                        }
                        else if (c == '0')
                        {
                            state = ParseState.DecimalPoint;
                        }
                        else if (c > '0' && c <= '9')
                        {
                            preResult = (ulong) (c - '0');
                            state = ParseState.Number;
                        }
                        else return false;

                        break;
                    case ParseState.Sign:
                        if (c == '.')
                        {
                            noIntegerPart = true;
                            state = ParseState.FractionNumber;

                            if (i == end)
                                return false;
                        }
                        else if (c == '0')
                        {
                            state = ParseState.DecimalPoint;
                        }
                        else if (c > '0' && c <= '9')
                        {
                            preResult = (ulong) (c - '0');
                            state = ParseState.Number;
                        }
                        else return false;

                        break;
                    case ParseState.Number:
                        if (c == '.')
                        {
                            state = ParseState.FractionNumber;
                        }
                        else if (c >= '0' && c <= '9')
                        {
                            if (isLargeNumber)
                            {
                                checked
                                {
                                    result = 10 * result + (c - '0');
                                }
                            }
                            else
                            {
                                preResult = 10 * preResult + (ulong) (c - '0');
                                if (preResult > ulong.MaxValue / 10 - 10)
                                {
                                    isLargeNumber = true;
                                    result = preResult;
                                }
                            }
                        }
                        else if (JsonUtils.IsWhiteSpace(c))
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else if (allowThousands && c == ',') { }
                        else return false;

                        break;
                    case ParseState.DecimalPoint:
                        if (c == '.')
                        {
                            state = ParseState.FractionNumber;
                        }
                        else return false;

                        break;
                    case ParseState.FractionNumber:
                        if (JsonUtils.IsWhiteSpace(c))
                        {
                            if (noIntegerPart)
                                return false;
                            state = ParseState.TrailingWhite;
                        }
                        else if (c == 'e' || c == 'E')
                        {
                            if (noIntegerPart && scale == 0)
                                return false;
                            state = ParseState.Exponent;
                        }
                        else if (c >= '0' && c <= '9')
                        {
                            if (isLargeNumber)
                            {
                                checked
                                {
                                    result = 10 * result + (c - '0');
                                }
                            }
                            else
                            {
                                preResult = 10 * preResult + (ulong) (c - '0');
                                if (preResult > ulong.MaxValue / 10 - 10)
                                {
                                    isLargeNumber = true;
                                    result = preResult;
                                }
                            }

                            scale++;
                        }
                        else return false;

                        break;
                    case ParseState.Exponent:
                        bool expNegative = false;
                        if (c == '-')
                        {
                            if (i == end)
                                return false;

                            expNegative = true;
                            c = value[i++];
                        }
                        else if (c == '+')
                        {
                            if (i == end)
                                return false;
                            c = value[i++];
                        }

                        //skip leading zeroes
                        while (c == '0' && i < end) c = value[i++];

                        if (c > '0' && c <= '9')
                        {
                            var exp = SignedInteger<long>.ParseInt64(value.Slice(i - 1, end - i + 1));
                            if (exp < sbyte.MinValue || exp > sbyte.MaxValue)
                                return false;

                            if (!expNegative)
                            {
                                exp = (sbyte) -exp;
                            }

                            if (exp >= 0 || scale > -exp)
                            {
                                scale += (sbyte) exp;
                            }
                            else
                            {
                                for (int j = 0; j < -exp - scale; j++)
                                {
                                    if (isLargeNumber)
                                    {
                                        checked
                                        {
                                            result = 10 * result;
                                        }
                                    }
                                    else
                                    {
                                        preResult = 10 * preResult;
                                        if (preResult > ulong.MaxValue / 10)
                                        {
                                            isLargeNumber = true;
                                            result = preResult;
                                        }
                                    }
                                }

                                scale = 0;
                            }

                            //set i to end of string, because ParseInt16 eats number and all trailing whites
                            i = end;
                        }
                        else return false;

                        break;
                    case ParseState.TrailingWhite:
                        if (!JsonUtils.IsWhiteSpace(c))
                            return false;
                        break;
                }
            }

            if (!isLargeNumber)
            {
                var mid = (int) (preResult >> 32);
                var lo = (int) (preResult & 0xffffffff);
                result = new decimal(lo, mid, 0, negative, (byte) scale);
            }
            else
            {
                var bits = decimal.GetBits(result);
                result = new decimal(bits[0], bits[1], bits[2], negative, (byte) scale);
            }

            return true;
        }

        private static readonly byte[] lo16 = {
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 0, 1,
            2, 3, 4, 5, 6, 7, 8, 9, 255, 255,
            255, 255, 255, 255, 255, 10, 11, 12, 13, 14,
            15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 10, 11, 12,
            13, 14, 15
        };

        private static readonly byte[] hi16 = {
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 0, 16,
            32, 48, 64, 80, 96, 112, 128, 144, 255, 255,
            255, 255, 255, 255, 255, 160, 176, 192, 208, 224,
            240, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 160, 176, 192,
            208, 224, 240
        };

        public override Guid ParseGuid(ReadOnlySpan<char> value)
        {
            if (value.IsEmpty)
                throw new FormatException(BadFormat);

            //Guid can be in one of 3 forms:
            //1. General `{dddddddd-dddd-dddd-dddd-dddddddddddd}` or `(dddddddd-dddd-dddd-dddd-dddddddddddd)` 8-4-4-4-12 chars
            //2. Hex `{0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}`  8-4-4-8x2 chars
            //3. No style `dddddddddddddddddddddddddddddddd` 32 chars

            int i = 0;
            int end = value.Length;
            while (i < end && JsonUtils.IsWhiteSpace(value[i])) i++;

            if (i == end)
                throw new FormatException(BadFormat);

            var result = ParseGeneralStyleGuid(value.Slice(i, end - i), out var guidLen);
            i += guidLen;

            while (i < end && JsonUtils.IsWhiteSpace(value[i])) i++;

            if (i < end)
                throw new FormatException(BadFormat);

            return result;
        }

        public override void Write(Stream stream, ReadOnlyMemory<char> value)
        {
            var bytes = BufferPool.GetBuffer(Encoding.UTF8.GetMaxByteCount(value.Length));
            try
            {
                var chars = value.ToArray();
                int bytesCount = Encoding.UTF8.GetBytes(chars, 0, chars.Length, bytes, 0);
                stream.Write(bytes, 0, bytesCount);
            }
            finally
            {
                BufferPool.ReleaseBufferToPool(ref bytes);
            }
        }

        public override void Write(Stream stream, ReadOnlyMemory<byte> value)
        {
            if (MemoryMarshal.TryGetArray(value, out var segment) && segment.Array != null)
            {
                byte[] bytes = BufferPool.GetBuffer(segment.Count);
                try
                {
                    stream.Write(segment.Array, 0, segment.Count);
                }
                finally
                {
                    BufferPool.ReleaseBufferToPool(ref bytes);
                }
            }
            else
            {
                var bytes = value.ToArray();
                stream.Write(bytes, 0, value.Length);
            }
        }

        public override Task WriteAsync(Stream stream, ReadOnlySpan<char> value, CancellationToken token = default)
        {
            byte[] bytes = BufferPool.GetBuffer(Encoding.UTF8.GetMaxByteCount(value.Length));
            try
            {
                var chars = value.ToArray();
                int bytesCount = Encoding.UTF8.GetBytes(chars, 0, chars.Length, bytes, 0);
                return stream.WriteAsync(bytes, 0, bytesCount, token);
            }
            finally
            {
                BufferPool.ReleaseBufferToPool(ref bytes);
            }
        }

        public override Task WriteAsync(Stream stream, ReadOnlyMemory<char> value, CancellationToken token = default) =>
            WriteAsync(stream, value.Span, token);

        public override Task WriteAsync(Stream stream, ReadOnlyMemory<byte> value, CancellationToken token = default)
        {
            byte[] bytes = BufferPool.GetBuffer(value.Length);
            try
            {
                value.CopyTo(bytes);
                if (stream is MemoryStream ms)
                {
                    ms.Write(bytes, 0, value.Length);
                    return TypeConstants.EmptyTask;
                }
                else
                {
                    return stream.WriteAsync(bytes, 0, value.Length, token);
                }
            }
            finally
            {
                BufferPool.ReleaseBufferToPool(ref bytes);
            }
        }

        public override object Deserialize(Stream stream, Type type, DeserializeStringSpanDelegate deserializer)
        {
            var fromPool = false;

            if (!(stream is MemoryStream ms))
            {
                fromPool = true;

                if (stream.CanSeek)
                    stream.Position = 0;

                ms = stream.CopyToNewMemoryStream();
            }

            return Deserialize(ms, fromPool, type, deserializer);
        }

        public override async Task<object> DeserializeAsync(Stream stream, Type type,
            DeserializeStringSpanDelegate deserializer)
        {
            var fromPool = false;

            if (!(stream is MemoryStream ms))
            {
                fromPool = true;

                if (stream.CanSeek)
                    stream.Position = 0;

                ms = await stream.CopyToNewMemoryStreamAsync();
            }

            return Deserialize(ms, fromPool, type, deserializer);
        }

        private static object Deserialize(MemoryStream ms, bool fromPool, Type type,
            DeserializeStringSpanDelegate deserializer)
        {
            var bytes = ms.GetBufferAsBytes();
            var utf8 = CharPool.GetBuffer(Encoding.UTF8.GetCharCount(bytes, 0, (int) ms.Length));
            try
            {
                var charsWritten = Encoding.UTF8.GetChars(bytes, 0, (int) ms.Length, utf8, 0);
                var ret = deserializer(type, new ReadOnlySpan<char>(utf8, 0, charsWritten).WithoutBom());
                return ret;
            }
            finally
            {
                CharPool.ReleaseBufferToPool(ref utf8);

                if (fromPool)
                    ms.Dispose();
            }
        }

        public override byte[] ParseBase64(ReadOnlySpan<char> value)
        {
            return Convert.FromBase64String(value.ToString());
        }

        public override string ToBase64(ReadOnlyMemory<byte> value)
        {
            return MemoryMarshal.TryGetArray(value, out var segment)
                ? Convert.ToBase64String(segment.Array, 0, segment.Count)
                : Convert.ToBase64String(value.ToArray());
        }

        public override StringBuilder Append(StringBuilder sb, ReadOnlySpan<char> value)
        {
            return sb.Append(value.ToArray());
        }

        public override int GetUtf8CharCount(ReadOnlySpan<byte> bytes) =>
            Encoding.UTF8.GetCharCount(bytes.ToArray()); //SLOW

        public override int GetUtf8ByteCount(ReadOnlySpan<char> chars) =>
            Encoding.UTF8.GetByteCount(chars.ToArray()); //SLOW

        public override ReadOnlyMemory<byte> ToUtf8(ReadOnlySpan<char> source)
        {
            var chars = source.ToArray();
            var bytes = new byte[Encoding.UTF8.GetByteCount(chars)];
            var bytesWritten = Encoding.UTF8.GetBytes(chars, 0, source.Length, bytes, 0);
            return new ReadOnlyMemory<byte>(bytes, 0, bytesWritten);
        }

        public override ReadOnlyMemory<char> FromUtf8(ReadOnlySpan<byte> source)
        {
            var bytes = source.WithoutBom().ToArray();
            var chars = new char[Encoding.UTF8.GetCharCount(bytes)];
            var charsWritten = Encoding.UTF8.GetChars(bytes, 0, bytes.Length, chars, 0);
            return new ReadOnlyMemory<char>(chars, 0, charsWritten);
        }

        public override int ToUtf8(ReadOnlySpan<char> source, Span<byte> destination)
        {
            var chars = source.ToArray();
            var bytes = destination.ToArray();
            var bytesWritten = Encoding.UTF8.GetBytes(chars, 0, source.Length, bytes, 0);
            new ReadOnlySpan<byte>(bytes, 0, bytesWritten).CopyTo(destination);
            return bytesWritten;
        }

        public override int FromUtf8(ReadOnlySpan<byte> source, Span<char> destination)
        {
            var bytes = source.WithoutBom().ToArray();
            var chars = destination.ToArray();
            var charsWritten = Encoding.UTF8.GetChars(bytes, 0, bytes.Length, chars, 0);
            new ReadOnlySpan<char>(chars, 0, charsWritten).CopyTo(destination);
            return charsWritten;
        }

        public override byte[] ToUtf8Bytes(ReadOnlySpan<char> source) => Encoding.UTF8.GetBytes(source.ToArray());

        public override string FromUtf8Bytes(ReadOnlySpan<byte> source) => Encoding.UTF8.GetString(source.WithoutBom().ToArray());

        public override MemoryStream ToMemoryStream(ReadOnlySpan<byte> source) =>
            MemoryStreamFactory.GetStream(source.ToArray());

        private static Guid ParseGeneralStyleGuid(ReadOnlySpan<char> value, out int len)
        {
            var buf = value;
            var n = 0;

            int dash = 0;
            len = 32;
            bool hasParenthesis = false;

            if (value.Length < len)
                throw new FormatException(BadFormat);

            var cs = value[0];
            if (cs == '{' || cs == '(')
            {
                n++;
                len += 2;
                hasParenthesis = true;

                if (buf[8 + n] != '-')
                    throw new FormatException(BadFormat);
            }

            if (buf[8 + n] == '-')
            {
                if (buf[13 + n] != '-'
                    || buf[18 + n] != '-'
                    || buf[23 + n] != '-')
                    throw new FormatException(BadFormat);

                len += 4;
                dash = 1;
            }

            if (value.Length < len)
                throw new FormatException(BadFormat);

            if (hasParenthesis)
            {
                var ce = buf[len - 1];

                if ((cs != '{' || ce != '}') && (cs != '(' || ce != ')'))
                    throw new FormatException(BadFormat);
            }

            int a;
            short b, c;
            byte d, e, f, g, h, i, j, k;

            byte a1 = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            byte a2 = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            byte a3 = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            byte a4 = ParseHexByte(buf[n], buf[n + 1]);
            a = (a1 << 24) + (a2 << 16) + (a3 << 8) + a4;
            n += 2 + dash;

            byte b1 = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            byte b2 = ParseHexByte(buf[n], buf[n + 1]);
            b = (short) ((b1 << 8) + b2);
            n += 2 + dash;

            byte c1 = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            byte c2 = ParseHexByte(buf[n], buf[n + 1]);
            c = (short) ((c1 << 8) + c2);
            n += 2 + dash;

            d = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            e = ParseHexByte(buf[n], buf[n + 1]);
            n += 2 + dash;

            f = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            g = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            h = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            i = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            j = ParseHexByte(buf[n], buf[n + 1]);
            n += 2;
            k = ParseHexByte(buf[n], buf[n + 1]);

            return new Guid(a, b, c, d, e, f, g, h, i, j, k);
        }

        private static byte ParseHexByte(char c1, char c2)
        {
            try
            {
                byte lo = lo16[c2];
                byte hi = hi16[c1];

                if (lo == 255 || hi == 255)
                    throw new FormatException(BadFormat);

                return (byte) (hi + lo);
            }
            catch (IndexOutOfRangeException)
            {
                throw new FormatException(BadFormat);
            }
        }
    }

    enum ParseState
    {
        LeadingWhite,
        Sign,
        Number,
        DecimalPoint,
        FractionNumber,
        Exponent,
        ExponentSign,
        ExponentValue,
        TrailingWhite
    }

    internal static class SignedInteger<T> where T : struct, IComparable<T>, IEquatable<T>, IConvertible
    {
        private static readonly TypeCode typeCode;
        private static readonly long minValue;
        private static readonly long maxValue;

        static SignedInteger()
        {
            typeCode = Type.GetTypeCode(typeof(T));

            switch (typeCode)
            {
                case TypeCode.SByte:
                    minValue = sbyte.MinValue;
                    maxValue = sbyte.MaxValue;
                    break;
                case TypeCode.Int16:
                    minValue = short.MinValue;
                    maxValue = short.MaxValue;
                    break;
                case TypeCode.Int32:
                    minValue = int.MinValue;
                    maxValue = int.MaxValue;
                    break;
                case TypeCode.Int64:
                    minValue = long.MinValue;
                    maxValue = long.MaxValue;
                    break;
                default:
                    throw new NotSupportedException($"{typeof(T).Name} is not a signed integer");
            }
        }

        internal static object ParseNullableObject(ReadOnlySpan<char> value)
        {
            if (value.IsNullOrEmpty())
                return null;

            return ParseObject(value);
        }

        internal static object ParseObject(ReadOnlySpan<char> value)
        {
            var result = ParseInt64(value);
            switch (typeCode)
            {
                case TypeCode.SByte:
                    return (sbyte) result;
                case TypeCode.Int16:
                    return (short) result;
                case TypeCode.Int32:
                    return (int) result;
                default:
                    return result;
            }
        }

        public static sbyte ParseSByte(ReadOnlySpan<char> value) => (sbyte) ParseInt64(value);
        public static short ParseInt16(ReadOnlySpan<char> value) => (short) ParseInt64(value);
        public static int ParseInt32(ReadOnlySpan<char> value) => (int) ParseInt64(value);

        public static long ParseInt64(ReadOnlySpan<char> value)
        {
            if (value.IsEmpty)
                throw new FormatException(MemoryProvider.BadFormat);

            long result = 0;
            int i = 0;
            int end = value.Length;
            var state = ParseState.LeadingWhite;
            bool negative = false;

            //skip leading whitespaces
            while (i < end && JsonUtils.IsWhiteSpace(value[i])) i++;

            if (i == end)
                throw new FormatException(MemoryProvider.BadFormat);

            //skip leading zeros
            while (i < end && value[i] == '0')
            {
                state = ParseState.Number;
                i++;
            }

            while (i < end)
            {
                var c = value[i++];

                switch (state)
                {
                    case ParseState.LeadingWhite:
                        if (c == '-')
                        {
                            negative = true;
                            state = ParseState.Sign;
                        }
                        else if (c == '0')
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else if (c > '0' && c <= '9')
                        {
                            result = -(c - '0');
                            state = ParseState.Number;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                    case ParseState.Sign:
                        if (c == '0')
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else if (c > '0' && c <= '9')
                        {
                            result = -(c - '0');
                            state = ParseState.Number;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                    case ParseState.Number:
                        if (c >= '0' && c <= '9')
                        {
                            checked
                            {
                                result = 10 * result - (c - '0');
                            }

                            if (result < minValue
                            ) //check only minvalue, because in absolute value it's greater than maxvalue
                                throw DefaultMemory.CreateOverflowException(maxValue);
                        }
                        else if (JsonUtils.IsWhiteSpace(c))
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                    case ParseState.TrailingWhite:
                        if (JsonUtils.IsWhiteSpace(c))
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                }
            }

            if (state != ParseState.Number && state != ParseState.TrailingWhite)
                throw new FormatException(MemoryProvider.BadFormat);

            if (negative)
                return result;

            checked
            {
                result = -result;
            }

            if (result > maxValue)
                throw DefaultMemory.CreateOverflowException(maxValue);

            return result;
        }
    }

    internal static class UnsignedInteger<T> where T : struct, IComparable<T>, IEquatable<T>, IConvertible
    {
        private static readonly TypeCode typeCode;
        private static readonly ulong maxValue;

        static UnsignedInteger()
        {
            typeCode = Type.GetTypeCode(typeof(T));

            switch (typeCode)
            {
                case TypeCode.Byte:
                    maxValue = byte.MaxValue;
                    break;
                case TypeCode.UInt16:
                    maxValue = ushort.MaxValue;
                    break;
                case TypeCode.UInt32:
                    maxValue = uint.MaxValue;
                    break;
                case TypeCode.UInt64:
                    maxValue = ulong.MaxValue;
                    break;
                default:
                    throw new NotSupportedException($"{typeof(T).Name} is not a signed integer");
            }
        }

        internal static object ParseNullableObject(ReadOnlySpan<char> value)
        {
            if (value.IsNullOrEmpty())
                return null;

            return ParseObject(value);
        }

        internal static object ParseObject(ReadOnlySpan<char> value)
        {
            var result = ParseUInt64(value);
            switch (typeCode)
            {
                case TypeCode.Byte:
                    return (byte) result;
                case TypeCode.UInt16:
                    return (ushort) result;
                case TypeCode.UInt32:
                    return (uint) result;
                default:
                    return result;
            }
        }

        public static byte ParseByte(ReadOnlySpan<char> value) => (byte) ParseUInt64(value);
        public static ushort ParseUInt16(ReadOnlySpan<char> value) => (ushort) ParseUInt64(value);
        public static uint ParseUInt32(ReadOnlySpan<char> value) => (uint) ParseUInt64(value);

        internal static ulong ParseUInt64(ReadOnlySpan<char> value)
        {
            if (value.IsEmpty)
                throw new FormatException(MemoryProvider.BadFormat);

            ulong result = 0;
            int i = 0;
            int end = value.Length;
            var state = ParseState.LeadingWhite;

            //skip leading whitespaces
            while (i < end && JsonUtils.IsWhiteSpace(value[i])) i++;

            if (i == end)
                throw new FormatException(MemoryProvider.BadFormat);

            //skip leading zeros
            while (i < end && value[i] == '0')
            {
                state = ParseState.Number;
                i++;
            }

            while (i < end)
            {
                var c = value[i++];

                switch (state)
                {
                    case ParseState.LeadingWhite:
                        if (JsonUtils.IsWhiteSpace(c))
                            break;
                        if (c == '0')
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else if (c > '0' && c <= '9')
                        {
                            result = (ulong) (c - '0');
                            state = ParseState.Number;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                    case ParseState.Number:
                        if (c >= '0' && c <= '9')
                        {
                            checked
                            {
                                result = 10 * result + (ulong) (c - '0');
                            }

                            if (result > maxValue
                            ) //check only minvalue, because in absolute value it's greater than maxvalue
                                throw DefaultMemory.CreateOverflowException(maxValue);
                        }
                        else if (JsonUtils.IsWhiteSpace(c))
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                    case ParseState.TrailingWhite:
                        if (JsonUtils.IsWhiteSpace(c))
                        {
                            state = ParseState.TrailingWhite;
                        }
                        else throw new FormatException(MemoryProvider.BadFormat);

                        break;
                }
            }

            if (state != ParseState.Number && state != ParseState.TrailingWhite)
                throw new FormatException(MemoryProvider.BadFormat);

            return result;
        }
    }
}


text:
'use strict';

var angular = require('angular');
var expect  = require('chai').expect;

describe('angular-router-exception-handler', function () {

  beforeEach(angular.mock.module(require('../')));
  beforeEach(angular.mock.module(function ($exceptionHandlerProvider) {
    $exceptionHandlerProvider.mode('log');
  }));

  it('passes $routeChangeError to $exceptionHandler', function () {
    angular.mock.module(function ($provide) {
      $provide.value('$route', {});
    });
    angular.mock.inject(function ($rootScope, $exceptionHandler) {
      var err = new Error();
      $rootScope.$broadcast('$routeChangeError', 'to', 'from', err);
      expect($exceptionHandler.errors[0][0]).to.equal(err);
      expect($exceptionHandler.errors[0][1]).to.deep.equal({
        to: 'to',
        from: 'from'
      });
    });
  });

  it('passes $stateChangeError to $exceptionHandler', function () {
    angular.mock.module(function ($provide) {
      $provide.value('$state', {});
    });
    angular.mock.inject(function ($rootScope, $exceptionHandler) {
      var err = new Error();
      $rootScope.$broadcast('$stateChangeError', 'toState', 'toParams', 'fromState', 'fromParams', err);
      expect($exceptionHandler.errors[0][0]).to.equal(err);
      expect($exceptionHandler.errors[0][1]).to.deep.equal({
        to: {
          state: 'toState',
          params: 'toParams'
        },
        from: {
          state: 'fromState',
          params: 'fromParams'
        }
      });
    });
  });

});

redpajama_set_name: RedPajamaGithub


text:
#include "sprite.h"
#include <stdlib.h>
#include <libiff/io.h>
#include <libiff/util.h>
#include "ilbm.h"

#define CHUNKID "SPRT"

ILBM_Sprite *ILBM_createSprite(void)
{
    ILBM_Sprite *sprite = (ILBM_Sprite*)IFF_allocateChunk(CHUNKID, sizeof(ILBM_Sprite));

    if(sprite != NULL)
	sprite->chunkSize = sizeof(IFF_UWord);

    return sprite;
}

IFF_Chunk *ILBM_readSprite(FILE *file, const IFF_Long chunkSize)
{
    ILBM_Sprite *sprite = ILBM_createSprite();

    if(sprite != NULL)
    {
	if(!IFF_readUWord(file, &sprite->spritePrecedence, CHUNKID, "spritePrecedence"))
	{
	    ILBM_free((IFF_Chunk*)sprite);
	    return NULL;
	}
    }

    return (IFF_Chunk*)sprite;
}

int ILBM_writeSprite(FILE *file, const IFF_Chunk *chunk)
{
    const ILBM_Sprite *sprite = (const ILBM_Sprite*)chunk;

    if(!IFF_writeUWord(file, sprite->spritePrecedence, CHUNKID, "spritePrecedence"))
	return FALSE;

    return TRUE;
}

int ILBM_checkSprite(const IFF_Chunk *chunk)
{
    return TRUE;
}

void ILBM_freeSprite(IFF_Chunk *chunk)
{
}

void ILBM_printSprite(const IFF_Chunk *chunk, const unsigned int indentLevel)
{
    const ILBM_Sprite *sprite = (const ILBM_Sprite*)chunk;

    IFF_printIndent(stdout, indentLevel, "spritePrecedence = %u;\n", sprite->spritePrecedence);
}

int ILBM_compareSprite(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2)
{
    const ILBM_Sprite *sprite1 = (const ILBM_Sprite*)chunk1;
    const ILBM_Sprite *sprite2 = (const ILBM_Sprite*)chunk2;

    if(sprite1->spritePrecedence != sprite2->spritePrecedence)
	return FALSE;

    return TRUE;
}


text:
require 'pp'
module Jekyll
  # Need to overwrite the inspect method here because the original
  # uses < > to encapsulate the psuedo post/page objects in which case
  # the output is taken for HTML tags and hidden from view.
  #
  class Post
    def inspect
      "#Jekyll:Post @id=#{self.id.inspect}"
    end
  end

  class Page
    def inspect
      "#Jekyll:Page @name=#{self.name.inspect}"
    end
  end
end # Jekyll

module Jekyll
  module DebugFilter

    def debug(obj, stdout=false)
      puts obj.pretty_inspect if stdout
      "<pre>#{obj.class}\n#{obj.pretty_inspect}</pre>"
    end

  end # DebugFilter
end # Jekyll

Liquid::Template.register_filter(Jekyll::DebugFilter)


text:
<?php

class Partida extends ActiveRecord\Model {

  static $table_name = "partida";
  static $primary_key = 'id';

  static $belongs_to = array(
    array('contratista', 'primary_key' => 'id', 'foreign_key' => 'contratista_id', 'select' => 'id, referencia, nro_doc, razon_social, email, telf_local, telf_movil'),
    array('presupuesto', 'primary_key' => 'id', 'foreign_key' => 'presupuesto_id', 'select' => 'id, descripcion, proyecto_id'),
    array('unidad', 'primary_key' => 'id', 'foreign_key' => 'unidad_id', 'select' => 'id, unidad'),
    array('status', 'primary_key' => 'id', 'foreign_key' => 'status_id', 'select' => 'id, nombre')
  );

  static $has_many = array(
    array('cpp', 'class_name' => 'CuentaPorPagarContratista')
  );

  function actualizar(){
    $status = $this->update_attribute('status_id', 4);
    return $status;
  }

  function precio_unitario(){
    return number_format($this->precio_unitario, 2, '.', '');
  }

  function precio_total(){
    return $this->precio_unitario * $this->cantidad;
  }

  static function ultima_ref($ref){ //referencia
    $last = Partida::last();
    $ref = (isset($last)) ? $ref.'-'.str_pad($last->id+1, 8, '0', STR_PAD_LEFT) : $ref.'-'.str_pad(1, 8, '0', STR_PAD_LEFT);
    return $ref;
  }

  static function lista_partidas(){
    $partidas = Partida::all(array('select' => 'id, presupuesto_id, status_id, referencia, descripcion, unidad_id, cantidad, activo, created_at', 'order' => 'created_at DESC', 'conditions' => 'activo = 1', 'include' => array('status', 'presupuesto')));
    $result = array();
    foreach ($partidas as $partida) {
      $result[] = array('id' => $partida->id,
                        'presupuesto' => $partida->presupuesto->descripcion,
                        'referencia' => $partida->referencia,
                        'descripcion' => $partida->descripcion,
                        'status' => $partida->status->nombre,
                        'created_at' => $partida->created_at);
    }
    return $result;
  }

  function activo(){
    return ($this->activo == 1) ? TRUE : FALSE;
  }

  function finalizada(){
    return ($this->status_id == 8) ? TRUE : FALSE;
  }

}


text:
Pattern: Use of deprecated `destroyed`/`beforeDestroy` hooks

Issue: -

## Description

This rule reports use of deprecated `destroyed` and `beforeDestroy` lifecycle hooks. (in Vue.js 3.0.0+).

<eslint-code-block :rules="{'vue/no-deprecated-destroyed-lifecycle': ['error']}">

```vue
<script>
export default {
  /* ✓ GOOD */
  beforeMount () {},
  mounted () {},
  beforeUnmount () {},
  unmounted () {},

  /* ✗ BAD */
  beforeDestroy () {},
  destroyed () {}
}
</script>
```

</eslint-code-block>

## Further Reading

* [eslint-plugin-vue - no-deprecated-destroyed-lifecycle](https://eslint.vuejs.org/rules/no-deprecated-destroyed-lifecycle.html)


text:
from ..base import SEMLikeCommandLine

class SlicerCommandLine(SEMLikeCommandLine):
    pass


text:
namespace views {
namespace test {

namespace {

// Test implementation of MenuDelegate that only reports calls of OnPerformDrop.
class TestMenuDelegate : public MenuDelegate {
 public:
  TestMenuDelegate();
  ~TestMenuDelegate() override;

  bool on_perform_drop_called() { return on_perform_drop_called_; }

  int OnPerformDrop(MenuItemView* menu,
                    DropPosition position,
                    const ui::DropTargetEvent& event) override;

 private:
  bool on_perform_drop_called_;
  DISALLOW_COPY_AND_ASSIGN(TestMenuDelegate);
};

TestMenuDelegate::TestMenuDelegate() : on_perform_drop_called_(false) {}

TestMenuDelegate::~TestMenuDelegate() {}

int TestMenuDelegate::OnPerformDrop(MenuItemView* menu,
                                    DropPosition position,
                                    const ui::DropTargetEvent& event) {
  on_perform_drop_called_ = true;
  return ui::DragDropTypes::DRAG_COPY;
}

// Test implementation of MenuControllerDelegate that only reports the values
// called of OnMenuClosed.
class TestMenuControllerDelegate : public internal::MenuControllerDelegate {
 public:
  TestMenuControllerDelegate();
  ~TestMenuControllerDelegate() override {}

  int on_menu_closed_called() { return on_menu_closed_called_; }

  NotifyType on_menu_closed_notify_type() {
    return on_menu_closed_notify_type_;
  }

  MenuItemView* on_menu_closed_menu() { return on_menu_closed_menu_; }

  int on_menu_closed_mouse_event_flags() {
    return on_menu_closed_mouse_event_flags_;
  }

  // internal::MenuControllerDelegate:
  void OnMenuClosed(NotifyType type,
                    MenuItemView* menu,
                    int mouse_event_flags) override;
  void SiblingMenuCreated(MenuItemView* menu) override;

 private:
  // Number of times OnMenuClosed has been called.
  int on_menu_closed_called_;

  // The values passed on the last call of OnMenuClosed.
  NotifyType on_menu_closed_notify_type_;
  MenuItemView* on_menu_closed_menu_;
  int on_menu_closed_mouse_event_flags_;

  DISALLOW_COPY_AND_ASSIGN(TestMenuControllerDelegate);
};

TestMenuControllerDelegate::TestMenuControllerDelegate()
    : on_menu_closed_called_(0),
      on_menu_closed_notify_type_(NOTIFY_DELEGATE),
      on_menu_closed_menu_(nullptr),
      on_menu_closed_mouse_event_flags_(0) {}

void TestMenuControllerDelegate::OnMenuClosed(NotifyType type,
                                              MenuItemView* menu,
                                              int mouse_event_flags) {
  on_menu_closed_called_++;
  on_menu_closed_notify_type_ = type;
  on_menu_closed_menu_ = menu;
  on_menu_closed_mouse_event_flags_ = mouse_event_flags;
}

void TestMenuControllerDelegate::SiblingMenuCreated(MenuItemView* menu) {}

class SubmenuViewShown : public SubmenuView {
 public:
  SubmenuViewShown(MenuItemView* parent) : SubmenuView(parent) {}
  ~SubmenuViewShown() override {}
  bool IsShowing() override { return true; }

 private:
  DISALLOW_COPY_AND_ASSIGN(SubmenuViewShown);
};

class TestEventHandler : public ui::EventHandler {
 public:
  TestEventHandler() : outstanding_touches_(0) {}

  void OnTouchEvent(ui::TouchEvent* event) override {
    switch(event->type()) {
      case ui::ET_TOUCH_PRESSED:
        outstanding_touches_++;
        break;
      case ui::ET_TOUCH_RELEASED:
      case ui::ET_TOUCH_CANCELLED:
        outstanding_touches_--;
        break;
      default:
        break;
    }
  }

  int outstanding_touches() const { return outstanding_touches_; }

 private:
  int outstanding_touches_;
  DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
};

// A wrapper around MenuMessageLoop that can be used to track whether a message
// loop is running or not.
class TestMenuMessageLoop : public MenuMessageLoop {
 public:
  explicit TestMenuMessageLoop(scoped_ptr<MenuMessageLoop> original);
  ~TestMenuMessageLoop() override;

  bool is_running() const { return is_running_; }

 private:
  // MenuMessageLoop:
  void Run(MenuController* controller,
           Widget* owner,
           bool nested_menu) override;
  void QuitNow() override;
  void ClearOwner() override;

  scoped_ptr<MenuMessageLoop> original_;
  bool is_running_;

  DISALLOW_COPY_AND_ASSIGN(TestMenuMessageLoop);
};

TestMenuMessageLoop::TestMenuMessageLoop(scoped_ptr<MenuMessageLoop> original)
    : original_(std::move(original)) {
  DCHECK(original_);
}

TestMenuMessageLoop::~TestMenuMessageLoop() {}

void TestMenuMessageLoop::Run(MenuController* controller,
                              Widget* owner,
                              bool nested_menu) {
  is_running_ = true;
  original_->Run(controller, owner, nested_menu);
}

void TestMenuMessageLoop::QuitNow() {
  is_running_ = false;
  original_->QuitNow();
}

void TestMenuMessageLoop::ClearOwner() {
  original_->ClearOwner();
}

}  // namespace

class TestMenuItemViewShown : public MenuItemView {
 public:
  TestMenuItemViewShown(MenuDelegate* delegate) : MenuItemView(delegate) {
    submenu_ = new SubmenuViewShown(this);
  }
  ~TestMenuItemViewShown() override {}

  void SetController(MenuController* controller) {
    set_controller(controller);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown);
};

class MenuControllerTest : public ViewsTestBase {
 public:
  MenuControllerTest() : menu_controller_(nullptr) {
  }

  ~MenuControllerTest() override {}

  // ViewsTestBase:
  void SetUp() override {
    ViewsTestBase::SetUp();
    Init();
  }

  void TearDown() override {
    owner_->CloseNow();

    menu_controller_->showing_ = false;
    menu_controller_->owner_ = nullptr;
    delete menu_controller_;
    menu_controller_ = nullptr;

    ViewsTestBase::TearDown();
  }

  void ReleaseTouchId(int id) {
    event_generator_->ReleaseTouchId(id);
  }

  void PressKey(ui::KeyboardCode key_code) {
    event_generator_->PressKey(key_code, 0);
  }

#if defined(OS_LINUX) && defined(USE_X11)
  void TestEventTargeter() {
    {
      // With the |ui::NullEventTargeter| instantiated and assigned we expect
      // the menu to not handle the key event.
      aura::ScopedWindowTargeter scoped_targeter(
          owner()->GetNativeWindow()->GetRootWindow(),
          scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
      event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
      EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
    }
    // Now that the targeter has been destroyed, expect to exit the menu
    // normally when hitting escape.
    event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
    EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
  }
#endif  // defined(OS_LINUX) && defined(USE_X11)

  void TestAsynchronousNestedExitAll() {
    ASSERT_TRUE(test_message_loop_->is_running());

    scoped_ptr<TestMenuControllerDelegate> nested_delegate(
        new TestMenuControllerDelegate());

    menu_controller()->AddNestedDelegate(nested_delegate.get());
    menu_controller()->SetAsyncRun(true);

    int mouse_event_flags = 0;
    MenuItemView* run_result = menu_controller()->Run(
        owner(), nullptr, menu_item(), gfx::Rect(), MENU_ANCHOR_TOPLEFT, false,
        false, &mouse_event_flags);
    EXPECT_EQ(run_result, nullptr);

    // Exit all menus and check that the parent menu's message loop is
    // terminated.
    menu_controller()->Cancel(MenuController::EXIT_ALL);
    EXPECT_EQ(MenuController::EXIT_ALL, menu_controller()->exit_type());
    EXPECT_FALSE(test_message_loop_->is_running());
  }

  void TestAsynchronousNestedExitOutermost() {
    ASSERT_TRUE(test_message_loop_->is_running());

    scoped_ptr<TestMenuControllerDelegate> nested_delegate(
        new TestMenuControllerDelegate());

    menu_controller()->AddNestedDelegate(nested_delegate.get());
    menu_controller()->SetAsyncRun(true);

    int mouse_event_flags = 0;
    MenuItemView* run_result = menu_controller()->Run(
        owner(), nullptr, menu_item(), gfx::Rect(), MENU_ANCHOR_TOPLEFT, false,
        false, &mouse_event_flags);
    EXPECT_EQ(run_result, nullptr);

    // Exit the nested menu and check that the parent menu's message loop is
    // still running.
    menu_controller()->Cancel(MenuController::EXIT_OUTERMOST);
    EXPECT_EQ(MenuController::EXIT_NONE, menu_controller()->exit_type());
    EXPECT_TRUE(test_message_loop_->is_running());

    // Now, exit the parent menu and check that its message loop is terminated.
    menu_controller()->Cancel(MenuController::EXIT_OUTERMOST);
    EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_controller()->exit_type());
    EXPECT_FALSE(test_message_loop_->is_running());
  }

 protected:
  void SetPendingStateItem(MenuItemView* item) {
    menu_controller_->pending_state_.item = item;
    menu_controller_->pending_state_.submenu_open = true;
  }

  void ResetSelection() {
    menu_controller_->SetSelection(
        nullptr,
        MenuController::SELECTION_EXIT |
        MenuController::SELECTION_UPDATE_IMMEDIATELY);
  }

  void IncrementSelection() {
    menu_controller_->IncrementSelection(
        MenuController::INCREMENT_SELECTION_DOWN);
  }

  void DecrementSelection() {
    menu_controller_->IncrementSelection(
        MenuController::INCREMENT_SELECTION_UP);
  }

  MenuItemView* FindInitialSelectableMenuItemDown(MenuItemView* parent) {
    return menu_controller_->FindInitialSelectableMenuItem(
        parent, MenuController::INCREMENT_SELECTION_DOWN);
  }

  MenuItemView* FindInitialSelectableMenuItemUp(MenuItemView* parent) {
    return menu_controller_->FindInitialSelectableMenuItem(
        parent, MenuController::INCREMENT_SELECTION_UP);
  }

  MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
                                           int index) {

    return menu_controller_->FindNextSelectableMenuItem(
        parent, index, MenuController::INCREMENT_SELECTION_DOWN);
  }

  MenuItemView* FindPreviousSelectableMenuItem(MenuItemView* parent,
                                               int index) {
    return menu_controller_->FindNextSelectableMenuItem(
        parent, index, MenuController::INCREMENT_SELECTION_UP);
  }

  internal::MenuControllerDelegate* GetCurrentDelegate() {
    return menu_controller_->delegate_;
  }

  bool IsAsyncRun() { return menu_controller_->async_run_; }

  bool IsShowing() { return menu_controller_->showing_; }

  void SelectByChar(base::char16 character) {
    menu_controller_->SelectByChar(character);
  }

  void SetDropMenuItem(MenuItemView* target,
                       MenuDelegate::DropPosition position) {
    menu_controller_->SetDropMenuItem(target, position);
  }

  void SetIsCombobox(bool is_combobox) {
    menu_controller_->set_is_combobox(is_combobox);
  }

  void SetSelectionOnPointerDown(SubmenuView* source,
                                 const ui::LocatedEvent* event) {
    menu_controller_->SetSelectionOnPointerDown(source, event);
  }

  void RunMenu() {
    menu_controller_->message_loop_depth_++;
    menu_controller_->RunMessageLoop(false);
    menu_controller_->message_loop_depth_--;
  }

  void Accept(MenuItemView* item, int event_flags) {
    menu_controller_->Accept(item, event_flags);
  }

  void InstallTestMenuMessageLoop() {
    test_message_loop_ =
        new TestMenuMessageLoop(std::move(menu_controller_->message_loop_));
    menu_controller_->message_loop_.reset(test_message_loop_);
  }

  Widget* owner() { return owner_.get(); }
  ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
  TestMenuItemViewShown* menu_item() { return menu_item_.get(); }
  TestMenuControllerDelegate* menu_controller_delegate() {
    return menu_controller_delegate_.get();
  }
  MenuController* menu_controller() { return menu_controller_; }
  const MenuItemView* pending_state_item() const {
      return menu_controller_->pending_state_.item;
  }
  MenuController::ExitType menu_exit_type() const {
    return menu_controller_->exit_type_;
  }

 private:
  void Init() {
    owner_.reset(new Widget);
    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    owner_->Init(params);
    event_generator_.reset(
        new ui::test::EventGenerator(GetContext(), owner_->GetNativeWindow()));
    owner_->Show();

#if defined(OS_WIN)
    dispatcher_client_.reset(new DesktopDispatcherClient);
    aura::client::SetDispatcherClient(owner_->GetNativeView()->GetRootWindow(),
                                      dispatcher_client_.get());
#endif

    SetupMenuItem();

    SetupMenuController();
  }

  void SetupMenuItem() {
    menu_delegate_.reset(new TestMenuDelegate);
    menu_item_.reset(new TestMenuItemViewShown(menu_delegate_.get()));
    menu_item_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
    menu_item_->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
    menu_item_->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
    menu_item_->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
  }

  void SetupMenuController() {
    menu_controller_delegate_.reset(new TestMenuControllerDelegate);
    menu_controller_ =
        new MenuController(true, menu_controller_delegate_.get());
    menu_controller_->owner_ = owner_.get();
    menu_controller_->showing_ = true;
    menu_controller_->SetSelection(
        menu_item_.get(), MenuController::SELECTION_UPDATE_IMMEDIATELY);
    menu_item_->SetController(menu_controller_);
  }

#if defined(OS_WIN)
  scoped_ptr<aura::client::DispatcherClient> dispatcher_client_;
#endif

  scoped_ptr<Widget> owner_;
  scoped_ptr<ui::test::EventGenerator> event_generator_;
  scoped_ptr<TestMenuItemViewShown> menu_item_;
  scoped_ptr<TestMenuControllerDelegate> menu_controller_delegate_;
  scoped_ptr<MenuDelegate> menu_delegate_;
  MenuController* menu_controller_;
  TestMenuMessageLoop* test_message_loop_;

  DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
};

#if defined(OS_LINUX) && defined(USE_X11)
// Tests that an event targeter which blocks events will be honored by the menu
// event dispatcher.
TEST_F(MenuControllerTest, EventTargeter) {
  base::MessageLoopForUI::current()->PostTask(
      FROM_HERE,
      base::Bind(&MenuControllerTest::TestEventTargeter,
                 base::Unretained(this)));
  RunMenu();
}
#endif  // defined(OS_LINUX) && defined(USE_X11)

#if defined(USE_X11)
// Tests that touch event ids are released correctly. See crbug.com/439051 for
// details. When the ids aren't managed correctly, we get stuck down touches.
TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
  TestEventHandler test_event_handler;
  owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
      &test_event_handler);

  std::vector<int> devices;
  devices.push_back(1);
  ui::SetUpTouchDevicesForTest(devices);

  event_generator()->PressTouchId(0);
  event_generator()->PressTouchId(1);
  event_generator()->ReleaseTouchId(0);

  base::MessageLoopForUI::current()->PostTask(
      FROM_HERE,
      base::Bind(&MenuControllerTest::ReleaseTouchId,
                 base::Unretained(this),
                 1));

  base::MessageLoopForUI::current()->PostTask(
      FROM_HERE,
      base::Bind(&MenuControllerTest::PressKey,
                 base::Unretained(this),
                 ui::VKEY_ESCAPE));

  RunMenu();

  EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
  EXPECT_EQ(0, test_event_handler.outstanding_touches());

  owner()->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
      &test_event_handler);
}
#endif  // defined(USE_X11)

// Tests that initial selected menu items are correct when items are enabled or
// disabled.
TEST_F(MenuControllerTest, InitialSelectedItem) {
  // Leave items "Two", "Three", and "Four" enabled.
  menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
  // The first selectable item should be item "Two".
  MenuItemView* first_selectable =
      FindInitialSelectableMenuItemDown(menu_item());
  ASSERT_NE(nullptr, first_selectable);
  EXPECT_EQ(2, first_selectable->GetCommand());
  // The last selectable item should be item "Four".
  MenuItemView* last_selectable =
      FindInitialSelectableMenuItemUp(menu_item());
  ASSERT_NE(nullptr, last_selectable);
  EXPECT_EQ(4, last_selectable->GetCommand());

  // Leave items "One" and "Two" enabled.
  menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
  menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
  menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
  // The first selectable item should be item "One".
  first_selectable = FindInitialSelectableMenuItemDown(menu_item());
  ASSERT_NE(nullptr, first_selectable);
  EXPECT_EQ(1, first_selectable->GetCommand());
  // The last selectable item should be item "Two".
  last_selectable = FindInitialSelectableMenuItemUp(menu_item());
  ASSERT_NE(nullptr, last_selectable);
  EXPECT_EQ(2, last_selectable->GetCommand());

  // Leave only a single item "One" enabled.
  menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
  menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
  // The first selectable item should be item "One".
  first_selectable = FindInitialSelectableMenuItemDown(menu_item());
  ASSERT_NE(nullptr, first_selectable);
  EXPECT_EQ(1, first_selectable->GetCommand());
  // The last selectable item should be item "One".
  last_selectable = FindInitialSelectableMenuItemUp(menu_item());
  ASSERT_NE(nullptr, last_selectable);
  EXPECT_EQ(1, last_selectable->GetCommand());

  // Leave only a single item "Three" enabled.
  menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true);
  menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
  // The first selectable item should be item "Three".
  first_selectable = FindInitialSelectableMenuItemDown(menu_item());
  ASSERT_NE(nullptr, first_selectable);
  EXPECT_EQ(3, first_selectable->GetCommand());
  // The last selectable item should be item "Three".
  last_selectable = FindInitialSelectableMenuItemUp(menu_item());
  ASSERT_NE(nullptr, last_selectable);
  EXPECT_EQ(3, last_selectable->GetCommand());

  // Leave only a single item ("Two") selected. It should be the first and the
  // last selectable item.
  menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
  menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
  menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
  first_selectable = FindInitialSelectableMenuItemDown(menu_item());
  ASSERT_NE(nullptr, first_selectable);
  EXPECT_EQ(2, first_selectable->GetCommand());
  last_selectable = FindInitialSelectableMenuItemUp(menu_item());
  ASSERT_NE(nullptr, last_selectable);
  EXPECT_EQ(2, last_selectable->GetCommand());

  // There should be no next or previous selectable item since there is only a
  // single enabled item in the menu.
  EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1));
  EXPECT_EQ(nullptr, FindPreviousSelectableMenuItem(menu_item(), 1));

  // Clear references in menu controller to the menu item that is going away.
  ResetSelection();
}

// Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled
// items.
TEST_F(MenuControllerTest, NextSelectedItem) {
  // Disabling the item "Three" gets it skipped when using keyboard to navigate.
  menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);

  // Fake initial hot selection.
  SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
  EXPECT_EQ(1, pending_state_item()->GetCommand());

  // Move down in the menu.
  // Select next item.
  IncrementSelection();
  EXPECT_EQ(2, pending_state_item()->GetCommand());

  // Skip disabled item.
  IncrementSelection();
  EXPECT_EQ(4, pending_state_item()->GetCommand());

  // Wrap around.
  IncrementSelection();
  EXPECT_EQ(1, pending_state_item()->GetCommand());

  // Move up in the menu.
  // Wrap around.
  DecrementSelection();
  EXPECT_EQ(4, pending_state_item()->GetCommand());

  // Skip disabled item.
  DecrementSelection();
  EXPECT_EQ(2, pending_state_item()->GetCommand());

  // Select previous item.
  DecrementSelection();
  EXPECT_EQ(1, pending_state_item()->GetCommand());

  // Clear references in menu controller to the menu item that is going away.
  ResetSelection();
}

// Tests that opening menu and pressing 'Up' selects the last enabled menu item.
TEST_F(MenuControllerTest, PreviousSelectedItem) {
  // Disabling the item "Four" gets it skipped when using keyboard to navigate.
  menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);

  // Fake initial root item selection and submenu showing.
  SetPendingStateItem(menu_item());
  EXPECT_EQ(0, pending_state_item()->GetCommand());

  // Move up and select a previous (in our case the last enabled) item.
  DecrementSelection();
  EXPECT_EQ(3, pending_state_item()->GetCommand());

  // Clear references in menu controller to the menu item that is going away.
  ResetSelection();
}

// Tests that opening menu and calling SelectByChar works correctly.
TEST_F(MenuControllerTest, SelectByChar) {
  SetIsCombobox(true);

  // Handle null character should do nothing.
  SelectByChar(0);
  EXPECT_EQ(0, pending_state_item()->GetCommand());

  // Handle searching for 'f'; should find "Four".
  SelectByChar('f');
  EXPECT_EQ(4, pending_state_item()->GetCommand());

  // Clear references in menu controller to the menu item that is going away.
  ResetSelection();
}

// Tests that a menu opened asynchronously, will notify its
// MenuControllerDelegate when Accept is called.
TEST_F(MenuControllerTest, AsynchronousAccept) {
  MenuController* controller = menu_controller();
  controller->SetAsyncRun(true);

  int mouse_event_flags = 0;
  MenuItemView* run_result =
      controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
                      MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
  EXPECT_EQ(run_result, nullptr);
  TestMenuControllerDelegate* delegate = menu_controller_delegate();
  EXPECT_EQ(0, delegate->on_menu_closed_called());

  MenuItemView* accepted = menu_item()->GetSubmenu()->GetMenuItemAt(0);
  const int kEventFlags = 42;
  Accept(accepted, kEventFlags);

  EXPECT_EQ(1, delegate->on_menu_closed_called());
  EXPECT_EQ(accepted, delegate->on_menu_closed_menu());
  EXPECT_EQ(kEventFlags, delegate->on_menu_closed_mouse_event_flags());
  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
            delegate->on_menu_closed_notify_type());
}

// Tests that a menu opened asynchronously, will notify its
// MenuControllerDelegate when CancelAll is called.
TEST_F(MenuControllerTest, AsynchronousCancelAll) {
  MenuController* controller = menu_controller();
  controller->SetAsyncRun(true);

  int mouse_event_flags = 0;
  MenuItemView* run_result =
      controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
                      MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
  EXPECT_EQ(run_result, nullptr);
  TestMenuControllerDelegate* delegate = menu_controller_delegate();
  EXPECT_EQ(0, delegate->on_menu_closed_called());

  controller->CancelAll();
  EXPECT_EQ(1, delegate->on_menu_closed_called());
  EXPECT_EQ(nullptr, delegate->on_menu_closed_menu());
  EXPECT_EQ(0, delegate->on_menu_closed_mouse_event_flags());
  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
            delegate->on_menu_closed_notify_type());
  EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}

// Tests that an asynchrnous menu nested within a synchronous menu restores the
// previous MenuControllerDelegate and synchronous settings.
TEST_F(MenuControllerTest, AsynchronousNestedDelegate) {
  MenuController* controller = menu_controller();
  TestMenuControllerDelegate* delegate = menu_controller_delegate();
  scoped_ptr<TestMenuControllerDelegate> nested_delegate(
      new TestMenuControllerDelegate());

  ASSERT_FALSE(IsAsyncRun());
  controller->AddNestedDelegate(nested_delegate.get());
  controller->SetAsyncRun(true);

  EXPECT_TRUE(IsAsyncRun());
  EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());

  int mouse_event_flags = 0;
  MenuItemView* run_result =
      controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
                      MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
  EXPECT_EQ(run_result, nullptr);

  controller->CancelAll();
  EXPECT_FALSE(IsAsyncRun());
  EXPECT_EQ(delegate, GetCurrentDelegate());
  EXPECT_EQ(0, delegate->on_menu_closed_called());
  EXPECT_EQ(1, nested_delegate->on_menu_closed_called());
  EXPECT_EQ(nullptr, nested_delegate->on_menu_closed_menu());
  EXPECT_EQ(0, nested_delegate->on_menu_closed_mouse_event_flags());
  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
            nested_delegate->on_menu_closed_notify_type());
  EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}

// Tests that dropping within an asynchronous menu stops the menu from showing
// and does not notify the controller.
TEST_F(MenuControllerTest, AsynchronousPerformDrop) {
  MenuController* controller = menu_controller();
  controller->SetAsyncRun(true);
  SubmenuView* source = menu_item()->GetSubmenu();
  MenuItemView* target = source->GetMenuItemAt(0);

  SetDropMenuItem(target, MenuDelegate::DropPosition::DROP_AFTER);

  ui::OSExchangeData drop_data;
  gfx::Rect bounds(target->bounds());
  gfx::Point location(bounds.x(), bounds.y());
  ui::DropTargetEvent target_event(drop_data, location, location,
                                   ui::DragDropTypes::DRAG_MOVE);
  controller->OnPerformDrop(source, target_event);

  TestMenuDelegate* menu_delegate =
      static_cast<TestMenuDelegate*>(target->GetDelegate());
  TestMenuControllerDelegate* controller_delegate = menu_controller_delegate();
  EXPECT_TRUE(menu_delegate->on_perform_drop_called());
  EXPECT_FALSE(IsShowing());
  EXPECT_EQ(0, controller_delegate->on_menu_closed_called());
}

// Tests that dragging within an asynchronous menu notifies the
// MenuControllerDelegate for shutdown.
TEST_F(MenuControllerTest, AsynchronousDragComplete) {
  MenuController* controller = menu_controller();
  controller->SetAsyncRun(true);

  controller->OnDragWillStart();
  controller->OnDragComplete(true);

  EXPECT_FALSE(controller->drag_in_progress());
  TestMenuControllerDelegate* controller_delegate = menu_controller_delegate();
  EXPECT_EQ(1, controller_delegate->on_menu_closed_called());
  EXPECT_EQ(nullptr, controller_delegate->on_menu_closed_menu());
  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
            controller_delegate->on_menu_closed_notify_type());
  EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}

// Tets that an asynchronous menu nested within an asynchronous menu closes both
// menus, and notifies both delegates.
TEST_F(MenuControllerTest, DoubleAsynchronousNested) {
  MenuController* controller = menu_controller();
  TestMenuControllerDelegate* delegate = menu_controller_delegate();
  scoped_ptr<TestMenuControllerDelegate> nested_delegate(
      new TestMenuControllerDelegate());

  ASSERT_FALSE(IsAsyncRun());
  // Sets the run created in SetUp
  controller->SetAsyncRun(true);

  // Nested run
  controller->AddNestedDelegate(nested_delegate.get());
  controller->SetAsyncRun(true);
  int mouse_event_flags = 0;
  MenuItemView* run_result =
      controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
                      MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
  EXPECT_EQ(run_result, nullptr);

  controller->CancelAll();
  EXPECT_EQ(1, delegate->on_menu_closed_called());
  EXPECT_EQ(1, nested_delegate->on_menu_closed_called());
}

// Tests that an asynchronous menu nested within a synchronous menu does not
// crash when trying to repost events that occur outside of the bounds of the
// menu. Instead a proper shutdown should occur.
TEST_F(MenuControllerTest, AsynchronousRepostEvent) {
  MenuController* controller = menu_controller();
  TestMenuControllerDelegate* delegate = menu_controller_delegate();
  scoped_ptr<TestMenuControllerDelegate> nested_delegate(
      new TestMenuControllerDelegate());

  ASSERT_FALSE(IsAsyncRun());

  controller->AddNestedDelegate(nested_delegate.get());
  controller->SetAsyncRun(true);

  EXPECT_TRUE(IsAsyncRun());
  EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());

  MenuItemView* item = menu_item();
  int mouse_event_flags = 0;
  MenuItemView* run_result =
      controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
                      false, false, &mouse_event_flags);
  EXPECT_EQ(run_result, nullptr);

  // Show a sub menu to targert with a pointer selection. However have the event
  // occur outside of the bounds of the entire menu.
  SubmenuView* sub_menu = item->GetSubmenu();
  sub_menu->ShowAt(owner(), item->bounds(), false);
  gfx::Point location(sub_menu->bounds().bottom_right());
  location.Offset(1, 1);
  ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location,
                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);

  // When attempting to select outside of all menus this should lead to a
  // shutdown. This should not crash while attempting to repost the event.
  SetSelectionOnPointerDown(sub_menu, &event);

  EXPECT_FALSE(IsAsyncRun());
  EXPECT_EQ(delegate, GetCurrentDelegate());
  EXPECT_EQ(0, delegate->on_menu_closed_called());
  EXPECT_EQ(1, nested_delegate->on_menu_closed_called());
  EXPECT_EQ(nullptr, nested_delegate->on_menu_closed_menu());
  EXPECT_EQ(0, nested_delegate->on_menu_closed_mouse_event_flags());
  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
            nested_delegate->on_menu_closed_notify_type());
  EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}

// Tests that an asynchronous menu reposts touch events that occur outside of
// the bounds of the menu, and that the menu closes.
TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) {
  MenuController* controller = menu_controller();
  TestMenuControllerDelegate* delegate = menu_controller_delegate();
  controller->SetAsyncRun(true);

  // Show a sub menu to targert with a touch event. However have the event occur
  // outside of the bounds of the entire menu.
  MenuItemView* item = menu_item();
  SubmenuView* sub_menu = item->GetSubmenu();
  sub_menu->ShowAt(owner(), item->bounds(), false);
  gfx::Point location(sub_menu->bounds().bottom_right());
  location.Offset(1, 1);
  ui::TouchEvent event(ui::ET_TOUCH_PRESSED, location, 0, 0,
                       ui::EventTimeForNow(), 0, 0, 0, 0);
  controller->OnTouchEvent(sub_menu, &event);

  EXPECT_FALSE(IsShowing());
  EXPECT_EQ(1, delegate->on_menu_closed_called());
  EXPECT_EQ(nullptr, delegate->on_menu_closed_menu());
  EXPECT_EQ(0, delegate->on_menu_closed_mouse_event_flags());
  EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
            delegate->on_menu_closed_notify_type());
  EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}

// Tests that if you exit all menus when an asynchrnous menu is nested within a
// synchronous menu, the message loop for the parent menu finishes running.
TEST_F(MenuControllerTest, AsynchronousNestedExitAll) {
  InstallTestMenuMessageLoop();

  base::MessageLoopForUI::current()->PostTask(
      FROM_HERE, base::Bind(&MenuControllerTest::TestAsynchronousNestedExitAll,
                            base::Unretained(this)));

  RunMenu();
}

// Tests that if you exit the nested menu when an asynchrnous menu is nested
// within a synchronous menu, the message loop for the parent menu remains
// running.
TEST_F(MenuControllerTest, AsynchronousNestedExitOutermost) {
  InstallTestMenuMessageLoop();

  base::MessageLoopForUI::current()->PostTask(
      FROM_HERE,
      base::Bind(&MenuControllerTest::TestAsynchronousNestedExitOutermost,
                 base::Unretained(this)));

  RunMenu();
}

}  // namespace test
}  // namespace views


text:
//----------------------------------------------------------------------------
/** @file GoUctDefaultPriorKnowledge.h */
//----------------------------------------------------------------------------

#ifndef GOUCT_DEFAULTPRIORKNOWLEDGE_H
#define GOUCT_DEFAULTPRIORKNOWLEDGE_H

#include "../go/GoBoard.h"
#include "../gouct/GoUctKnowledge.h"
#include "../gouct/GoUctPlayoutPolicy.h"

//----------------------------------------------------------------------------

/** Default prior knowledge heuristic.
    Generates prior knowledge from:
    1. GoUctPlayoutPolicy, including pattern gamma values
    2. Global pattern gammas
    3. bonus near block of last move - nearness measured by cfg metric
    4. bonus for large sideextensions in the opening
*/
class GoUctDefaultPriorKnowledge
: public GoUctKnowledge
{
public:
    GoUctDefaultPriorKnowledge(const GoBoard& bd,
                               const GoUctPlayoutPolicyParam& param);

    void ProcessPosition(std::vector<SgUctMoveInfo>& moves);

    bool FindGlobalPatternAndAtariMoves(SgPointSet& pattern,
                                        SgPointSet& atari,
                                        GoPointList& empty);
private:

    GoUctPlayoutPolicy<GoBoard> m_policy;

    void AddBonusNearPoint(GoPointList& emptyPoints,
                           SgUctValue count,
                           SgPoint focus,
                           SgUctValue v1,
                           SgUctValue v2,
                           SgUctValue v3,
                           bool addPass
                           );

    void AddLocalityBonus(GoPointList& emptyPoints, bool isSmallBoard);

    void AddOpeningBonus();

    void InitializeForRandomPolicyMove(const GoPointList& empty,
                                       int nuSimulations);

    void InitializeForGlobalHeuristic(const GoPointList& empty,
                                      const SgPointSet& pattern,
                                      const SgPointSet& atari,
                                      int nuSimulations);

	void InitializeForNonRandomPolicyMove(const GoPointList& empty,
                                          const SgPointSet& pattern,
                                          const SgPointSet& atari,
                                          int nuSimulations);

	/** Temporary variable to hold max. of m_patternGammas for current move */
	float m_maxPatternGamma;

	/** Gamma values used as prior knowledge for pattern moves */
	SgArray<float,SG_MAXPOINT> m_patternGammas;
};

//----------------------------------------------------------------------------

#endif // GOUCT_DEFAULTPRIORKNOWLEDGE_H


text:
/***************************************************************************/
/*                                                                         */
/*  svfntfmt.h                                                             */
/*                                                                         */
/*    The FreeType font format service (specification only).               */
/*                                                                         */
/*  Copyright 2003-2015 by                                                 */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#ifndef __SVFNTFMT_H__
#define __SVFNTFMT_H__

#include FT_INTERNAL_SERVICE_H

FT_BEGIN_HEADER

  /*
   *  A trivial service used to return the name of a face's font driver,
   *  according to the XFree86 nomenclature.  Note that the service data
   *  is a simple constant string pointer.
   */

#define FT_SERVICE_ID_FONT_FORMAT  "font-format"

#define FT_FONT_FORMAT_TRUETYPE  "TrueType"
#define FT_FONT_FORMAT_TYPE_1    "Type 1"
#define FT_FONT_FORMAT_BDF       "BDF"
#define FT_FONT_FORMAT_PCF       "PCF"
#define FT_FONT_FORMAT_TYPE_42   "Type 42"
#define FT_FONT_FORMAT_CID       "CID Type 1"
#define FT_FONT_FORMAT_CFF       "CFF"
#define FT_FONT_FORMAT_PFR       "PFR"
#define FT_FONT_FORMAT_WINFNT    "Windows FNT"

  /* */

FT_END_HEADER

#endif /* __SVFNTFMT_H__ */

/* END */


text:
'use strict';
/* globals describe, it */
/* eslint node/no-unpublished-require: ["error", {"allowModules": ["chai"]}] */
const expect = require('chai').expect;
const EventTime = require('../lib/event-time');
const msgpack = require('msgpack-lite');

const codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

describe('EventTime', () => {
  it('should equal to decoded value', (done) => {
    const eventTime = EventTime.now();
    const encoded = msgpack.encode(eventTime, { codec: codec });
    const decoded = msgpack.decode(encoded, { codec: codec });
    expect(JSON.stringify(decoded)).to.equal(JSON.stringify(eventTime));
    done();
  });
  it('should equal fromDate and fromTimestamp', (done) => {
    const now = new Date(1489543720999); // 2017-03-15T02:08:40.999Z
    const timestamp = now.getTime();
    const eventTime = JSON.stringify(new EventTime(1489543720, 999000000));
    const eventTime1 = JSON.stringify(EventTime.fromDate(now));
    const eventTime2 = JSON.stringify(EventTime.fromTimestamp(timestamp));
    expect(eventTime1).to.equal(eventTime);
    expect(eventTime2).to.equal(eventTime);
    done();
  });
});


text:
using System;
using System.Runtime.InteropServices;

namespace Holf.AllForOne
{
    [StructLayout(LayoutKind.Sequential)]
    public struct Security_Attributes
    {
        public UInt32 nLength;
        public IntPtr lpSecurityDescriptor;
        public Int32 bInheritHandle;
    }
}


text:
const NodePath = require('../node-path');
const generator = require('../../generator');
const parser = require('../../parser');
const traverse = require('..');

describe('NodePath', () => {

  it('creates a node path', () => {
    const ast = parser.parse('/a/');
    const node = ast.body;

    const regexpPath = NodePath.getForNode(ast);

    expect(regexpPath.node).toBe(ast);
    expect(regexpPath.parent).toBe(null);
    expect(regexpPath.parentPath).toBe(null);
    expect(regexpPath.property).toBe(null);
    expect(regexpPath.index).toBe(null);

    const charPath = NodePath.getForNode(node, regexpPath, 'body');

    expect(charPath.node).toBe(node);
    expect(charPath.parent).toBe(ast);
    expect(charPath.parentPath).toBe(regexpPath);
    expect(charPath.property).toBe('body');
    expect(charPath.index).toBe(null);
  });

  it('removes a node', () => {
    const ast = parser.parse('/[ab]/');

    const bCharPath = NodePath.getForNode(
      ast.body.expressions[1],
      NodePath.getForNode(ast.body),
      'expressions',
      1
    );

    bCharPath.remove();

    expect(bCharPath.isRemoved()).toBe(true);
    expect(bCharPath.node).toBe(null);

    expect(ast).toEqual({
      type: 'RegExp',
      body: {
        type: 'CharacterClass',
        expressions: [
          {
            type: 'Char',
            value: 'a',
            symbol: 'a',
            kind: 'simple',
            codePoint: 'a'.codePointAt(0)
          },
          // No 'b' char.
        ]
      },
      flags: '',
    });
  });

  it('checks correct indices after removal', () => {
    const ast = parser.parse('/abcde/');

    traverse.traverse(ast, [
      // First handler, removes current 'b', and further 'c'.
      {
        Char(path) {
          const {node} = path;

          if (node.value === 'b') {

            const aPath = path.getPreviousSibling();
            const cPath = path.getNextSibling();
            const dPath = cPath.getNextSibling();
            const ePath = dPath.getNextSibling();

            // Remove 'b' itself.
            path.remove();

            // Remove 'c' as well.
            cPath.remove();

            // Check the index is rebuilt:

            // a, 0
            expect(aPath.node.value).toBe('a');
            expect(aPath.index).toBe(0);

            // No b (was 1 before removal)
            expect(path.isRemoved()).toBe(true);

            // No c (was 2 before removal)
            expect(cPath.isRemoved()).toBe(true);

            // d is now 1
            expect(dPath.node.value).toBe('d');
            expect(dPath.index).toBe(1);

            // e is now 2
            expect(ePath.node.value).toBe('e');
            expect(ePath.index).toBe(2);
          }
        },
      },

      // Second handler, backward-removes 'a' being on last 'e'.
      {
        // This handler is not called for 'b', and 'c' since
        // they were removed in the previous handler.
        Char(path) {
          const {node} = path;

          // Never can be 'b' or 'c', since they were removed.
          expect(path.value).not.toBe('b');
          expect(path.value).not.toBe('c');

          if (node.value === 'e') {

            // Initially index of `e` is 2.
            expect(path.index).toBe(2);

            // Being on 'd', we remove one of the previous siblings, 'a':

            const aPath = path.getPreviousSibling().getPreviousSibling();
            expect(aPath.node.value).toBe('a');

            const dPath = path.getPreviousSibling();
            expect(dPath.node.value).toBe('d');

            // Remove 'a'
            aPath.remove();
            expect(aPath.isRemoved()).toBe(true);

            // Check the index is rebuilt:

            // d, 0
            expect(dPath.index).toBe(0);

            // e, 1 (index of `e` is changed from 2 to 1)
            expect(path.index).toBe(1);

            expect(path.getNextSibling()).toBe(null);
          }
        }
      }
    ]);

    // '/abcde/' -> '/ae/', after 3 removals in 2 handlers.
    expect(generator.generate(ast)).toBe('/de/');
  });

  it('conditional remove', () => {
    const ast = parser.parse('/abcd/');

    // '/abcd/' -> '/ad/'
    traverse.traverse(ast, {
      Char(path) {
        const {node} = path;
        if (node.value === 'b' || node.value === 'c') {
          path.remove();
        }
      }
    });

    expect(generator.generate(ast)).toBe('/ad/');
  });

  it('several backward/forward removes', () => {
    const ast = parser.parse('/abcdefghi/');

    // '/abcdefghi/' -> '/bfi/'
    traverse.traverse(ast, {
      Char(path) {
        const {node} = path;

        // From 'd' remove previous 'a', 'c', 'd' (itself), and 'e'.
        // After this it is: bfghi
        if (node.value === 'd') {
          const cPath = path.getPreviousSibling();
          const aPath = cPath.getPreviousSibling().getPreviousSibling();
          const ePath = path.getNextSibling();

          aPath.remove();
          cPath.remove();
          path.remove();
          ePath.remove();
        }

        // From 'f' remove two next 'g', and 'h'
        // After this it is: bfi
        if (node.value === 'f') {
          const gPath = path.getNextSibling();
          const hPath = gPath.getNextSibling();

          gPath.remove();
          hPath.remove();
        }
      }
    });

    expect(generator.generate(ast)).toBe('/bfi/');
  });

  it('several backward/forward removes/inserts', () => {
    const ast = parser.parse('/abcdefghi/');

    // '/abcdefghi/' -> '/bxyfzi/'
    traverse.traverse(ast, {
      Char(path) {
        const {node} = path;

        // From 'd' remove previous 'a', 'c', inserts 'x' before 'd',
        // removes 'd' (itself), insert 'y' after 'e', remove 'e'.
        // After this it is: bxyfghi
        if (node.value === 'd') {
          const cPath = path.getPreviousSibling();
          const aPath = cPath.getPreviousSibling().getPreviousSibling();
          const ePath = path.getNextSibling();

          // Remove 'a', and 'c'.
          aPath.remove();
          cPath.remove();

          // Insert 'x' before 'd'. After we removed 'a', and 'c'
          // insert index is 1.
          const xNode = {
            type: 'Char',
            value: 'x',
            symbol: 'x',
            kind: 'simple',
            codePoint: 'x'.codePointAt(0)
          };

          const parentPath = path.parentPath;

          parentPath.insertChildAt(xNode, 1);

          // Remove 'd'.
          path.remove();

          // Insert 'y' after 'e'.
          const yNode = {
            type: 'Char',
            value: 'y',
            symbol: 'y',
            kind: 'simple',
            codePoint: 'y'.codePointAt(0)
          };

          parentPath.insertChildAt(yNode, 3);

          // Remove 'e'.
          ePath.remove();
        }

        // From 'f' remove two next 'g', and 'h', insert 'z' after 'f'.
        // After this it is: bfi
        if (node.value === 'f') {
          const gPath = path.getNextSibling();
          const hPath = gPath.getNextSibling();

          // Remove 'g'.
          gPath.remove();

          // Insert 'z'.
          const zNode = {
            type: 'Char',
            value: 'z',
            symbol: 'z',
            kind: 'simple',
            codePoint: 'z'.codePointAt(0)
          };
          path.parentPath.insertChildAt(zNode, 4);

          // Remove 'h'.
          hPath.remove();
        }
      }
    });

    expect(generator.generate(ast)).toBe('/bxyfzi/');
  });

  it('replaces a node', () => {
    const ast = parser.parse('/[ab]/');

    const bCharPath = new NodePath(
      ast.body.expressions[1],
      new NodePath(ast.body),
      'expressions',
      1
    );

    const cNode = {
      type: 'Char',
      value: 'c',
      symbol: 'c',
      kind: 'simple',
      codePoint: 'c'.codePointAt(0)
    };

    bCharPath.replace(cNode);
    expect(bCharPath.node).toEqual(cNode);

    expect(ast).toEqual({
      type: 'RegExp',
      body: {
        type: 'CharacterClass',
        expressions: [
          {
            type: 'Char',
            value: 'a',
            symbol: 'a',
            kind: 'simple',
            codePoint: 'a'.codePointAt(0)
          },
          // 'b' replaced with 'c'
          cNode
        ]
      },
      flags: '',
    });
  });

  it('replaces with already used node with another parent', () => {
    const ast = parser.parse('/a(b)/');

    const bodyPath = new NodePath(ast.body);
    const aCharPath = bodyPath.getChild(0);
    const groupPath = bodyPath.getChild(1);
    const bCharPath = groupPath.getChild();
    const aNode = aCharPath.node;
    const bNode = bCharPath.node;

    bodyPath.node.mark = 'body';
    groupPath.node.mark = 'group';

    // swap a and b
    groupPath.setChild(aNode);
    bodyPath.setChild(bNode, 0);

    // 'a' and 'b' should be swapped now
    expect(generator.generate(ast)).toBe('/b(a)/');

    // body and group still ok
    expect(bodyPath.node.mark).toBe('body');
    expect(groupPath.node.mark).toBe('group');
    expect(bodyPath.getChild(1).node.mark).toBe('group');

    // first is now Char 'b' in body
    expect(bodyPath.getChild(0).node.type).toBe('Char');
    expect(bodyPath.getChild(0).node.value).toBe('b');
    // parentPath should point to the same node as parent
    expect(bodyPath.getChild(0).parentPath.node)
      .toBe(bodyPath.getChild(0).parent);
    // now the parent of 'b' is the body
    expect(bodyPath.getChild(0).parent.mark).toBe('body');
    expect(bodyPath.getChild(0).parent.type).toBe('Alternative');
    // Group has children property 'expressions'
    expect(bodyPath.getChild(0).property).toBe('expressions');
    // and an index of 0
    expect(bodyPath.getChild(0).index).toBe(0);

    // second is Char 'a' in the Group
    expect(bodyPath.getChild(1).getChild().node.type).toBe('Char');
    expect(bodyPath.getChild(1).getChild().node.value).toBe('a');
    // parentPath should point to the same node as parent
    expect(bodyPath.getChild(1).getChild().parentPath.node)
      .toBe(bodyPath.getChild(1).getChild().parent);
    // now the parent of 'a' is the Group
    expect(bodyPath.getChild(1).getChild().parent.mark).toBe('group');
    expect(bodyPath.getChild(1).getChild().parent.type).toBe('Group');
    // Group has child property 'expression'
    expect(bodyPath.getChild(1).getChild().property).toBe('expression');
    // and no index!
    expect(bodyPath.getChild(1).getChild().index).toBe(null);

    // the locally stored NodePaths should have new parents
    expect(bCharPath.parentPath).toBe(bodyPath);
    expect(aCharPath.parentPath).toBe(groupPath);
    // paths from the registry should be the same
    const bCharPath2 = NodePath.getForNode(bNode);
    expect(bCharPath2).toBe(bCharPath);
    const aCharPath2 = NodePath.getForNode(aNode);
    expect(aCharPath2).toBe(aCharPath);
  });

  it('sets a child node to two new nested nodes', () => {
    const ast = parser.parse('/ab/');

    const bodyPath = new NodePath(ast.body);
    const bCharPath = bodyPath.getChild(1);

    const cNode = {
      type: 'Char',
      value: 'c',
      symbol: 'c',
      kind: 'simple',
      codePoint: 'c'.codePointAt(0)
    };

    const groupNode = {
      type: 'Group',
      capturing: true,
      expression: null
    };

    const alterNode = {
      type: 'Alternative',
      expressions: []
    };

    bCharPath.replace(groupNode);
    expect(bCharPath.node).toEqual(groupNode);

    const groupPath = bodyPath.getChild(1);

    groupPath.setChild(cNode);

    const cPath = NodePath.getForNode(cNode);
    expect(cPath.parentPath).toBe(groupPath);
    const cPath2 = groupPath.getChild();
    expect(cPath2).toBe(cPath);
    expect(cPath2.parentPath).toBe(groupPath);

    const alterPath = groupPath.setChild(alterNode);
    alterPath.appendChild(cNode);

    const dNode = {
      type: 'Char',
      value: 'd',
      symbol: 'd',
      kind: 'simple',
      codePoint: 'd'.codePointAt(0)
    };
    alterPath.appendChild(dNode);

    const dPath = NodePath.getForNode(dNode);
    expect(cPath.parentPath).toBe(alterPath);
    expect(dPath.parentPath).toBe(alterPath);
    expect(alterPath.parentPath).toBe(groupPath);

    expect(generator.generate(ast)).toEqual('/a(cd)/');
  });

  it('getPreviousSibling', () => {
    const ast = parser.parse('/ab/');

    const aCharPath = NodePath.getForNode(
      ast.body.expressions[0],
      NodePath.getForNode(ast.body),
      'expressions',
      0
    );

    const bCharPath = NodePath.getForNode(
      ast.body.expressions[1],
      NodePath.getForNode(ast.body),
      'expressions',
      1
    );

    expect(bCharPath.getPreviousSibling()).toBe(aCharPath);
  });

  it('getNextSibling', () => {
    const ast = parser.parse('/ab/');

    const aCharPath = NodePath.getForNode(
      ast.body.expressions[0],
      NodePath.getForNode(ast.body),
      'expressions',
      0
    );

    const bCharPath = NodePath.getForNode(
      ast.body.expressions[1],
      NodePath.getForNode(ast.body),
      'expressions',
      1
    );

    expect(aCharPath.getNextSibling()).toBe(bCharPath);

  });

  it('getParent/getChild', () => {
    const ast = parser.parse('/a(bc)d/');

    const bodyPath = NodePath.getForNode(ast.body);
    const groupPath = bodyPath.getChild(1);

    expect(groupPath.node.type).toBe('Group');
    expect(groupPath.getParent()).toBe(bodyPath);

    const alterPath = groupPath.getChild();

    expect(alterPath.node.type).toBe('Alternative');
    expect(alterPath.getParent()).toBe(groupPath);

    const bCharPath = alterPath.getChild(0);
    const cCharPath = alterPath.getChild(1);

    expect(bCharPath.getParent()).toBe(alterPath);
    expect(cCharPath.getParent()).toBe(alterPath);

    expect(bCharPath.getParent().getParent()).toBe(groupPath);
    expect(cCharPath.getParent().getParent()).toBe(groupPath);

    expect(groupPath.getChild()).toBe(alterPath);
    expect(groupPath.getChild(0)).toBe(alterPath);
    expect(groupPath.getChild(1)).toBe(null);

    expect(groupPath.getChild().getChild(0)).toBe(bCharPath);
    expect(groupPath.getChild().getChild(1)).toBe(cCharPath);

    expect(groupPath.getChild()).toBe(alterPath);
    expect(groupPath.getChild(0)).toBe(alterPath);
    expect(groupPath.getChild(1)).toBe(null);
  });

  it('hasEqualSource', () => {
    const ast = parser.parse('/aba/', {
      captureLocations: true,
    });

    const parentPath = NodePath.getForNode(ast.body);

    const a1Path = NodePath.getForNode(
      ast.body.expressions[0],
      parentPath,
      'expressions',
      0
    );

    const bPath = NodePath.getForNode(
      ast.body.expressions[1],
      parentPath,
      'expressions',
      1
    );

    const a2Path = NodePath.getForNode(
      ast.body.expressions[2],
      parentPath,
      'expressions',
      2
    );

    expect(a1Path.hasEqualSource(a2Path)).toBe(true);

    expect(bPath.hasEqualSource(a1Path)).toBe(false);
    expect(bPath.hasEqualSource(a2Path)).toBe(false);
  });

  it('jsonEncode', () => {
    const node =  {
      type: 'Char',
      value: 'a',
      symbol: 'a',
      kind: 'simple',
      codePoint: 'a'.codePointAt(0)
    };

    const path = NodePath.getForNode(
      Object.assign({}, node, {
        loc: {
          source: 'a',
          start: 1,
          end: 2,
        }
      })
    );

    expect(path.jsonEncode())
      .toBe(JSON.stringify(node, null, (prop, value) => {
        if (prop === 'loc') {
          return undefined;
        }
        return value;
      }));
  });

});